diff --git a/CMakeLists.txt b/CMakeLists.txt
index 06cc1cd8ddba43e22ee6dd1a39eab58d67851132..af1f64bd83e317f91670a19b3a95113639f59193 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -330,7 +330,6 @@ set(ZIG_STAGE2_SOURCES
src/Air/Liveness.zig
src/Air/Liveness/Verify.zig
src/Air/print.zig
- src/Air/types_resolved.zig
src/Builtin.zig
src/Compilation.zig
src/Compilation/Config.zig
@@ -344,6 +343,7 @@ set(ZIG_STAGE2_SOURCES
src/Sema.zig
src/Sema/bitcast.zig
src/Sema/comptime_ptr_access.zig
+ src/Sema/type_resolution.zig
src/Type.zig
src/Value.zig
src/Zcu.zig
@@ -360,7 +360,8 @@ set(ZIG_STAGE2_SOURCES
src/codegen/aarch64/Mir.zig
src/codegen/aarch64/Select.zig
src/codegen/c.zig
- src/codegen/c/Type.zig
+ src/codegen/c/type.zig
+ src/codegen/c/type/render_defs.zig
src/codegen/llvm.zig
src/codegen/llvm/bindings.zig
src/crash_report.zig
@@ -375,6 +376,7 @@ set(ZIG_STAGE2_SOURCES
src/libs/libunwind.zig
src/link.zig
src/link/C.zig
+ src/link/ConstPool.zig
src/link/Coff.zig
src/link/Dwarf.zig
src/link/Elf.zig
@@ -606,8 +608,8 @@ if(MSVC)
set(ZIG2_LINK_FLAGS "/STACK:16777216 /FORCE:MULTIPLE")
else()
set(ZIG_WASM2C_COMPILE_FLAGS "-std=c99 -O2")
- set(ZIG1_COMPILE_FLAGS "-std=c99 -Os")
- set(ZIG2_COMPILE_FLAGS "-std=c99 -O0 -fno-sanitize=undefined -fno-stack-protector")
+ set(ZIG1_COMPILE_FLAGS "-std=c99 -Os -fno-strict-aliasing")
+ set(ZIG2_COMPILE_FLAGS "-std=c99 -O0 -fno-sanitize=undefined -fno-stack-protector -fno-strict-aliasing")
# Must match the condition in build.zig.
if(ZIG_HOST_TARGET_ARCH MATCHES "^(arm|thumb)(eb)?$" OR ZIG_HOST_TARGET_ARCH MATCHES "^powerpc(64)?(le)?$")
set(ZIG1_COMPILE_FLAGS "${ZIG1_COMPILE_FLAGS} -ffunction-sections -fdata-sections")
@@ -623,6 +625,12 @@ else()
else()
set(ZIG2_LINK_FLAGS "-Wl,-z,stack-size=0x10000000")
endif()
+ # Prevent GCC from miscompiling 'zig2.c'. See also 'workaround_gcc_sra_miscomp' in 'bootstrap.c'.
+ if (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND
+ CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL "13.0" AND
+ CMAKE_C_COMPILER_VERSION VERSION_LESS_EQUAL "15.2")
+ set(ZIG2_COMPILE_FLAGS "${ZIG2_COMPILE_FLAGS} -fno-tree-sra")
+ endif()
endif()
set(ZIG1_WASM_MODULE "${PROJECT_SOURCE_DIR}/stage1/zig1.wasm")
diff --git a/bootstrap.c b/bootstrap.c
index 44ba0714764a387eff427c118e4a66c8bcfb3a69..ad4ccec54a67fd3b94f880d0669be25303afd14f 100644
--- a/bootstrap.c
+++ b/bootstrap.c
@@ -102,6 +102,26 @@ int main(int argc, char **argv) {
const char *cc = get_c_compiler();
const char *host_triple = get_host_triple();
+ // GCC versions 13.0--14.1 have a miscompilation where some bytes of a union may get clobbered
+ // depending on the union layout and the order in which types are defined. This miscompilation
+ // affects the output of the C backend, and thus can affect the bootstrap process. Specifically,
+ // we observe that using the self-hosted x86_64 backend in 'zig2' will cause all function calls
+ // to be relocated incorrectly, causing immediate crashes on any binary produced by it.
+ //
+ // The only reliable workaround for this bug is to disable the optimization pass containing it,
+ // so here we check for a CLI flag requesting that workaround.
+ //
+ // The upstream bug is fixed in GCC version 15.2 onwards (and was also backported to the 13 and
+ // 14 branches). Once this bug is no longer widespread, we can remove this CLI flag.
+ //
+ // Upstream bug report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119085
+ bool workaround_gcc_sra_miscomp = false;
+ for (int i = 1; i < argc; ++i) {
+ if (!strcmp(argv[i], "--workaround-gcc-sra-miscomp")) {
+ workaround_gcc_sra_miscomp = true;
+ }
+ }
+
{
const char *child_argv[] = {
cc, "-o", "zig-wasm2c", "stage1/wasm2c.c", "-O2", "-std=c99", NULL,
@@ -116,7 +136,7 @@ int main(int argc, char **argv) {
}
{
const char *child_argv[] = {
- cc, "-o", "zig1", "zig1.c", "stage1/wasi.c", "-std=c99", "-Os", "-lm", NULL,
+ cc, "-o", "zig1", "zig1.c", "stage1/wasi.c", "-std=c99", "-Os", "-fno-strict-aliasing", "-lm", NULL,
};
print_and_run(child_argv);
}
@@ -193,6 +213,8 @@ int main(int argc, char **argv) {
#if defined(__GNUC__)
"-pthread",
#endif
+ "-fno-strict-aliasing",
+ workaround_gcc_sra_miscomp ? "-fno-tree-sra" : NULL,
NULL,
};
print_and_run(child_argv);
diff --git a/build.zig b/build.zig
index 06ba1aab65bb127957fb1abb3ba8dafc3d40db9d..4e6efa41a6e6dbca14bf3d37f17117a61f1fcb85 100644
--- a/build.zig
+++ b/build.zig
@@ -568,7 +568,7 @@ pub fn build(b: *std.Build) !void {
.skip_linux = skip_linux,
.skip_llvm = skip_llvm,
.skip_libc = skip_libc,
- .max_rss = 8_500_000_000,
+ .max_rss = 9_300_000_000,
}));
const unit_tests_step = b.step("test-unit", "Run the compiler source unit tests");
@@ -584,7 +584,7 @@ pub fn build(b: *std.Build) !void {
.use_llvm = use_llvm,
.use_lld = use_llvm,
.zig_lib_dir = b.path("lib"),
- .max_rss = 2_500_000_000,
+ .max_rss = 2_700_000_000,
});
if (link_libc) {
unit_tests.root_module.link_libc = true;
@@ -611,7 +611,7 @@ pub fn build(b: *std.Build) !void {
.skip_linux = skip_linux,
.skip_llvm = skip_llvm,
.skip_release = skip_release,
- .max_rss = 3_000_000_000,
+ .max_rss = 3_300_000_000,
}));
test_step.dependOn(tests.addLinkTests(b, enable_macos_sdk, enable_ios_sdk, enable_symlinks_windows));
test_step.dependOn(tests.addStackTraceTests(b, test_filters, skip_non_native));
@@ -767,7 +767,7 @@ fn addCompilerMod(b: *std.Build, options: AddCompilerModOptions) *std.Build.Modu
fn addCompilerStep(b: *std.Build, options: AddCompilerModOptions) *std.Build.Step.Compile {
const exe = b.addExecutable(.{
.name = "zig",
- .max_rss = 7_900_000_000,
+ .max_rss = 8_700_000_000,
.root_module = addCompilerMod(b, options),
});
exe.stack_size = stack_size;
diff --git a/ci/aarch64-freebsd-debug.sh b/ci/aarch64-freebsd-debug.sh
index c296a50fd15388ae07286336b32bd0b9157849ec..87ffb3110223a6dfb7192833c0f3d7fd91f2c947 100755
--- a/ci/aarch64-freebsd-debug.sh
+++ b/ci/aarch64-freebsd-debug.sh
@@ -47,7 +47,6 @@ stage3-debug/bin/zig build test docs \
--maxrss ${ZSF_MAX_RSS:-0} \
-Dstatic-llvm \
-Dskip-non-native \
- -Dskip-test-incremental \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
--test-timeout 2m
diff --git a/ci/aarch64-freebsd-release.sh b/ci/aarch64-freebsd-release.sh
index 1686327fb0b7da983d1f98fbd5d4188f01768d62..d5911241d6150e43e7273142c2882e956956fed2 100755
--- a/ci/aarch64-freebsd-release.sh
+++ b/ci/aarch64-freebsd-release.sh
@@ -47,7 +47,6 @@ stage3-release/bin/zig build test docs \
--maxrss ${ZSF_MAX_RSS:-0} \
-Dstatic-llvm \
-Dskip-non-native \
- -Dskip-test-incremental \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
--test-timeout 2m
diff --git a/ci/aarch64-linux-debug.sh b/ci/aarch64-linux-debug.sh
index 37a09b539845be9864c06f336eca482ab02983c9..7a4a6daa2aef60e1a9194184b1307f85992db3de 100755
--- a/ci/aarch64-linux-debug.sh
+++ b/ci/aarch64-linux-debug.sh
@@ -47,7 +47,6 @@ stage3-debug/bin/zig build test docs \
--maxrss ${ZSF_MAX_RSS:-0} \
-Dstatic-llvm \
-Dskip-non-native \
- -Dskip-test-incremental \
-Dtarget=native-native-musl \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
diff --git a/ci/aarch64-linux-release.sh b/ci/aarch64-linux-release.sh
index 8cde024ab11450376913d68816fd9d02a3a9c00e..39ad9767ab62264b19846ef8bc22e2d6ad23ed85 100755
--- a/ci/aarch64-linux-release.sh
+++ b/ci/aarch64-linux-release.sh
@@ -47,7 +47,6 @@ stage3-release/bin/zig build test docs \
--maxrss ${ZSF_MAX_RSS:-0} \
-Dstatic-llvm \
-Dskip-non-native \
- -Dskip-test-incremental \
-Dtarget=native-native-musl \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
diff --git a/ci/aarch64-macos-debug.sh b/ci/aarch64-macos-debug.sh
index 369afc8d9e94a02ed77965bffc9692a5b5e344c4..7dc60c1f4ed13f8835538a2609955423ef8d551e 100755
--- a/ci/aarch64-macos-debug.sh
+++ b/ci/aarch64-macos-debug.sh
@@ -47,7 +47,6 @@ stage3-debug/bin/zig build test docs \
-Denable-macos-sdk \
-Dstatic-llvm \
-Dskip-non-native \
- -Dskip-test-incremental \
--search-prefix "$PREFIX" \
--test-timeout 2m
diff --git a/ci/aarch64-macos-release.sh b/ci/aarch64-macos-release.sh
index f7e6ae6fd3f4dba1970b94f6bc8e98305b2585be..00b6571f170a7fece1dcfb53755f9b271f438aae 100755
--- a/ci/aarch64-macos-release.sh
+++ b/ci/aarch64-macos-release.sh
@@ -46,7 +46,6 @@ stage3-release/bin/zig build test docs \
-Denable-macos-sdk \
-Dstatic-llvm \
-Dskip-non-native \
- -Dskip-test-incremental \
--search-prefix "$PREFIX" \
--test-timeout 2m
diff --git a/ci/aarch64-netbsd-debug.sh b/ci/aarch64-netbsd-debug.sh
index 5c87d14f47d15ab5bb82158ef0aa28c2dbafdb07..4f5eb0d41089778c97d4fe8e4eea70d1e88cea62 100755
--- a/ci/aarch64-netbsd-debug.sh
+++ b/ci/aarch64-netbsd-debug.sh
@@ -47,7 +47,6 @@ stage3-debug/bin/zig build test docs \
--maxrss ${ZSF_MAX_RSS:-0} \
-Dstatic-llvm \
-Dskip-non-native \
- -Dskip-test-incremental \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
--test-timeout 4m
diff --git a/ci/aarch64-netbsd-release.sh b/ci/aarch64-netbsd-release.sh
index bf54c10efc835b51f87731bfd082132a7ec8fd19..d9d9477904cc721a9c40080e3d5470d129e0b8b0 100755
--- a/ci/aarch64-netbsd-release.sh
+++ b/ci/aarch64-netbsd-release.sh
@@ -47,7 +47,6 @@ stage3-release/bin/zig build test docs \
--maxrss ${ZSF_MAX_RSS:-0} \
-Dstatic-llvm \
-Dskip-non-native \
- -Dskip-test-incremental \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
--test-timeout 4m
diff --git a/ci/aarch64-windows.ps1 b/ci/aarch64-windows.ps1
index 57d77993519f230c2fc6e14de5a7e6957c51062a..96e07642565019c9a805ecc8c5ac29f461341df1 100644
--- a/ci/aarch64-windows.ps1
+++ b/ci/aarch64-windows.ps1
@@ -60,7 +60,6 @@ Write-Output "Main test suite..."
--search-prefix "$PREFIX_PATH" `
-Dstatic-llvm `
-Dskip-non-native `
- -Dskip-test-incremental `
-Denable-symlinks-windows `
--test-timeout 30m
CheckLastExitCode
diff --git a/ci/loongarch64-linux-debug.sh b/ci/loongarch64-linux-debug.sh
index 2d966f37427b1408febbc92abd516cebca096047..4cba17b0319039daf2d132ece4908cfdf542cffa 100755
--- a/ci/loongarch64-linux-debug.sh
+++ b/ci/loongarch64-linux-debug.sh
@@ -48,7 +48,6 @@ stage3-debug/bin/zig build test docs \
--maxrss ${ZSF_MAX_RSS:-0} \
-Dstatic-llvm \
-Dskip-non-native \
- -Dskip-test-incremental \
-Dtarget=native-native-musl \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
diff --git a/ci/loongarch64-linux-release.sh b/ci/loongarch64-linux-release.sh
index 558177a8d99ea2c6885cb2ab0d405cecf4cb8ca5..5b05284d26668d01020f204f09d3a73921883ce5 100755
--- a/ci/loongarch64-linux-release.sh
+++ b/ci/loongarch64-linux-release.sh
@@ -48,7 +48,6 @@ stage3-release/bin/zig build test docs \
--maxrss ${ZSF_MAX_RSS:-0} \
-Dstatic-llvm \
-Dskip-non-native \
- -Dskip-test-incremental \
-Dtarget=native-native-musl \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
diff --git a/ci/powerpc64le-linux-debug.sh b/ci/powerpc64le-linux-debug.sh
index 2875dcba955eeee80cda7eeadc38b3a0526f01be..1b9a51e44debff61729207ec1529e1d494b8c84b 100755
--- a/ci/powerpc64le-linux-debug.sh
+++ b/ci/powerpc64le-linux-debug.sh
@@ -48,7 +48,6 @@ stage3-debug/bin/zig build test docs \
--maxrss ${ZSF_MAX_RSS:-0} \
-Dstatic-llvm \
-Dskip-non-native \
- -Dskip-test-incremental \
-Dtarget=native-native-musl \
-Dcpu=native+longcall \
--search-prefix "$PREFIX" \
diff --git a/ci/powerpc64le-linux-release.sh b/ci/powerpc64le-linux-release.sh
index fffcbe2bd2c8bc72f18f21db76b557df1f1b8798..77e1ca803ae27db49ed7a2b8fed48392f485c4d4 100755
--- a/ci/powerpc64le-linux-release.sh
+++ b/ci/powerpc64le-linux-release.sh
@@ -48,7 +48,6 @@ stage3-release/bin/zig build test docs \
--maxrss ${ZSF_MAX_RSS:-0} \
-Dstatic-llvm \
-Dskip-non-native \
- -Dskip-test-incremental \
-Dtarget=native-native-musl \
-Dcpu=native+longcall \
--search-prefix "$PREFIX" \
diff --git a/ci/s390x-linux-debug.sh b/ci/s390x-linux-debug.sh
index a76ed6f04df534ee6d124bc0848a0d8ce3b0669f..ffe4d0f02b3cada3b36e24fcc3572a1a14d5b389 100755
--- a/ci/s390x-linux-debug.sh
+++ b/ci/s390x-linux-debug.sh
@@ -48,7 +48,6 @@ stage3-debug/bin/zig build test docs \
--maxrss ${ZSF_MAX_RSS:-0} \
-Dstatic-llvm \
-Dskip-non-native \
- -Dskip-test-incremental \
-Dtarget=native-native-musl \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
diff --git a/ci/s390x-linux-release.sh b/ci/s390x-linux-release.sh
index 0a9b82620d5a9176a3542b5fd953054ee4f1feed..7fb6cd3641fa73752ca4f6eb1967f1a2de9dd8bf 100755
--- a/ci/s390x-linux-release.sh
+++ b/ci/s390x-linux-release.sh
@@ -48,7 +48,6 @@ stage3-release/bin/zig build test docs \
--maxrss ${ZSF_MAX_RSS:-0} \
-Dstatic-llvm \
-Dskip-non-native \
- -Dskip-test-incremental \
-Dtarget=native-native-musl \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
diff --git a/ci/x86_64-freebsd-debug.sh b/ci/x86_64-freebsd-debug.sh
index 8bf492540eadd7cc68db8d43d06a5c0296165ab3..a4d7034325b33dc92b9d8ba97442d4449ad6a4c5 100755
--- a/ci/x86_64-freebsd-debug.sh
+++ b/ci/x86_64-freebsd-debug.sh
@@ -53,7 +53,6 @@ stage3-debug/bin/zig build test docs \
-Dskip-openbsd \
-Dskip-windows \
-Dskip-darwin \
- -Dskip-test-incremental \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
--test-timeout 2m
diff --git a/ci/x86_64-freebsd-release.sh b/ci/x86_64-freebsd-release.sh
index 44c4e76da2558d4fd399cee1452f4bc76ea8404d..0ce708c63d7715c4e6ad4e4e3927d4a100b9f65e 100755
--- a/ci/x86_64-freebsd-release.sh
+++ b/ci/x86_64-freebsd-release.sh
@@ -53,7 +53,6 @@ stage3-release/bin/zig build test docs \
-Dskip-openbsd \
-Dskip-windows \
-Dskip-darwin \
- -Dskip-test-incremental \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
--test-timeout 2m
diff --git a/ci/x86_64-linux-debug-llvm.sh b/ci/x86_64-linux-debug-llvm.sh
index a37fc6c2a6214888856401ee0d7f1ba1939eb38b..96bb795e18e23d72eb8715951a1c9bfc9e28243d 100755
--- a/ci/x86_64-linux-debug-llvm.sh
+++ b/ci/x86_64-linux-debug-llvm.sh
@@ -64,7 +64,6 @@ stage3-debug/bin/zig build test docs \
-Dskip-openbsd \
-Dskip-windows \
-Dskip-darwin \
- -Dskip-test-incremental \
-Dtarget=native-native-musl \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
diff --git a/ci/x86_64-linux-debug.sh b/ci/x86_64-linux-debug.sh
index 60203bdcd0c4a66929be7b4d55bdfe416744a20b..aeaf5b8678badc181f79fdc76597edf1fa8ed203 100755
--- a/ci/x86_64-linux-debug.sh
+++ b/ci/x86_64-linux-debug.sh
@@ -63,7 +63,6 @@ stage3-debug/bin/zig build test docs \
-Dskip-windows \
-Dskip-darwin \
-Dskip-llvm \
- -Dskip-test-incremental \
-Dtarget=native-native-musl \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
diff --git a/ci/x86_64-linux-release.sh b/ci/x86_64-linux-release.sh
index 21411ab2af64258aff7910c2dcd3abcdb834cbf3..b1f6b84dcd10681631d1ad5fde7e36356d042ac4 100755
--- a/ci/x86_64-linux-release.sh
+++ b/ci/x86_64-linux-release.sh
@@ -21,7 +21,8 @@ export ZIG_LOCAL_CACHE_DIR="$PWD/zig-local-cache"
# Test building from source without LLVM.
cc -o bootstrap bootstrap.c
-./bootstrap
+# See comments in bootstrap.c for an explanation of the flag given here.
+./bootstrap --workaround-gcc-sra-miscomp
./zig2 build -Dno-lib
./zig-out/bin/zig test test/behavior.zig
@@ -64,7 +65,6 @@ stage3-release/bin/zig build test docs \
--libc-runtimes $HOME/deps/glibc-2.43-musl-1.2.5 \
-fwasmtime \
-Dstatic-llvm \
- -Dskip-test-incremental \
-Dtarget=native-native-musl \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
diff --git a/ci/x86_64-netbsd-debug.sh b/ci/x86_64-netbsd-debug.sh
index 416ab6a5e0168464e4295d1dc54c5e2c19ac4366..68e9081f3ba040c83e4116b194ba17a46692798e 100755
--- a/ci/x86_64-netbsd-debug.sh
+++ b/ci/x86_64-netbsd-debug.sh
@@ -47,7 +47,6 @@ stage3-debug/bin/zig build test docs \
--maxrss ${ZSF_MAX_RSS:-0} \
-Dstatic-llvm \
-Dskip-non-native \
- -Dskip-test-incremental \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
--test-timeout 2m
diff --git a/ci/x86_64-netbsd-release.sh b/ci/x86_64-netbsd-release.sh
index d8c54ca28d095b3a7e65a53fab1f572162fc4ea5..225a527686ac06cc1da2241f0fb624956f2d5a58 100755
--- a/ci/x86_64-netbsd-release.sh
+++ b/ci/x86_64-netbsd-release.sh
@@ -47,7 +47,6 @@ stage3-release/bin/zig build test docs \
--maxrss ${ZSF_MAX_RSS:-0} \
-Dstatic-llvm \
-Dskip-non-native \
- -Dskip-test-incremental \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
--test-timeout 2m
diff --git a/ci/x86_64-openbsd-debug.sh b/ci/x86_64-openbsd-debug.sh
index 58363e52d3b9339395b4270f35f9e6b9427d7df1..133c8dd4d642a9d4a019d297a3648567231d6078 100755
--- a/ci/x86_64-openbsd-debug.sh
+++ b/ci/x86_64-openbsd-debug.sh
@@ -47,7 +47,6 @@ stage3-debug/bin/zig build test docs \
--maxrss ${ZSF_MAX_RSS:-0} \
-Dstatic-llvm \
-Dskip-non-native \
- -Dskip-test-incremental \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
--test-timeout 2m
diff --git a/ci/x86_64-openbsd-release.sh b/ci/x86_64-openbsd-release.sh
index ebdaac1ee0c4e0c092929534517096bd5051a450..535b1a147166a1b724dd39358db56f18f17e09cd 100755
--- a/ci/x86_64-openbsd-release.sh
+++ b/ci/x86_64-openbsd-release.sh
@@ -47,7 +47,6 @@ stage3-release/bin/zig build test docs \
--maxrss ${ZSF_MAX_RSS:-0} \
-Dstatic-llvm \
-Dskip-non-native \
- -Dskip-test-incremental \
--search-prefix "$PREFIX" \
--zig-lib-dir "$PWD/../lib" \
--test-timeout 2m
diff --git a/doc/langref.html.in b/doc/langref.html.in
index e87decdf4a9ab51de65bc8ae0c8d6a8378b47dcd..643c948b68e99e11236f9c24e180af848736a820 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -2103,8 +2103,9 @@ or
less than {#syntax#}1 << 29{#endsyntax#}.
- In Zig, a pointer type has an alignment value. If the value is equal to the
- alignment of the underlying type, it can be omitted from the type:
+ Pointer types may explicitly specify an alignment in bytes. If it is not
+ specified, the alignment is assumed to be equal to the alignment of the
+ underlying type.
{#code|test_variable_alignment.zig#}
diff --git a/doc/langref/test_comptime_invalid_error_code.zig b/doc/langref/test_comptime_invalid_error_code.zig
index ebc6314764b399fcbbb5a1b03225e4d9611f5f21..e4fedf5812a972af6168e26c7689de92a204165c 100644
--- a/doc/langref/test_comptime_invalid_error_code.zig
+++ b/doc/langref/test_comptime_invalid_error_code.zig
@@ -1,8 +1,5 @@
comptime {
- const err = error.AnError;
- const number = @intFromError(err) + 10;
- const invalid_err = @errorFromInt(number);
- _ = invalid_err;
+ _ = @errorFromInt(12345);
}
-// test_error=integer value '11' represents no error
+// test_error=integer value '12345' represents no error
diff --git a/doc/langref/test_missized_packed_struct.zig b/doc/langref/test_missized_packed_struct.zig
index 791f97cc311b6f33b5859e1612c684cde6d0d6c3..df323244d4bebdf34dd6dde9bdbdfe6d8720dfd2 100644
--- a/doc/langref/test_missized_packed_struct.zig
+++ b/doc/langref/test_missized_packed_struct.zig
@@ -3,4 +3,4 @@ test "missized packed struct" {
_ = S{ .a = 4, .b = 2 };
}
-// test_error=backing integer type 'u32' has bit size 32 but the struct fields have a total bit size of 24
+// test_error=backing integer bit width does not match total bit width of fields
diff --git a/doc/langref/test_variable_alignment.zig b/doc/langref/test_variable_alignment.zig
index 01768e29eb0e81d5924644fbbbbd6739047fb690..d0a4560fa2954930d7d2f460c2d74d6b64b0d3cf 100644
--- a/doc/langref/test_variable_alignment.zig
+++ b/doc/langref/test_variable_alignment.zig
@@ -1,15 +1,20 @@
const std = @import("std");
const builtin = @import("builtin");
+const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
test "variable alignment" {
var x: i32 = 1234;
- const align_of_i32 = @alignOf(@TypeOf(x));
+
try expectEqual(*i32, @TypeOf(&x));
- try expectEqual(*align(align_of_i32) i32, *i32);
- if (builtin.target.cpu.arch == .x86_64) {
- try expectEqual(4, @typeInfo(*i32).pointer.alignment);
- }
+
+ try expect(@intFromPtr(&x) % @alignOf(i32) == 0);
+
+ // The implicitly-aligned pointer can be coerced to be explicitly-aligned to
+ // the alignment of the underlying type `i32`:
+ const ptr: *align(@alignOf(i32)) i32 = &x;
+
+ try expectEqual(1234, ptr.*);
}
// test
diff --git a/lib/compiler/aro/aro/InitList.zig b/lib/compiler/aro/aro/InitList.zig
index 9d8af869d75851b43b752427423f872b0493932e..ed7af8f998b9e37acd6d83e6c73ec6370b071783 100644
--- a/lib/compiler/aro/aro/InitList.zig
+++ b/lib/compiler/aro/aro/InitList.zig
@@ -22,9 +22,15 @@ const Item = struct {
const InitList = @This();
-list: std.ArrayList(Item) = .empty,
-node: Node.OptIndex = .null,
-tok: TokenIndex = 0,
+list: std.ArrayList(Item),
+node: Node.OptIndex,
+tok: TokenIndex,
+
+pub const empty: InitList = .{
+ .list = .empty,
+ .node = .null,
+ .tok = 0,
+};
/// Deinitialize freeing all memory.
pub fn deinit(il: *InitList, gpa: Allocator) void {
@@ -43,7 +49,7 @@ pub fn find(il: *InitList, gpa: Allocator, index: u64) !*InitList {
if (il.list.items.len == 0) {
const item = try il.list.addOne(gpa);
item.* = .{
- .list = .{},
+ .list = .empty,
.index = index,
};
return &item.list;
@@ -51,7 +57,7 @@ pub fn find(il: *InitList, gpa: Allocator, index: u64) !*InitList {
// Append a new value to the end of the list.
const new = try il.list.addOne(gpa);
new.* = .{
- .list = .{},
+ .list = .empty,
.index = index,
};
return &new.list;
@@ -70,7 +76,7 @@ pub fn find(il: *InitList, gpa: Allocator, index: u64) !*InitList {
// Insert a new value into a sorted position.
try il.list.insert(gpa, left, .{
- .list = .{},
+ .list = .empty,
.index = index,
});
return &il.list.items[left].list;
@@ -78,7 +84,7 @@ pub fn find(il: *InitList, gpa: Allocator, index: u64) !*InitList {
test "basic usage" {
const gpa = testing.allocator;
- var il: InitList = .{};
+ var il: InitList = .empty;
defer il.deinit(gpa);
{
diff --git a/lib/compiler/aro/aro/Parser.zig b/lib/compiler/aro/aro/Parser.zig
index fc21ee4d0b5f25f8f28b08c157d80a59b83adda8..6e60dbd623e6c729375c4e522cd4fbd43cb43b4c 100644
--- a/lib/compiler/aro/aro/Parser.zig
+++ b/lib/compiler/aro/aro/Parser.zig
@@ -3977,7 +3977,7 @@ fn initializer(p: *Parser, init_qt: QualType) Error!Result {
final_init_qt = .invalid;
}
- var il: InitList = .{};
+ var il: InitList = .empty;
defer il.deinit(p.comp.gpa);
try p.initializerItem(&il, final_init_qt, l_brace);
@@ -4028,12 +4028,12 @@ fn initializerItem(p: *Parser, il: *InitList, init_qt: QualType, l_brace: TokenI
try p.err(first_tok, .initializer_overrides, .{});
try p.err(item.il.tok, .previous_initializer, .{});
item.il.deinit(gpa);
- item.il.* = .{};
+ item.il.* = .empty;
}
try p.initializerItem(item.il, item.qt, inner_l_brace);
} else {
// discard further values
- var tmp_il: InitList = .{};
+ var tmp_il: InitList = .empty;
defer tmp_il.deinit(gpa);
try p.initializerItem(&tmp_il, .invalid, inner_l_brace);
if (!warned_excess) try p.err(first_tok, switch (init_qt.base(p.comp).type) {
diff --git a/lib/compiler/aro/aro/Toolchain.zig b/lib/compiler/aro/aro/Toolchain.zig
index 0aa9d76fc88a176f9ac5690fbf40dd0563b48aab..9a923c08461ddb36dc055f81de813ddaac90e99c 100644
--- a/lib/compiler/aro/aro/Toolchain.zig
+++ b/lib/compiler/aro/aro/Toolchain.zig
@@ -43,13 +43,13 @@ const Toolchain = @This();
driver: *Driver,
/// The list of toolchain specific path prefixes to search for libraries.
-library_paths: PathList = .{},
+library_paths: PathList = .empty,
/// The list of toolchain specific path prefixes to search for files.
-file_paths: PathList = .{},
+file_paths: PathList = .empty,
/// The list of toolchain specific path prefixes to search for programs.
-program_paths: PathList = .{},
+program_paths: PathList = .empty,
selected_multilib: Multilib = .{},
diff --git a/lib/compiler/objcopy.zig b/lib/compiler/objcopy.zig
index 57d019bc95b8887c9bce708d6be08fb3abc9205a..9c3fffc67f07b8e6c918d554747ba6a421ba026d 100644
--- a/lib/compiler/objcopy.zig
+++ b/lib/compiler/objcopy.zig
@@ -388,8 +388,8 @@ const BinaryElfOutput = struct {
pub fn parse(allocator: Allocator, in: *File.Reader, elf_hdr: elf.Header) !Self {
var self: Self = .{
- .segments = .{},
- .sections = .{},
+ .segments = .empty,
+ .sections = .empty,
.allocator = allocator,
.shstrtab = null,
};
diff --git a/lib/compiler/resinator/cvtres.zig b/lib/compiler/resinator/cvtres.zig
index 26b6620af23224ab147ad7ceeafe802bfcb1ae46..6973be714c66540f51a6633ba8c9affff6085a26 100644
--- a/lib/compiler/resinator/cvtres.zig
+++ b/lib/compiler/resinator/cvtres.zig
@@ -410,7 +410,7 @@ pub const ResourceDirectoryTable = extern struct {
};
pub const ResourceDirectoryEntry = extern struct {
- entry: packed union {
+ entry: packed union(u32) {
name_offset: packed struct(u32) {
address: u31,
/// This is undocumented in the PE/COFF spec, but the high bit
diff --git a/lib/compiler/test_runner.zig b/lib/compiler/test_runner.zig
index 899b5dafbfb7fa2683854b81ff198eb2a7be4573..db8958519a4d44ef96cd006980146276b93d29cf 100644
--- a/lib/compiler/test_runner.zig
+++ b/lib/compiler/test_runner.zig
@@ -38,10 +38,10 @@ pub fn main(init: std.process.Init.Minimal) void {
}
if (need_simple) {
- return mainSimple() catch @panic("test failure");
+ return mainSimple() catch |err| std.debug.panic("test failure: {t}", .{err});
}
- const args = init.args.toSlice(fba.allocator()) catch @panic("unable to parse command line args");
+ const args = init.args.toSlice(fba.allocator()) catch |err| std.debug.panic("unable to parse command line args: {t}", .{err});
var listen = false;
var opt_cache_dir: ?[]const u8 = null;
@@ -55,7 +55,7 @@ pub fn main(init: std.process.Init.Minimal) void {
} else if (std.mem.startsWith(u8, arg, "--cache-dir")) {
opt_cache_dir = arg["--cache-dir=".len..];
} else {
- @panic("unrecognized command line argument");
+ std.debug.panic("unrecognized command line argument: {s}", .{arg});
}
}
@@ -65,7 +65,7 @@ pub fn main(init: std.process.Init.Minimal) void {
}
if (listen) {
- return mainServer(init) catch @panic("internal test runner failure");
+ return mainServer(init) catch |err| std.debug.panic("internal test runner failure: {t}", .{err});
} else {
return mainTerminal(init);
}
diff --git a/lib/std/Build/Fuzz.zig b/lib/std/Build/Fuzz.zig
index b2477f50884b34100e772960ca4a2c387ddd0008..e4104661add503c549ef09fbb3b16244683a9ce4 100644
--- a/lib/std/Build/Fuzz.zig
+++ b/lib/std/Build/Fuzz.zig
@@ -390,7 +390,7 @@ fn prepareTables(fuzz: *Fuzz, run_step: *Step.Run, coverage_id: u64) error{ OutO
.coverage = std.debug.Coverage.init,
.mapped_memory = undefined, // populated below
.source_locations = undefined, // populated below
- .entry_points = .{},
+ .entry_points = .empty,
.start_timestamp = ws.now(),
.start_n_runs = undefined, // populated below
};
@@ -450,7 +450,7 @@ fn prepareTables(fuzz: *Fuzz, run_step: *Step.Run, coverage_id: u64) error{ OutO
// Unfortunately the PCs array that LLVM gives us from the 8-bit PC
// counters feature is not sorted.
- var sorted_pcs: std.MultiArrayList(struct { pc: u64, index: u32, sl: Coverage.SourceLocation }) = .{};
+ var sorted_pcs: std.MultiArrayList(struct { pc: u64, index: u32, sl: Coverage.SourceLocation }) = .empty;
defer sorted_pcs.deinit(gpa);
try sorted_pcs.resize(gpa, pcs.len);
@memcpy(sorted_pcs.items(.pc), pcs);
diff --git a/lib/std/Build/Module.zig b/lib/std/Build/Module.zig
index 657f8bb74eed1773400caa86c66e0b36211fbe1c..959e110c4ad47a5ddd95a508f91a3b49c66636ea 100644
--- a/lib/std/Build/Module.zig
+++ b/lib/std/Build/Module.zig
@@ -275,18 +275,18 @@ pub fn init(
m.* = .{
.owner = owner,
.root_source_file = if (options.root_source_file) |lp| lp.dupe(owner) else null,
- .import_table = .{},
+ .import_table = .empty,
.resolved_target = options.target,
.optimize = options.optimize,
.link_libc = options.link_libc,
.link_libcpp = options.link_libcpp,
.dwarf_format = options.dwarf_format,
- .c_macros = .{},
- .include_dirs = .{},
- .lib_paths = .{},
- .rpaths = .{},
- .frameworks = .{},
- .link_objects = .{},
+ .c_macros = .empty,
+ .include_dirs = .empty,
+ .lib_paths = .empty,
+ .rpaths = .empty,
+ .frameworks = .empty,
+ .link_objects = .empty,
.strip = options.strip,
.unwind_tables = options.unwind_tables,
.single_threaded = options.single_threaded,
diff --git a/lib/std/Build/Step.zig b/lib/std/Build/Step.zig
index b518826843caad753b23051f92840af7b6143a22..5876614099b38b9608006650b464978a87443b6f 100644
--- a/lib/std/Build/Step.zig
+++ b/lib/std/Build/Step.zig
@@ -250,7 +250,7 @@ pub fn init(options: StepOptions) Step {
const first_ret_addr = options.first_ret_addr orelse @returnAddress();
break :blk std.debug.captureCurrentStackTrace(.{ .first_address = first_ret_addr }, addr_buf);
},
- .result_error_msgs = .{},
+ .result_error_msgs = .empty,
.result_error_bundle = std.zig.ErrorBundle.empty,
.result_stderr = "",
.result_cached = false,
diff --git a/lib/std/Build/Step/Run.zig b/lib/std/Build/Step/Run.zig
index 8a21e6fef9b3da523b2ad087008b805c7da0e676..63c9f4e6d4c823a32d0d348935c44be2cec84eb9 100644
--- a/lib/std/Build/Step/Run.zig
+++ b/lib/std/Build/Step/Run.zig
@@ -213,13 +213,13 @@ pub fn create(owner: *std.Build, name: []const u8) *Run {
.owner = owner,
.makeFn = make,
}),
- .argv = .{},
+ .argv = .empty,
.cwd = null,
.environ_map = null,
.disable_zig_progress = false,
.stdio = .infer_from_args,
.stdin = .none,
- .file_inputs = .{},
+ .file_inputs = .empty,
.rename_step_with_output_arg = true,
.skip_foreign_checks = false,
.failing_to_execute_foreign_is_an_error = true,
@@ -228,7 +228,7 @@ pub fn create(owner: *std.Build, name: []const u8) *Run {
.captured_stderr = null,
.dep_output_file = null,
.has_side_effects = false,
- .fuzz_tests = .{},
+ .fuzz_tests = .empty,
.rebuilt_executable = null,
.producer = null,
};
@@ -642,7 +642,7 @@ pub fn addCheck(run: *Run, new_check: StdIo.Check) void {
switch (run.stdio) {
.infer_from_args => {
- run.stdio = .{ .check = .{} };
+ run.stdio = .{ .check = .empty };
run.stdio.check.append(b.allocator, new_check) catch @panic("OOM");
},
.check => |*checks| checks.append(b.allocator, new_check) catch @panic("OOM"),
diff --git a/lib/std/Build/Step/UpdateSourceFiles.zig b/lib/std/Build/Step/UpdateSourceFiles.zig
index 1c4c94f9cf65c1167d72a0ac92c8c5c9ec17a805..0cc3b787c3f8416c284b0977ea9e73b9bf405fd7 100644
--- a/lib/std/Build/Step/UpdateSourceFiles.zig
+++ b/lib/std/Build/Step/UpdateSourceFiles.zig
@@ -35,7 +35,7 @@ pub fn create(owner: *std.Build) *UpdateSourceFiles {
.owner = owner,
.makeFn = make,
}),
- .output_source_files = .{},
+ .output_source_files = .empty,
};
return usf;
}
diff --git a/lib/std/Build/Step/WriteFile.zig b/lib/std/Build/Step/WriteFile.zig
index 0c0e2b5d8637c10a5c6acae515927c84d690c371..3613fa3fef8fa5ac1a5587a4c4cdcca96661b7b6 100644
--- a/lib/std/Build/Step/WriteFile.zig
+++ b/lib/std/Build/Step/WriteFile.zig
@@ -94,8 +94,8 @@ pub fn create(owner: *std.Build) *WriteFile {
.owner = owner,
.makeFn = make,
}),
- .files = .{},
- .directories = .{},
+ .files = .empty,
+ .directories = .empty,
.generated_directory = .{ .step = &write_file.step },
};
return write_file;
diff --git a/lib/std/Io/Dir.zig b/lib/std/Io/Dir.zig
index 85ab6b77d4990420c32086efaf634dc0fc830938..3e38849f7f60fa80cdd4b3903ccc4e5f07ad4d12 100644
--- a/lib/std/Io/Dir.zig
+++ b/lib/std/Io/Dir.zig
@@ -334,7 +334,7 @@ pub fn walkSelectively(dir: Dir, allocator: Allocator) !SelectiveWalker {
return .{
.stack = stack,
- .name_buffer = .{},
+ .name_buffer = .empty,
.allocator = allocator,
};
}
diff --git a/lib/std/array_list.zig b/lib/std/array_list.zig
index f15388d7b5df62c3112b4ab0902ee587425c0442..d763233beda0ec7805ed71af07932bfe88fecf8a 100644
--- a/lib/std/array_list.zig
+++ b/lib/std/array_list.zig
@@ -582,10 +582,10 @@ pub fn Aligned(comptime T: type, comptime alignment: ?mem.Alignment) type {
/// functions of this ArrayList in accordance with the respective
/// documentation. In all cases, "invalidated" means that the memory
/// has been passed to an allocator's resize or free function.
- items: Slice = &[_]T{},
+ items: Slice,
/// How many T values this list can hold without allocating
/// additional memory.
- capacity: usize = 0,
+ capacity: usize,
/// An ArrayList containing no elements.
pub const empty: Self = .{
diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig
index e10935f0c6a6fa15da09bf0611463a4d4347e6cc..00ae6199d1d9cdf96e8202a29b3f0b7385b5d387 100644
--- a/lib/std/builtin.zig
+++ b/lib/std/builtin.zig
@@ -592,8 +592,8 @@ pub const Type = union(enum) {
size: Size,
is_const: bool,
is_volatile: bool,
- /// TODO make this u16 instead of comptime_int
- alignment: comptime_int,
+ /// `null` means implicit alignment, which is equivalent to `@alignOf(child)`.
+ alignment: ?usize,
address_space: AddressSpace,
child: type,
is_allowzero: bool,
@@ -670,7 +670,9 @@ pub const Type = union(enum) {
/// See also: `defaultValue`.
default_value_ptr: ?*const anyopaque,
is_comptime: bool,
- alignment: comptime_int,
+ /// `null` means the field alignment was not explicitly specified. The
+ /// field will still be aligned to at least `@alignOf` its `type`.
+ alignment: ?usize,
/// Loads the field's default value from `default_value_ptr`.
/// Returns `null` if the field has no default value.
@@ -747,7 +749,9 @@ pub const Type = union(enum) {
pub const UnionField = struct {
name: [:0]const u8,
type: type,
- alignment: comptime_int,
+ /// `null` means the field alignment was not explicitly specified. The
+ /// field will still be aligned to at least `@alignOf` its `type`.
+ alignment: ?usize,
/// This data structure is used by the Zig language code generation and
/// therefore must be kept in sync with the compiler implementation.
diff --git a/lib/std/c/darwin.zig b/lib/std/c/darwin.zig
index f18b61187c92fb2ddfb2ed4d4e922aaa957632fc..452411c52e94af5122ce5265edf95689f54f2b5c 100644
--- a/lib/std/c/darwin.zig
+++ b/lib/std/c/darwin.zig
@@ -436,7 +436,7 @@ pub const thread_state_flavor_t = c_int;
pub const ipc_space_t = mach_port_t;
pub const ipc_space_port_t = ipc_space_t;
-pub const mach_msg_option_t = packed union {
+pub const mach_msg_option_t = packed union(integer_t) {
RCV: MACH.RCV,
SEND: MACH.SEND,
diff --git a/lib/std/c/darwin/dispatch.zig b/lib/std/c/darwin/dispatch.zig
index 68b0b48782b02295064a6362b9ed0e249a92659e..770eadf7170f915d877d3d079c7d13b9585ae0a1 100644
--- a/lib/std/c/darwin/dispatch.zig
+++ b/lib/std/c/darwin/dispatch.zig
@@ -210,7 +210,7 @@ pub const source_timer_flags_t = packed struct(usize) {
STRICT: bool = false,
unused1: @Int(.unsigned, @bitSizeOf(usize) - 1) = 0,
};
-pub const source_flags_t = packed union {
+pub const source_flags_t = packed union(usize) {
raw: usize,
MACH_SEND: source_mach_send_flags_t,
MACH_RECV: source_mach_recv_flags_t,
diff --git a/lib/std/compress/lzma.zig b/lib/std/compress/lzma.zig
index 7a586298bea5f7b3db346ce9e5cccb834cb05e47..4e3c6146167868e04f257cdec38cb9eb83ae642a 100644
--- a/lib/std/compress/lzma.zig
+++ b/lib/std/compress/lzma.zig
@@ -349,7 +349,7 @@ pub const Decode = struct {
pub fn init(dict_size: usize, mem_limit: usize) CircularBuffer {
return .{
- .buf = .{},
+ .buf = .empty,
.dict_size = dict_size,
.mem_limit = mem_limit,
.cursor = 0,
diff --git a/lib/std/compress/lzma2.zig b/lib/std/compress/lzma2.zig
index 7d743f9a1b6c87c06b0aeca93cd8019eb0b75404..42c887c042bac9b239036e2f7bbfbb1657966b20 100644
--- a/lib/std/compress/lzma2.zig
+++ b/lib/std/compress/lzma2.zig
@@ -16,7 +16,7 @@ pub const AccumBuffer = struct {
pub fn init(memlimit: usize) AccumBuffer {
return .{
- .buf = .{},
+ .buf = .empty,
.memlimit = memlimit,
.len = 0,
};
diff --git a/lib/std/debug/Coverage.zig b/lib/std/debug/Coverage.zig
index 81dfce853e0e66c706be73f09407de80d37f339f..b3e16382cc45dff17d34b9bf57f7accb63d918e5 100644
--- a/lib/std/debug/Coverage.zig
+++ b/lib/std/debug/Coverage.zig
@@ -27,10 +27,10 @@ string_bytes: std.ArrayList(u8),
mutex: Io.Mutex,
pub const init: Coverage = .{
- .directories = .{},
- .files = .{},
+ .directories = .empty,
+ .files = .empty,
.mutex = .init,
- .string_bytes = .{},
+ .string_bytes = .empty,
};
pub const String = enum(u32) {
diff --git a/lib/std/elf.zig b/lib/std/elf.zig
index 962e0ceb9e22f655c9542c94928c98691d63a4fb..b9ddf88123e6a6d6c4aa5b5691e92a0dd6370b3e 100644
--- a/lib/std/elf.zig
+++ b/lib/std/elf.zig
@@ -1071,7 +1071,7 @@ pub const Elf32 = struct {
pub const Shdr = extern struct {
name: Word,
type: SHT,
- flags: packed struct { shf: SHF },
+ flags: packed struct(Word) { shf: SHF },
addr: Elf32.Addr,
offset: Elf32.Off,
size: Word,
@@ -1161,7 +1161,7 @@ pub const Elf64 = struct {
pub const Shdr = extern struct {
name: Word,
type: SHT,
- flags: packed struct { shf: SHF, unused: Word = 0 },
+ flags: packed struct(Xword) { shf: SHF, unused: Word = 0 },
addr: Elf64.Addr,
offset: Elf64.Off,
size: Xword,
diff --git a/lib/std/hash_map.zig b/lib/std/hash_map.zig
index 58c9397a6b9955a7c0aefc2368a49cbd160cf68d..cb74cbc08b6eb554ff20eb5fe0c920a821ec51e0 100644
--- a/lib/std/hash_map.zig
+++ b/lib/std/hash_map.zig
@@ -1526,9 +1526,9 @@ pub fn HashMapUnmanaged(
}
comptime {
- if (!builtin.strip_debug_info) _ = switch (builtin.zig_backend) {
- .stage2_llvm => &dbHelper,
- .stage2_x86_64 => KV,
+ if (!builtin.strip_debug_info) switch (builtin.zig_backend) {
+ .stage2_llvm => _ = &dbHelper,
+ .stage2_x86_64 => _ = @as(KV, undefined),
else => {},
};
}
diff --git a/lib/std/macho.zig b/lib/std/macho.zig
index 57f892bdf7bb3f3be0c8b32a798b8fd305c14e15..9fdce9dd6605f450ab7eb9fee2b19b4f3787783d 100644
--- a/lib/std/macho.zig
+++ b/lib/std/macho.zig
@@ -851,7 +851,7 @@ pub const nlist = extern struct {
pub const nlist_64 = extern struct {
n_strx: u32,
- n_type: packed union {
+ n_type: packed union(u8) {
bits: packed struct(u8) {
ext: bool,
type: enum(u3) {
diff --git a/lib/std/math/big/int.zig b/lib/std/math/big/int.zig
index 96fee84ddf2c6459a72b6823d4a0ea513a113270..9fc50c9e5b1ce4be1f0013af0f906cdd8d0920e2 100644
--- a/lib/std/math/big/int.zig
+++ b/lib/std/math/big/int.zig
@@ -924,7 +924,12 @@ pub const Mutable = struct {
/// Asserts the result fits in `r`. Upper bound on the number of limbs needed by
/// r is `calcTwosCompLimbCount(bit_count)`.
pub fn bitReverse(r: *Mutable, a: Const, signedness: Signedness, bit_count: usize) void {
- if (bit_count == 0) return;
+ if (bit_count == 0) {
+ r.limbs[0] = 0;
+ r.len = 1;
+ r.positive = true;
+ return;
+ }
r.copy(a);
@@ -986,7 +991,12 @@ pub const Mutable = struct {
/// Asserts the result fits in `r`. Upper bound on the number of limbs needed by
/// r is `calcTwosCompLimbCount(8*byte_count)`.
pub fn byteSwap(r: *Mutable, a: Const, signedness: Signedness, byte_count: usize) void {
- if (byte_count == 0) return;
+ if (byte_count == 0) {
+ r.limbs[0] = 0;
+ r.len = 1;
+ r.positive = true;
+ return;
+ }
r.copy(a);
const limbs_required = calcTwosCompLimbCount(8 * byte_count);
diff --git a/lib/std/mem.zig b/lib/std/mem.zig
index cc03e5b2c54ccd67ccefe7e854a4385f614f1dae..4b34ad12385bc77b2d67f988d60cde2d9a277027 100644
--- a/lib/std/mem.zig
+++ b/lib/std/mem.zig
@@ -38,6 +38,10 @@ pub const Alignment = enum(math.Log2Int(usize)) {
return @enumFromInt(@ctz(n));
}
+ pub fn fromByteUnitsOptional(maybe_n: ?usize) ?Alignment {
+ return if (maybe_n) |n| .fromByteUnits(n) else null;
+ }
+
pub inline fn of(comptime T: type) Alignment {
return comptime fromByteUnits(@alignOf(T));
}
@@ -2287,8 +2291,8 @@ pub fn byteSwapAllFieldsAligned(comptime S: type, comptime a: Alignment, ptr: *a
ptr.* = @bitCast(@byteSwap(@as(Int, @bitCast(ptr.*))));
} else inline for (std.meta.fields(S)) |f| {
switch (@typeInfo(f.type)) {
- .@"struct" => byteSwapAllFieldsAligned(f.type, .fromByteUnits(f.alignment), &@field(ptr, f.name)),
- .@"union", .array => byteSwapAllFieldsAligned(f.type, .fromByteUnits(f.alignment), &@field(ptr, f.name)),
+ .@"struct" => byteSwapAllFieldsAligned(f.type, .fromByteUnits(f.alignment orelse @alignOf(f.type)), &@field(ptr, f.name)),
+ .@"union", .array => byteSwapAllFieldsAligned(f.type, .fromByteUnits(f.alignment orelse @alignOf(f.type)), &@field(ptr, f.name)),
.@"enum" => {
@field(ptr, f.name) = @enumFromInt(@byteSwap(@intFromEnum(@field(ptr, f.name))));
},
@@ -4330,7 +4334,7 @@ pub fn alignPointerOffset(ptr: anytype, align_to: usize) ?usize {
@compileError("expected many item pointer, got " ++ @typeName(T));
// Do nothing if the pointer is already well-aligned.
- if (align_to <= info.pointer.alignment)
+ if (align_to <= info.pointer.alignment orelse @alignOf(info.pointer.child))
return 0;
// Calculate the aligned base address with an eye out for overflow.
@@ -4388,7 +4392,11 @@ fn CopyPtrAttrs(
.@"const" = ptr.is_const,
.@"volatile" = ptr.is_volatile,
.@"allowzero" = ptr.is_allowzero,
- .@"align" = ptr.alignment,
+ .@"align" = ptr.alignment orelse a: {
+ // If the new child is aligned differently than the old one, explicitly align the type.
+ const want = @alignOf(ptr.child);
+ break :a if (@alignOf(child) == want) null else want;
+ },
.@"addrspace" = ptr.address_space,
}, child, null);
}
diff --git a/lib/std/mem/Allocator.zig b/lib/std/mem/Allocator.zig
index db1ea978eaf21d31fa846db8dc591fb9749f746d..caf049f296fbc3f9a7fb1d92dc0dd0aa98e571ff 100644
--- a/lib/std/mem/Allocator.zig
+++ b/lib/std/mem/Allocator.zig
@@ -179,7 +179,11 @@ pub fn destroy(self: Allocator, ptr: anytype) void {
const T = info.child;
if (@sizeOf(T) == 0) return;
const non_const_ptr = @as([*]u8, @ptrCast(@constCast(ptr)));
- self.rawFree(non_const_ptr[0..@sizeOf(T)], .fromByteUnits(info.alignment), @returnAddress());
+ self.rawFree(
+ non_const_ptr[0..@sizeOf(T)],
+ .fromByteUnits(info.alignment orelse @alignOf(T)),
+ @returnAddress(),
+ );
}
/// Allocates an array of `n` items of type `T` and sets all the
@@ -266,7 +270,7 @@ pub inline fn allocAdvancedWithRetAddr(
n: usize,
return_address: usize,
) Error![]align(if (alignment) |a| a.toByteUnits() else @alignOf(T)) T {
- const a = comptime (alignment orelse Alignment.of(T));
+ const a: Alignment = alignment orelse comptime .of(T);
const ptr: [*]align(a.toByteUnits()) T = @ptrCast(try self.allocWithSizeAndAlignment(@sizeOf(T), a, n, return_address));
return ptr[0..n];
}
@@ -278,7 +282,7 @@ fn allocWithSizeAndAlignment(
n: usize,
return_address: usize,
) Error![*]align(alignment.toByteUnits()) u8 {
- const byte_count = math.mul(usize, size, n) catch return Error.OutOfMemory;
+ const byte_count = math.mul(usize, size, n) catch return error.OutOfMemory;
return self.allocBytesWithAlignment(alignment, byte_count, return_address);
}
@@ -293,7 +297,7 @@ fn allocBytesWithAlignment(
return @as([*]align(alignment.toByteUnits()) u8, @ptrFromInt(ptr));
}
- const byte_ptr = self.rawAlloc(byte_count, alignment, return_address) orelse return Error.OutOfMemory;
+ const byte_ptr = self.rawAlloc(byte_count, alignment, return_address) orelse return error.OutOfMemory;
@memset(byte_ptr[0..byte_count], undefined);
return @alignCast(byte_ptr);
}
@@ -308,9 +312,9 @@ fn allocBytesWithAlignment(
///
/// `new_len` may be zero, in which case the allocation is freed.
pub fn resize(self: Allocator, allocation: anytype, new_len: usize) bool {
- const Slice = @typeInfo(@TypeOf(allocation)).pointer;
- const T = Slice.child;
- const alignment = Slice.alignment;
+ const slice_info = @typeInfo(@TypeOf(allocation)).pointer;
+ comptime assert(slice_info.size == .slice);
+ const T = slice_info.child;
if (new_len == 0) {
self.free(allocation);
return true;
@@ -323,7 +327,12 @@ pub fn resize(self: Allocator, allocation: anytype, new_len: usize) bool {
// on WebAssembly: https://github.com/ziglang/zig/issues/9660
//const new_len_bytes = new_len *| @sizeOf(T);
const new_len_bytes = math.mul(usize, @sizeOf(T), new_len) catch return false;
- return self.rawResize(old_memory, .fromByteUnits(alignment), new_len_bytes, @returnAddress());
+ return self.rawResize(
+ old_memory,
+ .fromByteUnits(slice_info.alignment orelse @alignOf(T)),
+ new_len_bytes,
+ @returnAddress(),
+ );
}
/// Request to modify the size of an allocation, allowing relocation.
@@ -342,14 +351,11 @@ pub fn resize(self: Allocator, allocation: anytype, new_len: usize) bool {
/// `new_len` may be zero, in which case the allocation is freed.
///
/// If the allocation's elements' type is zero bytes sized, `allocation.len` is set to `new_len`.
-pub fn remap(self: Allocator, allocation: anytype, new_len: usize) t: {
- const Slice = @typeInfo(@TypeOf(allocation)).pointer;
- break :t ?[]align(Slice.alignment) Slice.child;
-} {
- const Slice = @typeInfo(@TypeOf(allocation)).pointer;
- const T = Slice.child;
+pub fn remap(self: Allocator, allocation: anytype, new_len: usize) ?@TypeOf(allocation) {
+ const slice_info = @typeInfo(@TypeOf(allocation)).pointer;
+ comptime assert(slice_info.size == .slice);
+ const T = slice_info.child;
- const alignment = Slice.alignment;
if (new_len == 0) {
self.free(allocation);
return allocation[0..0];
@@ -367,9 +373,13 @@ pub fn remap(self: Allocator, allocation: anytype, new_len: usize) t: {
// on WebAssembly: https://github.com/ziglang/zig/issues/9660
//const new_len_bytes = new_len *| @sizeOf(T);
const new_len_bytes = math.mul(usize, @sizeOf(T), new_len) catch return null;
- const new_ptr = self.rawRemap(old_memory, .fromByteUnits(alignment), new_len_bytes, @returnAddress()) orelse return null;
- const new_memory: []align(alignment) u8 = @alignCast(new_ptr[0..new_len_bytes]);
- return mem.bytesAsSlice(T, new_memory);
+ const new_ptr = self.rawRemap(
+ old_memory,
+ .fromByteUnits(slice_info.alignment orelse @alignOf(T)),
+ new_len_bytes,
+ @returnAddress(),
+ ) orelse return null;
+ return @ptrCast(@alignCast(new_ptr[0..new_len_bytes]));
}
/// This function requests a new size for an existing allocation, which
@@ -386,10 +396,7 @@ pub fn remap(self: Allocator, allocation: anytype, new_len: usize) t: {
/// do the realloc more efficiently than the caller
/// * `resize` which returns `false` when the `Allocator` implementation cannot
/// change the size without relocating the allocation.
-pub fn realloc(self: Allocator, old_mem: anytype, new_n: usize) t: {
- const Slice = @typeInfo(@TypeOf(old_mem)).pointer;
- break :t Error![]align(Slice.alignment) Slice.child;
-} {
+pub fn realloc(self: Allocator, old_mem: anytype, new_n: usize) Error!@TypeOf(old_mem) {
return self.reallocAdvanced(old_mem, new_n, @returnAddress());
}
@@ -398,51 +405,49 @@ pub fn reallocAdvanced(
old_mem: anytype,
new_n: usize,
return_address: usize,
-) t: {
- const Slice = @typeInfo(@TypeOf(old_mem)).pointer;
- break :t Error![]align(Slice.alignment) Slice.child;
-} {
- const Slice = @typeInfo(@TypeOf(old_mem)).pointer;
- const T = Slice.child;
+) Error!@TypeOf(old_mem) {
+ const slice_info = @typeInfo(@TypeOf(old_mem)).pointer;
+ comptime assert(slice_info.size == .slice);
+ const T = slice_info.child;
if (old_mem.len == 0) {
- return self.allocAdvancedWithRetAddr(T, .fromByteUnits(Slice.alignment), new_n, return_address);
+ return self.allocAdvancedWithRetAddr(T, .fromByteUnitsOptional(slice_info.alignment), new_n, return_address);
}
if (new_n == 0) {
self.free(old_mem);
- const ptr = comptime std.mem.alignBackward(usize, math.maxInt(usize), Slice.alignment);
- return @as([*]align(Slice.alignment) T, @ptrFromInt(ptr))[0..0];
+ const alignment = slice_info.alignment orelse @alignOf(T);
+ const addr = comptime std.mem.alignBackward(usize, math.maxInt(usize), alignment);
+ const ptr: *align(alignment) [0]T = @ptrFromInt(addr);
+ return ptr;
}
const old_byte_slice = mem.sliceAsBytes(old_mem);
- const byte_count = math.mul(usize, @sizeOf(T), new_n) catch return Error.OutOfMemory;
+ const byte_count = math.mul(usize, @sizeOf(T), new_n) catch return error.OutOfMemory;
// Note: can't set shrunk memory to undefined as memory shouldn't be modified on realloc failure
- if (self.rawRemap(old_byte_slice, .fromByteUnits(Slice.alignment), byte_count, return_address)) |p| {
- const new_bytes: []align(Slice.alignment) u8 = @alignCast(p[0..byte_count]);
- return mem.bytesAsSlice(T, new_bytes);
+ if (self.rawRemap(old_byte_slice, .fromByteUnits(slice_info.alignment orelse @alignOf(T)), byte_count, return_address)) |p| {
+ return @ptrCast(@alignCast(p[0..byte_count]));
}
- const new_mem = self.rawAlloc(byte_count, .fromByteUnits(Slice.alignment), return_address) orelse
+ const new_mem = self.rawAlloc(byte_count, .fromByteUnits(slice_info.alignment orelse @alignOf(T)), return_address) orelse
return error.OutOfMemory;
const copy_len = @min(byte_count, old_byte_slice.len);
@memcpy(new_mem[0..copy_len], old_byte_slice[0..copy_len]);
@memset(old_byte_slice, undefined);
- self.rawFree(old_byte_slice, .fromByteUnits(Slice.alignment), return_address);
+ self.rawFree(old_byte_slice, .fromByteUnits(slice_info.alignment orelse @alignOf(T)), return_address);
- const new_bytes: []align(Slice.alignment) u8 = @alignCast(new_mem[0..byte_count]);
- return mem.bytesAsSlice(T, new_bytes);
+ return @ptrCast(@alignCast(new_mem[0..byte_count]));
}
/// Free an array allocated with `alloc`.
/// If memory has length 0, free is a no-op.
/// To free a single item, see `destroy`.
pub fn free(self: Allocator, memory: anytype) void {
- const Slice = @typeInfo(@TypeOf(memory)).pointer;
- const bytes = mem.sliceAsBytes(memory);
- const bytes_len = bytes.len + if (Slice.sentinel() != null) @sizeOf(Slice.child) else 0;
- if (bytes_len == 0) return;
- const non_const_ptr = @constCast(bytes.ptr);
- @memset(non_const_ptr[0..bytes_len], undefined);
- self.rawFree(non_const_ptr[0..bytes_len], .fromByteUnits(Slice.alignment), @returnAddress());
+ const slice_info = @typeInfo(@TypeOf(memory)).pointer;
+ comptime assert(slice_info.size == .slice);
+ const mem_with_sent = memory[0 .. memory.len + @intFromBool(slice_info.sentinel() != null)];
+ const bytes: []u8 = @ptrCast(@constCast(mem_with_sent));
+ if (bytes.len == 0) return;
+ @memset(bytes, undefined);
+ self.rawFree(bytes, .fromByteUnits(slice_info.alignment orelse @alignOf(slice_info.child)), @returnAddress());
}
/// Copies `m` to newly allocated memory. Caller owns the memory.
diff --git a/lib/std/meta.zig b/lib/std/meta.zig
index f1afa9bc7a049c5e4e13546e307b551e93e863c9..632c65678f28107c8f20444c68a74d27cae02309 100644
--- a/lib/std/meta.zig
+++ b/lib/std/meta.zig
@@ -63,7 +63,7 @@ pub fn alignment(comptime T: type) comptime_int {
.pointer, .@"fn" => alignment(info.child),
else => @alignOf(T),
},
- .pointer => |info| info.alignment,
+ .pointer => |info| info.alignment orelse @alignOf(info.child),
else => @alignOf(T),
};
}
@@ -315,7 +315,7 @@ test declarationInfo {
try testing.expect(comptime mem.eql(u8, info.name, "a"));
}
}
-pub fn fields(comptime T: type) switch (@typeInfo(T)) {
+pub inline fn fields(comptime T: type) switch (@typeInfo(T)) {
.@"struct" => []const Type.StructField,
.@"union" => []const Type.UnionField,
.@"enum" => []const Type.EnumField,
diff --git a/lib/std/multi_array_list.zig b/lib/std/multi_array_list.zig
index 990b85a238ebf056ad7031c92db088ae366c5eb4..fde7e93ed652c3d6d360516e9441ece0ca88dacc 100644
--- a/lib/std/multi_array_list.zig
+++ b/lib/std/multi_array_list.zig
@@ -19,7 +19,11 @@ const testing = std.testing;
/// For unions you can call `.items(.tags)` or `.items(.data)`.
pub fn MultiArrayList(comptime T: type) type {
return struct {
- bytes: [*]align(@alignOf(T)) u8 = undefined,
+ /// This pointer is always aligned to the boundary `sizes.big_align`; this is not specified
+ /// in the type to avoid `MultiArrayList(T)` depending on the alignment of `T` because this
+ /// can lead to dependency loops. See `allocatedBytes` which `@alignCast`s this pointer to
+ /// the correct type.
+ bytes: [*]u8 = undefined,
len: usize = 0,
capacity: usize = 0,
@@ -133,10 +137,8 @@ pub fn MultiArrayList(comptime T: type) type {
if (self.ptrs.len == 0 or self.capacity == 0) {
return .{};
}
- const unaligned_ptr = self.ptrs[sizes.fields[0]];
- const aligned_ptr: [*]align(@alignOf(Elem)) u8 = @alignCast(unaligned_ptr);
return .{
- .bytes = aligned_ptr,
+ .bytes = self.ptrs[sizes.fields[0]],
.len = self.len,
.capacity = self.capacity,
};
@@ -179,6 +181,7 @@ pub fn MultiArrayList(comptime T: type) type {
const fields = meta.fields(Elem);
/// `sizes.bytes` is an array of @sizeOf each T field. Sorted by alignment, descending.
/// `sizes.fields` is an array mapping from `sizes.bytes` array index to field index.
+ /// `sizes.big_align` is the overall alignment of the allocation, which equals the maximum field alignment.
const sizes = blk: {
const Data = struct {
size: usize,
@@ -186,12 +189,14 @@ pub fn MultiArrayList(comptime T: type) type {
alignment: usize,
};
var data: [fields.len]Data = undefined;
+ var big_align: usize = 1;
for (fields, 0..) |field_info, i| {
data[i] = .{
.size = @sizeOf(field_info.type),
.size_index = i,
- .alignment = if (@sizeOf(field_info.type) == 0) 1 else field_info.alignment,
+ .alignment = field_info.alignment orelse @alignOf(field_info.type),
};
+ big_align = @max(big_align, data[i].alignment);
}
const Sort = struct {
fn lessThan(context: void, lhs: Data, rhs: Data) bool {
@@ -210,6 +215,7 @@ pub fn MultiArrayList(comptime T: type) type {
break :blk .{
.bytes = sizes_bytes,
.fields = field_indexes,
+ .big_align = mem.Alignment.fromByteUnits(big_align),
};
};
@@ -452,7 +458,7 @@ pub fn MultiArrayList(comptime T: type) type {
assert(new_len <= self.capacity);
assert(new_len <= self.len);
- const other_bytes = gpa.alignedAlloc(u8, .of(Elem), capacityInBytes(new_len)) catch {
+ const other_bytes = gpa.alignedAlloc(u8, sizes.big_align, capacityInBytes(new_len)) catch {
const self_slice = self.slice();
inline for (fields, 0..) |field_info, i| {
if (@sizeOf(field_info.type) != 0) {
@@ -533,7 +539,7 @@ pub fn MultiArrayList(comptime T: type) type {
/// `new_capacity` must be greater or equal to `len`.
pub fn setCapacity(self: *Self, gpa: Allocator, new_capacity: usize) Allocator.Error!void {
assert(new_capacity >= self.len);
- const new_bytes = try gpa.alignedAlloc(u8, .of(Elem), capacityInBytes(new_capacity));
+ const new_bytes = try gpa.alignedAlloc(u8, sizes.big_align, capacityInBytes(new_capacity));
if (self.len == 0) {
gpa.free(self.allocatedBytes());
self.bytes = new_bytes.ptr;
@@ -650,8 +656,8 @@ pub fn MultiArrayList(comptime T: type) type {
return elem_bytes * capacity;
}
- fn allocatedBytes(self: Self) []align(@alignOf(Elem)) u8 {
- return self.bytes[0..capacityInBytes(self.capacity)];
+ fn allocatedBytes(self: Self) []align(sizes.big_align.toByteUnits()) u8 {
+ return @alignCast(self.bytes[0..capacityInBytes(self.capacity)]);
}
fn FieldType(comptime field: Field) type {
diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig
index cbe085a3af73ded631610881042cf0ed43844767..b884e8ea793d190ad8684824296656cf7ab86171 100644
--- a/lib/std/os/linux.zig
+++ b/lib/std/os/linux.zig
@@ -7113,7 +7113,7 @@ pub const io_uring_buf_reg = extern struct {
flags: Flags,
resv: [3]u64,
- pub const Flags = packed struct {
+ pub const Flags = packed struct(u16) {
_0: u1 = 0,
/// Incremental buffer consumption.
inc: bool,
diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig
index 8832b1add949df3245eed397ff6f614c54c33d6e..6f2c8f49381ca695d388f87a4be5070e42271959 100644
--- a/lib/std/os/windows.zig
+++ b/lib/std/os/windows.zig
@@ -4160,7 +4160,7 @@ pub const RUNTIME_FUNCTION = switch (native_arch) {
BeginAddress: DWORD,
DUMMYUNIONNAME: extern union {
UnwindData: DWORD,
- DUMMYSTRUCTNAME: packed struct {
+ DUMMYSTRUCTNAME: packed struct(u32) {
Flag: u2,
FunctionLength: u11,
Ret: u2,
@@ -4177,7 +4177,7 @@ pub const RUNTIME_FUNCTION = switch (native_arch) {
BeginAddress: DWORD,
DUMMYUNIONNAME: extern union {
UnwindData: DWORD,
- DUMMYSTRUCTNAME: packed struct {
+ DUMMYSTRUCTNAME: packed struct(u32) {
Flag: u2,
FunctionLength: u11,
RegF: u3,
@@ -5013,7 +5013,7 @@ pub const KUSER_SHARED_DATA = extern struct {
KdDebuggerEnabled: BOOLEAN,
DummyUnion1: extern union {
MitigationPolicies: UCHAR,
- Alt: packed struct {
+ Alt: packed struct(u8) {
NXSupportPolicy: u2,
SEHValidationPolicy: u2,
CurDirDevicesSkippedForDlls: u2,
@@ -5029,7 +5029,7 @@ pub const KUSER_SHARED_DATA = extern struct {
SafeBootMode: BOOLEAN,
DummyUnion2: extern union {
VirtualizationFlags: UCHAR,
- Alt: packed struct {
+ Alt: packed struct(u8) {
ArchStartedInEl2: u1,
QcSlIsSupported: u1,
SpareBits: u6,
@@ -5038,7 +5038,7 @@ pub const KUSER_SHARED_DATA = extern struct {
Reserved12: [2]UCHAR,
DummyUnion3: extern union {
SharedDataFlags: ULONG,
- Alt: packed struct {
+ Alt: packed struct(u32) {
DbgErrorPortPresent: u1,
DbgElevationEnabled: u1,
DbgVirtEnabled: u1,
diff --git a/lib/std/pdb.zig b/lib/std/pdb.zig
index 7e479de8d4fe196594c6184b9721d11f31e2051d..094537972b3c7e7e560019f56178631f52663312 100644
--- a/lib/std/pdb.zig
+++ b/lib/std/pdb.zig
@@ -332,7 +332,7 @@ pub const ProcSym = extern struct {
name: [1]u8, // null-terminated
};
-pub const ProcSymFlags = packed struct {
+pub const ProcSymFlags = packed struct(u8) {
has_fp: bool,
has_iret: bool,
has_fret: bool,
@@ -373,7 +373,7 @@ pub const LineFragmentHeader = extern struct {
code_size: u32,
};
-pub const LineFlags = packed struct {
+pub const LineFlags = packed struct(u16) {
/// CV_LINES_HAVE_COLUMNS
have_columns: bool,
unused: u15,
diff --git a/lib/std/testing.zig b/lib/std/testing.zig
index 09919f8b69220c51607e875dee868ea6a048d1a5..bfb50039ea2272242ec911d739b00830bbc4360f 100644
--- a/lib/std/testing.zig
+++ b/lib/std/testing.zig
@@ -950,9 +950,8 @@ test "expectEqualDeep primitive type" {
}
test "expectEqualDeep pointer" {
- const a = 1;
- const b = 1;
- try expectEqualDeep(&a, &b);
+ try comptime expectEqualDeep(&1, &1);
+ try expectEqualDeep(&@as(u32, 1), &@as(u32, 1));
}
test "expectEqualDeep composite type" {
diff --git a/lib/std/zig.zig b/lib/std/zig.zig
index ba799c650e74229e4f3812fe67742bc0550b8925..ca72dac442f36a5d4858780e0e9d61e021a553b7 100644
--- a/lib/std/zig.zig
+++ b/lib/std/zig.zig
@@ -837,6 +837,10 @@ pub const SimpleComptimeReason = enum(u32) {
tuple_field_types,
enum_field_names,
enum_field_values,
+ union_enum_tag_type,
+ enum_int_tag_type,
+ packed_struct_backing_int_type,
+ packed_union_backing_int_type,
// Evaluating at comptime because decl/field name must be comptime-known.
decl_name,
@@ -864,7 +868,7 @@ pub const SimpleComptimeReason = enum(u32) {
casted_to_comptime_enum,
casted_to_comptime_int,
casted_to_comptime_float,
- panic_handler,
+ std_builtin_decl,
pub fn message(r: SimpleComptimeReason) []const u8 {
return switch (r) {
@@ -925,6 +929,11 @@ pub const SimpleComptimeReason = enum(u32) {
.enum_field_names => "enum field names must be comptime-known",
.enum_field_values => "enum field values must be comptime-known",
+ .union_enum_tag_type => "enum tag type of union must be comptime-known",
+ .enum_int_tag_type => "integer tag type of enum must be comptime-known",
+ .packed_struct_backing_int_type => "packed struct backing integer type must be comptime-known",
+ .packed_union_backing_int_type => "packed struct backing integer type must be comptime-known",
+
.decl_name => "declaration name must be comptime-known",
.field_name => "field name must be comptime-known",
.tuple_field_index => "tuple field index must be comptime-known",
@@ -948,7 +957,7 @@ pub const SimpleComptimeReason = enum(u32) {
.casted_to_comptime_enum => "value casted to enum with 'comptime_int' tag type must be comptime-known",
.casted_to_comptime_int => "value casted to 'comptime_int' must be comptime-known",
.casted_to_comptime_float => "value casted to 'comptime_float' must be comptime-known",
- .panic_handler => "panic handler must be comptime-known",
+ .std_builtin_decl => "'std.builtin' declaration values must be comptime-known",
// zig fmt: on
};
}
diff --git a/lib/std/zig/Ast.zig b/lib/std/zig/Ast.zig
index 3c039b5fe5a54be45e0ca9c4bcee2ba9699a7f57..8620df51fa0dea04e3c075951bf0df0c161dd363 100644
--- a/lib/std/zig/Ast.zig
+++ b/lib/std/zig/Ast.zig
@@ -175,10 +175,10 @@ pub fn parseTokens(
.source = source,
.gpa = gpa,
.tokens = tokens,
- .errors = .{},
- .nodes = .{},
- .extra_data = .{},
- .scratch = .{},
+ .errors = .empty,
+ .nodes = .empty,
+ .extra_data = .empty,
+ .scratch = .empty,
.tok_i = 0,
};
defer parser.errors.deinit(gpa);
diff --git a/lib/std/zig/AstGen.zig b/lib/std/zig/AstGen.zig
index 667f5ef045bd431512b3aed957be43e125ddb0ad..377c9fb8dc6eda208b5581264399180cec8388f8 100644
--- a/lib/std/zig/AstGen.zig
+++ b/lib/std/zig/AstGen.zig
@@ -1780,7 +1780,7 @@ fn structInitExpr(
try gop.value_ptr.append(sfba_allocator, name_token);
any_duplicate = true;
} else {
- gop.value_ptr.* = .{};
+ gop.value_ptr.* = .empty;
try gop.value_ptr.append(sfba_allocator, name_token);
}
}
@@ -3975,81 +3975,67 @@ fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.
return rvalue(gz, ri, result, node);
}
-const WipMembers = struct {
- payload: *ArrayList(u32),
- payload_top: usize,
- field_bits_start: u32,
- fields_start: u32,
- fields_end: u32,
- decl_index: u32 = 0,
- field_index: u32 = 0,
-
- const Self = @This();
-
- fn init(gpa: Allocator, payload: *ArrayList(u32), decl_count: u32, field_count: u32, comptime bits_per_field: u32, comptime max_field_size: u32) Allocator.Error!Self {
- const payload_top: u32 = @intCast(payload.items.len);
- const field_bits_start = payload_top + decl_count;
- const fields_start = field_bits_start + if (bits_per_field > 0) blk: {
- const fields_per_u32 = 32 / bits_per_field;
- break :blk (field_count + fields_per_u32 - 1) / fields_per_u32;
- } else 0;
- const payload_end = fields_start + field_count * max_field_size;
- try payload.resize(gpa, payload_end);
+const Scratch = struct {
+ astgen: *AstGen,
+ scratch_top: u32,
+ fn init(astgen: *AstGen) Scratch {
return .{
- .payload = payload,
- .payload_top = payload_top,
- .field_bits_start = field_bits_start,
- .fields_start = fields_start,
- .fields_end = fields_start,
+ .astgen = astgen,
+ .scratch_top = @intCast(astgen.scratch.items.len),
};
}
-
- fn nextDecl(self: *Self, decl_inst: Zir.Inst.Index) void {
- self.payload.items[self.payload_top + self.decl_index] = @intFromEnum(decl_inst);
- self.decl_index += 1;
+ fn reset(s: *Scratch) void {
+ s.astgen.scratch.shrinkRetainingCapacity(s.scratch_top);
+ s.* = undefined;
}
-
- fn nextField(self: *Self, comptime bits_per_field: u32, bits: [bits_per_field]bool) void {
- const fields_per_u32 = 32 / bits_per_field;
- const index = self.field_bits_start + self.field_index / fields_per_u32;
- assert(index < self.fields_start);
- var bit_bag: u32 = if (self.field_index % fields_per_u32 == 0) 0 else self.payload.items[index];
- bit_bag >>= bits_per_field;
- comptime var i = 0;
- inline while (i < bits_per_field) : (i += 1) {
- bit_bag |= @as(u32, @intFromBool(bits[i])) << (32 - bits_per_field + i);
- }
- self.payload.items[index] = bit_bag;
- self.field_index += 1;
+ fn addSlice(s: *Scratch, len: u32) Allocator.Error!Slice {
+ const start: u32 = @intCast(s.astgen.scratch.items.len);
+ try s.astgen.scratch.resize(s.astgen.gpa, start + len);
+ return .{ .start = start, .len = len };
}
-
- fn appendToField(self: *Self, data: u32) void {
- assert(self.fields_end < self.payload.items.len);
- self.payload.items[self.fields_end] = data;
- self.fields_end += 1;
+ fn addOptionalSlice(s: *Scratch, present: bool, len: u32) Allocator.Error!?Slice {
+ if (!present) return null;
+ return try addSlice(s, len);
}
-
- fn finishBits(self: *Self, comptime bits_per_field: u32) void {
- if (bits_per_field > 0) {
- const fields_per_u32 = 32 / bits_per_field;
- const empty_field_slots = fields_per_u32 - (self.field_index % fields_per_u32);
- if (self.field_index > 0 and empty_field_slots < fields_per_u32) {
- const index = self.field_bits_start + self.field_index / fields_per_u32;
- self.payload.items[index] >>= @intCast(empty_field_slots * bits_per_field);
- }
- }
+ fn appendBodyWithFixups(s: *Scratch, body: []const Zir.Inst.Index) Allocator.Error!u32 {
+ const len = countBodyLenAfterFixups(s.astgen, body);
+ try s.astgen.scratch.ensureUnusedCapacity(s.astgen.gpa, len);
+ appendBodyWithFixupsArrayList(s.astgen, &s.astgen.scratch, body);
+ return len;
}
-
- fn declsSlice(self: *Self) []u32 {
- return self.payload.items[self.payload_top..][0..self.decl_index];
+ /// Returns the slice containing all data added to this `Scratch`.
+ fn all(s: *Scratch) Slice {
+ const len = s.astgen.scratch.items.len - s.scratch_top;
+ return .{ .start = s.scratch_top, .len = @intCast(len) };
}
+ const Slice = struct {
+ start: u32,
+ len: u32,
+ fn get(s: Slice, astgen: *AstGen) []u32 {
+ return astgen.scratch.items[s.start..][0..s.len];
+ }
+ };
+};
- fn fieldsSlice(self: *Self) []u32 {
- return self.payload.items[self.field_bits_start..self.fields_end];
- }
+const WipDecls = struct {
+ astgen: *AstGen,
+ slice: Scratch.Slice,
+ index: u32,
- fn deinit(self: *Self) void {
- self.payload.items.len = self.payload_top;
+ fn init(scratch: *Scratch, decls_len: u32) Allocator.Error!WipDecls {
+ return .{
+ .astgen = scratch.astgen,
+ .slice = try scratch.addSlice(decls_len),
+ .index = 0,
+ };
+ }
+ fn finish(wip: *WipDecls) void {
+ assert(wip.index == wip.slice.len);
+ wip.* = undefined;
+ }
+ fn nextDecl(wip: *WipDecls, decl_inst: Zir.Inst.Index) void {
+ wip.slice.get(wip.astgen)[wip.index] = @intFromEnum(decl_inst);
+ wip.index += 1;
}
};
@@ -4057,7 +4043,7 @@ fn fnDecl(
astgen: *AstGen,
gz: *GenZir,
scope: *Scope,
- wip_members: *WipMembers,
+ wip_decls: *WipDecls,
decl_node: Ast.Node.Index,
body_node: Ast.Node.OptionalIndex,
fn_proto: Ast.full.FnProto,
@@ -4133,7 +4119,7 @@ fn fnDecl(
assert(!is_extern); // validated by parser (TODO why???)
}
- wip_members.nextDecl(decl_inst);
+ wip_decls.nextDecl(decl_inst);
var type_gz: GenZir = .{
.is_comptime = true,
@@ -4488,7 +4474,7 @@ fn globalVarDecl(
astgen: *AstGen,
gz: *GenZir,
scope: *Scope,
- wip_members: *WipMembers,
+ wip_decls: *WipDecls,
node: Ast.Node.Index,
var_decl: Ast.full.VarDecl,
) InnerError!void {
@@ -4533,7 +4519,7 @@ fn globalVarDecl(
const decl_column = astgen.source_column;
const decl_inst = try gz.makeDeclaration(node);
- wip_members.nextDecl(decl_inst);
+ wip_decls.nextDecl(decl_inst);
if (var_decl.ast.init_node.unwrap()) |init_node| {
if (is_extern) {
@@ -4635,7 +4621,7 @@ fn comptimeDecl(
astgen: *AstGen,
gz: *GenZir,
scope: *Scope,
- wip_members: *WipMembers,
+ wip_decls: *WipDecls,
node: Ast.Node.Index,
) InnerError!void {
const tree = astgen.tree;
@@ -4650,7 +4636,7 @@ fn comptimeDecl(
// Up top so the ZIR instruction index marks the start range of this
// top-level declaration.
const decl_inst = try gz.makeDeclaration(node);
- wip_members.nextDecl(decl_inst);
+ wip_decls.nextDecl(decl_inst);
astgen.advanceSourceCursorToNode(node);
// This is just needed for the `setDeclaration` call.
@@ -4698,7 +4684,7 @@ fn testDecl(
astgen: *AstGen,
gz: *GenZir,
scope: *Scope,
- wip_members: *WipMembers,
+ wip_decls: *WipDecls,
node: Ast.Node.Index,
) InnerError!void {
const tree = astgen.tree;
@@ -4714,7 +4700,7 @@ fn testDecl(
// top-level declaration.
const decl_inst = try gz.makeDeclaration(node);
- wip_members.nextDecl(decl_inst);
+ wip_decls.nextDecl(decl_inst);
astgen.advanceSourceCursorToNode(node);
// This is just needed for the `setDeclaration` call.
@@ -4914,7 +4900,7 @@ fn structDeclInner(
node: Ast.Node.Index,
container_decl: Ast.full.ContainerDecl,
layout: std.builtin.Type.ContainerLayout,
- backing_int_node: Ast.Node.OptionalIndex,
+ maybe_backing_int_node: Ast.Node.OptionalIndex,
name_strat: Zir.Inst.NameStrategy,
) InnerError!Zir.Inst.Ref {
const astgen = gz.astgen;
@@ -4930,27 +4916,29 @@ fn structDeclInner(
if (node == .root) {
return astgen.failNode(tuple_field_node, "file cannot be a tuple", .{});
} else {
- return tupleDecl(gz, scope, node, container_decl, layout, backing_int_node);
+ return tupleDecl(gz, scope, node, container_decl, layout, maybe_backing_int_node);
}
}
+ astgen.advanceSourceCursorToNode(node);
+
const decl_inst = try gz.reserveInstructionIndex();
- if (container_decl.ast.members.len == 0 and backing_int_node == .none) {
+ if (container_decl.ast.members.len == 0 and maybe_backing_int_node == .none) {
try gz.setStruct(decl_inst, .{
.src_node = node,
+ .name_strat = name_strat,
.layout = layout,
- .captures_len = 0,
- .fields_len = 0,
+ .backing_int_type_body_len = null,
.decls_len = 0,
- .has_backing_int = false,
- .known_non_opv = false,
- .known_comptime_only = false,
+ .fields_len = 0,
+ .any_field_aligns = false,
+ .any_field_defaults = false,
.any_comptime_fields = false,
- .any_default_inits = false,
- .any_aligned_fields = false,
- .fields_hash = std.zig.hashSrc(@tagName(layout)),
- .name_strat = name_strat,
+ .fields_hash = @splat(0),
+ .captures = &.{},
+ .capture_names = &.{},
+ .remaining = &.{},
});
return decl_inst.toRef();
}
@@ -4967,7 +4955,6 @@ fn structDeclInner(
// The struct_decl instruction introduces a scope in which the decls of the struct
// are in scope, so that field types, alignments, and default value expressions
// can refer to decls within the struct itself.
- astgen.advanceSourceCursorToNode(node);
var block_scope: GenZir = .{
.parent = &namespace.base,
.decl_node_index = node,
@@ -4979,197 +4966,134 @@ fn structDeclInner(
};
defer block_scope.unstack();
- const scratch_top = astgen.scratch.items.len;
- defer astgen.scratch.items.len = scratch_top;
+ const scan_result = try astgen.scanContainer(&namespace, container_decl.ast.members, .@"struct");
- var backing_int_body_len: usize = 0;
- const backing_int_ref: Zir.Inst.Ref = blk: {
- if (backing_int_node.unwrap()) |arg| {
- if (layout != .@"packed") {
- return astgen.failNode(arg, "non-packed struct does not support backing integer type", .{});
- } else {
- const backing_int_ref = try typeExpr(&block_scope, &namespace.base, arg);
- if (!block_scope.isEmpty()) {
- if (!block_scope.endsWithNoReturn()) {
- _ = try block_scope.addBreak(.break_inline, decl_inst, backing_int_ref);
- }
+ var scratch: Scratch = .init(astgen);
+ defer scratch.reset();
- const body = block_scope.instructionsSlice();
- const old_scratch_len = astgen.scratch.items.len;
- try astgen.scratch.ensureUnusedCapacity(gpa, countBodyLenAfterFixups(astgen, body));
- appendBodyWithFixupsArrayList(astgen, &astgen.scratch, body);
- backing_int_body_len = astgen.scratch.items.len - old_scratch_len;
- block_scope.instructions.items.len = block_scope.instructions_top;
- }
- break :blk backing_int_ref;
- }
- } else {
- break :blk .none;
+ // Replicate the structure of the ZIR trailing data in `scratch`
+ var wip_decls: WipDecls = try .init(&scratch, scan_result.decls_len);
+ const field_names = try scratch.addSlice(scan_result.fields_len);
+ const field_type_body_lens = try scratch.addSlice(scan_result.fields_len);
+ const field_align_body_lens = try scratch.addOptionalSlice(scan_result.any_field_aligns, scan_result.fields_len);
+ const field_default_body_lens = try scratch.addOptionalSlice(scan_result.any_field_values, scan_result.fields_len);
+ const field_comptime_bits = try scratch.addOptionalSlice(
+ scan_result.any_comptime_fields,
+ std.math.divCeil(u32, scan_result.fields_len, 32) catch unreachable,
+ );
+ if (field_comptime_bits) |bits| @memset(bits.get(astgen), 0);
+
+ // Before any field bodies comes the backing int type, if specified.
+ const backing_int_type_body_len: ?u32 = if (maybe_backing_int_node.unwrap()) |backing_int_node| len: {
+ if (layout != .@"packed") return astgen.failNode(
+ backing_int_node,
+ "non-packed struct does not support backing integer type",
+ .{},
+ );
+ const type_ref = try typeExpr(&block_scope, &namespace.base, backing_int_node);
+ if (!block_scope.endsWithNoReturn()) {
+ _ = try block_scope.addBreak(.break_inline, decl_inst, type_ref);
}
- };
-
- const decl_count = try astgen.scanContainer(&namespace, container_decl.ast.members, .@"struct");
- const field_count: u32 = @intCast(container_decl.ast.members.len - decl_count);
-
- const bits_per_field = 4;
- const max_field_size = 5;
- var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size);
- defer wip_members.deinit();
-
- // We will use the scratch buffer, starting here, for the bodies:
- // bodies: { // for every fields_len
- // field_type_body_inst: Inst, // for each field_type_body_len
- // align_body_inst: Inst, // for each align_body_len
- // init_body_inst: Inst, // for each init_body_len
- // }
- // Note that the scratch buffer is simultaneously being used by WipMembers, however
- // it will not access any elements beyond this point in the ArrayList. It also
- // accesses via the ArrayList items field so it can handle the scratch buffer being
- // reallocated.
- // No defer needed here because it is handled by `wip_members.deinit()` above.
- const bodies_start = astgen.scratch.items.len;
+ const body_len = try scratch.appendBodyWithFixups(block_scope.instructionsSlice());
+ block_scope.instructions.items.len = block_scope.instructions_top;
+ break :len body_len;
+ } else null;
const old_hasher = astgen.src_hasher;
defer astgen.src_hasher = old_hasher;
- astgen.src_hasher = std.zig.SrcHasher.init(.{});
- astgen.src_hasher.update(@tagName(layout));
- if (backing_int_node.unwrap()) |arg| {
- astgen.src_hasher.update(tree.getNodeSource(arg));
- }
+ astgen.src_hasher = .init(.{});
- var known_non_opv = false;
- var known_comptime_only = false;
- var any_comptime_fields = false;
- var any_aligned_fields = false;
- var any_default_inits = false;
+ var next_field_idx: u32 = 0;
for (container_decl.ast.members) |member_node| {
- var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) {
+ var member = switch (try containerMember(&block_scope, &namespace.base, &wip_decls, member_node)) {
.decl => continue,
.field => |field| field,
};
+ const field_idx = next_field_idx;
+ next_field_idx += 1;
astgen.src_hasher.update(tree.getNodeSource(member_node));
- const field_name = try astgen.identAsString(member.ast.main_token);
member.convertToNonTupleLike(astgen.tree);
assert(!member.ast.tuple_like);
- wip_members.appendToField(@intFromEnum(field_name));
- const type_expr = member.ast.type_expr.unwrap() orelse {
- return astgen.failTok(member.ast.main_token, "struct field missing type", .{});
- };
+ field_names.get(astgen)[field_idx] = @intFromEnum(try astgen.identAsString(member.ast.main_token));
- const field_type = try typeExpr(&block_scope, &namespace.base, type_expr);
- const have_type_body = !block_scope.isEmpty();
- const have_align = member.ast.align_expr != .none;
- const have_value = member.ast.value_expr != .none;
- const is_comptime = member.comptime_token != null;
+ {
+ const type_node = member.ast.type_expr.unwrap() orelse {
+ return astgen.failTok(member.ast.main_token, "struct field missing type", .{});
+ };
+ const type_ref = try typeExpr(&block_scope, &namespace.base, type_node);
+ if (!block_scope.endsWithNoReturn()) {
+ _ = try block_scope.addBreak(.break_inline, decl_inst, type_ref);
+ }
+ const body_len = try scratch.appendBodyWithFixups(block_scope.instructionsSlice());
+ field_type_body_lens.get(astgen)[field_idx] = body_len;
+ block_scope.instructions.items.len = block_scope.instructions_top;
+ }
- if (is_comptime) {
+ if (member.ast.align_expr.unwrap()) |align_node| {
+ if (layout == .@"packed") {
+ return astgen.failNode(align_node, "unable to override alignment of packed struct fields", .{});
+ }
+ const align_ref = try expr(&block_scope, &namespace.base, coerced_align_ri, align_node);
+ if (!block_scope.endsWithNoReturn()) {
+ _ = try block_scope.addBreak(.break_inline, decl_inst, align_ref);
+ }
+ const body_len = try scratch.appendBodyWithFixups(block_scope.instructionsSlice());
+ field_align_body_lens.?.get(astgen)[field_idx] = body_len;
+ block_scope.instructions.items.len = block_scope.instructions_top;
+ } else if (field_align_body_lens) |lens| {
+ lens.get(astgen)[field_idx] = 0;
+ }
+
+ if (member.ast.value_expr.unwrap()) |default_node| {
+ const ri: ResultInfo = .{ .rl = .{ .coerced_ty = decl_inst.toRef() } };
+ const default_ref = try expr(&block_scope, &namespace.base, ri, default_node);
+ if (!block_scope.endsWithNoReturn()) {
+ _ = try block_scope.addBreak(.break_inline, decl_inst, default_ref);
+ }
+ const body_len = try scratch.appendBodyWithFixups(block_scope.instructionsSlice());
+ field_default_body_lens.?.get(astgen)[field_idx] = body_len;
+ block_scope.instructions.items.len = block_scope.instructions_top;
+ } else if (field_default_body_lens) |lens| {
+ lens.get(astgen)[field_idx] = 0;
+ }
+
+ if (member.comptime_token) |comptime_token| {
switch (layout) {
- .@"packed", .@"extern" => return astgen.failTok(member.comptime_token.?, "{s} struct fields cannot be marked comptime", .{@tagName(layout)}),
- .auto => any_comptime_fields = true,
+ .@"packed", .@"extern" => return astgen.failTok(comptime_token, "{s} struct fields cannot be marked comptime", .{@tagName(layout)}),
+ .auto => {},
}
- } else {
- known_non_opv = known_non_opv or
- nodeImpliesMoreThanOnePossibleValue(tree, type_expr);
- known_comptime_only = known_comptime_only or
- nodeImpliesComptimeOnly(tree, type_expr);
- }
- wip_members.nextField(bits_per_field, .{ have_align, have_value, is_comptime, have_type_body });
-
- if (have_type_body) {
- if (!block_scope.endsWithNoReturn()) {
- _ = try block_scope.addBreak(.break_inline, decl_inst, field_type);
+ if (member.ast.value_expr == .none) {
+ return astgen.failTok(comptime_token, "comptime field without default initialization value", .{});
}
- const body = block_scope.instructionsSlice();
- const old_scratch_len = astgen.scratch.items.len;
- try astgen.scratch.ensureUnusedCapacity(gpa, countBodyLenAfterFixups(astgen, body));
- appendBodyWithFixupsArrayList(astgen, &astgen.scratch, body);
- wip_members.appendToField(@intCast(astgen.scratch.items.len - old_scratch_len));
- block_scope.instructions.items.len = block_scope.instructions_top;
- } else {
- wip_members.appendToField(@intFromEnum(field_type));
- }
-
- if (member.ast.align_expr.unwrap()) |align_expr| {
- if (layout == .@"packed") {
- return astgen.failNode(align_expr, "unable to override alignment of packed struct fields", .{});
- }
- any_aligned_fields = true;
- const align_ref = try expr(&block_scope, &namespace.base, coerced_align_ri, align_expr);
- if (!block_scope.endsWithNoReturn()) {
- _ = try block_scope.addBreak(.break_inline, decl_inst, align_ref);
- }
- const body = block_scope.instructionsSlice();
- const old_scratch_len = astgen.scratch.items.len;
- try astgen.scratch.ensureUnusedCapacity(gpa, countBodyLenAfterFixups(astgen, body));
- appendBodyWithFixupsArrayList(astgen, &astgen.scratch, body);
- wip_members.appendToField(@intCast(astgen.scratch.items.len - old_scratch_len));
- block_scope.instructions.items.len = block_scope.instructions_top;
- }
-
- if (member.ast.value_expr.unwrap()) |value_expr| {
- any_default_inits = true;
-
- // The decl_inst is used as here so that we can easily reconstruct a mapping
- // between it and the field type when the fields inits are analyzed.
- const ri: ResultInfo = .{ .rl = if (field_type == .none) .none else .{ .coerced_ty = decl_inst.toRef() } };
-
- const default_inst = try expr(&block_scope, &namespace.base, ri, value_expr);
- if (!block_scope.endsWithNoReturn()) {
- _ = try block_scope.addBreak(.break_inline, decl_inst, default_inst);
- }
- const body = block_scope.instructionsSlice();
- const old_scratch_len = astgen.scratch.items.len;
- try astgen.scratch.ensureUnusedCapacity(gpa, countBodyLenAfterFixups(astgen, body));
- appendBodyWithFixupsArrayList(astgen, &astgen.scratch, body);
- wip_members.appendToField(@intCast(astgen.scratch.items.len - old_scratch_len));
- block_scope.instructions.items.len = block_scope.instructions_top;
- } else if (member.comptime_token) |comptime_token| {
- return astgen.failTok(comptime_token, "comptime field without default initialization value", .{});
+ const mask = @as(u32, 1) << @intCast(field_idx % 32);
+ field_comptime_bits.?.get(astgen)[field_idx / 32] |= mask;
}
}
+ assert(next_field_idx == scan_result.fields_len);
+ wip_decls.finish();
var fields_hash: std.zig.SrcHash = undefined;
astgen.src_hasher.final(&fields_hash);
try gz.setStruct(decl_inst, .{
.src_node = node,
+ .name_strat = name_strat,
.layout = layout,
- .captures_len = @intCast(namespace.captures.count()),
- .fields_len = field_count,
- .decls_len = decl_count,
- .has_backing_int = backing_int_ref != .none,
- .known_non_opv = known_non_opv,
- .known_comptime_only = known_comptime_only,
- .any_comptime_fields = any_comptime_fields,
- .any_default_inits = any_default_inits,
- .any_aligned_fields = any_aligned_fields,
+ .backing_int_type_body_len = backing_int_type_body_len,
+ .decls_len = scan_result.decls_len,
+ .fields_len = scan_result.fields_len,
+ .any_field_aligns = scan_result.any_field_aligns,
+ .any_field_defaults = scan_result.any_field_values,
+ .any_comptime_fields = scan_result.any_comptime_fields,
.fields_hash = fields_hash,
- .name_strat = name_strat,
+ .captures = namespace.captures.keys(),
+ .capture_names = namespace.captures.values(),
+ .remaining = scratch.all().get(astgen),
});
- wip_members.finishBits(bits_per_field);
- const decls_slice = wip_members.declsSlice();
- const fields_slice = wip_members.fieldsSlice();
- const bodies_slice = astgen.scratch.items[bodies_start..];
- try astgen.extra.ensureUnusedCapacity(gpa, backing_int_body_len + 2 +
- decls_slice.len + namespace.captures.count() * 2 + fields_slice.len + bodies_slice.len);
- astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.keys()));
- astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.values()));
- if (backing_int_ref != .none) {
- astgen.extra.appendAssumeCapacity(@intCast(backing_int_body_len));
- if (backing_int_body_len == 0) {
- astgen.extra.appendAssumeCapacity(@intFromEnum(backing_int_ref));
- } else {
- astgen.extra.appendSliceAssumeCapacity(astgen.scratch.items[scratch_top..][0..backing_int_body_len]);
- }
- }
- astgen.extra.appendSliceAssumeCapacity(decls_slice);
- astgen.extra.appendSliceAssumeCapacity(fields_slice);
- astgen.extra.appendSliceAssumeCapacity(bodies_slice);
-
block_scope.unstack();
return decl_inst.toRef();
}
@@ -5281,11 +5205,29 @@ fn unionDeclInner(
auto_enum_tok: ?Ast.TokenIndex,
name_strat: Zir.Inst.NameStrategy,
) InnerError!Zir.Inst.Ref {
- const decl_inst = try gz.reserveInstructionIndex();
-
const astgen = gz.astgen;
const gpa = astgen.gpa;
+ const explicit_int_or_enum_tag = switch (layout) {
+ .auto => opt_arg_node != .none,
+ .@"extern" => if (opt_arg_node.unwrap()) |arg_node| {
+ return astgen.failNode(arg_node, "{s} union does not support enum tag type", .{@tagName(layout)});
+ } else false,
+ .@"packed" => false,
+ };
+
+ if (auto_enum_tok) |t| {
+ if (layout != .auto) {
+ return astgen.failTok(t, "{s} union does not support enum tag type", .{@tagName(layout)});
+ }
+ }
+
+ const is_tagged = explicit_int_or_enum_tag or auto_enum_tok != null;
+
+ astgen.advanceSourceCursorToNode(node);
+
+ const decl_inst = try gz.reserveInstructionIndex();
+
var namespace: Scope.Namespace = .{
.parent = scope,
.node = node,
@@ -5298,7 +5240,6 @@ fn unionDeclInner(
// The union_decl instruction introduces a scope in which the decls of the union
// are in scope, so that field types, alignments, and default value expressions
// can refer to decls within the union itself.
- astgen.advanceSourceCursorToNode(node);
var block_scope: GenZir = .{
.parent = &namespace.base,
.decl_node_index = node,
@@ -5310,42 +5251,42 @@ fn unionDeclInner(
};
defer block_scope.unstack();
- const decl_count = try astgen.scanContainer(&namespace, members, .@"union");
- const field_count: u32 = @intCast(members.len - decl_count);
+ const scan_result = try astgen.scanContainer(&namespace, members, .@"union");
- if (layout != .auto and (auto_enum_tok != null or opt_arg_node != .none)) {
- if (opt_arg_node.unwrap()) |arg_node| {
- return astgen.failNode(arg_node, "{s} union does not support enum tag type", .{@tagName(layout)});
- } else {
- return astgen.failTok(auto_enum_tok.?, "{s} union does not support enum tag type", .{@tagName(layout)});
+ var scratch: Scratch = .init(astgen);
+ defer scratch.reset();
+
+ // Replicate the structure of the ZIR trailing data in `scratch`
+ var wip_decls: WipDecls = try .init(&scratch, scan_result.decls_len);
+ const field_names = try scratch.addSlice(scan_result.fields_len);
+ const field_type_body_lens = try scratch.addSlice(scan_result.fields_len);
+ const field_align_body_lens = try scratch.addOptionalSlice(scan_result.any_field_aligns, scan_result.fields_len);
+ const field_value_body_lens = try scratch.addOptionalSlice(scan_result.any_field_values, scan_result.fields_len);
+
+ // Before any field bodies comes the tag/backing type, if specified.
+ const arg_type_body_len: ?u32 = if (opt_arg_node.unwrap()) |arg_node| len: {
+ const type_ref = try typeExpr(&block_scope, &namespace.base, arg_node);
+ if (!block_scope.endsWithNoReturn()) {
+ _ = try block_scope.addBreak(.break_inline, decl_inst, type_ref);
}
- }
-
- const arg_inst: Zir.Inst.Ref = if (opt_arg_node.unwrap()) |arg_node|
- try typeExpr(&block_scope, &namespace.base, arg_node)
- else
- .none;
-
- const bits_per_field = 4;
- const max_field_size = 4;
- var any_aligned_fields = false;
- var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size);
- defer wip_members.deinit();
+ const body_len = try scratch.appendBodyWithFixups(block_scope.instructionsSlice());
+ block_scope.instructions.items.len = block_scope.instructions_top;
+ break :len body_len;
+ } else null;
const old_hasher = astgen.src_hasher;
defer astgen.src_hasher = old_hasher;
- astgen.src_hasher = std.zig.SrcHasher.init(.{});
- astgen.src_hasher.update(@tagName(layout));
- astgen.src_hasher.update(&.{@intFromBool(auto_enum_tok != null)});
- if (opt_arg_node.unwrap()) |arg_node| {
- astgen.src_hasher.update(astgen.tree.getNodeSource(arg_node));
- }
+ astgen.src_hasher = .init(.{});
+ var next_field_idx: u32 = 0;
for (members) |member_node| {
- var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) {
+ var member = switch (try containerMember(&block_scope, &namespace.base, &wip_decls, member_node)) {
.decl => continue,
.field => |field| field,
};
+ const field_idx = next_field_idx;
+ next_field_idx += 1;
+
astgen.src_hasher.update(astgen.tree.getNodeSource(member_node));
member.convertToNonTupleLike(astgen.tree);
if (member.ast.tuple_like) {
@@ -5355,97 +5296,91 @@ fn unionDeclInner(
return astgen.failTok(comptime_token, "union fields cannot be marked comptime", .{});
}
- const field_name = try astgen.identAsString(member.ast.main_token);
- wip_members.appendToField(@intFromEnum(field_name));
+ field_names.get(astgen)[field_idx] = @intFromEnum(try astgen.identAsString(member.ast.main_token));
- const have_type = member.ast.type_expr != .none;
- const have_align = member.ast.align_expr != .none;
- const have_value = member.ast.value_expr != .none;
- const unused = false;
- wip_members.nextField(bits_per_field, .{ have_type, have_align, have_value, unused });
-
- if (member.ast.type_expr.unwrap()) |type_expr| {
- const field_type = try typeExpr(&block_scope, &namespace.base, type_expr);
- wip_members.appendToField(@intFromEnum(field_type));
- } else if (arg_inst == .none and auto_enum_tok == null) {
+ if (member.ast.type_expr.unwrap()) |type_node| {
+ const type_ref = try typeExpr(&block_scope, &namespace.base, type_node);
+ if (!block_scope.endsWithNoReturn()) {
+ _ = try block_scope.addBreak(.break_inline, decl_inst, type_ref);
+ }
+ const body_len = try scratch.appendBodyWithFixups(block_scope.instructionsSlice());
+ field_type_body_lens.get(astgen)[field_idx] = body_len;
+ block_scope.instructions.items.len = block_scope.instructions_top;
+ } else if (!is_tagged) {
return astgen.failNode(member_node, "union field missing type", .{});
+ } else {
+ field_type_body_lens.get(astgen)[field_idx] = 0;
}
- if (member.ast.align_expr.unwrap()) |align_expr| {
+
+ if (member.ast.align_expr.unwrap()) |align_node| {
if (layout == .@"packed") {
- return astgen.failNode(align_expr, "unable to override alignment of packed union fields", .{});
+ return astgen.failNode(align_node, "unable to override alignment of packed union fields", .{});
}
- const align_inst = try expr(&block_scope, &block_scope.base, coerced_align_ri, align_expr);
- wip_members.appendToField(@intFromEnum(align_inst));
- any_aligned_fields = true;
+ const align_ref = try expr(&block_scope, &namespace.base, coerced_align_ri, align_node);
+ if (!block_scope.endsWithNoReturn()) {
+ _ = try block_scope.addBreak(.break_inline, decl_inst, align_ref);
+ }
+ const body_len = try scratch.appendBodyWithFixups(block_scope.instructionsSlice());
+ field_align_body_lens.?.get(astgen)[field_idx] = body_len;
+ block_scope.instructions.items.len = block_scope.instructions_top;
+ } else if (field_align_body_lens) |lens| {
+ lens.get(astgen)[field_idx] = 0;
}
- if (member.ast.value_expr.unwrap()) |value_expr| {
- if (arg_inst == .none) {
- return astgen.failNodeNotes(
- node,
- "explicitly valued tagged union missing integer tag type",
- .{},
- &[_]u32{
- try astgen.errNoteNode(
- value_expr,
- "tag value specified here",
- .{},
- ),
- },
- );
+
+ if (member.ast.value_expr.unwrap()) |value_node| {
+ if (!explicit_int_or_enum_tag) return astgen.failNodeNotes(
+ node,
+ "explicitly valued tagged union missing integer tag type",
+ .{},
+ &.{try astgen.errNoteNode(value_node, "tag value specified here", .{})},
+ );
+ if (auto_enum_tok == null) return astgen.failNodeNotes(
+ node,
+ "explicitly valued tagged union requires inferred enum tag type",
+ .{},
+ &.{try astgen.errNoteNode(value_node, "tag value specified here", .{})},
+ );
+ const ri: ResultInfo = .{ .rl = .{ .coerced_ty = decl_inst.toRef() } };
+ const value_ref = try expr(&block_scope, &namespace.base, ri, value_node);
+ if (!block_scope.endsWithNoReturn()) {
+ _ = try block_scope.addBreak(.break_inline, decl_inst, value_ref);
}
- if (auto_enum_tok == null) {
- return astgen.failNodeNotes(
- node,
- "explicitly valued tagged union requires inferred enum tag type",
- .{},
- &[_]u32{
- try astgen.errNoteNode(
- value_expr,
- "tag value specified here",
- .{},
- ),
- },
- );
- }
- const tag_value = try expr(&block_scope, &block_scope.base, .{ .rl = .{ .ty = arg_inst } }, value_expr);
- wip_members.appendToField(@intFromEnum(tag_value));
+ const body_len = try scratch.appendBodyWithFixups(block_scope.instructionsSlice());
+ field_value_body_lens.?.get(astgen)[field_idx] = body_len;
+ block_scope.instructions.items.len = block_scope.instructions_top;
+ } else if (field_value_body_lens) |lens| {
+ lens.get(astgen)[field_idx] = 0;
}
}
+ assert(next_field_idx == scan_result.fields_len);
+ wip_decls.finish();
var fields_hash: std.zig.SrcHash = undefined;
astgen.src_hasher.final(&fields_hash);
- if (!block_scope.isEmpty()) {
- _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
- }
-
- const body = block_scope.instructionsSlice();
- const body_len = astgen.countBodyLenAfterFixups(body);
-
try gz.setUnion(decl_inst, .{
.src_node = node,
- .layout = layout,
- .tag_type = arg_inst,
- .captures_len = @intCast(namespace.captures.count()),
- .body_len = body_len,
- .fields_len = field_count,
- .decls_len = decl_count,
- .auto_enum_tag = auto_enum_tok != null,
- .any_aligned_fields = any_aligned_fields,
- .fields_hash = fields_hash,
.name_strat = name_strat,
+ .kind = switch (layout) {
+ .auto => if (auto_enum_tok == null) l: {
+ break :l if (opt_arg_node == .none) .auto else .tagged_explicit;
+ } else l: {
+ break :l if (opt_arg_node == .none) .tagged_enum else .tagged_enum_explicit;
+ },
+ .@"extern" => .@"extern",
+ .@"packed" => if (opt_arg_node != .none) .packed_explicit else .@"packed",
+ },
+ .arg_type_body_len = arg_type_body_len,
+ .decls_len = scan_result.decls_len,
+ .fields_len = scan_result.fields_len,
+ .any_field_aligns = scan_result.any_field_aligns,
+ .any_field_values = scan_result.any_field_values,
+ .fields_hash = fields_hash,
+ .captures = namespace.captures.keys(),
+ .capture_names = namespace.captures.values(),
+ .remaining = scratch.all().get(astgen),
});
- wip_members.finishBits(bits_per_field);
- const decls_slice = wip_members.declsSlice();
- const fields_slice = wip_members.fieldsSlice();
- try astgen.extra.ensureUnusedCapacity(gpa, namespace.captures.count() * 2 + decls_slice.len + body_len + fields_slice.len);
- astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.keys()));
- astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.values()));
- astgen.extra.appendSliceAssumeCapacity(decls_slice);
- astgen.appendBodyWithFixups(body);
- astgen.extra.appendSliceAssumeCapacity(fields_slice);
-
block_scope.unstack();
return decl_inst.toRef();
}
@@ -5494,103 +5429,8 @@ fn containerDecl(
if (container_decl.layout_token) |t| {
return astgen.failTok(t, "enums do not support 'packed' or 'extern'; instead provide an explicit integer tag type", .{});
}
- // Count total fields as well as how many have explicitly provided tag values.
- const counts = blk: {
- var values: usize = 0;
- var total_fields: usize = 0;
- var decls: usize = 0;
- var opt_nonexhaustive_node: Ast.Node.OptionalIndex = .none;
- var nonfinal_nonexhaustive = false;
- for (container_decl.ast.members) |member_node| {
- var member = tree.fullContainerField(member_node) orelse {
- decls += 1;
- continue;
- };
- member.convertToNonTupleLike(astgen.tree);
- if (member.ast.tuple_like) {
- return astgen.failTok(member.ast.main_token, "enum field missing name", .{});
- }
- if (member.comptime_token) |comptime_token| {
- return astgen.failTok(comptime_token, "enum fields cannot be marked comptime", .{});
- }
- if (member.ast.type_expr.unwrap()) |type_expr| {
- return astgen.failNodeNotes(
- type_expr,
- "enum fields do not have types",
- .{},
- &[_]u32{
- try astgen.errNoteNode(
- node,
- "consider 'union(enum)' here to make it a tagged union",
- .{},
- ),
- },
- );
- }
- if (member.ast.align_expr.unwrap()) |align_expr| {
- return astgen.failNode(align_expr, "enum fields cannot be aligned", .{});
- }
- const name_token = member.ast.main_token;
- if (mem.eql(u8, tree.tokenSlice(name_token), "_")) {
- if (opt_nonexhaustive_node.unwrap()) |nonexhaustive_node| {
- return astgen.failNodeNotes(
- member_node,
- "redundant non-exhaustive enum mark",
- .{},
- &[_]u32{
- try astgen.errNoteNode(
- nonexhaustive_node,
- "other mark here",
- .{},
- ),
- },
- );
- }
- opt_nonexhaustive_node = member_node.toOptional();
- if (member.ast.value_expr.unwrap()) |value_expr| {
- return astgen.failNode(value_expr, "'_' is used to mark an enum as non-exhaustive and cannot be assigned a value", .{});
- }
- continue;
- } else if (opt_nonexhaustive_node != .none) {
- nonfinal_nonexhaustive = true;
- }
- total_fields += 1;
- if (member.ast.value_expr.unwrap()) |value_expr| {
- if (container_decl.ast.arg == .none) {
- return astgen.failNode(value_expr, "value assigned to enum tag with inferred tag type", .{});
- }
- values += 1;
- }
- }
- if (nonfinal_nonexhaustive) {
- return astgen.failNode(opt_nonexhaustive_node.unwrap().?, "'_' field of non-exhaustive enum must be last", .{});
- }
- break :blk .{
- .total_fields = total_fields,
- .values = values,
- .decls = decls,
- .nonexhaustive_node = opt_nonexhaustive_node,
- };
- };
- if (counts.nonexhaustive_node != .none and container_decl.ast.arg == .none) {
- const nonexhaustive_node = counts.nonexhaustive_node.unwrap().?;
- return astgen.failNodeNotes(
- node,
- "non-exhaustive enum missing integer tag type",
- .{},
- &[_]u32{
- try astgen.errNoteNode(
- nonexhaustive_node,
- "marked non-exhaustive here",
- .{},
- ),
- },
- );
- }
- // In this case we must generate ZIR code for the tag values, similar to
- // how structs are handled above.
- const nonexhaustive = counts.nonexhaustive_node != .none;
+ astgen.advanceSourceCursorToNode(node);
const decl_inst = try gz.reserveInstructionIndex();
@@ -5605,7 +5445,6 @@ fn containerDecl(
// The enum_decl instruction introduces a scope in which the decls of the enum
// are in scope, so that tag values can refer to decls within the enum itself.
- astgen.advanceSourceCursorToNode(node);
var block_scope: GenZir = .{
.parent = &namespace.base,
.decl_node_index = node,
@@ -5617,104 +5456,127 @@ fn containerDecl(
};
defer block_scope.unstack();
- _ = try astgen.scanContainer(&namespace, container_decl.ast.members, .@"enum");
- namespace.base.tag = .namespace;
+ const scan_result = try astgen.scanContainer(&namespace, container_decl.ast.members, .@"enum");
+ // The name `_` is not actually a field; it marks a non-exhaustive enum.
+ const fields_len: u32 = scan_result.fields_len - @intFromBool(scan_result.has_underscore_field);
- const arg_inst: Zir.Inst.Ref = if (container_decl.ast.arg.unwrap()) |arg|
- try comptimeExpr(&block_scope, &namespace.base, coerced_type_ri, arg, .type)
- else
- .none;
+ var scratch: Scratch = .init(astgen);
+ defer scratch.reset();
- const bits_per_field = 1;
- const max_field_size = 2;
- var wip_members = try WipMembers.init(gpa, &astgen.scratch, @intCast(counts.decls), @intCast(counts.total_fields), bits_per_field, max_field_size);
- defer wip_members.deinit();
+ // Replicate the structure of the ZIR trailing data in `scratch`
+ var wip_decls: WipDecls = try .init(&scratch, scan_result.decls_len);
+ const field_names = try scratch.addSlice(fields_len);
+ const field_value_body_lens = try scratch.addOptionalSlice(scan_result.any_field_values, fields_len);
+
+ // Before any field bodies comes the tag type, if specified.
+ const tag_type_body_len: ?u32 = if (container_decl.ast.arg.unwrap()) |tag_type_node| len: {
+ const type_ref = try typeExpr(&block_scope, &namespace.base, tag_type_node);
+ if (!block_scope.endsWithNoReturn()) {
+ _ = try block_scope.addBreak(.break_inline, decl_inst, type_ref);
+ }
+ const body_len = try scratch.appendBodyWithFixups(block_scope.instructionsSlice());
+ block_scope.instructions.items.len = block_scope.instructions_top;
+ break :len body_len;
+ } else null;
const old_hasher = astgen.src_hasher;
defer astgen.src_hasher = old_hasher;
- astgen.src_hasher = std.zig.SrcHasher.init(.{});
- if (container_decl.ast.arg.unwrap()) |arg| {
- astgen.src_hasher.update(tree.getNodeSource(arg));
- }
- astgen.src_hasher.update(&.{@intFromBool(nonexhaustive)});
+ astgen.src_hasher = .init(.{});
+ var next_field_idx: u32 = 0;
+ var opt_nonexhaustive_node: Ast.Node.OptionalIndex = .none;
for (container_decl.ast.members) |member_node| {
- if (member_node.toOptional() == counts.nonexhaustive_node)
- continue;
- astgen.src_hasher.update(tree.getNodeSource(member_node));
- var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) {
+ var member = switch (try containerMember(&block_scope, &namespace.base, &wip_decls, member_node)) {
.decl => continue,
.field => |field| field,
};
member.convertToNonTupleLike(astgen.tree);
- assert(member.comptime_token == null);
- assert(member.ast.type_expr == .none);
- assert(member.ast.align_expr == .none);
+ if (member.ast.tuple_like) return astgen.failTok(member.ast.main_token, "enum field missing name", .{});
+ if (member.comptime_token) |t| return astgen.failTok(t, "enum fields cannot be marked comptime", .{});
+ if (member.ast.type_expr.unwrap()) |type_node| {
+ return astgen.failNodeNotes(type_node, "enum fields do not have types", .{}, &.{
+ try astgen.errNoteNode(node, "consider 'union(enum)' here to make it a tagged union", .{}),
+ });
+ }
+ if (member.ast.align_expr.unwrap()) |n| return astgen.failNode(n, "enum fields cannot be aligned", .{});
+ if (mem.eql(u8, tree.tokenSlice(member.ast.main_token), "_")) {
+ // non-exhaustive mark
+ assert(scan_result.has_underscore_field);
+ if (opt_nonexhaustive_node.unwrap()) |prev_node| {
+ return astgen.failNodeNotes(member_node, "redundant non-exhaustive enum mark", .{}, &.{
+ try astgen.errNoteNode(prev_node, "other mark here", .{}),
+ });
+ }
+ if (member.ast.value_expr.unwrap()) |value_node| {
+ return astgen.failNode(value_node, "'_' is used to mark an enum as non-exhaustive and cannot be assigned a value", .{});
+ }
+ if (next_field_idx != fields_len) {
+ return astgen.failNode(member_node, "'_' field of non-exhaustive enum must be last", .{});
+ }
+ if (tag_type_body_len == null) {
+ return astgen.failNodeNotes(node, "non-exhaustive enum missing integer tag type", .{}, &.{
+ try astgen.errNoteNode(member_node, "marked non-exhaustive here", .{}),
+ });
+ }
+ opt_nonexhaustive_node = member_node.toOptional();
+ continue;
+ }
+
+ // This is a real field rather than a non-exhaustive mark.
+ const field_idx = next_field_idx;
+ next_field_idx += 1;
- const field_name = try astgen.identAsString(member.ast.main_token);
- wip_members.appendToField(@intFromEnum(field_name));
+ astgen.src_hasher.update(tree.getNodeSource(member_node));
- const have_value = member.ast.value_expr != .none;
- wip_members.nextField(bits_per_field, .{have_value});
+ field_names.get(astgen)[field_idx] = @intFromEnum(try astgen.identAsString(member.ast.main_token));
- if (member.ast.value_expr.unwrap()) |value_expr| {
- if (arg_inst == .none) {
- return astgen.failNodeNotes(
- node,
- "explicitly valued enum missing integer tag type",
- .{},
- &[_]u32{
- try astgen.errNoteNode(
- value_expr,
- "tag value specified here",
- .{},
- ),
- },
- );
+ if (member.ast.value_expr.unwrap()) |value_node| {
+ if (tag_type_body_len == null) {
+ return astgen.failNodeNotes(node, "explicitly valued enum missing integer tag type", .{}, &.{
+ try astgen.errNoteNode(value_node, "tag value specified here", .{}),
+ });
+ }
+ const val_ri: ResultInfo = .{ .rl = .{ .coerced_ty = decl_inst.toRef() } };
+ const value_ref = try expr(&block_scope, &namespace.base, val_ri, value_node);
+ if (!block_scope.endsWithNoReturn()) {
+ _ = try block_scope.addBreak(.break_inline, decl_inst, value_ref);
}
- const tag_value_inst = try expr(&block_scope, &namespace.base, .{ .rl = .{ .ty = arg_inst } }, value_expr);
- wip_members.appendToField(@intFromEnum(tag_value_inst));
+ const body_len = try scratch.appendBodyWithFixups(block_scope.instructionsSlice());
+ field_value_body_lens.?.get(astgen)[field_idx] = body_len;
+ block_scope.instructions.items.len = block_scope.instructions_top;
+ } else if (field_value_body_lens) |lens| {
+ lens.get(astgen)[field_idx] = 0;
}
}
-
- if (!block_scope.isEmpty()) {
- _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
- }
+ assert(scan_result.has_underscore_field == (opt_nonexhaustive_node != .none));
+ assert(next_field_idx == fields_len);
+ wip_decls.finish();
var fields_hash: std.zig.SrcHash = undefined;
astgen.src_hasher.final(&fields_hash);
- const body = block_scope.instructionsSlice();
- const body_len = astgen.countBodyLenAfterFixups(body);
-
try gz.setEnum(decl_inst, .{
.src_node = node,
- .nonexhaustive = nonexhaustive,
- .tag_type = arg_inst,
- .captures_len = @intCast(namespace.captures.count()),
- .body_len = body_len,
- .fields_len = @intCast(counts.total_fields),
- .decls_len = @intCast(counts.decls),
+ .name_strat = name_strat,
+ .tag_type_body_len = tag_type_body_len,
+ .nonexhaustive = scan_result.has_underscore_field,
+ .decls_len = scan_result.decls_len,
+ .fields_len = fields_len,
+ .any_field_values = scan_result.any_field_values,
.fields_hash = fields_hash,
- .name_strat = name_strat,
+ .captures = namespace.captures.keys(),
+ .capture_names = namespace.captures.values(),
+ .remaining = scratch.all().get(astgen),
});
- wip_members.finishBits(bits_per_field);
- const decls_slice = wip_members.declsSlice();
- const fields_slice = wip_members.fieldsSlice();
- try astgen.extra.ensureUnusedCapacity(gpa, namespace.captures.count() * 2 + decls_slice.len + body_len + fields_slice.len);
- astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.keys()));
- astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.values()));
- astgen.extra.appendSliceAssumeCapacity(decls_slice);
- astgen.appendBodyWithFixups(body);
- astgen.extra.appendSliceAssumeCapacity(fields_slice);
-
block_scope.unstack();
return rvalue(gz, ri, decl_inst.toRef(), node);
},
.keyword_opaque => {
assert(container_decl.ast.arg == .none);
+ astgen.advanceSourceCursorToNode(node);
+
const decl_inst = try gz.reserveInstructionIndex();
var namespace: Scope.Namespace = .{
@@ -5726,7 +5588,6 @@ fn containerDecl(
};
defer namespace.deinit(gpa);
- astgen.advanceSourceCursorToNode(node);
var block_scope: GenZir = .{
.parent = &namespace.base,
.decl_node_index = node,
@@ -5738,36 +5599,34 @@ fn containerDecl(
};
defer block_scope.unstack();
- const decl_count = try astgen.scanContainer(&namespace, container_decl.ast.members, .@"opaque");
+ const scan_result = try astgen.scanContainer(&namespace, container_decl.ast.members, .@"opaque");
- var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, 0, 0, 0);
- defer wip_members.deinit();
+ var scratch: Scratch = .init(astgen);
+ defer scratch.reset();
+ var wip_decls: WipDecls = try .init(&scratch, scan_result.decls_len);
if (container_decl.layout_token) |layout_token| {
return astgen.failTok(layout_token, "opaque types do not support 'packed' or 'extern'", .{});
}
for (container_decl.ast.members) |member_node| {
- const res = try containerMember(&block_scope, &namespace.base, &wip_members, member_node);
- if (res == .field) {
- return astgen.failNode(member_node, "opaque types cannot have fields", .{});
+ switch (try containerMember(&block_scope, &namespace.base, &wip_decls, member_node)) {
+ .decl => {},
+ .field => return astgen.failNode(member_node, "opaque types cannot have fields", .{}),
}
}
+ wip_decls.finish();
+
try gz.setOpaque(decl_inst, .{
.src_node = node,
- .captures_len = @intCast(namespace.captures.count()),
- .decls_len = decl_count,
.name_strat = name_strat,
+ .decls_len = scan_result.decls_len,
+ .captures = namespace.captures.keys(),
+ .capture_names = namespace.captures.values(),
+ .decls = @ptrCast(scratch.all().get(astgen)),
});
- wip_members.finishBits(0);
- const decls_slice = wip_members.declsSlice();
- try astgen.extra.ensureUnusedCapacity(gpa, namespace.captures.count() * 2 + decls_slice.len);
- astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.keys()));
- astgen.extra.appendSliceAssumeCapacity(@ptrCast(namespace.captures.values()));
- astgen.extra.appendSliceAssumeCapacity(decls_slice);
-
block_scope.unstack();
return rvalue(gz, ri, decl_inst.toRef(), node);
},
@@ -5780,7 +5639,7 @@ const ContainerMemberResult = union(enum) { decl, field: Ast.full.ContainerField
fn containerMember(
gz: *GenZir,
scope: *Scope,
- wip_members: *WipMembers,
+ wip_decls: *WipDecls,
member_node: Ast.Node.Index,
) InnerError!ContainerMemberResult {
const astgen = gz.astgen;
@@ -5805,13 +5664,13 @@ fn containerMember(
else
.none;
- const prev_decl_index = wip_members.decl_index;
- astgen.fnDecl(gz, scope, wip_members, member_node, body, full) catch |err| switch (err) {
+ const prev_decl_index = wip_decls.index;
+ astgen.fnDecl(gz, scope, wip_decls, member_node, body, full) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
error.AnalysisFail => {
- wip_members.decl_index = prev_decl_index;
+ wip_decls.index = prev_decl_index;
try addFailedDeclaration(
- wip_members,
+ wip_decls,
gz,
.@"const",
try astgen.identAsString(full.name_token.?),
@@ -5828,13 +5687,13 @@ fn containerMember(
.aligned_var_decl,
=> {
const full = tree.fullVarDecl(member_node).?;
- const prev_decl_index = wip_members.decl_index;
- astgen.globalVarDecl(gz, scope, wip_members, member_node, full) catch |err| switch (err) {
+ const prev_decl_index = wip_decls.index;
+ astgen.globalVarDecl(gz, scope, wip_decls, member_node, full) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
error.AnalysisFail => {
- wip_members.decl_index = prev_decl_index;
+ wip_decls.index = prev_decl_index;
try addFailedDeclaration(
- wip_members,
+ wip_decls,
gz,
.@"const", // doesn't really matter
try astgen.identAsString(full.ast.mut_token + 1),
@@ -5846,13 +5705,13 @@ fn containerMember(
},
.@"comptime" => {
- const prev_decl_index = wip_members.decl_index;
- astgen.comptimeDecl(gz, scope, wip_members, member_node) catch |err| switch (err) {
+ const prev_decl_index = wip_decls.index;
+ astgen.comptimeDecl(gz, scope, wip_decls, member_node) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
error.AnalysisFail => {
- wip_members.decl_index = prev_decl_index;
+ wip_decls.index = prev_decl_index;
try addFailedDeclaration(
- wip_members,
+ wip_decls,
gz,
.@"comptime",
.empty,
@@ -5863,16 +5722,16 @@ fn containerMember(
};
},
.test_decl => {
- const prev_decl_index = wip_members.decl_index;
+ const prev_decl_index = wip_decls.index;
// We need to have *some* decl here so that the decl count matches what's expected.
// Since it doesn't strictly matter *what* this is, let's save ourselves the trouble
// of duplicating the test name logic, and just assume this is an unnamed test.
- astgen.testDecl(gz, scope, wip_members, member_node) catch |err| switch (err) {
+ astgen.testDecl(gz, scope, wip_decls, member_node) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
error.AnalysisFail => {
- wip_members.decl_index = prev_decl_index;
+ wip_decls.index = prev_decl_index;
try addFailedDeclaration(
- wip_members,
+ wip_decls,
gz,
.unnamed_test,
.empty,
@@ -10619,482 +10478,6 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) BuiltinFn.Ev
}
}
-/// Returns `true` if it is known the type expression has more than one possible value;
-/// `false` otherwise.
-fn nodeImpliesMoreThanOnePossibleValue(tree: *const Ast, start_node: Ast.Node.Index) bool {
- var node = start_node;
- while (true) {
- switch (tree.nodeTag(node)) {
- .root,
- .test_decl,
- .switch_case,
- .switch_case_inline,
- .switch_case_one,
- .switch_case_inline_one,
- .container_field_init,
- .container_field_align,
- .container_field,
- .asm_output,
- .asm_input,
- .global_var_decl,
- .local_var_decl,
- .simple_var_decl,
- .aligned_var_decl,
- => unreachable,
-
- .@"return",
- .@"break",
- .@"continue",
- .bit_not,
- .bool_not,
- .@"defer",
- .@"errdefer",
- .address_of,
- .negation,
- .negation_wrap,
- .@"resume",
- .array_type,
- .@"suspend",
- .fn_decl,
- .anyframe_literal,
- .number_literal,
- .enum_literal,
- .string_literal,
- .multiline_string_literal,
- .char_literal,
- .unreachable_literal,
- .error_set_decl,
- .container_decl,
- .container_decl_trailing,
- .container_decl_two,
- .container_decl_two_trailing,
- .container_decl_arg,
- .container_decl_arg_trailing,
- .tagged_union,
- .tagged_union_trailing,
- .tagged_union_two,
- .tagged_union_two_trailing,
- .tagged_union_enum_tag,
- .tagged_union_enum_tag_trailing,
- .@"asm",
- .asm_simple,
- .add,
- .add_wrap,
- .add_sat,
- .array_cat,
- .array_mult,
- .assign,
- .assign_destructure,
- .assign_bit_and,
- .assign_bit_or,
- .assign_shl,
- .assign_shl_sat,
- .assign_shr,
- .assign_bit_xor,
- .assign_div,
- .assign_sub,
- .assign_sub_wrap,
- .assign_sub_sat,
- .assign_mod,
- .assign_add,
- .assign_add_wrap,
- .assign_add_sat,
- .assign_mul,
- .assign_mul_wrap,
- .assign_mul_sat,
- .bang_equal,
- .bit_and,
- .bit_or,
- .shl,
- .shl_sat,
- .shr,
- .bit_xor,
- .bool_and,
- .bool_or,
- .div,
- .equal_equal,
- .error_union,
- .greater_or_equal,
- .greater_than,
- .less_or_equal,
- .less_than,
- .merge_error_sets,
- .mod,
- .mul,
- .mul_wrap,
- .mul_sat,
- .switch_range,
- .for_range,
- .field_access,
- .sub,
- .sub_wrap,
- .sub_sat,
- .slice,
- .slice_open,
- .slice_sentinel,
- .deref,
- .array_access,
- .error_value,
- .while_simple,
- .while_cont,
- .for_simple,
- .if_simple,
- .@"catch",
- .@"orelse",
- .array_init_one,
- .array_init_one_comma,
- .array_init_dot_two,
- .array_init_dot_two_comma,
- .array_init_dot,
- .array_init_dot_comma,
- .array_init,
- .array_init_comma,
- .struct_init_one,
- .struct_init_one_comma,
- .struct_init_dot_two,
- .struct_init_dot_two_comma,
- .struct_init_dot,
- .struct_init_dot_comma,
- .struct_init,
- .struct_init_comma,
- .@"while",
- .@"if",
- .@"for",
- .@"switch",
- .switch_comma,
- .call_one,
- .call_one_comma,
- .call,
- .call_comma,
- .block_two,
- .block_two_semicolon,
- .block,
- .block_semicolon,
- .builtin_call,
- .builtin_call_comma,
- .builtin_call_two,
- .builtin_call_two_comma,
- // these are function bodies, not pointers
- .fn_proto_simple,
- .fn_proto_multi,
- .fn_proto_one,
- .fn_proto,
- => return false,
-
- // Forward the question to the LHS sub-expression.
- .@"try",
- .@"comptime",
- .@"nosuspend",
- => node = tree.nodeData(node).node,
- .grouped_expression,
- .unwrap_optional,
- => node = tree.nodeData(node).node_and_token[0],
-
- .ptr_type_aligned,
- .ptr_type_sentinel,
- .ptr_type,
- .ptr_type_bit_range,
- .optional_type,
- .anyframe_type,
- .array_type_sentinel,
- => return true,
-
- .identifier => {
- const ident_bytes = tree.tokenSlice(tree.nodeMainToken(node));
- if (primitive_instrs.get(ident_bytes)) |primitive| switch (primitive) {
- .anyerror_type,
- .anyframe_type,
- .anyopaque_type,
- .bool_type,
- .c_int_type,
- .c_long_type,
- .c_longdouble_type,
- .c_longlong_type,
- .c_char_type,
- .c_short_type,
- .c_uint_type,
- .c_ulong_type,
- .c_ulonglong_type,
- .c_ushort_type,
- .comptime_float_type,
- .comptime_int_type,
- .f16_type,
- .f32_type,
- .f64_type,
- .f80_type,
- .f128_type,
- .i16_type,
- .i32_type,
- .i64_type,
- .i128_type,
- .i8_type,
- .isize_type,
- .type_type,
- .u16_type,
- .u29_type,
- .u32_type,
- .u64_type,
- .u128_type,
- .u1_type,
- .u8_type,
- .usize_type,
- => return true,
-
- .void_type,
- .bool_false,
- .bool_true,
- .null_value,
- .undef,
- .noreturn_type,
- => return false,
-
- else => unreachable, // that's all the values from `primitives`.
- } else {
- return false;
- }
- },
- }
- }
-}
-
-/// Returns `true` if it is known the expression is a type that cannot be used at runtime;
-/// `false` otherwise.
-fn nodeImpliesComptimeOnly(tree: *const Ast, start_node: Ast.Node.Index) bool {
- var node = start_node;
- while (true) {
- switch (tree.nodeTag(node)) {
- .root,
- .test_decl,
- .switch_case,
- .switch_case_inline,
- .switch_case_one,
- .switch_case_inline_one,
- .container_field_init,
- .container_field_align,
- .container_field,
- .asm_output,
- .asm_input,
- .global_var_decl,
- .local_var_decl,
- .simple_var_decl,
- .aligned_var_decl,
- => unreachable,
-
- .@"return",
- .@"break",
- .@"continue",
- .bit_not,
- .bool_not,
- .@"defer",
- .@"errdefer",
- .address_of,
- .negation,
- .negation_wrap,
- .@"resume",
- .array_type,
- .@"suspend",
- .fn_decl,
- .anyframe_literal,
- .number_literal,
- .enum_literal,
- .string_literal,
- .multiline_string_literal,
- .char_literal,
- .unreachable_literal,
- .error_set_decl,
- .container_decl,
- .container_decl_trailing,
- .container_decl_two,
- .container_decl_two_trailing,
- .container_decl_arg,
- .container_decl_arg_trailing,
- .tagged_union,
- .tagged_union_trailing,
- .tagged_union_two,
- .tagged_union_two_trailing,
- .tagged_union_enum_tag,
- .tagged_union_enum_tag_trailing,
- .@"asm",
- .asm_simple,
- .add,
- .add_wrap,
- .add_sat,
- .array_cat,
- .array_mult,
- .assign,
- .assign_destructure,
- .assign_bit_and,
- .assign_bit_or,
- .assign_shl,
- .assign_shl_sat,
- .assign_shr,
- .assign_bit_xor,
- .assign_div,
- .assign_sub,
- .assign_sub_wrap,
- .assign_sub_sat,
- .assign_mod,
- .assign_add,
- .assign_add_wrap,
- .assign_add_sat,
- .assign_mul,
- .assign_mul_wrap,
- .assign_mul_sat,
- .bang_equal,
- .bit_and,
- .bit_or,
- .shl,
- .shl_sat,
- .shr,
- .bit_xor,
- .bool_and,
- .bool_or,
- .div,
- .equal_equal,
- .error_union,
- .greater_or_equal,
- .greater_than,
- .less_or_equal,
- .less_than,
- .merge_error_sets,
- .mod,
- .mul,
- .mul_wrap,
- .mul_sat,
- .switch_range,
- .for_range,
- .field_access,
- .sub,
- .sub_wrap,
- .sub_sat,
- .slice,
- .slice_open,
- .slice_sentinel,
- .deref,
- .array_access,
- .error_value,
- .while_simple,
- .while_cont,
- .for_simple,
- .if_simple,
- .@"catch",
- .@"orelse",
- .array_init_one,
- .array_init_one_comma,
- .array_init_dot_two,
- .array_init_dot_two_comma,
- .array_init_dot,
- .array_init_dot_comma,
- .array_init,
- .array_init_comma,
- .struct_init_one,
- .struct_init_one_comma,
- .struct_init_dot_two,
- .struct_init_dot_two_comma,
- .struct_init_dot,
- .struct_init_dot_comma,
- .struct_init,
- .struct_init_comma,
- .@"while",
- .@"if",
- .@"for",
- .@"switch",
- .switch_comma,
- .call_one,
- .call_one_comma,
- .call,
- .call_comma,
- .block_two,
- .block_two_semicolon,
- .block,
- .block_semicolon,
- .builtin_call,
- .builtin_call_comma,
- .builtin_call_two,
- .builtin_call_two_comma,
- .ptr_type_aligned,
- .ptr_type_sentinel,
- .ptr_type,
- .ptr_type_bit_range,
- .optional_type,
- .anyframe_type,
- .array_type_sentinel,
- => return false,
-
- // these are function bodies, not pointers
- .fn_proto_simple,
- .fn_proto_multi,
- .fn_proto_one,
- .fn_proto,
- => return true,
-
- // Forward the question to the LHS sub-expression.
- .@"try",
- .@"comptime",
- .@"nosuspend",
- => node = tree.nodeData(node).node,
- .grouped_expression,
- .unwrap_optional,
- => node = tree.nodeData(node).node_and_token[0],
-
- .identifier => {
- const ident_bytes = tree.tokenSlice(tree.nodeMainToken(node));
- if (primitive_instrs.get(ident_bytes)) |primitive| switch (primitive) {
- .anyerror_type,
- .anyframe_type,
- .anyopaque_type,
- .bool_type,
- .c_int_type,
- .c_long_type,
- .c_longdouble_type,
- .c_longlong_type,
- .c_char_type,
- .c_short_type,
- .c_uint_type,
- .c_ulong_type,
- .c_ulonglong_type,
- .c_ushort_type,
- .f16_type,
- .f32_type,
- .f64_type,
- .f80_type,
- .f128_type,
- .i16_type,
- .i32_type,
- .i64_type,
- .i128_type,
- .i8_type,
- .isize_type,
- .u16_type,
- .u29_type,
- .u32_type,
- .u64_type,
- .u128_type,
- .u1_type,
- .u8_type,
- .usize_type,
- .void_type,
- .bool_false,
- .bool_true,
- .null_value,
- .undef,
- .noreturn_type,
- => return false,
-
- .comptime_float_type,
- .comptime_int_type,
- .type_type,
- => return true,
-
- else => unreachable, // that's all the values from `primitives`.
- } else {
- return false;
- }
- },
- }
- }
-}
-
/// Applies `rl` semantics to `result`. Expressions which do not do their own handling of
/// result locations must call this function on their result.
/// As an example, if `ri.rl` is `.ptr`, it will write the result to the pointer.
@@ -13044,18 +12427,19 @@ const GenZir = struct {
fn setStruct(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
src_node: Ast.Node.Index,
- captures_len: u32,
- fields_len: u32,
- decls_len: u32,
- has_backing_int: bool,
+ name_strat: Zir.Inst.NameStrategy,
layout: std.builtin.Type.ContainerLayout,
- known_non_opv: bool,
- known_comptime_only: bool,
+ backing_int_type_body_len: ?u32,
+ decls_len: u32,
+ fields_len: u32,
+ any_field_aligns: bool,
+ any_field_defaults: bool,
any_comptime_fields: bool,
- any_default_inits: bool,
- any_aligned_fields: bool,
fields_hash: std.zig.SrcHash,
- name_strat: Zir.Inst.NameStrategy,
+ captures: []const Zir.Inst.Capture,
+ capture_names: []const Zir.NullTerminatedString,
+ /// The trailing declaration list, field information, and body instructions.
+ remaining: []const u32,
}) !void {
const astgen = gz.astgen;
const gpa = astgen.gpa;
@@ -13063,9 +12447,16 @@ const GenZir = struct {
// Node .root is valid for the root `struct_decl` of a file!
assert(args.src_node != .root or gz.parent.tag == .top);
+ const captures_len: u32 = @intCast(args.captures.len);
+ assert(args.capture_names.len == captures_len);
+
const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);
- try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.StructDecl).@"struct".fields.len + 3);
+ try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.StructDecl).@"struct".fields.len +
+ 4 + // `captures_len`, `decls_len`, `fields_len`, `backing_int_type_body_len`
+ captures_len * 2 + // `capture`, `capture_name`
+ args.remaining.len);
+
const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.StructDecl{
.fields_hash_0 = fields_hash_arr[0],
.fields_hash_1 = fields_hash_arr[1],
@@ -13075,31 +12466,28 @@ const GenZir = struct {
.src_node = args.src_node,
});
- if (args.captures_len != 0) {
- astgen.extra.appendAssumeCapacity(args.captures_len);
- }
- if (args.fields_len != 0) {
- astgen.extra.appendAssumeCapacity(args.fields_len);
- }
- if (args.decls_len != 0) {
- astgen.extra.appendAssumeCapacity(args.decls_len);
- }
+ if (captures_len != 0) astgen.extra.appendAssumeCapacity(captures_len);
+ if (args.decls_len != 0) astgen.extra.appendAssumeCapacity(args.decls_len);
+ if (args.fields_len != 0) astgen.extra.appendAssumeCapacity(args.fields_len);
+ if (args.backing_int_type_body_len) |n| astgen.extra.appendAssumeCapacity(n);
+ astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.captures));
+ astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.capture_names));
+ astgen.extra.appendSliceAssumeCapacity(args.remaining);
+
astgen.instructions.set(@intFromEnum(inst), .{
.tag = .extended,
.data = .{ .extended = .{
.opcode = .struct_decl,
.small = @bitCast(Zir.Inst.StructDecl.Small{
- .has_captures_len = args.captures_len != 0,
- .has_fields_len = args.fields_len != 0,
+ .has_captures_len = captures_len != 0,
.has_decls_len = args.decls_len != 0,
- .has_backing_int = args.has_backing_int,
- .known_non_opv = args.known_non_opv,
- .known_comptime_only = args.known_comptime_only,
+ .has_fields_len = args.fields_len != 0,
.name_strategy = args.name_strat,
.layout = args.layout,
+ .has_backing_int_type = args.backing_int_type_body_len != null,
+ .any_field_aligns = args.any_field_aligns,
+ .any_field_defaults = args.any_field_defaults,
.any_comptime_fields = args.any_comptime_fields,
- .any_default_inits = args.any_default_inits,
- .any_aligned_fields = args.any_aligned_fields,
}),
.operand = payload_index,
} },
@@ -13108,25 +12496,34 @@ const GenZir = struct {
fn setUnion(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
src_node: Ast.Node.Index,
- tag_type: Zir.Inst.Ref,
- captures_len: u32,
- body_len: u32,
- fields_len: u32,
+ name_strat: Zir.Inst.NameStrategy,
+ kind: Zir.Inst.UnionDecl.Kind,
+ arg_type_body_len: ?u32,
decls_len: u32,
- layout: std.builtin.Type.ContainerLayout,
- auto_enum_tag: bool,
- any_aligned_fields: bool,
+ fields_len: u32,
+ any_field_aligns: bool,
+ any_field_values: bool,
fields_hash: std.zig.SrcHash,
- name_strat: Zir.Inst.NameStrategy,
+ captures: []const Zir.Inst.Capture,
+ capture_names: []const Zir.NullTerminatedString,
+ /// The trailing declaration list, field information, and body instructions.
+ remaining: []const u32,
}) !void {
const astgen = gz.astgen;
const gpa = astgen.gpa;
assert(args.src_node != .root);
+ const captures_len: u32 = @intCast(args.captures.len);
+ assert(args.capture_names.len == captures_len);
+
const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);
- try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.UnionDecl).@"struct".fields.len + 5);
+ try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.UnionDecl).@"struct".fields.len +
+ 4 + // `captures_len`, `decls_len`, `fields_len`, `arg_type_body_len`
+ captures_len * 2 + // `capture`, `capture_name`
+ args.remaining.len);
+
const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.UnionDecl{
.fields_hash_0 = fields_hash_arr[0],
.fields_hash_1 = fields_hash_arr[1],
@@ -13136,35 +12533,30 @@ const GenZir = struct {
.src_node = args.src_node,
});
- if (args.tag_type != .none) {
- astgen.extra.appendAssumeCapacity(@intFromEnum(args.tag_type));
- }
- if (args.captures_len != 0) {
- astgen.extra.appendAssumeCapacity(args.captures_len);
- }
- if (args.body_len != 0) {
- astgen.extra.appendAssumeCapacity(args.body_len);
- }
- if (args.fields_len != 0) {
- astgen.extra.appendAssumeCapacity(args.fields_len);
- }
- if (args.decls_len != 0) {
- astgen.extra.appendAssumeCapacity(args.decls_len);
- }
+ if (captures_len != 0) astgen.extra.appendAssumeCapacity(captures_len);
+ if (args.decls_len != 0) astgen.extra.appendAssumeCapacity(args.decls_len);
+ if (args.fields_len != 0) astgen.extra.appendAssumeCapacity(args.fields_len);
+ if (args.kind.hasArgType()) {
+ astgen.extra.appendAssumeCapacity(args.arg_type_body_len.?);
+ } else {
+ assert(args.arg_type_body_len == null);
+ }
+ astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.captures));
+ astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.capture_names));
+ astgen.extra.appendSliceAssumeCapacity(args.remaining);
+
astgen.instructions.set(@intFromEnum(inst), .{
.tag = .extended,
.data = .{ .extended = .{
.opcode = .union_decl,
.small = @bitCast(Zir.Inst.UnionDecl.Small{
- .has_tag_type = args.tag_type != .none,
- .has_captures_len = args.captures_len != 0,
- .has_body_len = args.body_len != 0,
- .has_fields_len = args.fields_len != 0,
+ .has_captures_len = captures_len != 0,
.has_decls_len = args.decls_len != 0,
+ .has_fields_len = args.fields_len != 0,
.name_strategy = args.name_strat,
- .layout = args.layout,
- .auto_enum_tag = args.auto_enum_tag,
- .any_aligned_fields = args.any_aligned_fields,
+ .kind = args.kind,
+ .any_field_aligns = args.any_field_aligns,
+ .any_field_values = args.any_field_values,
}),
.operand = payload_index,
} },
@@ -13173,23 +12565,33 @@ const GenZir = struct {
fn setEnum(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
src_node: Ast.Node.Index,
- tag_type: Zir.Inst.Ref,
- captures_len: u32,
- body_len: u32,
- fields_len: u32,
- decls_len: u32,
+ name_strat: Zir.Inst.NameStrategy,
+ tag_type_body_len: ?u32,
nonexhaustive: bool,
+ decls_len: u32,
+ fields_len: u32,
+ any_field_values: bool,
fields_hash: std.zig.SrcHash,
- name_strat: Zir.Inst.NameStrategy,
+ captures: []const Zir.Inst.Capture,
+ capture_names: []const Zir.NullTerminatedString,
+ /// The trailing declaration list, field information, and body instructions.
+ remaining: []const u32,
}) !void {
const astgen = gz.astgen;
const gpa = astgen.gpa;
assert(args.src_node != .root);
+ const captures_len: u32 = @intCast(args.captures.len);
+ assert(args.capture_names.len == captures_len);
+
const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);
- try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.EnumDecl).@"struct".fields.len + 5);
+ try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.EnumDecl).@"struct".fields.len +
+ 4 + // `captures_len`, `decls_len`, `fields_len`, `tag_type_body_len`
+ captures_len * 2 + // `capture`, `capture_name`
+ args.remaining.len);
+
const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.EnumDecl{
.fields_hash_0 = fields_hash_arr[0],
.fields_hash_1 = fields_hash_arr[1],
@@ -13199,33 +12601,26 @@ const GenZir = struct {
.src_node = args.src_node,
});
- if (args.tag_type != .none) {
- astgen.extra.appendAssumeCapacity(@intFromEnum(args.tag_type));
- }
- if (args.captures_len != 0) {
- astgen.extra.appendAssumeCapacity(args.captures_len);
- }
- if (args.body_len != 0) {
- astgen.extra.appendAssumeCapacity(args.body_len);
- }
- if (args.fields_len != 0) {
- astgen.extra.appendAssumeCapacity(args.fields_len);
- }
- if (args.decls_len != 0) {
- astgen.extra.appendAssumeCapacity(args.decls_len);
- }
+ if (captures_len != 0) astgen.extra.appendAssumeCapacity(captures_len);
+ if (args.decls_len != 0) astgen.extra.appendAssumeCapacity(args.decls_len);
+ if (args.fields_len != 0) astgen.extra.appendAssumeCapacity(args.fields_len);
+ if (args.tag_type_body_len) |n| astgen.extra.appendAssumeCapacity(n);
+ astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.captures));
+ astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.capture_names));
+ astgen.extra.appendSliceAssumeCapacity(args.remaining);
+
astgen.instructions.set(@intFromEnum(inst), .{
.tag = .extended,
.data = .{ .extended = .{
.opcode = .enum_decl,
.small = @bitCast(Zir.Inst.EnumDecl.Small{
- .has_tag_type = args.tag_type != .none,
- .has_captures_len = args.captures_len != 0,
- .has_body_len = args.body_len != 0,
- .has_fields_len = args.fields_len != 0,
+ .has_captures_len = captures_len != 0,
.has_decls_len = args.decls_len != 0,
+ .has_fields_len = args.fields_len != 0,
.name_strategy = args.name_strat,
+ .has_tag_type = args.tag_type_body_len != null,
.nonexhaustive = args.nonexhaustive,
+ .any_field_values = args.any_field_values,
}),
.operand = payload_index,
} },
@@ -13234,33 +12629,41 @@ const GenZir = struct {
fn setOpaque(gz: *GenZir, inst: Zir.Inst.Index, args: struct {
src_node: Ast.Node.Index,
- captures_len: u32,
- decls_len: u32,
name_strat: Zir.Inst.NameStrategy,
+ decls_len: u32,
+ captures: []const Zir.Inst.Capture,
+ capture_names: []const Zir.NullTerminatedString,
+ decls: []const Zir.Inst.Index,
}) !void {
const astgen = gz.astgen;
const gpa = astgen.gpa;
assert(args.src_node != .root);
- try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.OpaqueDecl).@"struct".fields.len + 2);
+ const captures_len: u32 = @intCast(args.captures.len);
+ assert(args.capture_names.len == captures_len);
+
+ try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.OpaqueDecl).@"struct".fields.len +
+ 2 + // `captures_len`, `decls_len`
+ captures_len * 2 + // `capture`, `capture_name`
+ args.decls.len);
+
const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.OpaqueDecl{
.src_line = astgen.source_line,
.src_node = args.src_node,
});
+ if (captures_len != 0) astgen.extra.appendAssumeCapacity(captures_len);
+ if (args.decls_len != 0) astgen.extra.appendAssumeCapacity(args.decls_len);
+ astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.captures));
+ astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.capture_names));
+ astgen.extra.appendSliceAssumeCapacity(@ptrCast(args.decls));
- if (args.captures_len != 0) {
- astgen.extra.appendAssumeCapacity(args.captures_len);
- }
- if (args.decls_len != 0) {
- astgen.extra.appendAssumeCapacity(args.decls_len);
- }
astgen.instructions.set(@intFromEnum(inst), .{
.tag = .extended,
.data = .{ .extended = .{
.opcode = .opaque_decl,
.small = @bitCast(Zir.Inst.OpaqueDecl.Small{
- .has_captures_len = args.captures_len != 0,
+ .has_captures_len = captures_len != 0,
.has_decls_len = args.decls_len != 0,
.name_strategy = args.name_strat,
}),
@@ -13484,14 +12887,24 @@ fn restoreSourceCursor(astgen: *AstGen, cursor: SourceCursor) void {
astgen.source_column = cursor.column;
}
+const ScanContainerResult = struct {
+ /// Includes unnamed declarations (e.g. `comptime` decls)
+ decls_len: u32,
+ fields_len: u32,
+ any_field_aligns: bool,
+ any_field_values: bool,
+ any_comptime_fields: bool,
+ /// Whether there is a field named `_` (indicating a non-exhaustive enum)
+ has_underscore_field: bool,
+};
+
/// Detects name conflicts for decls and fields, and populates `namespace.decls` with all named declarations.
-/// Returns the number of declarations in the namespace, including unnamed declarations (e.g. `comptime` decls).
fn scanContainer(
astgen: *AstGen,
namespace: *Scope.Namespace,
members: []const Ast.Node.Index,
container_kind: enum { @"struct", @"union", @"enum", @"opaque" },
-) !u32 {
+) !ScanContainerResult {
const gpa = astgen.gpa;
const tree = astgen.tree;
@@ -13521,6 +12934,10 @@ fn scanContainer(
var any_duplicates = false;
var decl_count: u32 = 0;
+ var any_field_aligns = false;
+ var any_field_values = false;
+ var any_comptime_fields = false;
+ var has_underscore_field = false;
for (members) |member_node| {
const Kind = enum { decl, field };
const kind: Kind, const name_token = switch (tree.nodeTag(member_node)) {
@@ -13533,6 +12950,10 @@ fn scanContainer(
.@"struct", .@"opaque" => {},
.@"union", .@"enum" => full.convertToNonTupleLike(astgen.tree),
}
+ if (full.ast.align_expr != .none) any_field_aligns = true;
+ if (full.ast.value_expr != .none) any_field_values = true;
+ if (full.comptime_token != null) any_comptime_fields = true;
+ if (mem.eql(u8, tree.tokenSlice(full.ast.main_token), "_")) has_underscore_field = true;
if (full.ast.tuple_like) continue;
break :blk .{ .field, full.ast.main_token };
},
@@ -13698,7 +13119,14 @@ fn scanContainer(
if (!any_duplicates) {
if (any_invalid_declarations) return error.AnalysisFail;
- return decl_count;
+ return .{
+ .decls_len = decl_count,
+ .fields_len = @intCast(members.len - decl_count),
+ .any_field_aligns = any_field_aligns,
+ .any_field_values = any_field_values,
+ .any_comptime_fields = any_comptime_fields,
+ .has_underscore_field = has_underscore_field,
+ };
}
for (names.keys(), names.values()) |name, first| {
@@ -13954,7 +13382,7 @@ const DeclarationName = union(enum) {
};
fn addFailedDeclaration(
- wip_members: *WipMembers,
+ wip_decls: *WipDecls,
gz: *GenZir,
kind: Zir.Inst.Declaration.Unwrapped.Kind,
name: Zir.NullTerminatedString,
@@ -13962,7 +13390,7 @@ fn addFailedDeclaration(
is_pub: bool,
) !void {
const decl_inst = try gz.makeDeclaration(src_node);
- wip_members.nextDecl(decl_inst);
+ wip_decls.nextDecl(decl_inst);
var dummy_gz = gz.makeSubBlock(&gz.base);
diff --git a/lib/std/zig/ErrorBundle.zig b/lib/std/zig/ErrorBundle.zig
index c5275729ae5f1a6efd58ff65b813cc98863b49ff..ef3cd3d783509ca7de73eba085f6f411d7cc0a30 100644
--- a/lib/std/zig/ErrorBundle.zig
+++ b/lib/std/zig/ErrorBundle.zig
@@ -243,12 +243,14 @@ fn renderErrorMessage(
}
try t.setColor(.reset);
if (src.data.source_line != 0 and options.include_source_line) {
+ try w.splatByteAll(' ', indent);
const line = eb.nullTerminatedString(src.data.source_line);
for (line) |b| switch (b) {
'\t' => try w.writeByte(' '),
else => try w.writeByte(b),
};
try w.writeByte('\n');
+ try w.splatByteAll(' ', indent);
// TODO basic unicode code point monospace width
const before_caret = src.data.span_main - src.data.span_start;
// -1 since span.main includes the caret
@@ -267,11 +269,13 @@ fn renderErrorMessage(
if (src.data.reference_trace_len > 0 and options.include_reference_trace) {
try t.setColor(.reset);
try t.setColor(.dim);
+ try w.splatByteAll(' ', indent);
try w.print("referenced by:\n", .{});
var ref_index = src.end;
for (0..src.data.reference_trace_len) |_| {
const ref_trace = eb.extraData(ReferenceTrace, ref_index);
ref_index = ref_trace.end;
+ try w.splatByteAll(' ', indent);
if (ref_trace.data.src_loc != .none) {
const ref_src = eb.getSourceLocation(ref_trace.data.src_loc);
try w.print(" {s}: {s}:{d}:{d}\n", .{
@@ -340,9 +344,9 @@ pub const Wip = struct {
pub fn init(wip: *Wip, gpa: Allocator) !void {
wip.* = .{
.gpa = gpa,
- .string_bytes = .{},
- .extra = .{},
- .root_list = .{},
+ .string_bytes = .empty,
+ .extra = .empty,
+ .root_list = .empty,
};
// So that 0 can be used to indicate a null string.
@@ -371,9 +375,9 @@ pub const Wip = struct {
wip.deinit();
wip.* = .{
.gpa = gpa,
- .string_bytes = .{},
- .extra = .{},
- .root_list = .{},
+ .string_bytes = .empty,
+ .extra = .empty,
+ .root_list = .empty,
};
return empty;
}
diff --git a/lib/std/zig/Zir.zig b/lib/std/zig/Zir.zig
index 0e76f4ff5bf792d033ee6af276b90663742f06bf..94c76b429cb49845757ac0f4c0c40bc27d9f0c27 100644
--- a/lib/std/zig/Zir.zig
+++ b/lib/std/zig/Zir.zig
@@ -2443,7 +2443,7 @@ pub const Inst = struct {
has_align: bool,
has_addrspace: bool,
has_bit_range: bool,
- _: u1 = undefined,
+ _: u1 = 0,
},
size: std.builtin.Type.Pointer.Size,
/// Index into extra. See `PtrType`.
@@ -2668,7 +2668,7 @@ pub const Inst = struct {
has_ret_ty_body: bool,
has_any_noalias: bool,
ret_ty_is_generic: bool,
- _: u23 = undefined,
+ _: u23 = 0,
};
};
@@ -3134,7 +3134,7 @@ pub const Inst = struct {
pub const Flags = packed struct {
is_nosuspend: bool,
ensure_result_used: bool,
- _: u30 = undefined,
+ _: u30 = 0,
comptime {
if (@sizeOf(Flags) != 4 or @bitSizeOf(Flags) != 32)
@@ -3462,33 +3462,21 @@ pub const Inst = struct {
};
/// Trailing:
- /// 0. captures_len: u32 // if has_captures_len
- /// 1. fields_len: u32, // if has_fields_len
- /// 2. decls_len: u32, // if has_decls_len
- /// 3. capture: Capture // for every captures_len
- /// 4. capture_name: NullTerminatedString // for every captures_len
- /// 5. backing_int_body_len: u32, // if has_backing_int
- /// 6. backing_int_ref: Ref, // if has_backing_int and backing_int_body_len is 0
- /// 7. backing_int_body_inst: Inst, // if has_backing_int and backing_int_body_len is > 0
- /// 8. decl: Index, // for every decls_len; points to a `declaration` instruction
- /// 9. flags: u32 // for every 8 fields
- /// - sets of 4 bits:
- /// 0b000X: whether corresponding field has an align expression
- /// 0b00X0: whether corresponding field has a default expression
- /// 0b0X00: whether corresponding field is comptime
- /// 0bX000: whether corresponding field has a type expression
- /// 10. fields: { // for every fields_len
- /// field_name: u32,
- /// field_type: Ref, // if corresponding bit is not set. none means anytype.
- /// field_type_body_len: u32, // if corresponding bit is set
- /// align_body_len: u32, // if corresponding bit is set
- /// init_body_len: u32, // if corresponding bit is set
- /// }
- /// 11. bodies: { // for every fields_len
- /// field_type_body_inst: Inst, // for each field_type_body_len
- /// align_body_inst: Inst, // for each align_body_len
- /// init_body_inst: Inst, // for each init_body_len
- /// }
+ /// 0. captures_len: u32 // if `has_captures_len`
+ /// 1. decls_len: u32, // if `has_decls_len`
+ /// 2. fields_len: u32, // if `has_fields_len`
+ /// 3. backing_int_body_len: u32 // if `has_backing_int`
+ /// 4. capture: Capture // for every `captures_len`
+ /// 5. capture_name: NullTerminatedString // for every `captures_len`
+ /// 6. decl: Index, // for every `decls_len`; points to a `declaration` instruction
+ /// 7. field_name: NullTerminatedString // for every `fields_len`
+ /// 8. field_type_body_len: u32 // for every `fields_len`
+ /// 9. field_align_body_len: u32 // for every `fields_len` if `any_field_aligns`
+ /// 10. field_default_body_len: u32 // for every `fields_len` if `any_field_defaults`
+ /// 11. field_comptime_bits: u32 // one bit per `fields_len` if `any_comptime_fields`
+ /// // LSB is first field, minimum number of `u32` needed
+ /// 12. backing_int_body_inst: Inst.Index // for each `backing_int_body_len`
+ /// 13. body_inst: Inst.Index // type body, then align body, then default body, for each field
pub const StructDecl = struct {
// These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`.
// This hash contains the source of all fields, and any specified attributes (`extern`, backing type, etc).
@@ -3500,19 +3488,18 @@ pub const Inst = struct {
/// This node provides a new absolute baseline node for all instructions within this struct.
src_node: Ast.Node.Index,
- pub const Small = packed struct {
+ pub const Small = packed struct(u16) {
has_captures_len: bool,
- has_fields_len: bool,
has_decls_len: bool,
- has_backing_int: bool,
- known_non_opv: bool,
- known_comptime_only: bool,
+ has_fields_len: bool,
name_strategy: NameStrategy,
layout: std.builtin.Type.ContainerLayout,
- any_default_inits: bool,
+ /// Always `false` if `layout != .@"packed"`.
+ has_backing_int_type: bool,
+ any_field_aligns: bool,
+ any_field_defaults: bool,
any_comptime_fields: bool,
- any_aligned_fields: bool,
- _: u3 = undefined,
+ _: u5 = 0,
};
};
@@ -3633,21 +3620,17 @@ pub const Inst = struct {
};
/// Trailing:
- /// 0. tag_type: Ref, // if has_tag_type
- /// 1. captures_len: u32, // if has_captures_len
- /// 2. body_len: u32, // if has_body_len
- /// 3. fields_len: u32, // if has_fields_len
- /// 4. decls_len: u32, // if has_decls_len
- /// 5. capture: Capture // for every captures_len
- /// 6. capture_name: NullTerminatedString // for every captures_len
- /// 7. decl: Index, // for every decls_len; points to a `declaration` instruction
- /// 8. inst: Index // for every body_len
- /// 9. has_bits: u32 // for every 32 fields
- /// - the bit is whether corresponding field has an value expression
- /// 10. fields: { // for every fields_len
- /// field_name: u32,
- /// value: Ref, // if corresponding bit is set
- /// }
+ /// 0. captures_len: u32, // if has_captures_len
+ /// 1. decls_len: u32, // if has_decls_len
+ /// 2. fields_len: u32, // if has_fields_len
+ /// 3. tag_type_body_len: u32, // if has_tag_type
+ /// 4. capture: Capture // for every `captures_len`
+ /// 5. capture_name: NullTerminatedString // for every `captures_len`
+ /// 6. decl: Index, // for every `decls_len`; points to a `declaration` instruction
+ /// 7. field_name: NullTerminatedString // for every `fields_len`
+ /// 8. field_value_body_len: u32 // for every `fields_len` if `any_field_values`
+ /// 9. tag_type_body_inst: Inst.Index // for each `tag_type_body_len`
+ /// 10. body_inst: Inst.Index // value body for each field
pub const EnumDecl = struct {
// These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`.
// This hash contains the source of all fields, and the backing type if specified.
@@ -3659,40 +3642,32 @@ pub const Inst = struct {
/// This node provides a new absolute baseline node for all instructions within this struct.
src_node: Ast.Node.Index,
- pub const Small = packed struct {
- has_tag_type: bool,
+ pub const Small = packed struct(u16) {
has_captures_len: bool,
- has_body_len: bool,
- has_fields_len: bool,
has_decls_len: bool,
+ has_fields_len: bool,
name_strategy: NameStrategy,
+ has_tag_type: bool,
nonexhaustive: bool,
- _: u8 = undefined,
+ any_field_values: bool,
+ _: u8 = 0,
};
};
/// Trailing:
- /// 0. tag_type: Ref, // if has_tag_type
- /// 1. captures_len: u32 // if has_captures_len
- /// 2. body_len: u32, // if has_body_len
- /// 3. fields_len: u32, // if has_fields_len
- /// 4. decls_len: u32, // if has_decls_len
- /// 5. capture: Capture // for every captures_len
- /// 6. capture_name: NullTerminatedString // for every captures_len
- /// 7. decl: Index, // for every decls_len; points to a `declaration` instruction
- /// 8. inst: Index // for every body_len
- /// 9. has_bits: u32 // for every 8 fields
- /// - sets of 4 bits:
- /// 0b000X: whether corresponding field has a type expression
- /// 0b00X0: whether corresponding field has a align expression
- /// 0b0X00: whether corresponding field has a tag value expression
- /// 0bX000: unused
- /// 10. fields: { // for every fields_len
- /// field_name: NullTerminatedString, // null terminated string index
- /// field_type: Ref, // if corresponding bit is set
- /// align: Ref, // if corresponding bit is set
- /// tag_value: Ref, // if corresponding bit is set
- /// }
+ /// 0. captures_len: u32 // if `has_captures_len`
+ /// 1. decls_len: u32, // if `has_decls_len`
+ /// 2. fields_len: u32, // if `has_fields_len`
+ /// 3. arg_type_body_len: u32, // if `kind.hasArgType()`
+ /// 4. capture: Capture // for every `captures_len`
+ /// 5. capture_name: NullTerminatedString // for every `captures_len`
+ /// 6. decl: Index, // for every `decls_len`; points to a `declaration` instruction
+ /// 7. field_name: NullTerminatedString // for every `fields_len`
+ /// 8. field_type_body_len: u32 // for every `fields_len`
+ /// 9 . field_align_body_len: u32 // for every `fields_len` if `any_field_aligns`
+ /// 10. field_value_body_len: u32 // for every `fields_len` if `any_field_values`
+ /// 11. arg_type_body_inst: Inst.Index // for each `arg_type_body_len`
+ /// 12. body_inst: Inst.Index // type body, then align body, then value body, for each field
pub const UnionDecl = struct {
// These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`.
// This hash contains the source of all fields, and any specified attributes (`extern` etc).
@@ -3704,23 +3679,47 @@ pub const Inst = struct {
/// This node provides a new absolute baseline node for all instructions within this struct.
src_node: Ast.Node.Index,
- pub const Small = packed struct {
- has_tag_type: bool,
+ pub const Small = packed struct(u16) {
has_captures_len: bool,
- has_body_len: bool,
- has_fields_len: bool,
has_decls_len: bool,
+ has_fields_len: bool,
name_strategy: NameStrategy,
- layout: std.builtin.Type.ContainerLayout,
- /// has_tag_type | auto_enum_tag | result
- /// -------------------------------------
- /// false | false | union { }
- /// false | true | union(enum) { }
- /// true | true | union(enum(T)) { }
- /// true | false | union(T) { }
- auto_enum_tag: bool,
- any_aligned_fields: bool,
- _: u5 = undefined,
+ kind: Kind,
+ any_field_aligns: bool,
+ any_field_values: bool,
+ _: u6 = 0,
+ };
+
+ pub const Kind = enum(u3) {
+ /// `union`
+ auto,
+ /// `union(T)`
+ tagged_explicit,
+ /// `union(enum)`
+ tagged_enum,
+ /// `union(enum(T))`
+ tagged_enum_explicit,
+ /// `extern union`
+ @"extern",
+ /// `packed union`
+ @"packed",
+ /// `packed union(T)`
+ packed_explicit,
+
+ pub fn hasArgType(k: Kind) bool {
+ return switch (k) {
+ .auto, .tagged_enum, .@"extern", .@"packed" => false,
+ .tagged_explicit, .tagged_enum_explicit, .packed_explicit => true,
+ };
+ }
+
+ pub fn layout(k: Kind) std.builtin.Type.ContainerLayout {
+ return switch (k) {
+ .auto, .tagged_explicit, .tagged_enum, .tagged_enum_explicit => .auto,
+ .@"extern" => .@"extern",
+ .@"packed", .packed_explicit => .@"packed",
+ };
+ }
};
};
@@ -3735,11 +3734,11 @@ pub const Inst = struct {
/// This node provides a new absolute baseline node for all instructions within this struct.
src_node: Ast.Node.Index,
- pub const Small = packed struct {
+ pub const Small = packed struct(u16) {
has_captures_len: bool,
has_decls_len: bool,
name_strategy: NameStrategy,
- _: u12 = undefined,
+ _: u12 = 0,
};
};
@@ -3904,12 +3903,12 @@ pub const Inst = struct {
pub const AllocExtended = struct {
src_node: Ast.Node.Offset,
- pub const Small = packed struct {
+ pub const Small = packed struct(u16) {
has_type: bool,
has_align: bool,
is_const: bool,
is_comptime: bool,
- _: u12 = undefined,
+ _: u12 = 0,
};
};
@@ -4012,135 +4011,6 @@ pub const Inst = struct {
};
};
-pub const DeclIterator = struct {
- extra_index: u32,
- decls_remaining: u32,
- zir: Zir,
-
- pub fn next(it: *DeclIterator) ?Inst.Index {
- if (it.decls_remaining == 0) return null;
- const decl_inst: Zir.Inst.Index = @enumFromInt(it.zir.extra[it.extra_index]);
- it.extra_index += 1;
- it.decls_remaining -= 1;
- assert(it.zir.instructions.items(.tag)[@intFromEnum(decl_inst)] == .declaration);
- return decl_inst;
- }
-};
-
-pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
- const inst = zir.instructions.get(@intFromEnum(decl_inst));
- assert(inst.tag == .extended);
- const extended = inst.data.extended;
- switch (extended.opcode) {
- .struct_decl => {
- const small: Inst.StructDecl.Small = @bitCast(extended.small);
- var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.StructDecl).@"struct".fields.len);
- const captures_len = if (small.has_captures_len) captures_len: {
- const captures_len = zir.extra[extra_index];
- extra_index += 1;
- break :captures_len captures_len;
- } else 0;
- extra_index += @intFromBool(small.has_fields_len);
- const decls_len = if (small.has_decls_len) decls_len: {
- const decls_len = zir.extra[extra_index];
- extra_index += 1;
- break :decls_len decls_len;
- } else 0;
-
- extra_index += captures_len * 2;
-
- if (small.has_backing_int) {
- const backing_int_body_len = zir.extra[extra_index];
- extra_index += 1; // backing_int_body_len
- if (backing_int_body_len == 0) {
- extra_index += 1; // backing_int_ref
- } else {
- extra_index += backing_int_body_len; // backing_int_body_inst
- }
- }
-
- return .{
- .extra_index = extra_index,
- .decls_remaining = decls_len,
- .zir = zir,
- };
- },
- .enum_decl => {
- const small: Inst.EnumDecl.Small = @bitCast(extended.small);
- var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.EnumDecl).@"struct".fields.len);
- extra_index += @intFromBool(small.has_tag_type);
- const captures_len = if (small.has_captures_len) captures_len: {
- const captures_len = zir.extra[extra_index];
- extra_index += 1;
- break :captures_len captures_len;
- } else 0;
- extra_index += @intFromBool(small.has_body_len);
- extra_index += @intFromBool(small.has_fields_len);
- const decls_len = if (small.has_decls_len) decls_len: {
- const decls_len = zir.extra[extra_index];
- extra_index += 1;
- break :decls_len decls_len;
- } else 0;
-
- extra_index += captures_len * 2;
-
- return .{
- .extra_index = extra_index,
- .decls_remaining = decls_len,
- .zir = zir,
- };
- },
- .union_decl => {
- const small: Inst.UnionDecl.Small = @bitCast(extended.small);
- var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.UnionDecl).@"struct".fields.len);
- extra_index += @intFromBool(small.has_tag_type);
- const captures_len = if (small.has_captures_len) captures_len: {
- const captures_len = zir.extra[extra_index];
- extra_index += 1;
- break :captures_len captures_len;
- } else 0;
- extra_index += @intFromBool(small.has_body_len);
- extra_index += @intFromBool(small.has_fields_len);
- const decls_len = if (small.has_decls_len) decls_len: {
- const decls_len = zir.extra[extra_index];
- extra_index += 1;
- break :decls_len decls_len;
- } else 0;
-
- extra_index += captures_len * 2;
-
- return .{
- .extra_index = extra_index,
- .decls_remaining = decls_len,
- .zir = zir,
- };
- },
- .opaque_decl => {
- const small: Inst.OpaqueDecl.Small = @bitCast(extended.small);
- var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.OpaqueDecl).@"struct".fields.len);
- const decls_len = if (small.has_decls_len) decls_len: {
- const decls_len = zir.extra[extra_index];
- extra_index += 1;
- break :decls_len decls_len;
- } else 0;
- const captures_len = if (small.has_captures_len) captures_len: {
- const captures_len = zir.extra[extra_index];
- extra_index += 1;
- break :captures_len captures_len;
- } else 0;
-
- extra_index += captures_len * 2;
-
- return .{
- .extra_index = extra_index,
- .decls_remaining = decls_len,
- .zir = zir,
- };
- },
- else => unreachable,
- }
-}
-
/// `DeclContents` contains all "interesting" instructions found within a declaration by `findTrackable`.
/// These instructions are partitioned into a few different sets, since this makes ZIR instruction mapping
/// more effective.
@@ -4524,7 +4394,7 @@ fn findTrackableInner(
try zir.findTrackableBody(gpa, contents, defers, body);
},
- // Reifications and opaque declarations need tracking, but have no body.
+ // Reifications and opaque declarations need tracking, but have no bodies.
.reify_enum,
.reify_struct,
.reify_union,
@@ -4535,150 +4405,37 @@ fn findTrackableInner(
.struct_decl => {
try contents.explicit_types.append(gpa, inst);
- const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
- const extra = zir.extraData(Zir.Inst.StructDecl, extended.operand);
- var extra_index = extra.end;
- const captures_len = if (small.has_captures_len) blk: {
- const captures_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk captures_len;
- } else 0;
- const fields_len = if (small.has_fields_len) blk: {
- const fields_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk fields_len;
- } else 0;
- const decls_len = if (small.has_decls_len) blk: {
- const decls_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk decls_len;
- } else 0;
- extra_index += captures_len * 2;
- if (small.has_backing_int) {
- const backing_int_body_len = zir.extra[extra_index];
- extra_index += 1;
- if (backing_int_body_len == 0) {
- extra_index += 1; // backing_int_ref
- } else {
- const body = zir.bodySlice(extra_index, backing_int_body_len);
- extra_index += backing_int_body_len;
- try zir.findTrackableBody(gpa, contents, defers, body);
- }
+ const struct_decl = zir.getStructDecl(inst);
+ var it = struct_decl.iterateFields();
+ while (it.next()) |field| {
+ try zir.findTrackableBody(gpa, contents, defers, field.type_body);
+ if (field.align_body) |b| try zir.findTrackableBody(gpa, contents, defers, b);
+ if (field.default_body) |b| try zir.findTrackableBody(gpa, contents, defers, b);
}
- extra_index += decls_len;
-
- // This ZIR is structured in a slightly awkward way, so we have to split up the iteration.
- // `extra_index` iterates `flags` (bags of bits).
- // `fields_extra_index` iterates `fields`.
- // We accumulate the total length of bodies into `total_bodies_len`. This is sufficient because
- // the bodies are packed together in `extra` and we only need to traverse their instructions (we
- // don't really care about the structure).
-
- const bits_per_field = 4;
- const fields_per_u32 = 32 / bits_per_field;
- const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
- var cur_bit_bag: u32 = undefined;
-
- var fields_extra_index = extra_index + bit_bags_count;
- var total_bodies_len: u32 = 0;
-
- for (0..fields_len) |field_i| {
- if (field_i % fields_per_u32 == 0) {
- cur_bit_bag = zir.extra[extra_index];
- extra_index += 1;
- }
-
- const has_align = @as(u1, @truncate(cur_bit_bag)) != 0;
- cur_bit_bag >>= 1;
- const has_init = @as(u1, @truncate(cur_bit_bag)) != 0;
- cur_bit_bag >>= 2; // also skip `is_comptime`; we don't care
- const has_type_body = @as(u1, @truncate(cur_bit_bag)) != 0;
- cur_bit_bag >>= 1;
-
- fields_extra_index += 1; // field_name
-
- if (has_type_body) {
- const field_type_body_len = zir.extra[fields_extra_index];
- total_bodies_len += field_type_body_len;
- }
- fields_extra_index += 1; // field_type or field_type_body_len
-
- if (has_align) {
- const align_body_len = zir.extra[fields_extra_index];
- fields_extra_index += 1;
- total_bodies_len += align_body_len;
- }
-
- if (has_init) {
- const init_body_len = zir.extra[fields_extra_index];
- fields_extra_index += 1;
- total_bodies_len += init_body_len;
- }
- }
-
- // Now, `fields_extra_index` points to `bodies`. Let's treat this as one big body.
- const merged_bodies = zir.bodySlice(fields_extra_index, total_bodies_len);
- try zir.findTrackableBody(gpa, contents, defers, merged_bodies);
},
- // Union declarations need tracking and have a body.
+ // Union declarations need tracking and have bodies.
.union_decl => {
try contents.explicit_types.append(gpa, inst);
- const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
- const extra = zir.extraData(Zir.Inst.UnionDecl, extended.operand);
- var extra_index = extra.end;
- extra_index += @intFromBool(small.has_tag_type);
- const captures_len = if (small.has_captures_len) blk: {
- const captures_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk captures_len;
- } else 0;
- const body_len = if (small.has_body_len) blk: {
- const body_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk body_len;
- } else 0;
- extra_index += @intFromBool(small.has_fields_len);
- const decls_len = if (small.has_decls_len) blk: {
- const decls_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk decls_len;
- } else 0;
- extra_index += captures_len * 2;
- extra_index += decls_len;
- const body = zir.bodySlice(extra_index, body_len);
- try zir.findTrackableBody(gpa, contents, defers, body);
+ const union_decl = zir.getUnionDecl(inst);
+ var it = union_decl.iterateFields();
+ while (it.next()) |field| {
+ if (field.type_body) |b| try zir.findTrackableBody(gpa, contents, defers, b);
+ if (field.align_body) |b| try zir.findTrackableBody(gpa, contents, defers, b);
+ if (field.value_body) |b| try zir.findTrackableBody(gpa, contents, defers, b);
+ }
},
- // Enum declarations need tracking and have a body.
+ // Enum declarations need tracking and have bodies.
.enum_decl => {
try contents.explicit_types.append(gpa, inst);
- const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small);
- const extra = zir.extraData(Zir.Inst.EnumDecl, extended.operand);
- var extra_index = extra.end;
- extra_index += @intFromBool(small.has_tag_type);
- const captures_len = if (small.has_captures_len) blk: {
- const captures_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk captures_len;
- } else 0;
- const body_len = if (small.has_body_len) blk: {
- const body_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk body_len;
- } else 0;
- extra_index += @intFromBool(small.has_fields_len);
- const decls_len = if (small.has_decls_len) blk: {
- const decls_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk decls_len;
- } else 0;
- extra_index += captures_len * 2;
- extra_index += decls_len;
- const body = zir.bodySlice(extra_index, body_len);
- try zir.findTrackableBody(gpa, contents, defers, body);
+ const enum_decl = zir.getEnumDecl(inst);
+ var it = enum_decl.iterateFields();
+ while (it.next()) |field| {
+ if (field.value_body) |b| try zir.findTrackableBody(gpa, contents, defers, b);
+ }
},
}
},
@@ -5481,34 +5238,455 @@ pub fn assertTrackable(zir: Zir, inst_idx: Zir.Inst.Index) void {
}
}
-pub fn typeCapturesLen(zir: Zir, type_decl: Inst.Index) u32 {
+pub fn typeDecls(zir: Zir, type_decl: Inst.Index) []const Zir.Inst.Index {
const inst = zir.instructions.get(@intFromEnum(type_decl));
assert(inst.tag == .extended);
- switch (inst.data.extended.opcode) {
- .struct_decl => {
- const small: Inst.StructDecl.Small = @bitCast(inst.data.extended.small);
- if (!small.has_captures_len) return 0;
- const extra = zir.extraData(Inst.StructDecl, inst.data.extended.operand);
- return zir.extra[extra.end];
- },
- .union_decl => {
- const small: Inst.UnionDecl.Small = @bitCast(inst.data.extended.small);
- if (!small.has_captures_len) return 0;
- const extra = zir.extraData(Inst.UnionDecl, inst.data.extended.operand);
- return zir.extra[extra.end + @intFromBool(small.has_tag_type)];
- },
- .enum_decl => {
- const small: Inst.EnumDecl.Small = @bitCast(inst.data.extended.small);
- if (!small.has_captures_len) return 0;
- const extra = zir.extraData(Inst.EnumDecl, inst.data.extended.operand);
- return zir.extra[extra.end + @intFromBool(small.has_tag_type)];
- },
- .opaque_decl => {
- const small: Inst.OpaqueDecl.Small = @bitCast(inst.data.extended.small);
- if (!small.has_captures_len) return 0;
- const extra = zir.extraData(Inst.OpaqueDecl, inst.data.extended.operand);
- return zir.extra[extra.end];
- },
+ return switch (inst.data.extended.opcode) {
+ .struct_decl => zir.getStructDecl(type_decl).decls,
+ .union_decl => zir.getUnionDecl(type_decl).decls,
+ .enum_decl => zir.getEnumDecl(type_decl).decls,
+ .opaque_decl => zir.getOpaqueDecl(type_decl).decls,
else => unreachable,
+ };
+}
+
+pub fn getStructDecl(zir: *const Zir, struct_decl: Inst.Index) UnwrappedStructDecl {
+ const inst_data = zir.instructions.get(@intFromEnum(struct_decl));
+ assert(inst_data.tag == .extended);
+ assert(inst_data.data.extended.opcode == .struct_decl);
+ const small: Inst.StructDecl.Small = @bitCast(inst_data.data.extended.small);
+ const extra = zir.extraData(Inst.StructDecl, inst_data.data.extended.operand);
+ var extra_index = extra.end;
+ const captures_len: u32 = if (small.has_captures_len) blk: {
+ const captures_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :blk captures_len;
+ } else 0;
+ const decls_len: u32 = if (small.has_decls_len) blk: {
+ const decls_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :blk decls_len;
+ } else 0;
+ const fields_len: u32 = if (small.has_fields_len) blk: {
+ const fields_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :blk fields_len;
+ } else 0;
+ const backing_int_type_body_len: u32 = if (small.has_backing_int_type) len: {
+ const body_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :len body_len;
+ } else 0;
+ const captures: []const Inst.Capture = @ptrCast(zir.extra[extra_index..][0..captures_len]);
+ extra_index += captures_len;
+ const capture_names: []const NullTerminatedString = @ptrCast(zir.extra[extra_index..][0..captures_len]);
+ extra_index += captures_len;
+ const decls: []const Inst.Index = @ptrCast(zir.extra[extra_index..][0..decls_len]);
+ extra_index += decls_len;
+ const field_names: []const NullTerminatedString = @ptrCast(zir.extra[extra_index..][0..fields_len]);
+ extra_index += fields_len;
+ const field_type_body_lens: []const u32 = @ptrCast(zir.extra[extra_index..][0..fields_len]);
+ extra_index += fields_len;
+ const field_align_body_lens: ?[]const u32 = if (small.any_field_aligns) lens: {
+ const lens = zir.extra[extra_index..][0..fields_len];
+ extra_index += fields_len;
+ break :lens @ptrCast(lens);
+ } else null;
+ const field_default_body_lens: ?[]const u32 = if (small.any_field_defaults) lens: {
+ const lens = zir.extra[extra_index..][0..fields_len];
+ extra_index += fields_len;
+ break :lens @ptrCast(lens);
+ } else null;
+ const field_comptime_bits: ?[]const u32 = if (small.any_comptime_fields) bits: {
+ const bits_len = std.math.divCeil(u32, fields_len, 32) catch unreachable;
+ const bits = zir.extra[extra_index..][0..bits_len];
+ extra_index += bits_len;
+ break :bits bits;
+ } else null;
+ const backing_int_type_body: ?[]const Zir.Inst.Index = switch (backing_int_type_body_len) {
+ 0 => null,
+ else => |n| zir.bodySlice(extra_index, n),
+ };
+ extra_index += backing_int_type_body_len;
+ const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]);
+ return .{
+ .src_line = extra.data.src_line,
+ .src_node = extra.data.src_node,
+ .name_strategy = small.name_strategy,
+ .captures = captures,
+ .capture_names = capture_names,
+ .decls = decls,
+ .layout = small.layout,
+ .backing_int_type_body = backing_int_type_body,
+ .field_names = field_names,
+ .field_type_body_lens = field_type_body_lens,
+ .field_align_body_lens = field_align_body_lens,
+ .field_default_body_lens = field_default_body_lens,
+ .field_comptime_bits = field_comptime_bits,
+ .field_bodies_overlong = field_bodies_overlong,
+ };
+}
+pub const UnwrappedStructDecl = struct {
+ src_line: u32,
+ src_node: Ast.Node.Index,
+ name_strategy: Inst.NameStrategy,
+
+ captures: []const Inst.Capture,
+ capture_names: []const NullTerminatedString,
+
+ decls: []const Inst.Index,
+
+ layout: std.builtin.Type.ContainerLayout,
+ backing_int_type_body: ?[]const Inst.Index,
+
+ field_names: []const NullTerminatedString,
+ field_type_body_lens: []const u32,
+ field_align_body_lens: ?[]const u32,
+ field_default_body_lens: ?[]const u32,
+ field_comptime_bits: ?[]const u32,
+ field_bodies_overlong: []const Inst.Index,
+
+ pub fn iterateFields(struct_decl: UnwrappedStructDecl) FieldIterator {
+ return .{
+ .next_idx = 0,
+ .names = struct_decl.field_names,
+ .type_body_lens = struct_decl.field_type_body_lens,
+ .align_body_lens = struct_decl.field_align_body_lens,
+ .default_body_lens = struct_decl.field_default_body_lens,
+ .comptime_bits = struct_decl.field_comptime_bits,
+ .bodies_overlong = struct_decl.field_bodies_overlong,
+ };
+ }
+
+ pub const FieldIterator = struct {
+ next_idx: u32,
+ names: []const NullTerminatedString,
+ type_body_lens: []const u32,
+ align_body_lens: ?[]const u32,
+ default_body_lens: ?[]const u32,
+ comptime_bits: ?[]const u32,
+ bodies_overlong: []const Inst.Index,
+ pub const Field = struct {
+ idx: u32,
+ name: NullTerminatedString,
+ type_body: []const Inst.Index,
+ align_body: ?[]const Inst.Index,
+ default_body: ?[]const Inst.Index,
+ is_comptime: bool,
+ };
+ pub fn next(it: *FieldIterator) ?Field {
+ const idx = it.next_idx;
+ if (idx == it.names.len) return null;
+ it.next_idx += 1;
+ return .{
+ .idx = idx,
+ .name = it.names[idx],
+ .type_body = it.body(it.type_body_lens[idx]).?,
+ .align_body = it.body(if (it.align_body_lens) |l| l[idx] else 0),
+ .default_body = it.body(if (it.default_body_lens) |l| l[idx] else 0),
+ .is_comptime = ct: {
+ const bits = it.comptime_bits orelse break :ct false;
+ const big = bits[idx / 32];
+ const shifted = big >> @intCast(idx % 32);
+ break :ct @as(u1, @truncate(shifted)) == 1;
+ },
+ };
+ }
+ fn body(it: *FieldIterator, len: u32) ?[]const Inst.Index {
+ if (len == 0) return null;
+ const b = it.bodies_overlong[0..len];
+ it.bodies_overlong = it.bodies_overlong[len..];
+ return b;
+ }
+ };
+};
+
+pub fn getUnionDecl(zir: *const Zir, union_decl: Inst.Index) UnwrappedUnionDecl {
+ const inst_data = zir.instructions.get(@intFromEnum(union_decl));
+ assert(inst_data.tag == .extended);
+ assert(inst_data.data.extended.opcode == .union_decl);
+ const small: Inst.UnionDecl.Small = @bitCast(inst_data.data.extended.small);
+ const extra = zir.extraData(Inst.UnionDecl, inst_data.data.extended.operand);
+ var extra_index = extra.end;
+ const captures_len: u32 = if (small.has_captures_len) blk: {
+ const captures_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :blk captures_len;
+ } else 0;
+ const decls_len: u32 = if (small.has_decls_len) blk: {
+ const decls_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :blk decls_len;
+ } else 0;
+ const fields_len: u32 = if (small.has_fields_len) blk: {
+ const fields_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :blk fields_len;
+ } else 0;
+ const arg_type_body_len: u32 = if (small.kind.hasArgType()) len: {
+ const body_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :len body_len;
+ } else 0;
+ const captures: []const Inst.Capture = @ptrCast(zir.extra[extra_index..][0..captures_len]);
+ extra_index += captures_len;
+ const capture_names: []const NullTerminatedString = @ptrCast(zir.extra[extra_index..][0..captures_len]);
+ extra_index += captures_len;
+ const decls: []const Inst.Index = @ptrCast(zir.extra[extra_index..][0..decls_len]);
+ extra_index += decls_len;
+ const field_names: []const NullTerminatedString = @ptrCast(zir.extra[extra_index..][0..fields_len]);
+ extra_index += fields_len;
+ const field_type_body_lens: []const u32 = @ptrCast(zir.extra[extra_index..][0..fields_len]);
+ extra_index += fields_len;
+ const field_align_body_lens: ?[]const u32 = if (small.any_field_aligns) lens: {
+ const lens = zir.extra[extra_index..][0..fields_len];
+ extra_index += fields_len;
+ break :lens @ptrCast(lens);
+ } else null;
+ const field_value_body_lens: ?[]const u32 = if (small.any_field_values) lens: {
+ const lens = zir.extra[extra_index..][0..fields_len];
+ extra_index += fields_len;
+ break :lens @ptrCast(lens);
+ } else null;
+ const arg_type_body: ?[]const Zir.Inst.Index = switch (arg_type_body_len) {
+ 0 => null,
+ else => |n| zir.bodySlice(extra_index, n),
+ };
+ extra_index += arg_type_body_len;
+ const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]);
+ return .{
+ .src_line = extra.data.src_line,
+ .src_node = extra.data.src_node,
+ .name_strategy = small.name_strategy,
+ .captures = captures,
+ .capture_names = capture_names,
+ .decls = decls,
+ .kind = small.kind,
+ .arg_type_body = arg_type_body,
+ .field_names = field_names,
+ .field_type_body_lens = field_type_body_lens,
+ .field_align_body_lens = field_align_body_lens,
+ .field_value_body_lens = field_value_body_lens,
+ .field_bodies_overlong = field_bodies_overlong,
+ };
+}
+pub const UnwrappedUnionDecl = struct {
+ src_line: u32,
+ src_node: Ast.Node.Index,
+ name_strategy: Inst.NameStrategy,
+
+ captures: []const Inst.Capture,
+ capture_names: []const NullTerminatedString,
+
+ decls: []const Inst.Index,
+
+ kind: Inst.UnionDecl.Kind,
+ arg_type_body: ?[]const Inst.Index,
+
+ field_names: []const NullTerminatedString,
+ field_type_body_lens: []const u32,
+ field_align_body_lens: ?[]const u32,
+ field_value_body_lens: ?[]const u32,
+ field_bodies_overlong: []const Inst.Index,
+
+ pub fn iterateFields(union_decl: UnwrappedUnionDecl) FieldIterator {
+ return .{
+ .next_idx = 0,
+ .names = union_decl.field_names,
+ .type_body_lens = union_decl.field_type_body_lens,
+ .align_body_lens = union_decl.field_align_body_lens,
+ .value_body_lens = union_decl.field_value_body_lens,
+ .bodies_overlong = union_decl.field_bodies_overlong,
+ };
+ }
+
+ pub const FieldIterator = struct {
+ next_idx: u32,
+ names: []const NullTerminatedString,
+ type_body_lens: []const u32,
+ align_body_lens: ?[]const u32,
+ value_body_lens: ?[]const u32,
+ bodies_overlong: []const Inst.Index,
+ pub const Field = struct {
+ idx: u32,
+ name: NullTerminatedString,
+ type_body: ?[]const Inst.Index,
+ align_body: ?[]const Inst.Index,
+ value_body: ?[]const Inst.Index,
+ };
+ pub fn next(it: *FieldIterator) ?Field {
+ const idx = it.next_idx;
+ if (idx == it.names.len) return null;
+ it.next_idx += 1;
+ return .{
+ .idx = idx,
+ .name = it.names[idx],
+ .type_body = it.body(it.type_body_lens[idx]),
+ .align_body = it.body(if (it.align_body_lens) |l| l[idx] else 0),
+ .value_body = it.body(if (it.value_body_lens) |l| l[idx] else 0),
+ };
+ }
+ fn body(it: *FieldIterator, len: u32) ?[]const Inst.Index {
+ if (len == 0) return null;
+ const b = it.bodies_overlong[0..len];
+ it.bodies_overlong = it.bodies_overlong[len..];
+ return b;
+ }
+ };
+};
+
+pub fn getEnumDecl(zir: *const Zir, enum_decl: Inst.Index) UnwrappedEnumDecl {
+ const inst_data = zir.instructions.get(@intFromEnum(enum_decl));
+ assert(inst_data.tag == .extended);
+ assert(inst_data.data.extended.opcode == .enum_decl);
+ const small: Inst.EnumDecl.Small = @bitCast(inst_data.data.extended.small);
+ const extra = zir.extraData(Inst.EnumDecl, inst_data.data.extended.operand);
+ var extra_index = extra.end;
+ const captures_len: u32 = if (small.has_captures_len) blk: {
+ const captures_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :blk captures_len;
+ } else 0;
+ const decls_len: u32 = if (small.has_decls_len) blk: {
+ const decls_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :blk decls_len;
+ } else 0;
+ const fields_len: u32 = if (small.has_fields_len) blk: {
+ const fields_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :blk fields_len;
+ } else 0;
+ const tag_type_body_len: u32 = if (small.has_tag_type) len: {
+ const body_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :len body_len;
+ } else 0;
+ const captures: []const Inst.Capture = @ptrCast(zir.extra[extra_index..][0..captures_len]);
+ extra_index += captures_len;
+ const capture_names: []const NullTerminatedString = @ptrCast(zir.extra[extra_index..][0..captures_len]);
+ extra_index += captures_len;
+ const decls: []const Inst.Index = @ptrCast(zir.extra[extra_index..][0..decls_len]);
+ extra_index += decls_len;
+ const field_names: []const NullTerminatedString = @ptrCast(zir.extra[extra_index..][0..fields_len]);
+ extra_index += fields_len;
+ const field_value_body_lens: ?[]const u32 = if (small.any_field_values) lens: {
+ const lens = zir.extra[extra_index..][0..fields_len];
+ extra_index += fields_len;
+ break :lens @ptrCast(lens);
+ } else null;
+ const tag_type_body: ?[]const Zir.Inst.Index = switch (tag_type_body_len) {
+ 0 => null,
+ else => |n| zir.bodySlice(extra_index, n),
+ };
+ extra_index += tag_type_body_len;
+ const field_bodies_overlong: []const Inst.Index = @ptrCast(zir.extra[extra_index..]);
+ return .{
+ .src_line = extra.data.src_line,
+ .src_node = extra.data.src_node,
+ .name_strategy = small.name_strategy,
+ .captures = captures,
+ .capture_names = capture_names,
+ .decls = decls,
+ .tag_type_body = tag_type_body,
+ .nonexhaustive = small.nonexhaustive,
+ .field_names = field_names,
+ .field_value_body_lens = field_value_body_lens,
+ .field_bodies_overlong = field_bodies_overlong,
+ };
+}
+pub const UnwrappedEnumDecl = struct {
+ src_line: u32,
+ src_node: Ast.Node.Index,
+ name_strategy: Inst.NameStrategy,
+
+ captures: []const Inst.Capture,
+ capture_names: []const NullTerminatedString,
+
+ decls: []const Inst.Index,
+
+ tag_type_body: ?[]const Inst.Index,
+ nonexhaustive: bool,
+
+ field_names: []const NullTerminatedString,
+ field_value_body_lens: ?[]const u32,
+ field_bodies_overlong: []const Inst.Index,
+
+ pub fn iterateFields(enum_decl: UnwrappedEnumDecl) FieldIterator {
+ return .{
+ .next_idx = 0,
+ .names = enum_decl.field_names,
+ .value_body_lens = enum_decl.field_value_body_lens,
+ .bodies_overlong = enum_decl.field_bodies_overlong,
+ };
}
+
+ pub const FieldIterator = struct {
+ next_idx: u32,
+ names: []const NullTerminatedString,
+ value_body_lens: ?[]const u32,
+ bodies_overlong: []const Inst.Index,
+ pub const Field = struct {
+ idx: u32,
+ name: NullTerminatedString,
+ value_body: ?[]const Inst.Index,
+ };
+ pub fn next(it: *FieldIterator) ?Field {
+ const idx = it.next_idx;
+ if (idx == it.names.len) return null;
+ it.next_idx += 1;
+ return .{
+ .idx = idx,
+ .name = it.names[idx],
+ .value_body = it.body(if (it.value_body_lens) |l| l[idx] else 0),
+ };
+ }
+ fn body(it: *FieldIterator, len: u32) ?[]const Inst.Index {
+ if (len == 0) return null;
+ const b = it.bodies_overlong[0..len];
+ it.bodies_overlong = it.bodies_overlong[len..];
+ return b;
+ }
+ };
+};
+
+pub fn getOpaqueDecl(zir: *const Zir, opaque_decl: Inst.Index) UnwrappedOpaqueDecl {
+ const inst_data = zir.instructions.get(@intFromEnum(opaque_decl));
+ assert(inst_data.tag == .extended);
+ assert(inst_data.data.extended.opcode == .opaque_decl);
+ const small: Inst.OpaqueDecl.Small = @bitCast(inst_data.data.extended.small);
+ const extra = zir.extraData(Inst.OpaqueDecl, inst_data.data.extended.operand);
+ var extra_index = extra.end;
+ const captures_len: u32 = if (small.has_captures_len) blk: {
+ const captures_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :blk captures_len;
+ } else 0;
+ const decls_len: u32 = if (small.has_decls_len) blk: {
+ const decls_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :blk decls_len;
+ } else 0;
+ const captures: []const Inst.Capture = @ptrCast(zir.extra[extra_index..][0..captures_len]);
+ extra_index += captures_len;
+ const capture_names: []const NullTerminatedString = @ptrCast(zir.extra[extra_index..][0..captures_len]);
+ extra_index += captures_len;
+ const decls: []const Inst.Index = @ptrCast(zir.extra[extra_index..][0..decls_len]);
+ extra_index += decls_len;
+ return .{
+ .src_line = extra.data.src_line,
+ .src_node = extra.data.src_node,
+ .name_strategy = small.name_strategy,
+ .captures = captures,
+ .capture_names = capture_names,
+ .decls = decls,
+ };
}
+pub const UnwrappedOpaqueDecl = struct {
+ src_line: u32,
+ src_node: Ast.Node.Index,
+ name_strategy: Inst.NameStrategy,
+ captures: []const Inst.Capture,
+ capture_names: []const NullTerminatedString,
+ decls: []const Inst.Index,
+};
diff --git a/lib/std/zig/llvm/BitcodeReader.zig b/lib/std/zig/llvm/BitcodeReader.zig
index d7b923c3c83c3625c80c57756d27f52323975786..e32e8afc033e0dc233bb7f37aea493f6bbcb1c9e 100644
--- a/lib/std/zig/llvm/BitcodeReader.zig
+++ b/lib/std/zig/llvm/BitcodeReader.zig
@@ -34,8 +34,8 @@ pub const Block = struct {
const default: Info = .{
.block_name = &.{},
- .record_names = .{},
- .abbrevs = .{ .abbrevs = .{} },
+ .record_names = .empty,
+ .abbrevs = .{ .abbrevs = .empty },
};
const set_bid_id: u32 = 1;
@@ -109,8 +109,8 @@ pub fn init(allocator: std.mem.Allocator, options: InitOptions) BitcodeReader {
.keep_names = options.keep_names,
.bit_buffer = 0,
.bit_offset = 0,
- .stack = .{},
- .block_info = .{},
+ .stack = .empty,
+ .block_info = .empty,
};
}
@@ -278,7 +278,7 @@ fn startBlock(bc: *BitcodeReader, block_id: ?u32, new_abbrev_len: u6) !void {
state.* = .{
.block_id = block_id,
.abbrev_id_width = new_abbrev_len,
- .abbrevs = .{ .abbrevs = .{} },
+ .abbrevs = .{ .abbrevs = .empty },
};
try state.abbrevs.abbrevs.ensureTotalCapacity(
bc.allocator,
diff --git a/lib/std/zig/llvm/Builder.zig b/lib/std/zig/llvm/Builder.zig
index 66d20df34810c62e2741ed066906a519032af6ef..5001a0c375a55f2c49a26e5f697086d65f34c2dd 100644
--- a/lib/std/zig/llvm/Builder.zig
+++ b/lib/std/zig/llvm/Builder.zig
@@ -7,6 +7,7 @@ const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const DW = std.dwarf;
const log = std.log.scoped(.llvm);
+const maxInt = std.math.maxInt;
const Writer = std.Io.Writer;
const bitcode_writer = @import("bitcode_writer.zig");
@@ -55,6 +56,8 @@ constant_items: std.MultiArrayList(Constant.Item),
constant_extra: std.ArrayList(u32),
constant_limbs: std.ArrayList(std.math.big.Limb),
+alignment_forward_references: std.ArrayList(Alignment),
+
metadata_map: std.AutoArrayHashMapUnmanaged(void, void),
metadata_items: std.MultiArrayList(Metadata.Item),
metadata_extra: std.ArrayList(u32),
@@ -85,7 +88,7 @@ pub const Options = struct {
};
pub const String = enum(u32) {
- none = std.math.maxInt(u31),
+ none = maxInt(u31),
empty,
_,
@@ -245,7 +248,7 @@ pub const Type = enum(u32) {
ptr,
@"ptr addrspace(4)",
- none = std.math.maxInt(u32),
+ none = maxInt(u32),
_,
pub const ptr_amdgpu_constant =
@@ -941,7 +944,7 @@ pub const Attribute = union(Kind) {
inalloca: Type,
sret: Type,
elementtype: Type,
- @"align": Alignment,
+ @"align": Alignment.Lazy,
@"noalias",
nocapture,
nofree,
@@ -956,7 +959,7 @@ pub const Attribute = union(Kind) {
immarg,
noundef,
nofpclass: FpClass,
- alignstack: Alignment,
+ alignstack: Alignment.Lazy,
allocalign,
allocptr,
readnone,
@@ -964,7 +967,7 @@ pub const Attribute = union(Kind) {
writeonly,
// Function Attributes
- //alignstack: Alignment,
+ //alignstack: Alignment.Lazy,
allockind: AllocKind,
allocsize: AllocSize,
alwaysinline,
@@ -1145,7 +1148,7 @@ pub const Attribute = union(Kind) {
return @unionInit(Attribute, field.name, switch (field.type) {
void => {},
u32 => storage.value,
- Alignment, String, Type, UwTable => @enumFromInt(storage.value),
+ Alignment.Lazy, String, Type, UwTable => @enumFromInt(storage.value),
AllocKind, AllocSize, FpClass, Memory, VScaleRange => @bitCast(storage.value),
else => @compileError("bad payload type: " ++ field.name ++ ": " ++
@typeName(field.type)),
@@ -1246,7 +1249,7 @@ pub const Attribute = union(Kind) {
.sret,
.elementtype,
=> |ty| try w.print(" {s}({f})", .{ @tagName(attribute), ty.fmt(data.builder, .percent) }),
- .@"align" => |alignment| try w.print("{f}", .{alignment.fmt(" ")}),
+ .@"align" => |alignment| try w.print("{f}", .{alignment.resolve(data.builder).fmt(" ")}),
.dereferenceable,
.dereferenceable_or_null,
=> |size| try w.print(" {s}({d})", .{ @tagName(attribute), size }),
@@ -1270,7 +1273,7 @@ pub const Attribute = union(Kind) {
},
.alignstack => |alignment| {
try w.print(" {t}", .{attribute});
- const alignment_bytes = alignment.toByteUnits() orelse return;
+ const alignment_bytes = alignment.resolve(data.builder).toByteUnits() orelse return;
if (data.flags.pound) {
try w.print("={d}", .{alignment_bytes});
} else {
@@ -1435,8 +1438,8 @@ pub const Attribute = union(Kind) {
//sanitize_memtag,
sanitize_address_dyninit = 102,
- string = std.math.maxInt(u31),
- none = std.math.maxInt(u32),
+ string = maxInt(u31),
+ none = maxInt(u32),
_,
pub const len = @typeInfo(Kind).@"enum".fields.len - 2;
@@ -1516,12 +1519,12 @@ pub const Attribute = union(Kind) {
elem_size: u16,
num_elems: u16,
- pub const none = std.math.maxInt(u16);
+ pub const none = maxInt(u16);
fn toLlvm(self: AllocSize) packed struct(u64) { num_elems: u32, elem_size: u32 } {
return .{ .num_elems = switch (self.num_elems) {
else => self.num_elems,
- none => std.math.maxInt(u32),
+ none => maxInt(u32),
}, .elem_size = self.elem_size };
}
};
@@ -1577,7 +1580,7 @@ pub const Attribute = union(Kind) {
inline else => |value, tag| .{ .kind = @as(Kind, self), .value = switch (@TypeOf(value)) {
void => 0,
u32 => value,
- Alignment, String, Type, UwTable => @intFromEnum(value),
+ Alignment.Lazy, String, Type, UwTable => @intFromEnum(value),
AllocKind, AllocSize, FpClass, Memory, VScaleRange => @bitCast(value),
else => @compileError("bad payload type: " ++ @tagName(tag) ++ @typeName(@TypeOf(value))),
} },
@@ -1627,7 +1630,7 @@ pub const FunctionAttributes = enum(u32) {
const params_index = 2;
pub const Wip = struct {
- maps: Maps = .{},
+ maps: Maps = .empty,
const Map = std.AutoArrayHashMapUnmanaged(Attribute.Kind, Attribute.Index);
const Maps = std.ArrayList(Map);
@@ -2017,9 +2020,32 @@ pub const ExternallyInitialized = enum {
};
pub const Alignment = enum(u6) {
- default = std.math.maxInt(u6),
+ default = maxInt(u6),
_,
+ pub const Lazy = enum(u32) {
+ /// Values which fit in a `u6` are already-resolved `Alignment` values. Other values are
+ /// indices into `Builder.alignment_forward_references`, offset by `maxInt(u6)`.
+ _,
+
+ pub fn wrap(a: Alignment) Lazy {
+ return @enumFromInt(@intFromEnum(a));
+ }
+ pub fn resolve(l: Lazy, b: *const Builder) Alignment {
+ return switch (@intFromEnum(l)) {
+ 0...maxInt(u6) => |raw| @enumFromInt(raw),
+ else => |offset_index| b.alignment_forward_references.items[offset_index - maxInt(u6)],
+ };
+ }
+
+ fn fromFwdRefIndex(index: usize) Lazy {
+ return @enumFromInt(index + maxInt(u6));
+ }
+ fn toFwdRefIndex(l: Lazy) usize {
+ return @intFromEnum(l) - maxInt(u6);
+ }
+ };
+
pub fn fromByteUnits(bytes: u64) Alignment {
if (bytes == 0) return .default;
assert(std.math.isPowerOfTwo(bytes));
@@ -2028,11 +2054,17 @@ pub const Alignment = enum(u6) {
}
pub fn toByteUnits(self: Alignment) ?u64 {
- return if (self == .default) null else @as(u64, 1) << @intFromEnum(self);
+ return switch (self) {
+ .default => null,
+ else => @as(u64, 1) << @intFromEnum(self),
+ };
}
pub fn toLlvm(self: Alignment) u6 {
- return if (self == .default) 0 else (@intFromEnum(self) + 1);
+ return switch (self) {
+ .default => 0,
+ else => @intFromEnum(self) + 1,
+ };
}
pub const Prefixed = struct {
@@ -2180,7 +2212,7 @@ pub const CallConv = enum(u10) {
};
pub const StrtabString = enum(u32) {
- none = std.math.maxInt(u31),
+ none = maxInt(u31),
empty,
_,
@@ -2308,7 +2340,7 @@ pub const Global = struct {
},
pub const Index = enum(u32) {
- none = std.math.maxInt(u32),
+ none = maxInt(u32),
_,
pub fn unwrap(self: Index, builder: *const Builder) Index {
@@ -2478,7 +2510,7 @@ pub const Alias = struct {
aliasee: Constant = .no_init,
pub const Index = enum(u32) {
- none = std.math.maxInt(u32),
+ none = maxInt(u32),
_,
pub fn ptr(self: Index, builder: *Builder) *Alias {
@@ -2530,7 +2562,7 @@ pub const Variable = struct {
alignment: Alignment = .default,
pub const Index = enum(u32) {
- none = std.math.maxInt(u32),
+ none = maxInt(u32),
_,
pub fn ptr(self: Index, builder: *Builder) *Variable {
@@ -3949,7 +3981,7 @@ pub const Intrinsic = enum {
.params = &.{
.{
.kind = .{ .type = Type.ptr_amdgpu_constant },
- .attrs = &.{.{ .@"align" = Builder.Alignment.fromByteUnits(4) }},
+ .attrs = &.{.{ .@"align" = .wrap(.fromByteUnits(4)) }},
},
},
.attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
@@ -4048,7 +4080,7 @@ pub const Function = struct {
section: String = .none,
alignment: Alignment = .default,
blocks: []const Block = &.{},
- instructions: std.MultiArrayList(Instruction) = .{},
+ instructions: std.MultiArrayList(Instruction) = .empty,
names: [*]const String = &[0]String{},
value_indices: [*]const u32 = &[0]u32{},
strip: bool,
@@ -4057,7 +4089,7 @@ pub const Function = struct {
extra: []const u32 = &.{},
pub const Index = enum(u32) {
- none = std.math.maxInt(u32),
+ none = maxInt(u32),
_,
pub fn ptr(self: Index, builder: *Builder) *Function {
@@ -4411,7 +4443,7 @@ pub const Function = struct {
};
pub const Index = enum(u32) {
- none = std.math.maxInt(u31),
+ none = maxInt(u31),
_,
pub fn name(self: Instruction.Index, function: *const Function) String {
@@ -5007,7 +5039,7 @@ pub const Function = struct {
fsub = 12,
fmax = 13,
fmin = 14,
- none = std.math.maxInt(u5),
+ none = maxInt(u5),
};
};
@@ -5222,13 +5254,13 @@ pub const WipFunction = struct {
.prev_debug_location = .no_location,
.debug_location = .no_location,
.cursor = undefined,
- .blocks = .{},
- .instructions = .{},
- .names = .{},
+ .blocks = .empty,
+ .instructions = .empty,
+ .names = .empty,
.strip = options.strip,
- .debug_locations = .{},
- .debug_values = .{},
- .extra = .{},
+ .debug_locations = .empty,
+ .debug_values = .empty,
+ .extra = .empty,
};
errdefer self.deinit();
@@ -5265,7 +5297,7 @@ pub const WipFunction = struct {
self.blocks.appendAssumeCapacity(.{
.name = final_name,
.incoming = incoming,
- .instructions = .{},
+ .instructions = .empty,
});
return index;
}
@@ -6132,8 +6164,8 @@ pub const WipFunction = struct {
kind: MemoryAccessKind,
@"inline": bool,
) Allocator.Error!Instruction.Index {
- var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = dst_align })};
- var src_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = src_align })};
+ var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = .wrap(dst_align) })};
+ var src_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = .wrap(src_align) })};
const value = try self.callIntrinsic(
.normal,
try self.builder.fnAttrs(&.{
@@ -6162,8 +6194,8 @@ pub const WipFunction = struct {
len: Value,
kind: MemoryAccessKind,
) Allocator.Error!Instruction.Index {
- var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = dst_align })};
- var src_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = src_align })};
+ var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = .wrap(dst_align) })};
+ var src_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = .wrap(src_align) })};
const value = try self.callIntrinsic(
.normal,
try self.builder.fnAttrs(&.{
@@ -6192,7 +6224,7 @@ pub const WipFunction = struct {
kind: MemoryAccessKind,
@"inline": bool,
) Allocator.Error!Instruction.Index {
- var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = dst_align })};
+ var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = .wrap(dst_align) })};
const value = try self.callIntrinsic(
.normal,
try self.builder.fnAttrs(&.{ .none, .none, try self.builder.attrs(&dst_attrs) }),
@@ -6325,7 +6357,7 @@ pub const WipFunction = struct {
function.blocks = &.{};
gpa.free(function.names[0..function.instructions.len]);
function.debug_locations.deinit(gpa);
- function.debug_locations = .{};
+ function.debug_locations = .empty;
gpa.free(function.debug_values);
function.debug_values = &.{};
gpa.free(function.extra);
@@ -7329,7 +7361,7 @@ pub const Constant = enum(u32) {
//indices: [info.indices_len]Constant,
pub const Kind = enum { normal, inbounds };
- pub const InRangeIndex = enum(u16) { none = std.math.maxInt(u16), _ };
+ pub const InRangeIndex = enum(u16) { none = maxInt(u16), _ };
pub const Info = packed struct(u32) { indices_len: u16, inrange: InRangeIndex };
};
@@ -7579,7 +7611,7 @@ pub const Constant = enum(u32) {
string: [
(std.math.big.int.Const{
.limbs = &([1]std.math.big.Limb{
- std.math.maxInt(std.math.big.Limb),
+ maxInt(std.math.big.Limb),
} ** expected_limbs),
.positive = false,
}).sizeInBaseUpperBound(10)
@@ -7643,7 +7675,7 @@ pub const Constant = enum(u32) {
std.math.minInt(Exponent64),
else => @as(Exponent64, repr.exponent) +
(std.math.floatExponentMax(f64) - std.math.floatExponentMax(f32)),
- std.math.maxInt(Exponent32) => std.math.maxInt(Exponent64),
+ maxInt(Exponent32) => maxInt(Exponent64),
},
.sign = repr.sign,
}))});
@@ -7820,7 +7852,7 @@ pub const Constant = enum(u32) {
};
pub const Value = enum(u32) {
- none = std.math.maxInt(u31),
+ none = maxInt(u31),
false = first_constant + @intFromEnum(Constant.false),
true = first_constant + @intFromEnum(Constant.true),
@"0" = first_constant + @intFromEnum(Constant.@"0"),
@@ -8021,6 +8053,7 @@ pub const Metadata = packed struct(u32) {
composite_vector_type,
derived_pointer_type,
derived_member_type,
+ derived_typedef_type,
subroutine_type,
enumerator_unsigned,
enumerator_signed_positive,
@@ -8064,6 +8097,7 @@ pub const Metadata = packed struct(u32) {
.composite_vector_type,
.derived_pointer_type,
.derived_member_type,
+ .derived_typedef_type,
.subroutine_type,
.enumerator_unsigned,
.enumerator_signed_positive,
@@ -8391,7 +8425,7 @@ pub const Metadata = packed struct(u32) {
map: std.AutoArrayHashMapUnmanaged(union(enum) {
metadata: Metadata,
debug_location: DebugLocation.Location,
- }, void) = .{},
+ }, void) = .empty,
const FormatData = struct {
formatter: *Formatter,
@@ -8649,52 +8683,54 @@ pub fn init(options: Options) Allocator.Error!Builder {
.source_filename = .none,
.data_layout = .none,
.target_triple = .none,
- .module_asm = .{},
+ .module_asm = .empty,
- .string_map = .{},
- .string_indices = .{},
- .string_bytes = .{},
+ .string_map = .empty,
+ .string_indices = .empty,
+ .string_bytes = .empty,
- .types = .{},
+ .types = .empty,
.next_unnamed_type = @enumFromInt(0),
- .next_unique_type_id = .{},
- .type_map = .{},
- .type_items = .{},
- .type_extra = .{},
+ .next_unique_type_id = .empty,
+ .type_map = .empty,
+ .type_items = .empty,
+ .type_extra = .empty,
- .attributes = .{},
- .attributes_map = .{},
- .attributes_indices = .{},
- .attributes_extra = .{},
+ .attributes = .empty,
+ .attributes_map = .empty,
+ .attributes_indices = .empty,
+ .attributes_extra = .empty,
- .function_attributes_set = .{},
+ .function_attributes_set = .empty,
- .globals = .{},
+ .globals = .empty,
.next_unnamed_global = @enumFromInt(0),
.next_replaced_global = .none,
- .next_unique_global_id = .{},
- .aliases = .{},
- .variables = .{},
- .functions = .{},
+ .next_unique_global_id = .empty,
+ .aliases = .empty,
+ .variables = .empty,
+ .functions = .empty,
- .strtab_string_map = .{},
- .strtab_string_indices = .{},
- .strtab_string_bytes = .{},
+ .strtab_string_map = .empty,
+ .strtab_string_indices = .empty,
+ .strtab_string_bytes = .empty,
- .constant_map = .{},
- .constant_items = .{},
- .constant_extra = .{},
- .constant_limbs = .{},
+ .constant_map = .empty,
+ .constant_items = .empty,
+ .constant_extra = .empty,
+ .constant_limbs = .empty,
- .metadata_map = .{},
- .metadata_items = .{},
- .metadata_extra = .{},
- .metadata_limbs = .{},
- .metadata_forward_references = .{},
- .metadata_named = .{},
- .metadata_string_map = .{},
- .metadata_string_indices = .{},
- .metadata_string_bytes = .{},
+ .alignment_forward_references = .empty,
+
+ .metadata_map = .empty,
+ .metadata_items = .empty,
+ .metadata_extra = .empty,
+ .metadata_limbs = .empty,
+ .metadata_forward_references = .empty,
+ .metadata_named = .empty,
+ .metadata_string_map = .empty,
+ .metadata_string_indices = .empty,
+ .metadata_string_bytes = .empty,
};
errdefer self.deinit();
@@ -8798,51 +8834,55 @@ pub fn clearAndFree(self: *Builder) void {
}
pub fn deinit(self: *Builder) void {
- self.module_asm.deinit(self.gpa);
-
- self.string_map.deinit(self.gpa);
- self.string_indices.deinit(self.gpa);
- self.string_bytes.deinit(self.gpa);
-
- self.types.deinit(self.gpa);
- self.next_unique_type_id.deinit(self.gpa);
- self.type_map.deinit(self.gpa);
- self.type_items.deinit(self.gpa);
- self.type_extra.deinit(self.gpa);
-
- self.attributes.deinit(self.gpa);
- self.attributes_map.deinit(self.gpa);
- self.attributes_indices.deinit(self.gpa);
- self.attributes_extra.deinit(self.gpa);
-
- self.function_attributes_set.deinit(self.gpa);
-
- self.globals.deinit(self.gpa);
- self.next_unique_global_id.deinit(self.gpa);
- self.aliases.deinit(self.gpa);
- self.variables.deinit(self.gpa);
- for (self.functions.items) |*function| function.deinit(self.gpa);
- self.functions.deinit(self.gpa);
-
- self.strtab_string_map.deinit(self.gpa);
- self.strtab_string_indices.deinit(self.gpa);
- self.strtab_string_bytes.deinit(self.gpa);
-
- self.constant_map.deinit(self.gpa);
- self.constant_items.deinit(self.gpa);
- self.constant_extra.deinit(self.gpa);
- self.constant_limbs.deinit(self.gpa);
-
- self.metadata_map.deinit(self.gpa);
- self.metadata_items.deinit(self.gpa);
- self.metadata_extra.deinit(self.gpa);
- self.metadata_limbs.deinit(self.gpa);
- self.metadata_forward_references.deinit(self.gpa);
- self.metadata_named.deinit(self.gpa);
-
- self.metadata_string_map.deinit(self.gpa);
- self.metadata_string_indices.deinit(self.gpa);
- self.metadata_string_bytes.deinit(self.gpa);
+ const gpa = self.gpa;
+
+ self.module_asm.deinit(gpa);
+
+ self.string_map.deinit(gpa);
+ self.string_indices.deinit(gpa);
+ self.string_bytes.deinit(gpa);
+
+ self.types.deinit(gpa);
+ self.next_unique_type_id.deinit(gpa);
+ self.type_map.deinit(gpa);
+ self.type_items.deinit(gpa);
+ self.type_extra.deinit(gpa);
+
+ self.attributes.deinit(gpa);
+ self.attributes_map.deinit(gpa);
+ self.attributes_indices.deinit(gpa);
+ self.attributes_extra.deinit(gpa);
+
+ self.function_attributes_set.deinit(gpa);
+
+ self.globals.deinit(gpa);
+ self.next_unique_global_id.deinit(gpa);
+ self.aliases.deinit(gpa);
+ self.variables.deinit(gpa);
+ for (self.functions.items) |*function| function.deinit(gpa);
+ self.functions.deinit(gpa);
+
+ self.strtab_string_map.deinit(gpa);
+ self.strtab_string_indices.deinit(gpa);
+ self.strtab_string_bytes.deinit(gpa);
+
+ self.constant_map.deinit(gpa);
+ self.constant_items.deinit(gpa);
+ self.constant_extra.deinit(gpa);
+ self.constant_limbs.deinit(gpa);
+
+ self.alignment_forward_references.deinit(gpa);
+
+ self.metadata_map.deinit(gpa);
+ self.metadata_items.deinit(gpa);
+ self.metadata_extra.deinit(gpa);
+ self.metadata_limbs.deinit(gpa);
+ self.metadata_forward_references.deinit(gpa);
+ self.metadata_named.deinit(gpa);
+
+ self.metadata_string_map.deinit(gpa);
+ self.metadata_string_indices.deinit(gpa);
+ self.metadata_string_bytes.deinit(gpa);
self.* = undefined;
}
@@ -8960,7 +9000,7 @@ pub fn structType(
pub fn opaqueType(self: *Builder, name: String) Allocator.Error!Type {
try self.string_map.ensureUnusedCapacity(self.gpa, 1);
if (name.slice(self)) |id| {
- const count: usize = comptime std.fmt.count("{d}", .{std.math.maxInt(u32)});
+ const count: usize = comptime std.fmt.count("{d}", .{maxInt(u32)});
try self.string_bytes.ensureUnusedCapacity(self.gpa, id.len + count);
}
try self.string_indices.ensureUnusedCapacity(self.gpa, 1);
@@ -9576,6 +9616,21 @@ pub fn asmValue(
return (try self.asmConst(ty, info, assembly, constraints)).toValue();
}
+/// The initial "resolved" value of the forward reference is `Alignment.default`.
+pub fn alignmentForwardReference(b: *Builder) Allocator.Error!Alignment.Lazy {
+ const index = b.alignment_forward_references.items.len;
+ try b.alignment_forward_references.append(b.gpa, .default);
+ return .fromFwdRefIndex(index);
+}
+
+/// Updates the "resolved" value of the alignment forward reference `fwd_ref` to `value`.
+///
+/// Asserts that `fwd_ref` is a forward reference, as opposed to a resolved alignment value.
+pub fn resolveAlignmentForwardReference(b: *Builder, fwd_ref: Alignment.Lazy, value: Alignment) void {
+ const index = fwd_ref.toFwdRefIndex();
+ b.alignment_forward_references.items[index] = value;
+}
+
pub fn dump(b: *Builder, io: Io) void {
var buffer: [4000]u8 = undefined;
const stderr: Io.File = .stderr();
@@ -10463,15 +10518,18 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void
},
.derived_pointer_type,
.derived_member_type,
+ .derived_typedef_type,
=> |kind| {
const extra = self.metadataExtraData(Metadata.DerivedType, metadata_item.data);
try metadata_formatter.specialized(.@"!", .DIDerivedType, .{
.tag = @as(enum {
DW_TAG_pointer_type,
DW_TAG_member,
+ DW_TAG_typedef,
}, switch (kind) {
.derived_pointer_type => .DW_TAG_pointer_type,
.derived_member_type => .DW_TAG_member,
+ .derived_typedef_type => .DW_TAG_typedef,
else => unreachable,
}),
.name = extra.name,
@@ -10510,7 +10568,7 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void
string: [
(std.math.big.int.Const{
.limbs = &([1]std.math.big.Limb{
- std.math.maxInt(std.math.big.Limb),
+ maxInt(std.math.big.Limb),
} ** expected_limbs),
.positive = false,
}).sizeInBaseUpperBound(10)
@@ -10660,7 +10718,7 @@ fn printEscapedString(slice: []const u8, quotes: QuoteBehavior, w: *Writer) Writ
fn ensureUnusedGlobalCapacity(self: *Builder, name: StrtabString) Allocator.Error!void {
try self.strtab_string_map.ensureUnusedCapacity(self.gpa, 1);
if (name.slice(self)) |id| {
- const count: usize = comptime std.fmt.count("{d}", .{std.math.maxInt(u32)});
+ const count: usize = comptime std.fmt.count("{d}", .{maxInt(u32)});
try self.strtab_string_bytes.ensureUnusedCapacity(self.gpa, id.len + count);
}
try self.strtab_string_indices.ensureUnusedCapacity(self.gpa, 1);
@@ -12069,7 +12127,7 @@ pub fn trailingMetadataStringAssumeCapacity(self: *Builder) Metadata.String {
const start = self.metadata_string_indices.getLast();
const bytes: []const u8 = self.metadata_string_bytes.items[start..];
assert(bytes.len > 0);
- const gop = self.metadata_string_map.getOrPutAssumeCapacityAdapted(bytes, String.Adapter{ .builder = self });
+ const gop = self.metadata_string_map.getOrPutAssumeCapacityAdapted(bytes, Metadata.String.Adapter{ .builder = self });
if (gop.found_existing) {
self.metadata_string_bytes.shrinkRetainingCapacity(start);
} else {
@@ -12360,6 +12418,30 @@ pub fn debugMemberType(
);
}
+pub fn debugTypedefType(
+ self: *Builder,
+ name: ?Metadata.String,
+ file: ?Metadata,
+ scope: ?Metadata,
+ line: u32,
+ underlying_type: ?Metadata,
+ size_in_bits: u64,
+ align_in_bits: u64,
+ offset_in_bits: u64,
+) Allocator.Error!Metadata {
+ try self.ensureUnusedMetadataCapacity(1, Metadata.DerivedType, 0);
+ return self.debugTypedefTypeAssumeCapacity(
+ name,
+ file,
+ scope,
+ line,
+ underlying_type,
+ size_in_bits,
+ align_in_bits,
+ offset_in_bits,
+ );
+}
+
pub fn debugSubroutineType(self: *Builder, types_tuple: ?Metadata) Allocator.Error!Metadata {
try self.ensureUnusedMetadataCapacity(1, Metadata.SubroutineType, 0);
return self.debugSubroutineTypeAssumeCapacity(types_tuple);
@@ -12467,11 +12549,12 @@ pub fn metadataConstant(self: *Builder, value: Constant) Allocator.Error!Metadat
return self.metadataConstantAssumeCapacity(value);
}
+/// Resolves the given forward reference to the given value (which is not itself a forward
+/// reference). If the forward reference is already resolved, its target is replaced.
pub fn resolveDebugForwardReference(self: *Builder, fwd_ref: Metadata, value: Metadata) void {
assert(fwd_ref.kind == .forward);
- const resolved = &self.metadata_forward_references.items[fwd_ref.index];
- assert(resolved.is_none);
- resolved.* = value.toOptional();
+ assert(value.kind != .forward);
+ self.metadata_forward_references.items[fwd_ref.index] = value.toOptional();
}
fn metadataSimpleAssumeCapacity(self: *Builder, tag: Metadata.Tag, value: anytype) Metadata {
@@ -12874,6 +12957,33 @@ fn debugMemberTypeAssumeCapacity(
});
}
+fn debugTypedefTypeAssumeCapacity(
+ self: *Builder,
+ name: ?Metadata.String,
+ file: ?Metadata,
+ scope: ?Metadata,
+ line: u32,
+ underlying_type: ?Metadata,
+ size_in_bits: u64,
+ align_in_bits: u64,
+ offset_in_bits: u64,
+) Metadata {
+ assert(!self.strip);
+ return self.metadataSimpleAssumeCapacity(.derived_typedef_type, Metadata.DerivedType{
+ .name = .wrap(name),
+ .file = .wrap(file),
+ .scope = .wrap(scope),
+ .line = line,
+ .underlying_type = .wrap(underlying_type),
+ .size_in_bits_lo = @truncate(size_in_bits),
+ .size_in_bits_hi = @truncate(size_in_bits >> 32),
+ .align_in_bits_lo = @truncate(align_in_bits),
+ .align_in_bits_hi = @truncate(align_in_bits >> 32),
+ .offset_in_bits_lo = @truncate(offset_in_bits),
+ .offset_in_bits_hi = @truncate(offset_in_bits >> 32),
+ });
+}
+
fn debugSubroutineTypeAssumeCapacity(self: *Builder, types_tuple: ?Metadata) Metadata {
assert(!self.strip);
return self.metadataSimpleAssumeCapacity(.subroutine_type, Metadata.SubroutineType{
@@ -13461,7 +13571,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco
try record.ensureUnusedCapacity(self.gpa, 3);
record.appendAssumeCapacity(1);
record.appendAssumeCapacity(@intFromEnum(kind));
- record.appendAssumeCapacity(alignment.toByteUnits() orelse 0);
+ record.appendAssumeCapacity(alignment.resolve(self).toByteUnits() orelse 0);
},
.dereferenceable,
.dereferenceable_or_null,
@@ -14222,12 +14332,14 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco
},
.derived_pointer_type,
.derived_member_type,
+ .derived_typedef_type,
=> |kind| {
const extra = self.metadataExtraData(Metadata.DerivedType, data);
try metadata_block.writeAbbrevAdapted(MetadataBlock.DerivedType{
.tag = switch (kind) {
.derived_pointer_type => DW.TAG.pointer_type,
.derived_member_type => DW.TAG.member,
+ .derived_typedef_type => DW.TAG.typedef,
else => unreachable,
},
.name = extra.name,
diff --git a/lib/std/zig/target.zig b/lib/std/zig/target.zig
index 34709e17ac9f0e9da4ff212c541e144f09d71da0..dee2241667c42db870163f1dbd9579ed7440a70d 100644
--- a/lib/std/zig/target.zig
+++ b/lib/std/zig/target.zig
@@ -503,8 +503,7 @@ pub fn intByteSize(target: *const std.Target, bits: u16) u16 {
pub fn intAlignment(target: *const std.Target, bits: u16) u16 {
return switch (target.cpu.arch) {
.x86 => switch (bits) {
- 0 => 0,
- 1...8 => 1,
+ 0...8 => 1,
9...16 => 2,
17...32 => 4,
33...64 => switch (target.os.tag) {
@@ -514,17 +513,19 @@ pub fn intAlignment(target: *const std.Target, bits: u16) u16 {
else => 16,
},
.x86_64 => switch (bits) {
- 0 => 0,
- 1...8 => 1,
+ 0...8 => 1,
9...16 => 2,
17...32 => 4,
33...64 => 8,
else => 16,
},
- else => return @min(
- std.math.ceilPowerOfTwoPromote(u16, @as(u16, @intCast((@as(u17, bits) + 7) / 8))),
- target.cMaxIntAlignment(),
- ),
+ else => switch (bits) {
+ 0 => 1,
+ else => @min(
+ std.math.ceilPowerOfTwoPromote(u16, @intCast((@as(u17, bits) + 7) / 8)),
+ target.cMaxIntAlignment(),
+ ),
+ },
};
}
diff --git a/lib/std/zon/Serializer.zig b/lib/std/zon/Serializer.zig
index 6f92a64dbdcf6a48867725780692c39b62e9ee21..c30c0e09d8051c0eafab2e8e4ba2a85d46aa1db2 100644
--- a/lib/std/zon/Serializer.zig
+++ b/lib/std/zon/Serializer.zig
@@ -793,9 +793,11 @@ test checkValueDepth {
try expectValueDepthEquals(2, @as(?u32, 1));
try expectValueDepthEquals(1, @as(?u32, null));
try expectValueDepthEquals(1, null);
- try expectValueDepthEquals(2, &1);
try expectValueDepthEquals(3, &@as(?u32, 1));
+ // The pointer drops the implicit comptime-ness, so we need to specify 'comptime' here
+ try comptime expectValueDepthEquals(2, &1);
+
const Union = union(enum) {
x: u32,
y: struct { x: u32 },
diff --git a/lib/std/zon/parse.zig b/lib/std/zon/parse.zig
index 3527f03342b64f5c6f19bad7e163873aeeabcd2b..9f492ddbea6eafdf1841d86cb0d9f383c42b8638 100644
--- a/lib/std/zon/parse.zig
+++ b/lib/std/zon/parse.zig
@@ -591,7 +591,7 @@ const Parser = struct {
if (pointer.child == u8 and
pointer.is_const and
(pointer.sentinel() == null or pointer.sentinel() == 0) and
- pointer.alignment == 1)
+ (pointer.alignment == null or pointer.alignment == 1))
{
if (opt) {
return self.failNode(node, "expected optional string");
@@ -717,7 +717,7 @@ const Parser = struct {
pointer.size != .slice or
!pointer.is_const or
(pointer.sentinel() != null and pointer.sentinel() != 0) or
- pointer.alignment != 1)
+ (pointer.alignment != null and pointer.alignment != 1))
{
return error.WrongType;
}
@@ -742,7 +742,7 @@ const Parser = struct {
const slice = try self.gpa.allocWithOptions(
pointer.child,
nodes.len,
- .fromByteUnits(pointer.alignment),
+ .fromByteUnitsOptional(pointer.alignment),
pointer.sentinel(),
);
errdefer self.gpa.free(slice);
diff --git a/lib/zig.h b/lib/zig.h
index 81a815ab5568b57f5d48c8da91a04b761d4f9a2a..0b9c6e58ca6d9f1800fd8059e5db9d3636faa35c 100644
--- a/lib/zig.h
+++ b/lib/zig.h
@@ -151,6 +151,14 @@
#define zig_has_attribute(attribute) 0
#endif
+#if __STDC_VERSION__ >= 201112L
+#define zig_static_assert(cond, msg) _Static_assert(cond, msg)
+#elif zig_has_attribute(unused)
+#define zig_static_assert(cond, _) typedef char zig_expand_concat(zig_static_assert_fail_, __LINE__)[!!(cond)] __attribute__((unused))
+#else
+#define zig_static_assert(cond, _) typedef char zig_expand_concat(zig_static_assert_fail_, __LINE__)[!!(cond)]
+#endif
+
#if __STDC_VERSION__ >= 202311L
#define zig_threadlocal thread_local
#elif __STDC_VERSION__ >= 201112L
@@ -259,7 +267,7 @@
#endif
#if zig_has_attribute(packed) || defined(zig_tinyc)
-#define zig_packed(definition) __attribute__((packed)) definition
+#define zig_packed(definition) definition __attribute__((packed))
#elif defined(zig_msvc)
#define zig_packed(definition) __pragma(pack(1)) definition __pragma(pack())
#else
diff --git a/src/Air.zig b/src/Air.zig
index 28b7a27ba992f375fffa3a96e7045f5de5952d1e..3f7314e11674a00620f6cf9e0da5d6fbb8671d28 100644
--- a/src/Air.zig
+++ b/src/Air.zig
@@ -14,7 +14,6 @@ const Type = @import("Type.zig");
const Value = @import("Value.zig");
const Zcu = @import("Zcu.zig");
const print = @import("Air/print.zig");
-const types_resolved = @import("Air/types_resolved.zig");
pub const Legalize = @import("Air/Legalize.zig");
pub const Liveness = @import("Air/Liveness.zig");
@@ -173,8 +172,8 @@ pub const Inst = struct {
/// outside the provenance of the operand, the result is undefined.
///
/// Uses the `ty_pl` field. Payload is `Bin`. The lhs is the pointer,
- /// rhs is the offset. Result type is the same as lhs. The operand may
- /// be a slice.
+ /// rhs is the offset. Result type is the same as lhs. The operand type's
+ /// pointer size may be `.slice`, `.many`, or `.c`.
ptr_add,
/// Subtract an offset, in element type units, from a pointer,
/// returning a new pointer. Element type may not be zero bits.
@@ -183,8 +182,8 @@ pub const Inst = struct {
/// outside the provenance of the operand, the result is undefined.
///
/// Uses the `ty_pl` field. Payload is `Bin`. The lhs is the pointer,
- /// rhs is the offset. Result type is the same as lhs. The operand may
- /// be a slice.
+ /// rhs is the offset. Result type is the same as lhs. The operand type's
+ /// pointer size may be `.slice`, `.many`, or `.c`.
ptr_sub,
/// Given two operands which can be floats, integers, or vectors, returns the
/// greater of the operands. For vectors it operates element-wise.
@@ -693,6 +692,7 @@ pub const Inst = struct {
/// Uses the `ty_pl` field with payload `Bin`.
slice_elem_ptr,
/// Given a pointer value, and element index, return the element value at that index.
+ /// The pointer size is either `.c` or `.many`.
/// Result type is the element type of the pointer operand.
/// Uses the `bin_op` field.
ptr_elem_val,
@@ -2440,9 +2440,6 @@ pub fn unwrapShuffleTwo(air: *const Air, zcu: *const Zcu, inst_index: Inst.Index
};
}
-pub const typesFullyResolved = types_resolved.typesFullyResolved;
-pub const typeFullyResolved = types_resolved.checkType;
-pub const valFullyResolved = types_resolved.checkVal;
pub const legalize = Legalize.legalize;
pub const write = print.write;
pub const writeInst = print.writeInst;
diff --git a/src/Air/Liveness.zig b/src/Air/Liveness.zig
index a85944c4678455126d04403e1c48486db9d6e860..384a056988b40b6a59fc4f9a582c7869bf994d3e 100644
--- a/src/Air/Liveness.zig
+++ b/src/Air/Liveness.zig
@@ -153,8 +153,8 @@ pub fn analyze(zcu: *Zcu, air: Air, intern_pool: *InternPool) Allocator.Error!Li
usize,
(air.instructions.len * bpi + @bitSizeOf(usize) - 1) / @bitSizeOf(usize),
),
- .extra = .{},
- .special = .{},
+ .extra = .empty,
+ .special = .empty,
.intern_pool = intern_pool,
};
errdefer gpa.free(a.tomb_bits);
@@ -175,7 +175,7 @@ pub fn analyze(zcu: *Zcu, air: Air, intern_pool: *InternPool) Allocator.Error!Li
var data: LivenessPassData(.main_analysis) = .{};
defer data.deinit(gpa);
data.old_extra = a.extra;
- a.extra = .{};
+ a.extra = .empty;
try analyzeBody(&a, .main_analysis, &data, main_body);
assert(data.live_set.count() == 0);
}
@@ -999,7 +999,7 @@ fn analyzeInstBlock(
// If the block is noreturn, block deaths not only aren't useful, they're impossible to
// find: there could be more stuff alive after the block than before it!
- if (!a.intern_pool.isNoReturn(ty.toIntern())) {
+ if (!ty.isNoReturn(a.zcu)) {
// The block kills the difference in the live sets
const block_scope = data.block_scopes.get(inst).?;
const num_deaths = data.live_set.count() - block_scope.live_set.count();
@@ -1360,7 +1360,7 @@ fn analyzeInstSwitchBr(
const mirrored_deaths = try gpa.alloc(DeathList, ncases + 1);
defer gpa.free(mirrored_deaths);
- @memset(mirrored_deaths, .{});
+ @memset(mirrored_deaths, .empty);
defer for (mirrored_deaths) |*md| md.deinit(gpa);
{
diff --git a/src/Air/Liveness/Verify.zig b/src/Air/Liveness/Verify.zig
index fc83574d070c018fc54ed095d4c67f0bf7698fb2..7f820e65981b1d4247b363c061269c8d893ce239 100644
--- a/src/Air/Liveness/Verify.zig
+++ b/src/Air/Liveness/Verify.zig
@@ -465,7 +465,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
for (block_liveness.deaths) |death| try self.verifyDeath(inst, death);
- if (ip.isNoReturn(block_ty.toIntern())) {
+ if (block_ty.isNoReturn(self.zcu)) {
assert(!self.blocks.contains(inst));
} else {
var live = if (self.blocks.fetchRemove(inst)) |kv| kv.value else {
diff --git a/src/Air/print.zig b/src/Air/print.zig
index 0c126fab22d364b97c49ed6d896801fe4c66451e..f6c0f5a03b8f1c957b0129978358888977690de7 100644
--- a/src/Air/print.zig
+++ b/src/Air/print.zig
@@ -692,33 +692,23 @@ const Writer = struct {
const zcu = w.pt.zcu;
const ip = &zcu.intern_pool;
- const aggregate = ip.indexToKey(unwrapped_asm.clobbers).aggregate;
- const struct_type: Type = .fromInterned(aggregate.ty);
- switch (aggregate.storage) {
- .elems => |elems| for (elems, 0..) |elem, i| {
- switch (elem) {
- .bool_true => {
- const clobber = struct_type.structFieldName(i, zcu).toSlice(ip).?;
- assert(clobber.len != 0);
- try s.writeAll(", ~{");
- try s.writeAll(clobber);
- try s.writeAll("}");
- },
- .bool_false => continue,
- else => unreachable,
- }
- },
- .repeated_elem => |elem| {
- try s.writeAll(", ");
- try s.writeAll(switch (elem) {
- .bool_true => "",
- .bool_false => "",
- else => unreachable,
- });
- },
- .bytes => |bytes| {
- try s.print(", {x}", .{bytes});
- },
+ const clobbers_val: Value = .fromInterned(unwrapped_asm.clobbers);
+ const clobbers_ty = clobbers_val.typeOf(zcu);
+ var clobbers_bigint_buf: Value.BigIntSpace = undefined;
+ const clobbers_bigint = clobbers_val.toBigInt(&clobbers_bigint_buf, zcu);
+ for (0..clobbers_ty.structFieldCount(zcu)) |field_index| {
+ assert(clobbers_ty.fieldType(field_index, zcu).toIntern() == .bool_type);
+ const limb_bits = @bitSizeOf(std.math.big.Limb);
+ if (field_index / limb_bits >= clobbers_bigint.limbs.len) continue; // field is false
+ switch (@as(u1, @truncate(clobbers_bigint.limbs[field_index / limb_bits] >> @intCast(field_index % limb_bits)))) {
+ 0 => continue, // field is false
+ 1 => {}, // field is true
+ }
+ const clobber = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?;
+ assert(clobber.len != 0);
+ try s.writeAll(", ~{");
+ try s.writeAll(clobber);
+ try s.writeAll("}");
}
const asm_source = unwrapped_asm.source;
try s.print(", \"{f}\"", .{std.zig.fmtString(asm_source)});
diff --git a/src/Air/types_resolved.zig b/src/Air/types_resolved.zig
deleted file mode 100644
index 216f690414abdf2daea6993536b303812a05866e..0000000000000000000000000000000000000000
--- a/src/Air/types_resolved.zig
+++ /dev/null
@@ -1,536 +0,0 @@
-const Air = @import("../Air.zig");
-const Zcu = @import("../Zcu.zig");
-const Type = @import("../Type.zig");
-const Value = @import("../Value.zig");
-const InternPool = @import("../InternPool.zig");
-
-/// Given a body of AIR instructions, returns whether all type resolution necessary for codegen is complete.
-/// If `false`, then type resolution must have failed, so codegen cannot proceed.
-pub fn typesFullyResolved(air: Air, zcu: *Zcu) bool {
- return checkBody(air, air.getMainBody(), zcu);
-}
-
-fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool {
- const tags = air.instructions.items(.tag);
- const datas = air.instructions.items(.data);
-
- for (body) |inst| {
- const data = datas[@intFromEnum(inst)];
- switch (tags[@intFromEnum(inst)]) {
- .inferred_alloc, .inferred_alloc_comptime => unreachable,
-
- .arg => {
- if (!checkType(data.arg.ty.toType(), zcu)) return false;
- },
-
- .add,
- .add_safe,
- .add_optimized,
- .add_wrap,
- .add_sat,
- .sub,
- .sub_safe,
- .sub_optimized,
- .sub_wrap,
- .sub_sat,
- .mul,
- .mul_safe,
- .mul_optimized,
- .mul_wrap,
- .mul_sat,
- .div_float,
- .div_float_optimized,
- .div_trunc,
- .div_trunc_optimized,
- .div_floor,
- .div_floor_optimized,
- .div_exact,
- .div_exact_optimized,
- .rem,
- .rem_optimized,
- .mod,
- .mod_optimized,
- .max,
- .min,
- .bit_and,
- .bit_or,
- .shr,
- .shr_exact,
- .shl,
- .shl_exact,
- .shl_sat,
- .xor,
- .cmp_lt,
- .cmp_lt_optimized,
- .cmp_lte,
- .cmp_lte_optimized,
- .cmp_eq,
- .cmp_eq_optimized,
- .cmp_gte,
- .cmp_gte_optimized,
- .cmp_gt,
- .cmp_gt_optimized,
- .cmp_neq,
- .cmp_neq_optimized,
- .bool_and,
- .bool_or,
- .store,
- .store_safe,
- .set_union_tag,
- .array_elem_val,
- .slice_elem_val,
- .ptr_elem_val,
- .memset,
- .memset_safe,
- .memcpy,
- .memmove,
- .atomic_store_unordered,
- .atomic_store_monotonic,
- .atomic_store_release,
- .atomic_store_seq_cst,
- .legalize_vec_elem_val,
- => {
- if (!checkRef(data.bin_op.lhs, zcu)) return false;
- if (!checkRef(data.bin_op.rhs, zcu)) return false;
- },
-
- .not,
- .bitcast,
- .clz,
- .ctz,
- .popcount,
- .byte_swap,
- .bit_reverse,
- .abs,
- .load,
- .fptrunc,
- .fpext,
- .intcast,
- .intcast_safe,
- .trunc,
- .optional_payload,
- .optional_payload_ptr,
- .optional_payload_ptr_set,
- .wrap_optional,
- .unwrap_errunion_payload,
- .unwrap_errunion_err,
- .unwrap_errunion_payload_ptr,
- .unwrap_errunion_err_ptr,
- .errunion_payload_ptr_set,
- .wrap_errunion_payload,
- .wrap_errunion_err,
- .struct_field_ptr_index_0,
- .struct_field_ptr_index_1,
- .struct_field_ptr_index_2,
- .struct_field_ptr_index_3,
- .get_union_tag,
- .slice_len,
- .slice_ptr,
- .ptr_slice_len_ptr,
- .ptr_slice_ptr_ptr,
- .array_to_slice,
- .int_from_float,
- .int_from_float_optimized,
- .int_from_float_safe,
- .int_from_float_optimized_safe,
- .float_from_int,
- .splat,
- .error_set_has_value,
- .addrspace_cast,
- .c_va_arg,
- .c_va_copy,
- => {
- if (!checkType(data.ty_op.ty.toType(), zcu)) return false;
- if (!checkRef(data.ty_op.operand, zcu)) return false;
- },
-
- .alloc,
- .ret_ptr,
- .c_va_start,
- => {
- if (!checkType(data.ty, zcu)) return false;
- },
-
- .ptr_add,
- .ptr_sub,
- .add_with_overflow,
- .sub_with_overflow,
- .mul_with_overflow,
- .shl_with_overflow,
- .slice,
- .slice_elem_ptr,
- .ptr_elem_ptr,
- => {
- const bin = air.extraData(Air.Bin, data.ty_pl.payload).data;
- if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;
- if (!checkRef(bin.lhs, zcu)) return false;
- if (!checkRef(bin.rhs, zcu)) return false;
- },
-
- .block,
- .loop,
- => {
- const block = air.unwrapBlock(inst);
- if (!checkType(block.ty, zcu)) return false;
- if (!checkBody(
- air,
- block.body,
- zcu,
- )) return false;
- },
-
- .dbg_inline_block => {
- const block = air.unwrapDbgBlock(inst);
- if (!checkType(block.ty, zcu)) return false;
- if (!checkBody(
- air,
- block.body,
- zcu,
- )) return false;
- },
-
- .sqrt,
- .sin,
- .cos,
- .tan,
- .exp,
- .exp2,
- .log,
- .log2,
- .log10,
- .floor,
- .ceil,
- .round,
- .trunc_float,
- .neg,
- .neg_optimized,
- .is_null,
- .is_non_null,
- .is_null_ptr,
- .is_non_null_ptr,
- .is_err,
- .is_non_err,
- .is_err_ptr,
- .is_non_err_ptr,
- .ret,
- .ret_safe,
- .ret_load,
- .is_named_enum_value,
- .tag_name,
- .error_name,
- .cmp_lt_errors_len,
- .c_va_end,
- .set_err_return_trace,
- => {
- if (!checkRef(data.un_op, zcu)) return false;
- },
-
- .br, .switch_dispatch => {
- if (!checkRef(data.br.operand, zcu)) return false;
- },
-
- .cmp_vector,
- .cmp_vector_optimized,
- => {
- const extra = air.extraData(Air.VectorCmp, data.ty_pl.payload).data;
- if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;
- if (!checkRef(extra.lhs, zcu)) return false;
- if (!checkRef(extra.rhs, zcu)) return false;
- },
-
- .reduce,
- .reduce_optimized,
- => {
- if (!checkRef(data.reduce.operand, zcu)) return false;
- },
-
- .struct_field_ptr,
- .struct_field_val,
- => {
- const extra = air.extraData(Air.StructField, data.ty_pl.payload).data;
- if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;
- if (!checkRef(extra.struct_operand, zcu)) return false;
- },
-
- .shuffle_one => {
- const unwrapped = air.unwrapShuffleOne(zcu, inst);
- if (!checkType(unwrapped.result_ty, zcu)) return false;
- if (!checkRef(unwrapped.operand, zcu)) return false;
- for (unwrapped.mask) |m| switch (m.unwrap()) {
- .elem => {},
- .value => |val| if (!checkVal(.fromInterned(val), zcu)) return false,
- };
- },
-
- .shuffle_two => {
- const unwrapped = air.unwrapShuffleTwo(zcu, inst);
- if (!checkType(unwrapped.result_ty, zcu)) return false;
- if (!checkRef(unwrapped.operand_a, zcu)) return false;
- if (!checkRef(unwrapped.operand_b, zcu)) return false;
- // No values to check because there are no comptime-known values other than undef
- },
-
- .cmpxchg_weak,
- .cmpxchg_strong,
- => {
- const extra = air.extraData(Air.Cmpxchg, data.ty_pl.payload).data;
- if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;
- if (!checkRef(extra.ptr, zcu)) return false;
- if (!checkRef(extra.expected_value, zcu)) return false;
- if (!checkRef(extra.new_value, zcu)) return false;
- },
-
- .aggregate_init => {
- const ty = data.ty_pl.ty.toType();
- const elems_len: usize = @intCast(ty.arrayLen(zcu));
- const elems: []const Air.Inst.Ref = @ptrCast(air.extra.items[data.ty_pl.payload..][0..elems_len]);
- if (!checkType(ty, zcu)) return false;
- if (ty.zigTypeTag(zcu) == .@"struct") {
- for (elems, 0..) |elem, elem_idx| {
- if (ty.structFieldIsComptime(elem_idx, zcu)) continue;
- if (!checkRef(elem, zcu)) return false;
- }
- } else {
- for (elems) |elem| {
- if (!checkRef(elem, zcu)) return false;
- }
- }
- },
-
- .union_init => {
- const extra = air.extraData(Air.UnionInit, data.ty_pl.payload).data;
- if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;
- if (!checkRef(extra.init, zcu)) return false;
- },
-
- .field_parent_ptr => {
- const extra = air.extraData(Air.FieldParentPtr, data.ty_pl.payload).data;
- if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;
- if (!checkRef(extra.field_ptr, zcu)) return false;
- },
-
- .atomic_load => {
- if (!checkRef(data.atomic_load.ptr, zcu)) return false;
- },
-
- .prefetch => {
- if (!checkRef(data.prefetch.ptr, zcu)) return false;
- },
-
- .runtime_nav_ptr => {
- if (!checkType(.fromInterned(data.ty_nav.ty), zcu)) return false;
- },
-
- .select,
- .mul_add,
- .legalize_vec_store_elem,
- => {
- const bin = air.extraData(Air.Bin, data.pl_op.payload).data;
- if (!checkRef(data.pl_op.operand, zcu)) return false;
- if (!checkRef(bin.lhs, zcu)) return false;
- if (!checkRef(bin.rhs, zcu)) return false;
- },
-
- .atomic_rmw => {
- const extra = air.extraData(Air.AtomicRmw, data.pl_op.payload).data;
- if (!checkRef(data.pl_op.operand, zcu)) return false;
- if (!checkRef(extra.operand, zcu)) return false;
- },
-
- .call,
- .call_always_tail,
- .call_never_tail,
- .call_never_inline,
- => {
- const call = air.unwrapCall(inst);
- const args = call.args;
- if (!checkRef(call.callee, zcu)) return false;
- for (args) |arg| if (!checkRef(arg, zcu)) return false;
- },
-
- .dbg_var_ptr,
- .dbg_var_val,
- .dbg_arg_inline,
- => {
- if (!checkRef(data.pl_op.operand, zcu)) return false;
- },
-
- .@"try", .try_cold => {
- const unwrapped_try = air.unwrapTry(inst);
- if (!checkRef(unwrapped_try.error_union, zcu)) return false;
- if (!checkBody(
- air,
- unwrapped_try.else_body,
- zcu,
- )) return false;
- },
-
- .try_ptr, .try_ptr_cold => {
- const unwrapped_try = air.unwrapTryPtr(inst);
- if (!checkType(unwrapped_try.error_union_payload_ptr_ty.toType(), zcu)) return false;
- if (!checkRef(unwrapped_try.error_union_ptr, zcu)) return false;
- if (!checkBody(
- air,
- unwrapped_try.else_body,
- zcu,
- )) return false;
- },
-
- .cond_br => {
- const cond_br = air.unwrapCondBr(inst);
- if (!checkRef(cond_br.condition, zcu)) return false;
- if (!checkBody(
- air,
- cond_br.then_body,
- zcu,
- )) return false;
- if (!checkBody(
- air,
- cond_br.else_body,
- zcu,
- )) return false;
- },
-
- .switch_br, .loop_switch_br => {
- const switch_br = air.unwrapSwitch(inst);
- if (!checkRef(switch_br.operand, zcu)) return false;
- var it = switch_br.iterateCases();
- while (it.next()) |case| {
- for (case.items) |item| if (!checkRef(item, zcu)) return false;
- for (case.ranges) |range| {
- if (!checkRef(range[0], zcu)) return false;
- if (!checkRef(range[1], zcu)) return false;
- }
- if (!checkBody(air, case.body, zcu)) return false;
- }
- if (!checkBody(air, it.elseBody(), zcu)) return false;
- },
-
- .assembly => {
- const unwrapped_asm = air.unwrapAsm(inst);
- if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;
- // Luckily, we only care about the inputs and outputs, so we don't have to do
- // the whole null-terminated string dance.
- const outputs = unwrapped_asm.outputs;
- const inputs = unwrapped_asm.inputs;
-
- for (outputs) |output| if (output != .none and !checkRef(output, zcu)) return false;
- for (inputs) |input| if (input != .none and !checkRef(input, zcu)) return false;
- },
-
- .legalize_compiler_rt_call => {
- const rt_call = air.unwrapCompilerRtCall(inst);
- const args = rt_call.args;
- for (args) |arg| if (!checkRef(arg, zcu)) return false;
- },
-
- .trap,
- .breakpoint,
- .ret_addr,
- .frame_addr,
- .unreach,
- .wasm_memory_size,
- .wasm_memory_grow,
- .work_item_id,
- .work_group_size,
- .work_group_id,
- .dbg_stmt,
- .dbg_empty_stmt,
- .err_return_trace,
- .save_err_return_trace_index,
- .repeat,
- => {},
- }
- }
- return true;
-}
-
-fn checkRef(ref: Air.Inst.Ref, zcu: *Zcu) bool {
- const ip_index = ref.toInterned() orelse {
- // This operand refers back to a previous instruction.
- // We have already checked that instruction's type.
- // So, there's no need to check this operand's type.
- return true;
- };
- return checkVal(Value.fromInterned(ip_index), zcu);
-}
-
-pub fn checkVal(val: Value, zcu: *Zcu) bool {
- const ty = val.typeOf(zcu);
- if (!checkType(ty, zcu)) return false;
- if (val.isUndef(zcu)) return true;
- if (ty.toIntern() == .type_type and !checkType(val.toType(), zcu)) return false;
- // Check for lazy values
- switch (zcu.intern_pool.indexToKey(val.toIntern())) {
- .int => |int| switch (int.storage) {
- .u64, .i64, .big_int => return true,
- .lazy_align, .lazy_size => |ty_index| {
- return checkType(Type.fromInterned(ty_index), zcu);
- },
- },
- else => return true,
- }
-}
-
-pub fn checkType(ty: Type, zcu: *Zcu) bool {
- const ip = &zcu.intern_pool;
- if (ty.isGenericPoison()) return true;
- return switch (ty.zigTypeTag(zcu)) {
- .type,
- .void,
- .bool,
- .noreturn,
- .int,
- .float,
- .error_set,
- .@"enum",
- .@"opaque",
- .vector,
- // These types can appear due to some dummy instructions Sema introduces and expects to be omitted by Liveness.
- // It's a little silly -- but fine, we'll return `true`.
- .comptime_float,
- .comptime_int,
- .undefined,
- .null,
- .enum_literal,
- => true,
-
- .frame,
- .@"anyframe",
- => @panic("TODO Air.types_resolved.checkType async frames"),
-
- .optional => checkType(ty.childType(zcu), zcu),
- .error_union => checkType(ty.errorUnionPayload(zcu), zcu),
- .pointer => checkType(ty.childType(zcu), zcu),
- .array => checkType(ty.childType(zcu), zcu),
-
- .@"fn" => {
- const info = zcu.typeToFunc(ty).?;
- for (0..info.param_types.len) |i| {
- const param_ty = info.param_types.get(ip)[i];
- if (!checkType(Type.fromInterned(param_ty), zcu)) return false;
- }
- return checkType(Type.fromInterned(info.return_type), zcu);
- },
- .@"struct" => switch (ip.indexToKey(ty.toIntern())) {
- .struct_type => {
- const struct_obj = zcu.typeToStruct(ty).?;
- return switch (struct_obj.layout) {
- .@"packed" => struct_obj.backingIntTypeUnordered(ip) != .none,
- .auto, .@"extern" => struct_obj.flagsUnordered(ip).fully_resolved,
- };
- },
- .tuple_type => |tuple| {
- for (0..tuple.types.len) |i| {
- const field_is_comptime = tuple.values.get(ip)[i] != .none;
- if (field_is_comptime) continue;
- const field_ty = tuple.types.get(ip)[i];
- if (!checkType(Type.fromInterned(field_ty), zcu)) return false;
- }
- return true;
- },
- else => unreachable,
- },
- .@"union" => return zcu.typeToUnion(ty).?.flagsUnordered(ip).status == .fully_resolved,
- };
-}
diff --git a/src/Compilation.zig b/src/Compilation.zig
index 521de0b427c4a9cba23daab8e46521bc1ec6ef59..9fbc36f070b5239b2a2d2ff0ec113055b929c79d 100644
--- a/src/Compilation.zig
+++ b/src/Compilation.zig
@@ -21,7 +21,6 @@ const introspect = @import("introspect.zig");
const link = @import("link.zig");
const tracy = @import("tracy.zig");
const trace = tracy.trace;
-const traceNamed = tracy.traceNamed;
const build_options = @import("build_options");
const LibCInstallation = std.zig.LibCInstallation;
const glibc = @import("libs/glibc.zig");
@@ -89,6 +88,9 @@ framework_dirs: []const []const u8,
/// These are only for DLLs dependencies fulfilled by the `.def` files shipped
/// with Zig. Static libraries are provided as `link.Input` values.
windows_libs: std.StringArrayHashMapUnmanaged(void),
+/// The number of items in `windows_libs` which we have already built. All items at or after this
+/// index will be built in `performAllTheWork`.
+windows_libs_num_done: u32,
version: ?std.SemanticVersion,
libc_installation: ?*const LibCInstallation,
skip_linker_dependencies: bool,
@@ -126,16 +128,6 @@ oneshot_prelink_tasks: std.ArrayList(link.PrelinkTask),
/// work is queued or not.
queued_jobs: QueuedJobs,
-work_queues: [
- len: {
- var len: usize = 0;
- for (std.enums.values(Job.Tag)) |tag| {
- len = @max(Job.stage(tag) + 1, len);
- }
- break :len len;
- }
-]std.Deque(Job),
-
/// These jobs are to invoke the Clang compiler to create an object file, which
/// gets linked with the Compilation.
c_object_work_queue: std.Deque(*CObject),
@@ -962,65 +954,6 @@ pub const RcSourceFile = struct {
extra_flags: []const []const u8 = &.{},
};
-const Job = union(enum) {
- /// Given the generated AIR for a function, put it onto the code generation queue.
- /// This `Job` exists (instead of the `link.ZcuTask` being directly queued) to ensure that
- /// all types are resolved before the linker task is queued.
- /// If the backend does not support `Zcu.Feature.separate_thread`, codegen and linking happen immediately.
- /// Before queueing this `Job`, increase the estimated total item count for both
- /// `comp.zcu.?.codegen_prog_node` and `comp.link_prog_node`.
- codegen_func: struct {
- func: InternPool.Index,
- /// The AIR emitted from analyzing `func`; owned by this `Job` in `gpa`.
- air: Air,
- },
- /// Queue a `link.ZcuTask` to emit this non-function `Nav` into the output binary.
- /// This `Job` exists (instead of the `link.ZcuTask` being directly queued) to ensure that
- /// all types are resolved before the linker task is queued.
- /// If the backend does not support `Zcu.Feature.separate_thread`, the task is run immediately.
- /// Before queueing this `Job`, increase the estimated total item count for `comp.link_prog_node`.
- link_nav: InternPool.Nav.Index,
- /// Queue a `link.ZcuTask` to emit debug information for this container type.
- /// This `Job` exists (instead of the `link.ZcuTask` being directly queued) to ensure that
- /// all types are resolved before the linker task is queued.
- /// If the backend does not support `Zcu.Feature.separate_thread`, the task is run immediately.
- /// Before queueing this `Job`, increase the estimated total item count for `comp.link_prog_node`.
- link_type: InternPool.Index,
- /// Before queueing this `Job`, increase the estimated total item count for `comp.link_prog_node`.
- update_line_number: InternPool.TrackedInst.Index,
- /// The `AnalUnit`, which is *not* a `func`, must be semantically analyzed.
- /// This may be its first time being analyzed, or it may be outdated.
- /// If the unit is a test function, an `analyze_func` job will then be queued.
- analyze_comptime_unit: InternPool.AnalUnit,
- /// This function must be semantically analyzed.
- /// This may be its first time being analyzed, or it may be outdated.
- /// After analysis, a `codegen_func` job will be queued.
- /// These must be separate jobs to ensure any needed type resolution occurs *before* codegen.
- /// This job is separate from `analyze_comptime_unit` because it has a different priority.
- analyze_func: InternPool.Index,
- /// The main source file for the module needs to be analyzed.
- analyze_mod: *Package.Module,
- /// Fully resolve the given `struct` or `union` type.
- resolve_type_fully: InternPool.Index,
-
- /// The value is the index into `windows_libs`.
- windows_import_lib: usize,
-
- const Tag = @typeInfo(Job).@"union".tag_type.?;
- fn stage(tag: Tag) usize {
- return switch (tag) {
- // Prioritize functions so that codegen can get to work on them on a
- // separate thread, while Sema goes back to its own work.
- .resolve_type_fully, .analyze_func, .codegen_func => 0,
- else => 1,
- };
- }
- comptime {
- // Job dependencies
- assert(stage(.resolve_type_fully) <= stage(.codegen_func));
- }
-};
-
pub const CObject = struct {
/// Relative to cwd. Owned by arena.
src: CSourceFile,
@@ -1412,7 +1345,6 @@ pub const MiscTask = enum {
wasi_libc_crt_file,
compiler_rt,
libzigc,
- analyze_mod,
link_depfile,
docs_copy,
docs_wasm,
@@ -2297,7 +2229,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
.root_mod = options.root_mod,
.config = options.config,
.dirs = options.dirs,
- .work_queues = @splat(.empty),
.c_object_work_queue = .empty,
.win32_resource_work_queue = .empty,
.c_source_files = options.c_source_files,
@@ -2331,6 +2262,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
.root_name = root_name,
.sysroot = sysroot,
.windows_libs = .empty,
+ .windows_libs_num_done = 0,
.version = options.version,
.libc_installation = libc_dirs.libc_installation,
.compiler_rt_strat = compiler_rt_strat,
@@ -2693,16 +2625,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
}
}
- // Generate Windows import libs.
- if (target.os.tag == .windows) {
- const count = comp.windows_libs.count();
- for (0..count) |i| {
- try comp.queueJob(.{ .windows_import_lib = i });
- }
- // when integrating coff linker with prelink, the above `queueJob` will need to move
- // to something in `dispatchPrelinkWork`, which must queue all prelink link tasks
- // *before* we begin working on the main job queue.
- }
if (comp.wantBuildLibUnwindFromSource()) {
comp.queued_jobs.libunwind = true;
}
@@ -2786,7 +2708,6 @@ pub fn destroy(comp: *Compilation) void {
if (comp.zcu) |zcu| zcu.deinit();
comp.cache_use.deinit(io);
- for (&comp.work_queues) |*work_queue| work_queue.deinit(gpa);
comp.c_object_work_queue.deinit(gpa);
comp.win32_resource_work_queue.deinit(gpa);
@@ -3461,9 +3382,6 @@ fn flush(comp: *Compilation, arena: Allocator, tid: Zcu.PerThread.Id) (Io.Cancel
error.OutOfMemory, error.Canceled => |e| return e,
};
}
- if (comp.zcu) |zcu| {
- try link.File.C.flushEmitH(zcu);
- }
}
/// This function is called by the frontend before flush(). It communicates that
@@ -3728,7 +3646,9 @@ const Header = extern struct {
src_hash_deps_len: u32,
nav_val_deps_len: u32,
nav_ty_deps_len: u32,
- interned_deps_len: u32,
+ type_layout_deps_len: u32,
+ struct_defaults_deps_len: u32,
+ func_ies_deps_len: u32,
zon_file_deps_len: u32,
embed_file_deps_len: u32,
namespace_deps_len: u32,
@@ -3776,7 +3696,9 @@ pub fn saveState(comp: *Compilation) !void {
.src_hash_deps_len = @intCast(ip.src_hash_deps.count()),
.nav_val_deps_len = @intCast(ip.nav_val_deps.count()),
.nav_ty_deps_len = @intCast(ip.nav_ty_deps.count()),
- .interned_deps_len = @intCast(ip.interned_deps.count()),
+ .type_layout_deps_len = @intCast(ip.type_layout_deps.count()),
+ .struct_defaults_deps_len = @intCast(ip.struct_defaults_deps.count()),
+ .func_ies_deps_len = @intCast(ip.func_ies_deps.count()),
.zon_file_deps_len = @intCast(ip.zon_file_deps.count()),
.embed_file_deps_len = @intCast(ip.embed_file_deps.count()),
.namespace_deps_len = @intCast(ip.namespace_deps.count()),
@@ -3800,7 +3722,7 @@ pub fn saveState(comp: *Compilation) !void {
},
});
- try bufs.ensureTotalCapacityPrecise(22 + 9 * pt_headers.items.len);
+ try bufs.ensureTotalCapacityPrecise(26 + 9 * pt_headers.items.len);
addBuf(&bufs, mem.asBytes(&header));
addBuf(&bufs, @ptrCast(pt_headers.items));
@@ -3810,8 +3732,12 @@ pub fn saveState(comp: *Compilation) !void {
addBuf(&bufs, @ptrCast(ip.nav_val_deps.values()));
addBuf(&bufs, @ptrCast(ip.nav_ty_deps.keys()));
addBuf(&bufs, @ptrCast(ip.nav_ty_deps.values()));
- addBuf(&bufs, @ptrCast(ip.interned_deps.keys()));
- addBuf(&bufs, @ptrCast(ip.interned_deps.values()));
+ addBuf(&bufs, @ptrCast(ip.type_layout_deps.keys()));
+ addBuf(&bufs, @ptrCast(ip.type_layout_deps.values()));
+ addBuf(&bufs, @ptrCast(ip.struct_defaults_deps.keys()));
+ addBuf(&bufs, @ptrCast(ip.struct_defaults_deps.values()));
+ addBuf(&bufs, @ptrCast(ip.func_ies_deps.keys()));
+ addBuf(&bufs, @ptrCast(ip.func_ies_deps.values()));
addBuf(&bufs, @ptrCast(ip.zon_file_deps.keys()));
addBuf(&bufs, @ptrCast(ip.zon_file_deps.values()));
addBuf(&bufs, @ptrCast(ip.embed_file_deps.keys()));
@@ -4128,21 +4054,12 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle {
const SortOrder = struct {
zcu: *Zcu,
errors: []const *Zcu.ErrorMsg,
- read_err: *?ReadError,
- const ReadError = struct {
- file: *Zcu.File,
- err: Zcu.File.GetSourceError,
- };
pub fn lessThan(ctx: @This(), lhs_index: usize, rhs_index: usize) bool {
- if (ctx.read_err.* != null) return lhs_index < rhs_index;
- var bad_file: *Zcu.File = undefined;
- return ctx.errors[lhs_index].src_loc.lessThan(ctx.errors[rhs_index].src_loc, ctx.zcu, &bad_file) catch |err| {
- ctx.read_err.* = .{
- .file = bad_file,
- .err = err,
- };
- return lhs_index < rhs_index;
- };
+ return Zcu.ErrorMsg.order(
+ ctx.errors[lhs_index],
+ ctx.errors[rhs_index],
+ ctx.zcu,
+ ).compare(.lt);
}
};
@@ -4152,16 +4069,10 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle {
var entries = try zcu.failed_analysis.entries.clone(gpa);
errdefer entries.deinit(gpa);
- var read_err: ?SortOrder.ReadError = null;
entries.sort(SortOrder{
.zcu = zcu,
.errors = entries.items(.value),
- .read_err = &read_err,
});
- if (read_err) |e| {
- try unableToLoadZcuFile(zcu, &bundle, e.file, e.err);
- break :zcu_errors;
- }
break :s entries.slice();
};
defer sorted_failed_analysis.deinit(gpa);
@@ -4200,6 +4111,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle {
}
}
}
+ try zcu.addDependencyLoopErrors(&bundle);
for (zcu.failed_codegen.values()) |error_msg| {
try addModuleErrorMsg(zcu, &bundle, error_msg.*, false);
}
@@ -4219,7 +4131,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle {
.notes_len = 1,
});
const notes_start = try bundle.reserveNotes(1);
- bundle.extra.items[notes_start] = @intFromEnum(try bundle.addErrorMessage(.{
+ bundle.extra.items[notes_start] = @intFromEnum(bundle.addErrorMessageAssumeCapacity(.{
.msg = try bundle.printString("use '--error-limit {d}' to increase limit", .{
actual_error_count,
}),
@@ -4241,10 +4153,10 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle {
.notes_len = 2,
});
const notes_start = try bundle.reserveNotes(2);
- bundle.extra.items[notes_start + 0] = @intFromEnum(try bundle.addErrorMessage(.{
+ bundle.extra.items[notes_start + 0] = @intFromEnum(bundle.addErrorMessageAssumeCapacity(.{
.msg = try bundle.addString("run 'zig libc -h' to learn about libc installations"),
}));
- bundle.extra.items[notes_start + 1] = @intFromEnum(try bundle.addErrorMessage(.{
+ bundle.extra.items[notes_start + 1] = @intFromEnum(bundle.addErrorMessageAssumeCapacity(.{
.msg = try bundle.addString("run 'zig targets' to see the targets for which zig can always provide libc"),
}));
}
@@ -4268,7 +4180,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle {
if (!refs.contains(logging_unit)) continue;
try messages.append(gpa, .{
.src_loc = compile_log.src(),
- .msg = undefined, // populated later
+ .msg = "", // populated later, but must be valid for `sort` call below
.notes = &.{},
// We actually clear this later for most of these, but we populate
// this field for now to avoid having to allocate more data to track
@@ -4281,33 +4193,11 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle {
// Okay, there *are* referenced compile logs. Sort them into a consistent order.
- {
- const SortContext = struct {
- zcu: *Zcu,
- read_err: *?ReadError,
- const ReadError = struct {
- file: *Zcu.File,
- err: Zcu.File.GetSourceError,
- };
- fn lessThan(ctx: @This(), lhs: Zcu.ErrorMsg, rhs: Zcu.ErrorMsg) bool {
- if (ctx.read_err.* != null) return false;
- var bad_file: *Zcu.File = undefined;
- return lhs.src_loc.lessThan(rhs.src_loc, ctx.zcu, &bad_file) catch |err| {
- ctx.read_err.* = .{
- .file = bad_file,
- .err = err,
- };
- return false;
- };
- }
- };
- var read_err: ?SortContext.ReadError = null;
- std.mem.sort(Zcu.ErrorMsg, messages.items, @as(SortContext, .{ .read_err = &read_err, .zcu = zcu }), SortContext.lessThan);
- if (read_err) |e| {
- try unableToLoadZcuFile(zcu, &bundle, e.file, e.err);
- break :compile_log_text "";
+ std.mem.sort(Zcu.ErrorMsg, messages.items, zcu, struct {
+ fn lessThan(zcu_inner: *Zcu, lhs: Zcu.ErrorMsg, rhs: Zcu.ErrorMsg) bool {
+ return Zcu.ErrorMsg.order(&lhs, &rhs, zcu_inner).compare(.lt);
}
- }
+ }.lessThan);
var log_text: std.ArrayList(u8) = .empty;
defer log_text.deinit(gpa);
@@ -4331,6 +4221,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle {
break :compile_log_text try log_text.toOwnedSlice(gpa);
};
+ defer gpa.free(compile_log_text);
// TODO: eventually, this should be behind `std.debug.runtime_safety`. But right now, this is a
// very common way for incremental compilation bugs to manifest, so let's always check it.
@@ -4439,7 +4330,6 @@ pub fn addModuleErrorMsg(
already_added_error: bool,
) Allocator.Error!void {
const gpa = eb.gpa;
- const ip = &zcu.intern_pool;
const err_src_loc = module_err_msg.src_loc.upgrade(zcu);
const err_source = err_src_loc.file_scope.getSource(zcu) catch |err| {
return unableToLoadZcuFile(zcu, eb, err_src_loc.file_scope, err);
@@ -4452,66 +4342,12 @@ pub fn addModuleErrorMsg(
var ref_traces: std.ArrayList(ErrorBundle.ReferenceTrace) = .empty;
defer ref_traces.deinit(gpa);
- rt: {
- const rt_root = module_err_msg.reference_trace_root.unwrap() orelse break :rt;
- const max_references = zcu.comp.reference_trace orelse refs: {
- if (already_added_error) break :rt;
+ if (module_err_msg.reference_trace_root.unwrap()) |root| {
+ const frame_limit: u32 = zcu.comp.reference_trace orelse refs: {
+ if (already_added_error) break :refs 0;
break :refs default_reference_trace_len;
};
-
- const all_references = try zcu.resolveReferences();
-
- var seen: std.AutoHashMapUnmanaged(InternPool.AnalUnit, void) = .empty;
- defer seen.deinit(gpa);
-
- var referenced_by = rt_root;
- while (all_references.get(referenced_by)) |maybe_ref| {
- const ref = maybe_ref orelse break;
- const gop = try seen.getOrPut(gpa, ref.referencer);
- if (gop.found_existing) break;
- if (ref_traces.items.len < max_references) {
- var last_call_src = ref.src;
- var opt_inline_frame = ref.inline_frame;
- while (opt_inline_frame.unwrap()) |inline_frame| {
- const f = inline_frame.ptr(zcu).*;
- const func_nav = ip.indexToKey(f.callee).func.owner_nav;
- const func_name = ip.getNav(func_nav).name.toSlice(ip);
- addReferenceTraceFrame(zcu, eb, &ref_traces, func_name, last_call_src, true) catch |err| switch (err) {
- error.OutOfMemory => |e| return e,
- error.AlreadyReported => {
- // An incomplete reference trace isn't the end of the world; just cut it off.
- break :rt;
- },
- };
- last_call_src = f.call_src;
- opt_inline_frame = f.parent;
- }
- const root_name: ?[]const u8 = switch (ref.referencer.unwrap()) {
- .@"comptime" => "comptime",
- .nav_val, .nav_ty => |nav| ip.getNav(nav).name.toSlice(ip),
- .type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),
- .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip),
- .memoized_state => null,
- };
- if (root_name) |n| {
- addReferenceTraceFrame(zcu, eb, &ref_traces, n, last_call_src, false) catch |err| switch (err) {
- error.OutOfMemory => |e| return e,
- error.AlreadyReported => {
- // An incomplete reference trace isn't the end of the world; just cut it off.
- break :rt;
- },
- };
- }
- }
- referenced_by = ref.referencer;
- }
-
- if (seen.count() > ref_traces.items.len) {
- try ref_traces.append(gpa, .{
- .decl_name = @intCast(seen.count() - ref_traces.items.len),
- .src_loc = .none,
- });
- }
+ try zcu.populateReferenceTrace(root, frame_limit, eb, &ref_traces);
}
const src_loc = try eb.addSourceLocation(.{
@@ -4576,43 +4412,10 @@ pub fn addModuleErrorMsg(
const notes_start = try eb.reserveNotes(notes_len);
for (notes_start.., notes.keys()) |i, note| {
- eb.extra.items[i] = @intFromEnum(try eb.addErrorMessage(note));
+ eb.extra.items[i] = @intFromEnum(eb.addErrorMessageAssumeCapacity(note));
}
}
-fn addReferenceTraceFrame(
- zcu: *Zcu,
- eb: *ErrorBundle.Wip,
- ref_traces: *std.ArrayList(ErrorBundle.ReferenceTrace),
- name: []const u8,
- lazy_src: Zcu.LazySrcLoc,
- inlined: bool,
-) error{ OutOfMemory, AlreadyReported }!void {
- const gpa = zcu.gpa;
- const src = lazy_src.upgrade(zcu);
- const source = src.file_scope.getSource(zcu) catch |err| {
- try unableToLoadZcuFile(zcu, eb, src.file_scope, err);
- return error.AlreadyReported;
- };
- const span = src.span(zcu) catch |err| {
- try unableToLoadZcuFile(zcu, eb, src.file_scope, err);
- return error.AlreadyReported;
- };
- const loc = std.zig.findLineColumn(source, span.main);
- try ref_traces.append(gpa, .{
- .decl_name = try eb.printString("{s}{s}", .{ name, if (inlined) " [inlined]" else "" }),
- .src_loc = try eb.addSourceLocation(.{
- .src_path = try eb.printString("{f}", .{src.file_scope.path.fmt(zcu.comp)}),
- .span_start = span.start,
- .span_main = span.main,
- .span_end = span.end,
- .line = @intCast(loc.line),
- .column = @intCast(loc.column),
- .source_line = 0,
- }),
- });
-}
-
fn addWholeFileError(
zcu: *Zcu,
eb: *ErrorBundle.Wip,
@@ -4669,13 +4472,7 @@ fn performAllTheWork(
comp: *Compilation,
main_progress_node: std.Progress.Node,
update_arena: Allocator,
-) JobError!void {
- defer if (comp.zcu) |zcu| {
- zcu.codegen_task_pool.cancel(zcu);
- // Regardless of errors, `comp.zcu` needs to update its generation number.
- zcu.generation += 1;
- };
-
+) (Allocator.Error || Io.Cancelable)!void {
const io = comp.io;
// This is awkward: we don't want to start the timer until later, but we won't want to stop it
@@ -4708,217 +4505,33 @@ fn performAllTheWork(
misc_group.async(io, workerDocsWasm, .{ comp, main_progress_node });
}
- if (comp.zcu) |zcu| {
- const tracy_trace = traceNamed(@src(), "astgen");
- defer tracy_trace.end();
-
- const zir_prog_node = main_progress_node.start("AST Lowering", 0);
- defer zir_prog_node.end();
-
- var timer = comp.startTimer();
- defer if (timer.finish(io)) |ns| {
- comp.mutex.lockUncancelable(io);
- defer comp.mutex.unlock(io);
- comp.time_report.?.stats.real_ns_files = ns;
- };
-
- const gpa = comp.gpa;
-
- var astgen_group: Io.Group = .init;
- defer astgen_group.cancel(io);
-
- // We cannot reference `zcu.import_table` after we spawn any `workerUpdateFile` jobs,
- // because on single-threaded targets the worker will be run eagerly, meaning the
- // `import_table` could be mutated, and not even holding `comp.mutex` will save us. So,
- // build up a list of the files to update *before* we spawn any jobs.
- var astgen_work_items: std.MultiArrayList(struct {
- file_index: Zcu.File.Index,
- file: *Zcu.File,
- }) = .empty;
- defer astgen_work_items.deinit(gpa);
- // Not every item in `import_table` will need updating, because some are builtin.zig
- // files. However, most will, so let's just reserve sufficient capacity upfront.
- try astgen_work_items.ensureTotalCapacity(gpa, zcu.import_table.count());
- for (zcu.import_table.keys()) |file_index| {
- const file = zcu.fileByIndex(file_index);
- if (file.is_builtin) {
- // This is a `builtin.zig`, so updating is redundant. However, we want to make
- // sure the file contents are still correct on disk, since it can improve the
- // debugging experience better. That job only needs `file`, so we can kick it
- // off right now.
- astgen_group.async(io, workerUpdateBuiltinFile, .{ comp, file });
- continue;
- }
- astgen_work_items.appendAssumeCapacity(.{
- .file_index = file_index,
- .file = file,
- });
- }
-
- // Now that we're not going to touch `zcu.import_table` again, we can spawn `workerUpdateFile` jobs.
- for (astgen_work_items.items(.file_index), astgen_work_items.items(.file)) |file_index, file| {
- astgen_group.async(io, workerUpdateFile, .{
- comp, file, file_index, zir_prog_node, &astgen_group,
- });
- }
-
- // On the other hand, it's fine to directly iterate `zcu.embed_table.keys()` here
- // because `workerUpdateEmbedFile` can't invalidate it. The different here is that one
- // `@embedFile` can't trigger analysis of a new `@embedFile`!
- for (0.., zcu.embed_table.keys()) |ef_index_usize, ef| {
- const ef_index: Zcu.EmbedFile.Index = @enumFromInt(ef_index_usize);
- astgen_group.async(io, workerUpdateEmbedFile, .{
- comp, ef_index, ef,
- });
- }
-
- try astgen_group.await(io);
- }
-
+ defer if (comp.zcu) |zcu| zcu.codegen_task_pool.cancel(zcu);
if (comp.zcu) |zcu| {
const pt: Zcu.PerThread = .activate(zcu, .main);
- defer pt.deactivate();
-
- const gpa = zcu.gpa;
-
- // On an incremental update, a source file might become "dead", in that all imports of
- // the file were removed. This could even change what module the file belongs to! As such,
- // we do a traversal over the files, to figure out which ones are alive and the modules
- // they belong to.
- const any_fatal_files = try pt.computeAliveFiles();
-
- // If the cache mode is `whole`, add every alive source file to the manifest.
- switch (comp.cache_use) {
- .whole => |whole| if (whole.cache_manifest) |man| {
- for (zcu.alive_files.keys()) |file_index| {
- const file = zcu.fileByIndex(file_index);
-
- switch (file.status) {
- .never_loaded => unreachable, // AstGen tried to load it
- .retryable_failure => continue, // the file cannot be read; this is a guaranteed error
- .astgen_failure, .success => {}, // the file was read successfully
- }
-
- const path = try file.path.toAbsolute(comp.dirs, gpa);
- defer gpa.free(path);
-
- const result = res: {
- try whole.cache_manifest_mutex.lock(io);
- defer whole.cache_manifest_mutex.unlock(io);
- if (file.source) |source| {
- break :res man.addFilePostContents(path, source, file.stat);
- } else {
- break :res man.addFilePost(path);
- }
- };
- result catch |err| switch (err) {
- error.OutOfMemory => |e| return e,
- else => {
- try pt.reportRetryableFileError(file_index, "unable to update cache: {s}", .{@errorName(err)});
- continue;
- },
- };
- }
- },
- .none, .incremental => {},
+ defer {
+ pt.deactivate();
+ // Regardless of errors, `comp.zcu` needs to update its generation number.
+ zcu.generation += 1;
}
-
- if (any_fatal_files or
- zcu.multi_module_err != null or
- zcu.failed_imports.items.len > 0 or
- comp.alloc_failure_occurred)
- {
- // We give up right now! No updating of ZIR refs, no nothing. The idea is that this prevents
- // us from invalidating lots of incremental dependencies due to files with e.g. parse errors.
- // However, this means our analysis data is invalid, so we want to omit all analysis errors.
- zcu.skip_analysis_this_update = true;
- // Since we're skipping analysis, there are no ZCU link tasks.
- comp.link_queue.finishZcuQueue(comp);
- // Let other compilation work finish to collect as many errors as possible.
- try misc_group.await(io);
- comp.link_queue.wait(io);
- return;
- }
-
- if (comp.time_report) |*tr| {
- tr.stats.n_reachable_files = @intCast(zcu.alive_files.count());
- }
-
- if (comp.config.incremental) {
- const update_zir_refs_node = main_progress_node.start("Update ZIR References", 0);
- defer update_zir_refs_node.end();
- try pt.updateZirRefs();
- }
- try zcu.flushRetryableFailures();
-
- // It's analysis time! Queue up our initial analysis.
- for (zcu.analysisRoots()) |mod| {
- try comp.queueJob(.{ .analyze_mod = mod });
- }
-
- zcu.sema_prog_node = main_progress_node.start("Semantic Analysis", 0);
- if (comp.bin_file != null) {
- zcu.codegen_prog_node = main_progress_node.start("Code Generation", 0);
- }
- // We increment `pending_codegen_jobs` so that it doesn't reach 0 until after analysis finishes.
- // That prevents the "Code Generation" node from constantly disappearing and reappearing when
- // we're probably going to analyze more functions at some point.
- assert(zcu.pending_codegen_jobs.swap(1, .monotonic) == 0); // don't let this become 0 until analysis finishes
- }
- // When analysis ends, delete the progress nodes for "Semantic Analysis" and possibly "Code Generation".
- defer if (comp.zcu) |zcu| {
- zcu.sema_prog_node.end();
- zcu.sema_prog_node = .none;
- if (zcu.pending_codegen_jobs.fetchSub(1, .monotonic) == 1) {
- // Decremented to 0, so all done.
- zcu.codegen_prog_node.end();
- zcu.codegen_prog_node = .none;
- }
- };
-
- if (comp.zcu) |zcu| {
- if (!zcu.backendSupportsFeature(.separate_thread)) {
- // Close the ZCU task queue. Prelink may still be running, but the closed
- // queue will cause the linker task to exit once prelink finishes. The
- // closed queue also communicates to `enqueueZcu` that it should wait for
- // the linker task to finish and then run ZCU tasks serially.
- comp.link_queue.finishZcuQueue(comp);
- }
- }
-
- if (comp.zcu != null) {
- // Start the timer for the "decls" part of the pipeline (Sema, CodeGen, link).
- decl_work_timer = comp.startTimer();
- }
-
- work: while (true) {
- for (&comp.work_queues) |*work_queue| if (work_queue.popFront()) |job| {
- try processOneJob(.main, comp, job);
- continue :work;
- };
- if (comp.zcu) |zcu| {
- // If there's no work queued, check if there's anything outdated
- // which we need to work on, and queue it if so.
- if (try zcu.findOutdatedToAnalyze()) |outdated| {
- try comp.queueJob(switch (outdated.unwrap()) {
- .func => |f| .{ .analyze_func = f },
- .memoized_state,
- .@"comptime",
- .nav_ty,
- .nav_val,
- .type,
- => .{ .analyze_comptime_unit = outdated },
- });
- continue;
- }
- zcu.sema_prog_node.end();
- zcu.sema_prog_node = .none;
- }
- break;
+ try pt.update(main_progress_node, &decl_work_timer);
}
comp.link_queue.finishZcuQueue(comp);
+ // This has to happen after the main semantic analysis loop because it is possible for Sema to
+ // call `addLinkLib` and hence add more items to `comp.windows_libs`.
+ for (comp.windows_libs.keys()[comp.windows_libs_num_done..]) |link_lib| {
+ mingw.buildImportLib(comp, link_lib) catch |err| {
+ // TODO Surface more error details.
+ comp.lockAndSetMiscFailure(
+ .windows_import_lib,
+ "unable to generate DLL import .lib file for {s}: {t}",
+ .{ link_lib, err },
+ );
+ };
+ }
+ comp.windows_libs_num_done = @intCast(comp.windows_libs.count());
+
// Main thread work is all done, now just wait for all async work.
try misc_group.await(io);
comp.link_queue.wait(io);
@@ -5148,172 +4761,6 @@ fn dispatchPrelinkWork(comp: *Compilation, main_progress_node: std.Progress.Node
};
}
-const JobError = Allocator.Error || Io.Cancelable;
-
-pub fn queueJob(comp: *Compilation, job: Job) !void {
- try comp.work_queues[Job.stage(job)].pushBack(comp.gpa, job);
-}
-
-pub fn queueJobs(comp: *Compilation, jobs: []const Job) !void {
- for (jobs) |job| try comp.queueJob(job);
-}
-
-fn processOneJob(tid: Zcu.PerThread.Id, comp: *Compilation, job: Job) JobError!void {
- switch (job) {
- .codegen_func => |func| {
- const zcu = comp.zcu.?;
- const gpa = zcu.gpa;
- var owned_air: ?Air = func.air;
- defer if (owned_air) |*air| air.deinit(gpa);
-
- if (!owned_air.?.typesFullyResolved(zcu)) {
- // Type resolution failed in a way which affects this function. This is a transitive
- // failure, but it doesn't need recording, because this function semantically depends
- // on the failed type, so when it is changed the function is updated.
- zcu.codegen_prog_node.completeOne();
- comp.link_prog_node.completeOne();
- return;
- }
-
- // Some linkers need to refer to the AIR. In that case, the linker is not running
- // concurrently, so we'll just keep ownership of the AIR for ourselves instead of
- // letting the codegen job destroy it.
- const disown_air = zcu.backendSupportsFeature(.separate_thread);
-
- // Begin the codegen task. If the codegen/link queue is backed up, this might
- // block until the linker is able to process some tasks.
- const codegen_task = try zcu.codegen_task_pool.start(zcu, func.func, &owned_air.?, disown_air);
- if (disown_air) owned_air = null;
-
- try comp.link_queue.enqueueZcu(comp, tid, .{ .link_func = codegen_task });
- },
- .link_nav => |nav_index| {
- const zcu = comp.zcu.?;
- const nav = zcu.intern_pool.getNav(nav_index);
- if (nav.analysis != null) {
- const unit: InternPool.AnalUnit = .wrap(.{ .nav_val = nav_index });
- if (zcu.failed_analysis.contains(unit) or zcu.transitive_failed_analysis.contains(unit)) {
- comp.link_prog_node.completeOne();
- return;
- }
- }
- assert(nav.status == .fully_resolved);
- if (!Air.valFullyResolved(zcu.navValue(nav_index), zcu)) {
- // Type resolution failed in a way which affects this `Nav`. This is a transitive
- // failure, but it doesn't need recording, because this `Nav` semantically depends
- // on the failed type, so when it is changed the `Nav` will be updated.
- comp.link_prog_node.completeOne();
- return;
- }
- try comp.link_queue.enqueueZcu(comp, tid, .{ .link_nav = nav_index });
- },
- .link_type => |ty| {
- const zcu = comp.zcu.?;
- if (zcu.failed_types.fetchSwapRemove(ty)) |*entry| entry.value.deinit(zcu.gpa);
- if (!Air.typeFullyResolved(.fromInterned(ty), zcu)) {
- // Type resolution failed in a way which affects this type. This is a transitive
- // failure, but it doesn't need recording, because this type semantically depends
- // on the failed type, so when that is changed, this type will be updated.
- comp.link_prog_node.completeOne();
- return;
- }
- try comp.link_queue.enqueueZcu(comp, tid, .{ .link_type = ty });
- },
- .update_line_number => |tracked_inst| {
- try comp.link_queue.enqueueZcu(comp, tid, .{ .update_line_number = tracked_inst });
- },
- .analyze_func => |func| {
- const tracy_trace = traceNamed(@src(), "analyze_func");
- defer tracy_trace.end();
-
- const pt: Zcu.PerThread = .activate(comp.zcu.?, tid);
- defer pt.deactivate();
-
- pt.ensureFuncBodyUpToDate(func) catch |err| switch (err) {
- error.OutOfMemory => |e| return e,
- error.Canceled => |e| return e,
- error.AnalysisFail => return,
- };
- },
- .analyze_comptime_unit => |unit| {
- const tracy_trace = traceNamed(@src(), "analyze_comptime_unit");
- defer tracy_trace.end();
-
- const pt: Zcu.PerThread = .activate(comp.zcu.?, tid);
- defer pt.deactivate();
-
- const maybe_err: Zcu.SemaError!void = switch (unit.unwrap()) {
- .@"comptime" => |cu| pt.ensureComptimeUnitUpToDate(cu),
- .nav_ty => |nav| pt.ensureNavTypeUpToDate(nav),
- .nav_val => |nav| pt.ensureNavValUpToDate(nav),
- .type => |ty| if (pt.ensureTypeUpToDate(ty)) |_| {} else |err| err,
- .memoized_state => |stage| pt.ensureMemoizedStateUpToDate(stage),
- .func => unreachable,
- };
- maybe_err catch |err| switch (err) {
- error.OutOfMemory => |e| return e,
- error.Canceled => |e| return e,
- error.AnalysisFail => return,
- };
-
- queue_test_analysis: {
- if (!comp.config.is_test) break :queue_test_analysis;
- const nav = switch (unit.unwrap()) {
- .nav_val => |nav| nav,
- else => break :queue_test_analysis,
- };
-
- // Check if this is a test function.
- const ip = &pt.zcu.intern_pool;
- if (!pt.zcu.test_functions.contains(nav)) {
- break :queue_test_analysis;
- }
-
- // Tests are always emitted in test binaries. The decl_refs are created by
- // Zcu.populateTestFunctions, but this will not queue body analysis, so do
- // that now.
- try pt.zcu.ensureFuncBodyAnalysisQueued(ip.getNav(nav).status.fully_resolved.val);
- }
- },
- .resolve_type_fully => |ty| {
- const tracy_trace = traceNamed(@src(), "resolve_type_fully");
- defer tracy_trace.end();
-
- const pt: Zcu.PerThread = .activate(comp.zcu.?, tid);
- defer pt.deactivate();
- Type.fromInterned(ty).resolveFully(pt) catch |err| switch (err) {
- error.OutOfMemory, error.Canceled => |e| return e,
- error.AnalysisFail => return,
- };
- },
- .analyze_mod => |mod| {
- const tracy_trace = traceNamed(@src(), "analyze_mod");
- defer tracy_trace.end();
-
- const pt: Zcu.PerThread = .activate(comp.zcu.?, tid);
- defer pt.deactivate();
- pt.semaMod(mod) catch |err| switch (err) {
- error.OutOfMemory, error.Canceled => |e| return e,
- error.AnalysisFail => return,
- };
- },
- .windows_import_lib => |index| {
- const tracy_trace = traceNamed(@src(), "windows_import_lib");
- defer tracy_trace.end();
-
- const link_lib = comp.windows_libs.keys()[index];
- mingw.buildImportLib(comp, link_lib) catch |err| {
- // TODO Surface more error details.
- comp.lockAndSetMiscFailure(
- .windows_import_lib,
- "unable to generate DLL import .lib file for {s}: {t}",
- .{ link_lib, err },
- );
- };
- },
- }
-}
-
fn createDepFile(comp: *Compilation, dep_file: []const u8, bin_file: Cache.Path) anyerror!void {
const io = comp.io;
@@ -5641,112 +5088,6 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) SubU
};
}
-fn workerUpdateFile(
- comp: *Compilation,
- file: *Zcu.File,
- file_index: Zcu.File.Index,
- prog_node: std.Progress.Node,
- group: *Io.Group,
-) void {
- const io = comp.io;
- const tid: Zcu.PerThread.Id = .acquire(io);
- defer tid.release(io);
-
- const child_prog_node = prog_node.start(fs.path.basename(file.path.sub_path), 0);
- defer child_prog_node.end();
-
- const pt: Zcu.PerThread = .activate(comp.zcu.?, tid);
- defer pt.deactivate();
- pt.updateFile(file_index, file) catch |err| {
- pt.reportRetryableFileError(file_index, "unable to load '{s}': {s}", .{ fs.path.basename(file.path.sub_path), @errorName(err) }) catch |oom| switch (oom) {
- error.OutOfMemory => {
- comp.mutex.lockUncancelable(io);
- defer comp.mutex.unlock(io);
- comp.setAllocFailure();
- },
- };
- return;
- };
-
- switch (file.getMode()) {
- .zig => {}, // continue to logic below
- .zon => return, // ZON can't import anything so we're done
- }
-
- // Discover all imports in the file. Imports of modules we ignore for now since we don't
- // know which module we're in, but imports of file paths might need us to queue up other
- // AstGen jobs.
- const imports_index = file.zir.?.extra[@intFromEnum(Zir.ExtraIndex.imports)];
- if (imports_index != 0) {
- const extra = file.zir.?.extraData(Zir.Inst.Imports, imports_index);
- var import_i: u32 = 0;
- var extra_index = extra.end;
-
- while (import_i < extra.data.imports_len) : (import_i += 1) {
- const item = file.zir.?.extraData(Zir.Inst.Imports.Item, extra_index);
- extra_index = item.end;
-
- const import_path = file.zir.?.nullTerminatedString(item.data.name);
-
- if (pt.discoverImport(file.path, import_path)) |res| switch (res) {
- .module, .existing_file => {},
- .new_file => |new| {
- group.async(io, workerUpdateFile, .{
- comp, new.file, new.index, prog_node, group,
- });
- },
- } else |err| switch (err) {
- error.OutOfMemory => {
- comp.mutex.lockUncancelable(io);
- defer comp.mutex.unlock(io);
- comp.setAllocFailure();
- },
- }
- }
- }
-}
-
-fn workerUpdateBuiltinFile(comp: *Compilation, file: *Zcu.File) void {
- Builtin.updateFileOnDisk(file, comp) catch |err| comp.lockAndSetMiscFailure(
- .write_builtin_zig,
- "unable to write '{f}': {s}",
- .{ file.path.fmt(comp), @errorName(err) },
- );
-}
-
-fn workerUpdateEmbedFile(comp: *Compilation, ef_index: Zcu.EmbedFile.Index, ef: *Zcu.EmbedFile) void {
- const io = comp.io;
- const tid: Zcu.PerThread.Id = .acquire(io);
- defer tid.release(io);
- comp.detectEmbedFileUpdate(tid, ef_index, ef) catch |err| switch (err) {
- error.OutOfMemory => {
- comp.mutex.lockUncancelable(io);
- defer comp.mutex.unlock(io);
- comp.setAllocFailure();
- },
- };
-}
-
-fn detectEmbedFileUpdate(comp: *Compilation, tid: Zcu.PerThread.Id, ef_index: Zcu.EmbedFile.Index, ef: *Zcu.EmbedFile) !void {
- const io = comp.io;
- const zcu = comp.zcu.?;
- const pt: Zcu.PerThread = .activate(zcu, tid);
- defer pt.deactivate();
-
- const old_val = ef.val;
- const old_err = ef.err;
-
- try pt.updateEmbedFile(ef, null);
-
- if (ef.val != .none and ef.val == old_val) return; // success, value unchanged
- if (ef.val == .none and old_val == .none and ef.err == old_err) return; // failure, error unchanged
-
- comp.mutex.lockUncancelable(io);
- defer comp.mutex.unlock(io);
-
- try zcu.markDependeeOutdated(.not_marked_po, .{ .embed_file = ef_index });
-}
-
pub fn obtainCObjectCacheManifest(
comp: *const Compilation,
owner_mod: *Package.Module,
@@ -8375,12 +7716,10 @@ pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void {
// If we haven't seen this library yet and we're targeting Windows, we need
// to queue up a work item to produce the DLL import library for this.
const gop = try comp.windows_libs.getOrPut(comp.gpa, lib_name);
- if (gop.found_existing) return;
- {
+ if (!gop.found_existing) {
errdefer _ = comp.windows_libs.pop();
gop.key_ptr.* = try comp.gpa.dupe(u8, lib_name);
}
- try comp.queueJob(.{ .windows_import_lib = gop.index });
}
/// This decides the optimization mode for all zig-provided libraries, including
diff --git a/src/IncrementalDebugServer.zig b/src/IncrementalDebugServer.zig
index b4bc2c812ebd8ad67dce61738989efca3f388058..7d0dc8e89b6fd9fd257733839e924de1ce92a25f 100644
--- a/src/IncrementalDebugServer.zig
+++ b/src/IncrementalDebugServer.zig
@@ -306,12 +306,8 @@ fn handleCommand(zcu: *Zcu, w: *Io.Writer, cmd_str: []const u8, arg_str: []const
try w.print("[{d}] ", .{i});
switch (dependee) {
.src_hash, .namespace, .namespace_name, .zon_file, .embed_file => try w.print("{f}", .{zcu.fmtDependee(dependee)}),
- .nav_val, .nav_ty => |nav| try w.print("{s} {d}", .{ @tagName(dependee), @intFromEnum(nav) }),
- .interned => |ip_index| switch (ip.indexToKey(ip_index)) {
- .struct_type, .union_type, .enum_type => try w.print("type {d}", .{@intFromEnum(ip_index)}),
- .func => try w.print("func {d}", .{@intFromEnum(ip_index)}),
- else => unreachable,
- },
+ .nav_val, .nav_ty => |nav| try w.print("{t} {d}", .{ dependee, @intFromEnum(nav) }),
+ .type_layout, .struct_defaults, .func_ies => |ip_index| try w.print("{t} {d}", .{ dependee, @intFromEnum(ip_index) }),
.memoized_state => |stage| try w.print("memoized_state {s}", .{@tagName(stage)}),
}
try w.writeByte('\n');
@@ -376,8 +372,10 @@ fn parseAnalUnit(str: []const u8) ?AnalUnit {
return .wrap(.{ .nav_val = @enumFromInt(parseIndex(idx_str) orelse return null) });
} else if (std.mem.eql(u8, kind, "nav_ty")) {
return .wrap(.{ .nav_ty = @enumFromInt(parseIndex(idx_str) orelse return null) });
- } else if (std.mem.eql(u8, kind, "type")) {
- return .wrap(.{ .type = @enumFromInt(parseIndex(idx_str) orelse return null) });
+ } else if (std.mem.eql(u8, kind, "type_layout")) {
+ return .wrap(.{ .type_layout = @enumFromInt(parseIndex(idx_str) orelse return null) });
+ } else if (std.mem.eql(u8, kind, "struct_defaults")) {
+ return .wrap(.{ .struct_defaults = @enumFromInt(parseIndex(idx_str) orelse return null) });
} else if (std.mem.eql(u8, kind, "func")) {
return .wrap(.{ .func = @enumFromInt(parseIndex(idx_str) orelse return null) });
} else if (std.mem.eql(u8, kind, "memoized_state")) {
diff --git a/src/InternPool.zig b/src/InternPool.zig
index 595bedd5473653ccc2885b3181d5007dfe0b926e..7a561d6ca246553d16cc11f9f9a00c67e977ddfb 100644
--- a/src/InternPool.zig
+++ b/src/InternPool.zig
@@ -17,6 +17,7 @@ const Hash = std.hash.Wyhash;
const Zir = std.zig.Zir;
const Zcu = @import("Zcu.zig");
+const TypeClass = @import("Type.zig").Class;
/// One item per thread, indexed by `tid`, which is dense and unique per thread.
locals: []Local,
@@ -47,11 +48,15 @@ nav_val_deps: std.AutoArrayHashMapUnmanaged(Nav.Index, DepEntry.Index),
/// Dependencies on the type of a Nav.
/// Value is index into `dep_entries` of the first dependency on this Nav value.
nav_ty_deps: std.AutoArrayHashMapUnmanaged(Nav.Index, DepEntry.Index),
-/// Dependencies on an interned value, either:
-/// * a runtime function (invalidated when its IES changes)
-/// * a container type requiring resolution (invalidated when the type must be recreated at a new index)
-/// Value is index into `dep_entries` of the first dependency on this interned value.
-interned_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index),
+/// Dependencies on a function's inferred error set. Key is the function body, not the IES.
+/// Value is index into `dep_entries` of the first dependency on this function's IES.
+func_ies_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index),
+/// Dependencies on the resolved layout of a `struct`, `union`, or `enum` type.
+/// Value is index into `dep_entries` of the first dependency on this type's layout.
+type_layout_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index),
+/// Dependencies on the resolved default field values of a `struct` type.
+/// Value is index into `dep_entries` of the first dependency on this type's inits.
+struct_defaults_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index),
/// Dependencies on a ZON file. Triggered by `@import` of ZON.
/// Value is index into `dep_entries` of the first dependency on this ZON file.
zon_file_deps: std.AutoArrayHashMapUnmanaged(FileIndex, DepEntry.Index),
@@ -104,7 +109,9 @@ pub const empty: InternPool = .{
.src_hash_deps = .empty,
.nav_val_deps = .empty,
.nav_ty_deps = .empty,
- .interned_deps = .empty,
+ .func_ies_deps = .empty,
+ .type_layout_deps = .empty,
+ .struct_defaults_deps = .empty,
.zon_file_deps = .empty,
.embed_file_deps = .empty,
.namespace_deps = .empty,
@@ -415,7 +422,8 @@ pub const AnalUnit = packed struct(u64) {
@"comptime",
nav_val,
nav_ty,
- type,
+ type_layout,
+ struct_defaults,
func,
memoized_state,
};
@@ -427,9 +435,10 @@ pub const AnalUnit = packed struct(u64) {
nav_val: Nav.Index,
/// This `AnalUnit` resolves the type of the given `Nav`.
nav_ty: Nav.Index,
- /// This `AnalUnit` resolves the given `struct`/`union`/`enum` type.
- /// Generated tag enums are never used here (they do not undergo type resolution).
- type: InternPool.Index,
+ /// This `AnalUnit` resolves the layout of the given `struct`, `union`, or `enum` type.
+ type_layout: InternPool.Index,
+ /// This `AnalUnit` resolves the default field values of the given `struct` type.
+ struct_defaults: InternPool.Index,
/// This `AnalUnit` analyzes the body of the given runtime function.
func: InternPool.Index,
/// This `AnalUnit` resolves all state which is memoized in fields on `Zcu`.
@@ -538,6 +547,8 @@ pub const Nav = struct {
analysis: ?struct {
namespace: NamespaceIndex,
zir_index: TrackedInst.Index,
+ /// Initially `false`. Set to `true` by `setWantNavAnalysis`.
+ wanted: bool,
},
status: union(enum) {
/// This `Nav` is pending semantic analysis.
@@ -735,7 +746,7 @@ pub const Nav = struct {
const Repr = struct {
name: NullTerminatedString,
fqn: NullTerminatedString,
- // The following 1 fields are either both populated, or both `.none`.
+ // The following 2 fields are either both populated, or both `.none`.
analysis_namespace: OptionalNamespaceIndex,
analysis_zir_index: TrackedInst.Index.Optional,
/// Populated only if `bits.status != .unresolved`.
@@ -754,7 +765,7 @@ pub const Nav = struct {
@"addrspace": std.builtin.AddressSpace,
/// Populated only if `bits.status == .type_resolved`.
is_threadlocal: bool,
- _: u1 = 0,
+ want_analysis: bool,
};
fn unpack(repr: Repr) Nav {
@@ -764,6 +775,7 @@ pub const Nav = struct {
.analysis = if (repr.analysis_namespace.unwrap()) |namespace| .{
.namespace = namespace,
.zir_index = repr.analysis_zir_index.unwrap().?,
+ .wanted = repr.bits.want_analysis,
} else a: {
assert(repr.analysis_zir_index == .none);
break :a null;
@@ -816,6 +828,7 @@ pub const Nav = struct {
.alignment = .none,
.@"addrspace" = .generic,
.is_threadlocal = false,
+ .want_analysis = if (nav.analysis) |a| a.wanted else false,
},
.type_resolved => |r| .{
.status = if (r.is_extern_decl) .type_resolved_extern_decl else .type_resolved,
@@ -823,6 +836,7 @@ pub const Nav = struct {
.alignment = r.alignment,
.@"addrspace" = r.@"addrspace",
.is_threadlocal = r.is_threadlocal,
+ .want_analysis = if (nav.analysis) |a| a.wanted else false,
},
.fully_resolved => |r| .{
.status = .fully_resolved,
@@ -830,6 +844,7 @@ pub const Nav = struct {
.alignment = r.alignment,
.@"addrspace" = r.@"addrspace",
.is_threadlocal = false,
+ .want_analysis = if (nav.analysis) |a| a.wanted else false,
},
},
};
@@ -840,7 +855,10 @@ pub const Dependee = union(enum) {
src_hash: TrackedInst.Index,
nav_val: Nav.Index,
nav_ty: Nav.Index,
- interned: Index,
+ /// Index is the function, not its IES.
+ func_ies: Index,
+ type_layout: Index,
+ struct_defaults: Index,
zon_file: FileIndex,
embed_file: Zcu.EmbedFile.Index,
namespace: TrackedInst.Index,
@@ -892,7 +910,9 @@ pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyI
.src_hash => |x| ip.src_hash_deps.get(x),
.nav_val => |x| ip.nav_val_deps.get(x),
.nav_ty => |x| ip.nav_ty_deps.get(x),
- .interned => |x| ip.interned_deps.get(x),
+ .func_ies => |x| ip.func_ies_deps.get(x),
+ .type_layout => |x| ip.type_layout_deps.get(x),
+ .struct_defaults => |x| ip.struct_defaults_deps.get(x),
.zon_file => |x| ip.zon_file_deps.get(x),
.embed_file => |x| ip.embed_file_deps.get(x),
.namespace => |x| ip.namespace_deps.get(x),
@@ -965,7 +985,9 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend
.src_hash => ip.src_hash_deps,
.nav_val => ip.nav_val_deps,
.nav_ty => ip.nav_ty_deps,
- .interned => ip.interned_deps,
+ .func_ies => ip.func_ies_deps,
+ .type_layout => ip.type_layout_deps,
+ .struct_defaults => ip.struct_defaults_deps,
.zon_file => ip.zon_file_deps,
.embed_file => ip.embed_file_deps,
.namespace => ip.namespace_deps,
@@ -2065,15 +2087,15 @@ pub const Key = union(enum) {
simple_type: SimpleType,
/// This represents a struct that has been explicitly declared in source code,
/// or was created with `@Struct`. It is unique and based on a declaration.
- struct_type: NamespaceType,
+ struct_type: ContainerType,
/// This is a tuple type. Tuples are logically similar to structs, but have some
/// important differences in semantics; they do not undergo staged type resolution,
/// so cannot be self-referential, and they are not considered container/namespace
/// types, so cannot have declarations and have structural equality properties.
tuple_type: TupleType,
- union_type: NamespaceType,
- opaque_type: NamespaceType,
- enum_type: NamespaceType,
+ union_type: ContainerType,
+ opaque_type: ContainerType,
+ enum_type: ContainerType,
func_type: FuncType,
error_set_type: ErrorSetType,
/// The payload is the function body, either a `func_decl` or `func_instance`.
@@ -2092,10 +2114,6 @@ pub const Key = union(enum) {
enum_literal: NullTerminatedString,
/// A specific enum tag, indicated by the integer tag value.
enum_tag: EnumTag,
- /// An empty enum or union. TODO: this value's existence is strange, because such a type in
- /// reality has no values. See #15909.
- /// Payload is the type for which we are an empty value.
- empty_enum_value: Index,
float: Float,
ptr: Ptr,
slice: Slice,
@@ -2109,6 +2127,8 @@ pub const Key = union(enum) {
aggregate: Aggregate,
/// An instance of a union.
un: Union,
+ /// An instance of a `packed struct` or `packed union`.
+ bitpack: Bitpack,
/// A comptime function call with a memoized result.
memoized_call: Key.MemoizedCall,
@@ -2211,16 +2231,10 @@ pub const Key = union(enum) {
/// * `loadUnionType`
/// * `loadEnumType`
/// * `loadOpaqueType`
- pub const NamespaceType = union(enum) {
+ pub const ContainerType = union(enum) {
/// This type corresponds to an actual source declaration, e.g. `struct { ... }`.
/// It is hashed based on its ZIR instruction index and set of captures.
declared: Declared,
- /// This type is an automatically-generated enum tag type for a union.
- /// It is hashed based on the index of the union type it corresponds to.
- generated_tag: struct {
- /// The union for which this is a tag type.
- union_type: Index,
- },
/// This type originates from a reification via `@Enum`, `@Struct`, `@Union` or from an anonymous initialization.
/// It is hashed based on its ZIR instruction index and fields, attributes, etc.
/// To avoid making this key overly complex, the type-specific data is hashed by Sema.
@@ -2231,6 +2245,9 @@ pub const Key = union(enum) {
/// A hash of this type's attributes, fields, etc, generated by Sema.
type_hash: u64,
},
+ /// This type is an automatically-generated enum tag type for this union type.
+ /// It is hashed based on the index of the union type it corresponds to.
+ generated_union_tag: Index,
pub const Declared = struct {
/// A `struct_decl`, `union_decl`, `enum_decl`, or `opaque_decl` instruction.
@@ -2254,7 +2271,6 @@ pub const Key = union(enum) {
noalias_bits: u32,
cc: std.builtin.CallingConvention,
is_var_args: bool,
- is_generic: bool,
is_noinline: bool,
pub fn paramIsComptime(self: @This(), i: u5) bool {
@@ -2273,7 +2289,6 @@ pub const Key = union(enum) {
a.comptime_bits == b.comptime_bits and
a.noalias_bits == b.noalias_bits and
a.is_var_args == b.is_var_args and
- a.is_generic == b.is_generic and
a.is_noinline == b.is_noinline and
std.meta.eql(a.cc, b.cc);
}
@@ -2287,7 +2302,6 @@ pub const Key = union(enum) {
std.hash.autoHash(hasher, self.noalias_bits);
std.hash.autoHash(hasher, self.cc);
std.hash.autoHash(hasher, self.is_var_args);
- std.hash.autoHash(hasher, self.is_generic);
std.hash.autoHash(hasher, self.is_noinline);
}
};
@@ -2403,17 +2417,6 @@ pub const Key = union(enum) {
@atomicStore(FuncAnalysis, analysis_ptr, analysis, .release);
}
- pub fn setAnalyzed(func: Func, ip: *InternPool, io: Io) void {
- const extra_mutex = &ip.getLocal(func.tid).mutate.extra.mutex;
- extra_mutex.lockUncancelable(io);
- defer extra_mutex.unlock(io);
-
- const analysis_ptr = func.analysisPtr(ip);
- var analysis = analysis_ptr.*;
- analysis.is_analyzed = true;
- @atomicStore(FuncAnalysis, analysis_ptr, analysis, .release);
- }
-
/// Returns a pointer that becomes invalid after any additions to the `InternPool`.
fn zirBodyInstPtr(func: Func, ip: *const InternPool) *TrackedInst.Index {
const extra = ip.getLocalShared(func.tid).extra.acquire();
@@ -2471,8 +2474,6 @@ pub const Key = union(enum) {
u64: u64,
i64: i64,
big_int: BigIntConst,
- lazy_align: Index,
- lazy_size: Index,
/// Big enough to fit any non-BigInt value
pub const BigIntSpace = struct {
@@ -2485,7 +2486,6 @@ pub const Key = union(enum) {
return switch (storage) {
.big_int => |x| x,
inline .u64, .i64 => |x| BigIntMutable.init(&space.limbs, x).toConst(),
- .lazy_align, .lazy_size => unreachable,
};
}
};
@@ -2680,6 +2680,15 @@ pub const Key = union(enum) {
};
};
+ /// As well as a key, this type doubles as the payload in `extra` for `Tag.bitpack`.
+ pub const Bitpack = struct {
+ /// The `packed struct` or `packed union` type.
+ ty: Index,
+ /// The contents of the bitpack, represented as the backing integer value. The type of this
+ /// value is the same as the backing integer type of `ty`.
+ backing_int_val: Index,
+ };
+
pub const MemoizedCall = struct {
func: Index,
arg_values: []const Index,
@@ -2710,7 +2719,6 @@ pub const Key = union(enum) {
.err,
.enum_literal,
.enum_tag,
- .empty_enum_value,
.inferred_error_set_type,
.un,
=> |x| Hash.hash(seed, asBytes(&x)),
@@ -2742,13 +2750,13 @@ pub const Key = union(enum) {
std.hash.autoHash(&hasher, cv);
}
},
- .generated_tag => |generated_tag| {
- std.hash.autoHash(&hasher, generated_tag.union_type);
- },
.reified => |reified| {
std.hash.autoHash(&hasher, reified.zir_index);
std.hash.autoHash(&hasher, reified.type_hash);
},
+ .generated_union_tag => |union_type| {
+ std.hash.autoHash(&hasher, union_type);
+ },
}
return hasher.final();
},
@@ -2756,23 +2764,12 @@ pub const Key = union(enum) {
.int => |int| {
var hasher = Hash.init(seed);
// Canonicalize all integers by converting them to BigIntConst.
- switch (int.storage) {
- .u64, .i64, .big_int => {
- var buffer: Key.Int.Storage.BigIntSpace = undefined;
- const big_int = int.storage.toBigInt(&buffer);
+ var buffer: Key.Int.Storage.BigIntSpace = undefined;
+ const big_int = int.storage.toBigInt(&buffer);
- std.hash.autoHash(&hasher, int.ty);
- std.hash.autoHash(&hasher, big_int.positive);
- for (big_int.limbs) |limb| std.hash.autoHash(&hasher, limb);
- },
- .lazy_align, .lazy_size => |lazy_ty| {
- std.hash.autoHash(
- &hasher,
- @as(@typeInfo(Key.Int.Storage).@"union".tag_type.?, int.storage),
- );
- std.hash.autoHash(&hasher, lazy_ty);
- },
- }
+ std.hash.autoHash(&hasher, int.ty);
+ std.hash.autoHash(&hasher, big_int.positive);
+ for (big_int.limbs) |limb| std.hash.autoHash(&hasher, limb);
return hasher.final();
},
@@ -2929,6 +2926,8 @@ pub const Key = union(enum) {
asBytes(&e.relocation) ++
asBytes(&e.is_const) ++ asBytes(&e.alignment) ++ asBytes(&e.@"addrspace") ++
asBytes(&e.zir_index) ++ &[1]u8{@intFromEnum(e.source)}),
+
+ .bitpack => |bitpack| Hash.hash(seed, asBytes(&bitpack.ty) ++ asBytes(&bitpack.backing_int_val)),
};
}
@@ -3002,9 +3001,9 @@ pub const Key = union(enum) {
const b_info = b.enum_tag;
return std.meta.eql(a_info, b_info);
},
- .empty_enum_value => |a_info| {
- const b_info = b.empty_enum_value;
- return a_info == b_info;
+ .bitpack => |a_info| {
+ const b_info = b.bitpack;
+ return a_info.ty == b_info.ty and a_info.backing_int_val == b_info.backing_int_val;
},
.variable => |a_info| {
@@ -3102,27 +3101,16 @@ pub const Key = union(enum) {
.u64 => |bb| aa == bb,
.i64 => |bb| aa == bb,
.big_int => |bb| bb.orderAgainstScalar(aa) == .eq,
- .lazy_align, .lazy_size => false,
},
.i64 => |aa| switch (b_info.storage) {
.u64 => |bb| aa == bb,
.i64 => |bb| aa == bb,
.big_int => |bb| bb.orderAgainstScalar(aa) == .eq,
- .lazy_align, .lazy_size => false,
},
.big_int => |aa| switch (b_info.storage) {
.u64 => |bb| aa.orderAgainstScalar(bb) == .eq,
.i64 => |bb| aa.orderAgainstScalar(bb) == .eq,
.big_int => |bb| aa.eql(bb),
- .lazy_align, .lazy_size => false,
- },
- .lazy_align => |aa| switch (b_info.storage) {
- .u64, .i64, .big_int, .lazy_size => false,
- .lazy_align => |bb| aa == bb,
- },
- .lazy_size => |aa| switch (b_info.storage) {
- .u64, .i64, .big_int, .lazy_align => false,
- .lazy_size => |bb| aa == bb,
},
};
},
@@ -3175,12 +3163,12 @@ pub const Key = union(enum) {
};
return std.mem.eql(u32, @ptrCast(a_captures), @ptrCast(b_captures));
},
- .generated_tag => |a_gt| return a_gt.union_type == b_info.generated_tag.union_type,
.reified => |a_r| {
const b_r = b_info.reified;
return a_r.zir_index == b_r.zir_index and
a_r.type_hash == b_r.type_hash;
},
+ .generated_union_tag => |a_union_ty| return a_union_ty == b_info.generated_union_tag,
}
},
.aggregate => |a_info| {
@@ -3292,19 +3280,17 @@ pub const Key = union(enum) {
.enum_tag,
.aggregate,
.un,
+ .bitpack,
=> |x| x.ty,
.enum_literal => .enum_literal_type,
.undef => |x| x,
- .empty_enum_value => |x| x,
.simple_value => |s| switch (s) {
- .undefined => .undefined_type,
.void => .void_type,
.null => .null_type,
.false, .true => .bool_type,
- .empty_tuple => .empty_tuple_type,
.@"unreachable" => .noreturn_type,
},
@@ -3313,374 +3299,53 @@ pub const Key = union(enum) {
}
};
-pub const RequiresComptime = enum(u2) { no, yes, unknown, wip };
-
-// Unlike `Tag.TypeUnion` which is an encoding, and `Key.UnionType` which is a
-// minimal hashmap key, this type is a convenience type that contains info
-// needed by semantic analysis.
-pub const LoadedUnionType = struct {
- tid: Zcu.PerThread.Id,
- /// The index of the `Tag.TypeUnion` payload.
- extra_index: u32,
- // TODO: the non-fqn will be needed by the new dwarf structure
- /// The name of this union type.
- name: NullTerminatedString,
- /// Represents the declarations inside this union.
- namespace: NamespaceIndex,
- /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after.
- /// Otherwise, this is `.none`.
- name_nav: Nav.Index.Optional,
- /// The enum tag type.
- enum_tag_ty: Index,
- /// List of field types in declaration order.
- /// These are `none` until `status` is `have_field_types` or `have_layout`.
- field_types: Index.Slice,
- /// List of field alignments in declaration order.
- /// `none` means the ABI alignment of the type.
- /// If this slice has length 0 it means all elements are `none`.
- field_aligns: Alignment.Slice,
- /// Index of the union_decl or reify ZIR instruction.
- zir_index: TrackedInst.Index,
- captures: CaptureValue.Slice,
-
- pub const RuntimeTag = enum(u2) {
- none,
- safety,
- tagged,
-
- pub fn hasTag(self: RuntimeTag) bool {
- return switch (self) {
- .none => false,
- .tagged, .safety => true,
- };
- }
- };
-
- pub const Status = enum(u3) {
- none,
- field_types_wip,
- have_field_types,
- layout_wip,
- have_layout,
- fully_resolved_wip,
- /// The types and all its fields have had their layout resolved.
- /// Even through pointer, which `have_layout` does not ensure.
- fully_resolved,
-
- pub fn haveFieldTypes(status: Status) bool {
- return switch (status) {
- .none,
- .field_types_wip,
- => false,
- .have_field_types,
- .layout_wip,
- .have_layout,
- .fully_resolved_wip,
- .fully_resolved,
- => true,
- };
- }
-
- pub fn haveLayout(status: Status) bool {
- return switch (status) {
- .none,
- .field_types_wip,
- .have_field_types,
- .layout_wip,
- => false,
- .have_layout,
- .fully_resolved_wip,
- .fully_resolved,
- => true,
- };
- }
- };
-
- pub fn loadTagType(self: LoadedUnionType, ip: *const InternPool) LoadedEnumType {
- return ip.loadEnumType(self.enum_tag_ty);
- }
-
- /// Pointer to an enum type which is used for the tag of the union.
- /// This type is created even for untagged unions, even when the memory
- /// layout does not store the tag.
- /// Whether zig chooses this type or the user specifies it, it is stored here.
- /// This will be set to the null type until status is `have_field_types`.
- /// This accessor is provided so that the tag type can be mutated, and so that
- /// when it is mutated, the mutations are observed.
- /// The returned pointer expires with any addition to the `InternPool`.
- fn tagTypePtr(self: LoadedUnionType, ip: *const InternPool) *Index {
- const extra = ip.getLocalShared(self.tid).extra.acquire();
- const field_index = std.meta.fieldIndex(Tag.TypeUnion, "tag_ty").?;
- return @ptrCast(&extra.view().items(.@"0")[self.extra_index + field_index]);
- }
-
- pub fn tagTypeUnordered(u: LoadedUnionType, ip: *const InternPool) Index {
- return @atomicLoad(Index, u.tagTypePtr(ip), .unordered);
- }
-
- pub fn setTagType(u: LoadedUnionType, ip: *InternPool, io: Io, tag_type: Index) void {
- const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex;
- extra_mutex.lockUncancelable(io);
- defer extra_mutex.unlock(io);
-
- @atomicStore(Index, u.tagTypePtr(ip), tag_type, .release);
- }
-
- /// The returned pointer expires with any addition to the `InternPool`.
- fn flagsPtr(self: LoadedUnionType, ip: *const InternPool) *Tag.TypeUnion.Flags {
- const extra = ip.getLocalShared(self.tid).extra.acquire();
- const field_index = std.meta.fieldIndex(Tag.TypeUnion, "flags").?;
- return @ptrCast(&extra.view().items(.@"0")[self.extra_index + field_index]);
- }
-
- pub fn flagsUnordered(u: LoadedUnionType, ip: *const InternPool) Tag.TypeUnion.Flags {
- return @atomicLoad(Tag.TypeUnion.Flags, u.flagsPtr(ip), .unordered);
- }
-
- pub fn setStatus(u: LoadedUnionType, ip: *InternPool, io: Io, status: Status) void {
- const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex;
- extra_mutex.lockUncancelable(io);
- defer extra_mutex.unlock(io);
-
- const flags_ptr = u.flagsPtr(ip);
- var flags = flags_ptr.*;
- flags.status = status;
- @atomicStore(Tag.TypeUnion.Flags, flags_ptr, flags, .release);
- }
-
- pub fn setStatusIfLayoutWip(u: LoadedUnionType, ip: *InternPool, io: Io, status: Status) void {
- const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex;
- extra_mutex.lockUncancelable(io);
- defer extra_mutex.unlock(io);
-
- const flags_ptr = u.flagsPtr(ip);
- var flags = flags_ptr.*;
- if (flags.status == .layout_wip) flags.status = status;
- @atomicStore(Tag.TypeUnion.Flags, flags_ptr, flags, .release);
- }
-
- pub fn setAlignment(u: LoadedUnionType, ip: *InternPool, io: Io, alignment: Alignment) void {
- const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex;
- extra_mutex.lockUncancelable(io);
- defer extra_mutex.unlock(io);
-
- const flags_ptr = u.flagsPtr(ip);
- var flags = flags_ptr.*;
- flags.alignment = alignment;
- @atomicStore(Tag.TypeUnion.Flags, flags_ptr, flags, .release);
- }
-
- pub fn assumeRuntimeBitsIfFieldTypesWip(u: LoadedUnionType, ip: *InternPool, io: Io) bool {
- const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex;
- extra_mutex.lockUncancelable(io);
- defer extra_mutex.unlock(io);
-
- const flags_ptr = u.flagsPtr(ip);
- var flags = flags_ptr.*;
- defer if (flags.status == .field_types_wip) {
- flags.assumed_runtime_bits = true;
- @atomicStore(Tag.TypeUnion.Flags, flags_ptr, flags, .release);
- };
- return flags.status == .field_types_wip;
- }
-
- pub fn requiresComptime(u: LoadedUnionType, ip: *const InternPool) RequiresComptime {
- return u.flagsUnordered(ip).requires_comptime;
- }
-
- pub fn setRequiresComptimeWip(u: LoadedUnionType, ip: *InternPool, io: Io) RequiresComptime {
- const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex;
- extra_mutex.lockUncancelable(io);
- defer extra_mutex.unlock(io);
-
- const flags_ptr = u.flagsPtr(ip);
- var flags = flags_ptr.*;
- defer if (flags.requires_comptime == .unknown) {
- flags.requires_comptime = .wip;
- @atomicStore(Tag.TypeUnion.Flags, flags_ptr, flags, .release);
- };
- return flags.requires_comptime;
- }
-
- pub fn setRequiresComptime(u: LoadedUnionType, ip: *InternPool, io: Io, requires_comptime: RequiresComptime) void {
- assert(requires_comptime != .wip); // see setRequiresComptimeWip
-
- const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex;
- extra_mutex.lockUncancelable(io);
- defer extra_mutex.unlock(io);
-
- const flags_ptr = u.flagsPtr(ip);
- var flags = flags_ptr.*;
- flags.requires_comptime = requires_comptime;
- @atomicStore(Tag.TypeUnion.Flags, flags_ptr, flags, .release);
- }
-
- pub fn assumePointerAlignedIfFieldTypesWip(u: LoadedUnionType, ip: *InternPool, io: Io, ptr_align: Alignment) bool {
- const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex;
- extra_mutex.lockUncancelable(io);
- defer extra_mutex.unlock(io);
-
- const flags_ptr = u.flagsPtr(ip);
- var flags = flags_ptr.*;
- defer if (flags.status == .field_types_wip) {
- flags.alignment = ptr_align;
- flags.assumed_pointer_aligned = true;
- @atomicStore(Tag.TypeUnion.Flags, flags_ptr, flags, .release);
- };
- return flags.status == .field_types_wip;
- }
-
- /// The returned pointer expires with any addition to the `InternPool`.
- fn sizePtr(self: LoadedUnionType, ip: *const InternPool) *u32 {
- const extra = ip.getLocalShared(self.tid).extra.acquire();
- const field_index = std.meta.fieldIndex(Tag.TypeUnion, "size").?;
- return &extra.view().items(.@"0")[self.extra_index + field_index];
- }
-
- pub fn sizeUnordered(u: LoadedUnionType, ip: *const InternPool) u32 {
- return @atomicLoad(u32, u.sizePtr(ip), .unordered);
- }
-
- /// The returned pointer expires with any addition to the `InternPool`.
- fn paddingPtr(self: LoadedUnionType, ip: *const InternPool) *u32 {
- const extra = ip.getLocalShared(self.tid).extra.acquire();
- const field_index = std.meta.fieldIndex(Tag.TypeUnion, "padding").?;
- return &extra.view().items(.@"0")[self.extra_index + field_index];
- }
-
- pub fn paddingUnordered(u: LoadedUnionType, ip: *const InternPool) u32 {
- return @atomicLoad(u32, u.paddingPtr(ip), .unordered);
- }
-
- pub fn hasTag(self: LoadedUnionType, ip: *const InternPool) bool {
- return self.flagsUnordered(ip).runtime_tag.hasTag();
- }
-
- pub fn haveFieldTypes(self: LoadedUnionType, ip: *const InternPool) bool {
- return self.flagsUnordered(ip).status.haveFieldTypes();
- }
-
- pub fn haveLayout(self: LoadedUnionType, ip: *const InternPool) bool {
- return self.flagsUnordered(ip).status.haveLayout();
- }
-
- pub fn setHaveLayout(u: LoadedUnionType, ip: *InternPool, io: Io, size: u32, padding: u32, alignment: Alignment) void {
- const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex;
- extra_mutex.lockUncancelable(io);
- defer extra_mutex.unlock(io);
-
- @atomicStore(u32, u.sizePtr(ip), size, .unordered);
- @atomicStore(u32, u.paddingPtr(ip), padding, .unordered);
- const flags_ptr = u.flagsPtr(ip);
- var flags = flags_ptr.*;
- flags.alignment = alignment;
- flags.status = .have_layout;
- @atomicStore(Tag.TypeUnion.Flags, flags_ptr, flags, .release);
- }
-
- pub fn fieldAlign(self: LoadedUnionType, ip: *const InternPool, field_index: usize) Alignment {
- if (self.field_aligns.len == 0) return .none;
- return self.field_aligns.get(ip)[field_index];
- }
-
- /// This does not mutate the field of LoadedUnionType.
- pub fn setZirIndex(self: LoadedUnionType, ip: *InternPool, new_zir_index: TrackedInst.Index.Optional) void {
- const flags_field_index = std.meta.fieldIndex(Tag.TypeUnion, "flags").?;
- const zir_index_field_index = std.meta.fieldIndex(Tag.TypeUnion, "zir_index").?;
- const ptr: *TrackedInst.Index.Optional =
- @ptrCast(&ip.extra_.items[self.flags_index - flags_field_index + zir_index_field_index]);
- ptr.* = new_zir_index;
- }
-
- pub fn setFieldTypes(self: LoadedUnionType, ip: *const InternPool, types: []const Index) void {
- @memcpy(self.field_types.get(ip), types);
- }
-
- pub fn setFieldAligns(self: LoadedUnionType, ip: *const InternPool, aligns: []const Alignment) void {
- if (aligns.len == 0) return;
- assert(self.flagsUnordered(ip).any_aligned_fields);
- @memcpy(self.field_aligns.get(ip), aligns);
- }
-};
-
-pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
- const unwrapped_index = index.unwrap(ip);
- const extra_list = unwrapped_index.getExtra(ip);
- const data = unwrapped_index.getData(ip);
- const type_union = extraDataTrail(extra_list, Tag.TypeUnion, data);
- const fields_len = type_union.data.fields_len;
-
- var extra_index = type_union.end;
- const captures_len = if (type_union.data.flags.any_captures) c: {
- const len = extra_list.view().items(.@"0")[extra_index];
- extra_index += 1;
- break :c len;
- } else 0;
-
- const captures: CaptureValue.Slice = .{
- .tid = unwrapped_index.tid,
- .start = extra_index,
- .len = captures_len,
- };
- extra_index += captures_len;
- if (type_union.data.flags.is_reified) {
- extra_index += 2; // PackedU64
- }
-
- const field_types: Index.Slice = .{
- .tid = unwrapped_index.tid,
- .start = extra_index,
- .len = fields_len,
- };
- extra_index += fields_len;
-
- const field_aligns = if (type_union.data.flags.any_aligned_fields) a: {
- const a: Alignment.Slice = .{
- .tid = unwrapped_index.tid,
- .start = extra_index,
- .len = fields_len,
- };
- extra_index += std.math.divCeil(u32, fields_len, 4) catch unreachable;
- break :a a;
- } else Alignment.Slice.empty;
-
- return .{
- .tid = unwrapped_index.tid,
- .extra_index = data,
- .name = type_union.data.name,
- .name_nav = type_union.data.name_nav,
- .namespace = type_union.data.namespace,
- .enum_tag_ty = type_union.data.tag_ty,
- .field_types = field_types,
- .field_aligns = field_aligns,
- .zir_index = type_union.data.zir_index,
- .captures = captures,
- };
-}
-
pub const LoadedStructType = struct {
- tid: Zcu.PerThread.Id,
- /// The index of the `Tag.TypeStruct` or `Tag.TypeStructPacked` payload.
- extra_index: u32,
+ /// Index of the `struct_decl` or `reify` ZIR instruction.
+ zir_index: TrackedInst.Index,
+ captures: CaptureValue.Slice,
+ is_reified: bool,
+
// TODO: the non-fqn will be needed by the new dwarf structure
/// The name of this struct type.
name: NullTerminatedString,
- namespace: NamespaceIndex,
/// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after.
/// Otherwise, or if this is a file's root struct type, this is `.none`.
name_nav: Nav.Index.Optional,
- /// Index of the `struct_decl` or `reify` ZIR instruction.
- zir_index: TrackedInst.Index,
+ namespace: NamespaceIndex,
+
layout: std.builtin.Type.ContainerLayout,
+ /// May be `undefined` if `layout != .@"packed"`.
+ packed_backing_mode: BackingTypeMode,
+
+ /// Initially `false`, and set to `true` once any dependency on or reference to the struct's
+ /// layout is encountered, after which it is never reset to `false`, even across incremental
+ /// updates.
+ ///
+ /// This field is purely an optimization to avoid resolving the layout of types whose layouts
+ /// are never demanded. If this field is `true` but the layout is not actually needed, the
+ /// compiler frontend resolves this by traversing the reference graph at the end of each update
+ /// with `Zcu.resolveReferences` and hiding compile errors which arise from this analysis.
+ want_layout: bool,
+
+ // The remaining fields are only valid once the struct's layout is resolved.
+ field_name_map: MapIndex,
field_names: NullTerminatedString.Slice,
field_types: Index.Slice,
- field_inits: Index.Slice,
+ field_defaults: Index.Slice,
field_aligns: Alignment.Slice,
- runtime_order: RuntimeOrder.Slice,
- comptime_bits: ComptimeBits,
- offsets: Offsets,
- names_map: OptionalMapIndex,
- captures: CaptureValue.Slice,
+ field_is_comptime_bits: ComptimeBits,
+ /// If `layout` is `.@"packed"`, this is `.empty`.
+ field_runtime_order: RuntimeOrder.Slice,
+ /// If `layout` is `.@"packed"`, this is `.empty`.
+ field_offsets: Offsets,
+ /// Only valid if `layout` is `.@"packed"`.
+ packed_backing_int_type: Index,
+ /// Only valid if `layout` is *not* `.@"packed"`.
+ class: TypeClass,
+ /// Only valid if `layout` is *not* `.@"packed"`.
+ size: u32,
+ /// Only valid if `layout` is *not* `.@"packed"`.
+ alignment: Alignment,
pub const ComptimeBits = struct {
tid: Zcu.PerThread.Id,
@@ -3690,22 +3355,14 @@ pub const LoadedStructType = struct {
pub const empty: ComptimeBits = .{ .tid = .main, .start = 0, .len = 0 };
- pub fn get(this: ComptimeBits, ip: *const InternPool) []u32 {
+ pub fn getAll(this: ComptimeBits, ip: *const InternPool) []u32 {
const extra = ip.getLocalShared(this.tid).extra.acquire();
return extra.view().items(.@"0")[this.start..][0..this.len];
}
- pub fn getBit(this: ComptimeBits, ip: *const InternPool, i: usize) bool {
+ pub fn get(this: ComptimeBits, ip: *const InternPool, i: usize) bool {
if (this.len == 0) return false;
- return @as(u1, @truncate(this.get(ip)[i / 32] >> @intCast(i % 32))) != 0;
- }
-
- pub fn setBit(this: ComptimeBits, ip: *const InternPool, i: usize) void {
- this.get(ip)[i / 32] |= @as(u32, 1) << @intCast(i % 32);
- }
-
- pub fn clearBit(this: ComptimeBits, ip: *const InternPool, i: usize) void {
- this.get(ip)[i / 32] &= ~(@as(u32, 1) << @intCast(i % 32));
+ return @as(u1, @truncate(this.getAll(ip)[i / 32] >> @intCast(i % 32))) != 0;
}
};
@@ -3753,865 +3410,602 @@ pub const LoadedStructType = struct {
/// Look up field index based on field name.
pub fn nameIndex(s: LoadedStructType, ip: *const InternPool, name: NullTerminatedString) ?u32 {
- const names_map = s.names_map.unwrap() orelse {
- const i = name.toUnsigned(ip) orelse return null;
- if (i >= s.field_types.len) return null;
- return i;
- };
- const map = names_map.get(ip);
+ const map = s.field_name_map.get(ip);
const adapter: NullTerminatedString.Adapter = .{ .strings = s.field_names.get(ip) };
const field_index = map.getIndexAdapted(name, adapter) orelse return null;
return @intCast(field_index);
}
- /// Returns the already-existing field with the same name, if any.
- pub fn addFieldName(
- s: LoadedStructType,
- ip: *InternPool,
- name: NullTerminatedString,
- ) ?u32 {
- const extra = ip.getLocalShared(s.tid).extra.acquire();
- return ip.addFieldName(extra, s.names_map.unwrap().?, s.field_names.start, name);
- }
-
- pub fn fieldAlign(s: LoadedStructType, ip: *const InternPool, i: usize) Alignment {
- if (s.field_aligns.len == 0) return .none;
- return s.field_aligns.get(ip)[i];
- }
-
- pub fn fieldInit(s: LoadedStructType, ip: *const InternPool, i: usize) Index {
- if (s.field_inits.len == 0) return .none;
- assert(s.haveFieldInits(ip));
- return s.field_inits.get(ip)[i];
- }
-
- pub fn fieldName(s: LoadedStructType, ip: *const InternPool, i: usize) NullTerminatedString {
- return s.field_names.get(ip)[i];
- }
-
- pub fn fieldIsComptime(s: LoadedStructType, ip: *const InternPool, i: usize) bool {
- return s.comptime_bits.getBit(ip, i);
- }
-
- pub fn setFieldComptime(s: LoadedStructType, ip: *InternPool, i: usize) void {
- s.comptime_bits.setBit(ip, i);
- }
-
- /// The returned pointer expires with any addition to the `InternPool`.
- /// Asserts the struct is not packed.
- fn flagsPtr(s: LoadedStructType, ip: *const InternPool) *Tag.TypeStruct.Flags {
- assert(s.layout != .@"packed");
- const extra = ip.getLocalShared(s.tid).extra.acquire();
- const flags_field_index = std.meta.fieldIndex(Tag.TypeStruct, "flags").?;
- return @ptrCast(&extra.view().items(.@"0")[s.extra_index + flags_field_index]);
- }
-
- pub fn flagsUnordered(s: LoadedStructType, ip: *const InternPool) Tag.TypeStruct.Flags {
- return @atomicLoad(Tag.TypeStruct.Flags, s.flagsPtr(ip), .unordered);
- }
-
- /// The returned pointer expires with any addition to the `InternPool`.
- /// Asserts that the struct is packed.
- fn packedFlagsPtr(s: LoadedStructType, ip: *const InternPool) *Tag.TypeStructPacked.Flags {
- assert(s.layout == .@"packed");
- const extra = ip.getLocalShared(s.tid).extra.acquire();
- const flags_field_index = std.meta.fieldIndex(Tag.TypeStructPacked, "flags").?;
- return @ptrCast(&extra.view().items(.@"0")[s.extra_index + flags_field_index]);
- }
-
- pub fn packedFlagsUnordered(s: LoadedStructType, ip: *const InternPool) Tag.TypeStructPacked.Flags {
- return @atomicLoad(Tag.TypeStructPacked.Flags, s.packedFlagsPtr(ip), .unordered);
- }
-
- /// Reads the non-opv flag calculated during AstGen. Used to short-circuit more
- /// complicated logic.
- pub fn knownNonOpv(s: LoadedStructType, ip: *const InternPool) bool {
- return switch (s.layout) {
- .@"packed" => false,
- .auto, .@"extern" => s.flagsUnordered(ip).known_non_opv,
- };
- }
-
- pub fn requiresComptime(s: LoadedStructType, ip: *const InternPool) RequiresComptime {
- return s.flagsUnordered(ip).requires_comptime;
- }
-
- pub fn setRequiresComptimeWip(s: LoadedStructType, ip: *InternPool, io: Io) RequiresComptime {
- const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
- extra_mutex.lockUncancelable(io);
- defer extra_mutex.unlock(io);
-
- const flags_ptr = s.flagsPtr(ip);
- var flags = flags_ptr.*;
- defer if (flags.requires_comptime == .unknown) {
- flags.requires_comptime = .wip;
- @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
- };
- return flags.requires_comptime;
- }
-
- pub fn setRequiresComptime(s: LoadedStructType, ip: *InternPool, io: Io, requires_comptime: RequiresComptime) void {
- assert(requires_comptime != .wip); // see setRequiresComptimeWip
-
- const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
- extra_mutex.lockUncancelable(io);
- defer extra_mutex.unlock(io);
-
- const flags_ptr = s.flagsPtr(ip);
- var flags = flags_ptr.*;
- flags.requires_comptime = requires_comptime;
- @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
- }
-
- pub fn assumeRuntimeBitsIfFieldTypesWip(s: LoadedStructType, ip: *InternPool, io: Io) bool {
- if (s.layout == .@"packed") return false;
-
- const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
- extra_mutex.lockUncancelable(io);
- defer extra_mutex.unlock(io);
-
- const flags_ptr = s.flagsPtr(ip);
- var flags = flags_ptr.*;
- defer if (flags.field_types_wip) {
- flags.assumed_runtime_bits = true;
- @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
- };
- return flags.field_types_wip;
- }
-
- pub fn setFieldTypesWip(s: LoadedStructType, ip: *InternPool, io: Io) bool {
- if (s.layout == .@"packed") return false;
-
- const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
- extra_mutex.lockUncancelable(io);
- defer extra_mutex.unlock(io);
-
- const flags_ptr = s.flagsPtr(ip);
- var flags = flags_ptr.*;
- defer {
- flags.field_types_wip = true;
- @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
- }
- return flags.field_types_wip;
- }
-
- pub fn clearFieldTypesWip(s: LoadedStructType, ip: *InternPool, io: Io) void {
- if (s.layout == .@"packed") return;
-
- const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
- extra_mutex.lockUncancelable(io);
- defer extra_mutex.unlock(io);
-
- const flags_ptr = s.flagsPtr(ip);
- var flags = flags_ptr.*;
- flags.field_types_wip = false;
- @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
- }
-
- pub fn setLayoutWip(s: LoadedStructType, ip: *InternPool, io: Io) bool {
- if (s.layout == .@"packed") return false;
-
- const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
- extra_mutex.lockUncancelable(io);
- defer extra_mutex.unlock(io);
-
- const flags_ptr = s.flagsPtr(ip);
- var flags = flags_ptr.*;
- defer {
- flags.layout_wip = true;
- @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
- }
- return flags.layout_wip;
- }
-
- pub fn clearLayoutWip(s: LoadedStructType, ip: *InternPool, io: Io) void {
- if (s.layout == .@"packed") return;
-
- const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
- extra_mutex.lockUncancelable(io);
- defer extra_mutex.unlock(io);
-
- const flags_ptr = s.flagsPtr(ip);
- var flags = flags_ptr.*;
- flags.layout_wip = false;
- @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
- }
-
- pub fn setAlignment(s: LoadedStructType, ip: *InternPool, io: Io, alignment: Alignment) void {
- const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
- extra_mutex.lockUncancelable(io);
- defer extra_mutex.unlock(io);
-
- const flags_ptr = s.flagsPtr(ip);
- var flags = flags_ptr.*;
- flags.alignment = alignment;
- @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
- }
-
- pub fn assumePointerAlignedIfFieldTypesWip(s: LoadedStructType, ip: *InternPool, io: Io, ptr_align: Alignment) bool {
- const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
- extra_mutex.lockUncancelable(io);
- defer extra_mutex.unlock(io);
-
- const flags_ptr = s.flagsPtr(ip);
- var flags = flags_ptr.*;
- defer if (flags.field_types_wip) {
- flags.alignment = ptr_align;
- flags.assumed_pointer_aligned = true;
- @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
- };
- return flags.field_types_wip;
- }
-
- pub fn assumePointerAlignedIfWip(s: LoadedStructType, ip: *InternPool, io: Io, ptr_align: Alignment) bool {
- const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
- extra_mutex.lockUncancelable(io);
- defer extra_mutex.unlock(io);
-
- const flags_ptr = s.flagsPtr(ip);
- var flags = flags_ptr.*;
- defer {
- if (flags.alignment_wip) {
- flags.alignment = ptr_align;
- flags.assumed_pointer_aligned = true;
- } else flags.alignment_wip = true;
- @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
- }
- return flags.alignment_wip;
- }
-
- pub fn clearAlignmentWip(s: LoadedStructType, ip: *InternPool, io: Io) void {
- if (s.layout == .@"packed") return;
-
- const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
- extra_mutex.lockUncancelable(io);
- defer extra_mutex.unlock(io);
-
- const flags_ptr = s.flagsPtr(ip);
- var flags = flags_ptr.*;
- flags.alignment_wip = false;
- @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
- }
-
- pub fn setInitsWip(s: LoadedStructType, ip: *InternPool, io: Io) bool {
- const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
- extra_mutex.lockUncancelable(io);
- defer extra_mutex.unlock(io);
-
- switch (s.layout) {
- .@"packed" => {
- const flags_ptr = s.packedFlagsPtr(ip);
- var flags = flags_ptr.*;
- defer {
- flags.field_inits_wip = true;
- @atomicStore(Tag.TypeStructPacked.Flags, flags_ptr, flags, .release);
- }
- return flags.field_inits_wip;
- },
- .auto, .@"extern" => {
- const flags_ptr = s.flagsPtr(ip);
- var flags = flags_ptr.*;
- defer {
- flags.field_inits_wip = true;
- @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
- }
- return flags.field_inits_wip;
- },
- }
- }
-
- pub fn clearInitsWip(s: LoadedStructType, ip: *InternPool, io: Io) void {
- const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
- extra_mutex.lockUncancelable(io);
- defer extra_mutex.unlock(io);
-
- switch (s.layout) {
- .@"packed" => {
- const flags_ptr = s.packedFlagsPtr(ip);
- var flags = flags_ptr.*;
- flags.field_inits_wip = false;
- @atomicStore(Tag.TypeStructPacked.Flags, flags_ptr, flags, .release);
- },
- .auto, .@"extern" => {
- const flags_ptr = s.flagsPtr(ip);
- var flags = flags_ptr.*;
- flags.field_inits_wip = false;
- @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
- },
- }
- }
-
- pub fn setFullyResolved(s: LoadedStructType, ip: *InternPool, io: Io) bool {
- if (s.layout == .@"packed") return true;
-
- const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
- extra_mutex.lockUncancelable(io);
- defer extra_mutex.unlock(io);
-
- const flags_ptr = s.flagsPtr(ip);
- var flags = flags_ptr.*;
- defer {
- flags.fully_resolved = true;
- @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
- }
- return flags.fully_resolved;
- }
-
- pub fn clearFullyResolved(s: LoadedStructType, ip: *InternPool, io: Io) void {
- const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
- extra_mutex.lockUncancelable(io);
- defer extra_mutex.unlock(io);
-
- const flags_ptr = s.flagsPtr(ip);
- var flags = flags_ptr.*;
- flags.fully_resolved = false;
- @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
- }
-
- /// The returned pointer expires with any addition to the `InternPool`.
- /// Asserts the struct is not packed.
- fn sizePtr(s: LoadedStructType, ip: *const InternPool) *u32 {
- assert(s.layout != .@"packed");
- const extra = ip.getLocalShared(s.tid).extra.acquire();
- const size_field_index = std.meta.fieldIndex(Tag.TypeStruct, "size").?;
- return @ptrCast(&extra.view().items(.@"0")[s.extra_index + size_field_index]);
- }
-
- pub fn sizeUnordered(s: LoadedStructType, ip: *const InternPool) u32 {
- return @atomicLoad(u32, s.sizePtr(ip), .unordered);
- }
-
- /// The backing integer type of the packed struct. Whether zig chooses
- /// this type or the user specifies it, it is stored here. This will be
- /// set to `none` until the layout is resolved.
- /// Asserts the struct is packed.
- fn backingIntTypePtr(s: LoadedStructType, ip: *const InternPool) *Index {
- assert(s.layout == .@"packed");
- const extra = ip.getLocalShared(s.tid).extra.acquire();
- const field_index = std.meta.fieldIndex(Tag.TypeStructPacked, "backing_int_ty").?;
- return @ptrCast(&extra.view().items(.@"0")[s.extra_index + field_index]);
- }
-
- pub fn backingIntTypeUnordered(s: LoadedStructType, ip: *const InternPool) Index {
- return @atomicLoad(Index, s.backingIntTypePtr(ip), .unordered);
- }
-
- pub fn setBackingIntType(s: LoadedStructType, ip: *InternPool, io: Io, backing_int_ty: Index) void {
- const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
- extra_mutex.lockUncancelable(io);
- defer extra_mutex.unlock(io);
-
- @atomicStore(Index, s.backingIntTypePtr(ip), backing_int_ty, .release);
- }
-
- /// Asserts the struct is not packed.
- pub fn setZirIndex(s: LoadedStructType, ip: *InternPool, new_zir_index: TrackedInst.Index.Optional) void {
- assert(s.layout != .@"packed");
- const field_index = std.meta.fieldIndex(Tag.TypeStruct, "zir_index").?;
- ip.extra_.items[s.extra_index + field_index] = @intFromEnum(new_zir_index);
- }
-
- pub fn haveFieldTypes(s: LoadedStructType, ip: *const InternPool) bool {
- const types = s.field_types.get(ip);
- return types.len == 0 or types[types.len - 1] != .none;
- }
-
- pub fn haveFieldInits(s: LoadedStructType, ip: *const InternPool) bool {
- return switch (s.layout) {
- .@"packed" => s.packedFlagsUnordered(ip).inits_resolved,
- .auto, .@"extern" => s.flagsUnordered(ip).inits_resolved,
- };
- }
-
- pub fn setHaveFieldInits(s: LoadedStructType, ip: *InternPool, io: Io) void {
- const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
- extra_mutex.lockUncancelable(io);
- defer extra_mutex.unlock(io);
-
- switch (s.layout) {
- .@"packed" => {
- const flags_ptr = s.packedFlagsPtr(ip);
- var flags = flags_ptr.*;
- flags.inits_resolved = true;
- @atomicStore(Tag.TypeStructPacked.Flags, flags_ptr, flags, .release);
- },
- .auto, .@"extern" => {
- const flags_ptr = s.flagsPtr(ip);
- var flags = flags_ptr.*;
- flags.inits_resolved = true;
- @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
- },
- }
- }
-
- pub fn haveLayout(s: LoadedStructType, ip: *const InternPool) bool {
- return switch (s.layout) {
- .@"packed" => s.backingIntTypeUnordered(ip) != .none,
- .auto, .@"extern" => s.flagsUnordered(ip).layout_resolved,
- };
- }
-
- pub fn setLayoutResolved(s: LoadedStructType, ip: *InternPool, io: Io, size: u32, alignment: Alignment) void {
- const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
- extra_mutex.lockUncancelable(io);
- defer extra_mutex.unlock(io);
-
- @atomicStore(u32, s.sizePtr(ip), size, .unordered);
- const flags_ptr = s.flagsPtr(ip);
- var flags = flags_ptr.*;
- flags.alignment = alignment;
- flags.layout_resolved = true;
- @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
- }
-
- pub fn hasReorderedFields(s: LoadedStructType) bool {
- return s.layout == .auto;
- }
-
- pub const RuntimeOrderIterator = struct {
- ip: *InternPool,
- field_index: u32,
- struct_type: InternPool.LoadedStructType,
-
- pub fn next(it: *@This()) ?u32 {
- var i = it.field_index;
-
- if (i >= it.struct_type.field_types.len)
- return null;
-
- if (it.struct_type.hasReorderedFields()) {
- it.field_index += 1;
- return it.struct_type.runtime_order.get(it.ip)[i].toInt();
- }
-
- while (it.struct_type.fieldIsComptime(it.ip, i)) {
- i += 1;
- if (i >= it.struct_type.field_types.len)
- return null;
- }
-
- it.field_index = i + 1;
- return i;
- }
- };
-
/// Iterates over non-comptime fields in the order they are laid out in memory at runtime.
/// May or may not include zero-bit fields.
/// Asserts the struct is not packed.
- pub fn iterateRuntimeOrder(s: LoadedStructType, ip: *InternPool) RuntimeOrderIterator {
- assert(s.layout != .@"packed");
- return .{
- .ip = ip,
- .field_index = 0,
- .struct_type = s,
- };
+ pub fn iterateRuntimeOrder(s: *const LoadedStructType, ip: *const InternPool) RuntimeOrderIterator {
+ switch (s.layout) {
+ .auto => {
+ const ro = std.mem.sliceTo(s.field_runtime_order.get(ip), .omitted);
+ return .{
+ .runtime_order = ro,
+ .fields_len = @intCast(ro.len),
+ .next_index = 0,
+ };
+ },
+ .@"extern" => return .{
+ .runtime_order = null,
+ .fields_len = s.field_names.len,
+ .next_index = 0,
+ },
+ .@"packed" => unreachable,
+ }
}
+ pub const RuntimeOrderIterator = struct {
+ runtime_order: ?[]const RuntimeOrder,
+ fields_len: u32,
+ next_index: u32,
+ pub fn next(it: *RuntimeOrderIterator) ?u32 {
+ const i = it.next_index;
+ if (i == it.fields_len) return null;
+ it.next_index = i + 1;
+ const ro = it.runtime_order orelse return i;
+ return ro[i].toInt().?;
+ }
+ };
+ pub fn iterateRuntimeOrderReverse(s: *const LoadedStructType, ip: *InternPool) ReverseRuntimeOrderIterator {
+ switch (s.layout) {
+ .auto => {
+ const ro = std.mem.sliceTo(s.field_runtime_order.get(ip), .omitted);
+ return .{
+ .runtime_order = ro,
+ .last_index = @intCast(ro.len),
+ };
+ },
+ .@"extern" => return .{
+ .runtime_order = null,
+ .last_index = s.field_names.len,
+ },
+ .@"packed" => unreachable,
+ }
+ }
pub const ReverseRuntimeOrderIterator = struct {
- ip: *InternPool,
+ runtime_order: ?[]const RuntimeOrder,
last_index: u32,
- struct_type: InternPool.LoadedStructType,
-
- pub fn next(it: *@This()) ?u32 {
- if (it.last_index == 0)
- return null;
-
- if (it.struct_type.hasReorderedFields()) {
- it.last_index -= 1;
- const order = it.struct_type.runtime_order.get(it.ip);
- while (order[it.last_index] == .omitted) {
- it.last_index -= 1;
- if (it.last_index == 0)
- return null;
- }
- return order[it.last_index].toInt();
- }
-
- it.last_index -= 1;
- while (it.struct_type.fieldIsComptime(it.ip, it.last_index)) {
- it.last_index -= 1;
- if (it.last_index == 0)
- return null;
- }
-
- return it.last_index;
+ pub fn next(it: *ReverseRuntimeOrderIterator) ?u32 {
+ if (it.last_index == 0) return null;
+ const i = it.last_index - 1;
+ it.last_index = i;
+ const ro = it.runtime_order orelse return i;
+ return ro[i].toInt().?;
}
};
-
- pub fn iterateRuntimeOrderReverse(s: LoadedStructType, ip: *InternPool) ReverseRuntimeOrderIterator {
- assert(s.layout != .@"packed");
- return .{
- .ip = ip,
- .last_index = s.field_types.len,
- .struct_type = s,
- };
- }
};
-pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
- const unwrapped_index = index.unwrap(ip);
- const extra_list = unwrapped_index.getExtra(ip);
- const extra_items = extra_list.view().items(.@"0");
- const item = unwrapped_index.getItem(ip);
- switch (item.tag) {
- .type_struct => {
- const name: NullTerminatedString = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "name").?]);
- const name_nav: Nav.Index.Optional = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "name_nav").?]);
- const namespace: NamespaceIndex = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?]);
- const zir_index: TrackedInst.Index = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "zir_index").?]);
- const fields_len = extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "fields_len").?];
- const flags: Tag.TypeStruct.Flags = @bitCast(@atomicLoad(u32, &extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "flags").?], .unordered));
- var extra_index = item.data + @as(u32, @typeInfo(Tag.TypeStruct).@"struct".fields.len);
- const captures_len = if (flags.any_captures) c: {
- const len = extra_list.view().items(.@"0")[extra_index];
- extra_index += 1;
- break :c len;
- } else 0;
- const captures: CaptureValue.Slice = .{
- .tid = unwrapped_index.tid,
- .start = extra_index,
- .len = captures_len,
- };
- extra_index += captures_len;
- if (flags.is_reified) {
- extra_index += 2; // type_hash: PackedU64
- }
- const field_types: Index.Slice = .{
- .tid = unwrapped_index.tid,
- .start = extra_index,
- .len = fields_len,
- };
- extra_index += fields_len;
- const names_map: OptionalMapIndex, const names = n: {
- const names_map: OptionalMapIndex = @enumFromInt(extra_list.view().items(.@"0")[extra_index]);
- extra_index += 1;
- const names: NullTerminatedString.Slice = .{
- .tid = unwrapped_index.tid,
- .start = extra_index,
- .len = fields_len,
- };
- extra_index += fields_len;
- break :n .{ names_map, names };
- };
- const inits: Index.Slice = if (flags.any_default_inits) i: {
- const inits: Index.Slice = .{
- .tid = unwrapped_index.tid,
- .start = extra_index,
- .len = fields_len,
- };
- extra_index += fields_len;
- break :i inits;
- } else Index.Slice.empty;
- const aligns: Alignment.Slice = if (flags.any_aligned_fields) a: {
- const a: Alignment.Slice = .{
- .tid = unwrapped_index.tid,
- .start = extra_index,
- .len = fields_len,
- };
- extra_index += std.math.divCeil(u32, fields_len, 4) catch unreachable;
- break :a a;
- } else Alignment.Slice.empty;
- const comptime_bits: LoadedStructType.ComptimeBits = if (flags.any_comptime_fields) c: {
- const len = std.math.divCeil(u32, fields_len, 32) catch unreachable;
- const c: LoadedStructType.ComptimeBits = .{
- .tid = unwrapped_index.tid,
- .start = extra_index,
- .len = len,
- };
- extra_index += len;
- break :c c;
- } else LoadedStructType.ComptimeBits.empty;
- const runtime_order: LoadedStructType.RuntimeOrder.Slice = if (!flags.is_extern) ro: {
- const ro: LoadedStructType.RuntimeOrder.Slice = .{
- .tid = unwrapped_index.tid,
- .start = extra_index,
- .len = fields_len,
- };
- extra_index += fields_len;
- break :ro ro;
- } else LoadedStructType.RuntimeOrder.Slice.empty;
- const offsets: LoadedStructType.Offsets = o: {
- const o: LoadedStructType.Offsets = .{
- .tid = unwrapped_index.tid,
- .start = extra_index,
- .len = fields_len,
- };
- extra_index += fields_len;
- break :o o;
- };
- return .{
- .tid = unwrapped_index.tid,
- .extra_index = item.data,
- .name = name,
- .name_nav = name_nav,
- .namespace = namespace,
- .zir_index = zir_index,
- .layout = if (flags.is_extern) .@"extern" else .auto,
- .field_names = names,
- .field_types = field_types,
- .field_inits = inits,
- .field_aligns = aligns,
- .runtime_order = runtime_order,
- .comptime_bits = comptime_bits,
- .offsets = offsets,
- .names_map = names_map,
- .captures = captures,
- };
- },
- .type_struct_packed, .type_struct_packed_inits => {
- const name: NullTerminatedString = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?]);
- const name_nav: Nav.Index.Optional = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "name_nav").?]);
- const zir_index: TrackedInst.Index = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "zir_index").?]);
- const fields_len = extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "fields_len").?];
- const namespace: NamespaceIndex = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?]);
- const names_map: MapIndex = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "names_map").?]);
- const flags: Tag.TypeStructPacked.Flags = @bitCast(@atomicLoad(u32, &extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "flags").?], .unordered));
- var extra_index = item.data + @as(u32, @typeInfo(Tag.TypeStructPacked).@"struct".fields.len);
- const has_inits = item.tag == .type_struct_packed_inits;
- const captures_len = if (flags.any_captures) c: {
- const len = extra_list.view().items(.@"0")[extra_index];
- extra_index += 1;
- break :c len;
- } else 0;
- const captures: CaptureValue.Slice = .{
- .tid = unwrapped_index.tid,
- .start = extra_index,
- .len = captures_len,
- };
- extra_index += captures_len;
- if (flags.is_reified) {
- extra_index += 2; // PackedU64
- }
- const field_types: Index.Slice = .{
- .tid = unwrapped_index.tid,
- .start = extra_index,
- .len = fields_len,
- };
- extra_index += fields_len;
- const field_names: NullTerminatedString.Slice = .{
- .tid = unwrapped_index.tid,
- .start = extra_index,
- .len = fields_len,
- };
- extra_index += fields_len;
- const field_inits: Index.Slice = if (has_inits) inits: {
- const i: Index.Slice = .{
- .tid = unwrapped_index.tid,
- .start = extra_index,
- .len = fields_len,
- };
- extra_index += fields_len;
- break :inits i;
- } else Index.Slice.empty;
- return .{
- .tid = unwrapped_index.tid,
- .extra_index = item.data,
- .name = name,
- .name_nav = name_nav,
- .namespace = namespace,
- .zir_index = zir_index,
- .layout = .@"packed",
- .field_names = field_names,
- .field_types = field_types,
- .field_inits = field_inits,
- .field_aligns = Alignment.Slice.empty,
- .runtime_order = LoadedStructType.RuntimeOrder.Slice.empty,
- .comptime_bits = LoadedStructType.ComptimeBits.empty,
- .offsets = LoadedStructType.Offsets.empty,
- .names_map = names_map.toOptional(),
- .captures = captures,
- };
- },
- else => unreachable,
- }
-}
+/// Unlike `Tag.TypeUnion` which is an encoding, and `Key.UnionType` which is a
+/// minimal hashmap key, this type is a convenience type that contains info
+/// needed by semantic analysis.
+pub const LoadedUnionType = struct {
+ /// Index of the `union_decl` or `reify` ZIR instruction.
+ zir_index: TrackedInst.Index,
+ captures: CaptureValue.Slice,
+ is_reified: bool,
+
+ // TODO: the non-fqn will be needed by the new dwarf structure
+ /// The name of this union type.
+ name: NullTerminatedString,
+ /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after.
+ /// Otherwise, this is `.none`.
+ name_nav: Nav.Index.Optional,
+ namespace: NamespaceIndex,
+
+ layout: std.builtin.Type.ContainerLayout,
+ enum_tag_mode: BackingTypeMode,
+ /// May be `undefined` if `layout != .@"packed"`.
+ packed_backing_mode: BackingTypeMode,
+
+ /// Only reified unions store field names; typically they should be loaded from `enum_tag_type`
+ /// instead. Reified unions store them because type resolution needs them in order to validate
+ /// or populate `enum_tag_type`.
+ reified_field_names: NullTerminatedString.Slice,
+
+ /// Initially `false`, and set to `true` once any dependency on or reference to the struct's
+ /// layout is encountered, after which it is never reset to `false`, even across incremental
+ /// updates.
+ ///
+ /// This field is purely an optimization to avoid resolving the layout of types whose layouts
+ /// are never demanded. If this field is `true` but the layout is not actually needed, the
+ /// compiler frontend resolves this by traversing the reference graph at the end of each update
+ /// with `Zcu.resolveReferences` and hiding compile errors which arise from this analysis.
+ want_layout: bool,
+
+ // The remaining fields are only valid once the union's layout is resolved.
+ field_types: Index.Slice,
+ field_aligns: Alignment.Slice,
+ tag_usage: TagUsage,
+ /// While `tag_usage` indicates whether the union should logically contain a tag, it may be
+ /// omitted if the union layout is resolved as OPV or NPV. This field is `true` iff there is an
+ /// actual runtime tag, with one or more runtime bits, in the union layout. It is always `false`
+ /// if `layout` is not `.auto`.
+ has_runtime_tag: bool,
+ /// Even if `tag_usage == .none` and `has_runtime_tag == false`, this is still populated with
+ /// the union's "hypothetical" tag type.
+ enum_tag_type: Index,
+ /// Only valid if `layout` is `.@"packed"`.
+ packed_backing_int_type: Index,
+ /// Not valid if `layout` is `.@"packed"`.
+ class: TypeClass,
+ /// Not valid if `layout` is `.@"packed"`.
+ size: u32,
+ /// Not valid if `layout` is `.@"packed"`.
+ padding: u32,
+ /// Not valid if `layout` is `.@"packed"`.
+ alignment: Alignment,
+
+ pub const TagUsage = enum(u2) {
+ none,
+ safety,
+ tagged,
+ };
+};
pub const LoadedEnumType = struct {
+ /// This is `none` iff this is a generated tag type.
+ /// Otherwise, index of the `enum_decl` or `reify` ZIR instruction.
+ zir_index: TrackedInst.Index.Optional,
+ captures: CaptureValue.Slice,
+ /// If `zir_index` is `.none`, this is the union type for which this enum is the tag type.
+ owner_union: Index,
+ is_reified: bool,
+
// TODO: the non-fqn will be needed by the new dwarf structure
/// The name of this enum type.
name: NullTerminatedString,
- /// Represents the declarations inside this enum.
- namespace: NamespaceIndex,
/// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after.
/// Otherwise, this is `.none`.
name_nav: Nav.Index.Optional,
- /// An integer type which is used for the numerical value of the enum.
- /// This field is present regardless of whether the enum has an
- /// explicitly provided tag type or auto-numbered.
- tag_ty: Index,
- /// Set of field names in declaration order.
- names: NullTerminatedString.Slice,
- /// Maps integer tag value to field index.
- /// Entries are in declaration order, same as `fields`.
- /// If this is empty, it means the enum tags are auto-numbered.
- values: Index.Slice,
- tag_mode: TagMode,
- names_map: MapIndex,
- /// This is guaranteed to not be `.none` if explicit values are provided.
- values_map: OptionalMapIndex,
- /// This is `none` only if this is a generated tag type.
- zir_index: TrackedInst.Index.Optional,
- captures: CaptureValue.Slice,
+ namespace: NamespaceIndex,
- pub const TagMode = enum {
- /// The integer tag type was auto-numbered by zig.
- auto,
- /// The integer tag type was provided by the enum declaration, and the enum
- /// is exhaustive.
- explicit,
- /// The integer tag type was provided by the enum declaration, and the enum
- /// is non-exhaustive.
- nonexhaustive,
- };
+ int_tag_mode: BackingTypeMode,
+ nonexhaustive: bool,
+
+ /// Initially `false`, and set to `true` once any dependency on or reference to the struct's
+ /// layout is encountered, after which it is never reset to `false`, even across incremental
+ /// updates.
+ ///
+ /// This field is purely an optimization to avoid resolving the layout of types whose layouts
+ /// are never demanded. If this field is `true` but the layout is not actually needed, the
+ /// compiler frontend resolves this by traversing the reference graph at the end of each update
+ /// with `Zcu.resolveReferences` and hiding compile errors which arise from this analysis.
+ want_layout: bool,
+
+ // The remaining fields are only valid once the enum's layout is resolved.
+ int_tag_type: Index,
+ field_name_map: MapIndex,
+ field_names: NullTerminatedString.Slice,
+ field_value_map: OptionalMapIndex,
+ field_values: Index.Slice,
/// Look up field index based on field name.
- pub fn nameIndex(self: LoadedEnumType, ip: *const InternPool, name: NullTerminatedString) ?u32 {
- const map = self.names_map.get(ip);
- const adapter: NullTerminatedString.Adapter = .{ .strings = self.names.get(ip) };
+ pub fn nameIndex(e: LoadedEnumType, ip: *const InternPool, name: NullTerminatedString) ?u32 {
+ const map = e.field_name_map.get(ip);
+ const adapter: NullTerminatedString.Adapter = .{ .strings = e.field_names.get(ip) };
const field_index = map.getIndexAdapted(name, adapter) orelse return null;
return @intCast(field_index);
}
- /// Look up field index based on tag value.
- /// Asserts that `values_map` is not `none`.
- /// This function returns `null` when `tag_val` does not have the
- /// integer tag type of the enum.
- pub fn tagValueIndex(self: LoadedEnumType, ip: *const InternPool, tag_val: Index) ?u32 {
- assert(tag_val != .none);
- // TODO: we should probably decide a single interface for this function, but currently
- // it's being called with both tag values and underlying ints. Fix this!
- const int_tag_val = switch (ip.indexToKey(tag_val)) {
- .enum_tag => |enum_tag| enum_tag.int,
- .int => tag_val,
- else => unreachable,
- };
- if (self.values_map.unwrap()) |values_map| {
- const map = values_map.get(ip);
- const adapter: Index.Adapter = .{ .indexes = self.values.get(ip) };
- const field_index = map.getIndexAdapted(int_tag_val, adapter) orelse return null;
+ /// Look up field index based on integer tag value.
+ /// Asserts that the type of `tag_val` is `enum_obj.int_tag_type`.
+ /// Asserts that `tag_val` is not `undefined`.
+ pub fn tagValueIndex(e: LoadedEnumType, ip: *const InternPool, tag_val: Index) ?u32 {
+ assert(ip.typeOf(tag_val) == e.int_tag_type);
+ assert(ip.indexToKey(tag_val) == .int);
+ if (e.field_value_map.unwrap()) |field_value_map| {
+ const map = field_value_map.get(ip);
+ const adapter: Index.Adapter = .{ .indexes = e.field_values.get(ip) };
+ const field_index = map.getIndexAdapted(tag_val, adapter) orelse return null;
return @intCast(field_index);
}
- // Auto-numbered enum. Convert `int_tag_val` to field index.
- const field_index = switch (ip.indexToKey(int_tag_val).int.storage) {
+ // Auto-numbered enum, so convert `tag_val` to field index
+ const field_index = switch (ip.indexToKey(tag_val).int.storage) {
inline .u64, .i64 => |x| std.math.cast(u32, x) orelse return null,
.big_int => |x| x.toInt(u32) catch return null,
- .lazy_align, .lazy_size => unreachable,
};
- return if (field_index < self.names.len) field_index else null;
+ return if (field_index < e.field_names.len) field_index else null;
}
};
-pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType {
- const unwrapped_index = index.unwrap(ip);
- const extra_list = unwrapped_index.getExtra(ip);
- const item = unwrapped_index.getItem(ip);
- const tag_mode: LoadedEnumType.TagMode = switch (item.tag) {
- .type_enum_auto => {
- const extra = extraDataTrail(extra_list, EnumAuto, item.data);
- var extra_index: u32 = @intCast(extra.end);
- if (extra.data.zir_index == .none) {
- extra_index += 1; // owner_union
- }
- const captures_len = if (extra.data.captures_len == std.math.maxInt(u32)) c: {
- extra_index += 2; // type_hash: PackedU64
- break :c 0;
- } else extra.data.captures_len;
- return .{
- .name = extra.data.name,
- .name_nav = extra.data.name_nav,
- .namespace = extra.data.namespace,
- .tag_ty = extra.data.int_tag_type,
- .names = .{
- .tid = unwrapped_index.tid,
- .start = extra_index + captures_len,
- .len = extra.data.fields_len,
- },
- .values = Index.Slice.empty,
- .tag_mode = .auto,
- .names_map = extra.data.names_map,
- .values_map = .none,
- .zir_index = extra.data.zir_index,
- .captures = .{
- .tid = unwrapped_index.tid,
- .start = extra_index,
- .len = captures_len,
- },
- };
- },
- .type_enum_explicit => .explicit,
- .type_enum_nonexhaustive => .nonexhaustive,
- else => unreachable,
- };
- const extra = extraDataTrail(extra_list, EnumExplicit, item.data);
- var extra_index: u32 = @intCast(extra.end);
- if (extra.data.zir_index == .none) {
- extra_index += 1; // owner_union
- }
- const captures_len = if (extra.data.captures_len == std.math.maxInt(u32)) c: {
- extra_index += 2; // type_hash: PackedU64
- break :c 0;
- } else extra.data.captures_len;
- return .{
- .name = extra.data.name,
- .name_nav = extra.data.name_nav,
- .namespace = extra.data.namespace,
- .tag_ty = extra.data.int_tag_type,
- .names = .{
- .tid = unwrapped_index.tid,
- .start = extra_index + captures_len,
- .len = extra.data.fields_len,
- },
- .values = .{
- .tid = unwrapped_index.tid,
- .start = extra_index + captures_len + extra.data.fields_len,
- .len = if (extra.data.values_map != .none) extra.data.fields_len else 0,
- },
- .tag_mode = tag_mode,
- .names_map = extra.data.names_map,
- .values_map = extra.data.values_map,
- .zir_index = extra.data.zir_index,
- .captures = .{
- .tid = unwrapped_index.tid,
- .start = extra_index,
- .len = captures_len,
- },
- };
-}
-
-/// Note that this type doubles as the payload for `Tag.type_opaque`.
pub const LoadedOpaqueType = struct {
- /// Contains the declarations inside this opaque.
- namespace: NamespaceIndex,
+ /// Index of the `opaque_decl` instruction.
+ zir_index: TrackedInst.Index,
+ captures: CaptureValue.Slice,
+
// TODO: the non-fqn will be needed by the new dwarf structure
/// The name of this opaque type.
name: NullTerminatedString,
/// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after.
/// Otherwise, this is `.none`.
name_nav: Nav.Index.Optional,
- /// Index of the `opaque_decl` or `reify` instruction.
- zir_index: TrackedInst.Index,
- captures: CaptureValue.Slice,
+ namespace: NamespaceIndex,
};
+pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
+ const unwrapped_index = index.unwrap(ip);
+ const extra_list = unwrapped_index.getExtra(ip);
+ const extra_items = extra_list.view().items(.@"0");
+ const item = unwrapped_index.getItem(ip);
+ // Exiting this `switch` means this is a `packed struct`.
+ const backing_mode: BackingTypeMode, const any_defaults: bool = switch (item.tag) {
+ .type_struct_packed_auto => .{ .auto, false },
+ .type_struct_packed_explicit => .{ .explicit, false },
+ .type_struct_packed_auto_defaults => .{ .auto, true },
+ .type_struct_packed_explicit_defaults => .{ .explicit, true },
+ .type_struct => {
+ const extra = extraDataTrail(extra_list, Tag.TypeStruct, item.data);
+ var extra_index = extra.end;
+ const captures: CaptureValue.Slice = switch (extra.data.flags.any_captures) {
+ .reified => captures: {
+ extra_index += 2; // type_hash: PackedU64
+ break :captures .empty;
+ },
+ .false => .empty,
+ .true => captures: {
+ const len = extra_items[extra_index];
+ extra_index += 1;
+ break :captures .{
+ .tid = unwrapped_index.tid,
+ .start = extra_index,
+ .len = len,
+ };
+ },
+ };
+ extra_index += captures.len;
+ const field_names: NullTerminatedString.Slice = .{
+ .tid = unwrapped_index.tid,
+ .start = extra_index,
+ .len = extra.data.fields_len,
+ };
+ extra_index += field_names.len;
+ const field_types: Index.Slice = .{
+ .tid = unwrapped_index.tid,
+ .start = extra_index,
+ .len = extra.data.fields_len,
+ };
+ extra_index += field_types.len;
+ const field_defaults: Index.Slice = if (extra.data.flags.any_field_defaults) .{
+ .tid = unwrapped_index.tid,
+ .start = extra_index,
+ .len = extra.data.fields_len,
+ } else .empty;
+ extra_index += field_defaults.len;
+ const field_aligns: Alignment.Slice = if (extra.data.flags.any_field_aligns) .{
+ .tid = unwrapped_index.tid,
+ .start = extra_index,
+ .len = extra.data.fields_len,
+ } else .empty;
+ extra_index += std.math.divCeil(u32, field_aligns.len, 4) catch unreachable;
+ const field_is_comptime_bits: LoadedStructType.ComptimeBits = if (extra.data.flags.any_comptime_fields) .{
+ .tid = unwrapped_index.tid,
+ .start = extra_index,
+ .len = std.math.divCeil(u32, extra.data.fields_len, 32) catch unreachable,
+ } else .empty;
+ extra_index += field_is_comptime_bits.len;
+ const field_runtime_order: LoadedStructType.RuntimeOrder.Slice = if (extra.data.flags.layout == .auto) .{
+ .tid = unwrapped_index.tid,
+ .start = extra_index,
+ .len = extra.data.fields_len,
+ } else .empty;
+ extra_index += field_runtime_order.len;
+ const field_offsets: LoadedStructType.Offsets = .{
+ .tid = unwrapped_index.tid,
+ .start = extra_index,
+ .len = extra.data.fields_len,
+ };
+ extra_index += field_offsets.len;
+
+ return .{
+ .zir_index = extra.data.zir_index,
+ .captures = captures,
+ .is_reified = extra.data.flags.any_captures == .reified,
+ .name = extra.data.name,
+ .name_nav = extra.data.name_nav,
+ .namespace = extra.data.namespace,
+ .layout = switch (extra.data.flags.layout) {
+ .auto => .auto,
+ .@"extern" => .@"extern",
+ },
+ .packed_backing_mode = undefined,
+
+ .want_layout = extra.data.flags.want_layout,
+
+ .field_name_map = extra.data.field_name_map,
+ .field_names = field_names,
+ .field_types = field_types,
+ .field_defaults = field_defaults,
+ .field_aligns = field_aligns,
+ .field_is_comptime_bits = field_is_comptime_bits,
+ .field_runtime_order = field_runtime_order,
+ .field_offsets = field_offsets,
+ .packed_backing_int_type = .none,
+ .class = extra.data.flags.class,
+ .size = extra.data.size,
+ .alignment = extra.data.flags.alignment,
+ };
+ },
+ else => unreachable,
+ };
+ const extra = extraDataTrail(extra_list, Tag.TypeStructPacked, item.data);
+ var extra_index = extra.end;
+ const captures: CaptureValue.Slice = switch (extra.data.bits.captures_len) {
+ .reified => captures: {
+ extra_index += 2; // type_hash: PackedU64
+ break :captures .empty;
+ },
+ _ => |n| .{
+ .tid = unwrapped_index.tid,
+ .start = extra_index,
+ .len = @intFromEnum(n),
+ },
+ };
+ extra_index += captures.len;
+ const field_names: NullTerminatedString.Slice = .{
+ .tid = unwrapped_index.tid,
+ .start = extra_index,
+ .len = extra.data.fields_len,
+ };
+ extra_index += field_names.len;
+ const field_types: Index.Slice = .{
+ .tid = unwrapped_index.tid,
+ .start = extra_index,
+ .len = extra.data.fields_len,
+ };
+ extra_index += field_types.len;
+ const field_defaults: Index.Slice = if (any_defaults) .{
+ .tid = unwrapped_index.tid,
+ .start = extra_index,
+ .len = extra.data.fields_len,
+ } else .empty;
+ extra_index += field_defaults.len;
+ return .{
+ .zir_index = extra.data.zir_index,
+ .captures = captures,
+ .is_reified = extra.data.bits.captures_len == .reified,
+ .name = extra.data.name,
+ .name_nav = extra.data.name_nav,
+ .namespace = extra.data.namespace,
+ .layout = .@"packed",
+ .packed_backing_mode = backing_mode,
+
+ .want_layout = extra.data.bits.want_layout,
+
+ .field_name_map = extra.data.field_name_map,
+ .field_names = field_names,
+ .field_types = field_types,
+ .field_defaults = field_defaults,
+ .field_aligns = .empty,
+ .field_is_comptime_bits = .empty,
+ .field_runtime_order = .empty,
+ .field_offsets = .empty,
+ .packed_backing_int_type = extra.data.backing_int_type,
+ .class = undefined,
+ .size = undefined,
+ .alignment = undefined,
+ };
+}
+
+pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
+ const unwrapped_index = index.unwrap(ip);
+ const extra_list = unwrapped_index.getExtra(ip);
+ const extra_items = extra_list.view().items(.@"0");
+ const item = unwrapped_index.getItem(ip);
+ // Exiting this `switch` means this is a `packed union`.
+ const backing_mode: BackingTypeMode = switch (item.tag) {
+ .type_union_packed_auto => .auto,
+ .type_union_packed_explicit => .explicit,
+ .type_union => {
+ const extra = extraDataTrail(extra_list, Tag.TypeUnion, item.data);
+ var extra_index = extra.end;
+ const captures: CaptureValue.Slice = switch (extra.data.flags.any_captures) {
+ .reified => captures: {
+ extra_index += 2; // type_hash: PackedU64
+ break :captures .empty;
+ },
+ .false => .empty,
+ .true => captures: {
+ const len = extra_items[extra_index];
+ extra_index += 1;
+ break :captures .{
+ .tid = unwrapped_index.tid,
+ .start = extra_index,
+ .len = len,
+ };
+ },
+ };
+ extra_index += captures.len;
+ const reified_field_names: NullTerminatedString.Slice = if (extra.data.flags.any_captures == .reified) .{
+ .tid = unwrapped_index.tid,
+ .start = extra_index,
+ .len = extra.data.fields_len,
+ } else .empty;
+ extra_index += reified_field_names.len;
+ const field_types: Index.Slice = .{
+ .tid = unwrapped_index.tid,
+ .start = extra_index,
+ .len = extra.data.fields_len,
+ };
+ extra_index += field_types.len;
+ const field_aligns: Alignment.Slice = if (extra.data.flags.any_field_aligns) .{
+ .tid = unwrapped_index.tid,
+ .start = extra_index,
+ .len = extra.data.fields_len,
+ } else .empty;
+ extra_index += std.math.divCeil(u32, field_aligns.len, 4) catch unreachable;
+
+ return .{
+ .zir_index = extra.data.zir_index,
+ .captures = captures,
+ .is_reified = extra.data.flags.any_captures == .reified,
+ .name = extra.data.name,
+ .name_nav = extra.data.name_nav,
+ .namespace = extra.data.namespace,
+ .layout = switch (extra.data.flags.layout) {
+ .auto => .auto,
+ .@"extern" => .@"extern",
+ },
+ .tag_usage = extra.data.flags.tag_usage,
+ .enum_tag_mode = extra.data.flags.enum_tag_mode,
+ .enum_tag_type = extra.data.enum_tag_type,
+ .packed_backing_mode = undefined,
+ .packed_backing_int_type = undefined,
+ .reified_field_names = reified_field_names,
+ .want_layout = extra.data.flags.want_layout,
+ .field_types = field_types,
+ .field_aligns = field_aligns,
+ .has_runtime_tag = extra.data.flags.has_runtime_tag,
+ .class = extra.data.flags.class,
+ .size = extra.data.size,
+ .padding = extra.data.padding,
+ .alignment = extra.data.flags.alignment,
+ };
+ },
+ else => unreachable,
+ };
+ const extra = extraDataTrail(extra_list, Tag.TypeUnionPacked, item.data);
+ var extra_index = extra.end;
+ const captures: CaptureValue.Slice = switch (extra.data.bits.captures_len) {
+ .reified => captures: {
+ extra_index += 2; // type_hash: PackedU64
+ break :captures .empty;
+ },
+ _ => |n| .{
+ .tid = unwrapped_index.tid,
+ .start = extra_index,
+ .len = @intFromEnum(n),
+ },
+ };
+ extra_index += captures.len;
+ const reified_field_names: NullTerminatedString.Slice = if (extra.data.bits.captures_len == .reified) .{
+ .tid = unwrapped_index.tid,
+ .start = extra_index,
+ .len = extra.data.fields_len,
+ } else .empty;
+ extra_index += reified_field_names.len;
+ const field_types: Index.Slice = .{
+ .tid = unwrapped_index.tid,
+ .start = extra_index,
+ .len = extra.data.fields_len,
+ };
+ extra_index += field_types.len;
+ return .{
+ .zir_index = extra.data.zir_index,
+ .captures = captures,
+ .is_reified = extra.data.bits.captures_len == .reified,
+ .name = extra.data.name,
+ .name_nav = extra.data.name_nav,
+ .namespace = extra.data.namespace,
+ .layout = .@"packed",
+ .tag_usage = .none,
+ .enum_tag_mode = .auto,
+ .enum_tag_type = extra.data.enum_tag_type,
+ .packed_backing_mode = backing_mode,
+ .packed_backing_int_type = extra.data.backing_int_type,
+ .reified_field_names = reified_field_names,
+ .want_layout = extra.data.bits.want_layout,
+ .field_types = field_types,
+ .field_aligns = .empty,
+ .has_runtime_tag = false,
+ .class = undefined,
+ .size = undefined,
+ .padding = undefined,
+ .alignment = undefined,
+ };
+}
+
+pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType {
+ const unwrapped_index = index.unwrap(ip);
+ const extra_list = unwrapped_index.getExtra(ip);
+ const extra_items = extra_list.view().items(.@"0");
+ const item = unwrapped_index.getItem(ip);
+ const explicit_int_tag: bool, const nonexhaustive: bool = switch (item.tag) {
+ .type_enum_auto => .{ false, false },
+ .type_enum_explicit => .{ true, false },
+ .type_enum_nonexhaustive => .{ true, true },
+ else => unreachable,
+ };
+ const extra = extraDataTrail(extra_list, Tag.TypeEnum, item.data);
+ var extra_index: u32 = @intCast(extra.end);
+ const zir_index: TrackedInst.Index.Optional, const captures: CaptureValue.Slice, const owner_union: Index = switch (extra.data.bits.captures_len) {
+ .reified => info: {
+ const zir_index: TrackedInst.Index = @enumFromInt(extra_items[extra_index]);
+ extra_index += 1;
+ extra_index += 2; // type_hash: PackedU64
+ break :info .{ zir_index.toOptional(), .empty, .none };
+ },
+ .generated_union_tag => info: {
+ const owner_union: Index = @enumFromInt(extra_items[extra_index]);
+ extra_index += 1;
+ break :info .{ .none, .empty, owner_union };
+ },
+ _ => |n| info: {
+ const zir_index: TrackedInst.Index = @enumFromInt(extra_items[extra_index]);
+ extra_index += 1;
+ const captures: CaptureValue.Slice = .{
+ .tid = unwrapped_index.tid,
+ .start = extra_index,
+ .len = @intFromEnum(n),
+ };
+ extra_index += captures.len;
+ break :info .{ zir_index.toOptional(), captures, .none };
+ },
+ };
+ const field_value_map: OptionalMapIndex = if (explicit_int_tag) m: {
+ const map: MapIndex = @enumFromInt(extra_items[extra_index]);
+ extra_index += 1;
+ break :m map.toOptional();
+ } else .none;
+ const field_names: NullTerminatedString.Slice = .{
+ .tid = unwrapped_index.tid,
+ .start = extra_index,
+ .len = extra.data.fields_len,
+ };
+ extra_index += field_names.len;
+ const field_values: Index.Slice = if (explicit_int_tag) .{
+ .tid = unwrapped_index.tid,
+ .start = extra_index,
+ .len = extra.data.fields_len,
+ } else .empty;
+ extra_index += field_values.len;
+ return .{
+ .zir_index = zir_index,
+ .captures = captures,
+ .is_reified = extra.data.bits.captures_len == .reified,
+ .owner_union = owner_union,
+ .name = extra.data.name,
+ .name_nav = extra.data.name_nav,
+ .namespace = extra.data.namespace,
+ .int_tag_type = extra.data.int_tag_type,
+ .int_tag_mode = if (explicit_int_tag) .explicit else .auto,
+ .nonexhaustive = nonexhaustive,
+ .want_layout = extra.data.bits.want_layout,
+ .field_name_map = extra.data.field_name_map,
+ .field_value_map = field_value_map,
+ .field_names = field_names,
+ .field_values = field_values,
+ };
+}
+
pub fn loadOpaqueType(ip: *const InternPool, index: Index) LoadedOpaqueType {
const unwrapped_index = index.unwrap(ip);
const item = unwrapped_index.getItem(ip);
assert(item.tag == .type_opaque);
const extra = extraDataTrail(unwrapped_index.getExtra(ip), Tag.TypeOpaque, item.data);
- const captures_len = if (extra.data.captures_len == std.math.maxInt(u32))
- 0
- else
- extra.data.captures_len;
return .{
- .name = extra.data.name,
- .name_nav = extra.data.name_nav,
- .namespace = extra.data.namespace,
.zir_index = extra.data.zir_index,
.captures = .{
.tid = unwrapped_index.tid,
.start = extra.end,
- .len = captures_len,
+ .len = extra.data.captures_len,
},
+ .name = extra.data.name,
+ .name_nav = extra.data.name_nav,
+ .namespace = extra.data.namespace,
};
}
@@ -4816,6 +4210,13 @@ pub const Index = enum(u32) {
const extra = ip.getLocalShared(slice.tid).extra.acquire();
return @ptrCast(extra.view().items(.@"0")[slice.start..][0..slice.len]);
}
+
+ /// If `slice` is empty (`slice.len == 0`), returns `.none`.
+ /// Otherwise, asserts that `index < slice.len`, and returns the value at `index`.
+ pub fn getOrNone(slice: Slice, ip: *const InternPool, index: usize) Index {
+ if (slice.len == 0) return .none;
+ return slice.get(ip)[index];
+ }
};
/// Used for a map of `Index` values to the index within a list of `Index` values.
@@ -4891,26 +4292,6 @@ pub const Index = enum(u32) {
/// Tag to encoding mapping to facilitate fancy debug printing for this type.
fn dbHelper(self: *Index, tag_to_encoding_map: *struct {
const DataIsIndex = struct { data: Index };
- const DataIsExtraIndexOfEnumExplicit = struct {
- const @"data.fields_len" = opaque {};
- data: *EnumExplicit,
- @"trailing.names.len": *@"data.fields_len",
- @"trailing.values.len": *@"data.fields_len",
- trailing: struct {
- names: []NullTerminatedString,
- values: []Index,
- },
- };
- const DataIsExtraIndexOfTypeTuple = struct {
- const @"data.fields_len" = opaque {};
- data: *TypeTuple,
- @"trailing.types.len": *@"data.fields_len",
- @"trailing.values.len": *@"data.fields_len",
- trailing: struct {
- types: []Index,
- values: []Index,
- },
- };
removed: void,
type_int_signed: struct { data: u32 },
@@ -4931,21 +4312,7 @@ pub const Index = enum(u32) {
trailing: struct { names: []NullTerminatedString },
},
type_inferred_error_set: DataIsIndex,
- type_enum_auto: struct {
- const @"data.fields_len" = opaque {};
- data: *EnumAuto,
- @"trailing.names.len": *@"data.fields_len",
- trailing: struct { names: []NullTerminatedString },
- },
- type_enum_explicit: DataIsExtraIndexOfEnumExplicit,
- type_enum_nonexhaustive: DataIsExtraIndexOfEnumExplicit,
simple_type: void,
- type_opaque: struct { data: *Tag.TypeOpaque },
- type_struct: struct { data: *Tag.TypeStruct },
- type_struct_packed: struct { data: *Tag.TypeStructPacked },
- type_struct_packed_inits: struct { data: *Tag.TypeStructPacked },
- type_tuple: DataIsExtraIndexOfTypeTuple,
- type_union: struct { data: *Tag.TypeUnion },
type_function: struct {
const @"data.flags.has_comptime_bits" = opaque {};
const @"data.flags.has_noalias_bits" = opaque {};
@@ -4956,6 +4323,29 @@ pub const Index = enum(u32) {
@"trailing.param_types.len": *@"data.params_len",
trailing: struct { comptime_bits: []u32, noalias_bits: []u32, param_types: []Index },
},
+ type_tuple: struct {
+ const @"data.fields_len" = opaque {};
+ data: *TypeTuple,
+ @"trailing.types.len": *@"data.fields_len",
+ @"trailing.values.len": *@"data.fields_len",
+ trailing: struct {
+ types: []Index,
+ values: []Index,
+ },
+ },
+
+ type_struct: struct { data: *Tag.TypeStruct },
+ type_struct_packed_auto: struct { data: *Tag.TypeStructPacked },
+ type_struct_packed_explicit: struct { data: *Tag.TypeStructPacked },
+ type_struct_packed_auto_defaults: struct { data: *Tag.TypeStructPacked },
+ type_struct_packed_explicit_defaults: struct { data: *Tag.TypeStructPacked },
+ type_union: struct { data: *Tag.TypeUnion },
+ type_union_packed_auto: struct { data: *Tag.TypeUnionPacked },
+ type_union_packed_explicit: struct { data: *Tag.TypeUnionPacked },
+ type_enum_auto: struct { data: *Tag.TypeEnum },
+ type_enum_explicit: struct { data: *Tag.TypeEnum },
+ type_enum_nonexhaustive: struct { data: *Tag.TypeEnum },
+ type_opaque: struct { data: *Tag.TypeOpaque },
undef: DataIsIndex,
simple_value: void,
@@ -4982,8 +4372,6 @@ pub const Index = enum(u32) {
int_small: struct { data: *IntSmall },
int_positive: struct { data: u32 },
int_negative: struct { data: u32 },
- int_lazy_align: struct { data: *IntLazy },
- int_lazy_size: struct { data: *IntLazy },
error_set_error: struct { data: *Key.Error },
error_union_error: struct { data: *Key.Error },
error_union_payload: struct { data: *Tag.TypeValue },
@@ -5027,6 +4415,7 @@ pub const Index = enum(u32) {
trailing: struct { element_values: []Index },
},
repeated: struct { data: *Repeated },
+ bitpack: struct { data: *Key.Bitpack },
memoized_call: struct {
const @"data.args_len" = opaque {};
@@ -5037,7 +4426,7 @@ pub const Index = enum(u32) {
}) void {
_ = self;
const map_fields = @typeInfo(@typeInfo(@TypeOf(tag_to_encoding_map)).pointer.child).@"struct".fields;
- @setEvalBranchQuota(2_000);
+ @setEvalBranchQuota(3_000);
inline for (@typeInfo(Tag).@"enum".fields, 0..) |tag, start| {
inline for (0..map_fields.len) |offset| {
if (comptime std.mem.eql(u8, tag.name, map_fields[(start + offset) % map_fields.len].name)) break;
@@ -5409,7 +4798,7 @@ pub const static_keys: [static_len]Key = .{
.values = .empty,
} },
- .{ .simple_value = .undefined },
+ .{ .undef = .undefined_type },
.{ .undef = .bool_type },
.{ .undef = .usize_type },
.{ .undef = .u1_type },
@@ -5469,7 +4858,11 @@ pub const static_keys: [static_len]Key = .{
.{ .simple_value = .null },
.{ .simple_value = .true },
.{ .simple_value = .false },
- .{ .simple_value = .empty_tuple },
+
+ .{ .aggregate = .{
+ .ty = .empty_tuple_type,
+ .storage = .{ .elems = &.{} },
+ } },
};
/// How many items in the InternPool are statically known.
@@ -5485,6 +4878,8 @@ pub const Tag = enum(u8) {
/// assert not this tag. `data` is unused.
removed,
+ /// A type that can be represented with only an enum tag.
+ simple_type,
/// An integer type.
/// data is number of bits
type_int_signed,
@@ -5524,41 +4919,68 @@ pub const Tag = enum(u8) {
/// The inferred error set type of a function.
/// data is `Index` of a `func_decl` or `func_instance`.
type_inferred_error_set,
- /// An enum type with auto-numbered tag values.
- /// The enum is exhaustive.
- /// data is payload index to `EnumAuto`.
+ /// A function body type.
+ /// `data` is extra index to `TypeFunction`.
+ type_function,
+ /// A `TupleType`.
+ /// data is extra index of `TypeTuple`.
+ type_tuple,
+
+ /// A non-packed struct type.
+ /// data is extra index of `TypeStruct`.
+ type_struct,
+ /// `packed struct { ... }` with no default field values.
+ /// data is extra index of `TypeStructPacked`.
+ type_struct_packed_auto,
+ /// `packed struct(T) { ... }` with no default field values.
+ /// data is extra index of `TypeStructPacked`.
+ type_struct_packed_explicit,
+ /// `packed struct { ... }` with one or more default field values.
+ /// data is extra index of `TypeStructPacked`.
+ type_struct_packed_auto_defaults,
+ /// `packed struct(T) { ... }` with one or more default field values.
+ /// data is extra index of `TypeStructPacked`.
+ type_struct_packed_explicit_defaults,
+
+ /// A non-packed union type.
+ /// data is extra index of `TypeUnion`.
+ type_union,
+ /// `packed union { ... }`.
+ /// data is extra index of `TypeUnionPacked`.
+ type_union_packed_auto,
+ /// `packed union(T) { ... }`.
+ /// data is extra index of `TypeUnionPacked`.
+ type_union_packed_explicit,
+
+ /// An exhaustive enum type *without* an explicit integer tag type. The tag type is inferred.
+ ///
+ /// Because the tag type is inferred, there are no explicit field values.
+ ///
+ /// May be the generated tag type for a `union(enum)`.
+ ///
+ /// data is extra index of `TypeEnum`.
type_enum_auto,
- /// An enum type with an explicitly provided integer tag type.
- /// The enum is exhaustive.
- /// data is payload index to `EnumExplicit`.
+ /// An exhaustive enum type *with* an explicit integer tag type.
+ ///
+ /// May have explicit field values.
+ ///
+ /// May be the generated tag type for a `union(enum(T))`.
+ ///
+ /// data is extra index of `TypeEnum`.
type_enum_explicit,
- /// An enum type with an explicitly provided integer tag type.
- /// The enum is non-exhaustive.
- /// data is payload index to `EnumExplicit`.
+ /// An non-exhaustive enum type (with an explicit integer tag type, since it is required for
+ /// non-exhaustive enums).
+ ///
+ /// May have explicit field values.
+ ///
+ /// This is *not* a union's generated tag type, because such types are always exhaustive.
+ ///
+ /// data is extra index of `TypeEnum`.
type_enum_nonexhaustive,
- /// A type that can be represented with only an enum tag.
- simple_type,
+
/// An opaque type.
- /// data is index of Tag.TypeOpaque in extra.
+ /// data is extra index of `TypeOpaque`.
type_opaque,
- /// A non-packed struct type.
- /// data is 0 or extra index of `TypeStruct`.
- type_struct,
- /// A packed struct, no fields have any init values.
- /// data is extra index of `TypeStructPacked`.
- type_struct_packed,
- /// A packed struct, one or more fields have init values.
- /// data is extra index of `TypeStructPacked`.
- type_struct_packed_inits,
- /// A `TupleType`.
- /// data is extra index of `TypeTuple`.
- type_tuple,
- /// A union type.
- /// `data` is extra index of `TypeUnion`.
- type_union,
- /// A function body type.
- /// `data` is extra index to `TypeFunction`.
- type_function,
/// Typed `undefined`.
/// `data` is `Index` of the type.
@@ -5644,12 +5066,6 @@ pub const Tag = enum(u8) {
/// A negative integer value.
/// data is a limbs index to `Int`.
int_negative,
- /// The ABI alignment of a lazy type.
- /// data is extra index of `IntLazy`.
- int_lazy_align,
- /// The ABI size of a lazy type.
- /// data is extra index of `IntLazy`.
- int_lazy_size,
/// An error value.
/// data is extra index of `Key.Error`.
error_set_error,
@@ -5735,6 +5151,9 @@ pub const Tag = enum(u8) {
/// An instance of an array or vector with every element being the same value.
/// data is extra index to `Repeated`.
repeated,
+ /// An instance of a `packed struct` or `packed union`.
+ /// data is extra index to `Key.Bitpack`.
+ bitpack,
/// A memoized comptime function call result.
/// data is extra index to `MemoizedCall`
@@ -5747,24 +5166,77 @@ pub const Tag = enum(u8) {
const Union = Key.Union;
const TypePointer = Key.PtrType;
+ const struct_packed_encoding = .{
+ .summary = .@"{.payload.name%summary#\"}",
+ .payload = TypeStructPacked,
+ .trailing = struct {
+ type_hash: ?u64,
+ captures: ?[]CaptureValue,
+ field_names: []NullTerminatedString,
+ field_types: []Index,
+ },
+ .config = .{
+ .@"trailing.type_hash.?" = .@"payload.captures_len == .reified",
+ .@"trailing.captures.?" = .@"payload.captures_len != .reified",
+ .@"trailing.captures.?.len" = .@"@intFromEnum(payload.captures_len)",
+ .@"trailing.field_names.len" = .@"payload.fields_len",
+ .@"trailing.field_types.len" = .@"payload.fields_len",
+ },
+ };
+ const struct_packed_defaults_encoding = .{
+ .summary = .@"{.payload.name%summary#\"}",
+ .payload = TypeStructPacked,
+ .trailing = struct {
+ type_hash: ?u64,
+ captures: ?[]CaptureValue,
+ field_names: []NullTerminatedString,
+ field_types: []Index,
+ field_defaults: []Index,
+ },
+ .config = .{
+ .@"trailing.type_hash.?" = .@"payload.captures_len == .reified",
+ .@"trailing.captures.?" = .@"payload.captures_len != .reified",
+ .@"trailing.captures.?.len" = .@"@intFromEnum(payload.captures_len)",
+ .@"trailing.field_names.len" = .@"payload.fields_len",
+ .@"trailing.field_types.len" = .@"payload.fields_len",
+ .@"trailing.field_defaults.len" = .@"payload.fields_len",
+ },
+ };
+ const union_packed_encoding = .{
+ .summary = .@"{.payload.name%summary#\"}",
+ .payload = TypeUnionPacked,
+ .trailing = struct {
+ type_hash: ?u64,
+ captures: ?[]CaptureValue,
+ field_types: []Index,
+ },
+ .config = .{
+ .@"trailing.type_hash.?" = .@"payload.captures_len == .reified",
+ .@"trailing.captures.?" = .@"payload.captures_len != .reified",
+ .@"trailing.captures.?.len" = .@"@intFromEnum(payload.captures_len)",
+ .@"trailing.field_types.len" = .@"payload.fields_len",
+ },
+ };
const enum_explicit_encoding = .{
.summary = .@"{.payload.name%summary#\"}",
- .payload = EnumExplicit,
+ .payload = TypeEnum,
.trailing = struct {
- owner_union: Index,
- captures: ?[]CaptureValue,
+ owner_union: ?Index,
+ zir_index: ?TrackedInst.Index,
type_hash: ?u64,
+ captures: ?[]CaptureValue,
+ field_value_map: MapIndex,
field_names: []NullTerminatedString,
- tag_values: []Index,
+ field_values: []Index,
},
.config = .{
- .@"trailing.owner_union.?" = .@"payload.zir_index == .none",
- .@"trailing.cau.?" = .@"payload.zir_index != .none",
- .@"trailing.captures.?" = .@"payload.captures_len < 0xffffffff",
- .@"trailing.captures.?.len" = .@"payload.captures_len",
- .@"trailing.type_hash.?" = .@"payload.captures_len == 0xffffffff",
+ .@"trailing.owner_union.?" = .@"payload.captures_len == .generated_union_tag",
+ .@"trailing.zir_index.?" = .@"payload.captures_len != .generated_union_tag",
+ .@"trailing.type_hash.?" = .@"payload.captures_len == .reified",
+ .@"trailing.captures.?" = .@"payload.captures_len != .reified and payload.captures_len != .generated_enum_tag",
+ .@"trailing.captures.?.len" = .@"@intFromEnum(payload.captures_len)",
.@"trailing.field_names.len" = .@"payload.fields_len",
- .@"trailing.tag_values.len" = .@"payload.fields_len",
+ .@"trailing.field_values.len" = .@"payload.fields_len",
},
};
const encodings = .{
@@ -5792,107 +5264,7 @@ pub const Tag = enum(u8) {
.summary = .@"@typeInfo(@typeInfo(@TypeOf({.data%summary})).@\"fn\".return_type.?).error_union.error_set",
.data = Index,
},
- .type_enum_auto = .{
- .summary = .@"{.payload.name%summary#\"}",
- .payload = EnumAuto,
- .trailing = struct {
- owner_union: ?Index,
- captures: ?[]CaptureValue,
- type_hash: ?u64,
- field_names: []NullTerminatedString,
- },
- .config = .{
- .@"trailing.owner_union.?" = .@"payload.zir_index == .none",
- .@"trailing.cau.?" = .@"payload.zir_index != .none",
- .@"trailing.captures.?" = .@"payload.captures_len < 0xffffffff",
- .@"trailing.captures.?.len" = .@"payload.captures_len",
- .@"trailing.type_hash.?" = .@"payload.captures_len == 0xffffffff",
- .@"trailing.field_names.len" = .@"payload.fields_len",
- },
- },
- .type_enum_explicit = enum_explicit_encoding,
- .type_enum_nonexhaustive = enum_explicit_encoding,
.simple_type = .{ .summary = .@"{.index%value#.}", .index = SimpleType },
- .type_opaque = .{
- .summary = .@"{.payload.name%summary#\"}",
- .payload = TypeOpaque,
- .trailing = struct { captures: []CaptureValue },
- .config = .{ .@"trailing.captures.len" = .@"payload.captures_len" },
- },
- .type_struct = .{
- .summary = .@"{.payload.name%summary#\"}",
- .payload = TypeStruct,
- .trailing = struct {
- captures_len: ?u32,
- captures: ?[]CaptureValue,
- type_hash: ?u64,
- field_types: []Index,
- field_names_map: OptionalMapIndex,
- field_names: []NullTerminatedString,
- field_inits: ?[]Index,
- field_aligns: ?[]Alignment,
- field_is_comptime_bits: ?[]u32,
- field_index: ?[]LoadedStructType.RuntimeOrder,
- field_offset: []u32,
- },
- .config = .{
- .@"trailing.captures_len.?" = .@"payload.flags.any_captures",
- .@"trailing.captures.?" = .@"payload.flags.any_captures",
- .@"trailing.captures.?.len" = .@"trailing.captures_len.?",
- .@"trailing.type_hash.?" = .@"payload.flags.is_reified",
- .@"trailing.field_types.len" = .@"payload.fields_len",
- .@"trailing.field_names.len" = .@"payload.fields_len",
- .@"trailing.field_inits.?" = .@"payload.flags.any_default_inits",
- .@"trailing.field_inits.?.len" = .@"payload.fields_len",
- .@"trailing.field_aligns.?" = .@"payload.flags.any_aligned_fields",
- .@"trailing.field_aligns.?.len" = .@"payload.fields_len",
- .@"trailing.field_is_comptime_bits.?" = .@"payload.flags.any_comptime_fields",
- .@"trailing.field_is_comptime_bits.?.len" = .@"(payload.fields_len + 31) / 32",
- .@"trailing.field_index.?" = .@"!payload.flags.is_extern",
- .@"trailing.field_index.?.len" = .@"payload.fields_len",
- .@"trailing.field_offset.len" = .@"payload.fields_len",
- },
- },
- .type_struct_packed = .{
- .summary = .@"{.payload.name%summary#\"}",
- .payload = TypeStructPacked,
- .trailing = struct {
- captures_len: ?u32,
- captures: ?[]CaptureValue,
- type_hash: ?u64,
- field_types: []Index,
- field_names: []NullTerminatedString,
- },
- .config = .{
- .@"trailing.captures_len.?" = .@"payload.flags.any_captures",
- .@"trailing.captures.?" = .@"payload.flags.any_captures",
- .@"trailing.captures.?.len" = .@"trailing.captures_len.?",
- .@"trailing.type_hash.?" = .@"payload.is_flags.is_reified",
- .@"trailing.field_types.len" = .@"payload.fields_len",
- .@"trailing.field_names.len" = .@"payload.fields_len",
- },
- },
- .type_struct_packed_inits = .{
- .summary = .@"{.payload.name%summary#\"}",
- .payload = TypeStructPacked,
- .trailing = struct {
- captures_len: ?u32,
- captures: ?[]CaptureValue,
- type_hash: ?u64,
- field_types: []Index,
- field_names: []NullTerminatedString,
- field_inits: []Index,
- },
- .config = .{
- .@"trailing.captures_len.?" = .@"payload.flags.any_captures",
- .@"trailing.captures.?" = .@"payload.flags.any_captures",
- .@"trailing.captures.?.len" = .@"trailing.captures_len.?",
- .@"trailing.type_hash.?" = .@"payload.is_flags.is_reified",
- .@"trailing.field_types.len" = .@"payload.fields_len",
- .@"trailing.field_names.len" = .@"payload.fields_len",
- .@"trailing.field_inits.len" = .@"payload.fields_len",
- },
- },
.type_tuple = .{
.summary = .@"struct {...}",
.payload = TypeTuple,
@@ -5905,25 +5277,6 @@ pub const Tag = enum(u8) {
.@"trailing.field_values.len" = .@"payload.fields_len",
},
},
- .type_union = .{
- .summary = .@"{.payload.name%summary#\"}",
- .payload = TypeUnion,
- .trailing = struct {
- captures_len: ?u32,
- captures: ?[]CaptureValue,
- type_hash: ?u64,
- field_types: []Index,
- field_aligns: []Alignment,
- },
- .config = .{
- .@"trailing.captures_len.?" = .@"payload.flags.any_captures",
- .@"trailing.captures.?" = .@"payload.flags.any_captures",
- .@"trailing.captures.?.len" = .@"trailing.captures_len.?",
- .@"trailing.type_hash.?" = .@"payload.is_flags.is_reified",
- .@"trailing.field_types.len" = .@"payload.fields_len",
- .@"trailing.field_aligns.len" = .@"payload.fields_len",
- },
- },
.type_function = .{
.summary = .@"fn (...) ... {.payload.return_type%summary}",
.payload = TypeFunction,
@@ -5941,6 +5294,93 @@ pub const Tag = enum(u8) {
},
},
+ .type_struct = .{
+ .summary = .@"{.payload.name%summary#\"}",
+ .payload = TypeStruct,
+ .trailing = struct {
+ type_hash: ?u64,
+ captures_len: ?u32,
+ captures: ?[]CaptureValue,
+ field_names: []NullTerminatedString,
+ field_types: []Index,
+ field_defaults: ?[]Index,
+ field_aligns: ?[]Alignment,
+ field_is_comptime_bits: ?[]u32,
+ field_runtime_order: ?[]u32,
+ field_offsets: []u32,
+ },
+ .config = .{
+ .@"trailing.type_hash.?" = .@"payload.flags.any_captures == .reified",
+ .@"trailing.captures_len.?" = .@"payload.flags.any_captures == .true",
+ .@"trailing.captures.?" = .@"payload.flags.any_captures == .true",
+ .@"trailing.captures.?.len" = .@"trailing.captures_len.?",
+ .@"trailing.field_names.len" = .@"payload.fields_len",
+ .@"trailing.field_types.len" = .@"payload.fields_len",
+ .@"trailing.field_defaults.?" = .@"payload.flags.any_field_defaults",
+ .@"trailing.field_defaults.?.len" = .@"payload.fields_len",
+ .@"trailing.field_aligns.?" = .@"payload.flags.any_field_aligns",
+ .@"trailing.field_aligns.?.len" = .@"payload.fields_len",
+ .@"trailing.field_is_comptime_bits.?" = .@"payload.flags.any_comptime_fields",
+ .@"trailing.field_is_comptime_bits.?.len" = .@"(payload.fields_len + 31) / 32",
+ .@"trailing.field_runtime_order.?" = .@"payload.flags.layout == .auto",
+ .@"trailing.field_runtime_order.?.len" = .@"payload.fields_len",
+ .@"trailing.field_offsets.len" = .@"payload.fields_len",
+ },
+ },
+ .type_struct_packed_auto = struct_packed_encoding,
+ .type_struct_packed_explicit = struct_packed_encoding,
+ .type_struct_packed_auto_defaults = struct_packed_defaults_encoding,
+ .type_struct_packed_explicit_defaults = struct_packed_defaults_encoding,
+ .type_union = .{
+ .summary = .@"{.payload.name%summary#\"}",
+ .payload = TypeUnion,
+ .trailing = struct {
+ type_hash: ?u64,
+ captures_len: ?u32,
+ captures: ?[]CaptureValue,
+ field_types: []Index,
+ field_aligns: ?[]Alignment,
+ },
+ .config = .{
+ .@"trailing.type_hash.?" = .@"payload.flags.any_captures == .reified",
+ .@"trailing.captures_len.?" = .@"payload.flags.any_captures == .true",
+ .@"trailing.captures.?" = .@"payload.flags.any_captures == .true",
+ .@"trailing.captures.?.len" = .@"trailing.captures_len.?",
+ .@"trailing.field_types.len" = .@"payload.fields_len",
+ .@"trailing.field_aligns.?" = .@"payloads.flags.any_field_aligns",
+ .@"trailing.field_aligns.?.len" = .@"payload.fields_len",
+ },
+ },
+ .type_union_packed_auto = union_packed_encoding,
+ .type_union_packed_explicit = union_packed_encoding,
+ .type_enum_auto = .{
+ .summary = .@"{.payload.name%summary#\"}",
+ .payload = TypeEnum,
+ .trailing = struct {
+ owner_union: ?Index,
+ zir_index: ?TrackedInst.Index,
+ type_hash: ?u64,
+ captures: ?[]CaptureValue,
+ field_names: []NullTerminatedString,
+ },
+ .config = .{
+ .@"trailing.owner_union.?" = .@"payload.captures_len == .generated_union_tag",
+ .@"trailing.zir_index.?" = .@"payload.captures_len != .generated_union_tag",
+ .@"trailing.type_hash.?" = .@"payload.captures_len == .reified",
+ .@"trailing.captures.?" = .@"payload.captures_len != .reified and payload.captures_len != .generated_enum_tag",
+ .@"trailing.captures.?.len" = .@"@intFromEnum(payload.captures_len)",
+ .@"trailing.field_names.len" = .@"payload.fields_len",
+ },
+ },
+ .type_enum_explicit = enum_explicit_encoding,
+ .type_enum_nonexhaustive = enum_explicit_encoding,
+ .type_opaque = .{
+ .summary = .@"{.payload.name%summary#\"}",
+ .payload = TypeOpaque,
+ .trailing = struct { captures: []CaptureValue },
+ .config = .{ .@"trailing.captures.len" = .@"payload.captures_len" },
+ },
+
.undef = .{ .summary = .@"@as({.data%summary}, undefined)", .data = Index },
.simple_value = .{ .summary = .@"{.index%value#.}", .index = SimpleValue },
.ptr_nav = .{
@@ -5999,8 +5439,6 @@ pub const Tag = enum(u8) {
.int_small = .{ .summary = .@"@as({.payload.ty%summary}, {.payload.value%value})", .payload = IntSmall },
.int_positive = .{},
.int_negative = .{},
- .int_lazy_align = .{ .summary = .@"@as({.payload.ty%summary}, @alignOf({.payload.lazy_ty%summary}))", .payload = IntLazy },
- .int_lazy_size = .{ .summary = .@"@as({.payload.ty%summary}, @sizeOf({.payload.lazy_ty%summary}))", .payload = IntLazy },
.error_set_error = .{ .summary = .@"@as({.payload.ty%summary}, error.@{.payload.name%summary})", .payload = Error },
.error_union_error = .{ .summary = .@"@as({.payload.ty%summary}, error.@{.payload.name%summary})", .payload = Error },
.error_union_payload = .{ .summary = .@"@as({.payload.ty%summary}, {.payload.val%summary})", .payload = TypeValue },
@@ -6049,6 +5487,7 @@ pub const Tag = enum(u8) {
.config = .{ .@"trailing.elements.len" = .@"payload.ty.payload.fields_len" },
},
.repeated = .{ .summary = .@"@as({.payload.ty%summary}, @splat({.payload.elem_val%summary}))", .payload = Repeated },
+ .bitpack = .{ .summary = .@"@as({.payload.ty%summary}, {})", .payload = Key.Bitpack },
.memoized_call = .{
.summary = .@"@memoize({.payload.func%summary})",
@@ -6166,77 +5605,10 @@ pub const Tag = enum(u8) {
pub const Flags = packed struct(u32) {
cc: PackedCallingConvention,
is_var_args: bool,
- is_generic: bool,
has_comptime_bits: bool,
has_noalias_bits: bool,
is_noinline: bool,
- _: u9 = 0,
- };
- };
-
- /// Trailing:
- /// 0. captures_len: u32 // if `any_captures`
- /// 1. capture: CaptureValue // for each `captures_len`
- /// 2. type_hash: PackedU64 // if `is_reified`
- /// 3. field type: Index for each field; declaration order
- /// 4. field align: Alignment for each field; declaration order
- pub const TypeUnion = struct {
- name: NullTerminatedString,
- name_nav: Nav.Index.Optional,
- flags: Flags,
- /// This could be provided through the tag type, but it is more convenient
- /// to store it directly. This is also necessary for `dumpStatsFallible` to
- /// work on unresolved types.
- fields_len: u32,
- /// Only valid after .have_layout
- size: u32,
- /// Only valid after .have_layout
- padding: u32,
- namespace: NamespaceIndex,
- /// The enum that provides the list of field names and values.
- tag_ty: Index,
- zir_index: TrackedInst.Index,
-
- pub const Flags = packed struct(u32) {
- any_captures: bool,
- runtime_tag: LoadedUnionType.RuntimeTag,
- /// If false, the field alignment trailing data is omitted.
- any_aligned_fields: bool,
- layout: std.builtin.Type.ContainerLayout,
- status: LoadedUnionType.Status,
- requires_comptime: RequiresComptime,
- assumed_runtime_bits: bool,
- assumed_pointer_aligned: bool,
- alignment: Alignment,
- is_reified: bool,
- _: u12 = 0,
- };
- };
-
- /// Trailing:
- /// 0. captures_len: u32 // if `any_captures`
- /// 1. capture: CaptureValue // for each `captures_len`
- /// 2. type_hash: PackedU64 // if `is_reified`
- /// 3. type: Index for each fields_len
- /// 4. name: NullTerminatedString for each fields_len
- /// 5. init: Index for each fields_len // if tag is type_struct_packed_inits
- pub const TypeStructPacked = struct {
- name: NullTerminatedString,
- name_nav: Nav.Index.Optional,
- zir_index: TrackedInst.Index,
- fields_len: u32,
- namespace: NamespaceIndex,
- backing_int_ty: Index,
- names_map: MapIndex,
- flags: Flags,
-
- pub const Flags = packed struct(u32) {
- any_captures: bool = false,
- /// Dependency loop detection when resolving field inits.
- field_inits_wip: bool = false,
- inits_resolved: bool = false,
- is_reified: bool = false,
- _: u28 = 0,
+ _: u10 = 0,
};
};
@@ -6255,80 +5627,241 @@ pub const Tag = enum(u8) {
/// than coming up with some other scheme for the data.
///
/// Trailing:
- /// 0. captures_len: u32 // if `any_captures`
- /// 1. capture: CaptureValue // for each `captures_len`
- /// 2. type_hash: PackedU64 // if `is_reified`
- /// 3. type: Index for each field in declared order
- /// 4. if any_default_inits:
- /// init: Index // for each field in declared order
- /// 5. if any_aligned_fields:
- /// align: Alignment // for each field in declared order
- /// 6. if any_comptime_fields:
- /// field_is_comptime_bits: u32 // minimal number of u32s needed, LSB is field 0
- /// 7. if not is_extern:
- /// field_index: RuntimeOrder // for each field in runtime order
- /// 8. field_offset: u32 // for each field in declared order, undef until layout_resolved
+ /// 0. type_hash: PackedU64 // if `any_captures == .reified`
+ /// 1. captures_len: u32 // if `any_captures == .true`
+ /// 2. capture: CaptureValue // for each `captures_len`
+ /// 3. field_name: NullTerminatedString // for each `fields_len`
+ /// 4. field_type: Index // for each `fields_len`
+ /// 5. field_default: Index // if `any_field_defaults`; for each `fields_len`
+ /// 6. field_align: Alignment // if `any_field_aligns`; for each `fields_len`
+ /// 7. field_is_comptime_bits: u32 // if `any_comptime_fields`; minimum `u32` for `fields_len`; LSB is field 0
+ /// 8. field_runtime_order: RuntimeOrder // if `layout == .auto`; for each `fields_len`
+ /// 9. field_offset: u32 // for each `fields_len`
pub const TypeStruct = struct {
+ zir_index: TrackedInst.Index,
+
name: NullTerminatedString,
name_nav: Nav.Index.Optional,
- zir_index: TrackedInst.Index,
namespace: NamespaceIndex,
+
fields_len: u32,
+ field_name_map: MapIndex,
+
+ /// Size in bytes of the whole struct. Always 0 until layout resolved.
+ size: u32,
+
flags: Flags,
+
+ pub const Flags = packed struct(u32) {
+ any_captures: enum(u2) { true, false, reified },
+
+ /// `packed` layout is represented separately by `TypeStructPacked`.
+ layout: enum(u1) { auto, @"extern" },
+
+ any_comptime_fields: bool,
+ any_field_defaults: bool,
+ any_field_aligns: bool,
+
+ class: TypeClass,
+ /// Alignment of the whole struct. Always `.none` until layout resolved.
+ alignment: Alignment,
+
+ want_layout: bool,
+
+ _: u16 = 0,
+ };
+ };
+
+ /// Trailing:
+ /// 0. type_hash: PackedU64 // if `captures_len == .reified`
+ /// 1. capture: CaptureValue // if `captures_len != .reified`; for each `captures_len`
+ /// 2. field_name: NullTerminatedString // for each `fields_len`
+ /// 3. field_type: Index // for each `fields_len`
+ /// 4. field_default: Index // if item tag implies field defaults; for each `fields_len`
+ pub const TypeStructPacked = struct {
+ zir_index: TrackedInst.Index,
+ bits: Bits,
+
+ name: NullTerminatedString,
+ name_nav: Nav.Index.Optional,
+ namespace: NamespaceIndex,
+
+ /// The corresponding `BackingTypeMode` depends on the item's `Tag`.
+ backing_int_type: Index,
+
+ fields_len: u32,
+ field_name_map: MapIndex,
+
+ const Bits = packed struct(u32) {
+ captures_len: enum(u31) {
+ reified = std.math.maxInt(u31),
+ _,
+ },
+ want_layout: bool,
+ };
+ };
+
+ /// For declared unions, field names are intentionally omitted because they are available in
+ /// `enum_tag_type`. However, reified unions do store field names, because they are needed by
+ /// type resolution to create or validate the enum tag type (type resolution for declared unions
+ /// instead fetches field names from ZIR).
+ ///
+ /// Trailing:
+ /// 0. type_hash: PackedU64 // if `any_captures == .reified`
+ /// 1. captures_len: u32 // if `any_captures == .true`
+ /// 2. capture: CaptureValue // if `any_captures == .true`; for each `captures_len`
+ /// 3. reified_field_name: NullTerminatedString // if `any_captures == .reified`; for each `fields_len`
+ /// 4. field_type: Index // for each `fields_len`
+ /// 5. field_align: Alignment // for each `fields_len` if `any_field_aligns`
+ pub const TypeUnion = struct {
+ zir_index: TrackedInst.Index,
+
+ name: NullTerminatedString,
+ name_nav: Nav.Index.Optional,
+ namespace: NamespaceIndex,
+ /// The enum that provides the list of field names and values.
+ enum_tag_type: Index,
+
+ /// This could be provided through the tag type, but it is more convenient
+ /// to store it directly. This is also necessary for `dumpStatsFallible` to
+ /// work on unresolved types.
+ fields_len: u32,
+
+ /// Always 0 until layout resolved.
size: u32,
+ /// Always 0 until layout resolved.
+ padding: u32,
+
+ flags: Flags,
pub const Flags = packed struct(u32) {
- any_captures: bool = false,
- is_extern: bool = false,
- known_non_opv: bool = false,
- requires_comptime: RequiresComptime = @enumFromInt(0),
- assumed_runtime_bits: bool = false,
- assumed_pointer_aligned: bool = false,
- any_comptime_fields: bool = false,
- any_default_inits: bool = false,
- any_aligned_fields: bool = false,
- /// `.none` until layout_resolved
- alignment: Alignment = @enumFromInt(0),
- /// Dependency loop detection when resolving struct alignment.
- alignment_wip: bool = false,
- /// Dependency loop detection when resolving field types.
- field_types_wip: bool = false,
- /// Dependency loop detection when resolving struct layout.
- layout_wip: bool = false,
- /// Indicates whether `size`, `alignment`, runtime field order, and
- /// field offets are populated.
- layout_resolved: bool = false,
- /// Dependency loop detection when resolving field inits.
- field_inits_wip: bool = false,
- /// Indicates whether `field_inits` has been resolved.
- inits_resolved: bool = false,
- // The types and all its fields have had their layout resolved. Even through pointer = false,
- // which `layout_resolved` does not ensure.
- fully_resolved: bool = false,
- is_reified: bool = false,
- _: u8 = 0,
+ any_captures: enum(u2) { true, false, reified },
+
+ /// Whether `enum_tag_type` was explicitly specified with `union(E)` syntax.
+ ///
+ /// For `union(enum(E))` syntax, this is `false`, but the generated enum tag type is
+ /// considered to have an explicitly specified integer tag type.
+ enum_tag_mode: BackingTypeMode,
+
+ /// `packed` layout is represented separately by `TypeStructPacked`.
+ layout: enum(u1) { auto, @"extern" },
+
+ any_field_aligns: bool,
+ tag_usage: LoadedUnionType.TagUsage,
+
+ class: TypeClass,
+ has_runtime_tag: bool,
+
+ /// Alignment of the whole union. Always `.none` until layout resolved.
+ alignment: Alignment,
+
+ want_layout: bool,
+
+ _: u14 = 0,
+ };
+ };
+
+ /// For declared unions, field names are intentionally omitted because they are available in
+ /// `enum_tag_type`. However, reified unions do store field names, because they are needed by
+ /// type resolution to create or validate the enum tag type (type resolution for declared unions
+ /// instead fetches field names from ZIR).
+ ///
+ /// Trailing:
+ /// 0. type_hash: PackedU64 // if `captures_len == .reified`
+ /// 1. capture: CaptureValue // if `captures_len != .reified`; for each `captures_len`
+ /// 2. reified_field_name: NullTerminatedString // if `captures_len == .reified`; for each `fields_len`
+ /// 3. field_type: Index // for each `fields_len`
+ pub const TypeUnionPacked = struct {
+ zir_index: TrackedInst.Index,
+ bits: Bits,
+
+ name: NullTerminatedString,
+ name_nav: Nav.Index.Optional,
+ namespace: NamespaceIndex,
+
+ /// The corresponding `BackingTypeMode` depends on the item's `Tag`.
+ backing_int_type: Index,
+ /// Although packed unions do not semantically have a tag type, the compiler still assigns
+ /// them a "hypothetical" tag type.
+ enum_tag_type: Index,
+
+ /// This could be provided through the tag type, but it is more convenient
+ /// to store it directly. This is also necessary for `dumpStatsFallible` to
+ /// work on unresolved types.
+ fields_len: u32,
+
+ const Bits = packed struct(u32) {
+ captures_len: enum(u31) {
+ reified = std.math.maxInt(u31),
+ _,
+ },
+ want_layout: bool,
+ };
+ };
+
+ /// Trailing:
+ /// 0. owner_union: Index // if `captures_len == .generated_union_tag`
+ /// 1. zir_index: TrackedInst.Index // if `captures_len != .generated_union_tag`
+ /// 2. type_hash: PackedU64 // if `captures_len == .reified`
+ /// 3. capture: CaptureValue // if `captures_len` is not a named tag; for each `captures_len`
+ /// 4. field_value_map: MapIndex // if tag is not `.type_enum_auto`
+ /// 5. field_name: NullTerminatedString // for each `fields_len`
+ /// 6. field_value: Index // if tag is not `.type_enum_auto`; for each `fields_len`
+ pub const TypeEnum = struct {
+ bits: Bits,
+
+ name: NullTerminatedString,
+ name_nav: Nav.Index.Optional,
+ namespace: NamespaceIndex,
+
+ /// An integer type which is used for the numerical value of the enum. Whether this was
+ /// user-provided or inferred by the compiler depends on the tag.
+ int_tag_type: Index,
+
+ fields_len: u32,
+ field_name_map: MapIndex,
+
+ const Bits = packed struct(u32) {
+ captures_len: enum(u31) {
+ reified = std.math.maxInt(u31),
+ generated_union_tag = std.math.maxInt(u31) - 1,
+ _,
+ },
+ want_layout: bool,
};
};
/// Trailing:
/// 0. capture: CaptureValue // for each `captures_len`
pub const TypeOpaque = struct {
- name: NullTerminatedString,
- name_nav: Nav.Index.Optional,
- /// Contains the declarations inside this opaque.
- namespace: NamespaceIndex,
- /// The index of the `opaque_decl` instruction.
zir_index: TrackedInst.Index,
- /// `std.math.maxInt(u32)` indicates this type is reified.
captures_len: u32,
+
+ name: NullTerminatedString,
+ name_nav: Nav.Index.Optional,
+ namespace: NamespaceIndex,
};
};
+/// Differentiates between user-provided and compiler-generated backing types for packed and tagged types.
+pub const BackingTypeMode = enum(u1) {
+ /// The backing type was explicitly provided by the user. For instance:
+ /// union(T)
+ /// enum(T)
+ /// packed struct(T)
+ /// packed union(T)
+ /// Type layout resolution will evaluate the user-provided expression and validate that type.
+ explicit,
+ /// No backing type was explicitly provided by the user. Type layout resolution will populate
+ /// an inferred/generated type.
+ auto,
+};
+
/// State that is mutable during semantic analysis. This data is not used for
/// equality or hashing, except for `inferred_error_set` which is considered
/// to be part of the type of the function.
pub const FuncAnalysis = packed struct(u32) {
- is_analyzed: bool,
+ want_runtime_analysis: bool,
branch_hint: std.builtin.BranchHint,
is_noinline: bool,
has_error_trace: bool,
@@ -6399,13 +5932,9 @@ pub const SimpleType = enum(u32) {
};
pub const SimpleValue = enum(u32) {
- /// This is untyped `undefined`.
- undefined = @intFromEnum(Index.undef),
void = @intFromEnum(Index.void_value),
/// This is untyped `null`.
null = @intFromEnum(Index.null_value),
- /// This is the untyped empty struct/array literal: `.{}`
- empty_tuple = @intFromEnum(Index.empty_tuple),
true = @intFromEnum(Index.bool_true),
false = @intFromEnum(Index.bool_false),
@"unreachable" = @intFromEnum(Index.unreachable_value),
@@ -6536,12 +6065,17 @@ pub const Alignment = enum(u6) {
pub const empty: Slice = .{ .tid = .main, .start = 0, .len = 0 };
pub fn get(slice: Slice, ip: *const InternPool) []Alignment {
- // TODO: implement @ptrCast between slices changing the length
const extra = ip.getLocalShared(slice.tid).extra.acquire();
- //const bytes: []u8 = @ptrCast(extra.view().items(.@"0")[slice.start..]);
- const bytes: []u8 = std.mem.sliceAsBytes(extra.view().items(.@"0")[slice.start..]);
+ const bytes: []u8 = @ptrCast(extra.view().items(.@"0")[slice.start..]);
return @ptrCast(bytes[0..slice.len]);
}
+
+ /// If `slice` is empty (`slice.len == 0`), returns `.none`.
+ /// Otherwise, asserts that `index < slice.len`, and returns the value at `index`.
+ pub fn getOrNone(slice: Slice, ip: *const InternPool, index: usize) Alignment {
+ if (slice.len == 0) return .none;
+ return slice.get(ip)[index];
+ }
};
pub fn toRelaxedCompareUnits(a: Alignment) u8 {
@@ -6596,55 +6130,6 @@ pub const Array = struct {
}
};
-/// Trailing:
-/// 0. owner_union: Index // if `zir_index == .none`
-/// 1. capture: CaptureValue // for each `captures_len`
-/// 2. type_hash: PackedU64 // if reified (`captures_len == std.math.maxInt(u32)`)
-/// 3. field name: NullTerminatedString for each fields_len; declaration order
-/// 4. tag value: Index for each fields_len; declaration order
-pub const EnumExplicit = struct {
- name: NullTerminatedString,
- name_nav: Nav.Index.Optional,
- /// `std.math.maxInt(u32)` indicates this type is reified.
- captures_len: u32,
- namespace: NamespaceIndex,
- /// An integer type which is used for the numerical value of the enum, which
- /// has been explicitly provided by the enum declaration.
- int_tag_type: Index,
- fields_len: u32,
- /// Maps field names to declaration index.
- names_map: MapIndex,
- /// Maps field values to declaration index.
- /// If this is `none`, it means the trailing tag values are absent because
- /// they are auto-numbered.
- values_map: OptionalMapIndex,
- /// `none` means this is a generated tag type.
- /// There will be a trailing union type for which this is a tag.
- zir_index: TrackedInst.Index.Optional,
-};
-
-/// Trailing:
-/// 0. owner_union: Index // if `zir_index == .none`
-/// 1. capture: CaptureValue // for each `captures_len`
-/// 2. type_hash: PackedU64 // if reified (`captures_len == std.math.maxInt(u32)`)
-/// 3. field name: NullTerminatedString for each fields_len; declaration order
-pub const EnumAuto = struct {
- name: NullTerminatedString,
- name_nav: Nav.Index.Optional,
- /// `std.math.maxInt(u32)` indicates this type is reified.
- captures_len: u32,
- namespace: NamespaceIndex,
- /// An integer type which is used for the numerical value of the enum, which
- /// was inferred by Zig based on the number of tags.
- int_tag_type: Index,
- fields_len: u32,
- /// Maps field names to declaration index.
- names_map: MapIndex,
- /// `none` means this is a generated tag type.
- /// There will be a trailing union type for which this is a tag.
- zir_index: TrackedInst.Index.Optional,
-};
-
pub const PackedU64 = packed struct(u64) {
a: u32,
b: u32,
@@ -6827,11 +6312,6 @@ pub const IntSmall = struct {
value: u32,
};
-pub const IntLazy = struct {
- ty: Index,
- lazy_ty: Index,
-};
-
/// A f64 value, broken up into 2 u32 parts.
pub const Float64 = struct {
piece0: u32,
@@ -6994,7 +6474,9 @@ pub fn deinit(ip: *InternPool, gpa: Allocator, io: Io) void {
ip.src_hash_deps.deinit(gpa);
ip.nav_val_deps.deinit(gpa);
ip.nav_ty_deps.deinit(gpa);
- ip.interned_deps.deinit(gpa);
+ ip.func_ies_deps.deinit(gpa);
+ ip.type_layout_deps.deinit(gpa);
+ ip.struct_defaults_deps.deinit(gpa);
ip.zon_file_deps.deinit(gpa);
ip.embed_file_deps.deinit(gpa);
ip.namespace_deps.deinit(gpa);
@@ -7130,132 +6612,118 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
.type_inferred_error_set => .{
.inferred_error_set_type = @enumFromInt(data),
},
-
- .type_opaque => .{ .opaque_type = ns: {
- const extra = extraDataTrail(unwrapped_index.getExtra(ip), Tag.TypeOpaque, data);
- if (extra.data.captures_len == std.math.maxInt(u32)) {
- break :ns .{ .reified = .{
- .zir_index = extra.data.zir_index,
- .type_hash = 0,
- } };
- }
- break :ns .{ .declared = .{
- .zir_index = extra.data.zir_index,
- .captures = .{ .owned = .{
- .tid = unwrapped_index.tid,
- .start = extra.end,
- .len = extra.data.captures_len,
- } },
- } };
- } },
-
- .type_struct => .{ .struct_type = ns: {
- const extra_list = unwrapped_index.getExtra(ip);
- const extra_items = extra_list.view().items(.@"0");
- const zir_index: TrackedInst.Index = @enumFromInt(extra_items[data + std.meta.fieldIndex(Tag.TypeStruct, "zir_index").?]);
- const flags: Tag.TypeStruct.Flags = @bitCast(@atomicLoad(u32, &extra_items[data + std.meta.fieldIndex(Tag.TypeStruct, "flags").?], .unordered));
- const end_extra_index = data + @as(u32, @typeInfo(Tag.TypeStruct).@"struct".fields.len);
- if (flags.is_reified) {
- assert(!flags.any_captures);
- break :ns .{ .reified = .{
- .zir_index = zir_index,
- .type_hash = extraData(extra_list, PackedU64, end_extra_index).get(),
- } };
- }
- break :ns .{ .declared = .{
- .zir_index = zir_index,
- .captures = .{ .owned = if (flags.any_captures) .{
- .tid = unwrapped_index.tid,
- .start = end_extra_index + 1,
- .len = extra_list.view().items(.@"0")[end_extra_index],
- } else CaptureValue.Slice.empty },
- } };
- } },
-
- .type_struct_packed, .type_struct_packed_inits => .{ .struct_type = ns: {
- const extra_list = unwrapped_index.getExtra(ip);
- const extra_items = extra_list.view().items(.@"0");
- const zir_index: TrackedInst.Index = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "zir_index").?]);
- const flags: Tag.TypeStructPacked.Flags = @bitCast(@atomicLoad(u32, &extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "flags").?], .unordered));
- const end_extra_index = data + @as(u32, @typeInfo(Tag.TypeStructPacked).@"struct".fields.len);
- if (flags.is_reified) {
- assert(!flags.any_captures);
- break :ns .{ .reified = .{
- .zir_index = zir_index,
- .type_hash = extraData(extra_list, PackedU64, end_extra_index).get(),
- } };
- }
- break :ns .{ .declared = .{
- .zir_index = zir_index,
- .captures = .{ .owned = if (flags.any_captures) .{
- .tid = unwrapped_index.tid,
- .start = end_extra_index + 1,
- .len = extra_items[end_extra_index],
- } else CaptureValue.Slice.empty },
- } };
- } },
+ .type_function => .{ .func_type = extraFuncType(unwrapped_index.tid, unwrapped_index.getExtra(ip), data) },
.type_tuple => .{ .tuple_type = extraTypeTuple(unwrapped_index.tid, unwrapped_index.getExtra(ip), data) },
+
+ .type_struct => .{ .struct_type = ns: {
+ const extra_list = unwrapped_index.getExtra(ip);
+ const extra = extraDataTrail(extra_list, Tag.TypeStruct, data);
+ break :ns switch (extra.data.flags.any_captures) {
+ .reified => .{ .reified = .{
+ .zir_index = extra.data.zir_index,
+ .type_hash = extraData(extra_list, PackedU64, extra.end).get(),
+ } },
+ .false => .{ .declared = .{
+ .zir_index = extra.data.zir_index,
+ .captures = .{ .owned = .empty },
+ } },
+ .true => .{ .declared = .{
+ .zir_index = extra.data.zir_index,
+ .captures = .{ .owned = .{
+ .tid = unwrapped_index.tid,
+ .start = extra.end + 1,
+ .len = extra_list.view().items(.@"0")[extra.end],
+ } },
+ } },
+ };
+ } },
+ .type_struct_packed_auto,
+ .type_struct_packed_explicit,
+ .type_struct_packed_auto_defaults,
+ .type_struct_packed_explicit_defaults,
+ => .{ .struct_type = ns: {
+ const extra_list = unwrapped_index.getExtra(ip);
+ const extra = extraDataTrail(extra_list, Tag.TypeStructPacked, data);
+ break :ns switch (extra.data.bits.captures_len) {
+ .reified => .{ .reified = .{
+ .zir_index = extra.data.zir_index,
+ .type_hash = extraData(extra_list, PackedU64, extra.end).get(),
+ } },
+ _ => |len| .{ .declared = .{
+ .zir_index = extra.data.zir_index,
+ .captures = .{ .owned = .{
+ .tid = unwrapped_index.tid,
+ .start = extra.end,
+ .len = @intFromEnum(len),
+ } },
+ } },
+ };
+ } },
.type_union => .{ .union_type = ns: {
const extra_list = unwrapped_index.getExtra(ip);
const extra = extraDataTrail(extra_list, Tag.TypeUnion, data);
- if (extra.data.flags.is_reified) {
- assert(!extra.data.flags.any_captures);
- break :ns .{ .reified = .{
+ break :ns switch (extra.data.flags.any_captures) {
+ .reified => .{ .reified = .{
.zir_index = extra.data.zir_index,
.type_hash = extraData(extra_list, PackedU64, extra.end).get(),
- } };
- }
+ } },
+ .false => .{ .declared = .{
+ .zir_index = extra.data.zir_index,
+ .captures = .{ .owned = .empty },
+ } },
+ .true => .{ .declared = .{
+ .zir_index = extra.data.zir_index,
+ .captures = .{ .owned = .{
+ .tid = unwrapped_index.tid,
+ .start = extra.end + 1,
+ .len = extra_list.view().items(.@"0")[extra.end],
+ } },
+ } },
+ };
+ } },
+ .type_union_packed_auto, .type_union_packed_explicit => .{ .union_type = ns: {
+ const extra_list = unwrapped_index.getExtra(ip);
+ const extra = extraDataTrail(extra_list, Tag.TypeUnionPacked, data);
+ break :ns switch (extra.data.bits.captures_len) {
+ .reified => .{ .reified = .{
+ .zir_index = extra.data.zir_index,
+ .type_hash = extraData(extra_list, PackedU64, extra.end).get(),
+ } },
+ _ => |len| .{ .declared = .{
+ .zir_index = extra.data.zir_index,
+ .captures = .{ .owned = .{
+ .tid = unwrapped_index.tid,
+ .start = extra.end,
+ .len = @intFromEnum(len),
+ } },
+ } },
+ };
+ } },
+ .type_enum_auto, .type_enum_explicit, .type_enum_nonexhaustive => .{ .enum_type = ns: {
+ const extra_list = unwrapped_index.getExtra(ip);
+ const extra = extraDataTrail(extra_list, Tag.TypeEnum, data);
+ break :ns switch (extra.data.bits.captures_len) {
+ .reified => .{ .reified = .{
+ .zir_index = @enumFromInt(extra_list.view().items(.@"0")[extra.end]),
+ .type_hash = extraData(extra_list, PackedU64, extra.end + 1).get(),
+ } },
+ .generated_union_tag => .{ .generated_union_tag = owner_union: {
+ break :owner_union @enumFromInt(extra_list.view().items(.@"0")[extra.end]);
+ } },
+ _ => |len| .{ .declared = .{
+ .zir_index = @enumFromInt(extra_list.view().items(.@"0")[extra.end]),
+ .captures = .{ .owned = .{
+ .tid = unwrapped_index.tid,
+ .start = extra.end + 1,
+ .len = @intFromEnum(len),
+ } },
+ } },
+ };
+ } },
+ .type_opaque => .{ .opaque_type = ns: {
+ const extra = extraDataTrail(unwrapped_index.getExtra(ip), Tag.TypeOpaque, data);
break :ns .{ .declared = .{
.zir_index = extra.data.zir_index,
- .captures = .{ .owned = if (extra.data.flags.any_captures) .{
- .tid = unwrapped_index.tid,
- .start = extra.end + 1,
- .len = extra_list.view().items(.@"0")[extra.end],
- } else CaptureValue.Slice.empty },
- } };
- } },
-
- .type_enum_auto => .{ .enum_type = ns: {
- const extra_list = unwrapped_index.getExtra(ip);
- const extra = extraDataTrail(extra_list, EnumAuto, data);
- const zir_index = extra.data.zir_index.unwrap() orelse {
- assert(extra.data.captures_len == 0);
- break :ns .{ .generated_tag = .{
- .union_type = @enumFromInt(extra_list.view().items(.@"0")[extra.end]),
- } };
- };
- if (extra.data.captures_len == std.math.maxInt(u32)) {
- break :ns .{ .reified = .{
- .zir_index = zir_index,
- .type_hash = extraData(extra_list, PackedU64, extra.end).get(),
- } };
- }
- break :ns .{ .declared = .{
- .zir_index = zir_index,
- .captures = .{ .owned = .{
- .tid = unwrapped_index.tid,
- .start = extra.end,
- .len = extra.data.captures_len,
- } },
- } };
- } },
- .type_enum_explicit, .type_enum_nonexhaustive => .{ .enum_type = ns: {
- const extra_list = unwrapped_index.getExtra(ip);
- const extra = extraDataTrail(extra_list, EnumExplicit, data);
- const zir_index = extra.data.zir_index.unwrap() orelse {
- assert(extra.data.captures_len == 0);
- break :ns .{ .generated_tag = .{
- .union_type = @enumFromInt(extra_list.view().items(.@"0")[extra.end]),
- } };
- };
- if (extra.data.captures_len == std.math.maxInt(u32)) {
- break :ns .{ .reified = .{
- .zir_index = zir_index,
- .type_hash = extraData(extra_list, PackedU64, extra.end).get(),
- } };
- }
- break :ns .{ .declared = .{
- .zir_index = zir_index,
.captures = .{ .owned = .{
.tid = unwrapped_index.tid,
.start = extra.end,
@@ -7263,7 +6731,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
} },
} };
} },
- .type_function => .{ .func_type = extraFuncType(unwrapped_index.tid, unwrapped_index.getExtra(ip), data) },
.undef => .{ .undef = @enumFromInt(data) },
.opt_null => .{ .opt = .{
@@ -7390,17 +6857,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
.storage = .{ .u64 = info.value },
} };
},
- .int_lazy_align, .int_lazy_size => |tag| {
- const info = extraData(unwrapped_index.getExtra(ip), IntLazy, data);
- return .{ .int = .{
- .ty = info.ty,
- .storage = switch (tag) {
- .int_lazy_align => .{ .lazy_align = info.lazy_ty },
- .int_lazy_size => .{ .lazy_size = info.lazy_ty },
- else => unreachable,
- },
- } };
- },
.float_f16 => .{ .float = .{
.ty = .f16_type,
.storage = .{ .f16 = @bitCast(@as(u16, @intCast(data))) },
@@ -7488,7 +6944,8 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
},
.type_array_small,
.type_vector,
- .type_struct_packed,
+ .type_struct_packed_auto,
+ .type_struct_packed_explicit,
=> .{ .aggregate = .{
.ty = ty,
.storage = .{ .elems = &.{} },
@@ -7496,11 +6953,14 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
// There is only one possible value precisely due to the
// fact that this values slice is fully populated!
- .type_struct, .type_struct_packed_inits => {
+ .type_struct,
+ .type_struct_packed_auto_defaults,
+ .type_struct_packed_explicit_defaults,
+ => {
const info = loadStructType(ip, ty);
return .{ .aggregate = .{
.ty = ty,
- .storage = .{ .elems = @ptrCast(info.field_inits.get(ip)) },
+ .storage = .{ .elems = @ptrCast(info.field_defaults.get(ip)) },
} };
},
@@ -7516,11 +6976,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
} };
},
- .type_enum_auto,
- .type_enum_explicit,
- .type_union,
- => .{ .empty_enum_value = ty },
-
else => unreachable,
};
},
@@ -7566,6 +7021,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
},
.enum_literal => .{ .enum_literal = @enumFromInt(data) },
.enum_tag => .{ .enum_tag = extraData(unwrapped_index.getExtra(ip), Tag.EnumTag, data) },
+ .bitpack => .{ .bitpack = extraData(unwrapped_index.getExtra(ip), Key.Bitpack, data) },
.memoized_call => {
const extra_list = unwrapped_index.getExtra(ip);
@@ -7634,7 +7090,6 @@ fn extraFuncType(tid: Zcu.PerThread.Id, extra: Local.Extra, extra_index: u32) Ke
.cc = type_function.data.flags.cc.unpack(),
.is_var_args = type_function.data.flags.is_var_args,
.is_noinline = type_function.data.flags.is_noinline,
- .is_generic = type_function.data.flags.is_generic,
};
}
@@ -7893,45 +7348,6 @@ fn getOrPutKeyEnsuringAdditionalCapacity(
.map_index = map_index,
} };
}
-/// Like `getOrPutKey`, but asserts that the key already exists, and prepares to replace
-/// its shard entry with a new `Index` anyway. After finalizing this, the old index remains
-/// valid (in that `indexToKey` and similar queries will behave as before), but it will
-/// never be returned from a lookup (`getOrPutKey` etc).
-/// This is used by incremental compilation when an existing container type is outdated. In
-/// this case, the type must be recreated at a new `InternPool.Index`, but the old index must
-/// remain valid since now-unreferenced `AnalUnit`s may retain references to it. The old index
-/// will be cleaned up when the `Zcu` undergoes garbage collection.
-fn putKeyReplace(
- ip: *InternPool,
- io: Io,
- tid: Zcu.PerThread.Id,
- key: Key,
-) GetOrPutKey {
- const full_hash = key.hash64(ip);
- const hash: u32 = @truncate(full_hash >> 32);
- const shard = &ip.shards[@intCast(full_hash & (ip.shards.len - 1))];
- shard.mutate.map.mutex.lock(io, tid);
- errdefer shard.mutate.map.mutex.unlock(io);
- const map = shard.shared.map;
- const map_mask = map.header().mask();
- var map_index = hash;
- while (true) : (map_index += 1) {
- map_index &= map_mask;
- const entry = &map.entries[map_index];
- const index = entry.value;
- assert(index != .none); // key not present
- if (entry.hash == hash and ip.indexToKey(index).eql(key, ip)) {
- break; // we found the entry to replace
- }
- }
- return .{ .new = .{
- .ip = ip,
- .tid = tid,
- .io = io,
- .shard = shard,
- .map_index = map_index,
- } };
-}
pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key: Key) Allocator.Error!Index {
var gop = try ip.getOrPutKey(gpa, io, tid, key);
@@ -8084,12 +7500,12 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
});
},
- .struct_type => unreachable, // use getStructType() instead
+ .struct_type => unreachable, // instead use: getDeclaredStructType, getReifiedStructType
+ .union_type => unreachable, // instead use: getDeclaredUnionType, getReifiedUnionType
+ .enum_type => unreachable, // instead use: getDeclaredEnumType, getReifiedEnumType, getGeneratedEnumTagType
+ .opaque_type => unreachable, // instead use: getDeclaredOpaqueType
+
.tuple_type => unreachable, // use getTupleType() instead
- .union_type => unreachable, // use getUnionType() instead
- .opaque_type => unreachable, // use getOpaqueType() instead
-
- .enum_type => unreachable, // use getEnumType() instead
.func_type => unreachable, // use getFuncType() instead
.@"extern" => unreachable, // use getExtern() instead
.func => unreachable, // use getFuncInstance() or getFuncDecl() instead
@@ -8249,23 +7665,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
.int => |int| b: {
assert(ip.isIntegerType(int.ty));
- switch (int.storage) {
- .u64, .i64, .big_int => {},
- .lazy_align, .lazy_size => |lazy_ty| {
- items.appendAssumeCapacity(.{
- .tag = switch (int.storage) {
- else => unreachable,
- .lazy_align => .int_lazy_align,
- .lazy_size => .int_lazy_size,
- },
- .data = try addExtra(extra, IntLazy{
- .ty = int.ty,
- .lazy_ty = lazy_ty,
- }),
- });
- return gop.put();
- },
- }
switch (int.ty) {
.u8_type => switch (int.storage) {
.big_int => |big_int| {
@@ -8282,7 +7681,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
});
break :b;
},
- .lazy_align, .lazy_size => unreachable,
},
.u16_type => switch (int.storage) {
.big_int => |big_int| {
@@ -8299,7 +7697,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
});
break :b;
},
- .lazy_align, .lazy_size => unreachable,
},
.u32_type => switch (int.storage) {
.big_int => |big_int| {
@@ -8316,7 +7713,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
});
break :b;
},
- .lazy_align, .lazy_size => unreachable,
},
.i32_type => switch (int.storage) {
.big_int => |big_int| {
@@ -8334,7 +7730,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
});
break :b;
},
- .lazy_align, .lazy_size => unreachable,
},
.usize_type => switch (int.storage) {
.big_int => |big_int| {
@@ -8355,7 +7750,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
break :b;
}
},
- .lazy_align, .lazy_size => unreachable,
},
.comptime_int_type => switch (int.storage) {
.big_int => |big_int| {
@@ -8390,7 +7784,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
break :b;
}
},
- .lazy_align, .lazy_size => unreachable,
},
else => {},
}
@@ -8427,7 +7820,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
const tag: Tag = if (big_int.positive) .int_positive else .int_negative;
try addInt(ip, gpa, io, tid, int.ty, tag, big_int.limbs);
},
- .lazy_align, .lazy_size => unreachable,
}
},
@@ -8468,7 +7860,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
assert(ip.isEnumType(enum_tag.ty));
switch (ip.indexToKey(enum_tag.ty)) {
.simple_type => assert(ip.isIntegerType(ip.typeOf(enum_tag.int))),
- .enum_type => assert(ip.typeOf(enum_tag.int) == ip.loadEnumType(enum_tag.ty).tag_ty),
+ .enum_type => assert(ip.typeOf(enum_tag.int) == ip.loadEnumType(enum_tag.ty).int_tag_type),
else => unreachable,
}
items.appendAssumeCapacity(.{
@@ -8477,11 +7869,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
});
},
- .empty_enum_value => |enum_or_union_ty| items.appendAssumeCapacity(.{
- .tag = .only_possible_value,
- .data = @intFromEnum(enum_or_union_ty),
- }),
-
.float => |float| {
switch (float.ty) {
.f16_type => items.appendAssumeCapacity(.{
@@ -8525,15 +7912,14 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
.aggregate => |aggregate| {
const ty_key = ip.indexToKey(aggregate.ty);
const len = ip.aggregateTypeLen(aggregate.ty);
- const child = switch (ty_key) {
- .array_type => |array_type| array_type.child,
- .vector_type => |vector_type| vector_type.child,
- .tuple_type, .struct_type => .none,
- else => unreachable,
- };
- const sentinel = switch (ty_key) {
- .array_type => |array_type| array_type.sentinel,
- .vector_type, .tuple_type, .struct_type => .none,
+ const child: Index, const sentinel: Index = switch (ty_key) {
+ .array_type => |array_type| .{ array_type.child, array_type.sentinel },
+ .vector_type => |vector_type| .{ vector_type.child, .none },
+ .tuple_type => .{ .none, .none },
+ .struct_type => child: {
+ assert(ip.loadStructType(aggregate.ty).layout != .@"packed");
+ break :child .{ .none, .none };
+ },
else => unreachable,
};
const len_including_sentinel = len + @intFromBool(sentinel != .none);
@@ -8715,6 +8101,18 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
extra.appendSliceAssumeCapacity(.{@ptrCast(aggregate.storage.elems)});
if (sentinel != .none) extra.appendAssumeCapacity(.{@intFromEnum(sentinel)});
},
+ .bitpack => |bitpack| {
+ switch (ip.zigTypeTag(bitpack.ty)) {
+ .@"struct" => assert(ip.typeOf(bitpack.backing_int_val) == ip.loadStructType(bitpack.ty).packed_backing_int_type),
+ .@"union" => assert(ip.typeOf(bitpack.backing_int_val) == ip.loadUnionType(bitpack.ty).packed_backing_int_type),
+ else => unreachable,
+ }
+ assert(!ip.isUndef(bitpack.backing_int_val));
+ items.appendAssumeCapacity(.{
+ .tag = .bitpack,
+ .data = try addExtra(extra, bitpack),
+ });
+ },
.memoized_call => |memoized_call| {
for (memoized_call.arg_values) |arg| assert(arg != .none);
@@ -8735,6 +8133,932 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
return gop.put();
}
+pub fn getDeclaredStructType(
+ ip: *InternPool,
+ gpa: Allocator,
+ io: Io,
+ tid: Zcu.PerThread.Id,
+ ini: struct {
+ zir_index: TrackedInst.Index,
+ captures: []const CaptureValue,
+
+ // If the value of any of the following fields would change on an incremental update, then logic
+ // in `Zcu.mapOldZirToNew` must detect that (these properties are all trivially known from ZIR)
+ // and refuse to map the type declaration. This causes `zir_index` to change so that a new type
+ // will be interned at a fresh index.
+ //
+ // In the future, it would be good to remove all of those fields from `ini`, and in fact just
+ // have a single function `getDeclaredContainer` which is suitable for all container types.
+ // However, this requires some major changes to how container types are represented in the
+ // InternPool, so that it is possible for their backing storage to be "reallocated" as needed
+ // during type resolution.
+ fields_len: u32,
+ layout: std.builtin.Type.ContainerLayout,
+ any_comptime_fields: bool,
+ any_field_defaults: bool,
+ any_field_aligns: bool,
+ packed_backing_mode: BackingTypeMode,
+ },
+) Allocator.Error!WipContainerType.Result {
+ var gop = try ip.getOrPutKey(gpa, io, tid, .{ .struct_type = .{ .declared = .{
+ .zir_index = ini.zir_index,
+ .captures = .{ .external = ini.captures },
+ } } });
+ defer gop.deinit();
+ if (gop == .existing) return .{ .existing = gop.existing };
+
+ const local = ip.getLocal(tid);
+ const items = local.getMutableItems(gpa, io);
+ const extra = local.getMutableExtra(gpa, io);
+ try items.ensureUnusedCapacity(1);
+
+ const field_name_map = try ip.addMap(gpa, io, tid, ini.fields_len);
+ errdefer local.mutate.maps.len -= 1;
+
+ const is_extern = switch (ini.layout) {
+ .auto => false,
+ .@"extern" => true,
+ .@"packed" => {
+ try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeStructPacked).@"struct".fields.len +
+ ini.captures.len + // capture
+ ini.fields_len + // field_name
+ ini.fields_len + // field_type
+ (if (ini.any_field_defaults) ini.fields_len else 0)); // field_default
+
+ const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStructPacked{
+ .zir_index = ini.zir_index,
+ .bits = .{
+ .captures_len = @enumFromInt(ini.captures.len),
+ .want_layout = false,
+ },
+ .name = undefined, // set by `finish`
+ .name_nav = undefined, // set by `finish`
+ .namespace = undefined, // set by `finish`
+ .backing_int_type = .none,
+ .fields_len = ini.fields_len,
+ .field_name_map = field_name_map,
+ });
+ extra.appendSliceAssumeCapacity(.{@ptrCast(ini.captures)}); // capture
+ extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name
+ extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type
+ if (ini.any_field_defaults) {
+ extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_default
+ }
+ items.appendAssumeCapacity(.{
+ .tag = switch (ini.packed_backing_mode) {
+ .auto => if (ini.any_field_defaults) .type_struct_packed_auto_defaults else .type_struct_packed_auto,
+ .explicit => if (ini.any_field_defaults) .type_struct_packed_explicit_defaults else .type_struct_packed_explicit,
+ },
+ .data = extra_index,
+ });
+ return .{ .wip = .{
+ .index = gop.put(),
+ .tid = tid,
+ .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?,
+ .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name_nav").?,
+ .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?,
+ .field_names = undefined,
+ .field_types = undefined,
+ .field_values = undefined,
+ .field_aligns = undefined,
+ .field_is_comptime_bits = undefined,
+ } };
+ },
+ };
+
+ try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeStruct).@"struct".fields.len +
+ 1 + // captures_len
+ ini.captures.len + // capture
+ ini.fields_len + // field_name
+ ini.fields_len + // field_type
+ (if (ini.any_field_defaults) ini.fields_len else 0) + // field_default
+ (if (ini.any_field_aligns) (ini.fields_len + 3) / 4 else 0) + // field_align
+ (if (ini.any_comptime_fields) (ini.fields_len + 31) / 32 else 0) + // field_is_comptime_bits
+ (if (!is_extern) ini.fields_len else 0) + // field_runtime_order
+ ini.fields_len); // field_offset
+
+ const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStruct{
+ .zir_index = ini.zir_index,
+ .name = undefined, // set by `finish`
+ .name_nav = undefined, // set by `finish`
+ .namespace = undefined, // set by `finish`
+ .fields_len = ini.fields_len,
+ .field_name_map = field_name_map,
+ .size = 0,
+ .flags = .{
+ .any_captures = if (ini.captures.len != 0) .true else .false,
+ .layout = if (is_extern) .@"extern" else .auto,
+ .any_comptime_fields = ini.any_comptime_fields,
+ .any_field_defaults = ini.any_field_defaults,
+ .any_field_aligns = ini.any_field_aligns,
+ .class = .no_possible_value,
+ .alignment = .none,
+ .want_layout = false,
+ },
+ });
+ if (ini.captures.len != 0) {
+ extra.appendAssumeCapacity(.{@intCast(ini.captures.len)}); // captures_len
+ extra.appendSliceAssumeCapacity(.{@ptrCast(ini.captures)}); // capture
+ }
+ extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name
+ extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type
+ if (ini.any_field_defaults) {
+ extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_default
+ }
+ if (ini.any_field_aligns) {
+ extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 3) / 4); // field_align
+ }
+ if (ini.any_comptime_fields) {
+ extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 31) / 32); // field_is_comptime_bits
+ }
+ if (!is_extern) {
+ extra.appendNTimesAssumeCapacity(.{@intFromEnum(LoadedStructType.RuntimeOrder.unresolved)}, ini.fields_len); // field_runtime_order
+ }
+ extra.appendNTimesAssumeCapacity(.{0}, ini.fields_len); // field_offset
+ items.appendAssumeCapacity(.{
+ .tag = .type_struct,
+ .data = extra_index,
+ });
+ return .{ .wip = .{
+ .index = gop.put(),
+ .tid = tid,
+ .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name").?,
+ .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name_nav").?,
+ .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?,
+ .field_names = undefined,
+ .field_types = undefined,
+ .field_values = undefined,
+ .field_aligns = undefined,
+ .field_is_comptime_bits = undefined,
+ } };
+}
+
+pub fn getReifiedStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct {
+ zir_index: TrackedInst.Index,
+ type_hash: u64,
+ fields_len: u32,
+ layout: std.builtin.Type.ContainerLayout,
+ any_comptime_fields: bool,
+ any_field_defaults: bool,
+ any_field_aligns: bool,
+ /// Explicitly specified backing int type. `.none` if not packed or if backing type is inferred.
+ packed_backing_int_type: Index,
+}) Allocator.Error!WipContainerType.Result {
+ var gop = try ip.getOrPutKey(gpa, io, tid, .{ .struct_type = .{ .reified = .{
+ .zir_index = ini.zir_index,
+ .type_hash = ini.type_hash,
+ } } });
+ defer gop.deinit();
+ if (gop == .existing) return .{ .existing = gop.existing };
+
+ const local = ip.getLocal(tid);
+ const items = local.getMutableItems(gpa, io);
+ const extra = local.getMutableExtra(gpa, io);
+ try items.ensureUnusedCapacity(1);
+
+ const field_name_map = try ip.addMap(gpa, io, tid, ini.fields_len);
+ errdefer local.mutate.maps.len -= 1;
+
+ const is_extern = switch (ini.layout) {
+ .auto => false,
+ .@"extern" => true,
+ .@"packed" => {
+ try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeStructPacked).@"struct".fields.len +
+ 2 + // type_hash
+ ini.fields_len + // field_name
+ ini.fields_len + // field_type
+ (if (ini.any_field_defaults) ini.fields_len else 0)); // field_default
+
+ const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStructPacked{
+ .zir_index = ini.zir_index,
+ .bits = .{
+ .captures_len = .reified,
+ .want_layout = false,
+ },
+ .name = undefined, // set by `finish`
+ .name_nav = undefined, // set by `finish`
+ .namespace = undefined, // set by `finish`
+ .backing_int_type = ini.packed_backing_int_type,
+ .fields_len = ini.fields_len,
+ .field_name_map = field_name_map,
+ });
+ _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash)); // type_hash
+ const field_names_start = extra.mutate.len;
+ extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name
+ const field_types_start = extra.mutate.len;
+ extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type
+ const field_defaults_start = extra.mutate.len;
+ if (ini.any_field_defaults) {
+ extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_default
+ }
+ items.appendAssumeCapacity(.{
+ .tag = switch (ini.packed_backing_int_type) {
+ .none => if (ini.any_field_defaults) .type_struct_packed_auto_defaults else .type_struct_packed_auto,
+ else => if (ini.any_field_defaults) .type_struct_packed_explicit_defaults else .type_struct_packed_explicit,
+ },
+ .data = extra_index,
+ });
+ return .{ .wip = .{
+ .index = gop.put(),
+ .tid = tid,
+ .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?,
+ .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name_nav").?,
+ .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?,
+ .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len },
+ .field_types = .{ .tid = tid, .start = field_types_start, .len = ini.fields_len },
+ .field_values = if (ini.any_field_defaults)
+ .{ .tid = tid, .start = field_defaults_start, .len = ini.fields_len }
+ else
+ undefined,
+ .field_aligns = undefined,
+ .field_is_comptime_bits = undefined,
+ } };
+ },
+ };
+
+ try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeStruct).@"struct".fields.len +
+ 2 + // type_hash
+ ini.fields_len + // field_name
+ ini.fields_len + // field_type
+ (if (ini.any_field_defaults) ini.fields_len else 0) + // field_default
+ (if (ini.any_field_aligns) (ini.fields_len + 3) / 4 else 0) + // field_align
+ (if (ini.any_comptime_fields) (ini.fields_len + 31) / 32 else 0) + // field_is_comptime_bits
+ (if (!is_extern) ini.fields_len else 0) + // field_runtime_order
+ ini.fields_len); // field_offset
+
+ const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStruct{
+ .zir_index = ini.zir_index,
+ .name = undefined, // set by `finish`
+ .name_nav = undefined, // set by `finish`
+ .namespace = undefined, // set by `finish`
+ .fields_len = ini.fields_len,
+ .field_name_map = field_name_map,
+ .size = 0,
+ .flags = .{
+ .any_captures = .reified,
+ .layout = if (is_extern) .@"extern" else .auto,
+ .any_comptime_fields = ini.any_comptime_fields,
+ .any_field_defaults = ini.any_field_defaults,
+ .any_field_aligns = ini.any_field_aligns,
+ .class = .no_possible_value,
+ .alignment = .none,
+ .want_layout = false,
+ },
+ });
+ _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash)); // type_hash
+ const field_names_start = extra.mutate.len;
+ extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name
+ const field_types_start = extra.mutate.len;
+ extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type
+ const field_defaults_start = extra.mutate.len;
+ if (ini.any_field_defaults) {
+ extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_default
+ }
+ const field_aligns_start = extra.mutate.len;
+ if (ini.any_field_aligns) {
+ extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 3) / 4); // field_align
+ }
+ const field_is_comptime_bits_start = extra.mutate.len;
+ if (ini.any_comptime_fields) {
+ extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 31) / 32); // field_is_comptime_bits
+ }
+ if (!is_extern) {
+ extra.appendNTimesAssumeCapacity(.{@intFromEnum(LoadedStructType.RuntimeOrder.unresolved)}, ini.fields_len); // field_runtime_order
+ }
+ extra.appendNTimesAssumeCapacity(.{0}, ini.fields_len); // field_offset
+ items.appendAssumeCapacity(.{
+ .tag = .type_struct,
+ .data = extra_index,
+ });
+ return .{ .wip = .{
+ .index = gop.put(),
+ .tid = tid,
+ .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name").?,
+ .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name_nav").?,
+ .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?,
+ .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len },
+ .field_types = .{ .tid = tid, .start = field_types_start, .len = ini.fields_len },
+ .field_values = if (ini.any_field_defaults)
+ .{ .tid = tid, .start = field_defaults_start, .len = ini.fields_len }
+ else
+ undefined,
+ .field_aligns = if (ini.any_field_aligns)
+ .{ .tid = tid, .start = field_aligns_start, .len = ini.fields_len }
+ else
+ undefined,
+ .field_is_comptime_bits = if (ini.any_comptime_fields)
+ .{ .tid = tid, .start = field_is_comptime_bits_start, .len = (ini.fields_len + 31) / 32 }
+ else
+ undefined,
+ } };
+}
+
+pub fn getDeclaredUnionType(
+ ip: *InternPool,
+ gpa: Allocator,
+ io: Io,
+ tid: Zcu.PerThread.Id,
+ ini: struct {
+ zir_index: TrackedInst.Index,
+ captures: []const CaptureValue,
+
+ // If the value of any of the following fields would change on an incremental update, then logic
+ // in `Zcu.mapOldZirToNew` must detect that (these properties are all trivially known from ZIR)
+ // and refuse to map the type declaration. This causes `zir_index` to change so that a new type
+ // will be interned at a fresh index.
+ //
+ // In the future, it would be good to remove all of those fields from `ini`, and in fact just
+ // have a single function `getDeclaredContainer` which is suitable for all container types.
+ // However, this requires some major changes to how container types are represented in the
+ // InternPool, so that it is possible for their backing storage to be "reallocated" as needed
+ // during type resolution.
+ fields_len: u32,
+ layout: std.builtin.Type.ContainerLayout,
+ any_field_aligns: bool,
+ tag_usage: LoadedUnionType.TagUsage,
+ enum_tag_mode: BackingTypeMode,
+ packed_backing_mode: BackingTypeMode,
+ },
+) Allocator.Error!WipContainerType.Result {
+ var gop = try ip.getOrPutKey(gpa, io, tid, .{ .union_type = .{ .declared = .{
+ .zir_index = ini.zir_index,
+ .captures = .{ .external = ini.captures },
+ } } });
+ defer gop.deinit();
+ if (gop == .existing) return .{ .existing = gop.existing };
+
+ const local = ip.getLocal(tid);
+ const items = local.getMutableItems(gpa, io);
+ const extra = local.getMutableExtra(gpa, io);
+ try items.ensureUnusedCapacity(1);
+
+ const is_extern = switch (ini.layout) {
+ .auto => false,
+ .@"extern" => true,
+ .@"packed" => {
+ try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeUnionPacked).@"struct".fields.len +
+ ini.captures.len + // capture
+ ini.fields_len); // field_type
+
+ const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnionPacked{
+ .zir_index = ini.zir_index,
+ .bits = .{
+ .captures_len = @enumFromInt(ini.captures.len),
+ .want_layout = false,
+ },
+ .name = undefined, // set by `finish`
+ .name_nav = undefined, // set by `finish`
+ .namespace = undefined, // set by `finish`
+ .backing_int_type = .none,
+ .enum_tag_type = .none,
+ .fields_len = ini.fields_len,
+ });
+ extra.appendSliceAssumeCapacity(.{@ptrCast(ini.captures)}); // capture
+ extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type
+ items.appendAssumeCapacity(.{
+ .tag = switch (ini.packed_backing_mode) {
+ .auto => .type_union_packed_auto,
+ .explicit => .type_union_packed_explicit,
+ },
+ .data = extra_index,
+ });
+ return .{ .wip = .{
+ .index = gop.put(),
+ .tid = tid,
+ .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name").?,
+ .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name_nav").?,
+ .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "namespace").?,
+ .field_names = undefined,
+ .field_types = undefined,
+ .field_values = undefined,
+ .field_aligns = undefined,
+ .field_is_comptime_bits = undefined,
+ } };
+ },
+ };
+
+ try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeUnion).@"struct".fields.len +
+ 1 + // captures_len
+ ini.captures.len + // capture
+ ini.fields_len + // field_type
+ (if (ini.any_field_aligns) (ini.fields_len + 3) / 4 else 0)); // field_align
+
+ const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnion{
+ .zir_index = ini.zir_index,
+ .name = undefined, // set by `finish`
+ .name_nav = undefined, // set by `finish`
+ .namespace = undefined, // set by `finish`
+ .enum_tag_type = .none,
+ .fields_len = ini.fields_len,
+ .size = 0,
+ .padding = 0,
+ .flags = .{
+ .any_captures = if (ini.captures.len != 0) .true else .false,
+ .enum_tag_mode = ini.enum_tag_mode,
+ .layout = if (is_extern) .@"extern" else .auto,
+ .any_field_aligns = ini.any_field_aligns,
+ .tag_usage = ini.tag_usage,
+ .class = .no_possible_value,
+ .has_runtime_tag = false,
+ .alignment = .none,
+ .want_layout = false,
+ },
+ });
+ if (ini.captures.len > 0) {
+ extra.appendAssumeCapacity(.{@intCast(ini.captures.len)}); // captures_len
+ extra.appendSliceAssumeCapacity(.{@ptrCast(ini.captures)}); // capture
+ }
+ extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type
+ if (ini.any_field_aligns) {
+ extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 3) / 4); // field_align
+ }
+ items.appendAssumeCapacity(.{
+ .tag = .type_union,
+ .data = extra_index,
+ });
+ return .{ .wip = .{
+ .index = gop.put(),
+ .tid = tid,
+ .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name").?,
+ .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name_nav").?,
+ .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?,
+ .field_names = undefined,
+ .field_types = undefined,
+ .field_values = undefined,
+ .field_aligns = undefined,
+ .field_is_comptime_bits = undefined,
+ } };
+}
+
+pub fn getReifiedUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct {
+ zir_index: TrackedInst.Index,
+ type_hash: u64,
+ fields_len: u32,
+ layout: std.builtin.Type.ContainerLayout,
+ any_field_aligns: bool,
+ tag_usage: LoadedUnionType.TagUsage,
+ /// Explicitly specified enum tag type. `.none` if `tag_usage != .tagged`.
+ enum_tag_type: Index,
+ /// Explicitly specified backing int type. `.none` if not packed or if backing type is inferred.
+ packed_backing_int_type: Index,
+}) Allocator.Error!WipContainerType.Result {
+ var gop = try ip.getOrPutKey(gpa, io, tid, .{ .union_type = .{ .reified = .{
+ .zir_index = ini.zir_index,
+ .type_hash = ini.type_hash,
+ } } });
+ defer gop.deinit();
+ if (gop == .existing) return .{ .existing = gop.existing };
+
+ const local = ip.getLocal(tid);
+ const items = local.getMutableItems(gpa, io);
+ const extra = local.getMutableExtra(gpa, io);
+ try items.ensureUnusedCapacity(1);
+
+ const is_extern = switch (ini.layout) {
+ .auto => false,
+ .@"extern" => true,
+ .@"packed" => {
+ try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeUnionPacked).@"struct".fields.len +
+ 2 + // type_hash
+ ini.fields_len + // reified_field_name
+ ini.fields_len); // field_type
+
+ const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnionPacked{
+ .zir_index = ini.zir_index,
+ .bits = .{
+ .captures_len = .reified,
+ .want_layout = false,
+ },
+ .name = undefined, // set by `finish`
+ .name_nav = undefined, // set by `finish`
+ .namespace = undefined, // set by `finish`
+ .backing_int_type = ini.packed_backing_int_type,
+ .enum_tag_type = .none,
+ .fields_len = ini.fields_len,
+ });
+ _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash)); // type_hash
+ const field_names_start = extra.mutate.len;
+ extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // reified_field_name
+ const field_types_start = extra.mutate.len;
+ extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type
+ items.appendAssumeCapacity(.{
+ .tag = switch (ini.packed_backing_int_type) {
+ .none => .type_union_packed_auto,
+ else => .type_union_packed_explicit,
+ },
+ .data = extra_index,
+ });
+ return .{ .wip = .{
+ .index = gop.put(),
+ .tid = tid,
+ .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name").?,
+ .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name_nav").?,
+ .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "namespace").?,
+ .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len },
+ .field_types = .{ .tid = tid, .start = field_types_start, .len = ini.fields_len },
+ .field_values = undefined,
+ .field_aligns = undefined,
+ .field_is_comptime_bits = undefined,
+ } };
+ },
+ };
+
+ try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeUnion).@"struct".fields.len +
+ 2 + // type_hash
+ ini.fields_len + // reified_field_name
+ ini.fields_len + // field_type
+ (if (ini.any_field_aligns) (ini.fields_len + 3) / 4 else 0)); // field_align
+
+ const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnion{
+ .zir_index = ini.zir_index,
+ .name = undefined, // set by `finish`
+ .name_nav = undefined, // set by `finish`
+ .namespace = undefined, // set by `finish`
+ .enum_tag_type = ini.enum_tag_type,
+ .fields_len = ini.fields_len,
+ .size = 0,
+ .padding = 0,
+ .flags = .{
+ .any_captures = .reified,
+ .enum_tag_mode = if (ini.enum_tag_type == .none) .auto else .explicit,
+ .layout = if (is_extern) .@"extern" else .auto,
+ .any_field_aligns = ini.any_field_aligns,
+ .tag_usage = ini.tag_usage,
+ .class = .no_possible_value,
+ .has_runtime_tag = false,
+ .alignment = .none,
+ .want_layout = false,
+ },
+ });
+ _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash));
+ const field_names_start = extra.mutate.len;
+ extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // reified_field_name
+ const field_types_start = extra.mutate.len;
+ extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type
+ const field_aligns_start = extra.mutate.len;
+ if (ini.any_field_aligns) {
+ extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 3) / 4); // field_align
+ }
+ items.appendAssumeCapacity(.{
+ .tag = .type_union,
+ .data = extra_index,
+ });
+ return .{ .wip = .{
+ .index = gop.put(),
+ .tid = tid,
+ .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name").?,
+ .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name_nav").?,
+ .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?,
+ .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len },
+ .field_types = .{ .tid = tid, .start = field_types_start, .len = ini.fields_len },
+ .field_values = undefined,
+ .field_aligns = if (ini.any_field_aligns)
+ .{ .tid = tid, .start = field_aligns_start, .len = ini.fields_len }
+ else
+ undefined,
+ .field_is_comptime_bits = undefined,
+ } };
+}
+
+pub fn getDeclaredEnumType(
+ ip: *InternPool,
+ gpa: Allocator,
+ io: Io,
+ tid: Zcu.PerThread.Id,
+ ini: struct {
+ zir_index: TrackedInst.Index,
+ captures: []const CaptureValue,
+
+ // If the value of any of the following fields would change on an incremental update, then logic
+ // in `Zcu.mapOldZirToNew` must detect that (these properties are all trivially known from ZIR)
+ // and refuse to map the type declaration. This causes `zir_index` to change so that a new type
+ // will be interned at a fresh index.
+ //
+ // In the future, it would be good to remove all of those fields from `ini`, and in fact just
+ // have a single function `getDeclaredContainer` which is suitable for all container types.
+ // However, this requires some major changes to how container types are represented in the
+ // InternPool, so that it is possible for their backing storage to be "reallocated" as needed
+ // during type resolution.
+ fields_len: u32,
+ nonexhaustive: bool,
+ /// For `enum(T)` this is `.explicit`. Otherwise this is `.none`.
+ int_tag_mode: BackingTypeMode,
+ },
+) Allocator.Error!WipContainerType.Result {
+ var gop = try ip.getOrPutKey(gpa, io, tid, .{ .enum_type = .{ .declared = .{
+ .zir_index = ini.zir_index,
+ .captures = .{ .external = ini.captures },
+ } } });
+ defer gop.deinit();
+ if (gop == .existing) return .{ .existing = gop.existing };
+
+ const local = ip.getLocal(tid);
+ const items = local.getMutableItems(gpa, io);
+ const extra = local.getMutableExtra(gpa, io);
+ try items.ensureUnusedCapacity(1);
+
+ const tag: Tag, const have_values: bool = if (ini.nonexhaustive)
+ .{ .type_enum_nonexhaustive, true }
+ else if (ini.int_tag_mode == .explicit)
+ .{ .type_enum_explicit, true }
+ else
+ .{ .type_enum_auto, false };
+
+ const field_name_map = try ip.addMap(gpa, io, tid, ini.fields_len);
+ errdefer local.mutate.maps.len -= 1;
+
+ const field_value_map = if (have_values) try ip.addMap(gpa, io, tid, ini.fields_len) else undefined;
+ errdefer local.mutate.maps.len -= @intFromBool(have_values);
+
+ try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeEnum).@"struct".fields.len +
+ 1 + // zir_index
+ ini.captures.len + // capture
+ @intFromBool(have_values) + // field_value_map
+ ini.fields_len + // field_name
+ (if (have_values) ini.fields_len else 0)); // field_value
+
+ const extra_index = addExtraAssumeCapacity(extra, Tag.TypeEnum{
+ .bits = .{
+ .captures_len = @enumFromInt(ini.captures.len),
+ .want_layout = false,
+ },
+ .name = undefined, // set by `finish`
+ .name_nav = undefined, // set by `finish`
+ .namespace = undefined, // set by `finish`
+ .int_tag_type = .none,
+ .fields_len = ini.fields_len,
+ .field_name_map = field_name_map,
+ });
+ extra.appendAssumeCapacity(.{@intFromEnum(ini.zir_index)}); // zir_index
+ extra.appendSliceAssumeCapacity(.{@ptrCast(ini.captures)}); // capture
+ if (have_values) extra.appendAssumeCapacity(.{@intFromEnum(field_value_map)}); // field_value_map
+ extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name
+ if (have_values) extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_value
+ items.appendAssumeCapacity(.{
+ .tag = tag,
+ .data = extra_index,
+ });
+ return .{ .wip = .{
+ .index = gop.put(),
+ .tid = tid,
+ .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name").?,
+ .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name_nav").?,
+ .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "namespace").?,
+ .field_names = undefined,
+ .field_types = undefined,
+ .field_values = undefined,
+ .field_aligns = undefined,
+ .field_is_comptime_bits = undefined,
+ } };
+}
+
+pub fn getReifiedEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct {
+ zir_index: TrackedInst.Index,
+ type_hash: u64,
+ fields_len: u32,
+ nonexhaustive: bool,
+ /// Explicitly specified int tag type, or `.none` if the int tag type is inferred.
+ int_tag_type: Index,
+}) Allocator.Error!WipContainerType.Result {
+ var gop = try ip.getOrPutKey(gpa, io, tid, .{ .enum_type = .{ .reified = .{
+ .zir_index = ini.zir_index,
+ .type_hash = ini.type_hash,
+ } } });
+ defer gop.deinit();
+ if (gop == .existing) return .{ .existing = gop.existing };
+
+ const local = ip.getLocal(tid);
+ const items = local.getMutableItems(gpa, io);
+ const extra = local.getMutableExtra(gpa, io);
+ try items.ensureUnusedCapacity(1);
+
+ const tag: Tag, const have_values: bool = if (ini.nonexhaustive)
+ .{ .type_enum_nonexhaustive, true }
+ else if (ini.int_tag_type != .none)
+ .{ .type_enum_explicit, true }
+ else
+ .{ .type_enum_auto, false };
+
+ const field_name_map = try ip.addMap(gpa, io, tid, ini.fields_len);
+ errdefer local.mutate.maps.len -= 1;
+
+ const field_value_map = if (have_values) try ip.addMap(gpa, io, tid, ini.fields_len) else undefined;
+ errdefer local.mutate.maps.len -= @intFromBool(have_values);
+
+ try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeEnum).@"struct".fields.len +
+ 1 + // zir_index
+ 2 + // type_hash
+ @intFromBool(have_values) + // field_value_map
+ ini.fields_len + // field_name
+ (if (have_values) ini.fields_len else 0)); // field_value
+
+ const extra_index = addExtraAssumeCapacity(extra, Tag.TypeEnum{
+ .bits = .{
+ .captures_len = .reified,
+ .want_layout = false,
+ },
+ .name = undefined, // set by `finish`
+ .name_nav = undefined, // set by `finish`
+ .namespace = undefined, // set by `finish`
+ .int_tag_type = ini.int_tag_type,
+ .fields_len = ini.fields_len,
+ .field_name_map = field_name_map,
+ });
+ extra.appendAssumeCapacity(.{@intFromEnum(ini.zir_index)}); // zir_index
+ _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash)); // type_hash
+ if (have_values) extra.appendAssumeCapacity(.{@intFromEnum(field_value_map)}); // field_value_map
+ const field_names_start = extra.mutate.len;
+ extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name
+ const field_values_start = extra.mutate.len;
+ if (have_values) extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_value
+ items.appendAssumeCapacity(.{
+ .tag = tag,
+ .data = extra_index,
+ });
+ return .{ .wip = .{
+ .index = gop.put(),
+ .tid = tid,
+ .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name").?,
+ .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name_nav").?,
+ .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "namespace").?,
+ .field_names = .{ .tid = tid, .start = field_names_start, .len = ini.fields_len },
+ .field_types = undefined,
+ .field_values = if (have_values)
+ .{ .tid = tid, .start = field_values_start, .len = ini.fields_len }
+ else
+ undefined,
+ .field_aligns = undefined,
+ .field_is_comptime_bits = undefined,
+ } };
+}
+
+pub fn getGeneratedEnumTagType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct {
+ /// The union type for which this enum is a generated tag.
+ union_type: Index,
+ /// For `union(enum(T))` this is `.explicit`. Otherwise this is `.none`.
+ int_tag_mode: BackingTypeMode,
+ fields_len: u32,
+}) Allocator.Error!WipContainerType.Result {
+ var gop = try ip.getOrPutKey(gpa, io, tid, .{ .enum_type = .{ .generated_union_tag = ini.union_type } });
+ defer gop.deinit();
+ if (gop == .existing) return .{ .existing = gop.existing };
+
+ const local = ip.getLocal(tid);
+ const items = local.getMutableItems(gpa, io);
+ const extra = local.getMutableExtra(gpa, io);
+ try items.ensureUnusedCapacity(1);
+
+ const field_name_map = try ip.addMap(gpa, io, tid, ini.fields_len);
+ errdefer local.mutate.maps.len -= 1;
+
+ const have_values = switch (ini.int_tag_mode) {
+ .explicit => true,
+ .auto => false,
+ };
+
+ const field_value_map = if (have_values) try ip.addMap(gpa, io, tid, ini.fields_len) else undefined;
+ errdefer local.mutate.maps.len -= @intFromBool(have_values);
+
+ try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeEnum).@"struct".fields.len +
+ 1 + // owner_union
+ @intFromBool(have_values) + // field_value_map
+ ini.fields_len + // field_name
+ (if (have_values) ini.fields_len else 0)); // field_value
+
+ const extra_index = addExtraAssumeCapacity(extra, Tag.TypeEnum{
+ .bits = .{
+ .captures_len = .generated_union_tag,
+ .want_layout = false,
+ },
+ .name = undefined, // set by `finish`
+ .name_nav = undefined, // set by `finish`
+ .namespace = undefined, // set by `finish`
+ .int_tag_type = .none,
+ .fields_len = ini.fields_len,
+ .field_name_map = field_name_map,
+ });
+ extra.appendAssumeCapacity(.{@intFromEnum(ini.union_type)}); // owner_union
+ if (have_values) extra.appendAssumeCapacity(.{@intFromEnum(field_value_map)});
+ extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name
+ if (have_values) extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_value
+ items.appendAssumeCapacity(.{
+ .tag = switch (ini.int_tag_mode) {
+ .auto => .type_enum_auto,
+ .explicit => .type_enum_explicit,
+ },
+ .data = extra_index,
+ });
+ return .{ .wip = .{
+ .index = gop.put(),
+ .tid = tid,
+ .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name").?,
+ .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name_nav").?,
+ .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "namespace").?,
+ .field_names = undefined,
+ .field_types = undefined,
+ .field_values = undefined,
+ .field_aligns = undefined,
+ .field_is_comptime_bits = undefined,
+ } };
+}
+
+pub fn getDeclaredOpaqueType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct {
+ zir_index: TrackedInst.Index,
+ captures: []const CaptureValue,
+}) Allocator.Error!WipContainerType.Result {
+ var gop = try ip.getOrPutKey(gpa, io, tid, .{ .opaque_type = .{ .declared = .{
+ .zir_index = ini.zir_index,
+ .captures = .{ .external = ini.captures },
+ } } });
+ defer gop.deinit();
+ if (gop == .existing) return .{ .existing = gop.existing };
+
+ const local = ip.getLocal(tid);
+ const items = local.getMutableItems(gpa, io);
+ const extra = local.getMutableExtra(gpa, io);
+ try items.ensureUnusedCapacity(1);
+
+ try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeOpaque).@"struct".fields.len + ini.captures.len);
+ const extra_index = addExtraAssumeCapacity(extra, Tag.TypeOpaque{
+ .zir_index = ini.zir_index,
+ .captures_len = @intCast(ini.captures.len),
+ .name = undefined, // set by `finish`
+ .name_nav = undefined, // set by `finish`
+ .namespace = undefined, // set by `finish`
+ });
+ extra.appendSliceAssumeCapacity(.{@ptrCast(ini.captures)});
+ items.appendAssumeCapacity(.{
+ .tag = .type_opaque,
+ .data = extra_index,
+ });
+ return .{ .wip = .{
+ .index = gop.put(),
+ .tid = tid,
+ .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name").?,
+ .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name_nav").?,
+ .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "namespace").?,
+ .field_names = undefined,
+ .field_types = undefined,
+ .field_values = undefined,
+ .field_aligns = undefined,
+ .field_is_comptime_bits = undefined,
+ } };
+}
+
+pub const WipContainerType = struct {
+ index: Index,
+ tid: Zcu.PerThread.Id,
+ type_name_index: u32,
+ name_nav_index: u32,
+ namespace_index: u32,
+
+ // These fields are only populated when creating reified types, because reified types populate
+ // field information immediately, with type resolution only handling validation. This is in
+ // contrast to declared types, where field information is populated by the type resolution
+ // process evaluating ZIR expressions.
+ field_names: NullTerminatedString.Slice,
+ field_types: Index.Slice,
+ field_values: Index.Slice,
+ field_aligns: Alignment.Slice,
+ field_is_comptime_bits: LoadedStructType.ComptimeBits,
+
+ pub fn setName(
+ wip: WipContainerType,
+ ip: *InternPool,
+ type_name: NullTerminatedString,
+ /// This should be the `Nav` we are named after if we use the `.parent` name strategy; `.none` otherwise.
+ /// This is also `.none` if we use `.parent` because we are the root struct type for a file.
+ name_nav: Nav.Index.Optional,
+ ) void {
+ const extra = ip.getLocalShared(wip.tid).extra.acquire();
+ const extra_items = extra.view().items(.@"0");
+ extra_items[wip.type_name_index] = @intFromEnum(type_name);
+ extra_items[wip.name_nav_index] = @intFromEnum(name_nav);
+ }
+
+ pub fn finish(
+ wip: WipContainerType,
+ ip: *InternPool,
+ namespace: NamespaceIndex,
+ ) Index {
+ const extra = ip.getLocalShared(wip.tid).extra.acquire();
+ const extra_items = extra.view().items(.@"0");
+
+ extra_items[wip.namespace_index] = @intFromEnum(namespace);
+
+ return wip.index;
+ }
+
+ pub fn cancel(wip: WipContainerType, ip: *InternPool, tid: Zcu.PerThread.Id) void {
+ ip.remove(tid, wip.index);
+ }
+
+ pub const Result = union(enum) {
+ wip: WipContainerType,
+ existing: Index,
+ };
+};
+
pub fn getUnion(
ip: *InternPool,
gpa: Allocator,
@@ -8742,16 +9066,18 @@ pub fn getUnion(
tid: Zcu.PerThread.Id,
un: Key.Union,
) Allocator.Error!Index {
- var gop = try ip.getOrPutKey(gpa, io, tid, .{ .un = un });
- defer gop.deinit();
- if (gop == .existing) return gop.existing;
- const local = ip.getLocal(tid);
- const items = local.getMutableItems(gpa, io);
- const extra = local.getMutableExtra(gpa, io);
- try items.ensureUnusedCapacity(1);
-
assert(un.ty != .none);
assert(un.val != .none);
+ assert(ip.loadUnionType(un.ty).layout != .@"packed");
+
+ var gop = try ip.getOrPutKey(gpa, io, tid, .{ .un = un });
+ defer gop.deinit();
+ if (gop == .existing) return gop.existing;
+ const local = ip.getLocal(tid);
+ const items = local.getMutableItems(gpa, io);
+ const extra = local.getMutableExtra(gpa, io);
+ try items.ensureUnusedCapacity(1);
+
items.appendAssumeCapacity(.{
.tag = .union_value,
.data = try addExtra(extra, un),
@@ -8760,440 +9086,6 @@ pub fn getUnion(
return gop.put();
}
-pub const UnionTypeInit = struct {
- flags: packed struct {
- runtime_tag: LoadedUnionType.RuntimeTag,
- any_aligned_fields: bool,
- layout: std.builtin.Type.ContainerLayout,
- status: LoadedUnionType.Status,
- requires_comptime: RequiresComptime,
- assumed_runtime_bits: bool,
- assumed_pointer_aligned: bool,
- alignment: Alignment,
- },
- fields_len: u32,
- enum_tag_ty: Index,
- /// May have length 0 which leaves the values unset until later.
- field_types: []const Index,
- /// May have length 0 which leaves the values unset until later.
- /// The logic for `any_aligned_fields` is asserted to have been done before
- /// calling this function.
- field_aligns: []const Alignment,
- key: union(enum) {
- declared: struct {
- zir_index: TrackedInst.Index,
- captures: []const CaptureValue,
- },
- declared_owned_captures: struct {
- zir_index: TrackedInst.Index,
- captures: CaptureValue.Slice,
- },
- reified: struct {
- zir_index: TrackedInst.Index,
- type_hash: u64,
- },
- },
-};
-
-pub fn getUnionType(
- ip: *InternPool,
- gpa: Allocator,
- io: Io,
- tid: Zcu.PerThread.Id,
- ini: UnionTypeInit,
- /// If it is known that there is an existing type with this key which is outdated,
- /// this is passed as `true`, and the type is replaced with one at a fresh index.
- replace_existing: bool,
-) Allocator.Error!WipNamespaceType.Result {
- const key: Key = .{ .union_type = switch (ini.key) {
- .declared => |d| .{ .declared = .{
- .zir_index = d.zir_index,
- .captures = .{ .external = d.captures },
- } },
- .declared_owned_captures => |d| .{ .declared = .{
- .zir_index = d.zir_index,
- .captures = .{ .owned = d.captures },
- } },
- .reified => |r| .{ .reified = .{
- .zir_index = r.zir_index,
- .type_hash = r.type_hash,
- } },
- } };
- var gop = if (replace_existing)
- ip.putKeyReplace(io, tid, key)
- else
- try ip.getOrPutKey(gpa, io, tid, key);
- defer gop.deinit();
- if (gop == .existing) return .{ .existing = gop.existing };
-
- const local = ip.getLocal(tid);
- const items = local.getMutableItems(gpa, io);
- try items.ensureUnusedCapacity(1);
- const extra = local.getMutableExtra(gpa, io);
-
- const align_elements_len = if (ini.flags.any_aligned_fields) (ini.fields_len + 3) / 4 else 0;
- const align_element: u32 = @bitCast([1]u8{@intFromEnum(Alignment.none)} ** 4);
- try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeUnion).@"struct".fields.len +
- // TODO: fmt bug
- // zig fmt: off
- switch (ini.key) {
- inline .declared, .declared_owned_captures => |d| @intFromBool(d.captures.len != 0) + d.captures.len,
- .reified => 2, // type_hash: PackedU64
- } +
- // zig fmt: on
- ini.fields_len + // field types
- align_elements_len);
-
- const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnion{
- .flags = .{
- .any_captures = switch (ini.key) {
- inline .declared, .declared_owned_captures => |d| d.captures.len != 0,
- .reified => false,
- },
- .runtime_tag = ini.flags.runtime_tag,
- .any_aligned_fields = ini.flags.any_aligned_fields,
- .layout = ini.flags.layout,
- .status = ini.flags.status,
- .requires_comptime = ini.flags.requires_comptime,
- .assumed_runtime_bits = ini.flags.assumed_runtime_bits,
- .assumed_pointer_aligned = ini.flags.assumed_pointer_aligned,
- .alignment = ini.flags.alignment,
- .is_reified = switch (ini.key) {
- .declared, .declared_owned_captures => false,
- .reified => true,
- },
- },
- .fields_len = ini.fields_len,
- .size = std.math.maxInt(u32),
- .padding = std.math.maxInt(u32),
- .name = undefined, // set by `finish`
- .name_nav = undefined, // set by `finish`
- .namespace = undefined, // set by `finish`
- .tag_ty = ini.enum_tag_ty,
- .zir_index = switch (ini.key) {
- inline else => |x| x.zir_index,
- },
- });
-
- items.appendAssumeCapacity(.{
- .tag = .type_union,
- .data = extra_index,
- });
-
- switch (ini.key) {
- .declared => |d| if (d.captures.len != 0) {
- extra.appendAssumeCapacity(.{@intCast(d.captures.len)});
- extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)});
- },
- .declared_owned_captures => |d| if (d.captures.len != 0) {
- extra.appendAssumeCapacity(.{@intCast(d.captures.len)});
- extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))});
- },
- .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)),
- }
-
- // field types
- if (ini.field_types.len > 0) {
- assert(ini.field_types.len == ini.fields_len);
- extra.appendSliceAssumeCapacity(.{@ptrCast(ini.field_types)});
- } else {
- extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len);
- }
-
- // field alignments
- if (ini.flags.any_aligned_fields) {
- extra.appendNTimesAssumeCapacity(.{align_element}, align_elements_len);
- if (ini.field_aligns.len > 0) {
- assert(ini.field_aligns.len == ini.fields_len);
- @memcpy((Alignment.Slice{
- .tid = tid,
- .start = @intCast(extra.mutate.len - align_elements_len),
- .len = @intCast(ini.field_aligns.len),
- }).get(ip), ini.field_aligns);
- }
- } else {
- assert(ini.field_aligns.len == 0);
- }
-
- return .{ .wip = .{
- .tid = tid,
- .index = gop.put(),
- .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name").?,
- .name_nav_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name_nav").?,
- .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?,
- } };
-}
-
-pub const WipNamespaceType = struct {
- tid: Zcu.PerThread.Id,
- index: Index,
- type_name_extra_index: u32,
- namespace_extra_index: u32,
- name_nav_extra_index: u32,
-
- pub fn setName(
- wip: WipNamespaceType,
- ip: *InternPool,
- type_name: NullTerminatedString,
- /// This should be the `Nav` we are named after if we use the `.parent` name strategy; `.none` otherwise.
- /// This is also `.none` if we use `.parent` because we are the root struct type for a file.
- name_nav: Nav.Index.Optional,
- ) void {
- const extra = ip.getLocalShared(wip.tid).extra.acquire();
- const extra_items = extra.view().items(.@"0");
- extra_items[wip.type_name_extra_index] = @intFromEnum(type_name);
- extra_items[wip.name_nav_extra_index] = @intFromEnum(name_nav);
- }
-
- pub fn finish(
- wip: WipNamespaceType,
- ip: *InternPool,
- namespace: NamespaceIndex,
- ) Index {
- const extra = ip.getLocalShared(wip.tid).extra.acquire();
- const extra_items = extra.view().items(.@"0");
-
- extra_items[wip.namespace_extra_index] = @intFromEnum(namespace);
-
- return wip.index;
- }
-
- pub fn cancel(wip: WipNamespaceType, ip: *InternPool, tid: Zcu.PerThread.Id) void {
- ip.remove(tid, wip.index);
- }
-
- pub const Result = union(enum) {
- wip: WipNamespaceType,
- existing: Index,
- };
-};
-
-pub const StructTypeInit = struct {
- layout: std.builtin.Type.ContainerLayout,
- fields_len: u32,
- known_non_opv: bool,
- requires_comptime: RequiresComptime,
- any_comptime_fields: bool,
- any_default_inits: bool,
- inits_resolved: bool,
- any_aligned_fields: bool,
- key: union(enum) {
- declared: struct {
- zir_index: TrackedInst.Index,
- captures: []const CaptureValue,
- },
- declared_owned_captures: struct {
- zir_index: TrackedInst.Index,
- captures: CaptureValue.Slice,
- },
- reified: struct {
- zir_index: TrackedInst.Index,
- type_hash: u64,
- },
- },
-};
-
-pub fn getStructType(
- ip: *InternPool,
- gpa: Allocator,
- io: Io,
- tid: Zcu.PerThread.Id,
- ini: StructTypeInit,
- /// If it is known that there is an existing type with this key which is outdated,
- /// this is passed as `true`, and the type is replaced with one at a fresh index.
- replace_existing: bool,
-) Allocator.Error!WipNamespaceType.Result {
- const key: Key = .{ .struct_type = switch (ini.key) {
- .declared => |d| .{ .declared = .{
- .zir_index = d.zir_index,
- .captures = .{ .external = d.captures },
- } },
- .declared_owned_captures => |d| .{ .declared = .{
- .zir_index = d.zir_index,
- .captures = .{ .owned = d.captures },
- } },
- .reified => |r| .{ .reified = .{
- .zir_index = r.zir_index,
- .type_hash = r.type_hash,
- } },
- } };
- var gop = if (replace_existing)
- ip.putKeyReplace(io, tid, key)
- else
- try ip.getOrPutKey(gpa, io, tid, key);
- defer gop.deinit();
- if (gop == .existing) return .{ .existing = gop.existing };
-
- const local = ip.getLocal(tid);
- const items = local.getMutableItems(gpa, io);
- const extra = local.getMutableExtra(gpa, io);
-
- const names_map = try ip.addMap(gpa, io, tid, ini.fields_len);
- errdefer local.mutate.maps.len -= 1;
-
- const zir_index = switch (ini.key) {
- inline else => |x| x.zir_index,
- };
-
- const is_extern = switch (ini.layout) {
- .auto => false,
- .@"extern" => true,
- .@"packed" => {
- try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeStructPacked).@"struct".fields.len +
- // TODO: fmt bug
- // zig fmt: off
- switch (ini.key) {
- inline .declared, .declared_owned_captures => |d| @intFromBool(d.captures.len != 0) + d.captures.len,
- .reified => 2, // type_hash: PackedU64
- } +
- // zig fmt: on
- ini.fields_len + // types
- ini.fields_len + // names
- ini.fields_len); // inits
- const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStructPacked{
- .name = undefined, // set by `finish`
- .name_nav = undefined, // set by `finish`
- .zir_index = zir_index,
- .fields_len = ini.fields_len,
- .namespace = undefined, // set by `finish`
- .backing_int_ty = .none,
- .names_map = names_map,
- .flags = .{
- .any_captures = switch (ini.key) {
- inline .declared, .declared_owned_captures => |d| d.captures.len != 0,
- .reified => false,
- },
- .field_inits_wip = false,
- .inits_resolved = ini.inits_resolved,
- .is_reified = switch (ini.key) {
- .declared, .declared_owned_captures => false,
- .reified => true,
- },
- },
- });
- try items.append(.{
- .tag = if (ini.any_default_inits) .type_struct_packed_inits else .type_struct_packed,
- .data = extra_index,
- });
- switch (ini.key) {
- .declared => |d| if (d.captures.len != 0) {
- extra.appendAssumeCapacity(.{@intCast(d.captures.len)});
- extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)});
- },
- .declared_owned_captures => |d| if (d.captures.len != 0) {
- extra.appendAssumeCapacity(.{@intCast(d.captures.len)});
- extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))});
- },
- .reified => |r| {
- _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash));
- },
- }
- extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len);
- extra.appendNTimesAssumeCapacity(.{@intFromEnum(OptionalNullTerminatedString.none)}, ini.fields_len);
- if (ini.any_default_inits) {
- extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len);
- }
- return .{ .wip = .{
- .tid = tid,
- .index = gop.put(),
- .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?,
- .name_nav_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name_nav").?,
- .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?,
- } };
- },
- };
-
- const align_elements_len = if (ini.any_aligned_fields) (ini.fields_len + 3) / 4 else 0;
- const align_element: u32 = @bitCast([1]u8{@intFromEnum(Alignment.none)} ** 4);
- const comptime_elements_len = if (ini.any_comptime_fields) (ini.fields_len + 31) / 32 else 0;
-
- try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeStruct).@"struct".fields.len +
- // TODO: fmt bug
- // zig fmt: off
- switch (ini.key) {
- inline .declared, .declared_owned_captures => |d| @intFromBool(d.captures.len != 0) + d.captures.len,
- .reified => 2, // type_hash: PackedU64
- } +
- // zig fmt: on
- (ini.fields_len * 5) + // types, names, inits, runtime order, offsets
- align_elements_len + comptime_elements_len +
- 1); // names_map
- const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStruct{
- .name = undefined, // set by `finish`
- .name_nav = undefined, // set by `finish`
- .zir_index = zir_index,
- .namespace = undefined, // set by `finish`
- .fields_len = ini.fields_len,
- .size = std.math.maxInt(u32),
- .flags = .{
- .any_captures = switch (ini.key) {
- inline .declared, .declared_owned_captures => |d| d.captures.len != 0,
- .reified => false,
- },
- .is_extern = is_extern,
- .known_non_opv = ini.known_non_opv,
- .requires_comptime = ini.requires_comptime,
- .assumed_runtime_bits = false,
- .assumed_pointer_aligned = false,
- .any_comptime_fields = ini.any_comptime_fields,
- .any_default_inits = ini.any_default_inits,
- .any_aligned_fields = ini.any_aligned_fields,
- .alignment = .none,
- .alignment_wip = false,
- .field_types_wip = false,
- .layout_wip = false,
- .layout_resolved = false,
- .field_inits_wip = false,
- .inits_resolved = ini.inits_resolved,
- .fully_resolved = false,
- .is_reified = switch (ini.key) {
- .declared, .declared_owned_captures => false,
- .reified => true,
- },
- },
- });
- try items.append(.{
- .tag = .type_struct,
- .data = extra_index,
- });
- switch (ini.key) {
- .declared => |d| if (d.captures.len != 0) {
- extra.appendAssumeCapacity(.{@intCast(d.captures.len)});
- extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)});
- },
- .declared_owned_captures => |d| if (d.captures.len != 0) {
- extra.appendAssumeCapacity(.{@intCast(d.captures.len)});
- extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))});
- },
- .reified => |r| {
- _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash));
- },
- }
- extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len);
- extra.appendAssumeCapacity(.{@intFromEnum(names_map)});
- extra.appendNTimesAssumeCapacity(.{@intFromEnum(OptionalNullTerminatedString.none)}, ini.fields_len);
- if (ini.any_default_inits) {
- extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len);
- }
- if (ini.any_aligned_fields) {
- extra.appendNTimesAssumeCapacity(.{align_element}, align_elements_len);
- }
- if (ini.any_comptime_fields) {
- extra.appendNTimesAssumeCapacity(.{0}, comptime_elements_len);
- }
- if (ini.layout == .auto) {
- extra.appendNTimesAssumeCapacity(.{@intFromEnum(LoadedStructType.RuntimeOrder.unresolved)}, ini.fields_len);
- }
- extra.appendNTimesAssumeCapacity(.{std.math.maxInt(u32)}, ini.fields_len);
- return .{ .wip = .{
- .tid = tid,
- .index = gop.put(),
- .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name").?,
- .name_nav_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name_nav").?,
- .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?,
- } };
-}
-
pub const TupleTypeInit = struct {
types: []const Index,
/// These elements may be `none`, indicating runtime-known.
@@ -9252,10 +9144,7 @@ pub const GetFuncTypeKey = struct {
/// `null` means generic.
cc: ?std.builtin.CallingConvention = .auto,
is_var_args: bool = false,
- is_generic: bool = false,
is_noinline: bool = false,
- section_is_generic: bool = false,
- addrspace_is_generic: bool = false,
};
pub fn getFuncType(
@@ -9293,7 +9182,6 @@ pub fn getFuncType(
.is_var_args = key.is_var_args,
.has_comptime_bits = key.comptime_bits != 0,
.has_noalias_bits = key.noalias_bits != 0,
- .is_generic = key.is_generic,
.is_noinline = key.is_noinline,
},
});
@@ -9427,7 +9315,7 @@ pub fn getFuncDecl(
const func_decl_extra_index = addExtraAssumeCapacity(extra, Tag.FuncDecl{
.analysis = .{
- .is_analyzed = false,
+ .want_runtime_analysis = false,
.branch_hint = .none,
.is_noinline = key.is_noinline,
.has_error_trace = false,
@@ -9480,7 +9368,6 @@ pub const GetFuncDeclIesKey = struct {
/// null means generic.
cc: ?std.builtin.CallingConvention,
is_var_args: bool,
- is_generic: bool,
is_noinline: bool,
zir_body_inst: TrackedInst.Index,
lbrace_line: u32,
@@ -9538,7 +9425,7 @@ pub fn getFuncDeclIes(
const func_decl_extra_index = addExtraAssumeCapacity(extra, Tag.FuncDecl{
.analysis = .{
- .is_analyzed = false,
+ .want_runtime_analysis = false,
.branch_hint = .none,
.is_noinline = key.is_noinline,
.has_error_trace = false,
@@ -9564,7 +9451,6 @@ pub fn getFuncDeclIes(
.is_var_args = key.is_var_args,
.has_comptime_bits = key.comptime_bits != 0,
.has_noalias_bits = key.noalias_bits != 0,
- .is_generic = key.is_generic,
.is_noinline = key.is_noinline,
},
});
@@ -9737,7 +9623,7 @@ pub fn getFuncInstance(
const func_extra_index = addExtraAssumeCapacity(extra, Tag.FuncInstance{
.analysis = .{
- .is_analyzed = false,
+ .want_runtime_analysis = false,
.branch_hint = .none,
.is_noinline = arg.is_noinline,
.has_error_trace = false,
@@ -9838,7 +9724,7 @@ fn getFuncInstanceIes(
const func_extra_index = addExtraAssumeCapacity(extra, Tag.FuncInstance{
.analysis = .{
- .is_analyzed = false,
+ .want_runtime_analysis = false,
.branch_hint = .none,
.is_noinline = arg.is_noinline,
.has_error_trace = false,
@@ -9864,7 +9750,6 @@ fn getFuncInstanceIes(
.is_var_args = false,
.has_comptime_bits = false,
.has_noalias_bits = arg.noalias_bits != 0,
- .is_generic = false,
.is_noinline = arg.is_noinline,
},
});
@@ -9972,444 +9857,6 @@ fn finishFuncInstance(
] = @intFromEnum(nav_index);
}
-pub const EnumTypeInit = struct {
- has_values: bool,
- tag_mode: LoadedEnumType.TagMode,
- fields_len: u32,
- key: union(enum) {
- declared: struct {
- zir_index: TrackedInst.Index,
- captures: []const CaptureValue,
- },
- declared_owned_captures: struct {
- zir_index: TrackedInst.Index,
- captures: CaptureValue.Slice,
- },
- reified: struct {
- zir_index: TrackedInst.Index,
- type_hash: u64,
- },
- },
-};
-
-pub const WipEnumType = struct {
- tid: Zcu.PerThread.Id,
- index: Index,
- tag_ty_index: u32,
- type_name_extra_index: u32,
- namespace_extra_index: u32,
- name_nav_extra_index: u32,
- names_map: MapIndex,
- names_start: u32,
- values_map: OptionalMapIndex,
- values_start: u32,
-
- pub fn setName(
- wip: WipEnumType,
- ip: *InternPool,
- type_name: NullTerminatedString,
- /// This should be the `Nav` we are named after if we use the `.parent` name strategy; `.none` otherwise.
- name_nav: Nav.Index.Optional,
- ) void {
- const extra = ip.getLocalShared(wip.tid).extra.acquire();
- const extra_items = extra.view().items(.@"0");
- extra_items[wip.type_name_extra_index] = @intFromEnum(type_name);
- extra_items[wip.name_nav_extra_index] = @intFromEnum(name_nav);
- }
-
- pub fn prepare(
- wip: WipEnumType,
- ip: *InternPool,
- namespace: NamespaceIndex,
- ) void {
- const extra = ip.getLocalShared(wip.tid).extra.acquire();
- const extra_items = extra.view().items(.@"0");
-
- extra_items[wip.namespace_extra_index] = @intFromEnum(namespace);
- }
-
- pub fn setTagTy(wip: WipEnumType, ip: *InternPool, tag_ty: Index) void {
- assert(ip.isIntegerType(tag_ty));
- const extra = ip.getLocalShared(wip.tid).extra.acquire();
- extra.view().items(.@"0")[wip.tag_ty_index] = @intFromEnum(tag_ty);
- }
-
- pub const FieldConflict = struct {
- kind: enum { name, value },
- prev_field_idx: u32,
- };
-
- /// Returns the already-existing field with the same name or value, if any.
- /// If the enum is automatially numbered, `value` must be `.none`.
- /// Otherwise, the type of `value` must be the integer tag type of the enum.
- pub fn nextField(wip: WipEnumType, ip: *InternPool, name: NullTerminatedString, value: Index) ?FieldConflict {
- const unwrapped_index = wip.index.unwrap(ip);
- const extra_list = ip.getLocalShared(unwrapped_index.tid).extra.acquire();
- const extra_items = extra_list.view().items(.@"0");
- if (ip.addFieldName(extra_list, wip.names_map, wip.names_start, name)) |conflict| {
- return .{ .kind = .name, .prev_field_idx = conflict };
- }
- if (value == .none) {
- assert(wip.values_map == .none);
- return null;
- }
- assert(ip.typeOf(value) == @as(Index, @enumFromInt(extra_items[wip.tag_ty_index])));
- const map = wip.values_map.unwrap().?.get(ip);
- const field_index = map.count();
- const indexes = extra_items[wip.values_start..][0..field_index];
- const adapter: Index.Adapter = .{ .indexes = @ptrCast(indexes) };
- const gop = map.getOrPutAssumeCapacityAdapted(value, adapter);
- if (gop.found_existing) {
- return .{ .kind = .value, .prev_field_idx = @intCast(gop.index) };
- }
- extra_items[wip.values_start + field_index] = @intFromEnum(value);
- return null;
- }
-
- pub fn cancel(wip: WipEnumType, ip: *InternPool, tid: Zcu.PerThread.Id) void {
- ip.remove(tid, wip.index);
- }
-
- pub const Result = union(enum) {
- wip: WipEnumType,
- existing: Index,
- };
-};
-
-pub fn getEnumType(
- ip: *InternPool,
- gpa: Allocator,
- io: Io,
- tid: Zcu.PerThread.Id,
- ini: EnumTypeInit,
- /// If it is known that there is an existing type with this key which is outdated,
- /// this is passed as `true`, and the type is replaced with one at a fresh index.
- replace_existing: bool,
-) Allocator.Error!WipEnumType.Result {
- const key: Key = .{ .enum_type = switch (ini.key) {
- .declared => |d| .{ .declared = .{
- .zir_index = d.zir_index,
- .captures = .{ .external = d.captures },
- } },
- .declared_owned_captures => |d| .{ .declared = .{
- .zir_index = d.zir_index,
- .captures = .{ .owned = d.captures },
- } },
- .reified => |r| .{ .reified = .{
- .zir_index = r.zir_index,
- .type_hash = r.type_hash,
- } },
- } };
- var gop = if (replace_existing)
- ip.putKeyReplace(io, tid, key)
- else
- try ip.getOrPutKey(gpa, io, tid, key);
- defer gop.deinit();
- if (gop == .existing) return .{ .existing = gop.existing };
-
- const local = ip.getLocal(tid);
- const items = local.getMutableItems(gpa, io);
- try items.ensureUnusedCapacity(1);
- const extra = local.getMutableExtra(gpa, io);
-
- const names_map = try ip.addMap(gpa, io, tid, ini.fields_len);
- errdefer local.mutate.maps.len -= 1;
-
- switch (ini.tag_mode) {
- .auto => {
- assert(!ini.has_values);
- try extra.ensureUnusedCapacity(@typeInfo(EnumAuto).@"struct".fields.len +
- // TODO: fmt bug
- // zig fmt: off
- switch (ini.key) {
- inline .declared, .declared_owned_captures => |d| d.captures.len,
- .reified => 2, // type_hash: PackedU64
- } +
- // zig fmt: on
- ini.fields_len); // field types
-
- const extra_index = addExtraAssumeCapacity(extra, EnumAuto{
- .name = undefined, // set by `prepare`
- .name_nav = undefined, // set by `prepare`
- .captures_len = switch (ini.key) {
- inline .declared, .declared_owned_captures => |d| @intCast(d.captures.len),
- .reified => std.math.maxInt(u32),
- },
- .namespace = undefined, // set by `prepare`
- .int_tag_type = .none, // set by `prepare`
- .fields_len = ini.fields_len,
- .names_map = names_map,
- .zir_index = switch (ini.key) {
- inline else => |x| x.zir_index,
- }.toOptional(),
- });
- items.appendAssumeCapacity(.{
- .tag = .type_enum_auto,
- .data = extra_index,
- });
- switch (ini.key) {
- .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}),
- .declared_owned_captures => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))}),
- .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)),
- }
- const names_start = extra.mutate.len;
- _ = extra.addManyAsSliceAssumeCapacity(ini.fields_len);
- return .{ .wip = .{
- .tid = tid,
- .index = gop.put(),
- .tag_ty_index = extra_index + std.meta.fieldIndex(EnumAuto, "int_tag_type").?,
- .type_name_extra_index = extra_index + std.meta.fieldIndex(EnumAuto, "name").?,
- .name_nav_extra_index = extra_index + std.meta.fieldIndex(EnumAuto, "name_nav").?,
- .namespace_extra_index = extra_index + std.meta.fieldIndex(EnumAuto, "namespace").?,
- .names_map = names_map,
- .names_start = @intCast(names_start),
- .values_map = .none,
- .values_start = undefined,
- } };
- },
- .explicit, .nonexhaustive => {
- const values_map: OptionalMapIndex = if (!ini.has_values) .none else m: {
- const values_map = try ip.addMap(gpa, io, tid, ini.fields_len);
- break :m values_map.toOptional();
- };
- errdefer if (ini.has_values) {
- local.mutate.maps.len -= 1;
- };
-
- try extra.ensureUnusedCapacity(@typeInfo(EnumExplicit).@"struct".fields.len +
- // TODO: fmt bug
- // zig fmt: off
- switch (ini.key) {
- inline .declared, .declared_owned_captures => |d| d.captures.len,
- .reified => 2, // type_hash: PackedU64
- } +
- // zig fmt: on
- ini.fields_len + // field types
- ini.fields_len * @intFromBool(ini.has_values)); // field values
-
- const extra_index = addExtraAssumeCapacity(extra, EnumExplicit{
- .name = undefined, // set by `prepare`
- .name_nav = undefined, // set by `prepare`
- .captures_len = switch (ini.key) {
- inline .declared, .declared_owned_captures => |d| @intCast(d.captures.len),
- .reified => std.math.maxInt(u32),
- },
- .namespace = undefined, // set by `prepare`
- .int_tag_type = .none, // set by `prepare`
- .fields_len = ini.fields_len,
- .names_map = names_map,
- .values_map = values_map,
- .zir_index = switch (ini.key) {
- inline else => |x| x.zir_index,
- }.toOptional(),
- });
- items.appendAssumeCapacity(.{
- .tag = switch (ini.tag_mode) {
- .auto => unreachable,
- .explicit => .type_enum_explicit,
- .nonexhaustive => .type_enum_nonexhaustive,
- },
- .data = extra_index,
- });
- switch (ini.key) {
- .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}),
- .declared_owned_captures => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))}),
- .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)),
- }
- const names_start = extra.mutate.len;
- _ = extra.addManyAsSliceAssumeCapacity(ini.fields_len);
- const values_start = extra.mutate.len;
- if (ini.has_values) {
- _ = extra.addManyAsSliceAssumeCapacity(ini.fields_len);
- }
- return .{ .wip = .{
- .tid = tid,
- .index = gop.put(),
- .tag_ty_index = extra_index + std.meta.fieldIndex(EnumExplicit, "int_tag_type").?,
- .type_name_extra_index = extra_index + std.meta.fieldIndex(EnumExplicit, "name").?,
- .name_nav_extra_index = extra_index + std.meta.fieldIndex(EnumExplicit, "name_nav").?,
- .namespace_extra_index = extra_index + std.meta.fieldIndex(EnumExplicit, "namespace").?,
- .names_map = names_map,
- .names_start = @intCast(names_start),
- .values_map = values_map,
- .values_start = @intCast(values_start),
- } };
- },
- }
-}
-
-const GeneratedTagEnumTypeInit = struct {
- name: NullTerminatedString,
- owner_union_ty: Index,
- tag_ty: Index,
- names: []const NullTerminatedString,
- values: []const Index,
- tag_mode: LoadedEnumType.TagMode,
- parent_namespace: NamespaceIndex,
-};
-
-/// Creates an enum type which was automatically-generated as the tag type of a
-/// `union` with no explicit tag type. Since this is only called once per union
-/// type, it asserts that no matching type yet exists.
-pub fn getGeneratedTagEnumType(
- ip: *InternPool,
- gpa: Allocator,
- io: Io,
- tid: Zcu.PerThread.Id,
- ini: GeneratedTagEnumTypeInit,
-) Allocator.Error!Index {
- assert(ip.isUnion(ini.owner_union_ty));
- assert(ip.isIntegerType(ini.tag_ty));
- for (ini.values) |val| assert(ip.typeOf(val) == ini.tag_ty);
-
- const local = ip.getLocal(tid);
- const items = local.getMutableItems(gpa, io);
- try items.ensureUnusedCapacity(1);
- const extra = local.getMutableExtra(gpa, io);
-
- const names_map = try ip.addMap(gpa, io, tid, ini.names.len);
- errdefer local.mutate.maps.len -= 1;
- ip.addStringsToMap(names_map, ini.names);
-
- const fields_len: u32 = @intCast(ini.names.len);
-
- // Predict the index the enum will live at so we can construct the namespace before releasing the shard's mutex.
- const enum_index = Index.Unwrapped.wrap(.{
- .tid = tid,
- .index = items.mutate.len,
- }, ip);
- const parent_namespace = ip.namespacePtr(ini.parent_namespace);
- const namespace = try ip.createNamespace(gpa, io, tid, .{
- .parent = ini.parent_namespace.toOptional(),
- .owner_type = enum_index,
- .file_scope = parent_namespace.file_scope,
- .generation = parent_namespace.generation,
- });
- errdefer ip.destroyNamespace(tid, namespace);
-
- const prev_extra_len = extra.mutate.len;
- switch (ini.tag_mode) {
- .auto => {
- try extra.ensureUnusedCapacity(@typeInfo(EnumAuto).@"struct".fields.len +
- 1 + // owner_union
- fields_len); // field names
- items.appendAssumeCapacity(.{
- .tag = .type_enum_auto,
- .data = addExtraAssumeCapacity(extra, EnumAuto{
- .name = ini.name,
- .name_nav = .none,
- .captures_len = 0,
- .namespace = namespace,
- .int_tag_type = ini.tag_ty,
- .fields_len = fields_len,
- .names_map = names_map,
- .zir_index = .none,
- }),
- });
- extra.appendAssumeCapacity(.{@intFromEnum(ini.owner_union_ty)});
- extra.appendSliceAssumeCapacity(.{@ptrCast(ini.names)});
- },
- .explicit, .nonexhaustive => {
- try extra.ensureUnusedCapacity(@typeInfo(EnumExplicit).@"struct".fields.len +
- 1 + // owner_union
- fields_len + // field names
- ini.values.len); // field values
-
- const values_map: OptionalMapIndex = if (ini.values.len != 0) m: {
- const map = try ip.addMap(gpa, io, tid, ini.values.len);
- ip.addIndexesToMap(map, ini.values);
- break :m map.toOptional();
- } else .none;
- // We don't clean up the values map on error!
- errdefer @compileError("error path leaks values_map");
-
- items.appendAssumeCapacity(.{
- .tag = switch (ini.tag_mode) {
- .explicit => .type_enum_explicit,
- .nonexhaustive => .type_enum_nonexhaustive,
- .auto => unreachable,
- },
- .data = addExtraAssumeCapacity(extra, EnumExplicit{
- .name = ini.name,
- .name_nav = .none,
- .captures_len = 0,
- .namespace = namespace,
- .int_tag_type = ini.tag_ty,
- .fields_len = fields_len,
- .names_map = names_map,
- .values_map = values_map,
- .zir_index = .none,
- }),
- });
- extra.appendAssumeCapacity(.{@intFromEnum(ini.owner_union_ty)});
- extra.appendSliceAssumeCapacity(.{@ptrCast(ini.names)});
- extra.appendSliceAssumeCapacity(.{@ptrCast(ini.values)});
- },
- }
- errdefer extra.mutate.len = prev_extra_len;
- errdefer switch (ini.tag_mode) {
- .auto => {},
- .explicit, .nonexhaustive => if (ini.values.len != 0) {
- local.mutate.maps.len -= 1;
- },
- };
-
- var gop = try ip.getOrPutKey(gpa, io, tid, .{ .enum_type = .{
- .generated_tag = .{ .union_type = ini.owner_union_ty },
- } });
- defer gop.deinit();
- assert(gop.put() == enum_index);
- return enum_index;
-}
-
-pub const OpaqueTypeInit = struct {
- zir_index: TrackedInst.Index,
- captures: []const CaptureValue,
-};
-
-pub fn getOpaqueType(
- ip: *InternPool,
- gpa: Allocator,
- io: Io,
- tid: Zcu.PerThread.Id,
- ini: OpaqueTypeInit,
-) Allocator.Error!WipNamespaceType.Result {
- var gop = try ip.getOrPutKey(gpa, io, tid, .{ .opaque_type = .{ .declared = .{
- .zir_index = ini.zir_index,
- .captures = .{ .external = ini.captures },
- } } });
- defer gop.deinit();
- if (gop == .existing) return .{ .existing = gop.existing };
-
- const local = ip.getLocal(tid);
- const items = local.getMutableItems(gpa, io);
- const extra = local.getMutableExtra(gpa, io);
- try items.ensureUnusedCapacity(1);
-
- try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeOpaque).@"struct".fields.len + ini.captures.len);
- const extra_index = addExtraAssumeCapacity(extra, Tag.TypeOpaque{
- .name = undefined, // set by `finish`
- .name_nav = undefined, // set by `finish`
- .namespace = undefined, // set by `finish`
- .zir_index = ini.zir_index,
- .captures_len = @intCast(ini.captures.len),
- });
- items.appendAssumeCapacity(.{
- .tag = .type_opaque,
- .data = extra_index,
- });
- extra.appendSliceAssumeCapacity(.{@ptrCast(ini.captures)});
- return .{
- .wip = .{
- .tid = tid,
- .index = gop.put(),
- .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name").?,
- .name_nav_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name_nav").?,
- .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "namespace").?,
- },
- };
-}
-
pub fn getIfExists(ip: *const InternPool, key: Key) ?Index {
const full_hash = key.hash64(ip);
const hash: u32 = @truncate(full_hash >> 32);
@@ -10440,19 +9887,6 @@ fn addStringsToMap(
}
}
-fn addIndexesToMap(
- ip: *InternPool,
- map_index: MapIndex,
- indexes: []const Index,
-) void {
- const map = map_index.get(ip);
- const adapter: Index.Adapter = .{ .indexes = indexes };
- for (indexes) |index| {
- const gop = map.getOrPutAssumeCapacityAdapted(index, adapter);
- assert(!gop.found_existing);
- }
-}
-
fn addMap(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, cap: usize) Allocator.Error!MapIndex {
const maps = ip.getLocal(tid).getMutableMaps(gpa, io);
const unwrapped: MapIndex.Unwrapped = .{ .tid = tid, .index = maps.mutate.len };
@@ -10545,7 +9979,9 @@ fn addExtraAssumeCapacity(extra: Local.Extra.Mutable, item: anytype) u32 {
Tag.TypePointer.PackedOffset,
Tag.TypeUnion.Flags,
Tag.TypeStruct.Flags,
- Tag.TypeStructPacked.Flags,
+ Tag.TypeStructPacked.Bits,
+ Tag.TypeUnionPacked.Bits,
+ Tag.TypeEnum.Bits,
=> @bitCast(@field(item, field.name)),
else => @compileError("bad field type: " ++ @typeName(field.type)),
@@ -10607,8 +10043,10 @@ fn extraDataTrail(extra: Local.Extra, comptime T: type, index: u32) struct { dat
Tag.TypePointer.PackedOffset,
Tag.TypeUnion.Flags,
Tag.TypeStruct.Flags,
- Tag.TypeStructPacked.Flags,
FuncAnalysis,
+ Tag.TypeStructPacked.Bits,
+ Tag.TypeUnionPacked.Bits,
+ Tag.TypeEnum.Bits,
=> @bitCast(extra_item),
else => @compileError("bad field type: " ++ @typeName(field.type)),
@@ -10786,7 +10224,7 @@ pub fn getCoerced(
.int => |int| switch (ip.indexToKey(new_ty)) {
.enum_type => return ip.get(gpa, io, tid, .{ .enum_tag = .{
.ty = new_ty,
- .int = try ip.getCoerced(gpa, io, tid, val, ip.loadEnumType(new_ty).tag_ty),
+ .int = try ip.getCoerced(gpa, io, tid, val, ip.loadEnumType(new_ty).int_tag_type),
} }),
.ptr_type => switch (int.storage) {
inline .u64, .i64 => |int_val| return ip.get(gpa, io, tid, .{ .ptr = .{
@@ -10795,7 +10233,6 @@ pub fn getCoerced(
.byte_offset = @intCast(int_val),
} }),
.big_int => unreachable, // must be a usize
- .lazy_align, .lazy_size => {},
},
else => if (ip.isIntegerType(new_ty))
return ip.getCoercedInts(gpa, io, tid, int, new_ty),
@@ -10825,11 +10262,11 @@ pub fn getCoerced(
const index = enum_type.nameIndex(ip, enum_literal).?;
return ip.get(gpa, io, tid, .{ .enum_tag = .{
.ty = new_ty,
- .int = if (enum_type.values.len != 0)
- enum_type.values.get(ip)[index]
+ .int = if (enum_type.field_values.len != 0)
+ enum_type.field_values.get(ip)[index]
else
try ip.get(gpa, io, tid, .{ .int = .{
- .ty = enum_type.tag_ty,
+ .ty = enum_type.int_tag_type,
.storage = .{ .u64 = index },
} }),
} });
@@ -11193,10 +10630,78 @@ pub fn dump(ip: *const InternPool) void {
const stderr = std.debug.lockStderr(&buffer);
defer std.debug.unlockStderr();
const w = &stderr.file_writer.interface;
+ dumpDependencyStatsFallible(ip, w) catch return;
dumpStatsFallible(ip, w, std.heap.page_allocator) catch return;
dumpAllFallible(ip, w) catch return;
}
+fn dumpDependencyStatsFallible(ip: *const InternPool, w: *Io.Writer) !void {
+ const dep_entries_len = ip.dep_entries.items.len - ip.free_dep_entries.items.len;
+ const src_hash_deps_len = ip.src_hash_deps.count();
+ const nav_val_deps_len = ip.nav_val_deps.count();
+ const nav_ty_deps_len = ip.nav_ty_deps.count();
+ const func_ies_deps_len = ip.func_ies_deps.count();
+ const type_layout_deps_len = ip.type_layout_deps.count();
+ const struct_defaults_deps_len = ip.struct_defaults_deps.count();
+ const zon_file_deps_len = ip.zon_file_deps.count();
+ const embed_file_deps_len = ip.embed_file_deps.count();
+ const namespace_deps_len = ip.namespace_deps.count();
+ const namespace_name_deps_len = ip.namespace_name_deps.count();
+ const dep_entries_size = dep_entries_len * @sizeOf(DepEntry);
+ const src_hash_deps_size = src_hash_deps_len * 8;
+ const nav_val_deps_size = nav_val_deps_len * 8;
+ const nav_ty_deps_size = nav_ty_deps_len * 8;
+ const func_ies_deps_size = func_ies_deps_len * 8;
+ const type_layout_deps_size = type_layout_deps_len * 8;
+ const struct_defaults_deps_size = struct_defaults_deps_len * 8;
+ const zon_file_deps_size = zon_file_deps_len * 8;
+ const embed_file_deps_size = embed_file_deps_len * 8;
+ const namespace_deps_size = namespace_deps_len * 8;
+ const namespace_name_deps_size = namespace_name_deps_len * (@sizeOf(NamespaceNameKey) + 4);
+
+ try w.print(
+ \\InternPool dependencies: {d} bytes
+ \\ {d} entries: {d} bytes
+ \\ {d} src_hash: {d} bytes
+ \\ {d} nav_val: {d} bytes
+ \\ {d} nav_ty: {d} bytes
+ \\ {d} func_ies: {d} bytes
+ \\ {d} type_layout: {d} bytes
+ \\ {d} struct_defaults: {d} bytes
+ \\ {d} zon_file: {d} bytes
+ \\ {d} embed_file: {d} bytes
+ \\ {d} namespace: {d} bytes
+ \\ {d} namespace_name: {d} bytes
+ \\
+ , .{
+ dep_entries_size + src_hash_deps_size + nav_val_deps_size + nav_ty_deps_size +
+ func_ies_deps_size + type_layout_deps_size + struct_defaults_deps_size + zon_file_deps_size +
+ embed_file_deps_size + namespace_deps_size + namespace_name_deps_size,
+ dep_entries_len,
+ dep_entries_size,
+ src_hash_deps_len,
+ src_hash_deps_size,
+ nav_val_deps_len,
+ nav_val_deps_size,
+ nav_ty_deps_len,
+ nav_ty_deps_size,
+ func_ies_deps_len,
+ func_ies_deps_size,
+ type_layout_deps_len,
+ type_layout_deps_size,
+ struct_defaults_deps_len,
+ struct_defaults_deps_size,
+ zon_file_deps_len,
+ zon_file_deps_size,
+ embed_file_deps_len,
+ embed_file_deps_size,
+ namespace_deps_len,
+ namespace_deps_size,
+ namespace_name_deps_len,
+ namespace_name_deps_size,
+ });
+}
+
fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !void {
var items_len: usize = 0;
var extra_len: usize = 0;
@@ -11211,10 +10716,10 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo
const limbs_size = 8 * limbs_len;
// TODO: map overhead size is not taken into account
- const total_size = @sizeOf(InternPool) + items_size + extra_size + limbs_size;
+ const total_size = items_size + extra_size + limbs_size;
- std.debug.print(
- \\InternPool size: {d} bytes
+ try w.print(
+ \\InternPool values: {d} bytes
\\ {d} items: {d} bytes
\\ {d} extra: {d} bytes
\\ {d} limbs: {d} bytes
@@ -11235,6 +10740,8 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo
};
var counts = std.AutoArrayHashMap(Tag, TagStats).init(arena);
for (ip.locals) |*local| {
+ // Early check for length 0, because `view()` is invalid if capacity is 0
+ if (local.mutate.items.len == 0) continue;
const items = local.shared.items.view().slice();
const extra_list = local.shared.extra;
const extra_items = extra_list.view().items(.@"0");
@@ -11266,92 +10773,10 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo
break :b @sizeOf(Tag.ErrorSet) + (@sizeOf(u32) * info.names_len);
},
.type_inferred_error_set => 0,
- .type_enum_explicit, .type_enum_nonexhaustive => b: {
- const info = extraData(extra_list, EnumExplicit, data);
- var ints = @typeInfo(EnumExplicit).@"struct".fields.len;
- if (info.zir_index == .none) ints += 1;
- ints += if (info.captures_len != std.math.maxInt(u32))
- info.captures_len
- else
- @typeInfo(PackedU64).@"struct".fields.len;
- ints += info.fields_len;
- if (info.values_map != .none) ints += info.fields_len;
- break :b @sizeOf(u32) * ints;
- },
- .type_enum_auto => b: {
- const info = extraData(extra_list, EnumAuto, data);
- const ints = @typeInfo(EnumAuto).@"struct".fields.len + info.captures_len + info.fields_len;
- break :b @sizeOf(u32) * ints;
- },
- .type_opaque => b: {
- const info = extraData(extra_list, Tag.TypeOpaque, data);
- const ints = @typeInfo(Tag.TypeOpaque).@"struct".fields.len + info.captures_len;
- break :b @sizeOf(u32) * ints;
- },
- .type_struct => b: {
- const extra = extraDataTrail(extra_list, Tag.TypeStruct, data);
- const info = extra.data;
- var ints: usize = @typeInfo(Tag.TypeStruct).@"struct".fields.len;
- if (info.flags.any_captures) {
- const captures_len = extra_items[extra.end];
- ints += 1 + captures_len;
- }
- ints += info.fields_len; // types
- ints += 1; // names_map
- ints += info.fields_len; // names
- if (info.flags.any_default_inits)
- ints += info.fields_len; // inits
- if (info.flags.any_aligned_fields)
- ints += (info.fields_len + 3) / 4; // aligns
- if (info.flags.any_comptime_fields)
- ints += (info.fields_len + 31) / 32; // comptime bits
- if (!info.flags.is_extern)
- ints += info.fields_len; // runtime order
- ints += info.fields_len; // offsets
- break :b @sizeOf(u32) * ints;
- },
- .type_struct_packed => b: {
- const extra = extraDataTrail(extra_list, Tag.TypeStructPacked, data);
- const captures_len = if (extra.data.flags.any_captures)
- extra_items[extra.end]
- else
- 0;
- break :b @sizeOf(u32) * (@typeInfo(Tag.TypeStructPacked).@"struct".fields.len +
- @intFromBool(extra.data.flags.any_captures) + captures_len +
- extra.data.fields_len * 2);
- },
- .type_struct_packed_inits => b: {
- const extra = extraDataTrail(extra_list, Tag.TypeStructPacked, data);
- const captures_len = if (extra.data.flags.any_captures)
- extra_items[extra.end]
- else
- 0;
- break :b @sizeOf(u32) * (@typeInfo(Tag.TypeStructPacked).@"struct".fields.len +
- @intFromBool(extra.data.flags.any_captures) + captures_len +
- extra.data.fields_len * 3);
- },
.type_tuple => b: {
const info = extraData(extra_list, TypeTuple, data);
break :b @sizeOf(TypeTuple) + (@sizeOf(u32) * 2 * info.fields_len);
},
-
- .type_union => b: {
- const extra = extraDataTrail(extra_list, Tag.TypeUnion, data);
- const captures_len = if (extra.data.flags.any_captures)
- extra_items[extra.end]
- else
- 0;
- const per_field = @sizeOf(u32); // field type
- // 1 byte per field for alignment, rounded up to the nearest 4 bytes
- const alignments = if (extra.data.flags.any_aligned_fields)
- ((extra.data.fields_len + 3) / 4) * 4
- else
- 0;
- break :b @sizeOf(Tag.TypeUnion) +
- 4 * (@intFromBool(extra.data.flags.any_captures) + captures_len) +
- (extra.data.fields_len * per_field) + alignments;
- },
-
.type_function => b: {
const info = extraData(extra_list, Tag.TypeFunction, data);
break :b @sizeOf(Tag.TypeFunction) +
@@ -11360,6 +10785,127 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo
(@as(u32, 4) * @intFromBool(info.flags.has_noalias_bits));
},
+ .type_struct => b: {
+ var n: usize = @typeInfo(Tag.TypeStruct).@"struct".fields.len;
+ const extra = extraDataTrail(extra_list, Tag.TypeStruct, data);
+ switch (extra.data.flags.any_captures) {
+ .reified => n += 2, // type_hash: PackedU64
+ .true => {
+ n += 1; // captures_len: u32
+ n += extra_items[extra.end]; // capture: CaptureValue
+ },
+ .false => {},
+ }
+ n += extra.data.fields_len; // field_name: NullTerminatedString
+ n += extra.data.fields_len; // field_type: Index
+ if (extra.data.flags.any_field_defaults) {
+ n += extra.data.fields_len; // field_default: Index
+ }
+ if (extra.data.flags.any_field_aligns) {
+ n += (extra.data.fields_len + 3) / 4; // field_align: Alignment
+ }
+ if (extra.data.flags.any_comptime_fields) {
+ n += (extra.data.fields_len + 31) / 32; // field_is_comptime_bits: u32
+ }
+ if (extra.data.flags.layout == .auto) {
+ n += extra.data.fields_len; // field_runtime_order: RuntimeOrder
+ }
+ n += extra.data.fields_len; // field_offset: u32
+ break :b n * @sizeOf(u32);
+ },
+ .type_struct_packed_auto, .type_struct_packed_explicit => b: {
+ var n: usize = @typeInfo(Tag.TypeStructPacked).@"struct".fields.len;
+ const extra = extraDataTrail(extra_list, Tag.TypeStructPacked, data);
+ switch (extra.data.bits.captures_len) {
+ .reified => n += 2, // type_hash: PackedU64
+ _ => |len| n += @intFromEnum(len), // capture: CaptureValue
+ }
+ n += extra.data.fields_len; // field_name: NullTerminatedString
+ n += extra.data.fields_len; // field_type: Index
+ break :b n * @sizeOf(u32);
+ },
+ .type_struct_packed_auto_defaults, .type_struct_packed_explicit_defaults => b: {
+ var n: usize = @typeInfo(Tag.TypeStructPacked).@"struct".fields.len;
+ const extra = extraDataTrail(extra_list, Tag.TypeStructPacked, data);
+ switch (extra.data.bits.captures_len) {
+ .reified => n += 2, // type_hash: PackedU64
+ _ => |len| n += @intFromEnum(len), // capture: CaptureValue
+ }
+ n += extra.data.fields_len; // field_name: NullTerminatedString
+ n += extra.data.fields_len; // field_type: Index
+ n += extra.data.fields_len; // field_default: Index
+ break :b n * @sizeOf(u32);
+ },
+ .type_union => b: {
+ var n: usize = @typeInfo(Tag.TypeUnion).@"struct".fields.len;
+ const extra = extraDataTrail(extra_list, Tag.TypeUnion, data);
+ switch (extra.data.flags.any_captures) {
+ .reified => n += 2, // type_hash: PackedU64
+ .true => {
+ n += 1; // captures_len: u32
+ n += extra_items[extra.end]; // capture: CaptureValue
+ },
+ .false => {},
+ }
+ n += extra.data.fields_len; // field_type: Index
+ if (extra.data.flags.any_field_aligns) {
+ n += (extra.data.fields_len + 3) / 4; // field_align: Alignment
+ }
+ break :b n * @sizeOf(u32);
+ },
+ .type_union_packed_auto, .type_union_packed_explicit => b: {
+ var n: usize = @typeInfo(Tag.TypeUnionPacked).@"struct".fields.len;
+ const extra = extraDataTrail(extra_list, Tag.TypeUnionPacked, data);
+ switch (extra.data.bits.captures_len) {
+ .reified => n += 2, // type_hash: PackedU64
+ _ => |len| n += @intFromEnum(len), // capture: CaptureValue
+ }
+ n += extra.data.fields_len; // field_type: Index
+ break :b n * @sizeOf(u32);
+ },
+ .type_enum_auto => b: {
+ var n: usize = @typeInfo(Tag.TypeEnum).@"struct".fields.len;
+ const extra = extraData(extra_list, Tag.TypeEnum, data);
+ switch (extra.bits.captures_len) {
+ .generated_union_tag => n += 1, // owner_union: Index
+ .reified => {
+ n += 1; // zir_index: TrackedInst.Index,
+ n += 2; // type_hash: PackedU64
+ },
+ _ => |len| {
+ n += 1; // zir_index: TrackedInst.Index,
+ n += @intFromEnum(len); // capture: CaptureValue
+ },
+ }
+ n += extra.fields_len; // field_name: NullTerminatedString
+ break :b n * @sizeOf(u32);
+ },
+ .type_enum_explicit, .type_enum_nonexhaustive => b: {
+ var n: usize = @typeInfo(Tag.TypeEnum).@"struct".fields.len;
+ const extra = extraData(extra_list, Tag.TypeEnum, data);
+ switch (extra.bits.captures_len) {
+ .generated_union_tag => n += 1, // owner_union: Index
+ .reified => {
+ n += 1; // zir_index: TrackedInst.Index,
+ n += 2; // type_hash: PackedU64
+ },
+ _ => |len| {
+ n += 1; // zir_index: TrackedInst.Index,
+ n += @intFromEnum(len); // capture: CaptureValue
+ },
+ }
+ n += 1; // field_value_map: MapIndex
+ n += extra.fields_len; // field_name: NullTerminatedString
+ n += extra.fields_len; // field_value: Index
+ break :b n * @sizeOf(u32);
+ },
+ .type_opaque => b: {
+ var n: usize = @typeInfo(Tag.TypeEnum).@"struct".fields.len;
+ const extra = extraData(extra_list, Tag.TypeOpaque, data);
+ n += extra.captures_len; // capture: CaptureValue
+ break :b n * @sizeOf(u32);
+ },
+
.undef => 0,
.simple_type => 0,
.simple_value => 0,
@@ -11393,8 +10939,6 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo
break :b @sizeOf(Int) + int.limbs_len * @sizeOf(Limb);
},
- .int_lazy_align, .int_lazy_size => @sizeOf(IntLazy),
-
.error_set_error, .error_union_error => @sizeOf(Key.Error),
.error_union_payload => @sizeOf(Tag.TypeValue),
.enum_literal => 0,
@@ -11432,6 +10976,7 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo
.func_coerced => @sizeOf(Tag.FuncCoerced),
.only_possible_value => 0,
.union_value => @sizeOf(Key.Union),
+ .bitpack => 2 * @sizeOf(u32),
.memoized_call => b: {
const info = extraData(extra_list, MemoizedCall, data);
@@ -11458,6 +11003,8 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo
fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void {
for (ip.locals, 0..) |*local, tid| {
+ // Early check for length 0, because `view()` is invalid if capacity is 0
+ if (local.mutate.items.len == 0) continue;
const items = local.shared.items.view();
for (
items.items(.tag)[0..local.mutate.items.len],
@@ -11484,16 +11031,20 @@ fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void {
.type_anyerror_union,
.type_error_set,
.type_inferred_error_set,
+ .type_tuple,
+ .type_function,
+ .type_struct,
+ .type_struct_packed_auto,
+ .type_struct_packed_explicit,
+ .type_struct_packed_auto_defaults,
+ .type_struct_packed_explicit_defaults,
+ .type_union,
+ .type_union_packed_auto,
+ .type_union_packed_explicit,
+ .type_enum_auto,
.type_enum_explicit,
.type_enum_nonexhaustive,
- .type_enum_auto,
.type_opaque,
- .type_struct,
- .type_struct_packed,
- .type_struct_packed_inits,
- .type_tuple,
- .type_union,
- .type_function,
.undef,
.ptr_nav,
.ptr_comptime_alloc,
@@ -11517,8 +11068,6 @@ fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void {
.int_small,
.int_positive,
.int_negative,
- .int_lazy_align,
- .int_lazy_size,
.error_set_error,
.error_union_error,
.error_union_payload,
@@ -11542,6 +11091,7 @@ fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void {
.func_instance,
.func_coerced,
.union_value,
+ .bitpack,
.memoized_call,
=> try w.print("{d}", .{data}),
@@ -11581,7 +11131,7 @@ pub fn dumpGenericInstancesFallible(ip: *const InternPool, allocator: Allocator,
const info = extraData(extra_list, Tag.FuncInstance, data);
const gop = try instances.getOrPut(arena, info.generic_owner);
- if (!gop.found_existing) gop.value_ptr.* = .{};
+ if (!gop.found_existing) gop.value_ptr.* = .empty;
try gop.value_ptr.append(
arena,
@@ -11722,6 +11272,7 @@ pub fn createDeclNav(
.analysis = .{
.namespace = namespace,
.zir_index = zir_index,
+ .wanted = false,
},
.status = .unresolved,
}));
@@ -12245,16 +11796,20 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
.type_anyerror_union,
.type_error_set,
.type_inferred_error_set,
+ .type_tuple,
+ .type_function,
+ .type_struct,
+ .type_struct_packed_auto,
+ .type_struct_packed_explicit,
+ .type_struct_packed_auto_defaults,
+ .type_struct_packed_explicit_defaults,
+ .type_union,
+ .type_union_packed_auto,
+ .type_union_packed_explicit,
.type_enum_auto,
.type_enum_explicit,
.type_enum_nonexhaustive,
.type_opaque,
- .type_struct,
- .type_struct_packed,
- .type_struct_packed_inits,
- .type_tuple,
- .type_union,
- .type_function,
=> .type_type,
.undef,
@@ -12278,8 +11833,6 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
.opt_payload,
.error_union_payload,
.int_small,
- .int_lazy_align,
- .int_lazy_size,
.error_set_error,
.error_union_error,
.enum_tag,
@@ -12293,6 +11846,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
.bytes,
.aggregate,
.repeated,
+ .bitpack,
=> |t| {
const extra_list = unwrapped_index.getExtra(ip);
return @enumFromInt(extra_list.view().items(.@"0")[item.data + std.meta.fieldIndex(t.Payload(), "ty").?]);
@@ -12389,20 +11943,6 @@ pub fn funcTypeReturnType(ip: *const InternPool, ty: Index) Index {
]);
}
-pub fn isNoReturn(ip: *const InternPool, ty: Index) bool {
- switch (ty) {
- .noreturn_type => return true,
- else => {
- const unwrapped_ty = ty.unwrap(ip);
- const ty_item = unwrapped_ty.getItem(ip);
- return switch (ty_item.tag) {
- .type_error_set => unwrapped_ty.getExtra(ip).view().items(.@"0")[ty_item.data + std.meta.fieldIndex(Tag.ErrorSet, "names_len").?] == 0,
- else => false,
- };
- },
- }
-}
-
pub fn isUndef(ip: *const InternPool, val: Index) bool {
return val == .undef or val.unwrap(ip).getTag(ip) == .undef;
}
@@ -12613,22 +12153,26 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId {
.type_inferred_error_set,
=> .error_set,
+ .simple_type => unreachable, // handled via Index tag above
+
+ .type_tuple => .@"struct",
+
+ .type_struct,
+ .type_struct_packed_auto,
+ .type_struct_packed_explicit,
+ .type_struct_packed_auto_defaults,
+ .type_struct_packed_explicit_defaults,
+ => .@"struct",
+ .type_union,
+ .type_union_packed_auto,
+ .type_union_packed_explicit,
+ => .@"union",
.type_enum_auto,
.type_enum_explicit,
.type_enum_nonexhaustive,
=> .@"enum",
-
- .simple_type => unreachable, // handled via Index tag above
-
- .type_opaque => .@"opaque",
-
- .type_struct,
- .type_struct_packed,
- .type_struct_packed_inits,
- .type_tuple,
- => .@"struct",
-
- .type_union => .@"union",
+ .type_opaque,
+ => .@"opaque",
.type_function => .@"fn",
@@ -12658,8 +12202,6 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId {
.int_small,
.int_positive,
.int_negative,
- .int_lazy_align,
- .int_lazy_size,
.error_set_error,
.error_union_error,
.error_union_payload,
@@ -12684,6 +12226,7 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId {
.bytes,
.aggregate,
.repeated,
+ .bitpack,
// memoization, not types
.memoized_call,
=> unreachable,
@@ -12871,22 +12414,42 @@ pub fn unwrapCoercedFunc(ip: *const InternPool, index: Index) Index {
};
}
-/// Returns the already-existing field with the same name, if any.
+/// Puts `name` into `names_slice` at the next index (that being the current length of `map`).
+/// Also inserts the name into `map`. If there is an existing field with this name, its index
+/// is returned. Otherwise, `null` is returned.
pub fn addFieldName(
ip: *InternPool,
- extra: Local.Extra,
- names_map: MapIndex,
- names_start: u32,
+ names: NullTerminatedString.Slice,
+ map: MapIndex,
name: NullTerminatedString,
) ?u32 {
- const extra_items = extra.view().items(.@"0");
- const map = names_map.get(ip);
- const field_index = map.count();
- const strings = extra_items[names_start..][0..field_index];
- const adapter: NullTerminatedString.Adapter = .{ .strings = @ptrCast(strings) };
- const gop = map.getOrPutAssumeCapacityAdapted(name, adapter);
+ const m = map.get(ip);
+ const field_idx = m.count();
+ const names_slice = names.get(ip);
+ names_slice[field_idx] = name;
+ const adapter: NullTerminatedString.Adapter = .{ .strings = names_slice[0..field_idx] };
+ const gop = m.getOrPutAssumeCapacityAdapted(name, adapter);
if (gop.found_existing) return @intCast(gop.index);
- extra_items[names_start + field_index] = @intFromEnum(name);
+ assert(gop.index == field_idx);
+ return null;
+}
+
+/// Like `addFieldName`, but instead of adding a field name to a struct, union, or enum, adds a
+/// field tag value for an enum.
+pub fn addFieldTagValue(
+ ip: *InternPool,
+ values: Index.Slice,
+ map: MapIndex,
+ value: Index,
+) ?u32 {
+ const m = map.get(ip);
+ const field_idx = m.count();
+ const values_slice = values.get(ip);
+ values_slice[field_idx] = value;
+ const adapter: Index.Adapter = .{ .indexes = values_slice[0..field_idx] };
+ const gop = m.getOrPutAssumeCapacityAdapted(value, adapter);
+ if (gop.found_existing) return @intCast(gop.index);
+ assert(gop.index == field_idx);
return null;
}
@@ -13169,3 +12732,275 @@ const PackedCallingConvention = packed struct(u18) {
};
}
};
+
+/// Asserts that `struct_type` is a non-packed struct type.
+/// As well as calling this function, the caller must also populate these arrays:
+/// * `field_types`
+/// * `field_aligns`
+/// * `field_runtime_order`
+/// * `field_offsets`
+pub fn resolveStructLayout(
+ ip: *InternPool,
+ io: Io,
+ struct_type: Index,
+ size: u32,
+ alignment: Alignment,
+ class: TypeClass,
+) void {
+ const unwrapped_index = struct_type.unwrap(ip);
+
+ const local = ip.getLocal(unwrapped_index.tid);
+ local.mutate.extra.mutex.lockUncancelable(io);
+ defer local.mutate.extra.mutex.unlock(io);
+
+ const extra_items = local.shared.extra.view().items(.@"0");
+ const item = unwrapped_index.getItem(ip);
+ assert(item.tag == .type_struct);
+
+ extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "size").?] = size;
+ const flags: *Tag.TypeStruct.Flags = @ptrCast(&extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "flags").?]);
+ flags.class = class;
+ flags.alignment = alignment;
+}
+
+/// Asserts that `union_type` is a non-packed union type.
+/// As well as calling this function, the caller must also populate these arrays:
+/// * `field_types`
+/// * `field_aligns`
+pub fn resolveUnionLayout(
+ ip: *InternPool,
+ io: Io,
+ union_type: Index,
+ enum_tag_type: Index,
+ class: TypeClass,
+ has_runtime_tag: bool,
+ size: u32,
+ padding: u32,
+ alignment: Alignment,
+) void {
+ const unwrapped_index = union_type.unwrap(ip);
+
+ const local = ip.getLocal(unwrapped_index.tid);
+ local.mutate.extra.mutex.lockUncancelable(io);
+ defer local.mutate.extra.mutex.unlock(io);
+
+ const extra_items = local.shared.extra.view().items(.@"0");
+ const item = unwrapped_index.getItem(ip);
+ assert(item.tag == .type_union);
+
+ extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "enum_tag_type").?] = @intFromEnum(enum_tag_type);
+ extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "size").?] = size;
+ extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "padding").?] = padding;
+ const flags: *Tag.TypeUnion.Flags = @ptrCast(&extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "flags").?]);
+ flags.class = class;
+ flags.has_runtime_tag = has_runtime_tag;
+ flags.alignment = alignment;
+}
+
+/// Asserts that `struct_type` is a packed struct type.
+pub fn resolvePackedStructLayout(
+ ip: *InternPool,
+ io: Io,
+ struct_type: Index,
+ backing_int_type: Index,
+) void {
+ const unwrapped_index = struct_type.unwrap(ip);
+
+ const local = ip.getLocal(unwrapped_index.tid);
+ local.mutate.extra.mutex.lockUncancelable(io);
+ defer local.mutate.extra.mutex.unlock(io);
+
+ const extra_items = local.shared.extra.view().items(.@"0");
+ const item = unwrapped_index.getItem(ip);
+ switch (item.tag) {
+ .type_struct_packed_auto,
+ .type_struct_packed_explicit,
+ .type_struct_packed_auto_defaults,
+ .type_struct_packed_explicit_defaults,
+ => {},
+ else => unreachable,
+ }
+
+ extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "backing_int_type").?] = @intFromEnum(backing_int_type);
+}
+
+/// Asserts that `union_type` is a packed union type.
+pub fn resolvePackedUnionLayout(
+ ip: *InternPool,
+ io: Io,
+ union_type: Index,
+ enum_tag_type: Index,
+ backing_int_type: Index,
+) void {
+ const unwrapped_index = union_type.unwrap(ip);
+
+ const local = ip.getLocal(unwrapped_index.tid);
+ local.mutate.extra.mutex.lockUncancelable(io);
+ defer local.mutate.extra.mutex.unlock(io);
+
+ const extra_items = local.shared.extra.view().items(.@"0");
+ const item = unwrapped_index.getItem(ip);
+ switch (item.tag) {
+ .type_union_packed_auto,
+ .type_union_packed_explicit,
+ => {},
+ else => unreachable,
+ }
+
+ extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnionPacked, "enum_tag_type").?] = @intFromEnum(enum_tag_type);
+ extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnionPacked, "backing_int_type").?] = @intFromEnum(backing_int_type);
+}
+
+/// Asserts that `enum_type` is an enum type.
+pub fn resolveEnumLayout(
+ ip: *InternPool,
+ io: Io,
+ enum_type: Index,
+ int_tag_type: Index,
+) void {
+ const unwrapped_index = enum_type.unwrap(ip);
+
+ const local = ip.getLocal(unwrapped_index.tid);
+ local.mutate.extra.mutex.lockUncancelable(io);
+ defer local.mutate.extra.mutex.unlock(io);
+
+ const extra_items = local.shared.extra.view().items(.@"0");
+ const item = unwrapped_index.getItem(ip);
+ switch (item.tag) {
+ .type_enum_auto,
+ .type_enum_explicit,
+ .type_enum_nonexhaustive,
+ => {},
+ else => unreachable,
+ }
+
+ extra_items[item.data + std.meta.fieldIndex(Tag.TypeEnum, "int_tag_type").?] = @intFromEnum(int_tag_type);
+}
+
+/// Sets the "want_layout" flag on the given struct, union, or enum type. Returns true if the flag
+/// was *not* already set, meaning we have just discovered the first reference to this type's
+/// layout. This flag is never reset to false, and exists purely as an optimization; for details,
+/// see doc comments in `LoadedStructType`.
+pub fn setWantTypeLayout(ip: *InternPool, io: Io, container_type: Index) bool {
+ const unwrapped_index = container_type.unwrap(ip);
+
+ const local = ip.getLocal(unwrapped_index.tid);
+ local.mutate.extra.mutex.lockUncancelable(io);
+ defer local.mutate.extra.mutex.unlock(io);
+
+ const extra_items = local.shared.extra.view().items(.@"0");
+ const item = unwrapped_index.getItem(ip);
+ switch (item.tag) {
+ .type_struct_packed_auto,
+ .type_struct_packed_explicit,
+ .type_struct_packed_auto_defaults,
+ .type_struct_packed_explicit_defaults,
+ => {
+ const bits: *Tag.TypeStructPacked.Bits = @ptrCast(&extra_items[
+ item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "bits").?
+ ]);
+ if (bits.want_layout) {
+ return false;
+ } else {
+ bits.want_layout = true;
+ return true;
+ }
+ },
+
+ .type_struct => {
+ const flags: *Tag.TypeStruct.Flags = @ptrCast(&extra_items[
+ item.data + std.meta.fieldIndex(Tag.TypeStruct, "flags").?
+ ]);
+ if (flags.want_layout) {
+ return false;
+ } else {
+ flags.want_layout = true;
+ return true;
+ }
+ },
+
+ .type_union_packed_auto,
+ .type_union_packed_explicit,
+ => {
+ const bits: *Tag.TypeUnionPacked.Bits = @ptrCast(&extra_items[
+ item.data + std.meta.fieldIndex(Tag.TypeUnionPacked, "bits").?
+ ]);
+ if (bits.want_layout) {
+ return false;
+ } else {
+ bits.want_layout = true;
+ return true;
+ }
+ },
+
+ .type_union => {
+ const flags: *Tag.TypeUnion.Flags = @ptrCast(&extra_items[
+ item.data + std.meta.fieldIndex(Tag.TypeUnion, "flags").?
+ ]);
+ if (flags.want_layout) {
+ return false;
+ } else {
+ flags.want_layout = true;
+ return true;
+ }
+ },
+
+ .type_enum_auto,
+ .type_enum_explicit,
+ .type_enum_nonexhaustive,
+ => {
+ const bits: *Tag.TypeEnum.Bits = @ptrCast(&extra_items[
+ item.data + std.meta.fieldIndex(Tag.TypeEnum, "bits").?
+ ]);
+ if (bits.want_layout) {
+ return false;
+ } else {
+ bits.want_layout = true;
+ return true;
+ }
+ },
+
+ else => unreachable,
+ }
+}
+
+/// Like `setWantTypeLayout`, but for runtime analysis of a function body, using the
+/// `FuncAnalysis.want_runtime_analysis` flag.
+pub fn setWantRuntimeFnAnalysis(ip: *InternPool, io: Io, func_index: Index) bool {
+ const unwrapped_index = func_index.unwrap(ip);
+
+ const local = ip.getLocal(unwrapped_index.tid);
+ local.mutate.extra.mutex.lockUncancelable(io);
+ defer local.mutate.extra.mutex.unlock(io);
+
+ const a = funcAnalysisPtr(ip, func_index);
+ if (a.want_runtime_analysis) {
+ return false;
+ } else {
+ a.want_runtime_analysis = true;
+ return true;
+ }
+}
+
+/// Like `setWantTypeLayout`, but for runtime analysis of a `Nav`, using the `Nav.analysis.wanted` flag.
+pub fn setWantNavAnalysis(ip: *InternPool, io: Io, nav_index: Nav.Index) bool {
+ const unwrapped = nav_index.unwrap(ip);
+
+ const local = ip.getLocal(unwrapped.tid);
+ local.mutate.extra.mutex.lockUncancelable(io);
+ defer local.mutate.extra.mutex.unlock(io);
+
+ const navs = local.shared.navs.view();
+
+ if (navs.items(.analysis_namespace)[unwrapped.index] == .none) {
+ return false;
+ }
+
+ const bits = &navs.items(.bits)[unwrapped.index];
+ if (bits.want_analysis) {
+ return false;
+ } else {
+ bits.want_analysis = true;
+ return true;
+ }
+}
diff --git a/src/Package/Manifest.zig b/src/Package/Manifest.zig
index 3370ef1d47dd6c771c5428adabe7160ea4964992..90d61c963b8a6ac8d6f62028f1e37f4d38a70fb5 100644
--- a/src/Package/Manifest.zig
+++ b/src/Package/Manifest.zig
@@ -66,7 +66,7 @@ pub fn parse(gpa: Allocator, ast: *const Ast, rng: std.Random, options: ParseOpt
.gpa = gpa,
.ast = ast.*,
.arena = arena_instance.allocator(),
- .errors = .{},
+ .errors = .empty,
.name = undefined,
.id = 0,
@@ -74,10 +74,10 @@ pub fn parse(gpa: Allocator, ast: *const Ast, rng: std.Random, options: ParseOpt
.version_node = undefined,
.dependencies = .{},
.dependencies_node = .none,
- .paths = .{},
+ .paths = .empty,
.allow_missing_paths_field = options.allow_missing_paths_field,
.minimum_zig_version = null,
- .buf = .{},
+ .buf = .empty,
};
defer p.buf.deinit(gpa);
defer p.errors.deinit(gpa);
diff --git a/src/Sema.zig b/src/Sema.zig
index 58fa1af124239ff05093bc9cf857a16f36de09e4..f2c52697b420eeca9674ed4f2e5f75060a67809a 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -173,13 +173,20 @@ const ComptimeAlloc = struct {
runtime_index: RuntimeIndex,
};
+/// Asserts that `ty` is not an OPV type.
/// `src` may be `null` if `is_const` will be set.
fn newComptimeAlloc(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type, alignment: Alignment) !ComptimeAllocIndex {
const pt = sema.pt;
- const init_val = try sema.typeHasOnePossibleValue(ty) orelse try pt.undefValue(ty);
+
+ switch (ty.classify(pt.zcu)) {
+ .no_possible_value => unreachable,
+ .one_possible_value => unreachable,
+ else => {},
+ }
+
const idx = sema.comptime_allocs.items.len;
try sema.comptime_allocs.append(sema.gpa, .{
- .val = .{ .interned = init_val.toIntern() },
+ .val = .{ .interned = (try pt.undefValue(ty)).toIntern() },
.is_const = false,
.src = src,
.alignment = alignment,
@@ -393,7 +400,7 @@ pub const Block = struct {
/// The name of the current "context" for naming namespace types.
/// The interpretation of this depends on the name strategy in ZIR, but the name
/// is always incorporated into the type name somehow.
- /// See `Sema.createTypeName`.
+ /// See `Sema.setTypeName`.
type_name_ctx: InternPool.NullTerminatedString,
/// Create a `LazySrcLoc` based on an `Offset` from the code being analyzed in this block.
@@ -409,7 +416,7 @@ pub const Block = struct {
return block.comptime_reason != null;
}
- fn builtinCallArgSrc(block: *Block, builtin_call_node: std.zig.Ast.Node.Offset, arg_index: u32) LazySrcLoc {
+ pub fn builtinCallArgSrc(block: *Block, builtin_call_node: std.zig.Ast.Node.Offset, arg_index: u32) LazySrcLoc {
return block.src(.{ .node_offset_builtin_call_arg = .{
.builtin_call_node = builtin_call_node,
.arg_index = arg_index,
@@ -1082,7 +1089,7 @@ fn analyzeInlineBody(
// This control flow goes further up the stack.
return error.ComptimeBreak;
}
- return try sema.resolveInst(break_inst.data.@"break".operand);
+ return sema.resolveInst(break_inst.data.@"break".operand);
}
/// Like `analyzeInlineBody`, but if the body does not break with a value, returns
@@ -1154,7 +1161,7 @@ fn analyzeBodyInner(
}, inst });
}
- const air_inst: Air.Inst.Ref = inst: switch (tags[@intFromEnum(inst)]) {
+ const air_ref: Air.Inst.Ref = inst: switch (tags[@intFromEnum(inst)]) {
// zig fmt: off
.alloc => try sema.zirAlloc(block, inst),
.alloc_inferred => try sema.zirAllocInferred(block, true),
@@ -1382,10 +1389,10 @@ fn analyzeBodyInner(
const extended = datas[@intFromEnum(inst)].extended;
break :ext switch (extended.opcode) {
// zig fmt: off
- .struct_decl => try sema.zirStructDecl( block, extended, inst),
- .enum_decl => try sema.zirEnumDecl( block, extended, inst),
- .union_decl => try sema.zirUnionDecl( block, extended, inst),
- .opaque_decl => try sema.zirOpaqueDecl( block, extended, inst),
+ .struct_decl => try sema.zirStructDecl( block, inst),
+ .enum_decl => try sema.zirEnumDecl( block, inst),
+ .union_decl => try sema.zirUnionDecl( block, inst),
+ .opaque_decl => try sema.zirOpaqueDecl( block, inst),
.tuple_decl => try sema.zirTupleDecl( block, extended),
.this => try sema.zirThis( block, extended),
.ret_addr => try sema.zirRetAddr( block, extended),
@@ -1869,7 +1876,7 @@ fn analyzeBodyInner(
const break_data = opt_break_data orelse break;
if (inst == break_data.block_inst) {
- break :blk try sema.resolveInst(break_data.operand);
+ break :blk sema.resolveInst(break_data.operand);
} else {
// `comptime_break_inst` preserved from `analyzeBodyInner` above.
return error.ComptimeBreak;
@@ -1890,7 +1897,7 @@ fn analyzeBodyInner(
extra.end + then_body.len,
extra.data.else_body_len,
);
- const uncasted_cond = try sema.resolveInst(extra.data.condition);
+ const uncasted_cond = sema.resolveInst(extra.data.condition);
const cond = try sema.coerce(block, .bool, uncasted_cond, cond_src);
const cond_val = try sema.resolveConstDefinedValue(
block,
@@ -1916,7 +1923,7 @@ fn analyzeBodyInner(
const operand_src = block.src(.{ .node_offset_try_operand = inst_data.src_node });
const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);
const inline_body = sema.code.bodySlice(extra.end, extra.data.body_len);
- const err_union = try sema.resolveInst(extra.data.operand);
+ const err_union = sema.resolveInst(extra.data.operand);
const err_union_ty = sema.typeOf(err_union);
if (err_union_ty.zigTypeTag(zcu) != .error_union) {
return sema.failWithOwnedErrorMsg(block, msg: {
@@ -1942,7 +1949,7 @@ fn analyzeBodyInner(
const operand_src = block.src(.{ .node_offset_try_operand = inst_data.src_node });
const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);
const inline_body = sema.code.bodySlice(extra.end, extra.data.body_len);
- const operand = try sema.resolveInst(extra.data.operand);
+ const operand = sema.resolveInst(extra.data.operand);
const err_union = try sema.analyzeLoad(block, src, operand, operand_src);
const is_non_err_val = (try sema.resolveIsNonErrVal(block, operand_src, err_union)).?;
if (is_non_err_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, operand_src, null);
@@ -1971,7 +1978,7 @@ fn analyzeBodyInner(
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].defer_err_code;
const extra = sema.code.extraData(Zir.Inst.DeferErrCode, inst_data.payload_index).data;
const defer_body = sema.code.bodySlice(extra.index, extra.len);
- const err_code = try sema.resolveInst(inst_data.err_code);
+ const err_code = sema.resolveInst(inst_data.err_code);
try map.ensureSpaceForInstructions(sema.gpa, defer_body);
map.putAssumeCapacity(extra.remapped_err_code, err_code);
if (sema.analyzeBodyInner(block, defer_body)) {
@@ -1987,18 +1994,35 @@ fn analyzeBodyInner(
break :blk .void_value;
},
};
- if (sema.isNoReturn(air_inst)) {
- // We're going to assume that the body itself is noreturn, so let's ensure that now
- assert(block.instructions.items.len > 0);
- assert(sema.isNoReturn(block.instructions.items[block.instructions.items.len - 1].toRef()));
- break;
- }
- map.putAssumeCapacity(inst, air_inst);
+
+ const is_inferred_alloc = if (air_ref.toIndex()) |air_inst| switch (sema.air_instructions.items(.tag)[@intFromEnum(air_inst)]) {
+ .inferred_alloc, .inferred_alloc_comptime => true,
+ else => false,
+ } else false;
+ // We must resolve the layout of a type before creating a value of that type. Therefore,
+ // the layout of the type of `air_ref` must already be resolved. The call to `classify`
+ // doubles as an assertion of this.
+ if (!is_inferred_alloc) switch (sema.typeOf(air_ref).classify(zcu)) {
+ .no_possible_value => {
+ // The instruction result was noreturn, which should mean that the body itself now
+ // ends with a noreturn instruction. Let's confirm that.
+ const last_inst = block.instructions.items[block.instructions.items.len - 1];
+ const last_inst_ty = sema.typeOf(last_inst.toRef());
+ assert(last_inst_ty.classify(zcu) == .no_possible_value);
+ break;
+ },
+ .one_possible_value => assert(air_ref.toInterned() != null), // the value should be comptime-known
+ .partially_comptime => assert(air_ref.toInterned() != null), // the value should be comptime-known
+ .fully_comptime => assert(air_ref.toInterned() != null), // the value should be comptime-known
+ .runtime => {},
+ };
+
+ map.putAssumeCapacity(inst, air_ref);
i += 1;
}
}
-pub fn resolveInstAllowNone(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref {
+fn resolveInstAllowNone(sema: *Sema, zir_ref: Zir.Inst.Ref) Air.Inst.Ref {
if (zir_ref == .none) {
return .none;
} else {
@@ -2006,7 +2030,7 @@ pub fn resolveInstAllowNone(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref {
}
}
-pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref {
+fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) Air.Inst.Ref {
assert(zir_ref != .none);
if (zir_ref.toIndex()) |i| {
return sema.inst_map.get(i).?;
@@ -2023,7 +2047,7 @@ fn resolveConstBool(
zir_ref: Zir.Inst.Ref,
reason: ComptimeReason,
) !bool {
- const air_inst = try sema.resolveInst(zir_ref);
+ const air_inst = sema.resolveInst(zir_ref);
const wanted_type: Type = .bool;
const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src);
const val = try sema.resolveConstDefinedValue(block, src, coerced_inst, reason);
@@ -2039,7 +2063,7 @@ fn resolveConstString(
/// being comptime-resolved is that the block is being comptime-evaluated.
reason: ?ComptimeReason,
) ![]u8 {
- const air_inst = try sema.resolveInst(zir_ref);
+ const air_inst = sema.resolveInst(zir_ref);
return sema.toConstString(block, src, air_inst, reason);
}
@@ -2066,7 +2090,7 @@ pub fn resolveConstStringIntern(
zir_ref: Zir.Inst.Ref,
reason: ComptimeReason,
) !InternPool.NullTerminatedString {
- const air_inst = try sema.resolveInst(zir_ref);
+ const air_inst = sema.resolveInst(zir_ref);
const wanted_type: Type = .slice_const_u8;
const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src);
const val = try sema.resolveConstDefinedValue(block, src, coerced_inst, reason);
@@ -2074,8 +2098,8 @@ pub fn resolveConstStringIntern(
}
fn resolveTypeOrPoison(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) !?Type {
- const air_inst = try sema.resolveInst(zir_ref);
- const ty = try sema.analyzeAsType(block, src, air_inst);
+ const air_inst = sema.resolveInst(zir_ref);
+ const ty = try sema.analyzeAsType(block, src, .type, air_inst);
if (ty.isGenericPoison()) return null;
return ty;
}
@@ -2168,7 +2192,7 @@ fn genericPoisonReason(sema: *Sema, block: *Block, ref: Zir.Inst.Ref) GenericPoi
// There are two cases here: the pointer type may already have been
// generic poison, or it may have been an anyopaque pointer.
const un_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
- const operand_ref = try sema.resolveInst(un_node.operand);
+ const operand_ref = sema.resolveInst(un_node.operand);
const operand_val = operand_ref.toInterned() orelse return .unknown;
if (operand_val == .generic_poison_type) {
// The pointer was generic poison - keep looking.
@@ -2190,15 +2214,16 @@ fn genericPoisonReason(sema: *Sema, block: *Block, ref: Zir.Inst.Ref) GenericPoi
}
}
-fn analyzeAsType(
+pub fn analyzeAsType(
sema: *Sema,
block: *Block,
src: LazySrcLoc,
+ reason: std.zig.SimpleComptimeReason,
air_inst: Air.Inst.Ref,
) !Type {
const wanted_type: Type = .type;
const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src);
- const val = try sema.resolveConstDefinedValue(block, src, coerced_inst, .{ .simple = .type });
+ const val = try sema.resolveConstDefinedValue(block, src, coerced_inst, .{ .simple = reason });
return val.toType();
}
@@ -2227,7 +2252,6 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize)
// var st: StackTrace = undefined;
const stack_trace_ty = try sema.getBuiltinType(block.nodeOffset(.zero), .StackTrace);
- try stack_trace_ty.resolveFields(pt);
const st_ptr = try err_trace_block.addTy(.alloc, try pt.singleMutPtrType(stack_trace_ty));
// st.instruction_addresses = &addrs;
@@ -2247,14 +2271,10 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize)
}
/// Return the Value corresponding to a given AIR ref, or `null` if it refers to a runtime value.
-fn resolveValue(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value {
+fn resolveValue(sema: *Sema, inst: Air.Inst.Ref) ?Value {
const zcu = sema.pt.zcu;
assert(inst != .none);
- if (try sema.typeHasOnePossibleValue(sema.typeOf(inst))) |opv| {
- return opv;
- }
-
if (inst.toInterned()) |ip_index| {
const val: Value = .fromInterned(ip_index);
assert(val.getVariable(zcu) == null);
@@ -2267,12 +2287,21 @@ fn resolveValue(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value {
.inferred_alloc_comptime => unreachable, // assertion failure
else => {},
}
+ // LLVM fails to eliminate this `classify` call in ReleaseFast, which hurts performance, so
+ // we must explicitly check for `std.debug.runtime_safety`.
+ if (std.debug.runtime_safety) switch (sema.typeOf(inst).classify(zcu)) {
+ .no_possible_value => unreachable, // values of this type do not exist
+ .one_possible_value => unreachable, // the value should be comptime-known
+ .partially_comptime => unreachable, // the value should be comptime-known
+ .fully_comptime => unreachable, // the value should be comptime-known
+ .runtime => {},
+ };
return null;
}
}
/// Like `resolveValue`, but emits an error if the value is not comptime-known.
-fn resolveConstValue(
+pub fn resolveConstValue(
sema: *Sema,
block: *Block,
src: LazySrcLoc,
@@ -2281,7 +2310,8 @@ fn resolveConstValue(
/// being comptime-resolved is that the block is being comptime-evaluated.
reason: ?ComptimeReason,
) CompileError!Value {
- return try sema.resolveValue(inst) orelse {
+ assert(reason != null or block.isComptime());
+ return sema.resolveValue(inst) orelse {
return sema.failWithNeededComptime(block, src, reason);
};
}
@@ -2295,13 +2325,13 @@ fn resolveDefinedValue(
) CompileError!?Value {
const pt = sema.pt;
const zcu = pt.zcu;
- const val = try sema.resolveValue(air_ref) orelse return null;
+ const val = sema.resolveValue(air_ref) orelse return null;
if (val.isUndef(zcu)) return sema.failWithUseOfUndef(block, src, null);
return val;
}
/// Like `resolveValue`, but emits an error if the value is not comptime-known or is undefined.
-fn resolveConstDefinedValue(
+pub fn resolveConstDefinedValue(
sema: *Sema,
block: *Block,
src: LazySrcLoc,
@@ -2315,11 +2345,6 @@ fn resolveConstDefinedValue(
return val;
}
-/// Like `resolveValue`, but recursively resolves lazy values before returning.
-fn resolveValueResolveLazy(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value {
- return try sema.resolveLazyValue((try sema.resolveValue(inst)) orelse return null);
-}
-
/// Value Tag may be `undef` or `variable`.
pub fn resolveFinalDeclValue(
sema: *Sema,
@@ -2439,13 +2464,14 @@ fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, non
fn failWithArrayInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError {
const pt = sema.pt;
+ const zcu = pt.zcu;
const msg = msg: {
const msg = try sema.errMsg(src, "type '{f}' does not support array initialization syntax", .{
ty.fmt(pt),
});
errdefer msg.destroy(sema.gpa);
- if (ty.isSlice(pt.zcu)) {
- try sema.errNote(src, msg, "inferred array length is specified with an underscore: '[_]{f}'", .{ty.elemType2(pt.zcu).fmt(pt)});
+ if (ty.isSlice(zcu)) {
+ try sema.errNote(src, msg, "inferred array length is specified with an underscore: '[_]{f}'", .{ty.childType(zcu).fmt(pt)});
}
break :msg msg;
};
@@ -2644,7 +2670,7 @@ pub fn fail(
src: LazySrcLoc,
comptime format: []const u8,
args: anytype,
-) CompileError {
+) SemaError {
const err_msg = try sema.errMsg(src, format, args);
inline for (args) |arg| {
if (@TypeOf(arg) == Type.Formatter) {
@@ -2772,7 +2798,7 @@ fn resolveAlign(
src: LazySrcLoc,
zir_ref: Zir.Inst.Ref,
) !Alignment {
- const air_ref = try sema.resolveInst(zir_ref);
+ const air_ref = sema.resolveInst(zir_ref);
return sema.analyzeAsAlign(block, src, air_ref);
}
@@ -2784,7 +2810,7 @@ fn resolveInt(
dest_ty: Type,
reason: ComptimeReason,
) !u64 {
- const air_ref = try sema.resolveInst(zir_ref);
+ const air_ref = sema.resolveInst(zir_ref);
return sema.analyzeAsInt(block, src, air_ref, dest_ty, reason);
}
@@ -2798,27 +2824,26 @@ fn analyzeAsInt(
) !u64 {
const coerced = try sema.coerce(block, dest_ty, air_ref, src);
const val = try sema.resolveConstDefinedValue(block, src, coerced, reason);
- return try val.toUnsignedIntSema(sema.pt);
+ return val.toUnsignedInt(sema.pt.zcu);
}
fn analyzeValueAsCallconv(
sema: *Sema,
block: *Block,
src: LazySrcLoc,
- unresolved_val: Value,
+ val: Value,
) !std.builtin.CallingConvention {
- return interpretBuiltinType(sema, block, src, unresolved_val, std.builtin.CallingConvention);
+ return interpretBuiltinType(sema, block, src, val, std.builtin.CallingConvention);
}
fn interpretBuiltinType(
sema: *Sema,
block: *Block,
src: LazySrcLoc,
- unresolved_val: Value,
+ val: Value,
comptime T: type,
) !T {
- const resolved_val = try sema.resolveLazyValue(unresolved_val);
- return resolved_val.interpret(T, sema.pt) catch |err| switch (err) {
+ return val.interpret(T, sema.pt) catch |err| switch (err) {
error.OutOfMemory => |e| return e,
error.UndefinedValue => return sema.failWithUseOfUndef(block, src, null),
error.TypeMismatch => @panic("std.builtin is corrupt"),
@@ -2864,7 +2889,7 @@ fn zirTupleDecl(
field_ty.* = field_type.toIntern();
field_init.* = init: {
if (zir_field_init != .none) {
- const uncoerced_field_init = try sema.resolveInst(zir_field_init);
+ const uncoerced_field_init = sema.resolveInst(zir_field_init);
const coerced_field_init = try sema.coerce(block, field_type, uncoerced_field_init, init_src);
const field_init_val = try sema.resolveConstDefinedValue(block, init_src, coerced_field_init, .{ .simple = .tuple_field_default_value });
if (field_init_val.canMutateComptimeVarState(zcu)) {
@@ -2913,7 +2938,13 @@ fn validateTupleFieldType(
/// Given a ZIR extra index which points to a list of `Zir.Inst.Capture`,
/// resolves this into a list of `InternPool.CaptureValue` allocated by `arena`.
-fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: usize, captures_len: u32) ![]InternPool.CaptureValue {
+fn getCaptures(
+ sema: *Sema,
+ block: *Block,
+ type_src: LazySrcLoc,
+ zir_captures: []const Zir.Inst.Capture,
+ zir_capture_names: []const Zir.NullTerminatedString,
+) ![]InternPool.CaptureValue {
const pt = sema.pt;
const zcu = pt.zcu;
const comp = zcu.comp;
@@ -2924,41 +2955,38 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us
const parent_ty: Type = .fromInterned(zcu.namespacePtr(block.namespace).owner_type);
const parent_captures: InternPool.CaptureValue.Slice = parent_ty.getCaptures(zcu);
- const captures = try sema.arena.alloc(InternPool.CaptureValue, captures_len);
+ const captures = try sema.arena.alloc(InternPool.CaptureValue, zir_captures.len);
- for (sema.code.extra[extra_index..][0..captures_len], sema.code.extra[extra_index + captures_len ..][0..captures_len], captures) |raw, raw_name, *capture| {
- const zir_capture: Zir.Inst.Capture = @bitCast(raw);
- const zir_name: Zir.NullTerminatedString = @enumFromInt(raw_name);
+ for (zir_captures, zir_capture_names, captures) |zir_capture, zir_name, *capture| {
const zir_name_slice = sema.code.nullTerminatedString(zir_name);
capture.* = switch (zir_capture.unwrap()) {
.nested => |parent_idx| parent_captures.get(ip)[parent_idx],
- .instruction_load => |ptr_inst| InternPool.CaptureValue.wrap(capture: {
- const ptr_ref = try sema.resolveInst(ptr_inst.toRef());
- const ptr_val = try sema.resolveValue(ptr_ref) orelse {
- break :capture .{ .runtime = sema.typeOf(ptr_ref).childType(zcu).toIntern() };
+ .instruction_load => |ptr_inst| capture: {
+ const ptr_ref = sema.resolveInst(ptr_inst.toRef());
+ const ptr_val = sema.resolveValue(ptr_ref) orelse {
+ break :capture .wrap(.{ .runtime = sema.typeOf(ptr_ref).childType(zcu).toIntern() });
};
// TODO: better source location
- const unresolved_loaded_val = try sema.pointerDeref(block, type_src, ptr_val, sema.typeOf(ptr_ref)) orelse {
- break :capture .{ .runtime = sema.typeOf(ptr_ref).childType(zcu).toIntern() };
+ const loaded_val = try sema.pointerDeref(block, type_src, ptr_val, sema.typeOf(ptr_ref)) orelse {
+ break :capture .wrap(.{ .runtime = sema.typeOf(ptr_ref).childType(zcu).toIntern() });
};
- const loaded_val = try sema.resolveLazyValue(unresolved_loaded_val);
if (loaded_val.canMutateComptimeVarState(zcu)) {
const field_name = try ip.getOrPutString(gpa, io, pt.tid, zir_name_slice, .no_embedded_nulls);
return sema.failWithContainsReferenceToComptimeVar(block, type_src, field_name, "captured value", loaded_val);
}
- break :capture .{ .@"comptime" = loaded_val.toIntern() };
- }),
- .instruction => |inst| InternPool.CaptureValue.wrap(capture: {
- const air_ref = try sema.resolveInst(inst.toRef());
- if (try sema.resolveValueResolveLazy(air_ref)) |val| {
+ break :capture .wrap(.{ .@"comptime" = loaded_val.toIntern() });
+ },
+ .instruction => |inst| capture: {
+ const air_ref = sema.resolveInst(inst.toRef());
+ if (sema.resolveValue(air_ref)) |val| {
if (val.canMutateComptimeVarState(zcu)) {
const field_name = try ip.getOrPutString(gpa, io, pt.tid, zir_name_slice, .no_embedded_nulls);
return sema.failWithContainsReferenceToComptimeVar(block, type_src, field_name, "captured value", val);
}
- break :capture .{ .@"comptime" = val.toIntern() };
+ break :capture .wrap(.{ .@"comptime" = val.toIntern() });
}
- break :capture .{ .runtime = sema.typeOf(air_ref).toIntern() };
- }),
+ break :capture .wrap(.{ .runtime = sema.typeOf(air_ref).toIntern() });
+ },
.decl_val => |str| capture: {
const decl_name = try ip.getOrPutString(
gpa,
@@ -2968,7 +2996,7 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us
.no_embedded_nulls,
);
const nav = try sema.lookupIdentifier(block, decl_name);
- break :capture InternPool.CaptureValue.wrap(.{ .nav_val = nav });
+ break :capture .wrap(.{ .nav_val = nav });
},
.decl_ref => |str| capture: {
const decl_name = try ip.getOrPutString(
@@ -2987,621 +3015,6 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us
return captures;
}
-fn zirStructDecl(
- sema: *Sema,
- block: *Block,
- extended: Zir.Inst.Extended.InstData,
- inst: Zir.Inst.Index,
-) CompileError!Air.Inst.Ref {
- const pt = sema.pt;
- const zcu = pt.zcu;
- const comp = zcu.comp;
- const gpa = comp.gpa;
- const io = comp.io;
- const ip = &zcu.intern_pool;
-
- const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
- const extra = sema.code.extraData(Zir.Inst.StructDecl, extended.operand);
-
- const tracked_inst = try block.trackZir(inst);
- const src: LazySrcLoc = .{
- .base_node_inst = tracked_inst,
- .offset = LazySrcLoc.Offset.nodeOffset(.zero),
- };
-
- var extra_index = extra.end;
-
- const captures_len = if (small.has_captures_len) blk: {
- const captures_len = sema.code.extra[extra_index];
- extra_index += 1;
- break :blk captures_len;
- } else 0;
- const fields_len = if (small.has_fields_len) blk: {
- const fields_len = sema.code.extra[extra_index];
- extra_index += 1;
- break :blk fields_len;
- } else 0;
- const decls_len = if (small.has_decls_len) blk: {
- const decls_len = sema.code.extra[extra_index];
- extra_index += 1;
- break :blk decls_len;
- } else 0;
-
- const captures = try sema.getCaptures(block, src, extra_index, captures_len);
- extra_index += captures_len * 2;
-
- if (small.has_backing_int) {
- const backing_int_body_len = sema.code.extra[extra_index];
- extra_index += 1; // backing_int_body_len
- if (backing_int_body_len == 0) {
- extra_index += 1; // backing_int_ref
- } else {
- extra_index += backing_int_body_len; // backing_int_body_inst
- }
- }
-
- const struct_init: InternPool.StructTypeInit = .{
- .layout = small.layout,
- .fields_len = fields_len,
- .known_non_opv = small.known_non_opv,
- .requires_comptime = if (small.known_comptime_only) .yes else .unknown,
- .any_comptime_fields = small.any_comptime_fields,
- .any_default_inits = small.any_default_inits,
- .inits_resolved = false,
- .any_aligned_fields = small.any_aligned_fields,
- .key = .{ .declared = .{
- .zir_index = tracked_inst,
- .captures = captures,
- } },
- };
- const wip_ty = switch (try ip.getStructType(gpa, io, pt.tid, struct_init, false)) {
- .existing => |ty| {
- const new_ty = try pt.ensureTypeUpToDate(ty);
-
- // Make sure we update the namespace if the declaration is re-analyzed, to pick
- // up on e.g. changed comptime decls.
- try pt.ensureNamespaceUpToDate(Type.fromInterned(new_ty).getNamespaceIndex(zcu));
-
- try sema.declareDependency(.{ .interned = new_ty });
- try sema.addTypeReferenceEntry(src, new_ty);
- return Air.internedToRef(new_ty);
- },
- .wip => |wip| wip,
- };
- errdefer wip_ty.cancel(ip, pt.tid);
-
- const type_name = try sema.createTypeName(
- block,
- small.name_strategy,
- "struct",
- inst,
- wip_ty.index,
- );
- wip_ty.setName(ip, type_name.name, type_name.nav);
-
- const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
- .parent = block.namespace.toOptional(),
- .owner_type = wip_ty.index,
- .file_scope = block.getFileScopeIndex(zcu),
- .generation = zcu.generation,
- });
- errdefer pt.destroyNamespace(new_namespace_index);
-
- if (pt.zcu.comp.config.incremental) {
- try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = tracked_inst });
- }
-
- const decls = sema.code.bodySlice(extra_index, decls_len);
- try pt.scanNamespace(new_namespace_index, decls);
-
- try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
- codegen_type: {
- if (zcu.comp.config.use_llvm) break :codegen_type;
- if (block.ownerModule().strip) break :codegen_type;
- // This job depends on any resolve_type_fully jobs queued up before it.
- zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
- try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
- }
- try sema.declareDependency(.{ .interned = wip_ty.index });
- try sema.addTypeReferenceEntry(src, wip_ty.index);
- if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
- return Air.internedToRef(wip_ty.finish(ip, new_namespace_index));
-}
-
-pub fn createTypeName(
- sema: *Sema,
- block: *Block,
- name_strategy: Zir.Inst.NameStrategy,
- anon_prefix: []const u8,
- inst: ?Zir.Inst.Index,
- /// This is used purely to give the type a unique name in the `anon` case.
- type_index: InternPool.Index,
-) CompileError!struct {
- name: InternPool.NullTerminatedString,
- nav: InternPool.Nav.Index.Optional,
-} {
- const pt = sema.pt;
- const zcu = pt.zcu;
- const comp = zcu.comp;
- const gpa = comp.gpa;
- const io = comp.io;
- const ip = &zcu.intern_pool;
-
- switch (name_strategy) {
- .anon => {}, // handled after switch
- .parent => return .{
- .name = block.type_name_ctx,
- .nav = sema.owner.unwrap().nav_val.toOptional(),
- },
- .func => func_strat: {
- const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip) orelse return error.AnalysisFail);
- const zir_tags = sema.code.instructions.items(.tag);
-
- var aw: std.Io.Writer.Allocating = .init(gpa);
- defer aw.deinit();
- const w = &aw.writer;
- w.print("{f}(", .{block.type_name_ctx.fmt(ip)}) catch return error.OutOfMemory;
-
- var arg_i: usize = 0;
- for (fn_info.param_body) |zir_inst| switch (zir_tags[@intFromEnum(zir_inst)]) {
- .param, .param_comptime, .param_anytype, .param_anytype_comptime => {
- const arg = sema.inst_map.get(zir_inst).?;
- // If this is being called in a generic function then analyzeCall will
- // have already resolved the args and this will work.
- // If not then this is a struct type being returned from a non-generic
- // function and the name doesn't matter since it will later
- // result in a compile error.
- const arg_val = try sema.resolveValue(arg) orelse break :func_strat; // fall through to anon strat
-
- if (arg_i != 0) w.writeByte(',') catch return error.OutOfMemory;
-
- // Limiting the depth here helps avoid type names getting too long, which
- // in turn helps to avoid unreasonably long symbol names for namespaced
- // symbols. Such names should ideally be human-readable, and additionally,
- // some tooling may not support very long symbol names.
- w.print("{f}", .{Value.fmtValueSemaFull(.{
- .val = arg_val,
- .pt = pt,
- .opt_sema = sema,
- .depth = 1,
- })}) catch return error.OutOfMemory;
-
- arg_i += 1;
- continue;
- },
- else => continue,
- };
-
- w.writeByte(')') catch return error.OutOfMemory;
- return .{
- .name = try ip.getOrPutString(gpa, io, pt.tid, aw.written(), .no_embedded_nulls),
- .nav = .none,
- };
- },
- .dbg_var => {
- // TODO: this logic is questionable. We ideally should be traversing the `Block` rather than relying on the order of AstGen instructions.
- const ref = inst.?.toRef();
- const zir_tags = sema.code.instructions.items(.tag);
- const zir_data = sema.code.instructions.items(.data);
- for (@intFromEnum(inst.?)..zir_tags.len) |i| switch (zir_tags[i]) {
- .dbg_var_ptr, .dbg_var_val => if (zir_data[i].str_op.operand == ref) {
- return .{
- .name = try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}.{s}", .{
- block.type_name_ctx.fmt(ip), zir_data[i].str_op.getStr(sema.code),
- }, .no_embedded_nulls),
- .nav = .none,
- };
- },
- else => {},
- };
- // fall through to anon strat
- },
- }
-
- // anon strat handling
-
- // It would be neat to have "struct:line:column" but this name has
- // to survive incremental updates, where it may have been shifted down
- // or up to a different line, but unchanged, and thus not unnecessarily
- // semantically analyzed.
- // TODO: that would be possible, by detecting line number changes and renaming
- // types appropriately. However, `@typeName` becomes a problem then. If we remove
- // that builtin from the language, we can consider this.
-
- return .{
- .name = try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}__{s}_{d}", .{
- block.type_name_ctx.fmt(ip), anon_prefix, @intFromEnum(type_index),
- }, .no_embedded_nulls),
- .nav = .none,
- };
-}
-
-fn zirEnumDecl(
- sema: *Sema,
- block: *Block,
- extended: Zir.Inst.Extended.InstData,
- inst: Zir.Inst.Index,
-) CompileError!Air.Inst.Ref {
- const tracy = trace(@src());
- defer tracy.end();
-
- const pt = sema.pt;
- const zcu = pt.zcu;
- const comp = zcu.comp;
- const gpa = comp.gpa;
- const io = comp.io;
- const ip = &zcu.intern_pool;
-
- const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small);
- const extra = sema.code.extraData(Zir.Inst.EnumDecl, extended.operand);
- var extra_index: usize = extra.end;
-
- const tracked_inst = try block.trackZir(inst);
- const src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = LazySrcLoc.Offset.nodeOffset(.zero) };
-
- const tag_type_ref = if (small.has_tag_type) blk: {
- const tag_type_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);
- extra_index += 1;
- break :blk tag_type_ref;
- } else .none;
-
- const captures_len = if (small.has_captures_len) blk: {
- const captures_len = sema.code.extra[extra_index];
- extra_index += 1;
- break :blk captures_len;
- } else 0;
-
- const body_len = if (small.has_body_len) blk: {
- const body_len = sema.code.extra[extra_index];
- extra_index += 1;
- break :blk body_len;
- } else 0;
-
- const fields_len = if (small.has_fields_len) blk: {
- const fields_len = sema.code.extra[extra_index];
- extra_index += 1;
- break :blk fields_len;
- } else 0;
-
- const decls_len = if (small.has_decls_len) blk: {
- const decls_len = sema.code.extra[extra_index];
- extra_index += 1;
- break :blk decls_len;
- } else 0;
-
- const captures = try sema.getCaptures(block, src, extra_index, captures_len);
- extra_index += captures_len * 2;
-
- const decls = sema.code.bodySlice(extra_index, decls_len);
- extra_index += decls_len;
-
- const body = sema.code.bodySlice(extra_index, body_len);
- extra_index += body.len;
-
- const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
- const body_end = extra_index;
- extra_index += bit_bags_count;
-
- const any_values = for (sema.code.extra[body_end..][0..bit_bags_count]) |bag| {
- if (bag != 0) break true;
- } else false;
-
- const enum_init: InternPool.EnumTypeInit = .{
- .has_values = any_values,
- .tag_mode = if (small.nonexhaustive)
- .nonexhaustive
- else if (tag_type_ref == .none)
- .auto
- else
- .explicit,
- .fields_len = fields_len,
- .key = .{ .declared = .{
- .zir_index = tracked_inst,
- .captures = captures,
- } },
- };
- const wip_ty = switch (try ip.getEnumType(gpa, io, pt.tid, enum_init, false)) {
- .existing => |ty| {
- const new_ty = try pt.ensureTypeUpToDate(ty);
-
- // Make sure we update the namespace if the declaration is re-analyzed, to pick
- // up on e.g. changed comptime decls.
- try pt.ensureNamespaceUpToDate(Type.fromInterned(new_ty).getNamespaceIndex(zcu));
-
- try sema.declareDependency(.{ .interned = new_ty });
- try sema.addTypeReferenceEntry(src, new_ty);
-
- // Since this is an enum, it has to be resolved immediately.
- // `ensureTypeUpToDate` has resolved the new type if necessary.
- // We just need to check for resolution failures.
- const ty_unit: AnalUnit = .wrap(.{ .type = new_ty });
- if (zcu.failed_analysis.contains(ty_unit) or zcu.transitive_failed_analysis.contains(ty_unit)) {
- return error.AnalysisFail;
- }
-
- return Air.internedToRef(new_ty);
- },
- .wip => |wip| wip,
- };
-
- // Once this is `true`, we will not delete the decl or type even upon failure, since we
- // have finished constructing the type and are in the process of analyzing it.
- var done = false;
-
- errdefer if (!done) wip_ty.cancel(ip, pt.tid);
-
- const type_name = try sema.createTypeName(
- block,
- small.name_strategy,
- "enum",
- inst,
- wip_ty.index,
- );
- wip_ty.setName(ip, type_name.name, type_name.nav);
-
- const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
- .parent = block.namespace.toOptional(),
- .owner_type = wip_ty.index,
- .file_scope = block.getFileScopeIndex(zcu),
- .generation = zcu.generation,
- });
- errdefer if (!done) pt.destroyNamespace(new_namespace_index);
-
- try pt.scanNamespace(new_namespace_index, decls);
-
- try sema.declareDependency(.{ .interned = wip_ty.index });
- try sema.addTypeReferenceEntry(src, wip_ty.index);
-
- // We've finished the initial construction of this type, and are about to perform analysis.
- // Set the namespace appropriately, and don't destroy anything on failure.
- if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
- wip_ty.prepare(ip, new_namespace_index);
- done = true;
-
- {
- const tracked_unit = zcu.trackUnitSema(type_name.name.toSlice(ip), null);
- defer tracked_unit.end(zcu);
- try Sema.resolveDeclaredEnum(
- pt,
- wip_ty,
- inst,
- tracked_inst,
- new_namespace_index,
- type_name.name,
- small,
- body,
- tag_type_ref,
- any_values,
- fields_len,
- sema.code,
- body_end,
- );
- }
-
- codegen_type: {
- if (zcu.comp.config.use_llvm) break :codegen_type;
- if (block.ownerModule().strip) break :codegen_type;
- // This job depends on any resolve_type_fully jobs queued up before it.
- zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
- try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
- }
- return Air.internedToRef(wip_ty.index);
-}
-
-fn zirUnionDecl(
- sema: *Sema,
- block: *Block,
- extended: Zir.Inst.Extended.InstData,
- inst: Zir.Inst.Index,
-) CompileError!Air.Inst.Ref {
- const tracy = trace(@src());
- defer tracy.end();
-
- const pt = sema.pt;
- const zcu = pt.zcu;
- const comp = zcu.comp;
- const gpa = comp.gpa;
- const io = comp.io;
- const ip = &zcu.intern_pool;
-
- const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
- const extra = sema.code.extraData(Zir.Inst.UnionDecl, extended.operand);
- var extra_index: usize = extra.end;
-
- const tracked_inst = try block.trackZir(inst);
- const src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = LazySrcLoc.Offset.nodeOffset(.zero) };
-
- extra_index += @intFromBool(small.has_tag_type);
- const captures_len = if (small.has_captures_len) blk: {
- const captures_len = sema.code.extra[extra_index];
- extra_index += 1;
- break :blk captures_len;
- } else 0;
- extra_index += @intFromBool(small.has_body_len);
- const fields_len = if (small.has_fields_len) blk: {
- const fields_len = sema.code.extra[extra_index];
- extra_index += 1;
- break :blk fields_len;
- } else 0;
-
- const decls_len = if (small.has_decls_len) blk: {
- const decls_len = sema.code.extra[extra_index];
- extra_index += 1;
- break :blk decls_len;
- } else 0;
-
- const captures = try sema.getCaptures(block, src, extra_index, captures_len);
- extra_index += captures_len * 2;
-
- const union_init: InternPool.UnionTypeInit = .{
- .flags = .{
- .layout = small.layout,
- .status = .none,
- .runtime_tag = if (small.has_tag_type or small.auto_enum_tag)
- .tagged
- else if (small.layout != .auto)
- .none
- else switch (block.wantSafeTypes()) {
- true => .safety,
- false => .none,
- },
- .any_aligned_fields = small.any_aligned_fields,
- .requires_comptime = .unknown,
- .assumed_runtime_bits = false,
- .assumed_pointer_aligned = false,
- .alignment = .none,
- },
- .fields_len = fields_len,
- .enum_tag_ty = .none, // set later
- .field_types = &.{}, // set later
- .field_aligns = &.{}, // set later
- .key = .{ .declared = .{
- .zir_index = tracked_inst,
- .captures = captures,
- } },
- };
- const wip_ty = switch (try ip.getUnionType(gpa, io, pt.tid, union_init, false)) {
- .existing => |ty| {
- const new_ty = try pt.ensureTypeUpToDate(ty);
-
- // Make sure we update the namespace if the declaration is re-analyzed, to pick
- // up on e.g. changed comptime decls.
- try pt.ensureNamespaceUpToDate(Type.fromInterned(new_ty).getNamespaceIndex(zcu));
-
- try sema.declareDependency(.{ .interned = new_ty });
- try sema.addTypeReferenceEntry(src, new_ty);
- return Air.internedToRef(new_ty);
- },
- .wip => |wip| wip,
- };
- errdefer wip_ty.cancel(ip, pt.tid);
-
- const type_name = try sema.createTypeName(
- block,
- small.name_strategy,
- "union",
- inst,
- wip_ty.index,
- );
- wip_ty.setName(ip, type_name.name, type_name.nav);
-
- const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
- .parent = block.namespace.toOptional(),
- .owner_type = wip_ty.index,
- .file_scope = block.getFileScopeIndex(zcu),
- .generation = zcu.generation,
- });
- errdefer pt.destroyNamespace(new_namespace_index);
-
- if (pt.zcu.comp.config.incremental) {
- try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = tracked_inst });
- }
-
- const decls = sema.code.bodySlice(extra_index, decls_len);
- try pt.scanNamespace(new_namespace_index, decls);
-
- try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
- codegen_type: {
- if (zcu.comp.config.use_llvm) break :codegen_type;
- if (block.ownerModule().strip) break :codegen_type;
- // This job depends on any resolve_type_fully jobs queued up before it.
- zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
- try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
- }
- try sema.declareDependency(.{ .interned = wip_ty.index });
- try sema.addTypeReferenceEntry(src, wip_ty.index);
- if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
- return Air.internedToRef(wip_ty.finish(ip, new_namespace_index));
-}
-
-fn zirOpaqueDecl(
- sema: *Sema,
- block: *Block,
- extended: Zir.Inst.Extended.InstData,
- inst: Zir.Inst.Index,
-) CompileError!Air.Inst.Ref {
- const tracy = trace(@src());
- defer tracy.end();
-
- const pt = sema.pt;
- const zcu = pt.zcu;
- const comp = zcu.comp;
- const gpa = comp.gpa;
- const io = comp.io;
- const ip = &zcu.intern_pool;
-
- const small: Zir.Inst.OpaqueDecl.Small = @bitCast(extended.small);
- const extra = sema.code.extraData(Zir.Inst.OpaqueDecl, extended.operand);
- var extra_index: usize = extra.end;
-
- const tracked_inst = try block.trackZir(inst);
- const src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = LazySrcLoc.Offset.nodeOffset(.zero) };
-
- const captures_len = if (small.has_captures_len) blk: {
- const captures_len = sema.code.extra[extra_index];
- extra_index += 1;
- break :blk captures_len;
- } else 0;
-
- const decls_len = if (small.has_decls_len) blk: {
- const decls_len = sema.code.extra[extra_index];
- extra_index += 1;
- break :blk decls_len;
- } else 0;
-
- const captures = try sema.getCaptures(block, src, extra_index, captures_len);
- extra_index += captures_len * 2;
-
- const opaque_init: InternPool.OpaqueTypeInit = .{
- .zir_index = tracked_inst,
- .captures = captures,
- };
- const wip_ty = switch (try ip.getOpaqueType(gpa, io, pt.tid, opaque_init)) {
- .existing => |ty| {
- // Make sure we update the namespace if the declaration is re-analyzed, to pick
- // up on e.g. changed comptime decls.
- try pt.ensureNamespaceUpToDate(Type.fromInterned(ty).getNamespaceIndex(zcu));
-
- try sema.declareDependency(.{ .interned = ty });
- try sema.addTypeReferenceEntry(src, ty);
- return Air.internedToRef(ty);
- },
- .wip => |wip| wip,
- };
- errdefer wip_ty.cancel(ip, pt.tid);
-
- const type_name = try sema.createTypeName(
- block,
- small.name_strategy,
- "opaque",
- inst,
- wip_ty.index,
- );
- wip_ty.setName(ip, type_name.name, type_name.nav);
-
- const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
- .parent = block.namespace.toOptional(),
- .owner_type = wip_ty.index,
- .file_scope = block.getFileScopeIndex(zcu),
- .generation = zcu.generation,
- });
- errdefer pt.destroyNamespace(new_namespace_index);
-
- const decls = sema.code.bodySlice(extra_index, decls_len);
- try pt.scanNamespace(new_namespace_index, decls);
-
- codegen_type: {
- if (zcu.comp.config.use_llvm) break :codegen_type;
- if (block.ownerModule().strip) break :codegen_type;
- // This job depends on any resolve_type_fully jobs queued up before it.
- zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
- try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
- }
- try sema.addTypeReferenceEntry(src, wip_ty.index);
- if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
- return Air.internedToRef(wip_ty.finish(ip, new_namespace_index));
-}
-
fn zirErrorSetDecl(
sema: *Sema,
inst: Zir.Inst.Index,
@@ -3640,16 +3053,16 @@ fn zirRetPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
defer tracy.end();
const pt = sema.pt;
+ const zcu = pt.zcu;
const src = block.nodeOffset(sema.code.instructions.items(.data)[@intFromEnum(inst)].node);
- if (block.isComptime() or try sema.fn_ret_ty.comptimeOnlySema(pt)) {
- try sema.fn_ret_ty.resolveFields(pt);
+ if (block.isComptime() or sema.fn_ret_ty.comptimeOnly(zcu)) {
return sema.analyzeComptimeAlloc(block, src, sema.fn_ret_ty, .none);
}
- const target = pt.zcu.getTarget();
- const ptr_type = try pt.ptrTypeSema(.{
+ const target = zcu.getTarget();
+ const ptr_type = try pt.ptrType(.{
.child = sema.fn_ret_ty.toIntern(),
.flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
});
@@ -3669,8 +3082,8 @@ fn zirRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
defer tracy.end();
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_tok;
- const operand = try sema.resolveInst(inst_data.operand);
- return sema.analyzeRef(block, block.tokenOffset(inst_data.src_tok), operand);
+ const operand = sema.resolveInst(inst_data.operand);
+ return sema.analyzeRef(block, block.tokenOffset(inst_data.src_tok), operand, .none);
}
fn zirEnsureResultUsed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
@@ -3678,7 +3091,7 @@ fn zirEnsureResultUsed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compile
defer tracy.end();
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
- const operand = try sema.resolveInst(inst_data.operand);
+ const operand = sema.resolveInst(inst_data.operand);
const src = block.nodeOffset(inst_data.src_node);
return sema.ensureResultUsed(block, sema.typeOf(operand), src);
@@ -3724,7 +3137,7 @@ fn zirEnsureResultNonError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
const pt = sema.pt;
const zcu = pt.zcu;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
- const operand = try sema.resolveInst(inst_data.operand);
+ const operand = sema.resolveInst(inst_data.operand);
const src = block.nodeOffset(inst_data.src_node);
const operand_ty = sema.typeOf(operand);
switch (operand_ty.zigTypeTag(zcu)) {
@@ -3750,7 +3163,7 @@ fn zirEnsureErrUnionPayloadVoid(sema: *Sema, block: *Block, inst: Zir.Inst.Index
const zcu = pt.zcu;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const src = block.nodeOffset(inst_data.src_node);
- const operand = try sema.resolveInst(inst_data.operand);
+ const operand = sema.resolveInst(inst_data.operand);
const operand_ty = sema.typeOf(operand);
const err_union_ty = if (operand_ty.zigTypeTag(zcu) == .pointer)
operand_ty.childType(zcu)
@@ -3775,7 +3188,7 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const src = block.nodeOffset(inst_data.src_node);
- const object = try sema.resolveInst(inst_data.operand);
+ const object = sema.resolveInst(inst_data.operand);
return indexablePtrLen(sema, block, src, object);
}
@@ -3826,6 +3239,7 @@ fn zirAllocExtended(
extended: Zir.Inst.Extended.InstData,
) CompileError!Air.Inst.Ref {
const pt = sema.pt;
+ const zcu = pt.zcu;
const gpa = sema.gpa;
const extra = sema.code.extraData(Zir.Inst.AllocExtended, extended.operand);
const var_src = block.nodeOffset(extra.data.src_node);
@@ -3847,37 +3261,20 @@ fn zirAllocExtended(
break :blk try sema.resolveAlign(block, align_src, align_ref);
} else .none;
- if (block.isComptime() or small.is_comptime) {
- if (small.has_type) {
- return sema.analyzeComptimeAlloc(block, var_src, var_ty, alignment);
- } else {
- try sema.air_instructions.append(gpa, .{
- .tag = .inferred_alloc_comptime,
- .data = .{ .inferred_alloc_comptime = .{
- .alignment = alignment,
- .is_const = small.is_const,
- .ptr = undefined,
- } },
- });
- return @as(Air.Inst.Index, @enumFromInt(sema.air_instructions.len - 1)).toRef();
- }
- }
-
- if (small.has_type and try var_ty.comptimeOnlySema(pt)) {
- return sema.analyzeComptimeAlloc(block, var_src, var_ty, alignment);
- }
-
if (small.has_type) {
+ try sema.ensureLayoutResolved(var_ty, var_src, if (small.is_const) .constant else .variable);
+ if (block.isComptime() or small.is_comptime or var_ty.comptimeOnly(zcu)) {
+ return sema.analyzeComptimeAlloc(block, var_src, var_ty, alignment);
+ }
if (!small.is_const) {
try sema.validateVarType(block, ty_src, var_ty, false);
}
const target = pt.zcu.getTarget();
- try var_ty.resolveLayout(pt);
- if (sema.func_is_naked and try var_ty.hasRuntimeBitsSema(pt)) {
+ if (sema.func_is_naked and var_ty.hasRuntimeBits(zcu)) {
const store_src = block.src(.{ .node_offset_store_ptr = extra.data.src_node });
return sema.fail(block, store_src, "local variable in naked function", .{});
}
- const ptr_type = try sema.pt.ptrTypeSema(.{
+ const ptr_type = try pt.ptrType(.{
.child = var_ty.toIntern(),
.flags = .{
.alignment = alignment,
@@ -3893,6 +3290,19 @@ fn zirAllocExtended(
return ptr;
}
+ if (block.isComptime() or small.is_comptime) {
+ const iac_index: Air.Inst.Index = @enumFromInt(sema.air_instructions.len);
+ try sema.air_instructions.append(gpa, .{
+ .tag = .inferred_alloc_comptime,
+ .data = .{ .inferred_alloc_comptime = .{
+ .alignment = alignment,
+ .is_const = small.is_const,
+ .ptr = undefined,
+ } },
+ });
+ return iac_index.toRef();
+ }
+
const result_index = try block.addInstAsIndex(.{
.tag = .inferred_alloc,
.data = .{ .inferred_alloc = .{
@@ -3916,6 +3326,7 @@ fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node });
const var_src = block.nodeOffset(inst_data.src_node);
const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
+ try sema.ensureLayoutResolved(var_ty, var_src, .variable);
return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none);
}
@@ -3923,7 +3334,7 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
const pt = sema.pt;
const zcu = pt.zcu;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
- const alloc = try sema.resolveInst(inst_data.operand);
+ const alloc = sema.resolveInst(inst_data.operand);
const alloc_ty = sema.typeOf(alloc);
const ptr_info = alloc_ty.ptrInfo(zcu);
const elem_ty: Type = .fromInterned(ptr_info.child);
@@ -3932,7 +3343,7 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
// However, if the final constructed value does not reference comptime-mutable memory, we wish
// to promote it to an anon decl.
already_ct: {
- const ptr_val = try sema.resolveValue(alloc) orelse break :already_ct;
+ const ptr_val = sema.resolveValue(alloc) orelse break :already_ct;
// If this was a comptime inferred alloc, then `storeToInferredAllocComptime`
// might have already done our job and created an anon decl ref.
@@ -3978,7 +3389,7 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
return sema.makePtrConst(block, Air.internedToRef(ptr_val));
}
- if (try elem_ty.comptimeOnlySema(pt)) {
+ if (elem_ty.comptimeOnly(zcu)) {
// The value was initialized through RLS, so we didn't detect the runtime condition earlier.
// TODO: source location of runtime control flow
const init_src = block.src(.{ .node_offset_var_decl_init = inst_data.src_node });
@@ -4001,20 +3412,23 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
const alloc_ty = resolved_alloc_ty orelse sema.typeOf(alloc);
const ptr_info = alloc_ty.ptrInfo(zcu);
const elem_ty: Type = .fromInterned(ptr_info.child);
+ elem_ty.assertHasLayout(zcu);
const alloc_inst = alloc.toIndex() orelse return null;
const comptime_info = sema.maybe_comptime_allocs.fetchRemove(alloc_inst) orelse return null;
const stores = comptime_info.value.stores.items(.inst);
+ // If the elem type is OPV, no need to faff about with `stores`; just use the OPV.
+ if (try elem_ty.onePossibleValue(pt)) |opv| {
+ return sema.finishResolveComptimeKnownAllocPtr(block, alloc_ty, opv.toIntern(), null, alloc_inst, comptime_info.value);
+ }
+
+ // Since the elem type isn't OPV, there should have been at least one store.
+ assert(stores.len > 0);
+
// Since the entry existed in `maybe_comptime_allocs`, the allocation is comptime-known.
// We will resolve and return its value.
- // We expect to have emitted at least one store, unless the elem type is OPV.
- if (stores.len == 0) {
- const val = (try sema.typeHasOnePossibleValue(elem_ty)).?.toIntern();
- return sema.finishResolveComptimeKnownAllocPtr(block, alloc_ty, val, null, alloc_inst, comptime_info.value);
- }
-
// In general, we want to create a comptime alloc of the correct type and
// apply the stores to that alloc in order. However, before going to all
// that effort, let's optimize for the common case of a single store.
@@ -4115,10 +3529,10 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
Air.Bin,
tmp_air.instructions.items(.data)[@intFromEnum(air_ptr)].ty_pl.payload,
).data;
- const idx_val = (try sema.resolveValue(data.rhs)).?;
+ const idx_val = sema.resolveValue(data.rhs).?;
break :blk .{
data.lhs,
- .{ .elem = try idx_val.toUnsignedIntSema(pt) },
+ .{ .elem = idx_val.toUnsignedInt(zcu) },
};
},
.bitcast => .{
@@ -4150,7 +3564,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
// If the payload is OPV, we must use that value instead of undef.
const opt_ty = Value.fromInterned(decl_parent_ptr).typeOf(zcu).childType(zcu);
const payload_ty = opt_ty.optionalChild(zcu);
- const payload_val = try sema.typeHasOnePossibleValue(payload_ty) orelse try pt.undefValue(payload_ty);
+ const payload_val = try payload_ty.onePossibleValue(pt) orelse try pt.undefValue(payload_ty);
const opt_val = try pt.intern(.{ .opt = .{
.ty = opt_ty.toIntern(),
.val = payload_val.toIntern(),
@@ -4163,7 +3577,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
// If the payload is OPV, we must use that value instead of undef.
const eu_ty = Value.fromInterned(decl_parent_ptr).typeOf(zcu).childType(zcu);
const payload_ty = eu_ty.errorUnionPayload(zcu);
- const payload_val = try sema.typeHasOnePossibleValue(payload_ty) orelse try pt.undefValue(payload_ty);
+ const payload_val = try payload_ty.onePossibleValue(pt) orelse try pt.undefValue(payload_ty);
const eu_val = try pt.intern(.{ .error_union = .{
.ty = eu_ty.toIntern(),
.val = .{ .payload = payload_val.toIntern() },
@@ -4173,18 +3587,31 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
},
.field => |idx| ptr: {
const maybe_union_ty = Value.fromInterned(decl_parent_ptr).typeOf(zcu).childType(zcu);
- if (zcu.typeToUnion(maybe_union_ty)) |union_obj| {
+ if (zcu.typeToUnion(maybe_union_ty)) |union_obj| if (union_obj.layout == .auto) {
// As this is a union field, we must store to the pointer now to set the tag.
// The payload value will be stored later, so undef is a sufficent payload for now.
const payload_ty: Type = .fromInterned(union_obj.field_types.get(&zcu.intern_pool)[idx]);
const payload_val = try pt.undefValue(payload_ty);
- const tag_val = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_ty), idx);
+ const tag_val = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_type), idx);
const store_val = try pt.unionValue(maybe_union_ty, tag_val, payload_val);
try sema.storePtrVal(block, .unneeded, .fromInterned(decl_parent_ptr), store_val, maybe_union_ty);
- }
+ };
break :ptr (try Value.fromInterned(decl_parent_ptr).ptrField(idx, pt)).toIntern();
},
- .elem => |idx| (try Value.fromInterned(decl_parent_ptr).ptrElem(idx, pt)).toIntern(),
+ .elem => |idx| ptr: {
+ const parent_ptr_val: Value = .fromInterned(decl_parent_ptr);
+ if (parent_ptr_val.typeOf(zcu).childType(zcu).zigTypeTag(zcu) == .vector) {
+ const elem_ptr_ty: Type = .fromInterned(new_ptr_ty);
+ // Vectors are a bit weird; see logic in `elemPtrVector`.
+ if (elem_ptr_ty.ptrInfo(zcu).flags.vector_index != .none) {
+ break :ptr (try pt.getCoerced(parent_ptr_val, elem_ptr_ty)).toIntern();
+ } else {
+ const bit_offset = idx * @divExact(elem_ptr_ty.childType(zcu).bitSize(zcu), 8);
+ break :ptr (try parent_ptr_val.getOffsetPtr(bit_offset, elem_ptr_ty, pt)).toIntern();
+ }
+ }
+ break :ptr (try parent_ptr_val.ptrElem(idx, pt)).toIntern();
+ },
};
try ptr_mapping.put(air_ptr, new_ptr);
}
@@ -4207,14 +3634,14 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
const tag_val: Value = .fromInterned(store_inst.data.bin_op.rhs.toInterned().?);
const union_ty = union_ptr_val.typeOf(zcu).childType(zcu);
const field_ty = union_ty.unionFieldType(tag_val, zcu).?;
- if (try sema.typeHasOnePossibleValue(field_ty)) |payload_val| {
+ if (try field_ty.onePossibleValue(pt)) |payload_val| {
const new_union_val = try pt.unionValue(union_ty, tag_val, payload_val);
try sema.storePtrVal(block, .unneeded, union_ptr_val, new_union_val, union_ty);
}
},
.store, .store_safe => {
const air_ptr_inst = store_inst.data.bin_op.lhs.toIndex().?;
- const store_val = (try sema.resolveValue(store_inst.data.bin_op.rhs)).?;
+ const store_val = sema.resolveValue(store_inst.data.bin_op.rhs).?;
const new_ptr = ptr_mapping.get(air_ptr_inst).?;
try sema.storePtrVal(block, .unneeded, .fromInterned(new_ptr), store_val, store_val.typeOf(zcu));
},
@@ -4289,7 +3716,7 @@ fn finishResolveComptimeKnownAllocPtr(
fn makePtrTyConst(sema: *Sema, ptr_ty: Type) CompileError!Type {
var ptr_info = ptr_ty.ptrInfo(sema.pt.zcu);
ptr_info.flags.is_const = true;
- return sema.pt.ptrTypeSema(ptr_info);
+ return sema.pt.ptrType(ptr_info);
}
fn makePtrConst(sema: *Sema, block: *Block, alloc: Air.Inst.Ref) CompileError!Air.Inst.Ref {
@@ -4297,7 +3724,7 @@ fn makePtrConst(sema: *Sema, block: *Block, alloc: Air.Inst.Ref) CompileError!Ai
const const_ptr_ty = try sema.makePtrTyConst(alloc_ty);
// Detect if a comptime value simply needs to have its type changed.
- if (try sema.resolveValue(alloc)) |val| {
+ if (sema.resolveValue(alloc)) |val| {
return Air.internedToRef((try sema.pt.getCoerced(val, const_ptr_ty)).toIntern());
}
@@ -4326,21 +3753,23 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
defer tracy.end();
const pt = sema.pt;
+ const zcu = pt.zcu;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node });
const var_src = block.nodeOffset(inst_data.src_node);
const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
- if (block.isComptime() or try var_ty.comptimeOnlySema(pt)) {
+ try sema.ensureLayoutResolved(var_ty, var_src, .constant);
+ if (block.isComptime() or var_ty.comptimeOnly(zcu)) {
return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none);
}
- if (sema.func_is_naked and try var_ty.hasRuntimeBitsSema(pt)) {
+ if (sema.func_is_naked and var_ty.hasRuntimeBits(zcu)) {
const mut_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node });
return sema.fail(block, mut_src, "local variable in naked function", .{});
}
- const target = pt.zcu.getTarget();
- const ptr_type = try pt.ptrTypeSema(.{
+ const target = zcu.getTarget();
+ const ptr_type = try pt.ptrType(.{
.child = var_ty.toIntern(),
.flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
});
@@ -4356,21 +3785,24 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
defer tracy.end();
const pt = sema.pt;
+ const zcu = pt.zcu;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node });
const var_src = block.nodeOffset(inst_data.src_node);
+
const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
+ try sema.ensureLayoutResolved(var_ty, var_src, .variable);
if (block.isComptime()) {
return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none);
}
- if (sema.func_is_naked and try var_ty.hasRuntimeBitsSema(pt)) {
+ if (sema.func_is_naked and var_ty.hasRuntimeBits(zcu)) {
const store_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node });
return sema.fail(block, store_src, "local variable in naked function", .{});
}
try sema.validateVarType(block, ty_src, var_ty, false);
- const target = pt.zcu.getTarget();
- const ptr_type = try pt.ptrTypeSema(.{
+ const target = zcu.getTarget();
+ const ptr_type = try pt.ptrType(.{
.child = var_ty.toIntern(),
.flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
});
@@ -4424,14 +3856,15 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const src = block.nodeOffset(inst_data.src_node);
const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node });
- const ptr = try sema.resolveInst(inst_data.operand);
+ const ptr = sema.resolveInst(inst_data.operand);
const ptr_inst = ptr.toIndex().?;
const target = zcu.getTarget();
switch (sema.air_instructions.items(.tag)[@intFromEnum(ptr_inst)]) {
.inferred_alloc_comptime => {
- // The work was already done for us by `Sema.storeToInferredAllocComptime`.
- // All we need to do is return the pointer.
+ // The work was already done for us by `Sema.storeToInferredAllocComptime`. Also, since
+ // we had a value of the exact correct type to store, the result type's layout must be
+ // already resolved. So all we need to do here is return the pointer.
const iac = sema.air_instructions.items(.data)[@intFromEnum(ptr_inst)].inferred_alloc_comptime;
const resolved_ptr = iac.ptr;
@@ -4450,7 +3883,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
};
if (zcu.intern_pool.isFuncBody(val)) {
const ty: Type = .fromInterned(zcu.intern_pool.typeOf(val));
- if (try ty.fnHasRuntimeBitsSema(pt)) {
+ if (ty.fnHasRuntimeBits(zcu)) {
const orig_fn_index = zcu.intern_pool.unwrapCoercedFunc(val);
try sema.addReferenceEntry(block, src, .wrap(.{ .func = orig_fn_index }));
try zcu.ensureFuncBodyAnalysisQueued(orig_fn_index);
@@ -4469,8 +3902,10 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
peer_val.* = bin_op.rhs;
}
const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_vals, .none);
+ // The layout of the peers is already resolved, so the layout of `final_elem_ty` is too.
+ final_elem_ty.assertHasLayout(zcu);
- const final_ptr_ty = try pt.ptrTypeSema(.{
+ const final_ptr_ty = try pt.ptrType(.{
.child = final_elem_ty.toIntern(),
.flags = .{
.alignment = ia1.alignment,
@@ -4484,21 +3919,16 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
const const_ptr_ty = try sema.makePtrTyConst(final_ptr_ty);
const new_const_ptr = try pt.getCoerced(Value.fromInterned(ptr_val), const_ptr_ty);
- // Unless the block is comptime, `alloc_inferred` always produces
- // a runtime constant. The final inferred type needs to be
- // fully resolved so it can be lowered in codegen.
- try final_elem_ty.resolveFully(pt);
-
return Air.internedToRef(new_const_ptr.toIntern());
}
- if (try final_elem_ty.comptimeOnlySema(pt)) {
+ if (final_elem_ty.comptimeOnly(zcu)) {
// The alloc wasn't comptime-known per the above logic, so the
// type cannot be comptime-only.
// TODO: source location of runtime control flow
return sema.fail(block, src, "value with comptime-only type '{f}' depends on runtime control flow", .{final_elem_ty.fmt(pt)});
}
- if (sema.func_is_naked and try final_elem_ty.hasRuntimeBitsSema(pt)) {
+ if (sema.func_is_naked and final_elem_ty.hasRuntimeBits(zcu)) {
const mut_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node });
return sema.fail(block, mut_src, "local variable in naked function", .{});
}
@@ -4591,7 +4021,7 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
const arg_len_uncoerced = if (zir_arg_pair[1] == .none) l: {
// This argument is an indexable.
- const object = try sema.resolveInst(zir_arg_pair[0]);
+ const object = sema.resolveInst(zir_arg_pair[0]);
const object_ty = sema.typeOf(object);
if (!object_ty.isIndexable(zcu)) {
// Instead of using checkIndexable we customize this error.
@@ -4612,8 +4042,8 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
break :l try sema.fieldVal(block, arg_src, object, try ip.getOrPutString(gpa, io, pt.tid, "len", .no_embedded_nulls), arg_src);
} else l: {
// This argument is a range.
- const range_start = try sema.resolveInst(zir_arg_pair[0]);
- const range_end = try sema.resolveInst(zir_arg_pair[1]);
+ const range_start = sema.resolveInst(zir_arg_pair[0]);
+ const range_end = sema.resolveInst(zir_arg_pair[1]);
if (try sema.resolveDefinedValue(block, arg_src, range_start)) |start| {
if (try sema.valuesEqual(start, .zero_usize, .usize)) break :l range_end;
}
@@ -4663,7 +4093,7 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
const i: u32 = @intCast(i_usize);
if (zir_arg_pair[0] == .none) continue;
if (zir_arg_pair[1] != .none) continue;
- const object = try sema.resolveInst(zir_arg_pair[0]);
+ const object = sema.resolveInst(zir_arg_pair[0]);
const object_ty = sema.typeOf(object);
const arg_src = block.src(.{ .for_input = .{
.for_node_offset = inst_data.src_node,
@@ -4701,9 +4131,11 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
/// or error union pointed to, initializing these pointers along the way.
/// Given a `*E!?T`, returns a (valid) `*T`.
/// May invalidate already-stored payload data.
+/// Asserts that the layout of the pointer child type is already resolved.
fn optEuBasePtrInit(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, src: LazySrcLoc) CompileError!Air.Inst.Ref {
const pt = sema.pt;
const zcu = pt.zcu;
+ sema.typeOf(ptr).childType(zcu).assertHasLayout(zcu);
var base_ptr = ptr;
while (true) switch (sema.typeOf(base_ptr).childType(zcu).zigTypeTag(zcu)) {
.error_union => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true),
@@ -4716,8 +4148,10 @@ fn optEuBasePtrInit(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, src: LazySrcL
fn zirOptEuBasePtrInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const un_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
- const ptr = try sema.resolveInst(un_node.operand);
- return sema.optEuBasePtrInit(block, ptr, block.nodeOffset(un_node.src_node));
+ const ptr = sema.resolveInst(un_node.operand);
+ const src = block.nodeOffset(un_node.src_node);
+ try sema.ensureLayoutResolved(sema.typeOf(ptr).childType(sema.pt.zcu), src, .init);
+ return sema.optEuBasePtrInit(block, ptr, src);
}
fn zirCoercePtrElemTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -4726,7 +4160,7 @@ fn zirCoercePtrElemTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
const pl_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const src = block.nodeOffset(pl_node.src_node);
const extra = sema.code.extraData(Zir.Inst.Bin, pl_node.payload_index).data;
- const uncoerced_val = try sema.resolveInst(extra.rhs);
+ const uncoerced_val = sema.resolveInst(extra.rhs);
const maybe_wrapped_ptr_ty = try sema.resolveTypeOrPoison(block, LazySrcLoc.unneeded, extra.lhs) orelse return uncoerced_val;
const ptr_ty = maybe_wrapped_ptr_ty.optEuBaseType(zcu);
assert(ptr_ty.zigTypeTag(zcu) == .pointer); // validated by a previous instruction
@@ -4812,7 +4246,7 @@ fn zirTryOperandTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: boo
if (is_ref) {
var ptr_info = operand_ty.ptrInfo(zcu);
ptr_info.child = eu_ty.toIntern();
- const eu_ptr_ty = try pt.ptrTypeSema(ptr_info);
+ const eu_ptr_ty = try pt.ptrType(ptr_info);
return Air.internedToRef(eu_ptr_ty.toIntern());
} else {
return Air.internedToRef(eu_ty.toIntern());
@@ -4842,7 +4276,7 @@ fn zirValidateConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
const un_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const src = block.nodeOffset(un_node.src_node);
- const init_ref = try sema.resolveInst(un_node.operand);
+ const init_ref = sema.resolveInst(un_node.operand);
if (!try sema.isComptimeKnown(init_ref)) {
return sema.failWithNeededComptime(block, src, null);
}
@@ -4935,7 +4369,6 @@ fn validateArrayInitTy(
return;
},
.@"struct" => if (ty.isTuple(zcu)) {
- try ty.resolveFields(pt);
const array_len = ty.arrayLen(zcu);
if (init_count > array_len) {
return sema.fail(block, src, "expected at most {d} tuple fields; found {d}", .{
@@ -4986,7 +4419,7 @@ fn zirValidatePtrStructInit(
const instrs = sema.code.bodySlice(validate_extra.end, validate_extra.data.body_len);
const field_ptr_data = sema.code.instructions.items(.data)[@intFromEnum(instrs[0])].pl_node;
const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
- const object_ptr = try sema.resolveInst(field_ptr_extra.lhs);
+ const object_ptr = sema.resolveInst(field_ptr_extra.lhs);
const agg_ty = sema.typeOf(object_ptr).childType(zcu).optEuBaseType(zcu);
switch (agg_ty.zigTypeTag(zcu)) {
.@"struct" => return sema.validateStructInit(
@@ -5097,12 +4530,16 @@ fn validateStructInit(
errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
for (found_fields, 0..) |explicit, i_usize| {
+ const i: u32 = @intCast(i_usize);
+
if (explicit) continue;
- const i: u32 = @intCast(i_usize);
+ if (struct_ty.structFieldIsComptime(i, zcu)) continue;
- try struct_ty.resolveStructFieldInits(pt);
- const default_val = struct_ty.structFieldDefaultValue(i, zcu);
- if (default_val.toIntern() == .unreachable_value) {
+ if (!struct_ty.isTuple(zcu)) {
+ try sema.ensureStructDefaultsResolved(struct_ty, init_src);
+ }
+
+ const default_val = struct_ty.structFieldDefaultValue(i, zcu) orelse {
const field_name = struct_ty.structFieldName(i, zcu).unwrap() orelse {
const template = "missing tuple field with index {d}";
if (root_msg) |msg| {
@@ -5120,13 +4557,10 @@ fn validateStructInit(
root_msg = try sema.errMsg(init_src, template, args);
}
continue;
- }
+ };
const field_src = init_src; // TODO better source location
- const default_field_ptr = if (struct_ty.isTuple(zcu))
- try sema.tupleFieldPtr(block, init_src, struct_ptr, field_src, @intCast(i), true)
- else
- try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(i), struct_ty);
+ const default_field_ptr = try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(i), struct_ty);
try sema.checkKnownAllocPtr(block, struct_ptr, default_field_ptr);
try sema.storePtr2(block, init_src, default_field_ptr, init_src, .fromValue(default_val), field_src, .store);
}
@@ -5151,7 +4585,7 @@ fn zirValidatePtrArrayInit(
const instrs = sema.code.bodySlice(validate_extra.end, validate_extra.data.body_len);
const first_elem_ptr_data = sema.code.instructions.items(.data)[@intFromEnum(instrs[0])].pl_node;
const elem_ptr_extra = sema.code.extraData(Zir.Inst.ElemPtrImm, first_elem_ptr_data.payload_index).data;
- const array_ptr = try sema.resolveInst(elem_ptr_extra.ptr);
+ const array_ptr = sema.resolveInst(elem_ptr_extra.ptr);
const array_ty = sema.typeOf(array_ptr).childType(zcu).optEuBaseType(zcu);
const array_len = array_ty.arrayLen(zcu);
@@ -5166,11 +4600,9 @@ fn zirValidatePtrArrayInit(
var root_msg: ?*Zcu.ErrorMsg = null;
errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
- try array_ty.resolveStructFieldInits(pt);
var i = instrs.len;
while (i < array_len) : (i += 1) {
- const default_val = array_ty.structFieldDefaultValue(i, zcu).toIntern();
- if (default_val == .unreachable_value) {
+ if (array_ty.structFieldDefaultValue(i, zcu) == null) {
const template = "missing tuple field with index {d}";
if (root_msg) |msg| {
try sema.errNote(init_src, msg, template, .{i});
@@ -5213,7 +4645,7 @@ fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
const zcu = pt.zcu;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const src = block.nodeOffset(inst_data.src_node);
- const operand = try sema.resolveInst(inst_data.operand);
+ const operand = sema.resolveInst(inst_data.operand);
const operand_ty = sema.typeOf(operand);
if (operand_ty.zigTypeTag(zcu) != .pointer) {
@@ -5224,40 +4656,14 @@ fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
.slice => return sema.fail(block, src, "index syntax required for slice type '{f}'", .{operand_ty.fmt(pt)}),
}
- if ((try sema.typeHasOnePossibleValue(operand_ty.childType(zcu))) != null) {
- // No need to validate the actual pointer value, we don't need it!
- return;
- }
-
- const elem_ty = operand_ty.elemType2(zcu);
- if (try sema.resolveValue(operand)) |val| {
- if (val.isUndef(zcu)) {
+ if (sema.resolveValue(operand)) |val| {
+ // Error for deref of undef pointer, unless the pointee is OPV in which case it's legal.
+ if (val.isUndef(zcu) and operand_ty.childType(zcu).classify(zcu) != .one_possible_value) {
return sema.fail(block, src, "cannot dereference undefined value", .{});
}
- } else if (try elem_ty.comptimeOnlySema(pt)) {
- const msg = msg: {
- const msg = try sema.errMsg(
- src,
- "values of type '{f}' must be comptime-known, but operand value is runtime-known",
- .{elem_ty.fmt(pt)},
- );
- errdefer msg.destroy(sema.gpa);
-
- try sema.explainWhyTypeIsComptime(msg, src, elem_ty);
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(block, msg);
}
}
-fn typeIsDestructurable(ty: Type, zcu: *const Zcu) bool {
- return switch (ty.zigTypeTag(zcu)) {
- .array, .vector => true,
- .@"struct" => ty.isTuple(zcu),
- else => false,
- };
-}
-
fn zirValidateDestructure(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
const pt = sema.pt;
const zcu = pt.zcu;
@@ -5265,17 +4671,17 @@ fn zirValidateDestructure(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp
const extra = sema.code.extraData(Zir.Inst.ValidateDestructure, inst_data.payload_index).data;
const src = block.nodeOffset(inst_data.src_node);
const destructure_src = block.nodeOffset(extra.destructure_node);
- const operand = try sema.resolveInst(extra.operand);
+ const operand = sema.resolveInst(extra.operand);
const operand_ty = sema.typeOf(operand);
- if (!typeIsDestructurable(operand_ty, zcu)) {
+ if (!operand_ty.destructurable(zcu)) {
return sema.failWithOwnedErrorMsg(block, msg: {
const msg = try sema.errMsg(src, "type '{f}' cannot be destructured", .{operand_ty.fmt(pt)});
errdefer msg.destroy(sema.gpa);
try sema.errNote(destructure_src, msg, "result destructured here", .{});
if (operand_ty.zigTypeTag(pt.zcu) == .error_union) {
const base_op_ty = operand_ty.errorUnionPayload(zcu);
- if (typeIsDestructurable(base_op_ty, zcu))
+ if (base_op_ty.destructurable(zcu))
try sema.errNote(src, msg, "consider using 'try', 'catch', or 'if'", .{});
}
break :msg msg;
@@ -5373,7 +4779,7 @@ fn failWithBadUnionFieldAccess(
return sema.failWithOwnedErrorMsg(block, msg);
}
-fn addDeclaredHereNote(sema: *Sema, parent: *Zcu.ErrorMsg, decl_ty: Type) !void {
+pub fn addDeclaredHereNote(sema: *Sema, parent: *Zcu.ErrorMsg, decl_ty: Type) !void {
const zcu = sema.pt.zcu;
const src_loc = decl_ty.srcLocOrNull(zcu) orelse return;
const category = switch (decl_ty.zigTypeTag(zcu)) {
@@ -5393,8 +4799,8 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi
const pl_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const src = block.nodeOffset(pl_node.src_node);
const bin = sema.code.extraData(Zir.Inst.Bin, pl_node.payload_index).data;
- const ptr = try sema.resolveInst(bin.lhs);
- const operand = try sema.resolveInst(bin.rhs);
+ const ptr = sema.resolveInst(bin.lhs);
+ const operand = sema.resolveInst(bin.rhs);
const ptr_inst = ptr.toIndex().?;
const air_datas = sema.air_instructions.items(.data);
@@ -5440,17 +4846,19 @@ fn storeToInferredAllocComptime(
const operand_ty = sema.typeOf(operand);
// There will be only one store_to_inferred_ptr because we are running at comptime.
// The alloc will turn into a Decl or a ComptimeAlloc.
- const operand_val = try sema.resolveValue(operand) orelse {
+ const operand_val = sema.resolveValue(operand) orelse {
return sema.failWithNeededComptime(block, src, .{ .simple = .stored_to_comptime_var });
};
- const alloc_ty = try pt.ptrTypeSema(.{
+ const alloc_ty = try pt.ptrType(.{
.child = operand_ty.toIntern(),
.flags = .{
.alignment = iac.alignment,
.is_const = iac.is_const,
},
});
- if (iac.is_const and !operand_val.canMutateComptimeVarState(zcu)) {
+ if (operand_ty.classify(zcu) == .one_possible_value or
+ (iac.is_const and !operand_val.canMutateComptimeVarState(zcu)))
+ {
iac.ptr = try pt.intern(.{ .ptr = .{
.ty = alloc_ty.toIntern(),
.base_addr = .{ .uav = .{
@@ -5487,8 +4895,8 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v
const inst_data = zir_datas[@intFromEnum(inst)].pl_node;
const src = block.nodeOffset(inst_data.src_node);
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
- const ptr = try sema.resolveInst(extra.lhs);
- const operand = try sema.resolveInst(extra.rhs);
+ const ptr = sema.resolveInst(extra.lhs);
+ const operand = sema.resolveInst(extra.rhs);
const is_ret = if (extra.lhs.toIndex()) |ptr_index|
zir_tags[@intFromEnum(ptr_index)] == .ret_ptr
@@ -5535,11 +4943,11 @@ pub fn addStrLit(sema: *Sema, string: InternPool.String, len: u64) CompileError!
.ty = array_ty.toIntern(),
.storage = .{ .bytes = string },
} });
- return sema.uavRef(val);
+ return sema.uavRef(.fromInterned(val));
}
-fn uavRef(sema: *Sema, val: InternPool.Index) CompileError!Air.Inst.Ref {
- return Air.internedToRef(try sema.pt.refValue(val));
+fn uavRef(sema: *Sema, val: Value) CompileError!Air.Inst.Ref {
+ return .fromValue(try sema.pt.uavValue(val));
}
fn zirInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -5622,9 +5030,9 @@ fn zirCompileLog(
for (args, 0..) |arg_ref, i| {
if (i != 0) writer.writeAll(", ") catch return error.OutOfMemory;
- const arg = try sema.resolveInst(arg_ref);
+ const arg = sema.resolveInst(arg_ref);
const arg_ty = sema.typeOf(arg);
- if (try sema.resolveValueResolveLazy(arg)) |val| {
+ if (sema.resolveValue(arg)) |val| {
writer.print("@as({f}, {f})", .{
arg_ty.fmt(pt), val.fmtValueSema(pt, sema),
}) catch return error.OutOfMemory;
@@ -5672,7 +5080,7 @@ fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const src = block.nodeOffset(inst_data.src_node);
- const msg_inst = try sema.resolveInst(inst_data.operand);
+ const msg_inst = sema.resolveInst(inst_data.operand);
const arg_src = block.builtinCallArgSrc(inst_data.src_node, 0);
const coerced_msg = try sema.coerce(block, .slice_const_u8, msg_inst, arg_src);
@@ -5752,9 +5160,9 @@ fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError
var label: Block.Label = .{
.zir_block = inst,
.merges = .{
- .src_locs = .{},
- .results = .{},
- .br_list = .{},
+ .src_locs = .empty,
+ .results = .empty,
+ .br_list = .empty,
.block_inst = block_inst,
},
};
@@ -5826,7 +5234,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
.parent = parent_block,
.sema = sema,
.namespace = parent_block.namespace,
- .instructions = .{},
+ .instructions = .empty,
.inlining = parent_block.inlining,
.comptime_reason = .{ .reason = .{
.src = src,
@@ -5927,11 +5335,10 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
pt.updateFile(new_file_index, zcu.fileByIndex(new_file_index)) catch |err|
return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)});
- try pt.ensureFileAnalyzed(new_file_index);
- const ty = zcu.fileRootType(new_file_index);
- try sema.declareDependency(.{ .interned = ty });
+ try pt.ensureFilePopulated(new_file_index);
+ const ty: Type = .fromInterned(zcu.fileRootType(new_file_index));
try sema.addTypeReferenceEntry(src, ty);
- return Air.internedToRef(ty);
+ return .fromType(ty);
}
fn zirSuspendBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -5962,9 +5369,9 @@ fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErro
var label: Block.Label = .{
.zir_block = inst,
.merges = .{
- .src_locs = .{},
- .results = .{},
- .br_list = .{},
+ .src_locs = .empty,
+ .results = .empty,
+ .br_list = .empty,
.block_inst = block_inst,
},
};
@@ -5973,7 +5380,7 @@ fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErro
.parent = parent_block,
.sema = sema,
.namespace = parent_block.namespace,
- .instructions = .{},
+ .instructions = .empty,
.label = &label,
.inlining = parent_block.inlining,
.comptime_reason = parent_block.comptime_reason,
@@ -6043,7 +5450,7 @@ fn resolveBlockBody(
const break_data = sema.code.instructions.items(.data)[@intFromEnum(break_inst)].@"break";
const extra = sema.code.extraData(Zir.Inst.Break, break_data.payload_index).data;
if (extra.block_inst == body_inst) {
- return try sema.resolveInst(break_data.operand);
+ return sema.resolveInst(break_data.operand);
} else {
return error.ComptimeBreak;
}
@@ -6134,7 +5541,7 @@ fn resolveAnalyzedBlock(
// Okay, we need a runtime block. If the value is comptime-known, the
// block should just return void, and we return the merge result
// directly. Otherwise, we can defer to the logic below.
- if (try sema.resolveValue(merges.results.items[0])) |result_val| {
+ if (sema.resolveValue(merges.results.items[0])) |result_val| {
// Create a block containing all instruction from the body.
try parent_block.instructions.append(gpa, merges.block_inst);
switch (block_tag) {
@@ -6177,10 +5584,11 @@ fn resolveAnalyzedBlock(
// to emit a jump instruction to after the block when it encounters the break.
try parent_block.instructions.append(gpa, merges.block_inst);
const resolved_ty = try sema.resolvePeerTypes(parent_block, src, merges.results.items, .{ .override = merges.src_locs.items });
+ resolved_ty.assertHasLayout(zcu);
// TODO add note "missing else causes void value"
const type_src = src; // TODO: better source location
- if (try resolved_ty.comptimeOnlySema(pt)) {
+ if (resolved_ty.comptimeOnly(zcu)) {
const msg = msg: {
const msg = try sema.errMsg(type_src, "value with comptime-only type '{f}' depends on runtime control flow", .{resolved_ty.fmt(pt)});
errdefer msg.destroy(sema.gpa);
@@ -6274,10 +5682,7 @@ fn resolveAnalyzedBlock(
});
}
- if (try sema.typeHasOnePossibleValue(resolved_ty)) |block_only_value| {
- return Air.internedToRef(block_only_value.toIntern());
- }
-
+ if (try resolved_ty.onePossibleValue(pt)) |opv| return .fromValue(opv);
return merges.block_inst.toRef();
}
@@ -6295,7 +5700,7 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
const ptr_src = block.builtinCallArgSrc(inst_data.src_node, 0);
const options_src = block.builtinCallArgSrc(inst_data.src_node, 1);
- const ptr = try sema.resolveInst(extra.exported);
+ const ptr = sema.resolveInst(extra.exported);
const ptr_val = try sema.resolveConstDefinedValue(block, ptr_src, ptr, .{ .simple = .export_target });
const ptr_ty = ptr_val.typeOf(zcu);
@@ -6314,91 +5719,95 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
}
}
+ const export_ty = ptr_ty.childType(zcu);
+ try sema.ensureLayoutResolved(export_ty, src, .@"export");
+ if (!export_ty.validateExtern(.other, zcu)) {
+ return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)});
+ errdefer msg.destroy(sema.gpa);
+ try sema.explainWhyTypeIsNotExtern(msg, src, export_ty, .other);
+ try sema.addDeclaredHereNote(msg, export_ty);
+ break :msg msg;
+ });
+ }
+
const ptr_info = ip.indexToKey(ptr_val.toIntern()).ptr;
- switch (ptr_info.base_addr) {
+ const target: Zcu.Exported = switch (ptr_info.base_addr) {
.comptime_alloc, .int, .comptime_field => return sema.fail(block, ptr_src, "export target must be a global variable or a comptime-known constant", .{}),
.eu_payload, .opt_payload, .field, .arr_elem => return sema.fail(block, ptr_src, "TODO: export pointer in middle of value", .{}),
- .uav => |uav| {
- if (ptr_info.byte_offset != 0) {
- return sema.fail(block, ptr_src, "TODO: export pointer in middle of value", .{});
+ .uav => |uav| .{ .uav = uav.val },
+ .nav => |orig_nav| target: {
+ try sema.ensureNavResolved(block, src, orig_nav, .fully);
+ const export_nav = switch (ip.indexToKey(ip.getNav(orig_nav).status.fully_resolved.val)) {
+ .variable => |v| v.owner_nav,
+ .@"extern" => |e| e.owner_nav,
+ .func => |f| f.owner_nav,
+ else => orig_nav,
+ };
+ if (ip.getNav(export_nav).getExtern(ip) != null) {
+ return sema.fail(block, src, "export target cannot be extern", .{});
}
- if (zcu.llvm_object != null and options.linkage == .internal) return;
- const export_ty = Value.fromInterned(uav.val).typeOf(zcu);
- if (!try sema.validateExternType(export_ty, .other)) {
- return sema.failWithOwnedErrorMsg(block, msg: {
- const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)});
- errdefer msg.destroy(sema.gpa);
- try sema.explainWhyTypeIsNotExtern(msg, src, export_ty, .other);
- try sema.addDeclaredHereNote(msg, export_ty);
- break :msg msg;
- });
- }
- try sema.exports.append(zcu.gpa, .{
- .opts = options,
- .src = src,
- .exported = .{ .uav = uav.val },
- .status = .in_progress,
- });
- },
- .nav => |nav| {
- if (ptr_info.byte_offset != 0) {
- return sema.fail(block, ptr_src, "TODO: export pointer in middle of value", .{});
- }
- try sema.analyzeExport(block, src, options, nav);
+ try sema.maybeQueueFuncBodyAnalysis(block, src, export_nav);
+ break :target .{ .nav = export_nav };
},
+ };
+ if (ptr_info.byte_offset != 0) {
+ return sema.fail(block, ptr_src, "TODO: export pointer in middle of value", .{});
}
+ if (zcu.llvm_object != null and options.linkage == .internal) return;
+ try sema.exports.append(zcu.gpa, .{
+ .opts = options,
+ .src = src,
+ .exported = target,
+ .status = .in_progress,
+ });
}
-pub fn analyzeExport(
+/// Asserts that `sema.owner` is a `.nav_val` whose value is resolved.
+///
+/// Exports that `Nav` by the given name with all other options set to default.
+pub fn analyzeExportSelfNav(
sema: *Sema,
block: *Block,
src: LazySrcLoc,
- options: Zcu.Export.Options,
- orig_nav_index: InternPool.Nav.Index,
+ name: InternPool.NullTerminatedString,
) !void {
const gpa = sema.gpa;
const pt = sema.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
- if (zcu.llvm_object != null and options.linkage == .internal)
- return;
+ const orig_nav = sema.owner.unwrap().nav_val;
+ const export_val: Value = .fromInterned(ip.getNav(orig_nav).status.fully_resolved.val);
+ const export_ty = export_val.typeOf(zcu);
- try sema.ensureNavResolved(block, src, orig_nav_index, .fully);
+ if (!export_ty.validateExtern(.other, zcu)) {
+ return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)});
+ errdefer msg.destroy(gpa);
+ try sema.explainWhyTypeIsNotExtern(msg, src, export_ty, .other);
+ try sema.addDeclaredHereNote(msg, export_ty);
+ break :msg msg;
+ });
+ }
- const exported_nav_index = switch (ip.indexToKey(ip.getNav(orig_nav_index).status.fully_resolved.val)) {
+ const export_nav = switch (ip.indexToKey(export_val.toIntern())) {
.variable => |v| v.owner_nav,
.@"extern" => |e| e.owner_nav,
- .func => |f| f.owner_nav,
- else => orig_nav_index,
+ .func => |f| export_nav: {
+ assert(export_ty.fnHasRuntimeBits(zcu)); // otherwise `validateExtern` failed above
+ const orig_fn_index = ip.unwrapCoercedFunc(export_val.toIntern());
+ try sema.addReferenceEntry(block, src, .wrap(.{ .func = orig_fn_index }));
+ try zcu.ensureFuncBodyAnalysisQueued(orig_fn_index);
+ break :export_nav f.owner_nav;
+ },
+ else => orig_nav,
};
- const exported_nav = ip.getNav(exported_nav_index);
- const export_ty: Type = .fromInterned(exported_nav.typeOf(ip));
-
- if (!try sema.validateExternType(export_ty, .other)) {
- return sema.failWithOwnedErrorMsg(block, msg: {
- const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)});
- errdefer msg.destroy(gpa);
-
- try sema.explainWhyTypeIsNotExtern(msg, src, export_ty, .other);
-
- try sema.addDeclaredHereNote(msg, export_ty);
- break :msg msg;
- });
- }
-
- // TODO: some backends might support re-exporting extern decls
- if (exported_nav.getExtern(ip) != null) {
- return sema.fail(block, src, "export target cannot be extern", .{});
- }
-
- try sema.maybeQueueFuncBodyAnalysis(block, src, exported_nav_index);
-
try sema.exports.append(gpa, .{
- .opts = options,
+ .opts = .{ .name = name },
.src = src,
- .exported = .{ .nav = exported_nav_index },
+ .exported = .{ .nav = export_nav },
.status = .in_progress,
});
}
@@ -6413,7 +5822,8 @@ fn zirDisableInstrumentation(sema: *Sema) CompileError!void {
.@"comptime",
.nav_val,
.nav_ty,
- .type,
+ .type_layout,
+ .struct_defaults,
.memoized_state,
=> return, // does nothing outside a function
};
@@ -6431,7 +5841,8 @@ fn zirDisableIntrinsics(sema: *Sema) CompileError!void {
.@"comptime",
.nav_val,
.nav_ty,
- .type,
+ .type_layout,
+ .struct_defaults,
.memoized_state,
=> return, // does nothing outside a function
};
@@ -6457,7 +5868,7 @@ fn zirBreak(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) CompileError
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].@"break";
const extra = sema.code.extraData(Zir.Inst.Break, inst_data.payload_index).data;
- const operand = try sema.resolveInst(inst_data.operand);
+ const operand = sema.resolveInst(inst_data.operand);
const zir_block = extra.block_inst;
var block = start_block;
@@ -6491,7 +5902,7 @@ fn zirSwitchContinue(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) Com
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].@"break";
const extra = sema.code.extraData(Zir.Inst.Break, inst_data.payload_index).data;
const operand_src = start_block.nodeOffset(extra.operand_src_node.unwrap().?);
- const uncoerced_operand = try sema.resolveInst(inst_data.operand);
+ const uncoerced_operand = sema.resolveInst(inst_data.operand);
const switch_inst = extra.block_inst;
switch (sema.code.instructions.items(.tag)[@intFromEnum(switch_inst)]) {
@@ -6500,7 +5911,7 @@ fn zirSwitchContinue(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) Com
else => unreachable, // assertion failure
}
- const operand_ty = (try sema.resolveInst(switch_inst.toRef())).toType();
+ const operand_ty = (sema.resolveInst(switch_inst.toRef())).toType();
const operand = try sema.coerce(start_block, operand_ty, uncoerced_operand, operand_src);
try sema.validateRuntimeValue(start_block, operand_src, operand);
@@ -6567,7 +5978,7 @@ fn zirDbgVar(
air_tag: Air.Inst.Tag,
) CompileError!void {
const str_op = sema.code.instructions.items(.data)[@intFromEnum(inst)].str_op;
- const operand = try sema.resolveInst(str_op.operand);
+ const operand = sema.resolveInst(str_op.operand);
const name = str_op.getStr(sema.code);
try sema.addDbgVar(block, operand, air_tag, name);
}
@@ -6589,9 +6000,9 @@ fn addDbgVar(
.dbg_var_val, .dbg_arg_inline => operand_ty,
else => unreachable,
};
- if (try val_ty.comptimeOnlySema(pt)) return;
- if (!(try val_ty.hasRuntimeBitsSema(pt))) return;
- if (try sema.resolveValue(operand)) |operand_val| {
+ if (val_ty.comptimeOnly(zcu)) return;
+ if (!val_ty.hasRuntimeBits(zcu)) return;
+ if (sema.resolveValue(operand)) |operand_val| {
if (operand_val.canMutateComptimeVarState(zcu)) return;
}
@@ -6730,7 +6141,7 @@ fn funcDeclSrcInst(sema: *Sema, func_inst: Air.Inst.Ref) !?InternPool.TrackedIns
const pt = sema.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
- const func_val = try sema.resolveValue(func_inst) orelse return null;
+ const func_val = sema.resolveValue(func_inst) orelse return null;
if (func_val.isUndef(zcu)) return null;
const nav = switch (ip.indexToKey(func_val.toIntern())) {
.@"extern" => |e| e.owner_nav,
@@ -6759,7 +6170,6 @@ pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref
if (!block.ownerModule().error_tracing) return .none;
const stack_trace_ty = try sema.getBuiltinType(block.nodeOffset(.zero), .StackTrace);
- try stack_trace_ty.resolveFields(pt);
const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls);
const field_index = sema.structFieldIndex(block, stack_trace_ty, field_name, LazySrcLoc.unneeded) catch |err| switch (err) {
error.AnalysisFail => @panic("std.builtin.StackTrace is corrupt"),
@@ -6803,11 +6213,10 @@ fn popErrorReturnTrace(
// the result is comptime-known to be a non-error. Either way, pop unconditionally.
const stack_trace_ty = try sema.getBuiltinType(src, .StackTrace);
- try stack_trace_ty.resolveFields(pt);
const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty);
const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty);
const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls);
- const field_ptr = try sema.structFieldPtr(block, src, err_return_trace, field_name, src, stack_trace_ty, true);
+ const field_ptr = try sema.structFieldPtr(block, src, err_return_trace, field_name, src, stack_trace_ty);
try sema.storePtr2(block, src, field_ptr, src, saved_error_trace_index, src, .store);
} else if (is_non_error == null) {
// The result might be an error. If it is, we leave the error trace alone. If it isn't, we need
@@ -6829,11 +6238,10 @@ fn popErrorReturnTrace(
// If non-error, then pop the error return trace by restoring the index.
const stack_trace_ty = try sema.getBuiltinType(src, .StackTrace);
- try stack_trace_ty.resolveFields(pt);
const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty);
const err_return_trace = try then_block.addTy(.err_return_trace, ptr_stack_trace_ty);
const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls);
- const field_ptr = try sema.structFieldPtr(&then_block, src, err_return_trace, field_name, src, stack_trace_ty, true);
+ const field_ptr = try sema.structFieldPtr(&then_block, src, err_return_trace, field_name, src, stack_trace_ty);
try sema.storePtr2(&then_block, src, field_ptr, src, saved_error_trace_index, src, .store);
_ = try then_block.addBr(cond_block_inst, .void_value);
@@ -6905,9 +6313,9 @@ fn zirCall(
const pop_error_return_trace = extra.data.flags.pop_error_return_trace;
const callee: ResolvedFieldCallee = switch (kind) {
- .direct => .{ .direct = try sema.resolveInst(extra.data.callee) },
+ .direct => .{ .direct = sema.resolveInst(extra.data.callee) },
.field => blk: {
- const object_ptr = try sema.resolveInst(extra.data.obj_ptr);
+ const object_ptr = sema.resolveInst(extra.data.obj_ptr);
const field_name = try zcu.intern_pool.getOrPutString(
gpa,
io,
@@ -6969,7 +6377,6 @@ fn zirCall(
// need to clean-up our own trace if we were passed to a non-error-handling expression.
if (input_is_error or (pop_error_return_trace and return_ty.isError(zcu))) {
const stack_trace_ty = try sema.getBuiltinType(call_src, .StackTrace);
- try stack_trace_ty.resolveFields(pt);
const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls);
const field_index = try sema.structFieldIndex(block, stack_trace_ty, field_name, call_src);
@@ -7255,7 +6662,7 @@ const CallArgsInfo = union(enum) {
return sema.failWithNeededComptime(block, cai.argSrc(block, arg_index), null);
}
- if (sema.typeOf(uncoerced_arg).zigTypeTag(zcu) == .noreturn) {
+ if (sema.typeOf(uncoerced_arg).classify(zcu) == .no_possible_value) {
// This terminates resolution of arguments. The caller should
// propagate this.
return uncoerced_arg;
@@ -7318,6 +6725,21 @@ fn analyzeCall(
} else func_src;
const func_ty_info = zcu.typeToFunc(func_ty).?;
+
+ for (func_ty_info.param_types.get(ip), 0..) |param_ty_ip, param_index| {
+ const arg_src = args_info.argSrc(block, param_index);
+ try sema.ensureLayoutResolved(.fromInterned(param_ty_ip), arg_src, .init);
+ }
+ try sema.ensureLayoutResolved(.fromInterned(func_ty_info.return_type), func_ret_ty_src, .return_type);
+ try sema.validateResolvedFuncType(
+ block,
+ func_ty_info.cc,
+ func_ty_info.param_types.get(ip),
+ .fromInterned(func_ty_info.return_type),
+ func_src,
+ maybe_func_inst,
+ );
+
if (!callConvIsCallable(func_ty_info.cc)) {
return sema.failWithOwnedErrorMsg(block, msg: {
const msg = try sema.errMsg(
@@ -7334,6 +6756,28 @@ fn analyzeCall(
});
}
+ const any_comptime_params = func_ty_info.comptime_bits != 0 or ct: {
+ for (func_ty_info.param_types.get(ip)) |param_ty| {
+ if (Type.fromInterned(param_ty).comptimeOnly(zcu)) break :ct true;
+ }
+ break :ct Type.fromInterned(func_ty_info.return_type).comptimeOnly(zcu);
+ };
+ const any_generic_types = generic: {
+ for (func_ty_info.param_types.get(ip)) |param_ty| {
+ if (param_ty == .generic_poison_type) break :generic true;
+ }
+ const ret_ty: Type = .fromInterned(func_ty_info.return_type);
+ if (ret_ty.toIntern() == .generic_poison_type) {
+ break :generic true;
+ }
+ if (ret_ty.zigTypeTag(zcu) == .error_union and
+ ret_ty.errorUnionPayload(zcu).toIntern() == .generic_poison_type)
+ {
+ break :generic true;
+ }
+ break :generic false;
+ };
+
// We need this value in a few code paths.
const callee_val = try sema.resolveDefinedValue(block, call_src, callee);
// If the callee is a comptime-known *non-extern* function, `func_val` is populated.
@@ -7353,7 +6797,7 @@ fn analyzeCall(
else => unreachable,
} else .{ null, false };
- if (func_ty_info.is_generic and func_val == null) {
+ if ((any_generic_types or any_comptime_params) and func_val == null) {
return sema.failWithNeededComptime(block, func_src, .{ .simple = .generic_call_target });
}
@@ -7369,19 +6813,18 @@ fn analyzeCall(
.src = call_src,
.r = .{ .simple = .comptime_call_modifier },
} };
- } else if (!inline_requested and try Type.fromInterned(func_ty_info.return_type).comptimeOnlySema(pt)) {
- block.comptime_reason = .{
- .reason = .{
+ } else if (!inline_requested) {
+ const ret_ty: Type = .fromInterned(func_ty_info.return_type);
+ if (ret_ty.comptimeOnly(zcu)) {
+ block.comptime_reason = .{ .reason = .{
.src = call_src,
- .r = .{
- .comptime_only_ret_ty = .{
- .ty = .fromInterned(func_ty_info.return_type),
- .is_generic_inst = false,
- .ret_ty_src = func_ret_ty_src,
- },
- },
- },
- };
+ .r = .{ .comptime_only_ret_ty = .{
+ .ty = .fromInterned(func_ty_info.return_type),
+ .is_generic_inst = false,
+ .ret_ty_src = func_ret_ty_src,
+ } },
+ } };
+ }
}
}
@@ -7403,13 +6846,13 @@ fn analyzeCall(
// This is the `inst_map` used when evaluating generic parameters and return types.
var generic_inst_map: InstMap = .{};
defer generic_inst_map.deinit(gpa);
- if (func_ty_info.is_generic) {
+ if (any_generic_types) {
try generic_inst_map.ensureSpaceForInstructions(gpa, fn_zir_info.param_body);
}
// This exists so that `generic_block` below can include a "called from here" note back to this
// call site when analyzing generic parameter/return types.
- var generic_inlining: Block.Inlining = if (func_ty_info.is_generic) .{
+ var generic_inlining: Block.Inlining = if (any_generic_types) .{
.call_block = block,
.call_src = call_src,
.func = func_val.?.toIntern(),
@@ -7422,18 +6865,18 @@ fn analyzeCall(
// This is the block in which we evaluate generic function components: that is, generic parameter
// types and the generic return type. This must not be used if the function is not generic.
// `comptime_reason` is set as needed.
- var generic_block: Block = if (func_ty_info.is_generic) .{
+ var generic_block: Block = if (any_generic_types) .{
.parent = null,
.sema = sema,
.namespace = fn_nav.analysis.?.namespace,
- .instructions = .{},
+ .instructions = .empty,
.inlining = &generic_inlining,
.src_base_inst = fn_nav.analysis.?.zir_index,
.type_name_ctx = fn_nav.fqn,
} else undefined;
- defer if (func_ty_info.is_generic) generic_block.instructions.deinit(gpa);
+ defer if (any_generic_types) generic_block.instructions.deinit(gpa);
- if (func_ty_info.is_generic) {
+ if (any_generic_types) {
// We certainly depend on the generic owner's signature!
try sema.declareDependency(.{ .src_hash = fn_tracked_inst });
}
@@ -7445,7 +6888,7 @@ fn analyzeCall(
if (raw != .generic_poison_type) break :ty .fromInterned(raw);
// We must discover the generic parameter type.
- assert(func_ty_info.is_generic);
+ assert(any_generic_types);
const param_inst_idx = fn_zir_info.param_body[arg_idx];
const param_inst = fn_zir.instructions.get(@intFromEnum(param_inst_idx));
switch (param_inst.tag) {
@@ -7476,7 +6919,7 @@ fn analyzeCall(
} };
const ty_ref = try sema.resolveInlineBody(&generic_block, body, param_inst_idx);
- const param_ty = try sema.analyzeAsType(&generic_block, param_src, ty_ref);
+ const param_ty = try sema.analyzeAsType(&generic_block, param_src, .fn_param_types, ty_ref);
if (!param_ty.isValidParamType(zcu)) {
const opaque_str = if (param_ty.zigTypeTag(zcu) == .@"opaque") "opaque " else "";
@@ -7490,15 +6933,15 @@ fn analyzeCall(
arg.* = try args_info.analyzeArg(sema, block, arg_idx, param_ty, func_ty_info, callee, maybe_func_inst);
const arg_ty = sema.typeOf(arg.*);
- if (arg_ty.zigTypeTag(zcu) == .noreturn) {
+ if (arg_ty.classify(zcu) == .no_possible_value) {
return arg.*; // terminate analysis here
}
- if (func_ty_info.is_generic) {
+ if (any_generic_types) {
// We need to put the argument into `generic_inst_map` so that other parameters can refer to it.
const param_inst_idx = fn_zir_info.param_body[arg_idx];
const declared_comptime = if (std.math.cast(u5, arg_idx)) |i| func_ty_info.paramIsComptime(i) else false;
- const param_is_comptime = declared_comptime or try arg_ty.comptimeOnlySema(pt);
+ const param_is_comptime = declared_comptime or arg_ty.comptimeOnly(zcu);
// We allow comptime-known arguments to propagate to generic types not only for comptime
// parameters, but if the call is known to be inline.
if (param_is_comptime or early_known_inline) {
@@ -7516,6 +6959,10 @@ fn analyzeCall(
);
}
generic_inst_map.putAssumeCapacityNoClobber(param_inst_idx, arg.*);
+ } else if (try arg_ty.onePossibleValue(pt)) |opv| {
+ // The argument is comptime-known, even though this is a generic instantiation (as
+ // opposed to an inline call), because the parameter type is OPV.
+ generic_inst_map.putAssumeCapacityNoClobber(param_inst_idx, .fromValue(opv));
} else {
// We need a dummy instruction with this type. It doesn't actually need to be in any block,
// since it will never be referenced at runtime!
@@ -7532,7 +6979,7 @@ fn analyzeCall(
// calls (where it should be the IES of the instantiation). However, it's how we print this
// in error messages.
const resolved_ret_ty: Type = ret_ty: {
- if (!func_ty_info.is_generic) break :ret_ty .fromInterned(func_ty_info.return_type);
+ if (!any_generic_types) break :ret_ty .fromInterned(func_ty_info.return_type);
const maybe_poison_bare = if (fn_zir_info.inferred_error_set) maybe_poison: {
break :maybe_poison ip.errorUnionPayload(func_ty_info.return_type);
@@ -7542,7 +6989,7 @@ fn analyzeCall(
// Evaluate the generic return type. As with generic parameters, we switch out `sema.code` and `sema.inst_map`.
- assert(func_ty_info.is_generic);
+ assert(any_generic_types);
const old_code = sema.code;
const old_inst_map = sema.inst_map;
@@ -7565,7 +7012,7 @@ fn analyzeCall(
} else bare: {
assert(fn_zir_info.ret_ty_body.len != 0);
const ty_ref = try sema.resolveInlineBody(&generic_block, fn_zir_info.ret_ty_body, fn_zir_inst);
- break :bare try sema.analyzeAsType(&generic_block, func_ret_ty_src, ty_ref);
+ break :bare try sema.analyzeAsType(&generic_block, func_ret_ty_src, .fn_ret_ty, ty_ref);
};
assert(bare_ty.toIntern() != .generic_poison_type);
@@ -7584,10 +7031,11 @@ fn analyzeCall(
break :ret_ty full_ty;
};
+ try sema.ensureLayoutResolved(resolved_ret_ty, func_ret_ty_src, .return_type);
// If we've discovered after evaluating arguments that a generic function instantiation is
// comptime-only, then we can mark the block as comptime *now*.
- if (!inline_requested and !block.isComptime() and try resolved_ret_ty.comptimeOnlySema(pt)) {
+ if (!inline_requested and !block.isComptime() and resolved_ret_ty.comptimeOnly(zcu)) {
block.comptime_reason = .{
.reason = .{
.src = call_src,
@@ -7618,15 +7066,23 @@ fn analyzeCall(
});
if (func_ty_info.cc == .auto) {
switch (sema.owner.unwrap()) {
- .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {},
+ .@"comptime",
+ .nav_ty,
+ .nav_val,
+ .type_layout,
+ .struct_defaults,
+ .memoized_state,
+ => {},
+
.func => |owner_func| ip.funcSetHasErrorTrace(io, owner_func, true),
}
}
for (args, 0..) |arg, arg_idx| {
- try sema.validateRuntimeValue(block, args_info.argSrc(block, arg_idx), arg);
+ const arg_src = args_info.argSrc(block, arg_idx);
+ try sema.validateRuntimeValue(block, arg_src, arg);
}
const runtime_func: Air.Inst.Ref, const runtime_args: []const Air.Inst.Ref = func: {
- if (!func_ty_info.is_generic) break :func .{ callee, args };
+ if (!any_generic_types and !any_comptime_params) break :func .{ callee, args };
// Instantiate the generic function!
@@ -7648,13 +7104,13 @@ fn analyzeCall(
break :c true;
}
}
- break :c try arg_ty.comptimeOnlySema(pt);
+ break :c arg_ty.comptimeOnly(zcu);
};
const is_noalias = if (std.math.cast(u5, arg_idx)) |i| func_ty_info.paramIsNoalias(i) else false;
if (is_comptime) {
// We already emitted an error if the argument isn't comptime-known.
- comptime_arg.* = (try sema.resolveValue(arg)).?.toIntern();
+ comptime_arg.* = sema.resolveValue(arg).?.toIntern();
} else {
comptime_arg.* = .none;
if (is_noalias) {
@@ -7695,7 +7151,7 @@ fn analyzeCall(
};
ref_func: {
- const runtime_func_val = try sema.resolveValue(runtime_func) orelse break :ref_func;
+ const runtime_func_val = sema.resolveValue(runtime_func) orelse break :ref_func;
if (!ip.isFuncBody(runtime_func_val.toIntern())) break :ref_func;
const orig_fn_index = ip.unwrapCoercedFunc(runtime_func_val.toIntern());
try sema.addReferenceEntry(block, call_src, .wrap(.{ .func = orig_fn_index }));
@@ -7714,7 +7170,7 @@ fn analyzeCall(
};
try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).@"struct".fields.len + runtime_args.len);
- const maybe_opv = try block.addInst(.{
+ const call_ref = try block.addInst(.{
.tag = call_tag,
.data = .{ .pl_op = .{
.operand = runtime_func,
@@ -7725,8 +7181,10 @@ fn analyzeCall(
});
sema.appendRefsAssumeCapacity(runtime_args);
+ const actual_ret_ty = sema.typeOf(call_ref);
+
if (ensure_result_used) {
- try sema.ensureResultUsed(block, sema.typeOf(maybe_opv), call_src);
+ try sema.ensureResultUsed(block, actual_ret_ty, call_src);
}
if (call_tag == .call_always_tail) {
@@ -7736,29 +7194,32 @@ fn analyzeCall(
.pointer => func_or_ptr_ty.childType(zcu),
else => unreachable,
};
- return sema.handleTailCall(block, call_src, runtime_func_ty, maybe_opv);
+ return sema.handleTailCall(block, call_src, runtime_func_ty, call_ref);
}
- if (ip.isNoReturn(resolved_ret_ty.toIntern())) {
- const want_check = c: {
- if (!block.wantSafety()) break :c false;
- if (func_val != null) break :c false;
- break :c true;
- };
- if (want_check) {
- try sema.safetyPanic(block, call_src, .noreturn_returned);
- } else {
- _ = try block.addNoOp(.unreach);
- }
- return .unreachable_value;
+ switch (actual_ret_ty.classify(zcu)) {
+ .no_possible_value => {
+ const want_check = c: {
+ if (!block.wantSafety()) break :c false;
+ if (func_val != null) break :c false;
+ break :c true;
+ };
+ if (want_check) {
+ try sema.safetyPanic(block, call_src, .noreturn_returned);
+ } else {
+ _ = try block.addNoOp(.unreach);
+ }
+ return .unreachable_value;
+ },
+ .one_possible_value => {
+ return .fromValue((try actual_ret_ty.onePossibleValue(pt)).?);
+ },
+ .runtime => {
+ return call_ref;
+ },
+ .partially_comptime => unreachable,
+ .fully_comptime => unreachable,
}
-
- const result: Air.Inst.Ref = if (try sema.typeHasOnePossibleValue(sema.typeOf(maybe_opv))) |opv|
- .fromValue(opv)
- else
- maybe_opv;
-
- return result;
}
// This is an inline call. The function must be comptime-known. We will analyze its body directly using this `Sema`.
@@ -7836,14 +7297,14 @@ fn analyzeCall(
if (zcu.comp.config.incremental) break :m false;
if (!block.isComptime()) break :m false;
for (args) |a| {
- const val = (try sema.resolveValue(a)).?;
+ const val = sema.resolveValue(a).?;
if (val.canMutateComptimeVarState(zcu)) break :m false;
}
break :m true;
};
const memoized_arg_values: []const InternPool.Index = if (want_memoize) arg_vals: {
const vals = try sema.arena.alloc(InternPool.Index, args.len);
- for (vals, args) |*v, a| v.* = (try sema.resolveValue(a)).?.toIntern();
+ for (vals, args) |*v, a| v.* = sema.resolveValue(a).?.toIntern();
break :arg_vals vals;
} else undefined;
if (want_memoize) memoize: {
@@ -7927,7 +7388,7 @@ fn analyzeCall(
.parent = null,
.sema = sema,
.namespace = fn_nav.analysis.?.namespace,
- .instructions = .{},
+ .instructions = .empty,
.inlining = &inlining,
.is_typeof = block.is_typeof,
.comptime_reason = if (block.isComptime()) .inlining_parent else null,
@@ -8000,7 +7461,11 @@ fn analyzeCall(
break :result try sema.resolveAnalyzedBlock(block, call_src, &child_block, &inlining.merges, need_debug_scope);
};
- const maybe_opv: Air.Inst.Ref = if (try sema.resolveValue(result_raw)) |result_val| r: {
+ if (sema.typeOf(result_raw).isNoReturn(zcu)) {
+ return .unreachable_value;
+ }
+
+ const maybe_opv: Air.Inst.Ref = if (sema.resolveValue(result_raw)) |result_val| r: {
const val_resolved = try sema.resolveAdHocInferredErrorSet(block, call_src, result_val.toIntern());
break :r Air.internedToRef(val_resolved);
} else r: {
@@ -8012,7 +7477,7 @@ fn analyzeCall(
};
if (block.isComptime()) {
- const result_val = (try sema.resolveValue(maybe_opv)).?;
+ const result_val = sema.resolveValue(maybe_opv).?;
if (want_memoize and sema.allow_memoize and !result_val.canMutateComptimeVarState(zcu)) {
_ = try pt.intern(.{ .memoized_call = .{
.func = func_val.?.toIntern(),
@@ -8081,15 +7546,12 @@ fn zirArrayInitElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil
const bin = sema.code.instructions.items(.data)[@intFromEnum(inst)].bin;
const maybe_wrapped_indexable_ty = try sema.resolveTypeOrPoison(block, LazySrcLoc.unneeded, bin.lhs) orelse return .generic_poison_type;
const indexable_ty = maybe_wrapped_indexable_ty.optEuBaseType(zcu);
- try indexable_ty.resolveFields(pt);
assert(indexable_ty.isIndexable(zcu)); // validated by a previous instruction
- if (indexable_ty.zigTypeTag(zcu) == .@"struct") {
- const elem_type = indexable_ty.fieldType(@intFromEnum(bin.rhs), zcu);
- return Air.internedToRef(elem_type.toIntern());
- } else {
- const elem_type = indexable_ty.elemType2(zcu);
- return Air.internedToRef(elem_type.toIntern());
- }
+ const elem_ty = switch (indexable_ty.zigTypeTag(zcu)) {
+ .@"struct" => indexable_ty.fieldType(@intFromEnum(bin.rhs), zcu),
+ else => indexable_ty.indexableElem(zcu),
+ };
+ return .fromType(elem_ty);
}
fn zirElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -8190,7 +7652,7 @@ fn zirArrayTypeSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil
const len = try sema.resolveInt(block, len_src, extra.len, .usize, .{ .simple = .array_length });
const elem_type = try sema.resolveType(block, elem_src, extra.elem_type);
try sema.validateArrayElemType(block, elem_type, elem_src);
- const uncasted_sentinel = try sema.resolveInst(extra.sentinel);
+ const uncasted_sentinel = sema.resolveInst(extra.sentinel);
const sentinel = try sema.coerce(block, elem_type, uncasted_sentinel, sentinel_src);
const sentinel_val = try sema.resolveConstDefinedValue(block, sentinel_src, sentinel, .{ .simple = .array_sentinel });
if (sentinel_val.canMutateComptimeVarState(zcu)) {
@@ -8306,11 +7768,11 @@ fn zirIntFromError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD
const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
const src = block.nodeOffset(extra.node);
const operand_src = block.builtinCallArgSrc(extra.node, 0);
- const uncasted_operand = try sema.resolveInst(extra.operand);
+ const uncasted_operand = sema.resolveInst(extra.operand);
const operand = try sema.coerce(block, .anyerror, uncasted_operand, operand_src);
const err_int_ty = try pt.errorIntType();
- if (try sema.resolveValue(operand)) |val| {
+ if (sema.resolveValue(operand)) |val| {
if (val.isUndef(zcu)) {
return pt.undefRef(err_int_ty);
}
@@ -8350,12 +7812,12 @@ fn zirErrorFromInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD
const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
const src = block.nodeOffset(extra.node);
const operand_src = block.builtinCallArgSrc(extra.node, 0);
- const uncasted_operand = try sema.resolveInst(extra.operand);
+ const uncasted_operand = sema.resolveInst(extra.operand);
const err_int_ty = try pt.errorIntType();
const operand = try sema.coerce(block, err_int_ty, uncasted_operand, operand_src);
if (try sema.resolveDefinedValue(block, operand_src, operand)) |value| {
- const int = try sema.usizeCast(block, operand_src, try value.toUnsignedIntSema(pt));
+ const int = try sema.usizeCast(block, operand_src, value.toUnsignedInt(zcu));
if (int > len: {
const mutate = &ip.global_error_set.mutate;
mutate.map.mutex.lockUncancelable(io);
@@ -8397,8 +7859,8 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
const src = block.src(.{ .node_offset_bin_op = inst_data.src_node });
const lhs_src = block.src(.{ .node_offset_bin_lhs = inst_data.src_node });
const rhs_src = block.src(.{ .node_offset_bin_rhs = inst_data.src_node });
- const lhs = try sema.resolveInst(extra.lhs);
- const rhs = try sema.resolveInst(extra.rhs);
+ const lhs = sema.resolveInst(extra.lhs);
+ const rhs = sema.resolveInst(extra.rhs);
if (sema.typeOf(lhs).zigTypeTag(zcu) == .bool and sema.typeOf(rhs).zigTypeTag(zcu) == .bool) {
const msg = msg: {
const msg = try sema.errMsg(lhs_src, "expected error set type, found 'bool'", .{});
@@ -8408,8 +7870,8 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
};
return sema.failWithOwnedErrorMsg(block, msg);
}
- const lhs_ty = try sema.analyzeAsType(block, lhs_src, lhs);
- const rhs_ty = try sema.analyzeAsType(block, rhs_src, rhs);
+ const lhs_ty = try sema.analyzeAsType(block, lhs_src, .type, lhs);
+ const rhs_ty = try sema.analyzeAsType(block, rhs_src, .type, rhs);
if (lhs_ty.zigTypeTag(zcu) != .error_set)
return sema.fail(block, lhs_src, "expected error set type, found '{f}'", .{lhs_ty.fmt(pt)});
if (rhs_ty.zigTypeTag(zcu) != .error_set)
@@ -8420,21 +7882,21 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
return .anyerror_type;
}
- if (ip.isInferredErrorSetType(lhs_ty.toIntern())) {
- switch (try sema.resolveInferredErrorSet(block, src, lhs_ty.toIntern())) {
- // isAnyError might have changed from a false negative to a true
- // positive after resolution.
- .anyerror_type => return .anyerror_type,
- else => {},
- }
+ switch (ip.indexToKey(lhs_ty.toIntern())) {
+ .inferred_error_set_type => |func_index| {
+ try sema.ensureFuncIesResolved(block, src, func_index);
+ if (ip.funcIesResolvedUnordered(func_index) == .anyerror_type) return .anyerror_type;
+ },
+ .error_set_type => {},
+ else => unreachable,
}
- if (ip.isInferredErrorSetType(rhs_ty.toIntern())) {
- switch (try sema.resolveInferredErrorSet(block, src, rhs_ty.toIntern())) {
- // isAnyError might have changed from a false negative to a true
- // positive after resolution.
- .anyerror_type => return .anyerror_type,
- else => {},
- }
+ switch (ip.indexToKey(rhs_ty.toIntern())) {
+ .inferred_error_set_type => |func_index| {
+ try sema.ensureFuncIesResolved(block, src, func_index);
+ if (ip.funcIesResolvedUnordered(func_index) == .anyerror_type) return .anyerror_type;
+ },
+ .error_set_type => {},
+ else => unreachable,
}
const err_set_ty = try sema.errorSetMerge(lhs_ty, rhs_ty);
@@ -8533,23 +7995,22 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const src = block.nodeOffset(inst_data.src_node);
const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);
- const operand = try sema.resolveInst(inst_data.operand);
+ const operand = sema.resolveInst(inst_data.operand);
const operand_ty = sema.typeOf(operand);
const enum_tag: Air.Inst.Ref = switch (operand_ty.zigTypeTag(zcu)) {
.@"enum" => operand,
.@"union" => blk: {
- try operand_ty.resolveFields(pt);
- const tag_ty = operand_ty.unionTagType(zcu) orelse {
+ if (operand_ty.unionTagType(zcu) == null) {
return sema.fail(
block,
operand_src,
"untagged union '{f}' cannot be converted to integer",
.{operand_ty.fmt(pt)},
);
- };
+ }
- break :blk try sema.unionToTag(block, tag_ty, operand, operand_src);
+ break :blk try sema.unionToTag(block, operand);
},
else => {
return sema.fail(block, operand_src, "expected enum or tagged union, found '{f}'", .{
@@ -8568,17 +8029,9 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
});
}
- if (try sema.typeHasOnePossibleValue(enum_tag_ty)) |opv| {
- return Air.internedToRef((try pt.getCoerced(opv, int_tag_ty)).toIntern());
- }
-
- if (try sema.resolveValue(enum_tag)) |enum_tag_val| {
- if (enum_tag_val.isUndef(zcu)) {
- return pt.undefRef(int_tag_ty);
- }
-
- const val = try enum_tag_val.intFromEnum(enum_tag_ty, pt);
- return Air.internedToRef(val.toIntern());
+ if (sema.resolveValue(enum_tag)) |enum_tag_val| {
+ if (enum_tag_val.isUndef(zcu)) return pt.undefRef(int_tag_ty);
+ return .fromValue(enum_tag_val.intFromEnum(zcu));
}
try sema.requireRuntimeBlock(block, src, operand_src);
@@ -8593,18 +8046,19 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
const src = block.nodeOffset(inst_data.src_node);
const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);
const dest_ty = try sema.resolveDestType(block, src, extra.lhs, .remove_eu_opt, "@enumFromInt");
- const operand = try sema.resolveInst(extra.rhs);
+ const operand = sema.resolveInst(extra.rhs);
const operand_ty = sema.typeOf(operand);
if (dest_ty.zigTypeTag(zcu) != .@"enum") {
return sema.fail(block, src, "expected enum, found '{f}'", .{dest_ty.fmt(pt)});
}
+ try sema.ensureLayoutResolved(dest_ty, src, .init);
_ = try sema.checkIntType(block, operand_src, operand_ty);
- if (try sema.resolveValue(operand)) |int_val| {
+ if (sema.resolveValue(operand)) |int_val| {
if (dest_ty.isNonexhaustiveEnum(zcu)) {
const int_tag_ty = dest_ty.intTagType(zcu);
- if (try sema.intFitsInType(int_val, int_tag_ty, null)) {
+ if (int_val.intFitsInType(int_tag_ty, null, zcu)) {
return Air.internedToRef((try pt.getCoerced(int_val, dest_ty)).toIntern());
}
return sema.fail(block, src, "int value '{f}' out of range of non-exhaustive enum '{f}'", .{
@@ -8626,19 +8080,15 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
return sema.failWithNeededComptime(block, operand_src, .{ .simple = .casted_to_comptime_enum });
}
- if (try sema.typeHasOnePossibleValue(dest_ty)) |opv| {
+ if (try dest_ty.onePossibleValue(pt)) |opv| {
if (block.wantSafety()) {
// The operand is runtime-known but the result is comptime-known. In
// this case we still need a safety check.
- const expect_int_val = switch (zcu.intern_pool.indexToKey(opv.toIntern())) {
- .enum_tag => |enum_tag| enum_tag.int,
- else => unreachable,
- };
- const expect_int_coerced = try pt.getCoerced(.fromInterned(expect_int_val), operand_ty);
- const ok = try block.addBinOp(.cmp_eq, operand, Air.internedToRef(expect_int_coerced.toIntern()));
+ const expect_int = try pt.getCoerced(opv.intFromEnum(zcu), operand_ty);
+ const ok = try block.addBinOp(.cmp_eq, operand, .fromValue(expect_int));
try sema.addSafetyCheck(block, src, ok, .invalid_enum_value);
}
- return Air.internedToRef(opv.toIntern());
+ return .fromValue(opv);
}
try sema.requireRuntimeBlock(block, src, operand_src);
@@ -8660,12 +8110,17 @@ fn zirOptionalPayloadPtr(
defer tracy.end();
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
- const optional_ptr = try sema.resolveInst(inst_data.operand);
+ const optional_ptr = sema.resolveInst(inst_data.operand);
const src = block.nodeOffset(inst_data.src_node);
+ const ptr_ty = sema.typeOf(optional_ptr);
+ assert(ptr_ty.zigTypeTag(sema.pt.zcu) == .pointer);
+ try sema.ensureLayoutResolved(ptr_ty.childType(sema.pt.zcu), src, .ptr_access);
+
return sema.analyzeOptionalPayloadPtr(block, src, optional_ptr, safety_check, false);
}
+/// Asserts that the layout of the pointer child type is already resolved.
fn analyzeOptionalPayloadPtr(
sema: *Sema,
block: *Block,
@@ -8680,12 +8135,13 @@ fn analyzeOptionalPayloadPtr(
assert(optional_ptr_ty.zigTypeTag(zcu) == .pointer);
const opt_type = optional_ptr_ty.childType(zcu);
+ opt_type.assertHasLayout(zcu);
if (opt_type.zigTypeTag(zcu) != .optional) {
return sema.failWithExpectedOptionalType(block, src, opt_type);
}
const child_type = opt_type.optionalChild(zcu);
- const child_pointer = try pt.ptrTypeSema(.{
+ const child_pointer = try pt.ptrType(.{
.child = child_type.toIntern(),
.flags = .{
.is_const = optional_ptr_ty.isConstPtr(zcu),
@@ -8698,7 +8154,7 @@ fn analyzeOptionalPayloadPtr(
if (sema.isComptimeMutablePtr(ptr_val)) {
// Set the optional to non-null at comptime.
// If the payload is OPV, we must use that value instead of undef.
- const payload_val = try sema.typeHasOnePossibleValue(child_type) orelse try pt.undefValue(child_type);
+ const payload_val = try child_type.onePossibleValue(pt) orelse try pt.undefValue(child_type);
const opt_val = try pt.intern(.{ .opt = .{
.ty = opt_type.toIntern(),
.val = payload_val.toIntern(),
@@ -8748,33 +8204,27 @@ fn zirOptionalPayload(
const zcu = pt.zcu;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const src = block.nodeOffset(inst_data.src_node);
- const operand = try sema.resolveInst(inst_data.operand);
+ const operand = sema.resolveInst(inst_data.operand);
const operand_ty = sema.typeOf(operand);
const result_ty = switch (operand_ty.zigTypeTag(zcu)) {
.optional => operand_ty.optionalChild(zcu),
- .pointer => t: {
- if (operand_ty.ptrSize(zcu) != .c) {
- return sema.failWithExpectedOptionalType(block, src, operand_ty);
- }
- // TODO https://github.com/ziglang/zig/issues/6597
- if (true) break :t operand_ty;
- const ptr_info = operand_ty.ptrInfo(zcu);
- break :t try pt.ptrTypeSema(.{
- .child = ptr_info.child,
- .flags = .{
- .alignment = ptr_info.flags.alignment,
- .is_const = ptr_info.flags.is_const,
- .is_volatile = ptr_info.flags.is_volatile,
- .is_allowzero = ptr_info.flags.is_allowzero,
- .address_space = ptr_info.flags.address_space,
- },
- });
+ // TODO: https://github.com/ziglang/zig/issues/6597 will eliminate this branch so that we only need to handle optionals.
+ .pointer => switch (operand_ty.ptrSize(zcu)) {
+ .c => operand_ty, // if `ptr` is a `[*c]T`, then `ptr.?` is also a `[*c]T`
+ .one, .many, .slice => return sema.failWithExpectedOptionalType(block, src, operand_ty),
},
else => return sema.failWithExpectedOptionalType(block, src, operand_ty),
};
- if (try sema.resolveDefinedValue(block, src, operand)) |val| {
- if (val.optionalValue(zcu)) |payload| return Air.internedToRef(payload.toIntern());
+ ct: {
+ if (try sema.resolveDefinedValue(block, src, operand)) |val| {
+ if (val.optionalValue(zcu)) |payload| return .fromValue(payload); // comptime-known payload
+ } else if (try sema.resolveIsNullFromType(block, src, operand_ty)) |is_null| {
+ if (!is_null) break :ct; // fully runtime-known
+ } else {
+ break :ct; // fully runtime-known
+ }
+ // Comptime-known to be `null`.
if (block.isComptime()) return sema.fail(block, src, "unable to unwrap null", .{});
if (safety_check and block.wantSafety()) {
try sema.safetyPanic(block, src, .unwrap_null);
@@ -8784,11 +8234,14 @@ fn zirOptionalPayload(
return .unreachable_value;
}
- try sema.requireRuntimeBlock(block, src, null);
if (safety_check and block.wantSafety()) {
const is_non_null = try block.addUnOp(.is_non_null, operand);
try sema.addSafetyCheck(block, src, is_non_null, .unwrap_null);
}
+
+ // If the payload is OPV, we need the safety check but have a comptime-known result.
+ if (try result_ty.onePossibleValue(pt)) |opv| return .fromValue(opv);
+
return block.addTyOp(.optional_payload, result_ty, operand);
}
@@ -8805,7 +8258,7 @@ fn zirErrUnionPayload(
const zcu = pt.zcu;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const src = block.nodeOffset(inst_data.src_node);
- const operand = try sema.resolveInst(inst_data.operand);
+ const operand = sema.resolveInst(inst_data.operand);
const operand_src = src;
const err_union_ty = sema.typeOf(operand);
if (err_union_ty.zigTypeTag(zcu) != .error_union) {
@@ -8844,8 +8297,8 @@ fn analyzeErrUnionPayload(
try sema.addSafetyCheckUnwrapError(block, src, operand, .unwrap_errunion_err, .is_non_err);
}
- if (try sema.typeHasOnePossibleValue(payload_ty)) |payload_only_value| {
- return Air.internedToRef(payload_only_value.toIntern());
+ if (try payload_ty.onePossibleValue(pt)) |payload_opv| {
+ return .fromValue(payload_opv);
}
return block.addTyOp(.unwrap_errunion_payload, payload_ty, operand);
@@ -8861,12 +8314,17 @@ fn zirErrUnionPayloadPtr(
defer tracy.end();
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
- const operand = try sema.resolveInst(inst_data.operand);
+ const operand = sema.resolveInst(inst_data.operand);
const src = block.nodeOffset(inst_data.src_node);
+ const ptr_ty = sema.typeOf(operand);
+ assert(ptr_ty.zigTypeTag(sema.pt.zcu) == .pointer);
+ try sema.ensureLayoutResolved(ptr_ty.childType(sema.pt.zcu), src, .ptr_access);
+
return sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false);
}
+/// Asserts that the layout of the pointer child type is already resolved.
fn analyzeErrUnionPayloadPtr(
sema: *Sema,
block: *Block,
@@ -8887,8 +8345,9 @@ fn analyzeErrUnionPayloadPtr(
}
const err_union_ty = operand_ty.childType(zcu);
+ err_union_ty.assertHasLayout(zcu);
const payload_ty = err_union_ty.errorUnionPayload(zcu);
- const operand_pointer_ty = try pt.ptrTypeSema(.{
+ const operand_pointer_ty = try pt.ptrType(.{
.child = payload_ty.toIntern(),
.flags = .{
.is_const = operand_ty.isConstPtr(zcu),
@@ -8901,7 +8360,7 @@ fn analyzeErrUnionPayloadPtr(
if (sema.isComptimeMutablePtr(ptr_val)) {
// Set the error union to non-error at comptime.
// If the payload is OPV, we must use that value instead of undef.
- const payload_val = try sema.typeHasOnePossibleValue(payload_ty) orelse try pt.undefValue(payload_ty);
+ const payload_val = try payload_ty.onePossibleValue(pt) orelse try pt.undefValue(payload_ty);
const eu_val = try pt.intern(.{ .error_union = .{
.ty = err_union_ty.toIntern(),
.val = .{ .payload = payload_val.toIntern() },
@@ -8948,7 +8407,7 @@ fn zirErrUnionCode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const src = block.nodeOffset(inst_data.src_node);
- const operand = try sema.resolveInst(inst_data.operand);
+ const operand = sema.resolveInst(inst_data.operand);
return sema.analyzeErrUnionCode(block, src, operand);
}
@@ -8984,7 +8443,7 @@ fn zirErrUnionCodePtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const src = block.nodeOffset(inst_data.src_node);
- const operand = try sema.resolveInst(inst_data.operand);
+ const operand = sema.resolveInst(inst_data.operand);
return sema.analyzeErrUnionCodePtr(block, src, operand);
}
@@ -9302,11 +8761,12 @@ fn checkCallConvSupportsVarArgs(sema: *Sema, block: *Block, src: LazySrcLoc, cc:
}
}
-fn checkParamTypeCommon(
+fn checkParamType(
sema: *Sema,
block: *Block,
param_idx: u32,
param_ty: Type,
+ param_is_comptime: bool,
param_is_noalias: bool,
param_src: LazySrcLoc,
cc: std.builtin.CallingConvention,
@@ -9321,29 +8781,22 @@ fn checkParamTypeCommon(
opaque_str, param_ty.fmt(pt),
});
}
- if (!param_ty.isGenericPoison() and
- !target_util.fnCallConvAllowsZigTypes(cc) and
- !try sema.validateExternType(param_ty, .param_ty))
- {
- return sema.failWithOwnedErrorMsg(block, msg: {
- const msg = try sema.errMsg(param_src, "parameter of type '{f}' not allowed in function with calling convention '{s}'", .{
- param_ty.fmt(pt), @tagName(cc),
- });
- errdefer msg.destroy(sema.gpa);
-
- try sema.explainWhyTypeIsNotExtern(msg, param_src, param_ty, .param_ty);
-
- try sema.addDeclaredHereNote(msg, param_ty);
- break :msg msg;
- });
+ if (!target_util.fnCallConvAllowsZigTypes(cc)) {
+ if (param_is_comptime) {
+ return sema.fail(block, param_src, "comptime parameters not allowed in function with calling convention '{t}'", .{cc});
+ }
+ if (param_ty.isGenericPoison()) {
+ return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{t}'", .{cc});
+ }
+ // The `validateExtern` check happens later, in `validateResolvedFuncType`.
}
switch (cc) {
.x86_64_interrupt, .x86_interrupt => {
const err_code_size = target.ptrBitWidth();
switch (param_idx) {
- 0 => if (param_ty.zigTypeTag(zcu) != .pointer) return sema.fail(block, param_src, "first parameter of function with '{s}' calling convention must be a pointer type", .{@tagName(cc)}),
- 1 => if (param_ty.bitSize(zcu) != err_code_size) return sema.fail(block, param_src, "second parameter of function with '{s}' calling convention must be a {d}-bit integer", .{ @tagName(cc), err_code_size }),
- else => return sema.fail(block, param_src, "'{s}' calling convention supports up to 2 parameters, found {d}", .{ @tagName(cc), param_idx + 1 }),
+ 0 => if (param_ty.zigTypeTag(zcu) != .pointer) return sema.fail(block, param_src, "first parameter of function with '{t}' calling convention must be a pointer type", .{cc}),
+ 1 => if (param_ty.bitSize(zcu) != err_code_size) return sema.fail(block, param_src, "second parameter of function with '{t}' calling convention must be a {d}-bit integer", .{ cc, err_code_size }),
+ else => return sema.fail(block, param_src, "'{t}' calling convention supports up to 2 parameters, found {d}", .{ cc, param_idx + 1 }),
}
},
.arc_interrupt,
@@ -9359,7 +8812,7 @@ fn checkParamTypeCommon(
.m68k_interrupt,
.msp430_interrupt,
.avr_signal,
- => return sema.fail(block, param_src, "parameters are not allowed with '{s}' calling convention", .{@tagName(cc)}),
+ => return sema.fail(block, param_src, "parameters are not allowed with '{t}' calling convention", .{cc}),
else => {},
}
if (param_is_noalias and !param_ty.isGenericPoison() and !param_ty.isPtrAtRuntime(zcu) and !param_ty.isSliceAtRuntime(zcu)) {
@@ -9367,7 +8820,7 @@ fn checkParamTypeCommon(
}
}
-fn checkReturnTypeAndCallConvCommon(
+fn checkReturnTypeAndCallConv(
sema: *Sema,
block: *Block,
bare_ret_ty: Type,
@@ -9381,7 +8834,6 @@ fn checkReturnTypeAndCallConvCommon(
) CompileError!void {
const pt = sema.pt;
const zcu = pt.zcu;
- const gpa = zcu.gpa;
if (opt_varargs_src) |varargs_src| {
try sema.checkCallConvSupportsVarArgs(block, varargs_src, @"callconv");
}
@@ -9395,21 +8847,14 @@ fn checkReturnTypeAndCallConvCommon(
opaque_str, ies_ret_ty_prefix, bare_ret_ty.fmt(pt),
});
}
- if (!bare_ret_ty.isGenericPoison() and
- !target_util.fnCallConvAllowsZigTypes(@"callconv") and
- (inferred_error_set or !try sema.validateExternType(bare_ret_ty, .ret_ty)))
- {
- return sema.failWithOwnedErrorMsg(block, msg: {
- const msg = try sema.errMsg(ret_ty_src, "return type '{s}{f}' not allowed in function with calling convention '{s}'", .{
- ies_ret_ty_prefix, bare_ret_ty.fmt(pt), @tagName(@"callconv"),
- });
- errdefer msg.destroy(gpa);
- if (!inferred_error_set) {
- try sema.explainWhyTypeIsNotExtern(msg, ret_ty_src, bare_ret_ty, .ret_ty);
- try sema.addDeclaredHereNote(msg, bare_ret_ty);
- }
- break :msg msg;
- });
+ if (!target_util.fnCallConvAllowsZigTypes(@"callconv")) {
+ if (inferred_error_set) {
+ return sema.fail(block, ret_ty_src, "return type '!{f}' not allowed in function with calling convention '{t}'", .{ bare_ret_ty.fmt(pt), @"callconv" });
+ }
+ if (bare_ret_ty.isGenericPoison()) {
+ return sema.fail(block, ret_ty_src, "generic return type not allowed in function with calling convention '{t}'", .{@"callconv"});
+ }
+ // The `validateExtern` check happens later, in `validateResolvedFuncType`.
}
validate_incoming_stack_align: {
const a: u64 = switch (@"callconv") {
@@ -9444,7 +8889,7 @@ fn checkReturnTypeAndCallConvCommon(
else => false,
};
if (!ret_ok) {
- return sema.fail(block, ret_ty_src, "function with calling convention '{s}' must return 'void' or 'noreturn'", .{@tagName(@"callconv")});
+ return sema.fail(block, ret_ty_src, "function with calling convention '{t}' must return 'void' or 'noreturn'", .{@"callconv"});
}
},
.@"inline" => if (is_noinline) {
@@ -9465,18 +8910,76 @@ fn checkReturnTypeAndCallConvCommon(
}
}
};
- return sema.fail(block, callconv_src, "calling convention '{s}' only available on architectures {f}", .{
- @tagName(@"callconv"),
- ArchListFormatter{ .archs = allowed_archs },
+ return sema.fail(block, callconv_src, "calling convention '{t}' only available on architectures {f}", .{
+ @"callconv", ArchListFormatter{ .archs = allowed_archs },
});
},
- .bad_backend => |bad_backend| return sema.fail(block, callconv_src, "calling convention '{s}' not supported by compiler backend '{s}'", .{
- @tagName(@"callconv"),
- @tagName(bad_backend),
+ .bad_backend => |bad_backend| return sema.fail(block, callconv_src, "calling convention '{t}' not supported by compiler backend '{t}'", .{
+ @"callconv", bad_backend,
}),
}
}
+/// To avoid forcing type layout resolution too quickly, some validation of function types cannot be
+/// performed when the type is first constructed, and instead must happen when either (a) a function
+/// with that type is declared, or (b) a function with that type is called. That validation is
+/// handled here.
+///
+/// Asserts that all parameter types and return types have their layout fully resolved.
+fn validateResolvedFuncType(
+ sema: *Sema,
+ block: *Block,
+ @"callconv": std.builtin.CallingConvention,
+ param_types: []const InternPool.Index,
+ ret_ty: Type,
+ src: LazySrcLoc,
+ maybe_func_decl_inst: ?InternPool.TrackedInst.Index,
+) SemaError!void {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
+ const gpa = zcu.comp.gpa;
+ if (!target_util.fnCallConvAllowsZigTypes(@"callconv")) {
+ // Check that all parameter types are extern-compatible.
+ for (param_types, 0..) |param_ty_ip, param_index| {
+ const param_ty: Type = .fromInterned(param_ty_ip);
+ if (!param_ty.validateExtern(.param_ty, zcu)) {
+ const param_src: LazySrcLoc = if (maybe_func_decl_inst) |inst| .{
+ .base_node_inst = inst,
+ .offset = .{ .fn_proto_param = .{
+ .fn_proto_node_offset = .zero,
+ .param_index = @intCast(param_index),
+ } },
+ } else src;
+ return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(param_src, "parameter of type '{f}' not allowed in function with calling convention '{t}'", .{
+ param_ty.fmt(pt), @"callconv",
+ });
+ errdefer msg.destroy(gpa);
+ try sema.explainWhyTypeIsNotExtern(msg, param_src, param_ty, .param_ty);
+ try sema.addDeclaredHereNote(msg, param_ty);
+ break :msg msg;
+ });
+ }
+ }
+ // Check that the return type is extern-compatible.
+ if (!ret_ty.validateExtern(.ret_ty, zcu)) {
+ const ret_ty_src: LazySrcLoc = if (maybe_func_decl_inst) |inst| .{
+ .base_node_inst = inst,
+ .offset = .{ .node_offset_fn_type_ret_ty = .zero },
+ } else src;
+ return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(ret_ty_src, "return type '{f}' not allowed in function with calling convention '{t}'", .{
+ ret_ty.fmt(pt), @"callconv",
+ });
+ errdefer msg.destroy(gpa);
+ try sema.explainWhyTypeIsNotExtern(msg, ret_ty_src, ret_ty, .ret_ty);
+ try sema.addDeclaredHereNote(msg, ret_ty);
+ break :msg msg;
+ });
+ }
+ }
+}
+
fn callConvIsCallable(cc: std.builtin.CallingConvention.Tag) bool {
return switch (cc) {
.naked,
@@ -9569,12 +9072,9 @@ fn funcCommon(
const io = comp.io;
const ip = &zcu.intern_pool;
+ const src = block.nodeOffset(src_node_offset);
const ret_ty_src = block.src(.{ .node_offset_fn_type_ret_ty = src_node_offset });
const cc_src = block.src(.{ .node_offset_fn_type_cc = src_node_offset });
- const func_src = block.nodeOffset(src_node_offset);
-
- const ret_ty_requires_comptime = try bare_return_type.comptimeOnlySema(pt);
- var is_generic = bare_return_type.isGenericPoison() or ret_ty_requires_comptime;
var comptime_bits: u32 = 0;
for (block.params.items(.ty), block.params.items(.is_comptime), 0..) |param_ty_ip, param_is_comptime, i| {
@@ -9587,49 +9087,21 @@ fn funcCommon(
.fn_proto_node_offset = src_node_offset,
.param_index = @intCast(i),
} });
- const param_ty_comptime = try param_ty.comptimeOnlySema(pt);
- const param_ty_generic = param_ty.isGenericPoison();
- if (param_is_comptime or param_ty_comptime or param_ty_generic) {
- is_generic = true;
- }
if (param_is_comptime) {
comptime_bits |= @as(u32, 1) << @intCast(i); // TODO: handle cast error
}
- if (param_is_comptime and !target_util.fnCallConvAllowsZigTypes(cc)) {
- return sema.fail(block, param_src, "comptime parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});
- }
- if (param_ty_generic and !target_util.fnCallConvAllowsZigTypes(cc)) {
- return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});
- }
- try sema.checkParamTypeCommon(
+ try sema.checkParamType(
block,
@intCast(i),
param_ty,
+ param_is_comptime,
is_noalias,
param_src,
cc,
);
- if (param_ty_comptime and !param_is_comptime and has_body and !block.isComptime()) {
- const msg = msg: {
- const msg = try sema.errMsg(param_src, "parameter of type '{f}' must be declared comptime", .{
- param_ty.fmt(pt),
- });
- errdefer msg.destroy(sema.gpa);
-
- try sema.explainWhyTypeIsComptime(msg, param_src, param_ty);
-
- try sema.addDeclaredHereNote(msg, param_ty);
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(block, msg);
- }
- }
-
- if (var_args and is_generic) {
- return sema.fail(block, func_src, "generic function cannot be variadic", .{});
}
- try sema.checkReturnTypeAndCallConvCommon(
+ try sema.checkReturnTypeAndCallConv(
block,
bare_return_type,
ret_ty_src,
@@ -9643,48 +9115,28 @@ fn funcCommon(
is_noinline,
);
- // If the return type is comptime-only but not dependent on parameters then
- // all parameter types also need to be comptime.
- if (has_body and ret_ty_requires_comptime and !block.isComptime()) comptime_check: {
- for (block.params.items(.is_comptime)) |is_comptime| {
- if (!is_comptime) break;
- } else break :comptime_check;
- const ies_ret_ty_prefix: []const u8 = if (inferred_error_set) "!" else "";
- const msg = try sema.errMsg(
- ret_ty_src,
- "function with comptime-only return type '{s}{f}' requires all parameters to be comptime",
- .{ ies_ret_ty_prefix, bare_return_type.fmt(pt) },
- );
- errdefer msg.destroy(sema.gpa);
- try sema.explainWhyTypeIsComptime(msg, ret_ty_src, bare_return_type);
-
- const tags = sema.code.instructions.items(.tag);
- const data = sema.code.instructions.items(.data);
- const param_body = sema.code.getParamBody(func_inst);
- for (
- block.params.items(.is_comptime),
- block.params.items(.name),
- param_body[0..block.params.len],
- ) |is_comptime, name_nts, param_index| {
- if (!is_comptime) {
- const param_src = block.tokenOffset(switch (tags[@intFromEnum(param_index)]) {
- .param => data[@intFromEnum(param_index)].pl_tok.src_tok,
- .param_anytype => data[@intFromEnum(param_index)].str_tok.src_tok,
- else => unreachable,
- });
- const name = sema.code.nullTerminatedString(name_nts);
- if (name.len != 0) {
- try sema.errNote(param_src, msg, "param '{s}' is required to be comptime", .{name});
- } else {
- try sema.errNote(param_src, msg, "param is required to be comptime", .{});
- }
- }
- }
- return sema.failWithOwnedErrorMsg(block, msg);
- }
-
const param_types = block.params.items(.ty);
+ if (has_body) {
+ for (param_types, 0..) |param_ty_ip, param_index| {
+ const param_ty: Type = .fromInterned(param_ty_ip);
+ const param_src = block.src(.{ .fn_proto_param = .{
+ .fn_proto_node_offset = src_node_offset,
+ .param_index = @intCast(param_index),
+ } });
+ try sema.ensureLayoutResolved(param_ty, param_src, .parameter);
+ }
+ try sema.ensureLayoutResolved(bare_return_type, ret_ty_src, .return_type);
+ try sema.validateResolvedFuncType(
+ block,
+ cc,
+ param_types,
+ bare_return_type,
+ src,
+ ip.getNav(sema.owner.unwrap().nav_val).srcInst(ip),
+ );
+ }
+
if (inferred_error_set) {
assert(has_body);
return .fromIntern(try ip.getFuncDeclIes(gpa, io, pt.tid, .{
@@ -9696,7 +9148,6 @@ fn funcCommon(
.bare_return_type = bare_return_type.toIntern(),
.cc = cc,
.is_var_args = var_args,
- .is_generic = is_generic,
.is_noinline = is_noinline,
.zir_body_inst = try block.trackZir(func_inst),
@@ -9714,7 +9165,6 @@ fn funcCommon(
.return_type = bare_return_type.toIntern(),
.cc = cc,
.is_var_args = var_args,
- .is_generic = is_generic,
.is_noinline = is_noinline,
});
@@ -9756,7 +9206,7 @@ fn zirParam(
}
const param_ty_inst = try sema.resolveInlineBody(block, body, inst);
- break :ty try sema.analyzeAsType(block, src, param_ty_inst);
+ break :ty try sema.analyzeAsType(block, src, .fn_param_types, param_ty_inst);
};
try block.params.append(sema.arena, .{
@@ -9812,7 +9262,7 @@ fn analyzeAs(
) CompileError!Air.Inst.Ref {
const pt = sema.pt;
const zcu = pt.zcu;
- const operand = try sema.resolveInst(zir_operand);
+ const operand = sema.resolveInst(zir_operand);
const dest_ty = try sema.resolveTypeOrPoison(block, src, zir_dest_type) orelse return operand;
switch (dest_ty.zigTypeTag(zcu)) {
.@"opaque" => return sema.fail(block, src, "cannot cast to opaque type '{f}'", .{dest_ty.fmt(pt)}),
@@ -9838,32 +9288,23 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
const zcu = pt.zcu;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const ptr_src = block.builtinCallArgSrc(inst_data.src_node, 0);
- const operand = try sema.resolveInst(inst_data.operand);
+ const operand = sema.resolveInst(inst_data.operand);
const operand_ty = sema.typeOf(operand);
const ptr_ty = operand_ty.scalarType(zcu);
const is_vector = operand_ty.zigTypeTag(zcu) == .vector;
if (!ptr_ty.isPtrAtRuntime(zcu)) {
return sema.fail(block, ptr_src, "expected pointer, found '{f}'", .{ptr_ty.fmt(pt)});
}
- const pointee_ty = ptr_ty.childType(zcu);
- if (try ptr_ty.comptimeOnlySema(pt)) {
- const msg = msg: {
- const msg = try sema.errMsg(ptr_src, "comptime-only type '{f}' has no pointer address", .{pointee_ty.fmt(pt)});
- errdefer msg.destroy(sema.gpa);
- try sema.explainWhyTypeIsComptime(msg, ptr_src, pointee_ty);
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(block, msg);
- }
+
const len = if (is_vector) operand_ty.vectorLen(zcu) else undefined;
const dest_ty: Type = if (is_vector) try pt.vectorType(.{ .child = .usize_type, .len = len }) else .usize;
- if (try sema.resolveValue(operand)) |operand_val| ct: {
+ if (sema.resolveValue(operand)) |operand_val| ct: {
if (!is_vector) {
if (operand_val.isUndef(zcu)) {
return .undef_usize;
}
- const addr = try operand_val.getUnsignedIntSema(pt) orelse {
+ const addr = operand_val.getUnsignedInt(zcu) orelse {
// Wasn't an integer pointer. This is a runtime operation.
break :ct;
};
@@ -9879,7 +9320,7 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
new_elem.* = .undef_usize;
continue;
}
- const addr = try ptr_val.getUnsignedIntSema(pt) orelse {
+ const addr = ptr_val.getUnsignedInt(zcu) orelse {
// A vector element wasn't an integer pointer. This is a runtime operation.
break :ct;
};
@@ -9917,7 +9358,7 @@ fn zirFieldPtrLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
sema.code.nullTerminatedString(extra.field_name_start),
.no_embedded_nulls,
);
- const object_ptr = try sema.resolveInst(extra.lhs);
+ const object_ptr = sema.resolveInst(extra.lhs);
return fieldPtrLoad(sema, block, src, object_ptr, field_name, field_name_src);
}
@@ -9942,7 +9383,7 @@ fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
sema.code.nullTerminatedString(extra.field_name_start),
.no_embedded_nulls,
);
- const object_ptr = try sema.resolveInst(extra.lhs);
+ const object_ptr = sema.resolveInst(extra.lhs);
return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, false);
}
@@ -9967,7 +9408,7 @@ fn zirStructInitFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi
sema.code.nullTerminatedString(extra.field_name_start),
.no_embedded_nulls,
);
- const object_ptr = try sema.resolveInst(extra.lhs);
+ const object_ptr = sema.resolveInst(extra.lhs);
const struct_ty = sema.typeOf(object_ptr).childType(zcu);
switch (struct_ty.zigTypeTag(zcu)) {
.@"struct", .@"union" => {
@@ -9987,7 +9428,7 @@ fn zirFieldPtrNamedLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil
const src = block.nodeOffset(inst_data.src_node);
const field_name_src = block.builtinCallArgSrc(inst_data.src_node, 1);
const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data;
- const object_ptr = try sema.resolveInst(extra.lhs);
+ const object_ptr = sema.resolveInst(extra.lhs);
const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.field_name, .{ .simple = .field_name });
return fieldPtrLoad(sema, block, src, object_ptr, field_name, field_name_src);
}
@@ -10000,7 +9441,7 @@ fn zirFieldPtrNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
const src = block.nodeOffset(inst_data.src_node);
const field_name_src = block.builtinCallArgSrc(inst_data.src_node, 1);
const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data;
- const object_ptr = try sema.resolveInst(extra.lhs);
+ const object_ptr = sema.resolveInst(extra.lhs);
const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.field_name, .{ .simple = .field_name });
return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, false);
}
@@ -10015,7 +9456,7 @@ fn zirIntCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
const dest_ty = try sema.resolveDestType(block, src, extra.lhs, .remove_eu_opt, "@intCast");
- const operand = try sema.resolveInst(extra.rhs);
+ const operand = sema.resolveInst(extra.rhs);
return sema.intCast(block, block.nodeOffset(inst_data.src_node), dest_ty, src, operand, operand_src);
}
@@ -10044,7 +9485,7 @@ fn intCast(
try sema.checkVectorizableBinaryOperands(block, operand_src, dest_ty, operand_ty, dest_ty_src, operand_src);
const is_vector = dest_ty.zigTypeTag(zcu) == .vector;
- if ((try sema.typeHasOnePossibleValue(dest_ty))) |opv| {
+ if (try dest_ty.onePossibleValue(pt)) |opv| {
// requirement: intCast(u0, input) iff input == 0
if (block.wantSafety()) {
try sema.requireRuntimeBlock(block, src, operand_src);
@@ -10090,7 +9531,7 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
const dest_ty = try sema.resolveDestType(block, src, extra.lhs, .remove_eu_opt, "@bitCast");
- const operand = try sema.resolveInst(extra.rhs);
+ const operand = sema.resolveInst(extra.rhs);
const operand_ty = sema.typeOf(operand);
switch (dest_ty.zigTypeTag(zcu)) {
.@"anyframe",
@@ -10258,7 +9699,7 @@ fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
const dest_ty = try sema.resolveDestType(block, src, extra.lhs, .remove_eu_opt, "@floatCast");
const dest_scalar_ty = dest_ty.scalarType(zcu);
- const operand = try sema.resolveInst(extra.rhs);
+ const operand = sema.resolveInst(extra.rhs);
const operand_ty = sema.typeOf(operand);
const operand_scalar_ty = operand_ty.scalarType(zcu);
@@ -10287,7 +9728,7 @@ fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
),
}
- if (try sema.resolveValue(operand)) |operand_val| {
+ if (sema.resolveValue(operand)) |operand_val| {
if (!is_vector) {
return Air.internedToRef((try operand_val.floatCast(dest_ty, pt)).toIntern());
}
@@ -10319,8 +9760,8 @@ fn zirElemVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const src = block.nodeOffset(inst_data.src_node);
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
- const array = try sema.resolveInst(extra.lhs);
- const elem_index = try sema.resolveInst(extra.rhs);
+ const array = sema.resolveInst(extra.lhs);
+ const elem_index = sema.resolveInst(extra.rhs);
return sema.elemVal(block, src, array, elem_index, src, false);
}
@@ -10332,8 +9773,8 @@ fn zirElemPtrLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
const src = block.nodeOffset(inst_data.src_node);
const elem_index_src = block.src(.{ .node_offset_array_access_index = inst_data.src_node });
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
- const array_ptr = try sema.resolveInst(extra.lhs);
- const uncoerced_elem_index = try sema.resolveInst(extra.rhs);
+ const array_ptr = sema.resolveInst(extra.lhs);
+ const uncoerced_elem_index = sema.resolveInst(extra.rhs);
if (try sema.resolveDefinedValue(block, src, array_ptr)) |array_ptr_val| {
const array_ptr_ty = sema.typeOf(array_ptr);
if (try sema.pointerDeref(block, src, array_ptr_val, array_ptr_ty)) |array_val| {
@@ -10351,7 +9792,7 @@ fn zirElemValImm(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
defer tracy.end();
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].elem_val_imm;
- const array = try sema.resolveInst(inst_data.operand);
+ const array = sema.resolveInst(inst_data.operand);
const elem_index = try sema.pt.intRef(.usize, inst_data.idx);
return sema.elemVal(block, LazySrcLoc.unneeded, array, elem_index, LazySrcLoc.unneeded, false);
}
@@ -10365,8 +9806,8 @@ fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const src = block.nodeOffset(inst_data.src_node);
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
- const array_ptr = try sema.resolveInst(extra.lhs);
- const elem_index = try sema.resolveInst(extra.rhs);
+ const array_ptr = sema.resolveInst(extra.lhs);
+ const elem_index = sema.resolveInst(extra.rhs);
const indexable_ty = sema.typeOf(array_ptr);
if (indexable_ty.zigTypeTag(zcu) != .pointer) {
const capture_src = block.src(.{ .for_capture_from_input = inst_data.src_node });
@@ -10382,6 +9823,8 @@ fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
};
return sema.failWithOwnedErrorMsg(block, msg);
}
+ try sema.checkIndexable(block, src, indexable_ty);
+ try sema.ensureLayoutResolved(indexable_ty.childType(zcu), src, .ptr_access);
return sema.elemPtrOneLayerOnly(block, src, array_ptr, elem_index, src, false, false);
}
@@ -10393,8 +9836,8 @@ fn zirElemPtrNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
const src = block.nodeOffset(inst_data.src_node);
const elem_index_src = block.src(.{ .node_offset_array_access_index = inst_data.src_node });
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
- const array_ptr = try sema.resolveInst(extra.lhs);
- const uncoerced_elem_index = try sema.resolveInst(extra.rhs);
+ const array_ptr = sema.resolveInst(extra.lhs);
+ const uncoerced_elem_index = sema.resolveInst(extra.rhs);
const elem_index = try sema.coerce(block, .usize, uncoerced_elem_index, elem_index_src);
return sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src, false, true);
}
@@ -10408,7 +9851,7 @@ fn zirArrayInitElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compile
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const src = block.nodeOffset(inst_data.src_node);
const extra = sema.code.extraData(Zir.Inst.ElemPtrImm, inst_data.payload_index).data;
- const array_ptr = try sema.resolveInst(extra.ptr);
+ const array_ptr = sema.resolveInst(extra.ptr);
const elem_index = try pt.intRef(.usize, extra.index);
const array_ty = sema.typeOf(array_ptr).childType(zcu);
switch (array_ty.zigTypeTag(zcu)) {
@@ -10427,8 +9870,8 @@ fn zirSliceStart(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const src = block.nodeOffset(inst_data.src_node);
const extra = sema.code.extraData(Zir.Inst.SliceStart, inst_data.payload_index).data;
- const array_ptr = try sema.resolveInst(extra.lhs);
- const start = try sema.resolveInst(extra.start);
+ const array_ptr = sema.resolveInst(extra.lhs);
+ const start = sema.resolveInst(extra.start);
const ptr_src = block.src(.{ .node_offset_slice_ptr = inst_data.src_node });
const start_src = block.src(.{ .node_offset_slice_start = inst_data.src_node });
const end_src = block.src(.{ .node_offset_slice_end = inst_data.src_node });
@@ -10443,9 +9886,9 @@ fn zirSliceEnd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const src = block.nodeOffset(inst_data.src_node);
const extra = sema.code.extraData(Zir.Inst.SliceEnd, inst_data.payload_index).data;
- const array_ptr = try sema.resolveInst(extra.lhs);
- const start = try sema.resolveInst(extra.start);
- const end = try sema.resolveInst(extra.end);
+ const array_ptr = sema.resolveInst(extra.lhs);
+ const start = sema.resolveInst(extra.start);
+ const end = sema.resolveInst(extra.end);
const ptr_src = block.src(.{ .node_offset_slice_ptr = inst_data.src_node });
const start_src = block.src(.{ .node_offset_slice_start = inst_data.src_node });
const end_src = block.src(.{ .node_offset_slice_end = inst_data.src_node });
@@ -10461,10 +9904,10 @@ fn zirSliceSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
const src = block.nodeOffset(inst_data.src_node);
const sentinel_src = block.src(.{ .node_offset_slice_sentinel = inst_data.src_node });
const extra = sema.code.extraData(Zir.Inst.SliceSentinel, inst_data.payload_index).data;
- const array_ptr = try sema.resolveInst(extra.lhs);
- const start = try sema.resolveInst(extra.start);
- const end: Air.Inst.Ref = if (extra.end == .none) .none else try sema.resolveInst(extra.end);
- const sentinel = try sema.resolveInst(extra.sentinel);
+ const array_ptr = sema.resolveInst(extra.lhs);
+ const start = sema.resolveInst(extra.start);
+ const end: Air.Inst.Ref = if (extra.end == .none) .none else sema.resolveInst(extra.end);
+ const sentinel = sema.resolveInst(extra.sentinel);
const ptr_src = block.src(.{ .node_offset_slice_ptr = inst_data.src_node });
const start_src = block.src(.{ .node_offset_slice_start = inst_data.src_node });
const end_src = block.src(.{ .node_offset_slice_end = inst_data.src_node });
@@ -10479,10 +9922,10 @@ fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const src = block.nodeOffset(inst_data.src_node);
const extra = sema.code.extraData(Zir.Inst.SliceLength, inst_data.payload_index).data;
- const array_ptr = try sema.resolveInst(extra.lhs);
- const start = try sema.resolveInst(extra.start);
- const len = try sema.resolveInst(extra.len);
- const sentinel = if (extra.sentinel == .none) .none else try sema.resolveInst(extra.sentinel);
+ const array_ptr = sema.resolveInst(extra.lhs);
+ const start = sema.resolveInst(extra.start);
+ const len = sema.resolveInst(extra.len);
+ const sentinel = if (extra.sentinel == .none) .none else sema.resolveInst(extra.sentinel);
const ptr_src = block.src(.{ .node_offset_slice_ptr = inst_data.src_node });
const start_src = block.src(.{ .node_offset_slice_start = extra.start_src_node_offset });
const end_src = block.src(.{ .node_offset_slice_end = inst_data.src_node });
@@ -10510,7 +9953,7 @@ fn zirSliceSentinelTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
// This is like the logic in `analyzeSlice`; since we've evaluated the LHS as an lvalue, we will
// have a double pointer if it was already a pointer.
- const lhs_ptr_ty = sema.typeOf(try sema.resolveInst(inst_data.operand));
+ const lhs_ptr_ty = sema.typeOf(sema.resolveInst(inst_data.operand));
const lhs_ty = switch (lhs_ptr_ty.zigTypeTag(zcu)) {
.pointer => lhs_ptr_ty.childType(zcu),
else => return sema.fail(block, ptr_src, "expected pointer, found '{f}'", .{lhs_ptr_ty.fmt(pt)}),
@@ -10557,9 +10000,9 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp
var label: Block.Label = .{
.zir_block = inst,
.merges = .{
- .src_locs = .{},
- .results = .{},
- .br_list = .{},
+ .src_locs = .empty,
+ .results = .empty,
+ .br_list = .empty,
.block_inst = block_inst,
},
};
@@ -10590,12 +10033,14 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp
// Lastly, we analyze the error prong(s) as a regular switch.
const raw_switch_operand, const non_err_cond, const non_err_hint = non_err: {
- const eu_maybe_ptr = try sema.resolveInst(zir_switch.main_operand);
+ const eu_maybe_ptr = sema.resolveInst(zir_switch.main_operand);
const err_union_ty: Type = err_union_ty: {
const raw_operand_ty = sema.typeOf(eu_maybe_ptr);
if (!non_err_case.operand_is_ref) break :err_union_ty raw_operand_ty;
try sema.checkPtrOperand(block, operand_src, raw_operand_ty);
- break :err_union_ty raw_operand_ty.childType(zcu);
+ const child_ty = raw_operand_ty.childType(zcu);
+ try sema.ensureLayoutResolved(child_ty, operand_src, .ptr_access);
+ break :err_union_ty child_ty;
};
if (err_union_ty.zigTypeTag(zcu) != .error_union) {
return sema.fail(block, operand_src, "expected error union type, found '{f}'", .{
@@ -10711,9 +10156,9 @@ fn zirSwitchBlock(
var label: Block.Label = .{
.zir_block = inst,
.merges = .{
- .src_locs = .{},
- .results = .{},
- .br_list = .{},
+ .src_locs = .empty,
+ .results = .empty,
+ .br_list = .empty,
.block_inst = block_inst,
},
};
@@ -10723,7 +10168,7 @@ fn zirSwitchBlock(
defer child_block.instructions.deinit(sema.gpa);
defer merges.deinit(sema.gpa);
- const raw_operand = try sema.resolveInst(zir_switch.main_operand);
+ const raw_operand = sema.resolveInst(zir_switch.main_operand);
const validated_switch = try sema.validateSwitchBlock(block, raw_operand, operand_is_ref, inst, &zir_switch);
const maybe_ref = try sema.analyzeSwitchBlock(block, &child_block, raw_operand, operand_is_ref, merges, inst, &zir_switch, &validated_switch);
return maybe_ref orelse {
@@ -10764,18 +10209,19 @@ fn analyzeSwitchBlock(
.{ raw_operand, .none };
const operand_ty = sema.typeOf(val);
- const maybe_operand_opv = try sema.typeHasOnePossibleValue(operand_ty);
+ operand_ty.assertHasLayout(zcu);
+ const maybe_operand_opv = try operand_ty.onePossibleValue(pt);
const init_cond: Air.Inst.Ref, const item_ty: Type = switch (operand_ty.zigTypeTag(zcu)) {
.@"union" => tag: {
- const tag_ty = operand_ty.unionTagType(zcu).?;
- const tag_val = try sema.unionToTag(block, tag_ty, val, operand_src);
- break :tag .{ tag_val, tag_ty };
+ const tag_val = try sema.unionToTag(block, val);
+ break :tag .{ tag_val, sema.typeOf(tag_val) };
},
else => .{
if (maybe_operand_opv) |operand_opv| .fromValue(operand_opv) else val,
operand_ty,
},
};
+ item_ty.assertHasLayout(zcu);
if (zir_switch.has_continue and !block.isComptime()) {
const operand_alloc: Air.Inst.Ref = if (zir_switch.any_maybe_runtime_capture and
@@ -10849,7 +10295,7 @@ fn analyzeSwitchBlock(
if (extra.block_inst != switch_inst) return error.ComptimeBreak;
// This is a `switch_continue` targeting this block. Change the operand and start over.
const new_operand_src = child_block.nodeOffset(extra.operand_src_node.unwrap().?);
- const new_operand_uncoerced = try sema.resolveInst(break_inst.data.@"break".operand);
+ const new_operand_uncoerced = sema.resolveInst(break_inst.data.@"break".operand);
const new_operand = try sema.coerce(child_block, raw_operand_ty, new_operand_uncoerced, new_operand_src);
try sema.emitBackwardBranch(child_block, src);
@@ -10860,7 +10306,7 @@ fn analyzeSwitchBlock(
.{ new_operand, .none };
const new_cond_ref = if (union_originally)
- try sema.unionToTag(child_block, item_ty, new_val, src)
+ try sema.unionToTag(child_block, new_val)
else
new_val;
@@ -10881,7 +10327,7 @@ fn analyzeSwitchBlock(
unreachable;
}
- if (try sema.typeHasOnePossibleValue(item_ty)) |item_opv| {
+ if (try item_ty.onePossibleValue(pt)) |item_opv| {
// We simplify conditions with OPV to either a `loop` or a `block` since
// we cannot switch on a value which doesn't exist at runtime.
assert(operand == .loop); // `simple` should have already been comptime-resolved above!
@@ -10912,7 +10358,7 @@ fn analyzeSwitchBlock(
assert(case.range_infos.len == 0);
for (case.item_infos, item_refs) |item_info, item_ref| {
if (item_info.bodyLen()) |body_len| extra_index += body_len;
- if (sema.wantSwitchProngBodyAnalysis(block, item_ref, operand_ty, false, true, prong_info.is_comptime_unreach)) {
+ if (sema.wantSwitchProngBodyAnalysis(item_ref, operand_ty, false, true, prong_info.is_comptime_unreach)) {
break :skip_case;
}
}
@@ -10928,7 +10374,7 @@ fn analyzeSwitchBlock(
unreachable; // malformed validated switch
};
- const analyze_body = sema.wantSwitchProngBodyAnalysis(block, .fromValue(item_opv), operand_ty, union_originally, err_set, false);
+ const analyze_body = sema.wantSwitchProngBodyAnalysis(.fromValue(item_opv), operand_ty, union_originally, err_set, false);
if (!analyze_body) return .unreachable_value;
if (!(err_set and
@@ -10938,10 +10384,10 @@ fn analyzeSwitchBlock(
const payload_inst: Zir.Inst.Index = if (capture != .none) inst: {
const payload_inst = zir_switch.payload_capture_placeholder.unwrap() orelse switch_inst;
const payload_ref: Air.Inst.Ref = payload_ref: {
- const item_val: InternPool.Index = switch (operand_ty.zigTypeTag(zcu)) {
+ const item_val: Value = switch (operand_ty.zigTypeTag(zcu)) {
.@"union" => item_val: {
if (maybe_operand_opv) |operand_opv| {
- break :item_val zcu.intern_pool.indexToKey(operand_opv.toIntern()).un.val;
+ break :item_val .fromInterned(zcu.intern_pool.indexToKey(operand_opv.toIntern()).un.val);
}
assert(union_originally); // operand type must be union, otherwise it would be an OPV type here
assert(zir_switch.any_maybe_runtime_capture); // there's a payload capture
@@ -10978,10 +10424,10 @@ fn analyzeSwitchBlock(
validated_switch.else_err_ty,
);
},
- else => item_opv.toIntern(),
+ else => item_opv,
};
break :payload_ref switch (capture) {
- .by_val => .fromIntern(item_val),
+ .by_val => .fromValue(item_val),
.by_ref => try sema.uavRef(item_val),
.none => unreachable,
};
@@ -11186,7 +10632,7 @@ fn finishSwitchBr(
if (item_ref == .none) is_under_prong = true;
if (item_info.bodyLen()) |body_len| extra_index += body_len;
- const analyze_body = sema.wantSwitchProngBodyAnalysis(block, item_ref, operand_ty, union_originally, err_set, prong_info.is_comptime_unreach);
+ const analyze_body = sema.wantSwitchProngBodyAnalysis(item_ref, operand_ty, union_originally, err_set, prong_info.is_comptime_unreach);
if (analyze_body) any_analyze_body = true;
if (prong_info.is_inline) {
@@ -11246,11 +10692,11 @@ fn finishSwitchBr(
any_analyze_body = true; // always an integer range, always needs analysis
if (prong_info.is_inline) {
- var item = sema.resolveConstDefinedValue(block, .unneeded, range_ref[0], undefined) catch unreachable;
- const item_last = sema.resolveConstDefinedValue(block, .unneeded, range_ref[1], undefined) catch unreachable;
+ var item = sema.resolveValue(range_ref[0]).?;
+ const item_last = sema.resolveValue(range_ref[1]).?;
- if (try item.getUnsignedIntSema(pt)) |first_int| {
- if (try item_last.getUnsignedIntSema(pt)) |last_int| {
+ if (item.getUnsignedInt(zcu)) |first_int| {
+ if (item_last.getUnsignedInt(zcu)) |last_int| {
if (std.math.cast(u32, last_int - first_int)) |range_len| {
try branch_hints.ensureUnusedCapacity(gpa, range_len);
}
@@ -11259,7 +10705,6 @@ fn finishSwitchBr(
var prev_result_overflowed = false;
while (item.compareScalar(.lte, item_last, operand_ty, zcu)) : ({
- // Previous validation has resolved any possible lazy values.
const int_val: Value, const int_ty: Type = switch (operand_ty.zigTypeTag(zcu)) {
.int => .{ item, operand_ty },
.@"enum" => b: {
@@ -11426,7 +10871,7 @@ fn finishSwitchBr(
const item_ref: Air.Inst.Ref = .fromValue(item_val);
- const analyze_body = sema.wantSwitchProngBodyAnalysis(block, item_ref, operand_ty, union_originally, err_set, false);
+ const analyze_body = sema.wantSwitchProngBodyAnalysis(item_ref, operand_ty, union_originally, err_set, false);
if (emit_bb) try sema.emitBackwardBranch(block, else_prong_src);
emit_bb = true;
@@ -11896,72 +11341,69 @@ fn validateSwitchBlock(
try sema.inst_map.ensureSpaceForInstructions(gpa, &.{tag_capture_inst});
}
- const operand_ty: Type, const item_ty: Type = check_operand: {
- const operand_ty = operand_ty: {
- const raw_operand_ty = sema.typeOf(raw_operand);
- if (operand_is_ref) {
- try sema.checkPtrType(block, operand_src, raw_operand_ty, false);
- break :operand_ty raw_operand_ty.childType(zcu);
- }
- break :operand_ty raw_operand_ty;
- };
-
- const item_ty: Type = item_ty: {
- switch (operand_ty.zigTypeTag(zcu)) {
- .@"enum",
- .error_set,
- .int,
- .comptime_int,
- .type,
- .enum_literal,
- .@"fn",
- .bool,
- .void,
- => break :item_ty operand_ty,
+ const operand_ty = operand_ty: {
+ const raw_operand_ty = sema.typeOf(raw_operand);
+ if (operand_is_ref) {
+ try sema.checkPtrType(block, operand_src, raw_operand_ty, false);
+ const child_ty = raw_operand_ty.childType(zcu);
+ try sema.ensureLayoutResolved(child_ty, operand_src, .ptr_access);
+ break :operand_ty child_ty;
+ }
+ break :operand_ty raw_operand_ty;
+ };
- .@"union" => {
- try operand_ty.resolveFields(pt);
- const enum_ty = operand_ty.unionTagType(zcu) orelse {
- return sema.failWithOwnedErrorMsg(block, msg: {
- const msg = try sema.errMsg(operand_src, "switch on union with no attached enum", .{});
- errdefer msg.destroy(sema.gpa);
- if (operand_ty.srcLocOrNull(zcu)) |union_src| {
- try sema.errNote(union_src, msg, "consider 'union(enum)' here", .{});
- }
- break :msg msg;
- });
- };
- break :item_ty enum_ty;
- },
+ const item_ty: Type = item_ty: {
+ switch (operand_ty.zigTypeTag(zcu)) {
+ .@"enum",
+ .error_set,
+ .int,
+ .comptime_int,
+ .type,
+ .enum_literal,
+ .@"fn",
+ .bool,
+ .void,
+ => break :item_ty operand_ty,
- .pointer => {
- if (!operand_ty.isSlice(zcu)) {
- break :item_ty operand_ty;
- }
- },
+ .@"union" => {
+ const enum_ty = operand_ty.unionTagType(zcu) orelse {
+ return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(operand_src, "switch on union with no attached enum", .{});
+ errdefer msg.destroy(sema.gpa);
+ if (operand_ty.srcLocOrNull(zcu)) |union_src| {
+ try sema.errNote(union_src, msg, "consider 'union(enum)' here", .{});
+ }
+ break :msg msg;
+ });
+ };
+ break :item_ty enum_ty;
+ },
- else => {},
- }
- return sema.fail(block, operand_src, "switch on type '{f}'", .{operand_ty.fmt(pt)});
- };
+ .pointer => {
+ if (!operand_ty.isSlice(zcu)) {
+ break :item_ty operand_ty;
+ }
+ },
- if (zir_switch.has_continue and !block.isComptime()) {
- if (try operand_ty.comptimeOnlySema(pt)) {
- // Even if the operand is comptime-known, this `switch` is runtime.
- return sema.failWithOwnedErrorMsg(block, msg: {
- const msg = try sema.errMsg(operand_src, "operand of switch loop has comptime-only type '{f}'", .{operand_ty.fmt(pt)});
- errdefer msg.destroy(gpa);
- try sema.errNote(operand_src, msg, "switch loops are evaluated at runtime outside of comptime scopes", .{});
- try sema.explainWhyTypeIsComptime(msg, operand_src, operand_ty);
- break :msg msg;
- });
- }
- try sema.validateRuntimeValue(block, operand_src, raw_operand);
+ else => {},
}
-
- break :check_operand .{ operand_ty, item_ty };
+ return sema.fail(block, operand_src, "switch on type '{f}'", .{operand_ty.fmt(pt)});
};
+ if (zir_switch.has_continue and !block.isComptime()) {
+ if (operand_ty.comptimeOnly(zcu)) {
+ // Even if the operand is comptime-known, this `switch` is runtime.
+ return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(operand_src, "operand of switch loop has comptime-only type '{f}'", .{operand_ty.fmt(pt)});
+ errdefer msg.destroy(gpa);
+ try sema.errNote(operand_src, msg, "switch loops are evaluated at runtime outside of comptime scopes", .{});
+ try sema.explainWhyTypeIsComptime(msg, operand_src, operand_ty);
+ break :msg msg;
+ });
+ }
+ try sema.validateRuntimeValue(block, operand_src, raw_operand);
+ }
+
const has_else = zir_switch.else_case != null;
const has_under = zir_switch.has_under;
@@ -12305,7 +11747,7 @@ fn resolveSwitchBlock(
child_block: *Block,
operand: SwitchOperand,
raw_operand_ty: Type,
- maybe_lazy_cond_val: Value,
+ cond_val: Value,
merges: *Block.Merges,
switch_inst: Zir.Inst.Index,
zir_switch: *const Zir.UnwrappedSwitchBlock,
@@ -12325,9 +11767,6 @@ fn resolveSwitchBlock(
const err_set = item_ty.zigTypeTag(zcu) == .error_set;
const cond_ref = operand.simple.cond;
- // We have to resolve lazy values to ensure that comparisons with switch
- // prong items don't produce false negatives.
- const cond_val = try sema.resolveLazyValue(maybe_lazy_cond_val);
const case_vals = validated_switch.case_vals;
var case_val_idx: usize = 0;
@@ -12365,7 +11804,7 @@ fn resolveSwitchBlock(
};
continue;
}
- const item_val = sema.resolveConstDefinedValue(child_block, .unneeded, item_ref, undefined) catch unreachable;
+ const item_val = sema.resolveValue(item_ref).?;
if (cond_val.eql(item_val, item_ty, zcu)) {
if (err_set) try sema.maybeErrorUnwrapComptime(child_block, prong_body, cond_ref);
if (union_originally and operand_ty.unionFieldType(item_val, zcu).?.isNoReturn(zcu)) {
@@ -12398,8 +11837,8 @@ fn resolveSwitchBlock(
}
}
for (range_refs) |range_ref| {
- const first_val = sema.resolveConstDefinedValue(child_block, .unneeded, range_ref[0], undefined) catch unreachable;
- const last_val = sema.resolveConstDefinedValue(child_block, .unneeded, range_ref[1], undefined) catch unreachable;
+ const first_val = sema.resolveValue(range_ref[0]).?;
+ const last_val = sema.resolveValue(range_ref[1]).?;
if ((try sema.compareAll(cond_val, .gte, first_val, item_ty)) and
(try sema.compareAll(cond_val, .lte, last_val, item_ty)))
{
@@ -12608,7 +12047,6 @@ fn resolveSwitchProng(
fn wantSwitchProngBodyAnalysis(
sema: *Sema,
- block: *Block,
item_ref: Air.Inst.Ref,
operand_ty: Type,
union_originally: bool,
@@ -12617,16 +12055,14 @@ fn wantSwitchProngBodyAnalysis(
) bool {
const zcu = sema.pt.zcu;
if (union_originally) {
- const unresolved_item_val = sema.resolveConstDefinedValue(block, .unneeded, item_ref, undefined) catch unreachable;
- const item_val = sema.resolveLazyValue(unresolved_item_val) catch unreachable;
+ const item_val = sema.resolveValue(item_ref).?;
const field_ty = operand_ty.unionFieldType(item_val, zcu).?;
if (field_ty.isNoReturn(zcu)) return false;
}
if (err_set and prong_is_comptime_unreach) {
- const unresolved_item_val = sema.resolveConstDefinedValue(block, .unneeded, item_ref, undefined) catch unreachable;
- const item_val = sema.resolveLazyValue(unresolved_item_val) catch unreachable;
+ const item_val = sema.resolveValue(item_ref).?;
const err_name = item_val.getErrorName(zcu).unwrap().?;
- if (!Type.errorSetHasFieldIp(&zcu.intern_pool, operand_ty.toIntern(), err_name)) return false;
+ if (!operand_ty.errorSetHasField(err_name, zcu)) return false;
}
return true;
}
@@ -12772,8 +12208,7 @@ fn analyzeSwitchTagCapture(
.item_refs => |refs| if (refs.len == 1) return refs[0],
.special => {},
}
- const tag_ty = operand_ty.unionTagType(zcu).?;
- return sema.unionToTag(case_block, tag_ty, operand_val, tag_capture_src);
+ return sema.unionToTag(case_block, operand_val);
}
fn analyzeSwitchPayloadCapture(
@@ -12800,14 +12235,14 @@ fn analyzeSwitchPayloadCapture(
const switch_node_offset = operand_src.offset.node_offset_switch_operand;
if (kind == .inline_ref) {
- const item_val = sema.resolveConstDefinedValue(case_block, .unneeded, kind.inline_ref, undefined) catch unreachable;
+ const item_val = sema.resolveValue(kind.inline_ref).?;
if (operand_ty.zigTypeTag(zcu) == .@"union") {
const field_index: u32 = @intCast(operand_ty.unionTagFieldIndex(item_val, zcu).?);
const union_obj = zcu.typeToUnion(operand_ty).?;
const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);
if (capture_by_ref) {
const operand_ptr_info = sema.typeOf(operand_ptr).ptrInfo(zcu);
- const ptr_field_ty = try pt.ptrTypeSema(.{
+ const ptr_field_ty = try pt.ptrType(.{
.child = field_ty.toIntern(),
.flags = .{
.is_const = operand_ptr_info.flags.is_const,
@@ -12821,10 +12256,11 @@ fn analyzeSwitchPayloadCapture(
const tag_and_val = ip.indexToKey(union_val.toIntern()).un;
return .fromIntern(tag_and_val.val);
}
+ if (try field_ty.onePossibleValue(pt)) |opv| return .fromValue(opv);
return case_block.addStructFieldVal(operand_val, field_index, field_ty);
}
} else if (capture_by_ref) {
- return sema.uavRef(item_val.toIntern());
+ return sema.uavRef(item_val);
} else {
return kind.inline_ref;
}
@@ -12850,14 +12286,14 @@ fn analyzeSwitchPayloadCapture(
const case_vals = kind.item_refs;
const union_obj = zcu.typeToUnion(operand_ty).?;
- const first_item_val = sema.resolveConstDefinedValue(case_block, .unneeded, case_vals[0], undefined) catch unreachable;
+ const first_item_val = sema.resolveValue(case_vals[0]).?;
const first_field_index: u32 = zcu.unionTagFieldIndex(union_obj, first_item_val).?;
const first_field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[first_field_index]);
const field_indices = try sema.arena.alloc(u32, case_vals.len);
for (case_vals, field_indices) |item, *field_idx| {
- const item_val = sema.resolveConstDefinedValue(case_block, .unneeded, item, undefined) catch unreachable;
+ const item_val = sema.resolveValue(item).?;
field_idx.* = zcu.unionTagFieldIndex(union_obj, item_val).?;
}
@@ -12906,23 +12342,14 @@ fn analyzeSwitchPayloadCapture(
// By-reference captures have some further restrictions which make them easier to emit
if (capture_by_ref) {
- const operand_ptr_info = sema.typeOf(operand_ptr).ptrInfo(zcu);
+ const operand_ptr_ty = sema.typeOf(operand_ptr);
const capture_ptr_ty = resolve: {
// By-ref captures of hetereogeneous types are only allowed if all field
// pointer types are peer resolvable to each other.
// We need values to run PTR on, so make a bunch of undef constants.
const dummy_captures = try sema.arena.alloc(Air.Inst.Ref, case_vals.len);
- for (field_indices, dummy_captures) |field_idx, *dummy| {
- const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_idx]);
- const field_ptr_ty = try pt.ptrTypeSema(.{
- .child = field_ty.toIntern(),
- .flags = .{
- .is_const = operand_ptr_info.flags.is_const,
- .is_volatile = operand_ptr_info.flags.is_volatile,
- .address_space = operand_ptr_info.flags.address_space,
- .alignment = union_obj.fieldAlign(ip, field_idx),
- },
- });
+ for (field_indices, dummy_captures) |field_index, *dummy| {
+ const field_ptr_ty = try operand_ptr_ty.fieldPtrType(field_index, pt);
dummy.* = try pt.undefRef(field_ptr_ty);
}
const case_srcs = try sema.arena.alloc(?LazySrcLoc, case_vals.len);
@@ -12963,6 +12390,8 @@ fn analyzeSwitchPayloadCapture(
return case_block.addStructFieldPtr(operand_ptr, first_field_index, capture_ptr_ty);
}
+ if (try capture_ty.onePossibleValue(pt)) |opv| return .fromValue(opv);
+
if (try sema.resolveDefinedValue(case_block, operand_src, operand_val)) |operand_val_val| {
if (operand_val_val.isUndef(zcu)) return pt.undefRef(capture_ty);
const union_val = ip.indexToKey(operand_val_val.toIntern()).un;
@@ -13119,7 +12548,7 @@ fn analyzeSwitchPayloadCapture(
try sema.air_instructions.append(sema.gpa, .{
.tag = .get_union_tag,
.data = .{ .ty_op = .{
- .ty = .fromIntern(union_obj.enum_tag_ty),
+ .ty = .fromIntern(union_obj.enum_tag_type),
.operand = operand_val,
} },
});
@@ -13146,7 +12575,7 @@ fn analyzeSwitchPayloadCapture(
const case_vals = kind.item_refs;
if (case_vals.len == 1) {
- const item_val = sema.resolveConstDefinedValue(case_block, .unneeded, case_vals[0], undefined) catch unreachable;
+ const item_val = sema.resolveValue(case_vals[0]).?;
const item_ty = try pt.singleErrorSetType(item_val.getErrorName(zcu).unwrap().?);
return sema.bitCast(case_block, item_ty, .fromValue(item_val), operand_src, null);
}
@@ -13154,7 +12583,7 @@ fn analyzeSwitchPayloadCapture(
var names: InferredErrorSet.NameMap = .{};
try names.ensureUnusedCapacity(sema.arena, case_vals.len);
for (case_vals) |err| {
- const err_val = sema.resolveConstDefinedValue(case_block, .unneeded, err, undefined) catch unreachable;
+ const err_val = sema.resolveValue(err).?;
names.putAssumeCapacityNoClobber(err_val.getErrorName(zcu).unwrap().?, {});
}
const error_ty = try pt.errorSetFromUnsortedNames(names.keys());
@@ -13249,7 +12678,7 @@ fn resolveSwitchItem(
// We allow prongs with errors which are not part of the error set
// being switched on if their prong body is `=> comptime unreachable,`.
switch (try sema.coerceInMemoryAllowedErrorSets(block, item_ty, uncoerced_ty, item_src, item_src)) {
- .ok => if (try sema.resolveValue(uncoerced)) |uncoerced_val| {
+ .ok => if (sema.resolveValue(uncoerced)) |uncoerced_val| {
break :item_ref try sema.coerceInMemory(uncoerced_val, item_ty);
},
.missing_error => if (prong_is_comptime_unreach) {
@@ -13261,17 +12690,8 @@ fn resolveSwitchItem(
}
break :item_ref try sema.coerce(block, item_ty, uncoerced, item_src);
};
- const maybe_lazy = try sema.resolveConstDefinedValue(block, item_src, item_ref, .{ .simple = .switch_item });
-
- // We have to resolve lazy values here to avoid false negatives when detecting
- // duplicate items and comparing items to a comptime-known switch operand.
-
- const val = try sema.resolveLazyValue(maybe_lazy);
- const ref: Air.Inst.Ref = if (val.toIntern() == maybe_lazy.toIntern())
- item_ref
- else
- .fromValue(val);
- return .{ .{ .ref = ref, .val = val }, end };
+ const val = try sema.resolveConstDefinedValue(block, item_src, item_ref, .{ .simple = .switch_item });
+ return .{ .{ .ref = item_ref, .val = val }, end };
}
fn validateSwitchItemOrRange(
@@ -13422,7 +12842,7 @@ fn maybeErrorUnwrap(
},
.panic => {
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
- const msg_inst = try sema.resolveInst(inst_data.operand);
+ const msg_inst = sema.resolveInst(inst_data.operand);
const panic_fn = try getBuiltin(sema, operand_src, .@"panic.call");
const args: [2]Air.Inst.Ref = .{ msg_inst, .null_value };
@@ -13445,7 +12865,7 @@ fn maybeErrorUnwrapCondbr(sema: *Sema, block: *Block, body: []const Zir.Inst.Ind
if (sema.code.instructions.items(.tag)[@intFromEnum(index)] != .is_non_err) return;
const err_inst_data = sema.code.instructions.items(.data)[@intFromEnum(index)].un_node;
- const err_operand = try sema.resolveInst(err_inst_data.operand);
+ const err_operand = sema.resolveInst(err_inst_data.operand);
const operand_ty = sema.typeOf(err_operand);
if (operand_ty.zigTypeTag(zcu) == .error_set) {
try sema.maybeErrorUnwrapComptime(block, body, err_operand);
@@ -13488,7 +12908,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const name_src = block.builtinCallArgSrc(inst_data.src_node, 1);
const ty = try sema.resolveType(block, ty_src, extra.lhs);
const field_name = try sema.resolveConstStringIntern(block, name_src, extra.rhs, .{ .simple = .field_name });
- try ty.resolveFields(pt);
+ try sema.ensureLayoutResolved(ty, ty_src, .field_queried);
const ip = &zcu.intern_pool;
const has_field = hf: {
@@ -13510,7 +12930,8 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
},
.union_type => {
const union_type = ip.loadUnionType(ty.toIntern());
- break :hf union_type.loadTagType(ip).nameIndex(ip, field_name) != null;
+ const enum_type = ip.loadEnumType(union_type.enum_tag_type);
+ break :hf enum_type.nameIndex(ip, field_name) != null;
},
.enum_type => {
break :hf ip.loadEnumType(ty.toIntern()).nameIndex(ip, field_name) != null;
@@ -13568,17 +12989,18 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
const file = zcu.fileByIndex(file_index);
switch (file.getMode()) {
.zig => {
- try pt.ensureFileAnalyzed(file_index);
- const ty = zcu.fileRootType(file_index);
- try sema.declareDependency(.{ .interned = ty });
+ try pt.ensureFilePopulated(file_index);
+ const ty: Type = .fromInterned(zcu.fileRootType(file_index));
try sema.addTypeReferenceEntry(operand_src, ty);
- return Air.internedToRef(ty);
+ // No need for `ensureNamespaceUpToDate`, because `Zcu.PerThread.updateFileNamespace`
+ // already made sure that all root file structs have up-to-date namespaces.
+ return .fromType(ty);
},
.zon => {
const res_ty: InternPool.Index = b: {
if (extra.res_ty == .none) break :b .none;
- const res_ty_inst = try sema.resolveInst(extra.res_ty);
- const res_ty = try sema.analyzeAsType(block, operand_src, res_ty_inst);
+ const res_ty_inst = sema.resolveInst(extra.res_ty);
+ const res_ty = try sema.analyzeAsType(block, operand_src, .type, res_ty_inst);
if (res_ty.isGenericPoison()) break :b .none;
break :b res_ty.toIntern();
};
@@ -13665,8 +13087,8 @@ fn zirShl(
const zcu = pt.zcu;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
- const lhs = try sema.resolveInst(extra.lhs);
- const rhs = try sema.resolveInst(extra.rhs);
+ const lhs = sema.resolveInst(extra.lhs);
+ const rhs = sema.resolveInst(extra.rhs);
const lhs_ty = sema.typeOf(lhs);
const rhs_ty = sema.typeOf(rhs);
@@ -13692,8 +13114,8 @@ fn zirShl(
// we already know `scalar_rhs_ty` is valid for `.shl` -- we only need to validate for `.shl_sat`.
if (air_tag == .shl_sat) _ = try sema.checkIntType(block, rhs_src, scalar_rhs_ty);
- const maybe_lhs_val = try sema.resolveValueResolveLazy(lhs);
- const maybe_rhs_val = try sema.resolveValueResolveLazy(rhs);
+ const maybe_lhs_val = sema.resolveValue(lhs);
+ const maybe_rhs_val = sema.resolveValue(rhs);
const runtime_src = rs: {
if (maybe_rhs_val) |rhs_val| {
@@ -13713,11 +13135,11 @@ fn zirShl(
const bits = scalar_ty.intInfo(zcu).bits;
switch (rhs_ty.zigTypeTag(zcu)) {
.int, .comptime_int => {
- switch (try rhs_val.orderAgainstZeroSema(pt)) {
+ switch (Value.order(rhs_val, .zero_comptime_int, zcu)) {
.gt => {
if (air_tag != .shl_sat) {
var rhs_space: Value.BigIntSpace = undefined;
- const rhs_bigint = try rhs_val.toBigIntSema(&rhs_space, pt);
+ const rhs_bigint = rhs_val.toBigInt(&rhs_space, zcu);
if (rhs_bigint.orderAgainstScalar(bits) != .lt) {
return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs_val, rhs_src, null);
}
@@ -13736,11 +13158,11 @@ fn zirShl(
.shl, .shl_exact => return sema.failWithUseOfUndef(block, rhs_src, elem_idx),
else => unreachable,
};
- switch (try rhs_elem.orderAgainstZeroSema(pt)) {
+ switch (Value.order(rhs_elem, .zero_comptime_int, zcu)) {
.gt => {
if (air_tag != .shl_sat) {
var rhs_elem_space: Value.BigIntSpace = undefined;
- const rhs_elem_bigint = try rhs_elem.toBigIntSema(&rhs_elem_space, pt);
+ const rhs_elem_bigint = rhs_elem.toBigInt(&rhs_elem_space, zcu);
if (rhs_elem_bigint.orderAgainstScalar(bits) != .lt) {
return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs_elem, rhs_src, elem_idx);
}
@@ -13769,7 +13191,7 @@ fn zirShl(
.shl, .shl_exact => try sema.checkAllScalarsDefined(block, lhs_src, lhs_val),
else => unreachable,
}
- if (try lhs_val.compareAllWithZeroSema(.eq, pt)) return lhs;
+ if (lhs_val.compareAllWithZero(.eq, zcu)) return lhs;
}
}
break :rs rhs_src;
@@ -13785,13 +13207,13 @@ fn zirShl(
const rt_rhs_scalar_ty = try pt.smallestUnsignedInt(bit_count);
if (!rhs_ty.isVector(zcu)) break :rt_rhs try pt.intValue(
rt_rhs_scalar_ty,
- @min(try rhs_val.getUnsignedIntSema(pt) orelse bit_count, bit_count),
+ @min(rhs_val.getUnsignedInt(zcu) orelse bit_count, bit_count),
);
const rhs_len = rhs_ty.vectorLen(zcu);
const rhs_elems = try sema.arena.alloc(InternPool.Index, rhs_len);
for (rhs_elems, 0..) |*rhs_elem, i| rhs_elem.* = (try pt.intValue(
rt_rhs_scalar_ty,
- @min(try (try rhs_val.elemValue(pt, i)).getUnsignedIntSema(pt) orelse bit_count, bit_count),
+ @min((try rhs_val.elemValue(pt, i)).getUnsignedInt(zcu) orelse bit_count, bit_count),
)).toIntern();
break :rt_rhs try pt.aggregateValue(try pt.vectorType(.{
.len = rhs_len,
@@ -13855,8 +13277,8 @@ fn zirShr(
const zcu = pt.zcu;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
- const lhs = try sema.resolveInst(extra.lhs);
- const rhs = try sema.resolveInst(extra.rhs);
+ const lhs = sema.resolveInst(extra.lhs);
+ const rhs = sema.resolveInst(extra.rhs);
const lhs_ty = sema.typeOf(lhs);
const rhs_ty = sema.typeOf(rhs);
@@ -13875,8 +13297,8 @@ fn zirShr(
try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
const scalar_ty = lhs_ty.scalarType(zcu);
- const maybe_lhs_val = try sema.resolveValueResolveLazy(lhs);
- const maybe_rhs_val = try sema.resolveValueResolveLazy(rhs);
+ const maybe_lhs_val = sema.resolveValue(lhs);
+ const maybe_rhs_val = sema.resolveValue(rhs);
const runtime_src = rs: {
if (maybe_rhs_val) |rhs_val| {
@@ -13893,10 +13315,10 @@ fn zirShr(
const bits = scalar_ty.intInfo(zcu).bits;
switch (rhs_ty.zigTypeTag(zcu)) {
.int, .comptime_int => {
- switch (try rhs_val.orderAgainstZeroSema(pt)) {
+ switch (Value.order(rhs_val, .zero_comptime_int, zcu)) {
.gt => {
var rhs_space: Value.BigIntSpace = undefined;
- const rhs_bigint = try rhs_val.toBigIntSema(&rhs_space, pt);
+ const rhs_bigint = rhs_val.toBigInt(&rhs_space, zcu);
if (rhs_bigint.orderAgainstScalar(bits) != .lt) {
return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs_val, rhs_src, null);
}
@@ -13912,10 +13334,10 @@ fn zirShr(
if (rhs_elem.isUndef(zcu)) {
return sema.failWithUseOfUndef(block, rhs_src, elem_idx);
}
- switch (try rhs_elem.orderAgainstZeroSema(pt)) {
+ switch (Value.order(rhs_elem, .zero_comptime_int, zcu)) {
.gt => {
var rhs_elem_space: Value.BigIntSpace = undefined;
- const rhs_elem_bigint = try rhs_elem.toBigIntSema(&rhs_elem_space, pt);
+ const rhs_elem_bigint = rhs_elem.toBigInt(&rhs_elem_space, zcu);
if (rhs_elem_bigint.orderAgainstScalar(bits) != .lt) {
return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs_elem, rhs_src, elem_idx);
}
@@ -13936,7 +13358,7 @@ fn zirShr(
}
if (maybe_lhs_val) |lhs_val| {
try sema.checkAllScalarsDefined(block, lhs_src, lhs_val);
- if (try lhs_val.compareAllWithZeroSema(.eq, pt)) return lhs;
+ if (lhs_val.compareAllWithZero(.eq, zcu)) return lhs;
}
}
break :rs rhs_src;
@@ -13988,8 +13410,8 @@ fn zirBitwise(
const lhs_src = block.src(.{ .node_offset_bin_lhs = inst_data.src_node });
const rhs_src = block.src(.{ .node_offset_bin_rhs = inst_data.src_node });
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
- const lhs = try sema.resolveInst(extra.lhs);
- const rhs = try sema.resolveInst(extra.rhs);
+ const lhs = sema.resolveInst(extra.lhs);
+ const rhs = sema.resolveInst(extra.rhs);
const lhs_ty = sema.typeOf(lhs);
const rhs_ty = sema.typeOf(rhs);
try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
@@ -14011,8 +13433,8 @@ fn zirBitwise(
const runtime_src = runtime: {
// TODO: ask the linker what kind of relocations are available, and
// in some cases emit a Value that means "this decl's address AND'd with this operand".
- if (try sema.resolveValueResolveLazy(casted_lhs)) |lhs_val| {
- if (try sema.resolveValueResolveLazy(casted_rhs)) |rhs_val| {
+ if (sema.resolveValue(casted_lhs)) |lhs_val| {
+ if (sema.resolveValue(casted_rhs)) |rhs_val| {
const result_val = switch (air_tag) {
// zig fmt: off
.bit_and => try arith.bitwiseBin(sema, resolved_type, lhs_val, rhs_val, .@"and"),
@@ -14040,7 +13462,7 @@ fn zirBitNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const operand_src = block.src(.{ .node_offset_un_op = inst_data.src_node });
const src = block.nodeOffset(inst_data.src_node);
- const operand = try sema.resolveInst(inst_data.operand);
+ const operand = sema.resolveInst(inst_data.operand);
const operand_ty = sema.typeOf(operand);
const scalar_ty = operand_ty.scalarType(zcu);
const scalar_tag = scalar_ty.zigTypeTag(zcu);
@@ -14058,7 +13480,7 @@ fn analyzeBitNot(
src: LazySrcLoc,
) CompileError!Air.Inst.Ref {
const operand_ty = sema.typeOf(operand);
- if (try sema.resolveValue(operand)) |operand_val| {
+ if (sema.resolveValue(operand)) |operand_val| {
const result_val = try arith.bitwiseNot(sema, operand_ty, operand_val);
return Air.internedToRef(result_val.toIntern());
}
@@ -14106,13 +13528,13 @@ fn analyzeTupleCat(
var i: u32 = 0;
while (i < lhs_len) : (i += 1) {
types[i] = lhs_ty.fieldType(i, zcu).toIntern();
- const default_val = lhs_ty.structFieldDefaultValue(i, zcu);
- values[i] = default_val.toIntern();
const operand_src = block.src(.{ .array_cat_lhs = .{
.array_cat_offset = src_node,
.elem_index = i,
} });
- if (default_val.toIntern() == .unreachable_value) {
+ if (lhs_ty.structFieldDefaultValue(i, zcu)) |default_val| {
+ values[i] = default_val.toIntern();
+ } else {
runtime_src = operand_src;
values[i] = .none;
}
@@ -14120,13 +13542,13 @@ fn analyzeTupleCat(
i = 0;
while (i < rhs_len) : (i += 1) {
types[i + lhs_len] = rhs_ty.fieldType(i, zcu).toIntern();
- const default_val = rhs_ty.structFieldDefaultValue(i, zcu);
- values[i + lhs_len] = default_val.toIntern();
const operand_src = block.src(.{ .array_cat_rhs = .{
.array_cat_offset = src_node,
.elem_index = i,
} });
- if (default_val.toIntern() == .unreachable_value) {
+ if (rhs_ty.structFieldDefaultValue(i, zcu)) |default_val| {
+ values[i + lhs_len] = default_val.toIntern();
+ } else {
runtime_src = operand_src;
values[i + lhs_len] = .none;
}
@@ -14168,8 +13590,8 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const zcu = pt.zcu;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
- const lhs = try sema.resolveInst(extra.lhs);
- const rhs = try sema.resolveInst(extra.rhs);
+ const lhs = sema.resolveInst(extra.lhs);
+ const rhs = sema.resolveInst(extra.rhs);
const lhs_ty = sema.typeOf(lhs);
const rhs_ty = sema.typeOf(rhs);
const src = block.nodeOffset(inst_data.src_node);
@@ -14263,12 +13685,12 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
};
const runtime_src = if (switch (lhs_ty.zigTypeTag(zcu)) {
- .array, .@"struct" => try sema.resolveValue(lhs),
+ .array, .@"struct" => sema.resolveValue(lhs),
.pointer => try sema.resolveDefinedValue(block, lhs_src, lhs),
else => unreachable,
}) |lhs_val| rs: {
if (switch (rhs_ty.zigTypeTag(zcu)) {
- .array, .@"struct" => try sema.resolveValue(rhs),
+ .array, .@"struct" => sema.resolveValue(rhs),
.pointer => try sema.resolveDefinedValue(block, rhs_src, rhs),
else => unreachable,
}) |rhs_val| {
@@ -14290,32 +13712,30 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
var elem_i: u32 = 0;
while (elem_i < lhs_len) : (elem_i += 1) {
const lhs_elem_i = elem_i;
- const elem_default_val = if (lhs_is_tuple) lhs_ty.structFieldDefaultValue(lhs_elem_i, zcu) else Value.@"unreachable";
- const elem_val = if (elem_default_val.toIntern() == .unreachable_value) try lhs_sub_val.elemValue(pt, lhs_elem_i) else elem_default_val;
- const elem_val_inst = Air.internedToRef(elem_val.toIntern());
+ const elem_default_val: ?Value = if (lhs_is_tuple) lhs_ty.structFieldDefaultValue(lhs_elem_i, zcu) else null;
+ const elem_val = elem_default_val orelse try lhs_sub_val.elemValue(pt, lhs_elem_i);
const operand_src = block.src(.{ .array_cat_lhs = .{
.array_cat_offset = inst_data.src_node,
.elem_index = elem_i,
} });
- const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, elem_val_inst, operand_src);
- const coerced_elem_val = try sema.resolveConstValue(block, operand_src, coerced_elem_val_inst, undefined);
+ const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, .fromValue(elem_val), operand_src);
+ const coerced_elem_val = sema.resolveValue(coerced_elem_val_inst).?;
element_vals[elem_i] = coerced_elem_val.toIntern();
}
while (elem_i < result_len) : (elem_i += 1) {
const rhs_elem_i = elem_i - lhs_len;
- const elem_default_val = if (rhs_is_tuple) rhs_ty.structFieldDefaultValue(rhs_elem_i, zcu) else Value.@"unreachable";
- const elem_val = if (elem_default_val.toIntern() == .unreachable_value) try rhs_sub_val.elemValue(pt, rhs_elem_i) else elem_default_val;
- const elem_val_inst = Air.internedToRef(elem_val.toIntern());
+ const elem_default_val: ?Value = if (rhs_is_tuple) rhs_ty.structFieldDefaultValue(rhs_elem_i, zcu) else null;
+ const elem_val = elem_default_val orelse try rhs_sub_val.elemValue(pt, rhs_elem_i);
const operand_src = block.src(.{ .array_cat_rhs = .{
.array_cat_offset = inst_data.src_node,
.elem_index = @intCast(rhs_elem_i),
} });
- const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, elem_val_inst, operand_src);
- const coerced_elem_val = try sema.resolveConstValue(block, operand_src, coerced_elem_val_inst, undefined);
+ const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, .fromValue(elem_val), operand_src);
+ const coerced_elem_val = sema.resolveValue(coerced_elem_val_inst).?;
element_vals[elem_i] = coerced_elem_val.toIntern();
}
return sema.addConstantMaybeRef(
- (try pt.aggregateValue(result_ty, element_vals)).toIntern(),
+ try pt.aggregateValue(result_ty, element_vals),
ptr_addrspace != null,
);
} else break :rs rhs_src;
@@ -14324,18 +13744,18 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
try sema.requireRuntimeBlock(block, src, runtime_src);
if (ptr_addrspace) |ptr_as| {
- const constant_alloc_ty = try pt.ptrTypeSema(.{
+ const constant_alloc_ty = try pt.ptrType(.{
.child = result_ty.toIntern(),
.flags = .{
.address_space = ptr_as,
.is_const = true,
},
});
- const alloc_ty = try pt.ptrTypeSema(.{
+ const alloc_ty = try pt.ptrType(.{
.child = result_ty.toIntern(),
.flags = .{ .address_space = ptr_as },
});
- const elem_ptr_ty = try pt.ptrTypeSema(.{
+ const elem_ptr_ty = try pt.ptrType(.{
.child = resolved_elem_ty.toIntern(),
.flags = .{ .address_space = ptr_as },
});
@@ -14347,7 +13767,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
if (lhs_ty.zigTypeTag(zcu) == .pointer and
rhs_ty.zigTypeTag(zcu) == .pointer)
{
- const slice_ty = try pt.ptrTypeSema(.{
+ const slice_ty = try pt.ptrType(.{
.child = resolved_elem_ty.toIntern(),
.flags = .{
.size = .slice,
@@ -14359,45 +13779,44 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const many_alloc = try block.addBitCast(many_ty, mutable_alloc);
// lhs_dest_slice = dest[0..lhs.len]
- const slice_ty_ref = Air.internedToRef(slice_ty.toIntern());
- const lhs_len_ref = try pt.intRef(.usize, lhs_len);
- const lhs_dest_slice = try block.addInst(.{
- .tag = .slice,
- .data = .{ .ty_pl = .{
- .ty = slice_ty_ref,
- .payload = try sema.addExtra(Air.Bin{
- .lhs = many_alloc,
- .rhs = lhs_len_ref,
- }),
- } },
- });
-
- _ = try block.addBinOp(.memcpy, lhs_dest_slice, lhs);
+ if (lhs_len > 0) {
+ const lhs_dest_slice = try block.addInst(.{
+ .tag = .slice,
+ .data = .{ .ty_pl = .{
+ .ty = .fromType(slice_ty),
+ .payload = try sema.addExtra(Air.Bin{
+ .lhs = many_alloc,
+ .rhs = try pt.intRef(.usize, lhs_len),
+ }),
+ } },
+ });
+ _ = try block.addBinOp(.memcpy, lhs_dest_slice, lhs);
+ }
// rhs_dest_slice = dest[lhs.len..][0..rhs.len]
- const rhs_len_ref = try pt.intRef(.usize, rhs_len);
- const rhs_dest_offset = try block.addInst(.{
- .tag = .ptr_add,
- .data = .{ .ty_pl = .{
- .ty = Air.internedToRef(many_ty.toIntern()),
- .payload = try sema.addExtra(Air.Bin{
- .lhs = many_alloc,
- .rhs = lhs_len_ref,
- }),
- } },
- });
- const rhs_dest_slice = try block.addInst(.{
- .tag = .slice,
- .data = .{ .ty_pl = .{
- .ty = slice_ty_ref,
- .payload = try sema.addExtra(Air.Bin{
- .lhs = rhs_dest_offset,
- .rhs = rhs_len_ref,
- }),
- } },
- });
-
- _ = try block.addBinOp(.memcpy, rhs_dest_slice, rhs);
+ if (rhs_len > 0) {
+ const rhs_dest_offset = try block.addInst(.{
+ .tag = .ptr_add,
+ .data = .{ .ty_pl = .{
+ .ty = Air.internedToRef(many_ty.toIntern()),
+ .payload = try sema.addExtra(Air.Bin{
+ .lhs = many_alloc,
+ .rhs = try pt.intRef(.usize, lhs_len),
+ }),
+ } },
+ });
+ const rhs_dest_slice = try block.addInst(.{
+ .tag = .slice,
+ .data = .{ .ty_pl = .{
+ .ty = .fromType(slice_ty),
+ .payload = try sema.addExtra(Air.Bin{
+ .lhs = rhs_dest_offset,
+ .rhs = try pt.intRef(.usize, rhs_len),
+ }),
+ } },
+ });
+ _ = try block.addBinOp(.memcpy, rhs_dest_slice, rhs);
+ }
if (res_sent_val) |sent_val| {
const elem_index = try pt.intRef(.usize, result_len);
@@ -14486,7 +13905,7 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins
.none => null,
else => Value.fromInterned(ptr_info.sentinel),
},
- .len = try val.sliceLen(pt),
+ .len = val.sliceLen(zcu),
};
},
.one => {
@@ -14500,8 +13919,20 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins
.@"struct" => {
if (operand_ty.isTuple(zcu) and peer_ty.isIndexable(zcu)) {
assert(!peer_ty.isTuple(zcu));
+ const peer_elem_ty = switch (peer_ty.zigTypeTag(zcu)) {
+ .pointer => switch (peer_ty.ptrSize(zcu)) {
+ .one => switch (peer_ty.childType(zcu).zigTypeTag(zcu)) {
+ .array, .vector => peer_ty.childType(zcu).childType(zcu),
+ .@"struct" => return null,
+ else => unreachable,
+ },
+ .many, .c, .slice => peer_ty.childType(zcu),
+ },
+ .vector, .array => peer_ty.childType(zcu),
+ else => unreachable,
+ };
return .{
- .elem_type = peer_ty.elemType2(zcu),
+ .elem_type = peer_elem_ty,
.sentinel = null,
.len = operand_ty.arrayLen(zcu),
};
@@ -14543,12 +13974,13 @@ fn analyzeTupleMul(
var runtime_src: ?LazySrcLoc = null;
for (0..tuple_len) |i| {
types[i] = operand_ty.fieldType(i, zcu).toIntern();
- values[i] = operand_ty.structFieldDefaultValue(i, zcu).toIntern();
const operand_src = block.src(.{ .array_cat_lhs = .{
.array_cat_offset = src_node,
.elem_index = @intCast(i),
} });
- if (values[i] == .unreachable_value) {
+ if (operand_ty.structFieldDefaultValue(i, zcu)) |default_val| {
+ values[i] = default_val.toIntern();
+ } else {
runtime_src = operand_src;
values[i] = .none; // TODO don't treat unreachable_value as special
}
@@ -14593,7 +14025,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const zcu = pt.zcu;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = sema.code.extraData(Zir.Inst.ArrayMul, inst_data.payload_index).data;
- const uncoerced_lhs = try sema.resolveInst(extra.lhs);
+ const uncoerced_lhs = sema.resolveInst(extra.lhs);
const uncoerced_lhs_ty = sema.typeOf(uncoerced_lhs);
const src: LazySrcLoc = block.nodeOffset(inst_data.src_node);
const lhs_src = block.src(.{ .node_offset_bin_lhs = inst_data.src_node });
@@ -14672,7 +14104,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const ptr_addrspace = if (lhs_ty.zigTypeTag(zcu) == .pointer) lhs_ty.ptrAddressSpace(zcu) else null;
const lhs_len = try sema.usizeCast(block, lhs_src, lhs_info.len);
- if (try sema.resolveValue(lhs)) |lhs_val| ct: {
+ if (sema.resolveValue(lhs)) |lhs_val| ct: {
const lhs_sub_val = if (lhs_ty.isSinglePointer(zcu))
try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty) orelse break :ct
else if (lhs_ty.isSlice(zcu))
@@ -14700,7 +14132,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
}
break :v try pt.aggregateValue(result_ty, element_vals);
};
- return sema.addConstantMaybeRef(val.toIntern(), ptr_addrspace != null);
+ return sema.addConstantMaybeRef(val, ptr_addrspace != null);
}
try sema.requireRuntimeBlock(block, src, lhs_src);
@@ -14714,7 +14146,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
}
if (ptr_addrspace) |ptr_as| {
- const alloc_ty = try pt.ptrTypeSema(.{
+ const alloc_ty = try pt.ptrType(.{
.child = result_ty.toIntern(),
.flags = .{
.address_space = ptr_as,
@@ -14722,7 +14154,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
},
});
const alloc = try block.addTy(.alloc, alloc_ty);
- const elem_ptr_ty = try pt.ptrTypeSema(.{
+ const elem_ptr_ty = try pt.ptrType(.{
.child = lhs_info.elem_type.toIntern(),
.flags = .{ .address_space = ptr_as },
});
@@ -14761,7 +14193,7 @@ fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
const lhs_src = src;
const rhs_src = block.src(.{ .node_offset_un_op = inst_data.src_node });
- const rhs = try sema.resolveInst(inst_data.operand);
+ const rhs = sema.resolveInst(inst_data.operand);
const rhs_ty = sema.typeOf(rhs);
const rhs_scalar_ty = rhs_ty.scalarType(zcu);
@@ -14774,7 +14206,7 @@ fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
if (rhs_scalar_ty.isAnyFloat()) {
// We handle float negation here to ensure negative zero is represented in the bits.
- if (try sema.resolveValue(rhs)) |rhs_val| {
+ if (sema.resolveValue(rhs)) |rhs_val| {
const result = try arith.negateFloat(sema, rhs_ty, rhs_val);
return Air.internedToRef(result.toIntern());
}
@@ -14794,7 +14226,7 @@ fn zirNegateWrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
const lhs_src = src;
const rhs_src = block.src(.{ .node_offset_un_op = inst_data.src_node });
- const rhs = try sema.resolveInst(inst_data.operand);
+ const rhs = sema.resolveInst(inst_data.operand);
const rhs_ty = sema.typeOf(rhs);
const rhs_scalar_ty = rhs_ty.scalarType(zcu);
@@ -14822,8 +14254,8 @@ fn zirArithmetic(
const lhs_src = block.src(.{ .node_offset_bin_lhs = inst_data.src_node });
const rhs_src = block.src(.{ .node_offset_bin_rhs = inst_data.src_node });
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
- const lhs = try sema.resolveInst(extra.lhs);
- const rhs = try sema.resolveInst(extra.rhs);
+ const lhs = sema.resolveInst(extra.lhs);
+ const rhs = sema.resolveInst(extra.rhs);
return sema.analyzeArithmetic(block, zir_tag, lhs, rhs, src, lhs_src, rhs_src, safety);
}
@@ -14836,8 +14268,8 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
const lhs_src = block.src(.{ .node_offset_bin_lhs = inst_data.src_node });
const rhs_src = block.src(.{ .node_offset_bin_rhs = inst_data.src_node });
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
- const lhs = try sema.resolveInst(extra.lhs);
- const rhs = try sema.resolveInst(extra.rhs);
+ const lhs = sema.resolveInst(extra.lhs);
+ const rhs = sema.resolveInst(extra.rhs);
const lhs_ty = sema.typeOf(lhs);
const rhs_ty = sema.typeOf(rhs);
const lhs_zig_ty_tag = lhs_ty.zigTypeTag(zcu);
@@ -14859,8 +14291,8 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div);
- const maybe_lhs_val = try sema.resolveValueResolveLazy(casted_lhs);
- const maybe_rhs_val = try sema.resolveValueResolveLazy(casted_rhs);
+ const maybe_lhs_val = sema.resolveValue(casted_lhs);
+ const maybe_rhs_val = sema.resolveValue(casted_rhs);
if ((lhs_ty.zigTypeTag(zcu) == .comptime_float and rhs_ty.zigTypeTag(zcu) == .comptime_int) or
(lhs_ty.zigTypeTag(zcu) == .comptime_int and rhs_ty.zigTypeTag(zcu) == .comptime_float))
@@ -14945,8 +14377,8 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const lhs_src = block.builtinCallArgSrc(inst_data.src_node, 0);
const rhs_src = block.builtinCallArgSrc(inst_data.src_node, 1);
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
- const lhs = try sema.resolveInst(extra.lhs);
- const rhs = try sema.resolveInst(extra.rhs);
+ const lhs = sema.resolveInst(extra.lhs);
+ const rhs = sema.resolveInst(extra.rhs);
const lhs_ty = sema.typeOf(lhs);
const rhs_ty = sema.typeOf(rhs);
const lhs_zig_ty_tag = lhs_ty.zigTypeTag(zcu);
@@ -14968,8 +14400,8 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_exact);
- const maybe_lhs_val = try sema.resolveValueResolveLazy(casted_lhs);
- const maybe_rhs_val = try sema.resolveValueResolveLazy(casted_rhs);
+ const maybe_lhs_val = sema.resolveValue(casted_lhs);
+ const maybe_rhs_val = sema.resolveValue(casted_rhs);
// Because `@divExact` can trigger Illegal Behavior, undefined operands trigger Illegal Behavior.
@@ -15041,8 +14473,8 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const lhs_src = block.builtinCallArgSrc(inst_data.src_node, 0);
const rhs_src = block.builtinCallArgSrc(inst_data.src_node, 1);
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
- const lhs = try sema.resolveInst(extra.lhs);
- const rhs = try sema.resolveInst(extra.rhs);
+ const lhs = sema.resolveInst(extra.lhs);
+ const rhs = sema.resolveInst(extra.rhs);
const lhs_ty = sema.typeOf(lhs);
const rhs_ty = sema.typeOf(rhs);
const lhs_zig_ty_tag = lhs_ty.zigTypeTag(zcu);
@@ -15064,8 +14496,8 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_floor);
- const maybe_lhs_val = try sema.resolveValueResolveLazy(casted_lhs);
- const maybe_rhs_val = try sema.resolveValueResolveLazy(casted_rhs);
+ const maybe_lhs_val = sema.resolveValue(casted_lhs);
+ const maybe_rhs_val = sema.resolveValue(casted_rhs);
const allow_div_zero = !is_int and
resolved_type.toIntern() != .comptime_float_type and
@@ -15106,8 +14538,8 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const lhs_src = block.builtinCallArgSrc(inst_data.src_node, 0);
const rhs_src = block.builtinCallArgSrc(inst_data.src_node, 1);
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
- const lhs = try sema.resolveInst(extra.lhs);
- const rhs = try sema.resolveInst(extra.rhs);
+ const lhs = sema.resolveInst(extra.lhs);
+ const rhs = sema.resolveInst(extra.rhs);
const lhs_ty = sema.typeOf(lhs);
const rhs_ty = sema.typeOf(rhs);
const lhs_zig_ty_tag = lhs_ty.zigTypeTag(zcu);
@@ -15129,8 +14561,8 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_trunc);
- const maybe_lhs_val = try sema.resolveValueResolveLazy(casted_lhs);
- const maybe_rhs_val = try sema.resolveValueResolveLazy(casted_rhs);
+ const maybe_lhs_val = sema.resolveValue(casted_lhs);
+ const maybe_rhs_val = sema.resolveValue(casted_rhs);
const allow_div_zero = !is_int and
resolved_type.toIntern() != .comptime_float_type and
@@ -15317,8 +14749,8 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
const lhs_src = block.src(.{ .node_offset_bin_lhs = inst_data.src_node });
const rhs_src = block.src(.{ .node_offset_bin_rhs = inst_data.src_node });
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
- const lhs = try sema.resolveInst(extra.lhs);
- const rhs = try sema.resolveInst(extra.rhs);
+ const lhs = sema.resolveInst(extra.lhs);
+ const rhs = sema.resolveInst(extra.rhs);
const lhs_ty = sema.typeOf(lhs);
const rhs_ty = sema.typeOf(rhs);
const lhs_zig_ty_tag = lhs_ty.zigTypeTag(zcu);
@@ -15341,8 +14773,8 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .mod_rem);
- const maybe_lhs_val = try sema.resolveValueResolveLazy(casted_lhs);
- const maybe_rhs_val = try sema.resolveValueResolveLazy(casted_rhs);
+ const maybe_lhs_val = sema.resolveValue(casted_lhs);
+ const maybe_rhs_val = sema.resolveValue(casted_rhs);
const lhs_maybe_negative = a: {
if (lhs_scalar_ty.isUnsignedInt(zcu)) break :a false;
@@ -15418,8 +14850,8 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
const lhs_src = block.builtinCallArgSrc(inst_data.src_node, 0);
const rhs_src = block.builtinCallArgSrc(inst_data.src_node, 1);
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
- const lhs = try sema.resolveInst(extra.lhs);
- const rhs = try sema.resolveInst(extra.rhs);
+ const lhs = sema.resolveInst(extra.lhs);
+ const rhs = sema.resolveInst(extra.rhs);
const lhs_ty = sema.typeOf(lhs);
const rhs_ty = sema.typeOf(rhs);
const lhs_zig_ty_tag = lhs_ty.zigTypeTag(zcu);
@@ -15440,8 +14872,8 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .mod);
- const maybe_lhs_val = try sema.resolveValueResolveLazy(casted_lhs);
- const maybe_rhs_val = try sema.resolveValueResolveLazy(casted_rhs);
+ const maybe_lhs_val = sema.resolveValue(casted_lhs);
+ const maybe_rhs_val = sema.resolveValue(casted_rhs);
const allow_div_zero = !is_int and
resolved_type.toIntern() != .comptime_float_type and
@@ -15482,8 +14914,8 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
const lhs_src = block.builtinCallArgSrc(inst_data.src_node, 0);
const rhs_src = block.builtinCallArgSrc(inst_data.src_node, 1);
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
- const lhs = try sema.resolveInst(extra.lhs);
- const rhs = try sema.resolveInst(extra.rhs);
+ const lhs = sema.resolveInst(extra.lhs);
+ const rhs = sema.resolveInst(extra.rhs);
const lhs_ty = sema.typeOf(lhs);
const rhs_ty = sema.typeOf(rhs);
const lhs_zig_ty_tag = lhs_ty.zigTypeTag(zcu);
@@ -15504,8 +14936,8 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .rem);
- const maybe_lhs_val = try sema.resolveValueResolveLazy(casted_lhs);
- const maybe_rhs_val = try sema.resolveValueResolveLazy(casted_rhs);
+ const maybe_lhs_val = sema.resolveValue(casted_lhs);
+ const maybe_rhs_val = sema.resolveValue(casted_rhs);
const allow_div_zero = !is_int and
resolved_type.toIntern() != .comptime_float_type and
@@ -15553,8 +14985,8 @@ fn zirOverflowArithmetic(
const lhs_src = block.builtinCallArgSrc(extra.node, 0);
const rhs_src = block.builtinCallArgSrc(extra.node, 1);
- const uncasted_lhs = try sema.resolveInst(extra.lhs);
- const uncasted_rhs = try sema.resolveInst(extra.rhs);
+ const uncasted_lhs = sema.resolveInst(extra.lhs);
+ const uncasted_rhs = sema.resolveInst(extra.rhs);
const lhs_ty = sema.typeOf(uncasted_lhs);
const rhs_ty = sema.typeOf(uncasted_rhs);
@@ -15584,8 +15016,8 @@ fn zirOverflowArithmetic(
return sema.fail(block, src, "expected vector of integers or integer tag type, found '{f}'", .{dest_ty.fmt(pt)});
}
- const maybe_lhs_val = try sema.resolveValue(lhs);
- const maybe_rhs_val = try sema.resolveValue(rhs);
+ const maybe_lhs_val = sema.resolveValue(lhs);
+ const maybe_rhs_val = sema.resolveValue(rhs);
const tuple_ty = try pt.overflowArithmeticTupleType(dest_ty);
const overflow_ty: Type = .fromInterned(ip.indexToKey(tuple_ty.toIntern()).tuple_type.types.get(ip)[1]);
@@ -15601,12 +15033,12 @@ fn zirOverflowArithmetic(
// to the result, even if it is undefined..
// Otherwise, if either of the argument is undefined, undefined is returned.
if (maybe_lhs_val) |lhs_val| {
- if (!lhs_val.isUndef(zcu) and (try lhs_val.compareAllWithZeroSema(.eq, pt))) {
+ if (!lhs_val.isUndef(zcu) and lhs_val.compareAllWithZero(.eq, zcu)) {
break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = rhs };
}
}
if (maybe_rhs_val) |rhs_val| {
- if (!rhs_val.isUndef(zcu) and (try rhs_val.compareAllWithZeroSema(.eq, pt))) {
+ if (!rhs_val.isUndef(zcu) and rhs_val.compareAllWithZero(.eq, zcu)) {
break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = lhs };
}
}
@@ -15627,7 +15059,7 @@ fn zirOverflowArithmetic(
if (maybe_rhs_val) |rhs_val| {
if (rhs_val.isUndef(zcu)) {
break :result .{ .overflow_bit = .undef, .wrapped = .undef };
- } else if (try rhs_val.compareAllWithZeroSema(.eq, pt)) {
+ } else if (rhs_val.compareAllWithZero(.eq, zcu)) {
break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = lhs };
} else if (maybe_lhs_val) |lhs_val| {
if (lhs_val.isUndef(zcu)) {
@@ -15642,12 +15074,12 @@ fn zirOverflowArithmetic(
.mul_with_overflow => {
// If either of the arguments is zero, the result is zero and no overflow occured.
if (maybe_lhs_val) |lhs_val| {
- if (!lhs_val.isUndef(zcu) and try lhs_val.compareAllWithZeroSema(.eq, pt)) {
+ if (!lhs_val.isUndef(zcu) and lhs_val.compareAllWithZero(.eq, zcu)) {
break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = lhs };
}
}
if (maybe_rhs_val) |rhs_val| {
- if (!rhs_val.isUndef(zcu) and try rhs_val.compareAllWithZeroSema(.eq, pt)) {
+ if (!rhs_val.isUndef(zcu) and rhs_val.compareAllWithZero(.eq, zcu)) {
break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = rhs };
}
}
@@ -15694,10 +15126,10 @@ fn zirOverflowArithmetic(
const bits = scalar_ty.intInfo(zcu).bits;
switch (rhs_ty.zigTypeTag(zcu)) {
.int, .comptime_int => {
- switch (try rhs_val.orderAgainstZeroSema(pt)) {
+ switch (Value.order(rhs_val, .zero_comptime_int, zcu)) {
.gt => {
var rhs_space: Value.BigIntSpace = undefined;
- const rhs_bigint = try rhs_val.toBigIntSema(&rhs_space, pt);
+ const rhs_bigint = rhs_val.toBigInt(&rhs_space, zcu);
if (rhs_bigint.orderAgainstScalar(bits) != .lt) {
return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs_val, rhs_src, null);
}
@@ -15711,10 +15143,10 @@ fn zirOverflowArithmetic(
for (0..rhs_ty.vectorLen(zcu)) |elem_idx| {
const rhs_elem = try rhs_val.elemValue(pt, elem_idx);
if (rhs_elem.isUndef(zcu)) return sema.failWithUseOfUndef(block, rhs_src, elem_idx);
- switch (try rhs_elem.orderAgainstZeroSema(pt)) {
+ switch (Value.order(rhs_elem, .zero_comptime_int, zcu)) {
.gt => {
var rhs_elem_space: Value.BigIntSpace = undefined;
- const rhs_elem_bigint = try rhs_elem.toBigIntSema(&rhs_elem_space, pt);
+ const rhs_elem_bigint = rhs_elem.toBigInt(&rhs_elem_space, zcu);
if (rhs_elem_bigint.orderAgainstScalar(bits) != .lt) {
return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs_elem, rhs_src, elem_idx);
}
@@ -15728,7 +15160,7 @@ fn zirOverflowArithmetic(
},
else => unreachable,
}
- if (try rhs_val.compareAllWithZeroSema(.eq, pt)) {
+ if (rhs_val.compareAllWithZero(.eq, zcu)) {
break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = lhs };
}
} else {
@@ -15737,7 +15169,7 @@ fn zirOverflowArithmetic(
}
if (maybe_lhs_val) |lhs_val| {
try sema.checkAllScalarsDefined(block, lhs_src, lhs_val);
- if (try lhs_val.compareAllWithZeroSema(.eq, pt)) {
+ if (lhs_val.compareAllWithZero(.eq, zcu)) {
break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = lhs };
}
}
@@ -15767,7 +15199,7 @@ fn zirOverflowArithmetic(
};
if (result.inst != .none) {
- if (try sema.resolveValue(result.inst)) |some| {
+ if (sema.resolveValue(result.inst)) |some| {
result.wrapped = some;
result.inst = .none;
}
@@ -15817,22 +15249,45 @@ fn analyzeArithmetic(
if (zir_tag != .sub) {
return sema.failWithInvalidPtrArithmetic(block, src, "pointer-pointer", "subtraction");
}
- if (!lhs_ty.elemType2(zcu).eql(rhs_ty.elemType2(zcu), zcu)) {
+
+ // TODO: these semantics are really weird. Pointer subtraction works in increments
+ // of the pointer child for indexable pointers (excluding pointers to vectors),
+ // which makes sense, but we also allow it for arbitrary single-item pointers, which
+ // leads to the weird result that subtraction of '*T' works completely differently
+ // depending on whether 'T' is an array. That seems dangerous and confusing, and
+ // requires the odd logic below. This behavior originally came from a now-removed
+ // function `Type.elemType2`, which was removed precisely *because* the thing it did
+ // wasn't really well-defined; for that reason, these semantics were probably
+ // largely accidental to begin with. We should change the langauge to avoid this
+ // confusing behavior. For instance, perhaps pointer subtraction should only work on
+ // indexable pointers.
+ const lhs_elem_ty = ty: {
+ const ptr_elem_ty = lhs_ty.childType(zcu);
+ if (lhs_ty.ptrSize(zcu) == .one and ptr_elem_ty.zigTypeTag(zcu) == .array) break :ty ptr_elem_ty.childType(zcu);
+ break :ty ptr_elem_ty;
+ };
+ const rhs_elem_ty = ty: {
+ const ptr_elem_ty = rhs_ty.childType(zcu);
+ if (rhs_ty.ptrSize(zcu) == .one and ptr_elem_ty.zigTypeTag(zcu) == .array) break :ty ptr_elem_ty.childType(zcu);
+ break :ty ptr_elem_ty;
+ };
+ if (lhs_elem_ty.toIntern() != rhs_elem_ty.toIntern()) {
return sema.fail(block, src, "incompatible pointer arithmetic operands '{f}' and '{f}'", .{
lhs_ty.fmt(pt), rhs_ty.fmt(pt),
});
}
- const elem_size = lhs_ty.elemType2(zcu).abiSize(zcu);
+ try sema.ensureLayoutResolved(lhs_elem_ty, src, .ptr_offset);
+ const elem_size = lhs_elem_ty.abiSize(zcu);
if (elem_size == 0) {
- return sema.fail(block, src, "pointer arithmetic requires element type '{f}' to have runtime bits", .{
- lhs_ty.elemType2(zcu).fmt(pt),
+ return sema.fail(block, src, "pointer subtraction requires element type '{f}' to have runtime bits", .{
+ lhs_elem_ty.fmt(pt),
});
}
const runtime_src = runtime_src: {
- if (try sema.resolveValue(lhs)) |lhs_value| {
- if (try sema.resolveValue(rhs)) |rhs_value| {
+ if (sema.resolveValue(lhs)) |lhs_value| {
+ if (sema.resolveValue(rhs)) |rhs_value| {
const lhs_ptr = switch (zcu.intern_pool.indexToKey(lhs_value.toIntern())) {
.undef => return sema.failWithUseOfUndef(block, lhs_src, null),
.ptr => |ptr| ptr,
@@ -15875,12 +15330,8 @@ fn analyzeArithmetic(
else => return sema.failWithInvalidPtrArithmetic(block, src, "pointer-integer", "addition and subtraction"),
};
- if (!try lhs_ty.elemType2(zcu).hasRuntimeBitsSema(pt)) {
- return sema.fail(block, src, "pointer arithmetic requires element type '{f}' to have runtime bits", .{
- lhs_ty.elemType2(zcu).fmt(pt),
- });
- }
- return sema.analyzePtrArithmetic(block, src, lhs, rhs, air_tag, lhs_src, rhs_src);
+ try sema.ensureLayoutResolved(lhs_ty.childType(zcu), src, .ptr_offset);
+ return sema.analyzePtrArithmetic(block, src, lhs, rhs, air_tag, rhs_src);
},
}
}
@@ -15915,8 +15366,8 @@ fn analyzeArithmetic(
else => unreachable,
};
- const maybe_lhs_val = try sema.resolveValueResolveLazy(casted_lhs);
- const maybe_rhs_val = try sema.resolveValueResolveLazy(casted_rhs);
+ const maybe_lhs_val = sema.resolveValue(casted_lhs);
+ const maybe_rhs_val = sema.resolveValue(casted_rhs);
if (maybe_lhs_val) |lhs_val| {
if (maybe_rhs_val) |rhs_val| {
@@ -15972,6 +15423,7 @@ fn analyzeArithmetic(
return block.addBinOp(air_tag, casted_lhs, casted_rhs);
}
+/// Asserts that the layout of the pointer child type is already resolved.
fn analyzePtrArithmetic(
sema: *Sema,
block: *Block,
@@ -15979,7 +15431,6 @@ fn analyzePtrArithmetic(
ptr: Air.Inst.Ref,
uncasted_offset: Air.Inst.Ref,
air_tag: Air.Inst.Tag,
- ptr_src: LazySrcLoc,
offset_src: LazySrcLoc,
) CompileError!Air.Inst.Ref {
// TODO if the operand is comptime-known to be negative, or is a negative int,
@@ -15987,81 +15438,55 @@ fn analyzePtrArithmetic(
const offset = try sema.coerce(block, .usize, uncasted_offset, offset_src);
const pt = sema.pt;
const zcu = pt.zcu;
- const opt_ptr_val = try sema.resolveValue(ptr);
- const opt_off_val = try sema.resolveDefinedValue(block, offset_src, offset);
const ptr_ty = sema.typeOf(ptr);
const ptr_info = ptr_ty.ptrInfo(zcu);
assert(ptr_info.flags.size == .many or ptr_info.flags.size == .c);
- if ((try sema.typeHasOnePossibleValue(.fromInterned(ptr_info.child))) != null) {
- // Offset will be multiplied by zero, so result is the same as the base pointer.
- return ptr;
+ const maybe_index: ?u64 = if (try sema.resolveDefinedValue(block, offset_src, offset)) |val| off: {
+ break :off val.toUnsignedInt(zcu);
+ } else null;
+
+ const elem_ty: Type = .fromInterned(ptr_info.child);
+ elem_ty.assertHasLayout(zcu);
+
+ switch (elem_ty.classify(zcu)) {
+ .no_possible_value, .one_possible_value => {
+ // Offset will be multiplied by zero, so result is the same as the base pointer.
+ return ptr;
+ },
+ else => {},
}
- const new_ptr_ty = t: {
- // Calculate the new pointer alignment.
- // This code is duplicated in `Type.elemPtrType`.
- if (ptr_info.flags.alignment == .none) {
- // ABI-aligned pointer. Any pointer arithmetic maintains the same ABI-alignedness.
- break :t ptr_ty;
+ const elem_ptr_ty = try ptr_ty.elemPtrType(maybe_index, pt);
+ // `elem_ptr_ty` is a single-item pointer, but we want a many-item or C pointer, and to preserve
+ // any input sentinel.
+ const new_ptr_ty = try pt.ptrType(info: {
+ var info = elem_ptr_ty.ptrInfo(zcu);
+ info.flags.size = ptr_info.flags.size;
+ info.sentinel = ptr_info.sentinel;
+ break :info info;
+ });
+
+ ct: {
+ const ptr_val = sema.resolveValue(ptr) orelse break :ct;
+ if (ptr_val.isUndef(zcu)) return pt.undefRef(new_ptr_ty);
+ const index = maybe_index orelse break :ct;
+
+ if (index == 0) return ptr;
+ if (air_tag == .ptr_sub) {
+ const elem_size = elem_ty.abiSize(zcu);
+ return .fromValue(try sema.ptrSubtract(block, op_src, ptr_val, index * elem_size, new_ptr_ty));
+ } else {
+ return .fromValue(try pt.getCoerced(try ptr_val.ptrElem(index, pt), new_ptr_ty));
}
- // If the addend is not a comptime-known value we can still count on
- // it being a multiple of the type size.
- const elem_size = try Type.fromInterned(ptr_info.child).abiSizeSema(pt);
- const addend = if (opt_off_val) |off_val| a: {
- const off_int = try sema.usizeCast(block, offset_src, try off_val.toUnsignedIntSema(pt));
- break :a elem_size * off_int;
- } else elem_size;
+ }
- // The resulting pointer is aligned to the lcd between the offset (an
- // arbitrary number) and the alignment factor (always a power of two,
- // non zero).
- const new_align: Alignment = @enumFromInt(@min(
- @ctz(addend),
- @intFromEnum(ptr_info.flags.alignment),
- ));
- assert(new_align != .none);
-
- break :t try pt.ptrTypeSema(.{
- .child = ptr_info.child,
- .sentinel = ptr_info.sentinel,
- .flags = .{
- .size = ptr_info.flags.size,
- .alignment = new_align,
- .is_const = ptr_info.flags.is_const,
- .is_volatile = ptr_info.flags.is_volatile,
- .is_allowzero = ptr_info.flags.is_allowzero,
- .address_space = ptr_info.flags.address_space,
- },
- });
- };
-
- const runtime_src = rs: {
- if (opt_ptr_val) |ptr_val| {
- if (opt_off_val) |offset_val| {
- if (ptr_val.isUndef(zcu)) return pt.undefRef(new_ptr_ty);
-
- const offset_int = try sema.usizeCast(block, offset_src, try offset_val.toUnsignedIntSema(pt));
- if (offset_int == 0) return ptr;
- if (air_tag == .ptr_sub) {
- const elem_size = try Type.fromInterned(ptr_info.child).abiSizeSema(pt);
- const new_ptr_val = try sema.ptrSubtract(block, op_src, ptr_val, offset_int * elem_size, new_ptr_ty);
- return Air.internedToRef(new_ptr_val.toIntern());
- } else {
- const new_ptr_val = try pt.getCoerced(try ptr_val.ptrElem(offset_int, pt), new_ptr_ty);
- return Air.internedToRef(new_ptr_val.toIntern());
- }
- } else break :rs offset_src;
- } else break :rs ptr_src;
- };
-
- try sema.requireRuntimeBlock(block, op_src, runtime_src);
try sema.checkLogicalPtrOperation(block, op_src, ptr_ty);
return block.addInst(.{
.tag = air_tag,
.data = .{ .ty_pl = .{
- .ty = Air.internedToRef(new_ptr_ty.toIntern()),
+ .ty = .fromType(new_ptr_ty),
.payload = try sema.addExtra(Air.Bin{
.lhs = ptr,
.rhs = offset,
@@ -16077,7 +15502,7 @@ fn zirLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.In
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const src = block.nodeOffset(inst_data.src_node);
const ptr_src = src; // TODO better source location
- const ptr = try sema.resolveInst(inst_data.operand);
+ const ptr = sema.resolveInst(inst_data.operand);
return sema.analyzeLoad(block, src, ptr, ptr_src);
}
@@ -16151,7 +15576,7 @@ fn zirAsm(
const out_ty = try sema.resolveType(block, ret_ty_src, output.data.operand);
expr_ty = Air.internedToRef(out_ty.toIntern());
} else {
- const inst = try sema.resolveInst(output.data.operand);
+ const inst = sema.resolveInst(output.data.operand);
if (!sema.checkRuntimeValue(inst)) {
const output_name = try ip.getOrPutString(gpa, io, pt.tid, name, .no_embedded_nulls);
return sema.failWithContainsReferenceToComptimeVar(block, output_src, output_name, "assembly output", .fromInterned(inst.toInterned().?));
@@ -16181,7 +15606,7 @@ fn zirAsm(
} });
extra_i = input.end;
- const uncasted_arg = try sema.resolveInst(input.data.operand);
+ const uncasted_arg = sema.resolveInst(input.data.operand);
const name = sema.code.nullTerminatedString(input.data.name);
if (!sema.checkRuntimeValue(uncasted_arg)) {
const input_name = try ip.getOrPutString(gpa, io, pt.tid, name, .no_embedded_nulls);
@@ -16204,7 +15629,7 @@ fn zirAsm(
const clobbers = if (extra.data.clobbers == .none) empty: {
const clobbers_ty = try sema.getBuiltinType(src, .@"assembly.Clobbers");
break :empty try sema.structInitEmpty(block, clobbers_ty, src, src);
- } else try sema.resolveInst(extra.data.clobbers); // Already coerced by AstGen.
+ } else sema.resolveInst(extra.data.clobbers); // Already coerced by AstGen.
const clobbers_val = try sema.resolveConstDefinedValue(block, src, clobbers, .{ .simple = .clobber });
needed_capacity += asm_source.len / 4 + 1;
@@ -16248,6 +15673,7 @@ fn zirAsm(
buffer[input.c.len + 1 + input.n.len] = 0;
sema.air_extra.items.len += (input.c.len + input.n.len + (2 + 3)) / 4;
}
+ if (try expr_ty.toType().onePossibleValue(pt)) |opv| return .fromValue(opv);
return asm_air;
}
@@ -16269,8 +15695,8 @@ fn zirCmpEq(
const src: LazySrcLoc = block.nodeOffset(inst_data.src_node);
const lhs_src = block.src(.{ .node_offset_bin_lhs = inst_data.src_node });
const rhs_src = block.src(.{ .node_offset_bin_rhs = inst_data.src_node });
- const lhs = try sema.resolveInst(extra.lhs);
- const rhs = try sema.resolveInst(extra.rhs);
+ const lhs = sema.resolveInst(extra.lhs);
+ const rhs = sema.resolveInst(extra.rhs);
const lhs_ty = sema.typeOf(lhs);
const rhs_ty = sema.typeOf(rhs);
@@ -16283,10 +15709,10 @@ fn zirCmpEq(
// comparing null with optionals
if (lhs_ty_tag == .null and (rhs_ty_tag == .optional or rhs_ty.isCPtr(zcu))) {
- return sema.analyzeIsNull(block, rhs, op == .neq);
+ return sema.analyzeIsNull(block, src, rhs, op == .neq);
}
if (rhs_ty_tag == .null and (lhs_ty_tag == .optional or lhs_ty.isCPtr(zcu))) {
- return sema.analyzeIsNull(block, lhs, op == .neq);
+ return sema.analyzeIsNull(block, src, lhs, op == .neq);
}
if (lhs_ty_tag == .null or rhs_ty_tag == .null) {
@@ -16303,8 +15729,8 @@ fn zirCmpEq(
if (lhs_ty_tag == .error_set and rhs_ty_tag == .error_set) {
const runtime_src: LazySrcLoc = src: {
- if (try sema.resolveValue(lhs)) |lval| {
- if (try sema.resolveValue(rhs)) |rval| {
+ if (sema.resolveValue(lhs)) |lval| {
+ if (sema.resolveValue(rhs)) |rval| {
if (lval.isUndef(zcu) or rval.isUndef(zcu)) return .undef_bool;
const lkey = zcu.intern_pool.indexToKey(lval.toIntern());
const rkey = zcu.intern_pool.indexToKey(rval.toIntern());
@@ -16323,8 +15749,8 @@ fn zirCmpEq(
return block.addBinOp(air_tag, lhs, rhs);
}
if (lhs_ty_tag == .type and rhs_ty_tag == .type) {
- const lhs_as_type = try sema.analyzeAsType(block, lhs_src, lhs);
- const rhs_as_type = try sema.analyzeAsType(block, rhs_src, rhs);
+ const lhs_as_type = try sema.analyzeAsType(block, lhs_src, .type, lhs);
+ const rhs_as_type = try sema.analyzeAsType(block, rhs_src, .type, rhs);
return if (lhs_as_type.eql(rhs_as_type, zcu) == (op == .eq)) .bool_true else .bool_false;
}
return sema.analyzeCmp(block, src, lhs, rhs, op, lhs_src, rhs_src, true);
@@ -16343,7 +15769,6 @@ fn analyzeCmpUnionTag(
const pt = sema.pt;
const zcu = pt.zcu;
const union_ty = sema.typeOf(un);
- try union_ty.resolveFields(pt);
const union_tag_ty = union_ty.unionTagType(zcu) orelse {
const msg = msg: {
const msg = try sema.errMsg(un_src, "comparison of union and enum literal is only valid for tagged union types", .{});
@@ -16358,10 +15783,10 @@ fn analyzeCmpUnionTag(
const coerced_tag = try sema.coerce(block, union_tag_ty, tag, tag_src);
const coerced_union = try sema.coerce(block, union_tag_ty, un, un_src);
- if (try sema.resolveValue(coerced_tag)) |enum_val| {
+ if (sema.resolveValue(coerced_tag)) |enum_val| {
if (enum_val.isUndef(zcu)) return .undef_bool;
const field_ty = union_ty.unionFieldType(enum_val, zcu).?;
- if (field_ty.zigTypeTag(zcu) == .noreturn) {
+ if (field_ty.classify(zcu) == .no_possible_value) {
return .bool_false;
}
}
@@ -16384,8 +15809,8 @@ fn zirCmp(
const src: LazySrcLoc = block.nodeOffset(inst_data.src_node);
const lhs_src = block.src(.{ .node_offset_bin_lhs = inst_data.src_node });
const rhs_src = block.src(.{ .node_offset_bin_rhs = inst_data.src_node });
- const lhs = try sema.resolveInst(extra.lhs);
- const rhs = try sema.resolveInst(extra.rhs);
+ const lhs = sema.resolveInst(extra.lhs);
+ const rhs = sema.resolveInst(extra.rhs);
return sema.analyzeCmp(block, src, lhs, rhs, op, lhs_src, rhs_src, false);
}
@@ -16468,8 +15893,8 @@ fn cmpSelf(
const zcu = pt.zcu;
const resolved_type = sema.typeOf(casted_lhs);
- const maybe_lhs_val = try sema.resolveValue(casted_lhs);
- const maybe_rhs_val = try sema.resolveValue(casted_rhs);
+ const maybe_lhs_val = sema.resolveValue(casted_lhs);
+ const maybe_rhs_val = sema.resolveValue(casted_rhs);
if (maybe_lhs_val) |v| if (v.isUndef(zcu)) return .undef_bool;
if (maybe_rhs_val) |v| if (v.isUndef(zcu)) return .undef_bool;
@@ -16534,42 +15959,26 @@ fn runtimeBoolCmp(
fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const pt = sema.pt;
+ const zcu = pt.zcu;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);
const ty = try sema.resolveType(block, operand_src, inst_data.operand);
- switch (ty.zigTypeTag(pt.zcu)) {
- .@"fn",
- .noreturn,
- .undefined,
- .null,
- .@"opaque",
- => return sema.fail(block, operand_src, "no size available for type '{f}'", .{ty.fmt(pt)}),
+ try sema.ensureLayoutResolved(ty, operand_src, .size_of);
+ switch (ty.classify(zcu)) {
+ .no_possible_value,
+ => return sema.fail(block, operand_src, "no size available for uninstantiable type '{f}'", .{ty.fmt(pt)}),
- .type,
- .enum_literal,
- .comptime_float,
- .comptime_int,
- .void,
- => return .zero,
+ .partially_comptime,
+ .fully_comptime,
+ => return sema.fail(block, operand_src, "no size available for comptime-only type '{f}'", .{ty.fmt(pt)}),
- .bool,
- .int,
- .float,
- .pointer,
- .array,
- .@"struct",
- .optional,
- .error_union,
- .error_set,
- .@"enum",
- .@"union",
- .vector,
- .frame,
- .@"anyframe",
- => {},
+ .one_possible_value => {
+ assert(ty.abiSize(zcu) == 0);
+ return .zero;
+ },
+
+ .runtime => return .fromValue(try pt.intValue(.comptime_int, ty.abiSize(zcu))),
}
- const val = try ty.abiSizeLazy(pt);
- return Air.internedToRef(val.toIntern());
}
fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -16584,12 +15993,12 @@ fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
.undefined,
.null,
.@"opaque",
+ .type,
+ .enum_literal,
+ .comptime_float,
+ .comptime_int,
=> return sema.fail(block, operand_src, "no size available for type '{f}'", .{operand_ty.fmt(pt)}),
- .type,
- .enum_literal,
- .comptime_float,
- .comptime_int,
.void,
=> return .zero,
@@ -16609,8 +16018,8 @@ fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
.@"anyframe",
=> {},
}
- const bit_size = try operand_ty.bitSizeSema(pt);
- return pt.intRef(.comptime_int, bit_size);
+ try sema.ensureLayoutResolved(operand_ty, operand_src, .size_of);
+ return .fromValue(try pt.intValue(.comptime_int, operand_ty.bitSize(zcu)));
}
fn zirThis(
@@ -16619,34 +16028,7 @@ fn zirThis(
extended: Zir.Inst.Extended.InstData,
) CompileError!Air.Inst.Ref {
_ = extended;
- const pt = sema.pt;
- const zcu = pt.zcu;
- const namespace = pt.zcu.namespacePtr(block.namespace);
-
- switch (pt.zcu.intern_pool.indexToKey(namespace.owner_type)) {
- .opaque_type => {
- // Opaque types are never outdated since they don't undergo type resolution, so nothing to do!
- return Air.internedToRef(namespace.owner_type);
- },
- .struct_type, .union_type => {
- const new_ty = try pt.ensureTypeUpToDate(namespace.owner_type);
- try sema.declareDependency(.{ .interned = new_ty });
- return Air.internedToRef(new_ty);
- },
- .enum_type => {
- const new_ty = try pt.ensureTypeUpToDate(namespace.owner_type);
- try sema.declareDependency(.{ .interned = new_ty });
- // Since this is an enum, it has to be resolved immediately.
- // `ensureTypeUpToDate` has resolved the new type if necessary.
- // We just need to check for resolution failures.
- const ty_unit: AnalUnit = .wrap(.{ .type = new_ty });
- if (zcu.failed_analysis.contains(ty_unit) or zcu.transitive_failed_analysis.contains(ty_unit)) {
- return error.AnalysisFail;
- }
- return Air.internedToRef(new_ty);
- },
- else => unreachable,
- }
+ return .fromIntern(sema.pt.zcu.namespacePtr(block.namespace).owner_type);
}
fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
@@ -16739,7 +16121,7 @@ fn zirRetAddr(
_ = sema;
_ = extended;
if (block.isComptime()) {
- // TODO: we could give a meaningful lazy value here. #14938
+ // TODO: we could give a meaningful value here. #14938
return .zero_usize;
} else {
return block.addNoOp(.ret_addr);
@@ -16882,6 +16264,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const type_info_ty = try sema.getBuiltinType(src, .Type);
const type_info_tag_ty = type_info_ty.unionTagType(zcu).?;
+ try sema.ensureLayoutResolved(ty, src, .type_info);
+
if (ty.typeDeclInst(zcu)) |type_decl_inst| {
try sema.declareDependency(.{ .namespace = type_decl_inst });
}
@@ -16896,7 +16280,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.undefined,
.null,
.enum_literal,
- => |type_info_tag| return unionInitFromEnumTag(sema, block, src, type_info_ty, @intFromEnum(type_info_tag), .void_value),
+ => |type_info_tag| return .fromValue(try pt.unionValue(
+ type_info_ty,
+ Value.uninterpret(type_info_tag, type_info_tag_ty, pt) catch |err| switch (err) {
+ error.TypeMismatch => @panic("std.builtin is corrupt"),
+ error.OutOfMemory => |e| return e,
+ },
+ .void,
+ )),
.@"fn" => {
const fn_info_ty = try sema.getBuiltinType(src, .@"Type.Fn");
@@ -16904,19 +16295,25 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const func_ty_info = zcu.typeToFunc(ty).?;
const param_vals = try sema.arena.alloc(InternPool.Index, func_ty_info.param_types.len);
- for (param_vals, 0..) |*param_val, i| {
- const param_ty = func_ty_info.param_types.get(ip)[i];
+ var func_is_generic = false;
+
+ for (param_vals, 0..) |*param_val, param_index| {
+ const param_ty = func_ty_info.param_types.get(ip)[param_index];
const is_generic = param_ty == .generic_poison_type;
+ const is_noalias, const is_comptime = flags: {
+ const i = std.math.cast(u5, param_index) orelse break :flags .{ false, false };
+ break :flags .{ func_ty_info.paramIsNoalias(i), func_ty_info.paramIsComptime(i) };
+ };
+
+ if (is_generic or is_comptime or Type.fromInterned(param_ty).comptimeOnly(zcu)) {
+ func_is_generic = true;
+ }
+
const param_ty_val = try pt.intern(.{ .opt = .{
.ty = try pt.intern(.{ .opt_type = .type_type }),
.val = if (is_generic) .none else param_ty,
} });
- const is_noalias = blk: {
- const index = std.math.cast(u5, i) orelse break :blk false;
- break :blk @as(u1, @truncate(func_ty_info.noalias_bits >> index)) != 0;
- };
-
const param_fields = .{
// is_generic: bool,
Value.makeBool(is_generic).toIntern(),
@@ -16934,7 +16331,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.child = param_info_ty.toIntern(),
});
const new_decl_val = (try pt.aggregateValue(new_decl_ty, param_vals)).toIntern();
- const slice_ty = (try pt.ptrTypeSema(.{
+ const slice_ty = (try pt.ptrType(.{
.child = param_info_ty.toIntern(),
.flags = .{
.size = .slice,
@@ -16956,18 +16353,23 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
} });
};
+ const ret_ty_is_generic = generic: {
+ const ret_ty: Type = .fromInterned(func_ty_info.return_type);
+ if (ret_ty.toIntern() == .generic_poison_type or
+ (ret_ty.zigTypeTag(zcu) == .error_union and
+ ret_ty.errorUnionPayload(zcu).toIntern() == .generic_poison_type))
+ {
+ break :generic true;
+ }
+ break :generic false;
+ };
+ if (ret_ty_is_generic or Type.fromInterned(func_ty_info.return_type).comptimeOnly(zcu)) {
+ func_is_generic = true;
+ }
+
const ret_ty_opt = try pt.intern(.{ .opt = .{
.ty = try pt.intern(.{ .opt_type = .type_type }),
- .val = opt_val: {
- const ret_ty: Type = .fromInterned(func_ty_info.return_type);
- if (ret_ty.toIntern() == .generic_poison_type) break :opt_val .none;
- if (ret_ty.zigTypeTag(zcu) == .error_union) {
- if (ret_ty.errorUnionPayload(zcu).toIntern() == .generic_poison_type) {
- break :opt_val .none;
- }
- }
- break :opt_val ret_ty.toIntern();
- },
+ .val = if (ret_ty_is_generic) .none else func_ty_info.return_type,
} });
const callconv_ty = try sema.getBuiltinType(src, .CallingConvention);
@@ -16980,7 +16382,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
// calling_convention: CallingConvention,
callconv_val.toIntern(),
// is_generic: bool,
- Value.makeBool(func_ty_info.is_generic).toIntern(),
+ Value.makeBool(func_is_generic).toIntern(),
// is_var_args: bool,
Value.makeBool(func_ty_info.is_var_args).toIntern(),
// return_type: ?type,
@@ -17015,7 +16417,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const field_vals = .{
// bits: u16,
- (try pt.intValue(.u16, ty.bitSize(zcu))).toIntern(),
+ (try pt.intValue(.u16, ty.floatBits(zcu.getTarget()))).toIntern(),
};
return Air.internedToRef((try pt.internUnion(.{
.ty = type_info_ty.toIntern(),
@@ -17025,10 +16427,17 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
},
.pointer => {
const info = ty.ptrInfo(zcu);
- const alignment = if (info.flags.alignment.toByteUnits()) |alignment|
- try pt.intValue(.comptime_int, alignment)
- else
- try Type.fromInterned(info.child).lazyAbiAlignment(pt);
+ const alignment_ty = try pt.optionalType(.usize_type);
+ const alignment_val: Value = val: {
+ const bytes = info.flags.alignment.toByteUnits() orelse {
+ break :val try pt.nullValue(alignment_ty);
+ };
+ const int_val = try pt.intValue(.usize, bytes);
+ break :val .fromInterned(try pt.intern(.{ .opt = .{
+ .ty = alignment_ty.toIntern(),
+ .val = int_val.toIntern(),
+ } }));
+ };
const addrspace_ty = try sema.getBuiltinType(src, .AddressSpace);
const pointer_ty = try sema.getBuiltinType(src, .@"Type.Pointer");
@@ -17041,8 +16450,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
Value.makeBool(info.flags.is_const).toIntern(),
// is_volatile: bool,
Value.makeBool(info.flags.is_volatile).toIntern(),
- // alignment: comptime_int,
- alignment.toIntern(),
+ // alignment: ?usize,
+ alignment_val.toIntern(),
// address_space: AddressSpace
(try pt.enumValueFieldIndex(addrspace_ty, @intFromEnum(info.flags.address_space))).toIntern(),
// child: type,
@@ -17159,7 +16568,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
};
// Build our ?[]const Error value
- const slice_errors_ty = try pt.ptrTypeSema(.{
+ const slice_errors_ty = try pt.ptrType(.{
.child = error_field_ty.toIntern(),
.flags = .{
.size = .slice,
@@ -17215,19 +16624,19 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
})));
},
.@"enum" => {
- const is_exhaustive = Value.makeBool(ip.loadEnumType(ty.toIntern()).tag_mode != .nonexhaustive);
+ const enum_obj = ip.loadEnumType(ty.toIntern());
+ const is_exhaustive: Value = .makeBool(!enum_obj.nonexhaustive);
const enum_field_ty = try sema.getBuiltinType(src, .@"Type.EnumField");
- const enum_field_vals = try sema.arena.alloc(InternPool.Index, ip.loadEnumType(ty.toIntern()).names.len);
+ const enum_field_vals = try sema.arena.alloc(InternPool.Index, enum_obj.field_names.len);
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)
+ const value_val = if (enum_obj.field_values.len > 0)
try ip.getCoercedInts(
gpa,
io,
pt.tid,
- ip.indexToKey(enum_type.values.get(ip)[tag_index]).int,
+ ip.indexToKey(enum_obj.field_values.get(ip)[tag_index]).int,
.comptime_int_type,
)
else
@@ -17235,7 +16644,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
// TODO: write something like getCoercedInts to avoid needing to dupe
const name_val = v: {
- const tag_name = enum_type.names.get(ip)[tag_index];
+ const tag_name = enum_obj.field_names.get(ip)[tag_index];
const tag_name_len = tag_name.length(ip);
const new_decl_ty = try pt.arrayType(.{
.len = tag_name_len,
@@ -17275,7 +16684,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.child = enum_field_ty.toIntern(),
});
const new_decl_val = (try pt.aggregateValue(fields_array_ty, enum_field_vals)).toIntern();
- const slice_ty = (try pt.ptrTypeSema(.{
+ const slice_ty = (try pt.ptrType(.{
.child = enum_field_ty.toIntern(),
.flags = .{
.size = .slice,
@@ -17303,7 +16712,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const field_values = .{
// tag_type: type,
- ip.loadEnumType(ty.toIntern()).tag_ty,
+ ip.loadEnumType(ty.toIntern()).int_tag_type,
// fields: []const EnumField,
fields_val,
// decls: []const Declaration,
@@ -17321,17 +16730,16 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const type_union_ty = try sema.getBuiltinType(src, .@"Type.Union");
const union_field_ty = try sema.getBuiltinType(src, .@"Type.UnionField");
- try ty.resolveLayout(pt); // Getting alignment requires type layout
- const union_obj = zcu.typeToUnion(ty).?;
- const tag_type = union_obj.loadTagType(ip);
- const layout = union_obj.flagsUnordered(ip).layout;
+ const union_obj = ip.loadUnionType(ty.toIntern());
+ const enum_obj = ip.loadEnumType(union_obj.enum_tag_type);
+ const layout = union_obj.layout;
- const union_field_vals = try gpa.alloc(InternPool.Index, tag_type.names.len);
+ const union_field_vals = try gpa.alloc(InternPool.Index, enum_obj.field_names.len);
defer gpa.free(union_field_vals);
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 = enum_obj.field_names.get(ip)[field_index];
const field_name_len = field_name.length(ip);
const new_decl_ty = try pt.arrayType(.{
.len = field_name_len,
@@ -17356,19 +16764,31 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
} });
};
- const alignment = switch (layout) {
- .auto, .@"extern" => try ty.fieldAlignmentSema(field_index, pt),
- .@"packed" => .none,
+ const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);
+
+ const alignment_ty = try pt.optionalType(.usize_type);
+ const alignment_val: Value = val: {
+ const a: Alignment = switch (layout) {
+ .auto, .@"extern" => ty.explicitFieldAlignment(field_index, zcu),
+ .@"packed" => .none,
+ };
+ const bytes = a.toByteUnits() orelse {
+ break :val try pt.nullValue(alignment_ty);
+ };
+ const int_val = try pt.intValue(.usize, bytes);
+ break :val .fromInterned(try pt.intern(.{ .opt = .{
+ .ty = alignment_ty.toIntern(),
+ .val = int_val.toIntern(),
+ } }));
};
- const field_ty = union_obj.field_types.get(ip)[field_index];
const union_field_fields = .{
// name: [:0]const u8,
name_val,
// type: type,
- field_ty,
- // alignment: comptime_int,
- (try pt.intValue(.comptime_int, alignment.toByteUnits() orelse 0)).toIntern(),
+ field_ty.toIntern(),
+ // alignment: ?usize,
+ alignment_val.toIntern(),
};
field_val.* = (try pt.aggregateValue(union_field_ty, &union_field_fields)).toIntern();
}
@@ -17379,7 +16799,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.child = union_field_ty.toIntern(),
});
const new_decl_val = (try pt.aggregateValue(array_fields_ty, union_field_vals)).toIntern();
- const slice_ty = (try pt.ptrTypeSema(.{
+ const slice_ty = (try pt.ptrType(.{
.child = union_field_ty.toIntern(),
.flags = .{
.size = .slice,
@@ -17431,8 +16851,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const type_struct_ty = try sema.getBuiltinType(src, .@"Type.Struct");
const struct_field_ty = try sema.getBuiltinType(src, .@"Type.StructField");
- try ty.resolveLayout(pt); // Getting alignment requires type layout
-
var struct_field_vals: []InternPool.Index = &.{};
defer gpa.free(struct_field_vals);
fv: {
@@ -17468,11 +16886,10 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
} });
};
- try Type.fromInterned(field_ty).resolveLayout(pt);
-
const is_comptime = field_val != .none;
const opt_default_val = if (is_comptime) Value.fromInterned(field_val) else null;
const default_val_ptr = try sema.optRefValue(opt_default_val);
+
const struct_field_fields = .{
// name: [:0]const u8,
name_val,
@@ -17482,8 +16899,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
default_val_ptr.toIntern(),
// is_comptime: bool,
Value.makeBool(is_comptime).toIntern(),
- // alignment: comptime_int,
- (try pt.intValue(.comptime_int, Type.fromInterned(field_ty).abiAlignment(zcu).toByteUnits() orelse 0)).toIntern(),
+ // alignment: ?usize,
+ (try pt.nullValue(try pt.optionalType(.usize_type))).toIntern(),
};
struct_field_val.* = (try pt.aggregateValue(struct_field_ty, &struct_field_fields)).toIntern();
}
@@ -17492,16 +16909,17 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.struct_type => ip.loadStructType(ty.toIntern()),
else => unreachable,
};
+ try sema.ensureStructDefaultsResolved(ty, src); // can't do this sooner, since it's not allowed on tuples
struct_field_vals = try gpa.alloc(InternPool.Index, struct_type.field_types.len);
- try ty.resolveStructFieldInits(pt);
-
for (struct_field_vals, 0..) |*field_val, field_index| {
- const field_name = struct_type.fieldName(ip, field_index);
+ const field_name = struct_type.field_names.get(ip)[field_index];
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 field_default: InternPool.Index = if (struct_type.field_defaults.len > 0) d: {
+ break :d struct_type.field_defaults.get(ip)[field_index];
+ } else .none;
+ const field_is_comptime = struct_type.field_is_comptime_bits.get(ip, field_index);
const name_val = v: {
const new_decl_ty = try pt.arrayType(.{
.len = field_name_len,
@@ -17526,15 +16944,23 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
} });
};
- const opt_default_val = if (field_init == .none) null else Value.fromInterned(field_init);
+ const opt_default_val: ?Value = if (field_default == .none) null else .fromInterned(field_default);
const default_val_ptr = try sema.optRefValue(opt_default_val);
- const alignment = switch (struct_type.layout) {
- .@"packed" => .none,
- else => try field_ty.structFieldAlignmentSema(
- struct_type.fieldAlign(ip, field_index),
- struct_type.layout,
- pt,
- ),
+
+ const alignment_ty = try pt.optionalType(.usize_type);
+ const alignment_val: Value = val: {
+ const a: Alignment = switch (struct_type.layout) {
+ .auto, .@"extern" => ty.explicitFieldAlignment(field_index, zcu),
+ .@"packed" => .none,
+ };
+ const bytes = a.toByteUnits() orelse {
+ break :val try pt.nullValue(alignment_ty);
+ };
+ const int_val = try pt.intValue(.usize, bytes);
+ break :val .fromInterned(try pt.intern(.{ .opt = .{
+ .ty = alignment_ty.toIntern(),
+ .val = int_val.toIntern(),
+ } }));
};
const struct_field_fields = .{
@@ -17546,8 +16972,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
default_val_ptr.toIntern(),
// is_comptime: bool,
Value.makeBool(field_is_comptime).toIntern(),
- // alignment: comptime_int,
- (try pt.intValue(.comptime_int, alignment.toByteUnits() orelse 0)).toIntern(),
+ // alignment: ?usize,
+ alignment_val.toIntern(),
};
field_val.* = (try pt.aggregateValue(struct_field_ty, &struct_field_fields)).toIntern();
}
@@ -17559,7 +16985,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.child = struct_field_ty.toIntern(),
});
const new_decl_val = (try pt.aggregateValue(array_fields_ty, struct_field_vals)).toIntern();
- const slice_ty = (try pt.ptrTypeSema(.{
+ const slice_ty = (try pt.ptrType(.{
.child = struct_field_ty.toIntern(),
.flags = .{
.size = .slice,
@@ -17585,9 +17011,9 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const backing_integer_val = try pt.intern(.{ .opt = .{
.ty = (try pt.optionalType(.type_type)).toIntern(),
- .val = if (zcu.typeToPackedStruct(ty)) |packed_struct| val: {
- assert(Type.fromInterned(packed_struct.backingIntTypeUnordered(ip)).isInt(zcu));
- break :val packed_struct.backingIntTypeUnordered(ip);
+ .val = if (zcu.typeToPackedStruct(ty)) |struct_obj| val: {
+ assert(Type.fromInterned(struct_obj.packed_backing_int_type).isInt(zcu));
+ break :val struct_obj.packed_backing_int_type;
} else .none,
} });
@@ -17616,7 +17042,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.@"opaque" => {
const type_opaque_ty = try sema.getBuiltinType(src, .@"Type.Opaque");
- try ty.resolveFields(pt);
const decls_val = try sema.typeInfoDecls(src, ty.getNamespace(zcu));
const field_values = .{
@@ -17658,7 +17083,7 @@ fn typeInfoDecls(
.child = declaration_ty.toIntern(),
});
const new_decl_val = (try pt.aggregateValue(array_decl_ty, decl_vals.items)).toIntern();
- const slice_ty = (try pt.ptrTypeSema(.{
+ const slice_ty = (try pt.ptrType(.{
.child = declaration_ty.toIntern(),
.flags = .{
.size = .slice,
@@ -17740,7 +17165,7 @@ fn zirTypeof(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
_ = block;
const zir_datas = sema.code.instructions.items(.data);
const inst_data = zir_datas[@intFromEnum(inst)].un_node;
- const operand = try sema.resolveInst(inst_data.operand);
+ const operand = sema.resolveInst(inst_data.operand);
const operand_ty = sema.typeOf(operand);
return Air.internedToRef(operand_ty.toIntern());
}
@@ -17754,7 +17179,7 @@ fn zirTypeofBuiltin(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
.parent = block,
.sema = sema,
.namespace = block.namespace,
- .instructions = .{},
+ .instructions = .empty,
.inlining = block.inlining,
.comptime_reason = null,
.is_typeof = true,
@@ -17772,7 +17197,7 @@ fn zirTypeofBuiltin(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
fn zirTypeofLog2IntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const src = block.nodeOffset(inst_data.src_node);
- const operand = try sema.resolveInst(inst_data.operand);
+ const operand = sema.resolveInst(inst_data.operand);
const operand_ty = sema.typeOf(operand);
const res_ty = try sema.log2IntType(block, operand_ty, src);
return Air.internedToRef(res_ty.toIntern());
@@ -17783,22 +17208,12 @@ fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) Compi
const zcu = pt.zcu;
switch (operand.zigTypeTag(zcu)) {
.comptime_int => return .comptime_int,
- .int => {
- const bits = operand.bitSize(zcu);
- const count = if (bits == 0)
- 0
- else blk: {
- var count: u16 = 0;
- var s = bits - 1;
- while (s != 0) : (s >>= 1) {
- count += 1;
- }
- break :blk count;
- };
- return pt.intType(.unsigned, count);
- },
+ .int => return pt.intType(.unsigned, switch (operand.intInfo(zcu).bits) {
+ 0 => 0,
+ else => |b| std.math.log2_int_ceil(u16, b),
+ }),
.vector => {
- const elem_ty = operand.elemType2(zcu);
+ const elem_ty = operand.childType(zcu);
const log2_elem_ty = try sema.log2IntType(block, elem_ty, src);
return pt.vectorType(.{
.len = operand.vectorLen(zcu),
@@ -17832,7 +17247,7 @@ fn zirTypeofPeer(
.parent = block,
.sema = sema,
.namespace = block.namespace,
- .instructions = .{},
+ .instructions = .empty,
.inlining = block.inlining,
.comptime_reason = null,
.is_typeof = true,
@@ -17852,7 +17267,7 @@ fn zirTypeofPeer(
defer sema.gpa.free(inst_list);
for (args, 0..) |arg_ref, i| {
- inst_list[i] = try sema.resolveInst(arg_ref);
+ inst_list[i] = sema.resolveInst(arg_ref);
}
const result_type = try sema.resolvePeerTypes(block, src, inst_list, .{ .typeof_builtin_call_node_offset = extra.data.src_node });
@@ -17865,7 +17280,7 @@ fn zirBoolNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const src = block.nodeOffset(inst_data.src_node);
const operand_src = block.src(.{ .node_offset_un_op = inst_data.src_node });
- const uncasted_operand = try sema.resolveInst(inst_data.operand);
+ const uncasted_operand = sema.resolveInst(inst_data.operand);
const uncasted_ty = sema.typeOf(uncasted_operand);
if (uncasted_ty.isVector(zcu)) {
if (uncasted_ty.scalarType(zcu).zigTypeTag(zcu) != .bool) {
@@ -17876,7 +17291,7 @@ fn zirBoolNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
return analyzeBitNot(sema, block, uncasted_operand, src);
}
const operand = try sema.coerce(block, .bool, uncasted_operand, operand_src);
- if (try sema.resolveValue(operand)) |val| {
+ if (sema.resolveValue(operand)) |val| {
return if (val.isUndef(zcu)) .undef_bool else if (val.toBool()) .bool_false else .bool_true;
}
try sema.requireRuntimeBlock(block, src, null);
@@ -17900,7 +17315,7 @@ fn zirBoolBr(
const inst_data = datas[@intFromEnum(inst)].pl_node;
const extra = sema.code.extraData(Zir.Inst.BoolBr, inst_data.payload_index);
- const uncoerced_lhs = try sema.resolveInst(extra.data.lhs);
+ const uncoerced_lhs = sema.resolveInst(extra.data.lhs);
const body = sema.code.bodySlice(extra.end, extra.data.body_len);
const lhs_src = parent_block.src(.{ .node_offset_bin_lhs = inst_data.src_node });
const rhs_src = parent_block.src(.{ .node_offset_bin_rhs = inst_data.src_node });
@@ -18063,9 +17478,9 @@ fn zirIsNonNull(
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const src = block.nodeOffset(inst_data.src_node);
- const operand = try sema.resolveInst(inst_data.operand);
+ const operand = sema.resolveInst(inst_data.operand);
try sema.checkNullableType(block, src, sema.typeOf(operand));
- return sema.analyzeIsNull(block, operand, true);
+ return sema.analyzeIsNull(block, src, operand, true);
}
fn zirIsNonNullPtr(
@@ -18080,17 +17495,23 @@ fn zirIsNonNullPtr(
const zcu = pt.zcu;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const src = block.nodeOffset(inst_data.src_node);
- const ptr = try sema.resolveInst(inst_data.operand);
+ const ptr = sema.resolveInst(inst_data.operand);
const ptr_ty = sema.typeOf(ptr);
- try sema.checkNullableType(block, src, sema.typeOf(ptr).elemType2(zcu));
- if (try sema.resolveValue(ptr)) |ptr_val| {
- if (try sema.pointerDeref(block, src, ptr_val, ptr_ty)) |loaded_val| {
- return sema.analyzeIsNull(block, Air.internedToRef(loaded_val.toIntern()), true);
+ assert(ptr_ty.zigTypeTag(zcu) == .pointer);
+ const nullable_ty = ptr_ty.childType(zcu);
+
+ try sema.checkNullableType(block, src, nullable_ty);
+
+ if (try sema.resolveIsNullFromType(block, src, nullable_ty)) |is_null| {
+ return .fromValue(.makeBool(!is_null));
+ }
+
+ if (sema.resolveValue(ptr)) |ptr_val| {
+ if (try sema.pointerDeref(block, src, ptr_val, ptr_ty)) |nullable_val| {
+ return sema.analyzeIsNull(block, src, .fromValue(nullable_val), true);
}
}
- if (ptr_ty.childType(zcu).isNullFromType(zcu)) |is_null| {
- return if (is_null) .bool_false else .bool_true;
- }
+
return block.addUnOp(.is_non_null_ptr, ptr);
}
@@ -18111,7 +17532,7 @@ fn zirIsNonErr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const src = block.nodeOffset(inst_data.src_node);
- const operand = try sema.resolveInst(inst_data.operand);
+ const operand = sema.resolveInst(inst_data.operand);
try sema.checkErrorType(block, src, sema.typeOf(operand));
return sema.analyzeIsNonErr(block, src, operand);
}
@@ -18124,8 +17545,11 @@ fn zirIsNonErrPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
const zcu = pt.zcu;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const src = block.nodeOffset(inst_data.src_node);
- const ptr = try sema.resolveInst(inst_data.operand);
- try sema.checkErrorType(block, src, sema.typeOf(ptr).elemType2(zcu));
+ const ptr = sema.resolveInst(inst_data.operand);
+ const ptr_ty = sema.typeOf(ptr);
+ assert(ptr_ty.zigTypeTag(zcu) == .pointer);
+ const error_ty = ptr_ty.childType(zcu);
+ try sema.checkErrorType(block, src, error_ty);
const loaded = try sema.analyzeLoad(block, src, ptr, src);
return sema.analyzeIsNonErr(block, src, loaded);
}
@@ -18136,7 +17560,7 @@ fn zirRetIsNonErr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const src = block.nodeOffset(inst_data.src_node);
- const operand = try sema.resolveInst(inst_data.operand);
+ const operand = sema.resolveInst(inst_data.operand);
return sema.analyzeIsNonErr(block, src, operand);
}
@@ -18157,7 +17581,7 @@ fn zirCondbr(
const then_body = sema.code.bodySlice(extra.end, extra.data.then_body_len);
const else_body = sema.code.bodySlice(extra.end + then_body.len, extra.data.else_body_len);
- const uncasted_cond = try sema.resolveInst(extra.data.condition);
+ const uncasted_cond = sema.resolveInst(extra.data.condition);
const cond = try sema.coerce(parent_block, .bool, uncasted_cond, cond_src);
if (try sema.resolveDefinedValue(parent_block, cond_src, cond)) |cond_val| {
@@ -18193,7 +17617,7 @@ fn zirCondbr(
if (sema.code.instructions.items(.tag)[@intFromEnum(index)] != .is_non_err) break :blk null;
const err_inst_data = sema.code.instructions.items(.data)[@intFromEnum(index)].un_node;
- const err_operand = try sema.resolveInst(err_inst_data.operand);
+ const err_operand = sema.resolveInst(err_inst_data.operand);
const operand_ty = sema.typeOf(err_operand);
assert(operand_ty.zigTypeTag(zcu) == .error_union);
const result_ty = operand_ty.errorUnionSet(zcu);
@@ -18241,7 +17665,7 @@ fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!
const operand_src = parent_block.src(.{ .node_offset_try_operand = inst_data.src_node });
const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);
const body = sema.code.bodySlice(extra.end, extra.data.body_len);
- const err_union = try sema.resolveInst(extra.data.operand);
+ const err_union = sema.resolveInst(extra.data.operand);
const err_union_ty = sema.typeOf(err_union);
const pt = sema.pt;
const zcu = pt.zcu;
@@ -18294,6 +17718,11 @@ fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!
} },
});
sema.air_extra.appendSliceAssumeCapacity(@ptrCast(sub_block.instructions.items));
+
+ // The payload type might still be OPV, in which case `try_inst` is just there for the runtime
+ // control flow and we should return a comptime-known result.
+ if (try err_union_ty.errorUnionPayload(zcu).onePossibleValue(pt)) |opv| return .fromValue(opv);
+
return try_inst;
}
@@ -18303,7 +17732,7 @@ fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErr
const operand_src = parent_block.src(.{ .node_offset_try_operand = inst_data.src_node });
const extra = sema.code.extraData(Zir.Inst.Try, inst_data.payload_index);
const body = sema.code.bodySlice(extra.end, extra.data.body_len);
- const operand = try sema.resolveInst(extra.data.operand);
+ const operand = sema.resolveInst(extra.data.operand);
const err_union = try sema.analyzeLoad(parent_block, src, operand, operand_src);
const err_union_ty = sema.typeOf(err_union);
const pt = sema.pt;
@@ -18347,7 +17776,7 @@ fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErr
const operand_ty = sema.typeOf(operand);
const ptr_info = operand_ty.ptrInfo(zcu);
- const res_ty = try pt.ptrTypeSema(.{
+ const res_ty = try pt.ptrType(.{
.child = err_union_ty.errorUnionPayload(zcu).toIntern(),
.flags = .{
.is_const = ptr_info.flags.is_const,
@@ -18396,9 +17825,9 @@ fn ensurePostHoc(sema: *Sema, block: *Block, dest_block: Zir.Inst.Index) !*Label
.label = .{
.zir_block = dest_block,
.merges = .{
- .src_locs = .{},
- .results = .{},
- .br_list = .{},
+ .src_locs = .empty,
+ .results = .empty,
+ .br_list = .empty,
.block_inst = new_block_inst,
},
},
@@ -18406,7 +17835,7 @@ fn ensurePostHoc(sema: *Sema, block: *Block, dest_block: Zir.Inst.Index) !*Label
.parent = block,
.sema = sema,
.namespace = block.namespace,
- .instructions = .{},
+ .instructions = .empty,
.label = &labeled_block.label,
.inlining = block.inlining,
.comptime_reason = block.comptime_reason,
@@ -18424,7 +17853,7 @@ fn ensurePostHoc(sema: *Sema, block: *Block, dest_block: Zir.Inst.Index) !*Label
fn addRuntimeBreak(sema: *Sema, child_block: *Block, block_inst: Zir.Inst.Index, break_operand: Zir.Inst.Ref) !void {
const labeled_block = try sema.ensurePostHoc(child_block, block_inst);
- const operand = try sema.resolveInst(break_operand);
+ const operand = sema.resolveInst(break_operand);
const br_ref = try child_block.addBr(labeled_block.label.merges.block_inst, operand);
try labeled_block.label.merges.results.append(sema.gpa, operand);
@@ -18510,9 +17939,9 @@ fn zirRetImplicit(
return;
}
- const operand = try sema.resolveInst(inst_data.operand);
+ const operand = sema.resolveInst(inst_data.operand);
const ret_ty_src = block.src(.{ .node_offset_fn_type_ret_ty = .zero });
- const base_tag = sema.fn_ret_ty.baseZigTypeTag(zcu);
+ const base_tag = sema.fn_ret_ty.optEuBaseType(zcu).zigTypeTag(zcu);
if (base_tag == .noreturn) {
const msg = msg: {
const msg = try sema.errMsg(ret_ty_src, "function declared '{f}' implicitly returns", .{
@@ -18543,7 +17972,7 @@ fn zirRetNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!voi
defer tracy.end();
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
- const operand = try sema.resolveInst(inst_data.operand);
+ const operand = sema.resolveInst(inst_data.operand);
const src = block.nodeOffset(inst_data.src_node);
return sema.analyzeRet(block, operand, src, block.src(.{ .node_offset_return_operand = inst_data.src_node }));
@@ -18555,7 +17984,7 @@ fn zirRetLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!voi
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const src = block.nodeOffset(inst_data.src_node);
- const ret_ptr = try sema.resolveInst(inst_data.operand);
+ const ret_ptr = sema.resolveInst(inst_data.operand);
if (block.isComptime() or block.inlining != null or sema.func_is_naked) {
const operand = try sema.analyzeLoad(block, src, ret_ptr, src);
@@ -18652,7 +18081,7 @@ fn zirSaveErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
if (block.isComptime() or block.is_typeof) return;
const save_index = inst_data.operand == .none or b: {
- const operand = try sema.resolveInst(inst_data.operand);
+ const operand = sema.resolveInst(inst_data.operand);
const operand_ty = sema.typeOf(operand);
break :b operand_ty.isError(zcu);
};
@@ -18701,7 +18130,7 @@ fn restoreErrRetIndex(sema: *Sema, start_block: *Block, src: LazySrcLoc, target_
return; // No need to restore
};
- const operand = try sema.resolveInstAllowNone(operand_zir);
+ const operand = sema.resolveInstAllowNone(operand_zir);
if (start_block.isComptime() or start_block.is_typeof) {
const is_non_error = if (operand != .none) blk: {
@@ -18809,8 +18238,6 @@ fn analyzeRet(
return sema.failWithOwnedErrorMsg(block, msg);
}
- try sema.fn_ret_ty.resolveLayout(pt);
-
try sema.validateRuntimeValue(block, operand_src, operand);
const air_tag: Air.Inst.Tag = if (block.wantSafety()) .ret_safe else .ret;
@@ -18853,8 +18280,8 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
const hostsize_src = block.src(.{ .node_offset_ptr_hostsize = extra.data.src_node });
const elem_ty = blk: {
- const air_inst = try sema.resolveInst(extra.data.elem_type);
- const ty = sema.analyzeAsType(block, elem_ty_src, air_inst) catch |err| {
+ const air_inst = sema.resolveInst(extra.data.elem_type);
+ const ty = sema.analyzeAsType(block, elem_ty_src, .type, air_inst) catch |err| {
if (err == error.AnalysisFail and sema.err != null and sema.typeOf(air_inst).isSinglePointer(zcu)) {
try sema.errNote(elem_ty_src, sema.err.?, "use '.*' to dereference pointer", .{});
}
@@ -18874,7 +18301,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
const sentinel = if (inst_data.flags.has_sentinel) blk: {
const ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_i]);
extra_i += 1;
- const coerced = try sema.coerce(block, elem_ty, try sema.resolveInst(ref), sentinel_src);
+ const coerced = try sema.coerce(block, elem_ty, sema.resolveInst(ref), sentinel_src);
const val = try sema.resolveConstDefinedValue(block, sentinel_src, coerced, .{ .simple = .pointer_sentinel });
try checkSentinelType(sema, block, sentinel_src, elem_ty);
if (val.canMutateComptimeVarState(zcu)) {
@@ -18887,18 +18314,9 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
const abi_align: Alignment = if (inst_data.flags.has_align) blk: {
const ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_i]);
extra_i += 1;
- const coerced = try sema.coerce(block, align_ty, try sema.resolveInst(ref), align_src);
+ const coerced = try sema.coerce(block, align_ty, sema.resolveInst(ref), align_src);
const val = try sema.resolveConstDefinedValue(block, align_src, coerced, .{ .simple = .@"align" });
- // Check if this happens to be the lazy alignment of our element type, in
- // which case we can make this 0 without resolving it.
- switch (zcu.intern_pool.indexToKey(val.toIntern())) {
- .int => |int| switch (int.storage) {
- .lazy_align => |lazy_ty| if (lazy_ty == elem_ty.toIntern()) break :blk .none,
- else => {},
- },
- else => {},
- }
- const align_bytes = (try val.getUnsignedIntSema(pt)).?;
+ const align_bytes = val.toUnsignedInt(zcu);
break :blk try sema.validateAlign(block, align_src, align_bytes);
} else .none;
@@ -18928,7 +18346,8 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
elem_ty.fmt(pt), bit_offset, bit_offset - host_size * 8, host_size,
});
}
- const elem_bit_size = try elem_ty.bitSizeSema(pt);
+ try sema.ensureLayoutResolved(elem_ty, elem_ty_src, .bit_ptr_child);
+ const elem_bit_size = elem_ty.bitSize(zcu);
if (elem_bit_size > host_size * 8 - bit_offset) {
return sema.fail(block, bitoffset_src, "packed type '{f}' at bit offset {d} ends {d} bits after the end of a {d} byte host integer", .{
elem_ty.fmt(pt), bit_offset, elem_bit_size - (host_size * 8 - bit_offset), host_size,
@@ -18942,31 +18361,18 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
}
} else if (inst_data.size != .one and elem_ty.zigTypeTag(zcu) == .@"opaque") {
return sema.fail(block, elem_ty_src, "indexable pointer to opaque type '{f}' not allowed", .{elem_ty.fmt(pt)});
- } else if (inst_data.size == .c) {
- if (!try sema.validateExternType(elem_ty, .other)) {
- const msg = msg: {
- const msg = try sema.errMsg(elem_ty_src, "C pointers cannot point to non-C-ABI-compatible type '{f}'", .{elem_ty.fmt(pt)});
- errdefer msg.destroy(sema.gpa);
-
- try sema.explainWhyTypeIsNotExtern(msg, elem_ty_src, elem_ty, .other);
-
- try sema.addDeclaredHereNote(msg, elem_ty);
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(block, msg);
- }
}
- if (host_size != 0 and !try sema.validatePackedType(elem_ty)) {
- return sema.failWithOwnedErrorMsg(block, msg: {
+ if (host_size != 0) {
+ if (elem_ty.unpackable(zcu)) |reason| return sema.failWithOwnedErrorMsg(block, msg: {
const msg = try sema.errMsg(elem_ty_src, "bit-pointer cannot refer to value of type '{f}'", .{elem_ty.fmt(pt)});
errdefer msg.destroy(sema.gpa);
- try sema.explainWhyTypeIsNotPacked(msg, elem_ty_src, elem_ty);
+ try sema.explainWhyTypeIsUnpackable(msg, elem_ty_src, reason);
break :msg msg;
});
}
- const ty = try pt.ptrTypeSema(.{
+ const ty = try pt.ptrType(.{
.child = elem_ty.toIntern(),
.sentinel = sentinel,
.flags = .{
@@ -18996,6 +18402,8 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
const pt = sema.pt;
const zcu = pt.zcu;
+ try sema.ensureLayoutResolved(obj_ty, ty_src, .init);
+
switch (obj_ty.zigTypeTag(zcu)) {
.@"struct" => return sema.structInitEmpty(block, obj_ty, src, src),
.array, .vector => return sema.arrayInitEmpty(block, src, obj_ty),
@@ -19058,6 +18466,9 @@ fn zirStructInitEmptyResult(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is
.child = ptr_ty.childType(zcu).toIntern(),
});
} else ty_operand;
+
+ try sema.ensureLayoutResolved(init_ty, src, .init);
+
const obj_ty = init_ty.optEuBaseType(zcu);
const empty_ref = switch (obj_ty.zigTypeTag(zcu)) {
@@ -19069,13 +18480,13 @@ fn zirStructInitEmptyResult(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is
const init_ref = try sema.coerce(block, init_ty, empty_ref, src);
if (is_byref) {
- const init_val = (try sema.resolveValue(init_ref)).?;
- return sema.uavRef(init_val.toIntern());
+ return sema.uavRef(sema.resolveValue(init_ref).?);
} else {
return init_ref;
}
}
+/// Asserts that the layout of `struct_ty` is already resolved.
fn structInitEmpty(
sema: *Sema,
block: *Block,
@@ -19087,7 +18498,7 @@ fn structInitEmpty(
const zcu = pt.zcu;
const gpa = sema.gpa;
// This logic must be synchronized with that in `zirStructInit`.
- try struct_ty.resolveFields(pt);
+ struct_ty.assertHasLayout(zcu);
// The init values to use for the struct instance.
const field_inits = try gpa.alloc(Air.Inst.Ref, struct_ty.structFieldCount(zcu));
@@ -19118,63 +18529,36 @@ fn arrayInitEmpty(sema: *Sema, block: *Block, src: LazySrcLoc, obj_ty: Type) Com
fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const pt = sema.pt;
+ const zcu = pt.zcu;
+ const ip = &zcu.intern_pool;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const ty_src = block.builtinCallArgSrc(inst_data.src_node, 0);
const field_src = block.builtinCallArgSrc(inst_data.src_node, 1);
- const init_src = block.builtinCallArgSrc(inst_data.src_node, 2);
+ const payload_src = block.builtinCallArgSrc(inst_data.src_node, 2);
const extra = sema.code.extraData(Zir.Inst.UnionInit, inst_data.payload_index).data;
const union_ty = try sema.resolveType(block, ty_src, extra.union_type);
if (union_ty.zigTypeTag(pt.zcu) != .@"union") {
return sema.fail(block, ty_src, "expected union type, found '{f}'", .{union_ty.fmt(pt)});
}
+ union_ty.assertHasLayout(zcu); // from a previous `field_type_ref` instruction
const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, .{ .simple = .union_field_names });
- const init = try sema.resolveInst(extra.init);
- return sema.unionInit(block, init, init_src, union_ty, ty_src, field_name, field_src);
-}
-
-fn unionInit(
- sema: *Sema,
- block: *Block,
- uncasted_init: Air.Inst.Ref,
- init_src: LazySrcLoc,
- union_ty: Type,
- union_ty_src: LazySrcLoc,
- field_name: InternPool.NullTerminatedString,
- field_src: LazySrcLoc,
-) CompileError!Air.Inst.Ref {
- const pt = sema.pt;
- const zcu = pt.zcu;
- const ip = &zcu.intern_pool;
const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src);
const field_ty: Type = .fromInterned(zcu.typeToUnion(union_ty).?.field_types.get(ip)[field_index]);
- const init = try sema.coerce(block, field_ty, uncasted_init, init_src);
- _ = union_ty_src;
- return unionInitFromEnumTag(sema, block, init_src, union_ty, field_index, init);
-}
-fn unionInitFromEnumTag(
- sema: *Sema,
- block: *Block,
- init_src: LazySrcLoc,
- union_ty: Type,
- field_index: u32,
- init: Air.Inst.Ref,
-) !Air.Inst.Ref {
- const pt = sema.pt;
- const zcu = pt.zcu;
+ const payload = try sema.coerce(block, field_ty, sema.resolveInst(extra.init), payload_src);
- if (try sema.resolveValue(init)) |init_val| {
+ if (union_ty.containerLayout(zcu) == .@"packed") {
+ return sema.bitCast(block, union_ty, payload, block.nodeOffset(inst_data.src_node), payload_src);
+ }
+
+ if (sema.resolveValue(payload)) |payload_val| {
const tag_ty = union_ty.unionTagTypeHypothetical(zcu);
const tag_val = try pt.enumValueFieldIndex(tag_ty, field_index);
- return Air.internedToRef((try pt.internUnion(.{
- .ty = union_ty.toIntern(),
- .tag = tag_val.toIntern(),
- .val = init_val.toIntern(),
- })));
+ return .fromValue(try pt.unionValue(union_ty, tag_val, payload_val));
}
- try sema.requireRuntimeBlock(block, init_src, null);
- return block.addUnionInit(union_ty, field_index, init);
+ try sema.requireRuntimeBlock(block, payload_src, null);
+ return block.addUnionInit(union_ty, field_index, payload);
}
fn zirStructInit(
@@ -19202,8 +18586,8 @@ fn zirStructInit(
// The type wasn't actually known, so treat this as an anon struct init.
return sema.structInitAnon(block, src, inst, .typed_init, extra.data, extra.end, is_ref);
};
+ try sema.ensureLayoutResolved(result_ty, src, .init);
const resolved_ty = result_ty.optEuBaseType(zcu);
- try resolved_ty.resolveLayout(pt);
if (resolved_ty.zigTypeTag(zcu) == .@"struct") {
// This logic must be synchronized with that in `zirStructInitEmpty`.
@@ -19226,7 +18610,6 @@ fn zirStructInit(
var field_i: u32 = 0;
var extra_index = extra.end;
- const is_packed = resolved_ty.containerLayout(zcu) == .@"packed";
while (field_i < extra.data.fields_len) : (field_i += 1) {
const item = sema.code.extraData(Zir.Inst.StructInit.Item, extra_index);
extra_index = item.end;
@@ -19248,19 +18631,16 @@ fn zirStructInit(
assert(field_inits[field_index] == .none);
field_assign_idxs[field_index] = field_i;
found_fields[field_index] = item.data.field_type;
- const uncoerced_init = try sema.resolveInst(item.data.init);
+ const uncoerced_init = sema.resolveInst(item.data.init);
const field_ty = resolved_ty.fieldType(field_index, zcu);
field_inits[field_index] = try sema.coerce(block, field_ty, uncoerced_init, field_src);
- if (!is_packed) {
- try resolved_ty.resolveStructFieldInits(pt);
- if (try resolved_ty.structFieldValueComptime(pt, field_index)) |default_value| {
- const init_val = (try sema.resolveValue(field_inits[field_index])) orelse {
- return sema.failWithNeededComptime(block, field_src, .{ .simple = .stored_to_comptime_field });
- };
-
- if (!init_val.eql(default_value, resolved_ty.fieldType(field_index, zcu), zcu)) {
- return sema.failWithInvalidComptimeFieldStore(block, field_src, resolved_ty, field_index);
- }
+ if (resolved_ty.structFieldIsComptime(field_index, zcu)) {
+ const default_value = (try resolved_ty.structFieldValueComptime(pt, field_index)).?;
+ const init_val = sema.resolveValue(field_inits[field_index]) orelse {
+ return sema.failWithNeededComptime(block, field_src, .{ .simple = .stored_to_comptime_field });
+ };
+ if (!init_val.eql(default_value, resolved_ty.fieldType(field_index, zcu), zcu)) {
+ return sema.failWithInvalidComptimeFieldStore(block, field_src, resolved_ty, field_index);
}
}
}
@@ -19288,9 +18668,9 @@ fn zirStructInit(
const tag_val = try pt.enumValueFieldIndex(tag_ty, field_index);
const field_ty: Type = .fromInterned(zcu.typeToUnion(resolved_ty).?.field_types.get(ip)[field_index]);
- if (field_ty.zigTypeTag(zcu) == .noreturn) {
+ if (field_ty.classify(zcu) == .no_possible_value) {
return sema.failWithOwnedErrorMsg(block, msg: {
- const msg = try sema.errMsg(src, "cannot initialize 'noreturn' field of union", .{});
+ const msg = try sema.errMsg(src, "cannot initialize union field with uninstantiable type '{f}'", .{field_ty.fmt(pt)});
errdefer msg.destroy(sema.gpa);
try sema.addFieldErrNote(resolved_ty, field_index, msg, "field '{f}' declared here", .{
@@ -19301,21 +18681,31 @@ fn zirStructInit(
});
}
- const uncoerced_init_inst = try sema.resolveInst(item.data.init);
+ const uncoerced_init_inst = sema.resolveInst(item.data.init);
const init_inst = try sema.coerce(block, field_ty, uncoerced_init_inst, field_src);
- if (try sema.resolveValue(init_inst)) |val| {
+ if (resolved_ty.containerLayout(zcu) == .@"packed") {
+ const union_val = try sema.bitCast(block, resolved_ty, init_inst, src, field_src);
+ const result_val = try sema.coerce(block, result_ty, union_val, src);
+ if (is_ref) {
+ return sema.analyzeRef(block, src, result_val, .none);
+ } else {
+ return result_val;
+ }
+ }
+
+ if (sema.resolveValue(init_inst)) |val| {
const struct_val = Value.fromInterned(try pt.internUnion(.{
.ty = resolved_ty.toIntern(),
.tag = tag_val.toIntern(),
.val = val.toIntern(),
}));
const final_val_inst = try sema.coerce(block, result_ty, Air.internedToRef(struct_val.toIntern()), src);
- const final_val = (try sema.resolveValue(final_val_inst)).?;
- return sema.addConstantMaybeRef(final_val.toIntern(), is_ref);
+ const final_val = sema.resolveValue(final_val_inst).?;
+ return sema.addConstantMaybeRef(final_val, is_ref);
}
- if (try resolved_ty.comptimeOnlySema(pt)) {
+ if (resolved_ty.comptimeOnly(zcu)) {
return sema.failWithNeededComptime(block, field_src, .{ .comptime_only = .{
.ty = resolved_ty,
.msg = .union_init,
@@ -19326,7 +18716,7 @@ fn zirStructInit(
if (is_ref) {
const target = zcu.getTarget();
- const alloc_ty = try pt.ptrTypeSema(.{
+ const alloc_ty = try pt.ptrType(.{
.child = result_ty.toIntern(),
.flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
});
@@ -19334,10 +18724,6 @@ fn zirStructInit(
const base_ptr = try sema.optEuBasePtrInit(block, alloc, src);
const field_ptr = try sema.unionFieldPtr(block, field_src, base_ptr, field_name, field_src, resolved_ty, true);
try sema.storePtr(block, src, field_ptr, init_inst);
- if ((try sema.typeHasOnePossibleValue(tag_ty)) == null) {
- const new_tag = Air.internedToRef(tag_val.toIntern());
- _ = try block.addBinOp(.set_union_tag, base_ptr, new_tag);
- }
return sema.makePtrConst(block, alloc);
}
@@ -19409,20 +18795,29 @@ fn finishStructInit(
continue;
}
- try struct_ty.resolveStructFieldInits(pt);
+ if (struct_type.field_is_comptime_bits.get(ip, i)) {
+ field_inits[i] = .fromIntern(struct_type.field_defaults.get(ip)[i]);
+ continue;
+ }
- const field_init = struct_type.fieldInit(ip, i);
- if (field_init == .none) {
- const field_name = struct_type.field_names.get(ip)[i];
- const template = "missing struct field: {f}";
- const args = .{field_name.fmt(ip)};
- if (root_msg) |msg| {
- try sema.errNote(init_src, msg, template, args);
- } else {
- root_msg = try sema.errMsg(init_src, template, args);
- }
+ try sema.ensureStructDefaultsResolved(struct_ty, init_src);
+
+ const field_default: InternPool.Index = d: {
+ if (struct_type.field_defaults.len == 0) break :d .none;
+ break :d struct_type.field_defaults.get(ip)[i];
+ };
+ if (field_default != .none) {
+ field_inits[i] = .fromIntern(field_default);
+ continue;
+ }
+
+ const field_name = struct_type.field_names.get(ip)[i];
+ const template = "missing struct field: {f}";
+ const args = .{field_name.fmt(ip)};
+ if (root_msg) |msg| {
+ try sema.errNote(init_src, msg, template, args);
} else {
- field_inits[i] = Air.internedToRef(field_init);
+ root_msg = try sema.errMsg(init_src, template, args);
}
}
},
@@ -19442,18 +18837,38 @@ fn finishStructInit(
}
} else null;
- const runtime_index = opt_runtime_index orelse {
- const elems = try sema.arena.alloc(InternPool.Index, field_inits.len);
- for (elems, field_inits) |*elem, field_init| {
- elem.* = (sema.resolveValue(field_init) catch unreachable).?.toIntern();
- }
- const struct_val = try pt.aggregateValue(struct_ty, elems);
- const final_val_inst = try sema.coerce(block, result_ty, Air.internedToRef(struct_val.toIntern()), init_src);
- const final_val = (try sema.resolveValue(final_val_inst)).?;
- return sema.addConstantMaybeRef(final_val.toIntern(), is_ref);
+ const runtime_index = opt_runtime_index orelse switch (struct_ty.containerLayout(zcu)) {
+ .auto, .@"extern" => {
+ const elems = try sema.arena.alloc(InternPool.Index, field_inits.len);
+ for (elems, field_inits) |*elem, field_init| {
+ elem.* = sema.resolveValue(field_init).?.toIntern();
+ }
+ const struct_val = try pt.aggregateValue(struct_ty, elems);
+ const final_val_ref = try sema.coerce(block, result_ty, .fromValue(struct_val), init_src);
+ return sema.addConstantMaybeRef(sema.resolveValue(final_val_ref).?, is_ref);
+ },
+ .@"packed" => {
+ const buf = try sema.arena.alloc(u8, @intCast((struct_ty.bitSize(zcu) + 7) / 8));
+ var bit_offset: u16 = 0;
+ for (field_inits) |field_init| {
+ const field_val = sema.resolveValue(field_init).?;
+ field_val.writeToPackedMemory(pt, buf, bit_offset) catch |err| switch (err) {
+ error.ReinterpretDeclRef => unreachable, // bitpack fields cannot be pointers
+ error.OutOfMemory => |e| return e,
+ };
+ bit_offset += @intCast(field_val.typeOf(zcu).bitSize(zcu));
+ }
+ assert(bit_offset == struct_ty.bitSize(zcu));
+ const struct_val = Value.readFromPackedMemory(struct_ty, pt, buf, 0, sema.arena) catch |err| switch (err) {
+ error.IllDefinedMemoryLayout => unreachable, // bitpacks have well-defined layout
+ error.OutOfMemory => |e| return e,
+ };
+ const final_val_ref = try sema.coerce(block, result_ty, .fromValue(struct_val), init_src);
+ return sema.addConstantMaybeRef(sema.resolveValue(final_val_ref).?, is_ref);
+ },
};
- if (try struct_ty.comptimeOnlySema(pt)) {
+ if (struct_ty.comptimeOnly(zcu)) {
return sema.failWithNeededComptime(block, block.src(.{ .init_elem = .{
.init_node_offset = init_src.offset.node_offset.x,
.elem_index = @intCast(runtime_index),
@@ -19468,9 +18883,8 @@ fn finishStructInit(
}
if (is_ref) {
- try struct_ty.resolveLayout(pt);
const target = zcu.getTarget();
- const alloc_ty = try pt.ptrTypeSema(.{
+ const alloc_ty = try pt.ptrType(.{
.child = result_ty.toIntern(),
.flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
});
@@ -19489,7 +18903,6 @@ fn finishStructInit(
.init_node_offset = init_src.offset.node_offset.x,
.elem_index = @intCast(runtime_index),
} }));
- try struct_ty.resolveStructFieldInits(pt);
const struct_val = try block.addAggregateInit(struct_ty, field_inits);
return sema.coerce(block, result_ty, struct_val, init_src);
}
@@ -19558,7 +18971,7 @@ fn structInitAnon(
field_name.* = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, name, .no_embedded_nulls);
- const init = try sema.resolveInst(item.data.init);
+ const init = sema.resolveInst(item.data.init);
field_ty.* = sema.typeOf(init).toIntern();
if (Type.fromInterned(field_ty.*).zigTypeTag(zcu) == .@"opaque") {
const msg = msg: {
@@ -19574,7 +18987,7 @@ fn structInitAnon(
};
return sema.failWithOwnedErrorMsg(block, msg);
}
- if (try sema.resolveValue(init)) |init_val| {
+ if (sema.resolveValue(init)) |init_val| {
field_val.* = init_val.toIntern();
any_values = true;
} else {
@@ -19585,12 +18998,11 @@ fn structInitAnon(
break :rs runtime_index;
};
- // We treat anonymous struct types as reified types, because there are similarities:
- // * They use a form of structural equivalence, which we can easily model using a custom hash
- // * They do not have captures
- // * They immediately have their fields resolved
- // In general, other code should treat anon struct types and reified struct types identically,
- // so there's no point having a separate `InternPool.NamespaceType` field for them.
+ // We treat anonymous struct types as reified types, because there are similarities: they have
+ // no captures, and instead use a form of structural equivalence which we can easy represent by
+ // hashing the field names/types/values. They also perform layout resolution immediately. These
+ // similarities mean that other code should actually treat anon struct types and reified struct
+ // types identically anyway, so sharing the representation makes everything simpler.
const type_hash: u64 = hash: {
var hasher = std.hash.Wyhash.init(0);
hasher.update(std.mem.sliceAsBytes(types));
@@ -19599,35 +19011,33 @@ fn structInitAnon(
break :hash hasher.final();
};
const tracked_inst = try block.trackZir(inst);
- const struct_ty = switch (try ip.getStructType(gpa, io, pt.tid, .{
- .layout = .auto,
+ const struct_ty: Type = switch (try ip.getReifiedStructType(gpa, io, pt.tid, .{
+ .zir_index = tracked_inst,
+ .type_hash = type_hash,
.fields_len = extra_data.fields_len,
- .known_non_opv = false,
- .requires_comptime = .unknown,
+ .layout = .auto,
.any_comptime_fields = any_values,
- .any_default_inits = any_values,
- .inits_resolved = true,
- .any_aligned_fields = false,
- .key = .{ .reified = .{
- .zir_index = tracked_inst,
- .type_hash = type_hash,
- } },
- }, false)) {
+ .any_field_defaults = any_values,
+ .any_field_aligns = false,
+ .packed_backing_int_type = .none,
+ })) {
+ .existing => |ty| .fromInterned(ty),
.wip => |wip| ty: {
errdefer wip.cancel(ip, pt.tid);
- const type_name = try sema.createTypeName(block, .anon, "struct", inst, wip.index);
- wip.setName(ip, type_name.name, type_name.nav);
+ try sema.setTypeName(block, &wip, .anon, "struct", inst);
- const struct_type = ip.loadStructType(wip.index);
-
- for (names, values, 0..) |name, init_val, field_idx| {
- assert(struct_type.addFieldName(ip, name) == null);
- if (init_val != .none) struct_type.setFieldComptime(ip, field_idx);
- }
-
- @memcpy(struct_type.field_types.get(ip), types);
+ // Reified structs have field information populated immediately.
+ @memcpy(wip.field_names.get(ip), names);
+ @memcpy(wip.field_types.get(ip), types);
if (any_values) {
- @memcpy(struct_type.field_inits.get(ip), values);
+ @memcpy(wip.field_values.get(ip), values);
+ @memset(wip.field_is_comptime_bits.getAll(ip), 0);
+ for (values, 0..) |val, field_index| {
+ if (val == .none) continue;
+ const bit_bag_index = field_index / 32;
+ const mask = @as(u32, 1) << @intCast(field_index % 32);
+ wip.field_is_comptime_bits.getAll(ip)[bit_bag_index] |= mask;
+ }
}
const new_namespace_index = try pt.createNamespace(.{
@@ -19636,30 +19046,24 @@ fn structInitAnon(
.file_scope = block.getFileScopeIndex(zcu),
.generation = zcu.generation,
});
- try zcu.comp.queueJob(.{ .resolve_type_fully = wip.index });
- codegen_type: {
- if (zcu.comp.config.use_llvm) break :codegen_type;
- if (block.ownerModule().strip) break :codegen_type;
- zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
- try zcu.comp.queueJob(.{ .link_type = wip.index });
- }
+ errdefer pt.destroyNamespace(new_namespace_index);
if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
- break :ty wip.finish(ip, new_namespace_index);
+ break :ty .fromInterned(wip.finish(ip, new_namespace_index));
},
- .existing => |ty| ty,
};
- try sema.declareDependency(.{ .interned = struct_ty });
try sema.addTypeReferenceEntry(src, struct_ty);
+ // No need for `ensureNamespaceUpToDate` because this type's namespace is always empty.
+ try sema.ensureLayoutResolved(struct_ty, src, .init);
_ = opt_runtime_index orelse {
- const struct_val = try pt.aggregateValue(.fromInterned(struct_ty), values);
- return sema.addConstantMaybeRef(struct_val.toIntern(), is_ref);
+ const struct_val = try pt.aggregateValue(struct_ty, values);
+ return sema.addConstantMaybeRef(struct_val, is_ref);
};
if (is_ref) {
const target = zcu.getTarget();
- const alloc_ty = try pt.ptrTypeSema(.{
- .child = struct_ty,
+ const alloc_ty = try pt.ptrType(.{
+ .child = struct_ty.toIntern(),
.flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
});
const alloc = try block.addTy(.alloc, alloc_ty);
@@ -19672,12 +19076,12 @@ fn structInitAnon(
};
extra_index = item.end;
- const field_ptr_ty = try pt.ptrTypeSema(.{
+ const field_ptr_ty = try pt.ptrType(.{
.child = field_ty,
.flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
});
if (values[i] == .none) {
- const init = try sema.resolveInst(item.data.init);
+ const init = sema.resolveInst(item.data.init);
const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty);
_ = try block.addBinOp(.store, field_ptr, init);
}
@@ -19694,10 +19098,10 @@ fn structInitAnon(
.typed_init => sema.code.extraData(Zir.Inst.StructInit.Item, extra_index),
};
extra_index = item.end;
- element_refs[i] = try sema.resolveInst(item.data.init);
+ element_refs[i] = sema.resolveInst(item.data.init);
}
- return block.addAggregateInit(.fromInterned(struct_ty), element_refs);
+ return block.addAggregateInit(struct_ty, element_refs);
}
fn zirArrayInit(
@@ -19737,17 +19141,16 @@ fn zirArrayInit(
} });
// Less inits than needed.
if (i + 2 > args.len) if (is_tuple) {
- const default_val = array_ty.structFieldDefaultValue(i, zcu).toIntern();
- if (default_val == .unreachable_value) {
+ const default_val = array_ty.structFieldDefaultValue(i, zcu) orelse {
const template = "missing tuple field with index {d}";
if (root_msg) |msg| {
try sema.errNote(src, msg, template, .{i});
} else {
root_msg = try sema.errMsg(src, template, .{i});
}
- } else {
- dest.* = Air.internedToRef(default_val);
- }
+ continue;
+ };
+ dest.* = .fromValue(default_val);
continue;
} else {
dest.* = Air.internedToRef(sentinel_val.?.toIntern());
@@ -19755,15 +19158,13 @@ fn zirArrayInit(
};
const arg = args[i + 1];
- const resolved_arg = try sema.resolveInst(arg);
+ const resolved_arg = sema.resolveInst(arg);
const elem_ty = if (is_tuple)
array_ty.fieldType(i, zcu)
else
- array_ty.elemType2(zcu);
+ array_ty.childType(zcu);
dest.* = try sema.coerce(block, elem_ty, resolved_arg, elem_src);
if (is_tuple) {
- if (array_ty.structFieldIsComptime(i, zcu))
- try array_ty.resolveStructFieldInits(pt);
if (try array_ty.structFieldValueComptime(pt, i)) |field_val| {
const init_val = try sema.resolveConstValue(block, elem_src, dest.*, .{ .simple = .stored_to_comptime_field });
if (!field_val.eql(init_val, elem_ty, zcu)) {
@@ -19788,17 +19189,17 @@ fn zirArrayInit(
const elem_vals = try sema.arena.alloc(InternPool.Index, resolved_args.len);
for (elem_vals, resolved_args) |*val, arg| {
// We checked that all args are comptime above.
- val.* = (sema.resolveValue(arg) catch unreachable).?.toIntern();
+ val.* = sema.resolveValue(arg).?.toIntern();
}
const arr_val = try pt.aggregateValue(array_ty, elem_vals);
const result_ref = try sema.coerce(block, result_ty, Air.internedToRef(arr_val.toIntern()), src);
- const result_val = (try sema.resolveValue(result_ref)).?;
- return sema.addConstantMaybeRef(result_val.toIntern(), is_ref);
+ const result_val = (sema.resolveValue(result_ref)).?;
+ return sema.addConstantMaybeRef(result_val, is_ref);
};
if (is_ref) {
const target = zcu.getTarget();
- const alloc_ty = try pt.ptrTypeSema(.{
+ const alloc_ty = try pt.ptrType(.{
.child = result_ty.toIntern(),
.flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
});
@@ -19807,7 +19208,7 @@ fn zirArrayInit(
if (is_tuple) {
for (resolved_args, 0..) |arg, i| {
- const elem_ptr_ty = try pt.ptrTypeSema(.{
+ const elem_ptr_ty = try pt.ptrType(.{
.child = array_ty.fieldType(i, zcu).toIntern(),
.flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
});
@@ -19820,8 +19221,8 @@ fn zirArrayInit(
return sema.makePtrConst(block, alloc);
}
- const elem_ptr_ty = try pt.ptrTypeSema(.{
- .child = array_ty.elemType2(zcu).toIntern(),
+ const elem_ptr_ty = try pt.ptrType(.{
+ .child = array_ty.childType(zcu).toIntern(),
.flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
});
const elem_ptr_ty_ref = Air.internedToRef(elem_ptr_ty.toIntern());
@@ -19875,7 +19276,7 @@ fn arrayInitAnon(
.init_node_offset = src.offset.node_offset.x,
.elem_index = @intCast(i),
} });
- const elem = try sema.resolveInst(operand);
+ const elem = sema.resolveInst(operand);
types[i] = sema.typeOf(elem).toIntern();
if (Type.fromInterned(types[i]).zigTypeTag(zcu) == .@"opaque") {
const msg = msg: {
@@ -19887,7 +19288,7 @@ fn arrayInitAnon(
};
return sema.failWithOwnedErrorMsg(block, msg);
}
- if (try sema.resolveValue(elem)) |val| {
+ if (sema.resolveValue(elem)) |val| {
values[i] = val.toIntern();
any_comptime = true;
} else {
@@ -19917,7 +19318,7 @@ fn arrayInitAnon(
const runtime_src = opt_runtime_src orelse {
const tuple_val = try pt.aggregateValue(tuple_ty, values);
- return sema.addConstantMaybeRef(tuple_val.toIntern(), is_ref);
+ return sema.addConstantMaybeRef(tuple_val, is_ref);
};
try sema.requireRuntimeBlock(block, src, runtime_src);
@@ -19927,25 +19328,25 @@ fn arrayInitAnon(
.init_node_offset = src.offset.node_offset.x,
.elem_index = @intCast(i),
} });
- try sema.validateRuntimeValue(block, operand_src, try sema.resolveInst(operand));
+ try sema.validateRuntimeValue(block, operand_src, sema.resolveInst(operand));
}
if (is_ref) {
const target = sema.pt.zcu.getTarget();
- const alloc_ty = try pt.ptrTypeSema(.{
+ const alloc_ty = try pt.ptrType(.{
.child = tuple_ty.toIntern(),
.flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
});
const alloc = try block.addTy(.alloc, alloc_ty);
for (operands, 0..) |operand, i_usize| {
const i: u32 = @intCast(i_usize);
- const field_ptr_ty = try pt.ptrTypeSema(.{
+ const field_ptr_ty = try pt.ptrType(.{
.child = types[i],
.flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
});
if (values[i] == .none) {
const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty);
- _ = try block.addBinOp(.store, field_ptr, try sema.resolveInst(operand));
+ _ = try block.addBinOp(.store, field_ptr, sema.resolveInst(operand));
}
}
@@ -19954,14 +19355,14 @@ fn arrayInitAnon(
const element_refs = try sema.arena.alloc(Air.Inst.Ref, operands.len);
for (operands, 0..) |operand, i| {
- element_refs[i] = try sema.resolveInst(operand);
+ element_refs[i] = sema.resolveInst(operand);
}
return block.addAggregateInit(tuple_ty, element_refs);
}
-fn addConstantMaybeRef(sema: *Sema, val: InternPool.Index, is_ref: bool) !Air.Inst.Ref {
- return if (is_ref) sema.uavRef(val) else Air.internedToRef(val);
+fn addConstantMaybeRef(sema: *Sema, val: Value, is_ref: bool) !Air.Inst.Ref {
+ return if (is_ref) sema.uavRef(val) else .fromValue(val);
}
fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -19971,6 +19372,7 @@ fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
const field_src = block.builtinCallArgSrc(inst_data.src_node, 1);
const aggregate_ty = try sema.resolveType(block, ty_src, extra.container_type);
const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, .{ .simple = .field_name });
+ try sema.ensureLayoutResolved(aggregate_ty, ty_src, .field_queried);
return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src);
}
@@ -19990,9 +19392,11 @@ fn zirStructInitFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp
const aggregate_ty = wrapped_aggregate_ty.optEuBaseType(zcu);
const zir_field_name = sema.code.nullTerminatedString(extra.name_start);
const field_name = try ip.getOrPutString(gpa, io, pt.tid, zir_field_name, .no_embedded_nulls);
+ try sema.ensureLayoutResolved(aggregate_ty, ty_src, .init);
return sema.fieldType(block, aggregate_ty, field_name, field_name_src, ty_src);
}
+/// Asserts that the layout of `aggregate_ty` is resolved.
fn fieldType(
sema: *Sema,
block: *Block,
@@ -20004,9 +19408,9 @@ fn fieldType(
const pt = sema.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
+ aggregate_ty.assertHasLayout(zcu);
var cur_ty = aggregate_ty;
while (true) {
- try cur_ty.resolveFields(pt);
switch (cur_ty.zigTypeTag(zcu)) {
.@"struct" => switch (ip.indexToKey(cur_ty.toIntern())) {
.tuple_type => |tuple| {
@@ -20024,10 +19428,11 @@ fn fieldType(
},
.@"union" => {
const union_obj = zcu.typeToUnion(cur_ty).?;
- const field_index = union_obj.loadTagType(ip).nameIndex(ip, field_name) orelse
+ const enum_obj = ip.loadEnumType(union_obj.enum_tag_type);
+ const field_index = enum_obj.nameIndex(ip, field_name) orelse
return sema.failWithBadUnionFieldAccess(block, cur_ty, union_obj, field_src, field_name);
const field_ty = union_obj.field_types.get(ip)[field_index];
- return Air.internedToRef(field_ty);
+ return .fromIntern(field_ty);
},
.optional => {
// Struct/array init through optional requires the child type to not be a pointer.
@@ -20056,7 +19461,6 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const stack_trace_ty = try sema.getBuiltinType(block.nodeOffset(.zero), .StackTrace);
- try stack_trace_ty.resolveFields(pt);
const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty);
const opt_ptr_stack_trace_ty = try pt.optionalType(ptr_stack_trace_ty.toIntern());
@@ -20064,7 +19468,14 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {
.func => |func| if (ip.funcAnalysisUnordered(func).has_error_trace and block.ownerModule().error_tracing) {
return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty);
},
- .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {},
+
+ .@"comptime",
+ .nav_ty,
+ .nav_val,
+ .type_layout,
+ .struct_defaults,
+ .memoized_state,
+ => {},
}
return Air.internedToRef(try pt.intern(.{ .opt = .{
.ty = opt_ptr_stack_trace_ty.toIntern(),
@@ -20083,15 +19494,16 @@ fn zirFrame(
}
fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
- const zcu = sema.pt.zcu;
+ const pt = sema.pt;
+ const zcu = pt.zcu;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);
const ty = try sema.resolveType(block, operand_src, inst_data.operand);
+ try sema.ensureLayoutResolved(ty, operand_src, .align_of);
if (ty.isNoReturn(zcu)) {
- return sema.fail(block, operand_src, "no align available for type '{f}'", .{ty.fmt(sema.pt)});
+ return sema.fail(block, operand_src, "no align available for uninstantiable type '{f}'", .{ty.fmt(sema.pt)});
}
- const val = try ty.lazyAbiAlignment(sema.pt);
- return Air.internedToRef(val.toIntern());
+ return .fromValue(try pt.intValue(.comptime_int, ty.abiAlignment(zcu).toByteUnits().?));
}
fn zirIntFromBool(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -20099,7 +19511,7 @@ fn zirIntFromBool(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
const zcu = pt.zcu;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const src = block.nodeOffset(inst_data.src_node);
- const operand = try sema.resolveInst(inst_data.operand);
+ const operand = sema.resolveInst(inst_data.operand);
const operand_ty = sema.typeOf(operand);
const is_vector = operand_ty.zigTypeTag(zcu) == .vector;
const operand_scalar_ty = operand_ty.scalarType(zcu);
@@ -20108,7 +19520,7 @@ fn zirIntFromBool(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
}
const len = if (is_vector) operand_ty.vectorLen(zcu) else undefined;
const dest_ty: Type = if (is_vector) try pt.vectorType(.{ .child = .u1_type, .len = len }) else .u1;
- if (try sema.resolveValue(operand)) |val| {
+ if (sema.resolveValue(operand)) |val| {
if (!is_vector) {
return if (val.isUndef(zcu)) .undef_u1 else if (val.toBool()) .one_u1 else .zero_u1;
}
@@ -20131,7 +19543,7 @@ fn zirIntFromBool(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
fn zirErrorName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);
- const uncoerced_operand = try sema.resolveInst(inst_data.operand);
+ const uncoerced_operand = sema.resolveInst(inst_data.operand);
const operand = try sema.coerce(block, .anyerror, uncoerced_operand, operand_src);
if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| {
@@ -20152,7 +19564,7 @@ fn zirAbs(
const pt = sema.pt;
const zcu = pt.zcu;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
- const operand = try sema.resolveInst(inst_data.operand);
+ const operand = sema.resolveInst(inst_data.operand);
const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);
const operand_ty = sema.typeOf(operand);
const scalar_ty = operand_ty.scalarType(zcu);
@@ -20183,7 +19595,7 @@ fn maybeConstantUnaryMath(
const pt = sema.pt;
const zcu = pt.zcu;
switch (result_ty.zigTypeTag(zcu)) {
- .vector => if (try sema.resolveValue(operand)) |val| {
+ .vector => if (sema.resolveValue(operand)) |val| {
const scalar_ty = result_ty.scalarType(zcu);
const vec_len = result_ty.vectorLen(zcu);
if (val.isUndef(zcu))
@@ -20196,7 +19608,7 @@ fn maybeConstantUnaryMath(
}
return Air.internedToRef((try pt.aggregateValue(result_ty, elems)).toIntern());
},
- else => if (try sema.resolveValue(operand)) |operand_val| {
+ else => if (sema.resolveValue(operand)) |operand_val| {
if (operand_val.isUndef(zcu))
return try pt.undefRef(result_ty);
const result_val = try eval(operand_val, result_ty, sema.arena, pt);
@@ -20219,7 +19631,7 @@ fn zirUnaryMath(
const pt = sema.pt;
const zcu = pt.zcu;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
- const operand = try sema.resolveInst(inst_data.operand);
+ const operand = sema.resolveInst(inst_data.operand);
const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);
const operand_ty = sema.typeOf(operand);
const scalar_ty = operand_ty.scalarType(zcu);
@@ -20244,12 +19656,11 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);
const src = block.nodeOffset(inst_data.src_node);
- const operand = try sema.resolveInst(inst_data.operand);
+ const operand = sema.resolveInst(inst_data.operand);
const operand_ty = sema.typeOf(operand);
const pt = sema.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
- try operand_ty.resolveLayout(pt);
const enum_ty = switch (operand_ty.zigTypeTag(zcu)) {
.enum_literal => {
const val = (try sema.resolveDefinedValue(block, operand_src, operand)).?;
@@ -20332,17 +19743,17 @@ fn zirReifySliceArgTy(
// zig fmt: on
};
- const operand_ty = try pt.ptrTypeSema(.{
+ const operand_ty = try pt.ptrType(.{
.child = in_scalar_ty.toIntern(),
.flags = .{ .size = .slice, .is_const = true },
});
- const operand_uncoerced = try sema.resolveInst(extra.operand);
+ const operand_uncoerced = sema.resolveInst(extra.operand);
const operand_coerced = try sema.coerce(block, operand_ty, operand_uncoerced, src);
const operand_val = try sema.resolveConstDefinedValue(block, src, operand_coerced, .{ .simple = comptime_reason });
const len_val: Value = .fromInterned(zcu.intern_pool.indexToKey(operand_val.toIntern()).slice.len);
if (len_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, src, null);
- const len = try len_val.toUnsignedIntSema(pt);
+ const len = len_val.toUnsignedInt(zcu);
return .fromType(try pt.singleConstPtrType(try pt.arrayType(.{
.len = len,
@@ -20365,12 +19776,12 @@ fn zirReifyEnumValueSliceTy(
const int_tag_ty = try sema.resolveType(block, int_tag_ty_src, extra.lhs);
- const operand_uncoerced = try sema.resolveInst(extra.rhs);
+ const operand_uncoerced = sema.resolveInst(extra.rhs);
const operand_coerced = try sema.coerce(block, .slice_const_slice_const_u8, operand_uncoerced, field_names_src);
const operand_val = try sema.resolveConstDefinedValue(block, field_names_src, operand_coerced, .{ .simple = .enum_field_names });
const len_val: Value = .fromInterned(zcu.intern_pool.indexToKey(operand_val.toIntern()).slice.len);
if (len_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, field_names_src, null);
- const len = try len_val.toUnsignedIntSema(pt);
+ const len = len_val.toUnsignedInt(zcu);
return .fromType(try pt.singleConstPtrType(try pt.arrayType(.{
.len = len,
@@ -20410,7 +19821,7 @@ fn zirReifyTuple(
const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
const operand_src = block.builtinCallArgSrc(extra.node, 0);
- const types_uncoerced = try sema.resolveInst(extra.operand);
+ const types_uncoerced = sema.resolveInst(extra.operand);
const types_coerced = try sema.coerce(block, .slice_const_type, types_uncoerced, operand_src);
const types_slice_val = try sema.resolveConstDefinedValue(block, operand_src, types_coerced, .{ .simple = .tuple_field_types });
const types_array_val = try sema.derefSliceAsArray(block, operand_src, types_slice_val, .{ .simple = .tuple_field_types });
@@ -20422,6 +19833,7 @@ fn zirReifyTuple(
if (field_ty_val.isUndef(zcu)) {
return sema.failWithUseOfUndef(block, operand_src, null);
}
+ try sema.validateTupleFieldType(block, field_ty_val.toType(), operand_src);
field_ty.* = field_ty_val.toIntern();
}
@@ -20456,12 +19868,12 @@ fn zirReifyPointer(
const size_ty = try sema.getBuiltinType(size_src, .@"Type.Pointer.Size");
const attrs_ty = try sema.getBuiltinType(attrs_src, .@"Type.Pointer.Attributes");
- const size_uncoerced = try sema.resolveInst(extra.size);
+ const size_uncoerced = sema.resolveInst(extra.size);
const size_coerced = try sema.coerce(block, size_ty, size_uncoerced, size_src);
const size_val = try sema.resolveConstDefinedValue(block, size_src, size_coerced, .{ .simple = .pointer_size });
const size = try sema.interpretBuiltinType(block, size_src, size_val, std.builtin.Type.Pointer.Size);
- const attrs_uncoerced = try sema.resolveInst(extra.attrs);
+ const attrs_uncoerced = sema.resolveInst(extra.attrs);
const attrs_coerced = try sema.coerce(block, attrs_ty, attrs_uncoerced, attrs_src);
const attrs_val = try sema.resolveConstDefinedValue(block, attrs_src, attrs_coerced, .{ .simple = .pointer_attrs });
const attrs = try sema.interpretBuiltinType(block, attrs_src, attrs_val, std.builtin.Type.Pointer.Attributes);
@@ -20489,18 +19901,8 @@ fn zirReifyPointer(
else => {},
}
- if (size == .c and !try sema.validateExternType(elem_ty, .other)) {
- return sema.failWithOwnedErrorMsg(block, msg: {
- const msg = try sema.errMsg(src, "C pointers cannot point to non-C-ABI-compatible type '{f}'", .{elem_ty.fmt(pt)});
- errdefer msg.destroy(gpa);
- try sema.explainWhyTypeIsNotExtern(msg, elem_ty_src, elem_ty, .other);
- try sema.addDeclaredHereNote(msg, elem_ty);
- break :msg msg;
- });
- }
-
const sentinel_ty = try pt.optionalType(elem_ty.toIntern());
- const sentinel_uncoerced = try sema.resolveInst(extra.sentinel);
+ const sentinel_uncoerced = sema.resolveInst(extra.sentinel);
const sentinel_coerced = try sema.coerce(block, sentinel_ty, sentinel_uncoerced, sentinel_src);
const sentinel_val = try sema.resolveConstDefinedValue(block, sentinel_src, sentinel_coerced, .{ .simple = .pointer_sentinel });
const opt_sentinel = sentinel_val.optionalValue(zcu);
@@ -20516,7 +19918,7 @@ fn zirReifyPointer(
}
}
- return .fromType(try pt.ptrTypeSema(.{
+ return .fromType(try pt.ptrType(.{
.child = elem_ty.toIntern(),
.sentinel = if (opt_sentinel) |s| s.toIntern() else .none,
.flags = .{
@@ -20554,7 +19956,7 @@ fn zirReifyFn(
const single_param_attrs_ty = try sema.getBuiltinType(param_attrs_src, .@"Type.Fn.Param.Attributes");
const fn_attrs_ty = try sema.getBuiltinType(fn_attrs_src, .@"Type.Fn.Attributes");
- const param_types_uncoerced = try sema.resolveInst(extra.param_types);
+ const param_types_uncoerced = sema.resolveInst(extra.param_types);
const param_types_coerced = try sema.coerce(block, .slice_const_type, param_types_uncoerced, param_types_src);
const param_types_slice = try sema.resolveConstDefinedValue(block, param_types_src, param_types_coerced, .{ .simple = .fn_param_types });
const param_types_arr = try sema.derefSliceAsArray(block, param_types_src, param_types_slice, .{ .simple = .fn_param_types });
@@ -20565,14 +19967,14 @@ fn zirReifyFn(
.len = params_len,
.child = single_param_attrs_ty.toIntern(),
}));
- const param_attrs_uncoerced = try sema.resolveInst(extra.param_attrs);
+ const param_attrs_uncoerced = sema.resolveInst(extra.param_attrs);
const param_attrs_coerced = try sema.coerce(block, param_attrs_ty, param_attrs_uncoerced, param_attrs_src);
const param_attrs_slice = try sema.resolveConstDefinedValue(block, param_attrs_src, param_attrs_coerced, .{ .simple = .fn_param_attrs });
const param_attrs_arr = try sema.derefSliceAsArray(block, param_attrs_src, param_attrs_slice, .{ .simple = .fn_param_attrs });
const ret_ty = try sema.resolveType(block, ret_ty_src, extra.ret_ty);
- const fn_attrs_uncoerced = try sema.resolveInst(extra.fn_attrs);
+ const fn_attrs_uncoerced = sema.resolveInst(extra.fn_attrs);
const fn_attrs_coerced = try sema.coerce(block, fn_attrs_ty, fn_attrs_uncoerced, fn_attrs_src);
const fn_attrs_val = try sema.resolveConstDefinedValue(block, fn_attrs_src, fn_attrs_coerced, .{ .simple = .fn_attrs });
const fn_attrs = try sema.interpretBuiltinType(block, fn_attrs_src, fn_attrs_val, std.builtin.Type.Fn.Attributes);
@@ -20587,17 +19989,15 @@ fn zirReifyFn(
try param_attrs_arr.elemValue(pt, param_idx),
std.builtin.Type.Fn.Param.Attributes,
);
- try sema.checkParamTypeCommon(
+ try sema.checkParamType(
block,
@intCast(param_idx),
param_ty,
+ false,
param_attrs.@"noalias",
param_types_src,
fn_attrs.@"callconv",
);
- if (try param_ty.comptimeOnlySema(pt)) {
- return sema.fail(block, param_attrs_src, "cannot reify function type with comptime-only parameter type '{f}'", .{param_ty.fmt(pt)});
- }
if (param_attrs.@"noalias") {
if (param_idx > 31) {
return sema.fail(block, param_attrs_src, "this compiler implementation only supports 'noalias' on the first 32 parameters", .{});
@@ -20611,7 +20011,7 @@ fn zirReifyFn(
try sema.checkCallConvSupportsVarArgs(block, fn_attrs_src, fn_attrs.@"callconv");
}
- try sema.checkReturnTypeAndCallConvCommon(
+ try sema.checkReturnTypeAndCallConv(
block,
ret_ty,
ret_ty_src,
@@ -20621,9 +20021,6 @@ fn zirReifyFn(
false,
false,
);
- if (try ret_ty.comptimeOnlySema(pt)) {
- return sema.fail(block, param_attrs_src, "cannot reify function type with comptime-only return type '{f}'", .{ret_ty.fmt(pt)});
- }
return .fromIntern(try ip.getFuncType(gpa, io, pt.tid, .{
.param_types = param_types_ip,
@@ -20632,7 +20029,6 @@ fn zirReifyFn(
.return_type = ret_ty.toIntern(),
.cc = fn_attrs.@"callconv",
.is_var_args = fn_attrs.varargs,
- .is_generic = false,
.is_noinline = false,
}));
}
@@ -20653,6 +20049,7 @@ fn zirReifyStruct(
const name_strategy: Zir.Inst.NameStrategy = @enumFromInt(extended.small);
const extra = sema.code.extraData(Zir.Inst.ReifyStruct, extended.operand).data;
const tracked_inst = try block.trackZir(inst);
+
const src: LazySrcLoc = .{
.base_node_inst = tracked_inst,
.offset = .nodeOffset(.zero),
@@ -20697,16 +20094,16 @@ fn zirReifyStruct(
const container_layout_ty = try sema.getBuiltinType(layout_src, .@"Type.ContainerLayout");
const single_field_attrs_ty = try sema.getBuiltinType(field_attrs_src, .@"Type.StructField.Attributes");
- const layout_uncoerced = try sema.resolveInst(extra.layout);
+ const layout_uncoerced = sema.resolveInst(extra.layout);
const layout_coerced = try sema.coerce(block, container_layout_ty, layout_uncoerced, layout_src);
const layout_val = try sema.resolveConstDefinedValue(block, layout_src, layout_coerced, .{ .simple = .struct_layout });
const layout = try sema.interpretBuiltinType(block, layout_src, layout_val, std.builtin.Type.ContainerLayout);
- const backing_int_ty_uncoerced = try sema.resolveInst(extra.backing_ty);
+ const backing_int_ty_uncoerced = sema.resolveInst(extra.backing_ty);
const backing_int_ty_coerced = try sema.coerce(block, .optional_type, backing_int_ty_uncoerced, backing_ty_src);
- const backing_int_ty_val = try sema.resolveConstDefinedValue(block, backing_ty_src, backing_int_ty_coerced, .{ .simple = .type });
+ const backing_int_ty_val = try sema.resolveConstDefinedValue(block, backing_ty_src, backing_int_ty_coerced, .{ .simple = .packed_struct_backing_int_type });
- const field_names_uncoerced = try sema.resolveInst(extra.field_names);
+ const field_names_uncoerced = sema.resolveInst(extra.field_names);
const field_names_coerced = try sema.coerce(block, .slice_const_slice_const_u8, field_names_uncoerced, field_names_src);
const field_names_slice = try sema.resolveConstDefinedValue(block, field_names_src, field_names_coerced, .{ .simple = .struct_field_names });
const field_names_arr = try sema.derefSliceAsArray(block, field_names_src, field_names_slice, .{ .simple = .struct_field_names });
@@ -20722,12 +20119,12 @@ fn zirReifyStruct(
.child = single_field_attrs_ty.toIntern(),
}));
- const field_types_uncoerced = try sema.resolveInst(extra.field_types);
+ const field_types_uncoerced = sema.resolveInst(extra.field_types);
const field_types_coerced = try sema.coerce(block, field_types_ty, field_types_uncoerced, field_types_src);
const field_types_slice = try sema.resolveConstDefinedValue(block, field_types_src, field_types_coerced, .{ .simple = .struct_field_types });
const field_types_arr = try sema.derefSliceAsArray(block, field_types_src, field_types_slice, .{ .simple = .struct_field_types });
- const field_attrs_uncoerced = try sema.resolveInst(extra.field_attrs);
+ const field_attrs_uncoerced = sema.resolveInst(extra.field_attrs);
const field_attrs_coerced = try sema.coerce(block, field_attrs_ty, field_attrs_uncoerced, field_attrs_src);
const field_attrs_slice = try sema.resolveConstDefinedValue(block, field_attrs_src, field_attrs_coerced, .{ .simple = .struct_field_attrs });
const field_attrs_arr = try sema.derefSliceAsArray(block, field_attrs_src, field_attrs_slice, .{ .simple = .struct_field_attrs });
@@ -20744,19 +20141,30 @@ fn zirReifyStruct(
return sema.failWithUseOfUndef(block, backing_ty_src, null);
}
- // The validation work here is non-trivial, and it's possible the type already exists.
- // So in this first pass, let's just construct a hash to optimize for this case. If the
- // inputs turn out to be invalid, we can cancel the WIP type later.
+ // Most validation of this type happens during type resolution. We basically need to do the work
+ // which AstGen would normally do. An exception is checking for duplicate field names, which is
+ // handled by type resolution---it just simplifies some logic a little.
+
+ // As well as validation, we're going to gather some information about the fields, and construct
+ // a hash representing the inputs for deduplication purposes.
var any_comptime_fields = false;
- var any_default_inits = false;
- var any_aligned_fields = false;
+ var any_field_defaults = false;
+ var any_field_aligns = false;
- // For deduplication purposes, we must create a hash including all details of this type.
// TODO: use a longer hash!
var hasher = std.hash.Wyhash.init(0);
std.hash.autoHash(&hasher, layout);
std.hash.autoHash(&hasher, backing_int_ty_val);
+
+ const backing_int_ty: ?Type = if (backing_int_ty_val.optionalValue(zcu)) |backing| ty: {
+ switch (layout) {
+ .auto, .@"extern" => return sema.fail(block, backing_ty_src, "non-packed struct does not support backing integer type", .{}),
+ .@"packed" => {},
+ }
+ break :ty backing.toType();
+ } else null;
+
// The field *type* array has already been deduplicated for us thanks to the InternPool!
std.hash.autoHash(&hasher, field_types_arr);
// However, for field names and attributes, we need to actually iterate the individual fields,
@@ -20791,207 +20199,119 @@ fn zirReifyStruct(
field_attrs_src,
.{ .simple = .struct_field_default_value },
);
- // Resolve the value so that lazy values do not create distinct types.
- break :d (try sema.resolveLazyValue(deref_val)).toIntern();
+ if (deref_val.canMutateComptimeVarState(zcu)) {
+ return sema.failWithContainsReferenceToComptimeVar(block, field_attrs_src, field_name, "field default value", deref_val);
+ }
+ any_field_defaults = true;
+ break :d deref_val.toIntern();
};
+ if (field_attr_comptime.toBool()) {
+ if (field_default == .none) {
+ return sema.fail(block, field_attrs_src, "comptime field without default initialization value", .{});
+ }
+ if (layout != .auto) {
+ return sema.fail(block, field_attrs_src, "{t} struct fields cannot be marked comptime", .{layout});
+ }
+ any_comptime_fields = true;
+ }
+
+ if (field_attr_align.optionalValue(zcu)) |align_val| {
+ if (layout == .@"packed") {
+ return sema.fail(block, field_attrs_src, "packed struct fields cannot be aligned", .{});
+ }
+ // Trigger a compile error if the alignment is invalid.
+ _ = try sema.validateAlign(block, field_attrs_src, align_val.toUnsignedInt(zcu));
+ any_field_aligns = true;
+ }
+
std.hash.autoHash(&hasher, .{
field_name,
field_attr_comptime,
field_attr_align,
field_default,
});
-
- if (field_attr_comptime.toBool()) any_comptime_fields = true;
- if (field_attr_align.optionalValue(zcu)) |_| any_aligned_fields = true;
- if (field_default != .none) any_default_inits = true;
- }
-
- // Some basic validation to avoid a bogus `getStructType` call...
- const backing_int_ty: ?Type = if (backing_int_ty_val.optionalValue(zcu)) |backing| ty: {
- switch (layout) {
- .auto, .@"extern" => return sema.fail(block, backing_ty_src, "non-packed struct does not support backing integer type", .{}),
- .@"packed" => {},
- }
- break :ty backing.toType();
- } else null;
- if (any_aligned_fields and layout == .@"packed") {
- return sema.fail(block, field_attrs_src, "packed struct fields cannot be aligned", .{});
- }
- if (any_comptime_fields and layout != .auto) {
- return sema.fail(block, field_attrs_src, "{t} struct fields cannot be marked comptime", .{layout});
}
- const wip_ty = switch (try ip.getStructType(gpa, io, pt.tid, .{
- .layout = layout,
+ switch (try ip.getReifiedStructType(gpa, io, pt.tid, .{
+ .zir_index = tracked_inst,
+ .type_hash = hasher.final(),
.fields_len = @intCast(fields_len),
- .known_non_opv = false,
- .requires_comptime = .unknown,
+ .layout = layout,
.any_comptime_fields = any_comptime_fields,
- .any_default_inits = any_default_inits,
- .any_aligned_fields = any_aligned_fields,
- .inits_resolved = true,
- .key = .{ .reified = .{
- .zir_index = tracked_inst,
- .type_hash = hasher.final(),
- } },
- }, false)) {
- .wip => |wip| wip,
+ .any_field_defaults = any_field_defaults,
+ .any_field_aligns = any_field_aligns,
+ .packed_backing_int_type = if (backing_int_ty) |ty| ty.toIntern() else .none,
+ })) {
.existing => |ty| {
- try sema.declareDependency(.{ .interned = ty });
- try sema.addTypeReferenceEntry(src, ty);
- return Air.internedToRef(ty);
+ try sema.addTypeReferenceEntry(src, .fromInterned(ty));
+ // No need for `ensureNamespaceUpToDate` because this type's namespace is always empty.
+ return .fromIntern(ty);
},
- };
- errdefer wip_ty.cancel(ip, pt.tid);
+ .wip => |wip| {
+ errdefer wip.cancel(ip, pt.tid);
+ try sema.setTypeName(block, &wip, name_strategy, "struct", inst);
+ for (0..fields_len) |field_idx| {
+ const field_name_val = try field_names_arr.elemValue(pt, field_idx);
+ const field_attrs_val = try field_attrs_arr.elemValue(pt, field_idx);
- const type_name = try sema.createTypeName(
- block,
- name_strategy,
- "struct",
- inst,
- wip_ty.index,
- );
- wip_ty.setName(ip, type_name.name, type_name.nav);
+ // No source location or reason; first loop checked this is valid.
+ const field_name = try sema.sliceToIpString(block, .unneeded, field_name_val, undefined);
+ wip.field_names.get(ip)[field_idx] = field_name;
- const wip_struct_type = ip.loadStructType(wip_ty.index);
+ const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType();
+ wip.field_types.get(ip)[field_idx] = field_ty.toIntern();
- for (0..fields_len) |field_idx| {
- const field_name_val = try field_names_arr.elemValue(pt, field_idx);
- const field_attrs_val = try field_attrs_arr.elemValue(pt, field_idx);
+ const field_attr_comptime = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(
+ std.builtin.Type.StructField.Attributes,
+ "comptime",
+ ).?);
+ const field_attr_align = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(
+ std.builtin.Type.StructField.Attributes,
+ "align",
+ ).?);
+ const field_attr_default_value_ptr = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(
+ std.builtin.Type.StructField.Attributes,
+ "default_value_ptr",
+ ).?);
- const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType();
+ if (field_attr_comptime.toBool()) {
+ const bit_bag_index = field_idx / 32;
+ const mask = @as(u32, 1) << @intCast(field_idx % 32);
+ wip.field_is_comptime_bits.getAll(ip)[bit_bag_index] |= mask;
+ }
- // Don't pass a reason; first loop acts as a check that this is valid.
- const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined);
- if (wip_struct_type.addFieldName(ip, field_name)) |prev_index| {
- _ = prev_index; // TODO: better source location
- return sema.fail(block, field_names_src, "duplicate struct field name {f}", .{field_name.fmt(ip)});
- }
+ if (field_attr_default_value_ptr.optionalValue(zcu)) |ptr_val| {
+ const ptr_ty = try pt.singleConstPtrType(field_ty);
+ // No source location; first loop checked this is valid.
+ const deref_val = (try sema.pointerDeref(block, .unneeded, ptr_val, ptr_ty)).?;
+ wip.field_values.get(ip)[field_idx] = deref_val.toIntern();
+ } else if (any_field_defaults) {
+ wip.field_values.get(ip)[field_idx] = .none;
+ }
- const field_attr_comptime = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(
- std.builtin.Type.StructField.Attributes,
- "comptime",
- ).?);
- const field_attr_align = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(
- std.builtin.Type.StructField.Attributes,
- "align",
- ).?);
- const field_attr_default_value_ptr = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(
- std.builtin.Type.StructField.Attributes,
- "default_value_ptr",
- ).?);
-
- if (field_attr_align.optionalValue(zcu)) |field_align_val| {
- assert(layout != .@"packed");
- const bytes = try field_align_val.toUnsignedIntSema(pt);
- const a = try sema.validateAlign(block, field_attrs_src, bytes);
- wip_struct_type.field_aligns.get(ip)[field_idx] = a;
- } else if (any_aligned_fields) {
- assert(layout != .@"packed");
- wip_struct_type.field_aligns.get(ip)[field_idx] = .none;
- }
-
- const field_default: InternPool.Index = d: {
- const ptr_val = field_attr_default_value_ptr.optionalValue(zcu) orelse break :d .none;
- assert(any_default_inits);
- const ptr_ty = try pt.singleConstPtrType(field_ty);
- // The first loop checked that this is comptime-dereferencable.
- const deref_val = (try sema.pointerDeref(block, field_attrs_src, ptr_val, ptr_ty)).?;
- // ...but we've not checked this yet!
- if (deref_val.canMutateComptimeVarState(zcu)) {
- return sema.failWithContainsReferenceToComptimeVar(block, field_attrs_src, field_name, "field default value", deref_val);
- }
- break :d (try sema.resolveLazyValue(deref_val)).toIntern();
- };
-
- if (field_attr_comptime.toBool()) {
- assert(layout == .auto);
- if (field_default == .none) {
- return sema.fail(block, field_attrs_src, "comptime field without default initialization value", .{});
+ if (field_attr_align.optionalValue(zcu)) |field_align_val| {
+ const bytes = field_align_val.toUnsignedInt(zcu);
+ // No source location; first loop checked this is valid.
+ const a = try sema.validateAlign(block, .unneeded, bytes);
+ wip.field_aligns.get(ip)[field_idx] = a;
+ } else if (any_field_aligns) {
+ wip.field_aligns.get(ip)[field_idx] = .none;
+ }
}
- wip_struct_type.setFieldComptime(ip, field_idx);
- }
-
- wip_struct_type.field_types.get(ip)[field_idx] = field_ty.toIntern();
- if (field_default != .none) {
- wip_struct_type.field_inits.get(ip)[field_idx] = field_default;
- }
-
- switch (field_ty.zigTypeTag(zcu)) {
- .@"opaque" => return sema.failWithOwnedErrorMsg(block, msg: {
- const msg = try sema.errMsg(field_types_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
- errdefer msg.destroy(gpa);
- try sema.addDeclaredHereNote(msg, field_ty);
- break :msg msg;
- }),
- .noreturn => return sema.failWithOwnedErrorMsg(block, msg: {
- const msg = try sema.errMsg(field_types_src, "struct fields cannot be 'noreturn'", .{});
- errdefer msg.destroy(gpa);
- try sema.addDeclaredHereNote(msg, field_ty);
- break :msg msg;
- }),
- else => {},
- }
- switch (layout) {
- .auto => {},
- .@"extern" => if (!try sema.validateExternType(field_ty, .struct_field)) {
- return sema.failWithOwnedErrorMsg(block, msg: {
- const msg = try sema.errMsg(field_types_src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
- errdefer msg.destroy(gpa);
- try sema.explainWhyTypeIsNotExtern(msg, field_types_src, field_ty, .struct_field);
- try sema.addDeclaredHereNote(msg, field_ty);
- break :msg msg;
- });
- },
- .@"packed" => if (!try sema.validatePackedType(field_ty)) {
- return sema.failWithOwnedErrorMsg(block, msg: {
- const msg = try sema.errMsg(field_types_src, "packed structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
- errdefer msg.destroy(gpa);
- try sema.explainWhyTypeIsNotPacked(msg, field_types_src, field_ty);
- try sema.addDeclaredHereNote(msg, field_ty);
- break :msg msg;
- });
- },
- }
- }
-
- if (layout == .@"packed") {
- var fields_bit_sum: u64 = 0;
- for (0..wip_struct_type.field_types.len) |field_idx| {
- const field_ty: Type = .fromInterned(wip_struct_type.field_types.get(ip)[field_idx]);
- try field_ty.resolveLayout(pt);
- fields_bit_sum += field_ty.bitSize(zcu);
- }
- if (backing_int_ty) |ty| {
- try sema.checkBackingIntType(block, src, ty, fields_bit_sum);
- wip_struct_type.setBackingIntType(ip, io, ty.toIntern());
- } else {
- const ty = try pt.intType(.unsigned, @intCast(fields_bit_sum));
- wip_struct_type.setBackingIntType(ip, io, ty.toIntern());
- }
- }
-
- const new_namespace_index = try pt.createNamespace(.{
- .parent = block.namespace.toOptional(),
- .owner_type = wip_ty.index,
- .file_scope = block.getFileScopeIndex(zcu),
- .generation = zcu.generation,
- });
-
- try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
- codegen_type: {
- if (zcu.comp.config.use_llvm) break :codegen_type;
- if (block.ownerModule().strip) break :codegen_type;
- // This job depends on any resolve_type_fully jobs queued up before it.
- zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
- try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
+ const new_namespace_index = try pt.createNamespace(.{
+ .parent = block.namespace.toOptional(),
+ .owner_type = wip.index,
+ .file_scope = block.getFileScopeIndex(zcu),
+ .generation = zcu.generation,
+ });
+ errdefer pt.destroyNamespace(new_namespace_index);
+ if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
+ try sema.addTypeReferenceEntry(src, .fromInterned(wip.index));
+ return .fromIntern(wip.finish(ip, new_namespace_index));
+ },
}
- try sema.declareDependency(.{ .interned = wip_ty.index });
- try sema.addTypeReferenceEntry(src, wip_ty.index);
- if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
- return .fromIntern(wip_ty.finish(ip, new_namespace_index));
}
fn zirReifyUnion(
@@ -21054,16 +20374,19 @@ fn zirReifyUnion(
const container_layout_ty = try sema.getBuiltinType(layout_src, .@"Type.ContainerLayout");
const single_field_attrs_ty = try sema.getBuiltinType(field_attrs_src, .@"Type.UnionField.Attributes");
- const layout_uncoerced = try sema.resolveInst(extra.layout);
+ const layout_uncoerced = sema.resolveInst(extra.layout);
const layout_coerced = try sema.coerce(block, container_layout_ty, layout_uncoerced, layout_src);
const layout_val = try sema.resolveConstDefinedValue(block, layout_src, layout_coerced, .{ .simple = .union_layout });
const layout = try sema.interpretBuiltinType(block, layout_src, layout_val, std.builtin.Type.ContainerLayout);
- const arg_ty_uncoerced = try sema.resolveInst(extra.arg_ty);
+ const arg_ty_uncoerced = sema.resolveInst(extra.arg_ty);
const arg_ty_coerced = try sema.coerce(block, .optional_type, arg_ty_uncoerced, arg_ty_src);
- const arg_ty_val = try sema.resolveConstDefinedValue(block, arg_ty_src, arg_ty_coerced, .{ .simple = .type });
+ const arg_ty_val = try sema.resolveConstDefinedValue(block, arg_ty_src, arg_ty_coerced, switch (layout) {
+ .@"packed" => .{ .simple = .packed_union_backing_int_type },
+ .auto, .@"extern" => .{ .simple = .union_enum_tag_type },
+ });
- const field_names_uncoerced = try sema.resolveInst(extra.field_names);
+ const field_names_uncoerced = sema.resolveInst(extra.field_names);
const field_names_coerced = try sema.coerce(block, .slice_const_slice_const_u8, field_names_uncoerced, field_names_src);
const field_names_slice = try sema.resolveConstDefinedValue(block, field_names_src, field_names_coerced, .{ .simple = .union_field_names });
const field_names_arr = try sema.derefSliceAsArray(block, field_names_src, field_names_slice, .{ .simple = .union_field_names });
@@ -21079,12 +20402,12 @@ fn zirReifyUnion(
.child = single_field_attrs_ty.toIntern(),
}));
- const field_types_uncoerced = try sema.resolveInst(extra.field_types);
+ const field_types_uncoerced = sema.resolveInst(extra.field_types);
const field_types_coerced = try sema.coerce(block, field_types_ty, field_types_uncoerced, field_types_src);
const field_types_slice = try sema.resolveConstDefinedValue(block, field_types_src, field_types_coerced, .{ .simple = .union_field_types });
const field_types_arr = try sema.derefSliceAsArray(block, field_types_src, field_types_slice, .{ .simple = .union_field_types });
- const field_attrs_uncoerced = try sema.resolveInst(extra.field_attrs);
+ const field_attrs_uncoerced = sema.resolveInst(extra.field_attrs);
const field_attrs_coerced = try sema.coerce(block, field_attrs_ty, field_attrs_uncoerced, field_attrs_src);
const field_attrs_slice = try sema.resolveConstDefinedValue(block, field_attrs_src, field_attrs_coerced, .{ .simple = .union_field_attrs });
const field_attrs_arr = try sema.derefSliceAsArray(block, field_attrs_src, field_attrs_slice, .{ .simple = .union_field_attrs });
@@ -21101,17 +20424,29 @@ fn zirReifyUnion(
return sema.failWithUseOfUndef(block, arg_ty_src, null);
}
- // The validation work here is non-trivial, and it's possible the type already exists.
- // So in this first pass, let's just construct a hash to optimize for this case. If the
- // inputs turn out to be invalid, we can cancel the WIP type later.
+ // Most validation of this type happens during type resolution. We basically need to do the work
+ // which AstGen would normally do. An exception is checking for duplicate field names, which is
+ // handled by type resolution---it just simplifies some logic a little.
- var any_aligned_fields = false;
+ // As well as validation, we're going to gather some information about the fields, and construct
+ // a hash representing the inputs for deduplication purposes.
+
+ var any_field_aligns = false;
- // For deduplication purposes, we must create a hash including all details of this type.
// TODO: use a longer hash!
var hasher = std.hash.Wyhash.init(0);
std.hash.autoHash(&hasher, layout);
std.hash.autoHash(&hasher, arg_ty_val);
+
+ const explicit_tag_ty: ?Type, const explicit_packed_backing_type: ?Type = ty: {
+ const arg_ty = arg_ty_val.optionalValue(zcu) orelse break :ty .{ null, null };
+ switch (layout) {
+ .@"extern" => return sema.fail(block, arg_ty_src, "extern union does not support enum tag type", .{}),
+ .@"packed" => break :ty .{ null, arg_ty.toType() },
+ .auto => break :ty .{ arg_ty.toType(), null },
+ }
+ };
+
// `field_types_arr` and `field_attrs_arr` are already deduplicated by the InternPool!
std.hash.autoHash(&hasher, field_types_arr);
std.hash.autoHash(&hasher, field_attrs_arr);
@@ -21128,203 +20463,76 @@ fn zirReifyUnion(
try field_attrs_arr.elemValue(pt, field_idx),
std.builtin.Type.UnionField.Attributes,
);
- if (field_attrs.@"align" != null) {
- any_aligned_fields = true;
- }
- }
-
- // Some basic validation to avoid a bogus `getUnionType` call...
- const explicit_tag_ty: ?Type = if (arg_ty_val.optionalValue(zcu)) |arg_ty| ty: {
- switch (layout) {
- .@"extern", .@"packed" => return sema.fail(block, arg_ty_src, "{t} union does not support enum tag type", .{layout}),
- .auto => {},
- }
- break :ty arg_ty.toType();
- } else null;
- if (any_aligned_fields and layout == .@"packed") {
- return sema.fail(block, field_attrs_src, "packed union fields cannot be aligned", .{});
- }
-
- const wip_ty = switch (try ip.getUnionType(gpa, io, pt.tid, .{
- .flags = .{
- .layout = layout,
- .status = .none,
- .runtime_tag = rt: {
- if (explicit_tag_ty != null) break :rt .tagged;
- if (layout == .auto and block.wantSafeTypes()) break :rt .safety;
- break :rt .none;
- },
- .any_aligned_fields = any_aligned_fields,
- .requires_comptime = .unknown,
- .assumed_runtime_bits = false,
- .assumed_pointer_aligned = false,
- .alignment = .none,
- },
- .fields_len = @intCast(fields_len),
- .enum_tag_ty = .none, // set later because not yet validated
- .field_types = &.{}, // set later
- .field_aligns = &.{}, // set later
- .key = .{ .reified = .{
- .zir_index = tracked_inst,
- .type_hash = hasher.final(),
- } },
- }, false)) {
- .wip => |wip| wip,
- .existing => |ty| {
- try sema.declareDependency(.{ .interned = ty });
- try sema.addTypeReferenceEntry(src, ty);
- return Air.internedToRef(ty);
- },
- };
- errdefer wip_ty.cancel(ip, pt.tid);
-
- const type_name = try sema.createTypeName(
- block,
- name_strategy,
- "union",
- inst,
- wip_ty.index,
- );
- wip_ty.setName(ip, type_name.name, type_name.nav);
-
- const loaded_union = ip.loadUnionType(wip_ty.index);
-
- const enum_tag_ty, const has_explicit_tag = if (explicit_tag_ty) |enum_tag_ty| tag: {
- if (enum_tag_ty.zigTypeTag(zcu) != .@"enum") {
- return sema.fail(block, arg_ty_src, "tag type must be an enum type", .{});
- }
-
- const tag_ty_fields_len = enum_tag_ty.enumFieldCount(zcu);
-
- for (0..fields_len) |field_idx| {
- const field_name_val = try field_names_arr.elemValue(pt, field_idx);
- // Don't pass a reason; first loop acts as a check that this is valid.
- const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined);
-
- if (field_idx >= tag_ty_fields_len) {
- return sema.fail(block, field_names_src, "no field named '{f}' in enum '{f}'", .{
- field_name.fmt(ip), enum_tag_ty.fmt(pt),
- });
- }
-
- const enum_field_name = enum_tag_ty.enumFieldName(field_idx, zcu);
- if (enum_field_name != field_name) {
- return sema.fail(block, field_names_src, "union field name '{f}' does not match enum field name '{f}'", .{
- field_name.fmt(ip), enum_field_name.fmt(ip),
- });
- }
- }
- if (tag_ty_fields_len > fields_len) return sema.failWithOwnedErrorMsg(block, msg: {
- const msg = try sema.errMsg(field_names_src, "{d} enum fields missing in union", .{
- tag_ty_fields_len - fields_len,
- });
- errdefer msg.destroy(gpa);
- for (fields_len..tag_ty_fields_len) |enum_field_idx| {
- try sema.addFieldErrNote(enum_tag_ty, enum_field_idx, msg, "field '{f}' missing, declared here", .{
- enum_tag_ty.enumFieldName(enum_field_idx, zcu).fmt(ip),
- });
- }
- try sema.addDeclaredHereNote(msg, enum_tag_ty);
- break :msg msg;
- });
- break :tag .{ enum_tag_ty.toIntern(), true };
- } else tag: {
- // We must track field names and set up the tag type ourselves.
- var field_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .empty;
- try field_names.ensureTotalCapacity(sema.arena, fields_len);
-
- for (0..fields_len) |field_idx| {
- const field_name_val = try field_names_arr.elemValue(pt, field_idx);
- // Don't pass a reason; first loop acts as a check that this is valid.
- const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined);
- const gop = field_names.getOrPutAssumeCapacity(field_name);
- if (gop.found_existing) {
- // TODO: better source location
- return sema.fail(block, field_names_src, "duplicate union field {f}", .{field_name.fmt(ip)});
- }
- }
- const enum_tag_ty = try sema.generateUnionTagTypeSimple(block, field_names.keys(), wip_ty.index, type_name.name);
- break :tag .{ enum_tag_ty, false };
- };
- errdefer if (!has_explicit_tag) ip.remove(pt.tid, enum_tag_ty); // remove generated tag type on error
-
- for (0..fields_len) |field_idx| {
- const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType();
- const field_attrs = try sema.interpretBuiltinType(
- block,
- field_attrs_src,
- try field_attrs_arr.elemValue(pt, field_idx),
- std.builtin.Type.UnionField.Attributes,
- );
-
- if (field_ty.zigTypeTag(zcu) == .@"opaque") {
- return sema.failWithOwnedErrorMsg(block, msg: {
- const msg = try sema.errMsg(field_types_src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{});
- errdefer msg.destroy(gpa);
- try sema.addDeclaredHereNote(msg, field_ty);
- break :msg msg;
- });
- }
-
- switch (layout) {
- .auto => {},
- .@"extern" => if (!try sema.validateExternType(field_ty, .union_field)) {
- return sema.failWithOwnedErrorMsg(block, msg: {
- const msg = try sema.errMsg(field_types_src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
- errdefer msg.destroy(gpa);
-
- try sema.explainWhyTypeIsNotExtern(msg, field_types_src, field_ty, .union_field);
-
- try sema.addDeclaredHereNote(msg, field_ty);
- break :msg msg;
- });
- },
- .@"packed" => if (!try sema.validatePackedType(field_ty)) {
- return sema.failWithOwnedErrorMsg(block, msg: {
- const msg = try sema.errMsg(field_types_src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
- errdefer msg.destroy(gpa);
-
- try sema.explainWhyTypeIsNotPacked(msg, field_types_src, field_ty);
-
- try sema.addDeclaredHereNote(msg, field_ty);
- break :msg msg;
- });
- },
- }
-
- loaded_union.field_types.get(ip)[field_idx] = field_ty.toIntern();
if (field_attrs.@"align") |bytes| {
- assert(layout != .@"packed");
- const a = try sema.validateAlign(block, field_attrs_src, bytes);
- loaded_union.field_aligns.get(ip)[field_idx] = a;
- } else if (any_aligned_fields) {
- assert(layout != .@"packed");
- loaded_union.field_aligns.get(ip)[field_idx] = .none;
+ if (layout == .@"packed") {
+ return sema.fail(block, field_attrs_src, "packed union fields cannot be aligned", .{});
+ }
+ // Trigger a compile error if the alignment is invalid.
+ _ = try sema.validateAlign(block, field_attrs_src, bytes);
+ any_field_aligns = true;
}
}
- loaded_union.setTagType(ip, io, enum_tag_ty);
- loaded_union.setStatus(ip, io, .have_field_types);
+ switch (try ip.getReifiedUnionType(gpa, io, pt.tid, .{
+ .zir_index = tracked_inst,
+ .type_hash = hasher.final(),
+ .fields_len = @intCast(fields_len),
+ .layout = layout,
+ .any_field_aligns = any_field_aligns,
+ .tag_usage = tag: {
+ if (explicit_tag_ty != null) break :tag .tagged;
+ if (layout == .auto and block.wantSafeTypes()) break :tag .safety;
+ break :tag .none;
+ },
+ .enum_tag_type = if (explicit_tag_ty) |ty| ty.toIntern() else .none,
+ .packed_backing_int_type = if (explicit_packed_backing_type) |ty| ty.toIntern() else .none,
+ })) {
+ .existing => |ty| {
+ try sema.addTypeReferenceEntry(src, .fromInterned(ty));
+ // No need for `ensureNamespaceUpToDate` because this type's namespace is always empty.
+ return .fromIntern(ty);
+ },
+ .wip => |wip| {
+ errdefer wip.cancel(ip, pt.tid);
+ try sema.setTypeName(block, &wip, name_strategy, "union", inst);
- const new_namespace_index = try pt.createNamespace(.{
- .parent = block.namespace.toOptional(),
- .owner_type = wip_ty.index,
- .file_scope = block.getFileScopeIndex(zcu),
- .generation = zcu.generation,
- });
+ for (0..fields_len) |field_idx| {
+ const field_name_val = try field_names_arr.elemValue(pt, field_idx);
+ // No source location or reason; first loop checked this is valid.
+ const field_name = try sema.sliceToIpString(block, .unneeded, field_name_val, undefined);
+ wip.field_names.get(ip)[field_idx] = field_name;
- try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
- codegen_type: {
- if (zcu.comp.config.use_llvm) break :codegen_type;
- if (block.ownerModule().strip) break :codegen_type;
- // This job depends on any resolve_type_fully jobs queued up before it.
- zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
- try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
+ const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType();
+ wip.field_types.get(ip)[field_idx] = field_ty.toIntern();
+
+ // No source location; first loop checked this is valid.
+ const field_attrs = try sema.interpretBuiltinType(
+ block,
+ .unneeded,
+ try field_attrs_arr.elemValue(pt, field_idx),
+ std.builtin.Type.UnionField.Attributes,
+ );
+ if (field_attrs.@"align") |bytes| {
+ // No source location; first loop checked this is valid.
+ const a = try sema.validateAlign(block, .unneeded, bytes);
+ wip.field_aligns.get(ip)[field_idx] = a;
+ } else if (any_field_aligns) {
+ wip.field_aligns.get(ip)[field_idx] = .none;
+ }
+ }
+
+ const new_namespace_index = try pt.createNamespace(.{
+ .parent = block.namespace.toOptional(),
+ .owner_type = wip.index,
+ .file_scope = block.getFileScopeIndex(zcu),
+ .generation = zcu.generation,
+ });
+ errdefer pt.destroyNamespace(new_namespace_index);
+ if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
+ try sema.addTypeReferenceEntry(src, .fromInterned(wip.index));
+ return .fromIntern(wip.finish(ip, new_namespace_index));
+ },
}
- try sema.declareDependency(.{ .interned = wip_ty.index });
- try sema.addTypeReferenceEntry(src, wip_ty.index);
- if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
- return .fromIntern(wip_ty.finish(ip, new_namespace_index));
}
fn zirReifyEnum(
@@ -21379,12 +20587,12 @@ fn zirReifyEnum(
const enum_mode_ty = try sema.getBuiltinType(mode_src, .@"Type.Enum.Mode");
- const tag_ty = try sema.resolveType(block, tag_ty_src, extra.tag_ty);
- if (tag_ty.zigTypeTag(zcu) != .int) {
- return sema.fail(block, tag_ty_src, "tag type must be an integer type", .{});
- }
+ const tag_ty_uncoerced = sema.resolveInst(extra.tag_ty);
+ const tag_ty_coerced = try sema.coerce(block, .type, tag_ty_uncoerced, tag_ty_src);
+ const tag_ty_val = try sema.resolveConstDefinedValue(block, tag_ty_src, tag_ty_coerced, .{ .simple = .enum_int_tag_type });
+ const tag_ty = tag_ty_val.toType();
- const mode_uncoerced = try sema.resolveInst(extra.mode);
+ const mode_uncoerced = sema.resolveInst(extra.mode);
const mode_coerced = try sema.coerce(block, enum_mode_ty, mode_uncoerced, mode_src);
const mode_val = try sema.resolveConstDefinedValue(block, mode_src, mode_coerced, .{ .simple = .type });
const nonexhaustive = switch (try sema.interpretBuiltinType(block, mode_src, mode_val, std.builtin.Type.Enum.Mode)) {
@@ -21392,7 +20600,7 @@ fn zirReifyEnum(
.nonexhaustive => true,
};
- const field_names_uncoerced = try sema.resolveInst(extra.field_names);
+ const field_names_uncoerced = sema.resolveInst(extra.field_names);
const field_names_coerced = try sema.coerce(block, .slice_const_slice_const_u8, field_names_uncoerced, field_names_src);
const field_names_slice = try sema.resolveConstDefinedValue(block, field_names_src, field_names_coerced, .{ .simple = .enum_field_names });
const field_names_arr = try sema.derefSliceAsArray(block, field_names_src, field_names_slice, .{ .simple = .enum_field_names });
@@ -21404,7 +20612,7 @@ fn zirReifyEnum(
.child = tag_ty.toIntern(),
}));
- const field_values_uncoerced = try sema.resolveInst(extra.field_values);
+ const field_values_uncoerced = sema.resolveInst(extra.field_values);
const field_values_coerced = try sema.coerce(block, field_values_ty, field_values_uncoerced, field_values_src);
const field_values_slice = try sema.resolveConstDefinedValue(block, field_values_src, field_values_coerced, .{ .simple = .enum_field_values });
const field_values_arr = try sema.derefSliceAsArray(block, field_values_src, field_values_slice, .{ .simple = .enum_field_values });
@@ -21415,11 +20623,13 @@ fn zirReifyEnum(
}
// We don't need to check `field_names_arr`, because `sliceToIpString` will check that for us.
- // The validation work here is non-trivial, and it's possible the type already exists.
- // So in this first pass, let's just construct a hash to optimize for this case. If the
- // inputs turn out to be invalid, we can cancel the WIP type later.
+ // Most validation of this type happens during type resolution. We basically need to do the work
+ // which AstGen would normally do. An exception is checking for duplicate field names, which is
+ // handled by type resolution---it just simplifies some logic a little.
+
+ // As well as validation, we're going to gather some information about the fields, and construct
+ // a hash representing the inputs for deduplication purposes.
- // For deduplication purposes, we must create a hash including all details of this type.
// TODO: use a longer hash!
var hasher = std.hash.Wyhash.init(0);
std.hash.autoHash(&hasher, tag_ty.toIntern());
@@ -21435,87 +20645,46 @@ fn zirReifyEnum(
std.hash.autoHash(&hasher, field_name);
}
- const wip_ty = switch (try ip.getEnumType(gpa, io, pt.tid, .{
- .has_values = true,
- .tag_mode = if (nonexhaustive) .nonexhaustive else .explicit,
+ switch (try ip.getReifiedEnumType(gpa, io, pt.tid, .{
+ .zir_index = tracked_inst,
+ .type_hash = hasher.final(),
.fields_len = @intCast(fields_len),
- .key = .{ .reified = .{
- .zir_index = tracked_inst,
- .type_hash = hasher.final(),
- } },
- }, false)) {
- .wip => |wip| wip,
+ .nonexhaustive = nonexhaustive,
+ .int_tag_type = tag_ty.toIntern(),
+ })) {
.existing => |ty| {
- try sema.declareDependency(.{ .interned = ty });
- try sema.addTypeReferenceEntry(src, ty);
+ try sema.addTypeReferenceEntry(src, .fromInterned(ty));
+ // No need for `ensureNamespaceUpToDate` because this type's namespace is always empty.
return .fromIntern(ty);
},
- };
- var done = false;
- errdefer if (!done) wip_ty.cancel(ip, pt.tid);
+ .wip => |wip| {
+ errdefer wip.cancel(ip, pt.tid);
- const type_name = try sema.createTypeName(
- block,
- name_strategy,
- "enum",
- inst,
- wip_ty.index,
- );
- wip_ty.setName(ip, type_name.name, type_name.nav);
+ try sema.setTypeName(block, &wip, name_strategy, "enum", inst);
- const new_namespace_index = try pt.createNamespace(.{
- .parent = block.namespace.toOptional(),
- .owner_type = wip_ty.index,
- .file_scope = block.getFileScopeIndex(zcu),
- .generation = zcu.generation,
- });
+ // Populate field names and values. Duplicate checking will be handled by type resolution.
+ for (0..fields_len) |field_index| {
+ const field_name_val = try field_names_arr.elemValue(pt, field_index);
+ // No source location or reason; first loop checked this is valid.
+ const field_name = try sema.sliceToIpString(block, .unneeded, field_name_val, undefined);
+ wip.field_names.get(ip)[field_index] = field_name;
- try sema.declareDependency(.{ .interned = wip_ty.index });
- try sema.addTypeReferenceEntry(src, wip_ty.index);
- if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
- wip_ty.prepare(ip, new_namespace_index);
- wip_ty.setTagTy(ip, tag_ty.toIntern());
- done = true;
+ const field_val = try field_values_arr.elemValue(pt, field_index);
+ wip.field_values.get(ip)[field_index] = field_val.toIntern();
+ }
- for (0..fields_len) |field_idx| {
- const field_name_val = try field_names_arr.elemValue(pt, field_idx);
- // Don't pass a reason; first loop acts as a check that this is valid.
- const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined);
-
- const field_val = try field_values_arr.elemValue(pt, field_idx);
-
- if (wip_ty.nextField(ip, field_name, field_val.toIntern())) |conflict| {
- return sema.failWithOwnedErrorMsg(block, switch (conflict.kind) {
- .name => msg: {
- const msg = try sema.errMsg(field_names_src, "duplicate enum field '{f}'", .{field_name.fmt(ip)});
- errdefer msg.destroy(gpa);
- _ = conflict.prev_field_idx; // TODO: this note is incorrect
- try sema.errNote(field_names_src, msg, "other field here", .{});
- break :msg msg;
- },
- .value => msg: {
- const msg = try sema.errMsg(field_values_src, "enum tag value {f} already taken", .{field_val.fmtValueSema(pt, sema)});
- errdefer msg.destroy(gpa);
- _ = conflict.prev_field_idx; // TODO: this note is incorrect
- try sema.errNote(field_values_src, msg, "other enum tag value here", .{});
- break :msg msg;
- },
+ const new_namespace_index = try pt.createNamespace(.{
+ .parent = block.namespace.toOptional(),
+ .owner_type = wip.index,
+ .file_scope = block.getFileScopeIndex(zcu),
+ .generation = zcu.generation,
});
- }
+ errdefer pt.destroyNamespace(new_namespace_index);
+ if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
+ try sema.addTypeReferenceEntry(src, .fromInterned(wip.index));
+ return .fromIntern(wip.finish(ip, new_namespace_index));
+ },
}
-
- if (nonexhaustive and fields_len > 1 and std.math.log2_int(u64, fields_len) == tag_ty.bitSize(zcu)) {
- return sema.fail(block, src, "non-exhaustive enum specified every value", .{});
- }
-
- codegen_type: {
- if (zcu.comp.config.use_llvm) break :codegen_type;
- if (block.ownerModule().strip) break :codegen_type;
- // This job depends on any resolve_type_fully jobs queued up before it.
- zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
- try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
- }
- return Air.internedToRef(wip_ty.index);
}
fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) CompileError!Air.Inst.Ref {
@@ -21523,7 +20692,7 @@ fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.In
const va_list_ty = try sema.getBuiltinType(src, .VaList);
const va_list_ptr = try pt.singleMutPtrType(va_list_ty);
- const inst = try sema.resolveInst(zir_ref);
+ const inst = sema.resolveInst(zir_ref);
return sema.coerce(block, va_list_ptr, inst, src);
}
@@ -21535,8 +20704,8 @@ fn zirCVaArg(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C
const va_list_ref = try sema.resolveVaListRef(block, va_list_src, extra.lhs);
const arg_ty = try sema.resolveType(block, ty_src, extra.rhs);
-
- if (!try sema.validateExternType(arg_ty, .param_ty)) {
+ try sema.ensureLayoutResolved(arg_ty, ty_src, .parameter);
+ if (!arg_ty.validateExtern(.param_ty, sema.pt.zcu)) {
const msg = msg: {
const msg = try sema.errMsg(ty_src, "cannot get '{f}' from variadic argument", .{arg_ty.fmt(sema.pt)});
errdefer msg.destroy(sema.gpa);
@@ -21573,7 +20742,8 @@ fn zirCVaEnd(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C
const va_list_ref = try sema.resolveVaListRef(block, va_list_src, extra.operand);
try sema.requireRuntimeBlock(block, src, null);
- return block.addUnOp(.c_va_end, va_list_ref);
+ _ = try block.addUnOp(.c_va_end, va_list_ref);
+ return .void_value;
}
fn zirCVaStart(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
@@ -21618,7 +20788,7 @@ fn zirIntFromFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);
const dest_ty = try sema.resolveDestType(block, src, extra.lhs, .remove_eu_opt, "@intFromFloat");
- const operand = try sema.resolveInst(extra.rhs);
+ const operand = sema.resolveInst(extra.rhs);
const operand_ty = sema.typeOf(operand);
try sema.checkVectorizableBinaryOperands(block, operand_src, dest_ty, operand_ty, src, operand_src);
@@ -21630,7 +20800,7 @@ fn zirIntFromFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
_ = try sema.checkIntType(block, src, dest_scalar_ty);
try sema.checkFloatType(block, operand_src, operand_scalar_ty);
- if (try sema.resolveValue(operand)) |operand_val| {
+ if (sema.resolveValue(operand)) |operand_val| {
const result_val = try sema.intFromFloat(block, operand_src, operand_val, operand_ty, dest_ty, .truncate);
return Air.internedToRef(result_val.toIntern());
} else if (dest_scalar_ty.zigTypeTag(zcu) == .comptime_int) {
@@ -21671,7 +20841,7 @@ fn zirFloatFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);
const dest_ty = try sema.resolveDestType(block, src, extra.lhs, .remove_eu_opt, "@floatFromInt");
- const operand = try sema.resolveInst(extra.rhs);
+ const operand = sema.resolveInst(extra.rhs);
const operand_ty = sema.typeOf(operand);
try sema.checkVectorizableBinaryOperands(block, operand_src, dest_ty, operand_ty, src, operand_src);
@@ -21682,9 +20852,21 @@ fn zirFloatFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
try sema.checkFloatType(block, src, dest_scalar_ty);
_ = try sema.checkIntType(block, operand_src, operand_scalar_ty);
- if (try sema.resolveValue(operand)) |operand_val| {
- const result_val = try operand_val.floatFromIntAdvanced(sema.arena, operand_ty, dest_ty, pt, .sema);
- return Air.internedToRef(result_val.toIntern());
+ if (sema.resolveValue(operand)) |operand_val| {
+ if (operand_val.isUndef(zcu)) return .fromValue(try pt.undefValue(dest_ty));
+ if (dest_ty.zigTypeTag(zcu) != .vector) {
+ return .fromValue(try pt.floatValue(dest_ty, operand_val.toFloat(f128, zcu)));
+ }
+ const dest_elems = try sema.arena.alloc(InternPool.Index, dest_ty.vectorLen(zcu));
+ for (dest_elems, 0..) |*out_elem, elem_idx| {
+ const orig_elem = try operand_val.elemValue(pt, elem_idx);
+ const casted_elem = if (orig_elem.isUndef(zcu))
+ try pt.undefValue(dest_scalar_ty)
+ else
+ try pt.floatValue(dest_scalar_ty, orig_elem.toFloat(f128, zcu));
+ out_elem.* = casted_elem.toIntern();
+ }
+ return .fromValue(try pt.aggregateValue(dest_ty, dest_elems));
} else if (dest_scalar_ty.zigTypeTag(zcu) == .comptime_float) {
return sema.failWithNeededComptime(block, operand_src, .{ .simple = .casted_to_comptime_float });
}
@@ -21702,7 +20884,7 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);
- const operand_res = try sema.resolveInst(extra.rhs);
+ const operand_res = sema.resolveInst(extra.rhs);
const uncoerced_operand_ty = sema.typeOf(operand_res);
const dest_ty = try sema.resolveDestType(block, src, extra.lhs, .remove_eu, "@ptrFromInt");
@@ -21719,8 +20901,10 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
const ptr_ty = dest_ty.scalarType(zcu);
try sema.checkPtrType(block, src, ptr_ty, true);
- const elem_ty = ptr_ty.elemType2(zcu);
- const ptr_align = try ptr_ty.ptrAlignmentSema(pt);
+ const elem_ty = ptr_ty.nullablePtrElem(zcu);
+
+ try sema.ensureLayoutResolved(elem_ty, src, .align_check);
+ const ptr_align = ptr_ty.ptrAlignment(zcu);
if (ptr_ty.isSlice(zcu)) {
const msg = msg: {
@@ -21746,18 +20930,9 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
}
return Air.internedToRef((try pt.aggregateValue(dest_ty, new_elems)).toIntern());
}
- if (try ptr_ty.comptimeOnlySema(pt)) {
- return sema.failWithOwnedErrorMsg(block, msg: {
- const msg = try sema.errMsg(src, "pointer to comptime-only type '{f}' must be comptime-known, but operand is runtime-known", .{ptr_ty.fmt(pt)});
- errdefer msg.destroy(sema.gpa);
-
- try sema.explainWhyTypeIsComptime(msg, src, ptr_ty);
- break :msg msg;
- });
- }
try sema.requireRuntimeBlock(block, src, operand_src);
try sema.checkLogicalPtrOperation(block, src, ptr_ty);
- if (block.wantSafety() and (try elem_ty.hasRuntimeBitsSema(pt) or elem_ty.zigTypeTag(zcu) == .@"fn")) {
+ if (block.wantSafety()) {
if (!ptr_ty.isAllowzeroPtr(zcu)) {
const is_non_zero = if (is_vector) all_non_zero: {
const zero_usize = Air.internedToRef((try sema.splat(operand_ty, .zero_usize)).toIntern());
@@ -21804,7 +20979,7 @@ fn ptrFromIntVal(
}
return sema.failWithUseOfUndef(block, operand_src, vec_idx);
}
- const addr = try operand_val.toUnsignedIntSema(pt);
+ const addr = operand_val.toUnsignedInt(zcu);
if (!ptr_ty.isAllowzeroPtr(zcu) and addr == 0)
return sema.fail(block, operand_src, "pointer type '{f}' does not allow address zero", .{ptr_ty.fmt(pt)});
if (addr != 0 and ptr_align != .none) {
@@ -21836,7 +21011,7 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData
const src = block.nodeOffset(extra.node);
const operand_src = block.builtinCallArgSrc(extra.node, 0);
const dest_ty = try sema.resolveDestType(block, src, extra.lhs, .remove_opt, "@errorCast");
- const operand = try sema.resolveInst(extra.rhs);
+ const operand = sema.resolveInst(extra.rhs);
const operand_ty = sema.typeOf(operand);
const dest_tag = dest_ty.zigTypeTag(zcu);
@@ -21877,34 +21052,62 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData
else => unreachable,
};
- const disjoint = disjoint: {
- // Try avoiding resolving inferred error sets if we can
- if (!dest_err_ty.isAnyError(zcu) and dest_err_ty.errorSetIsEmpty(zcu)) break :disjoint true;
- if (!operand_err_ty.isAnyError(zcu) and operand_err_ty.errorSetIsEmpty(zcu)) break :disjoint true;
- if (dest_err_ty.isAnyError(zcu)) break :disjoint false;
- if (operand_err_ty.isAnyError(zcu)) break :disjoint false;
- const dest_err_names = dest_err_ty.errorSetNames(zcu);
- for (0..dest_err_names.len) |dest_err_index| {
- if (Type.errorSetHasFieldIp(ip, operand_err_ty.toIntern(), dest_err_names.get(ip)[dest_err_index]))
- break :disjoint false;
- }
+ switch (ip.indexToKey(operand_err_ty.toIntern())) {
+ .inferred_error_set_type => |func| try sema.ensureFuncIesResolved(block, src, func),
+ else => {},
+ }
- if (!ip.isInferredErrorSetType(dest_err_ty.toIntern()) and
- !ip.isInferredErrorSetType(operand_err_ty.toIntern()))
- {
- break :disjoint true;
- }
-
- _ = try sema.resolveInferredErrorSetTy(block, src, dest_err_ty.toIntern());
- _ = try sema.resolveInferredErrorSetTy(block, operand_src, operand_err_ty.toIntern());
- for (0..dest_err_names.len) |dest_err_index| {
- if (Type.errorSetHasFieldIp(ip, operand_err_ty.toIntern(), dest_err_names.get(ip)[dest_err_index]))
- break :disjoint false;
- }
-
- break :disjoint true;
+ const result: enum {
+ /// The operand and destination error sets are disjoint, i.e. have no errors in common.
+ disjoint,
+ /// The destination error set is a superset of the operand error set, so the operation is
+ /// effectively equivalent to a coercion.
+ superset,
+ /// The operand and destination error sets have *some* errors in common, but the destination
+ /// is not a superset of the operand, so a safety check may be needed.
+ overlap,
+ } = if (operand_err_ty.errorSetIsEmpty(zcu)) res: {
+ break :res .disjoint;
+ } else check: switch (dest_err_ty.toIntern()) {
+ .anyerror_type => .superset,
+ .adhoc_inferred_error_set_type => {
+ // `@errorCast` to this function's own error set.
+ try sema.fn_ret_ty_ies.?.addErrorSet(operand_err_ty, ip, sema.arena);
+ break :check .superset;
+ },
+ else => |err_set_ty| switch (ip.indexToKey(err_set_ty)) {
+ .inferred_error_set_type => |func_index| {
+ if (sema.fn_ret_ty_ies) |dst_ies| {
+ if (dst_ies.func == func_index) {
+ // `@errorCast` to this function's own error set.
+ try sema.fn_ret_ty_ies.?.addErrorSet(operand_err_ty, ip, sema.arena);
+ break :check .superset;
+ }
+ }
+ try sema.ensureFuncIesResolved(block, src, func_index);
+ continue :check ip.funcIesResolvedUnordered(func_index);
+ },
+ .error_set_type => |dest| {
+ if (dest.names.len == 0) break :check .disjoint; // dest is 'error{}'
+ if (operand_err_ty.isAnyError(zcu)) break :check .overlap; // anyerror -> error{...} (non-empty)
+ var dest_has_all = true;
+ var dest_has_any = false;
+ for (operand_err_ty.errorSetNames(zcu).get(ip)) |operand_err_name| {
+ if (dest.nameIndex(ip, operand_err_name) != null) {
+ dest_has_any = true;
+ } else {
+ dest_has_all = false;
+ }
+ }
+ if (!dest_has_any) break :check .disjoint;
+ if (dest_has_all) break :check .superset;
+ break :check .overlap;
+ },
+ else => unreachable,
+ },
};
- if (disjoint and !(operand_tag == .error_union and dest_tag == .error_union)) {
+
+ if (result == .disjoint and !(operand_tag == .error_union and dest_tag == .error_union)) {
return sema.fail(block, src, "error sets '{f}' and '{f}' have no common errors", .{
operand_err_ty.fmt(pt), dest_err_ty.fmt(pt),
});
@@ -21912,25 +21115,30 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData
// operand must be defined since it can be an invalid error value
if (try sema.resolveDefinedValue(block, operand_src, operand)) |operand_val| {
- const err_name: InternPool.NullTerminatedString = switch (operand_tag) {
- .error_set => ip.indexToKey(operand_val.toIntern()).err.name,
- .error_union => switch (ip.indexToKey(operand_val.toIntern()).error_union.val) {
+ const err_name: InternPool.NullTerminatedString = switch (ip.indexToKey(operand_val.toIntern())) {
+ .err => |err| err.name,
+ .error_union => |eu| switch (eu.val) {
.err_name => |name| name,
.payload => |payload_val| {
assert(dest_tag == .error_union); // should be guaranteed from the type checks above
- return sema.coerce(block, dest_ty, Air.internedToRef(payload_val), operand_src);
+ const dest_payload_ty = dest_ty.errorUnionPayload(zcu);
+ const coerced_payload = try sema.coerce(block, dest_payload_ty, .fromIntern(payload_val), operand_src);
+ return sema.wrapErrorUnionPayload(block, dest_ty, coerced_payload, operand_src) catch |err| switch (err) {
+ error.NotCoercible => unreachable,
+ else => |e| return e,
+ };
},
},
else => unreachable,
};
- if (!dest_err_ty.isAnyError(zcu) and !Type.errorSetHasFieldIp(ip, dest_err_ty.toIntern(), err_name)) {
+ if (result != .superset and !dest_err_ty.errorSetHasField(err_name, zcu)) {
return sema.fail(block, src, "'error.{f}' not a member of error set '{f}'", .{
err_name.fmt(ip), dest_err_ty.fmt(pt),
});
}
- return Air.internedToRef(try pt.intern(switch (dest_tag) {
+ return .fromIntern(try pt.intern(switch (dest_tag) {
.error_set => .{ .err = .{
.ty = dest_ty.toIntern(),
.name = err_name,
@@ -21944,21 +21152,17 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData
}
const err_int_ty = try pt.errorIntType();
- if (block.wantSafety() and !dest_err_ty.isAnyError(zcu) and
- dest_err_ty.toIntern() != .adhoc_inferred_error_set_type and
- zcu.backendSupportsFeature(.error_set_has_value))
- {
+ if (block.wantSafety() and result != .superset and zcu.backendSupportsFeature(.error_set_has_value)) {
const err_code_inst = switch (operand_tag) {
.error_set => operand,
.error_union => try block.addTyOp(.unwrap_errunion_err, operand_err_ty, operand),
else => unreachable,
};
const err_int_inst = try block.addBitCast(err_int_ty, err_code_inst);
-
if (dest_tag == .error_union) {
const zero_err = try pt.intRef(err_int_ty, 0);
const is_zero = try block.addBinOp(.cmp_eq, err_int_inst, zero_err);
- if (disjoint) {
+ if (result == .disjoint) {
// Error must be zero.
try sema.addSafetyCheck(block, src, is_zero, .invalid_error_code);
} else {
@@ -21987,7 +21191,7 @@ fn zirPtrCastFull(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDa
const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
const src = block.nodeOffset(extra.node);
const operand_src = block.src(.{ .node_offset_ptrcast_operand = extra.node });
- const operand = try sema.resolveInst(extra.rhs);
+ const operand = sema.resolveInst(extra.rhs);
const dest_ty = try sema.resolveDestType(block, src, extra.lhs, .remove_eu, flags.needResultTypeBuiltinName());
return sema.ptrCastFull(
block,
@@ -22006,7 +21210,7 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
const dest_ty = try sema.resolveDestType(block, src, extra.lhs, .remove_eu, "@ptrCast");
- const operand = try sema.resolveInst(extra.rhs);
+ const operand = sema.resolveInst(extra.rhs);
return sema.ptrCastFull(
block,
@@ -22043,8 +21247,8 @@ fn ptrCastFull(
const src_info = operand_ty.ptrInfo(zcu);
const dest_info = dest_ty.ptrInfo(zcu);
- try Type.fromInterned(src_info.child).resolveLayout(pt);
- try Type.fromInterned(dest_info.child).resolveLayout(pt);
+ try sema.ensureLayoutResolved(.fromInterned(src_info.child), operand_src, .align_check);
+ try sema.ensureLayoutResolved(.fromInterned(dest_info.child), src, .align_check);
const DestSliceLen = union(enum) {
undef,
@@ -22072,16 +21276,16 @@ fn ptrCastFull(
};
},
.slice => src: {
- const operand_val = try sema.resolveValue(operand) orelse break :src .{ .fromInterned(src_info.child), null };
+ const operand_val = sema.resolveValue(operand) orelse break :src .{ .fromInterned(src_info.child), null };
if (operand_val.isUndef(zcu)) break :len .undef;
const slice_val = switch (operand_ty.zigTypeTag(zcu)) {
.optional => operand_val.optionalValue(zcu) orelse break :len .undef,
.pointer => operand_val,
else => unreachable,
};
- const slice_len_resolved = try sema.resolveLazyValue(.fromInterned(zcu.intern_pool.sliceLen(slice_val.toIntern())));
- if (slice_len_resolved.isUndef(zcu)) break :len .undef;
- break :src .{ .fromInterned(src_info.child), slice_len_resolved.toUnsignedInt(zcu) };
+ const slice_len: Value = .fromInterned(zcu.intern_pool.sliceLen(slice_val.toIntern()));
+ if (slice_len.isUndef(zcu)) break :len .undef;
+ break :src .{ .fromInterned(src_info.child), slice_len.toUnsignedInt(zcu) };
},
.many, .c => {
return sema.fail(block, src, "cannot infer length of slice from {s}", .{pointerSizeString(src_info.flags.size)});
@@ -22369,7 +21573,7 @@ fn ptrCastFull(
ct: {
if (flags.addrspace_cast) break :ct; // cannot `@addrSpaceCast` at comptime
- const operand_val = try sema.resolveValue(operand) orelse break :ct;
+ const operand_val = sema.resolveValue(operand) orelse break :ct;
if (operand_val.isUndef(zcu)) {
if (!dest_ty.ptrAllowsZero(zcu)) {
@@ -22395,7 +21599,7 @@ fn ptrCastFull(
};
if (dest_align.compare(.gt, src_align)) {
- if (try ptr_val.getUnsignedIntSema(pt)) |addr| {
+ if (ptr_val.getUnsignedInt(zcu)) |addr| {
const masked_addr = if (Type.fromInterned(dest_info.child).fnPtrMaskOrNull(zcu)) |mask|
addr & mask
else
@@ -22464,7 +21668,7 @@ fn ptrCastFull(
// Now, do an addrspace cast if necessary!
if (!flags.addrspace_cast) break :ptr pre_addrspace_cast;
- const intermediate_ptr_ty = try pt.ptrTypeSema(info: {
+ const intermediate_ptr_ty = try pt.ptrType(info: {
var info = src_info;
info.flags.address_space = dest_info.flags.address_space;
break :info info;
@@ -22629,7 +21833,7 @@ fn zirPtrCastNoDest(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst
const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
const src = block.nodeOffset(extra.node);
const operand_src = block.src(.{ .node_offset_ptrcast_operand = extra.node });
- const operand = try sema.resolveInst(extra.operand);
+ const operand = sema.resolveInst(extra.operand);
const operand_ty = sema.typeOf(operand);
try sema.checkPtrOperand(block, operand_src, operand_ty);
@@ -22638,14 +21842,14 @@ fn zirPtrCastNoDest(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst
if (flags.volatile_cast) ptr_info.flags.is_volatile = false;
const dest_ty = blk: {
- const dest_ty = try pt.ptrTypeSema(ptr_info);
+ const dest_ty = try pt.ptrType(ptr_info);
if (operand_ty.zigTypeTag(zcu) == .optional) {
break :blk try pt.optionalType(dest_ty.toIntern());
}
break :blk dest_ty;
};
- if (try sema.resolveValue(operand)) |operand_val| {
+ if (sema.resolveValue(operand)) |operand_val| {
return Air.internedToRef((try pt.getCoerced(operand_val, dest_ty)).toIntern());
}
@@ -22664,7 +21868,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
const dest_ty = try sema.resolveDestType(block, src, extra.lhs, .remove_eu_opt, "@truncate");
const dest_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, dest_ty, src);
- const operand = try sema.resolveInst(extra.rhs);
+ const operand = sema.resolveInst(extra.rhs);
const operand_ty = sema.typeOf(operand);
const operand_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src);
@@ -22678,48 +21882,24 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
return sema.coerce(block, dest_ty, operand, operand_src);
}
+ if (try dest_ty.onePossibleValue(pt)) |opv| return .fromValue(opv);
+
const dest_info = dest_scalar_ty.intInfo(zcu);
- if (try sema.typeHasOnePossibleValue(dest_ty)) |val| {
- return Air.internedToRef(val.toIntern());
- }
-
if (operand_scalar_ty.zigTypeTag(zcu) != .comptime_int) {
const operand_info = operand_ty.intInfo(zcu);
- if (try sema.typeHasOnePossibleValue(operand_ty)) |val| {
- return Air.internedToRef(val.toIntern());
- }
if (operand_info.signedness != dest_info.signedness) {
return sema.fail(block, operand_src, "expected {s} integer type, found '{f}'", .{
@tagName(dest_info.signedness), operand_ty.fmt(pt),
});
}
- switch (std.math.order(dest_info.bits, operand_info.bits)) {
- .gt => {
- const msg = msg: {
- const msg = try sema.errMsg(
- src,
- "destination type '{f}' has more bits than source type '{f}'",
- .{ dest_ty.fmt(pt), operand_ty.fmt(pt) },
- );
- errdefer msg.destroy(sema.gpa);
- try sema.errNote(src, msg, "destination type has {d} bits", .{
- dest_info.bits,
- });
- try sema.errNote(operand_src, msg, "operand type has {d} bits", .{
- operand_info.bits,
- });
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(block, msg);
- },
- .eq => return operand,
- .lt => {},
+ if (dest_info.bits >= operand_info.bits) {
+ return sema.coerce(block, dest_ty, operand, operand_src);
}
}
- if (try sema.resolveValueResolveLazy(operand)) |val| {
+ if (sema.resolveValue(operand)) |val| {
const result_val = try arith.truncate(sema, val, operand_ty, dest_ty, dest_info.signedness, dest_info.bits);
return Air.internedToRef(result_val.toIntern());
}
@@ -22740,15 +21920,11 @@ fn zirBitCount(
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const src = block.nodeOffset(inst_data.src_node);
const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);
- const operand = try sema.resolveInst(inst_data.operand);
+ const operand = sema.resolveInst(inst_data.operand);
const operand_ty = sema.typeOf(operand);
_ = try sema.checkIntOrVector(block, operand, operand_src);
const bits = operand_ty.intInfo(zcu).bits;
- if (try sema.typeHasOnePossibleValue(operand_ty)) |val| {
- return Air.internedToRef(val.toIntern());
- }
-
const result_scalar_ty = try pt.smallestUnsignedInt(bits);
switch (operand_ty.zigTypeTag(zcu)) {
.vector => {
@@ -22757,7 +21933,7 @@ fn zirBitCount(
.len = vec_len,
.child = result_scalar_ty.toIntern(),
});
- if (try sema.resolveValue(operand)) |val| {
+ if (sema.resolveValue(operand)) |val| {
if (val.isUndef(zcu)) return pt.undefRef(result_ty);
const elems = try sema.arena.alloc(InternPool.Index, vec_len);
@@ -22774,7 +21950,7 @@ fn zirBitCount(
}
},
.int => {
- if (try sema.resolveValueResolveLazy(operand)) |val| {
+ if (sema.resolveValue(operand)) |val| {
if (val.isUndef(zcu)) return pt.undefRef(result_scalar_ty);
return pt.intRef(result_scalar_ty, comptimeOp(val, operand_ty, zcu));
} else {
@@ -22791,7 +21967,7 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const zcu = pt.zcu;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);
- const operand = try sema.resolveInst(inst_data.operand);
+ const operand = sema.resolveInst(inst_data.operand);
const operand_ty = sema.typeOf(operand);
const scalar_ty = try sema.checkIntOrVector(block, operand, operand_src);
const bits = scalar_ty.intInfo(zcu).bits;
@@ -22803,10 +21979,7 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.{ scalar_ty.fmt(pt), bits },
);
}
- if (try sema.typeHasOnePossibleValue(operand_ty)) |val| {
- return .fromValue(val);
- }
- if (try sema.resolveValue(operand)) |operand_val| {
+ if (sema.resolveValue(operand)) |operand_val| {
return .fromValue(try arith.byteSwap(sema, operand_val, operand_ty));
}
return block.addTyOp(.byte_swap, operand_ty, operand);
@@ -22815,14 +21988,11 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);
- const operand = try sema.resolveInst(inst_data.operand);
+ const operand = sema.resolveInst(inst_data.operand);
const operand_ty = sema.typeOf(operand);
_ = try sema.checkIntOrVector(block, operand, operand_src);
- if (try sema.typeHasOnePossibleValue(operand_ty)) |val| {
- return .fromValue(val);
- }
- if (try sema.resolveValue(operand)) |operand_val| {
+ if (sema.resolveValue(operand)) |operand_val| {
return .fromValue(try arith.bitReverse(sema, operand_val, operand_ty));
}
return block.addTyOp(.bit_reverse, operand_ty, operand);
@@ -22849,10 +22019,11 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6
const ty = try sema.resolveType(block, ty_src, extra.lhs);
const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.rhs, .{ .simple = .field_name });
+ try sema.ensureLayoutResolved(ty, ty_src, .field_queried);
+
const pt = sema.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
- try ty.resolveLayout(pt);
switch (ty.zigTypeTag(zcu)) {
.@"struct" => {},
else => return sema.fail(block, ty_src, "expected struct type, found '{f}'", .{ty.fmt(pt)}),
@@ -23090,7 +22261,7 @@ fn checkAtomicPtrOperand(
) CompileError!Air.Inst.Ref {
const pt = sema.pt;
const zcu = pt.zcu;
- try elem_ty.resolveLayout(pt);
+ try sema.ensureLayoutResolved(elem_ty, elem_ty_src, .ptr_access);
var diag: Zcu.AtomicPtrAlignmentDiagnostics = .{};
const alignment = zcu.atomicPtrAlignment(elem_ty, &diag) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
@@ -23126,7 +22297,7 @@ fn checkAtomicPtrOperand(
const ptr_data = switch (ptr_ty.zigTypeTag(zcu)) {
.pointer => ptr_ty.ptrInfo(zcu),
else => {
- const wanted_ptr_ty = try pt.ptrTypeSema(wanted_ptr_data);
+ const wanted_ptr_ty = try pt.ptrType(wanted_ptr_data);
_ = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src);
unreachable;
},
@@ -23136,7 +22307,7 @@ fn checkAtomicPtrOperand(
wanted_ptr_data.flags.is_allowzero = ptr_data.flags.is_allowzero;
wanted_ptr_data.flags.is_volatile = ptr_data.flags.is_volatile;
- const wanted_ptr_ty = try pt.ptrTypeSema(wanted_ptr_data);
+ const wanted_ptr_ty = try pt.ptrType(wanted_ptr_data);
const casted_ptr = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src);
return casted_ptr;
@@ -23245,8 +22416,8 @@ fn checkSimdBinOp(
.len = vec_len,
.lhs = lhs,
.rhs = rhs,
- .lhs_val = try sema.resolveValue(lhs),
- .rhs_val = try sema.resolveValue(rhs),
+ .lhs_val = sema.resolveValue(lhs),
+ .rhs_val = sema.resolveValue(rhs),
.result_ty = result_ty,
.scalar_ty = result_ty.scalarType(zcu),
};
@@ -23338,7 +22509,7 @@ fn resolveExportOptions(
const ip = &zcu.intern_pool;
const export_options_ty = try sema.getBuiltinType(src, .ExportOptions);
- const air_ref = try sema.resolveInst(zir_ref);
+ const air_ref = sema.resolveInst(zir_ref);
const options = try sema.coerce(block, export_options_ty, air_ref, src);
const name_src = block.src(.{ .init_field_name = src.offset.node_offset_builtin_call_arg.builtin_call_node });
@@ -23391,7 +22562,7 @@ fn resolveBuiltinEnum(
reason: ComptimeReason,
) CompileError!@field(std.builtin, @tagName(name)) {
const ty = try sema.getBuiltinType(src, name);
- const air_ref = try sema.resolveInst(zir_ref);
+ const air_ref = sema.resolveInst(zir_ref);
const coerced = try sema.coerce(block, ty, air_ref, src);
const val = try sema.resolveConstDefinedValue(block, src, coerced, reason);
return sema.interpretBuiltinType(block, src, val, @field(std.builtin, @tagName(name)));
@@ -23438,7 +22609,7 @@ fn zirCmpxchg(
const success_order_src = block.builtinCallArgSrc(extra.node, 4);
const failure_order_src = block.builtinCallArgSrc(extra.node, 5);
// zig fmt: on
- const expected_value = try sema.resolveInst(extra.expected_value);
+ const expected_value = sema.resolveInst(extra.expected_value);
const elem_ty = sema.typeOf(expected_value);
if (elem_ty.zigTypeTag(zcu) == .float) {
return sema.fail(
@@ -23448,9 +22619,9 @@ fn zirCmpxchg(
.{elem_ty.fmt(pt)},
);
}
- const uncasted_ptr = try sema.resolveInst(extra.ptr);
+ const uncasted_ptr = sema.resolveInst(extra.ptr);
const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false);
- const new_value = try sema.coerce(block, elem_ty, try sema.resolveInst(extra.new_value), new_value_src);
+ const new_value = try sema.coerce(block, elem_ty, sema.resolveInst(extra.new_value), new_value_src);
const success_order = try sema.resolveAtomicOrder(block, success_order_src, extra.success_order, .{ .simple = .atomic_order });
const failure_order = try sema.resolveAtomicOrder(block, failure_order_src, extra.failure_order, .{ .simple = .atomic_order });
@@ -23470,16 +22641,13 @@ fn zirCmpxchg(
const result_ty = try pt.optionalType(elem_ty.toIntern());
// special case zero bit types
- if ((try sema.typeHasOnePossibleValue(elem_ty)) != null) {
- return Air.internedToRef((try pt.intern(.{ .opt = .{
- .ty = result_ty.toIntern(),
- .val = .none,
- } })));
+ if (elem_ty.classify(zcu) == .one_possible_value) {
+ return .fromValue(try pt.nullValue(result_ty));
}
const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: {
- if (try sema.resolveValue(expected_value)) |expected_val| {
- if (try sema.resolveValue(new_value)) |new_val| {
+ if (sema.resolveValue(expected_value)) |expected_val| {
+ if (sema.resolveValue(new_value)) |new_val| {
if (expected_val.isUndef(zcu) or new_val.isUndef(zcu)) {
// TODO: this should probably cause the memory stored at the pointer
// to become undef as well
@@ -23531,22 +22699,18 @@ fn zirSplat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
else => return sema.fail(block, src, "expected array or vector type, found '{f}'", .{dest_ty.fmt(pt)}),
}
- const operand = try sema.resolveInst(extra.rhs);
+ const operand = sema.resolveInst(extra.rhs);
const scalar_ty = dest_ty.childType(zcu);
const scalar = try sema.coerce(block, scalar_ty, operand, scalar_src);
const len = try sema.usizeCast(block, src, dest_ty.arrayLen(zcu));
- if (try sema.typeHasOnePossibleValue(dest_ty)) |val| {
- return Air.internedToRef(val.toIntern());
- }
-
- // We also need this case because `[0:s]T` is not OPV.
+ // If the length is 0, the result is comptime-known even if the operand isn't.
if (len == 0) return .fromValue(try pt.aggregateValue(dest_ty, &.{}));
const maybe_sentinel = dest_ty.sentinel(zcu);
- if (try sema.resolveValue(scalar)) |scalar_val| {
+ if (sema.resolveValue(scalar)) |scalar_val| {
full: {
if (dest_ty.zigTypeTag(zcu) == .vector) break :full;
const sentinel = maybe_sentinel orelse break :full;
@@ -23581,7 +22745,7 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
const op_src = block.builtinCallArgSrc(inst_data.src_node, 0);
const operand_src = block.builtinCallArgSrc(inst_data.src_node, 1);
const operation = try sema.resolveBuiltinEnum(block, op_src, extra.lhs, .ReduceOp, .{ .simple = .operand_reduce_operation });
- const operand = try sema.resolveInst(extra.rhs);
+ const operand = sema.resolveInst(extra.rhs);
const operand_ty = sema.typeOf(operand);
const pt = sema.pt;
const zcu = pt.zcu;
@@ -23615,7 +22779,7 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
return sema.fail(block, operand_src, "@reduce operation requires a vector with nonzero length", .{});
}
- if (try sema.resolveValue(operand)) |operand_val| {
+ if (sema.resolveValue(operand)) |operand_val| {
if (operand_val.isUndef(zcu)) return pt.undefRef(scalar_ty);
var accum: Value = try operand_val.elemValue(pt, 0);
@@ -23651,9 +22815,9 @@ fn zirShuffle(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
const elem_ty = try sema.resolveType(block, elem_ty_src, extra.elem_type);
try sema.checkVectorElemType(block, elem_ty_src, elem_ty);
- const a = try sema.resolveInst(extra.a);
- const b = try sema.resolveInst(extra.b);
- var mask = try sema.resolveInst(extra.mask);
+ const a = sema.resolveInst(extra.a);
+ const b = sema.resolveInst(extra.b);
+ var mask = sema.resolveInst(extra.mask);
var mask_ty = sema.typeOf(mask);
const mask_len = switch (sema.typeOf(mask).zigTypeTag(zcu)) {
@@ -23733,7 +22897,7 @@ fn analyzeShuffle(
continue;
}
// Safe because mask elements are `i32` and we already checked for undef:
- const raw = (try sema.resolveLazyValue(mask_val)).toSignedInt(zcu);
+ const raw = mask_val.toSignedInt(zcu);
if (raw >= 0) {
const idx: u32 = @intCast(raw);
a_used = true;
@@ -23760,8 +22924,8 @@ fn analyzeShuffle(
}
}
- const maybe_a_val = try sema.resolveValue(a_coerced);
- const maybe_b_val = try sema.resolveValue(b_coerced);
+ const maybe_a_val = sema.resolveValue(a_coerced);
+ const maybe_b_val = sema.resolveValue(b_coerced);
const a_rt = a_used and maybe_a_val == null;
const b_rt = b_used and maybe_b_val == null;
@@ -23849,7 +23013,7 @@ fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C
const elem_ty = try sema.resolveType(block, elem_ty_src, extra.elem_type);
try sema.checkVectorElemType(block, elem_ty_src, elem_ty);
- const pred_uncoerced = try sema.resolveInst(extra.pred);
+ const pred_uncoerced = sema.resolveInst(extra.pred);
const pred_ty = sema.typeOf(pred_uncoerced);
const vec_len_u64 = switch (pred_ty.zigTypeTag(zcu)) {
@@ -23868,12 +23032,12 @@ fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C
.len = vec_len,
.child = elem_ty.toIntern(),
});
- const a = try sema.coerce(block, vec_ty, try sema.resolveInst(extra.a), a_src);
- const b = try sema.coerce(block, vec_ty, try sema.resolveInst(extra.b), b_src);
+ const a = try sema.coerce(block, vec_ty, sema.resolveInst(extra.a), a_src);
+ const b = try sema.coerce(block, vec_ty, sema.resolveInst(extra.b), b_src);
- const maybe_pred = try sema.resolveValue(pred);
- const maybe_a = try sema.resolveValue(a);
- const maybe_b = try sema.resolveValue(b);
+ const maybe_pred = sema.resolveValue(pred);
+ const maybe_a = sema.resolveValue(a);
+ const maybe_b = sema.resolveValue(b);
const runtime_src = if (maybe_pred) |pred_val| rs: {
if (pred_val.isUndef(zcu)) return pt.undefRef(vec_ty);
@@ -23934,10 +23098,12 @@ fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
const order_src = block.builtinCallArgSrc(inst_data.src_node, 2);
// zig fmt: on
const elem_ty = try sema.resolveType(block, elem_ty_src, extra.elem_type);
- const uncasted_ptr = try sema.resolveInst(extra.ptr);
+ const uncasted_ptr = sema.resolveInst(extra.ptr);
const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, true);
const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering, .{ .simple = .atomic_order });
+ try sema.ensureLayoutResolved(elem_ty, elem_ty_src, .ptr_access);
+
switch (order) {
.release, .acq_rel => {
return sema.fail(
@@ -23950,9 +23116,7 @@ fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
else => {},
}
- if (try sema.typeHasOnePossibleValue(elem_ty)) |val| {
- return Air.internedToRef(val.toIntern());
- }
+ if (try elem_ty.onePossibleValue(sema.pt)) |opv| return .fromValue(opv);
if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| {
if (try sema.pointerDeref(block, ptr_src, ptr_val, sema.typeOf(ptr))) |elem_val| {
@@ -23983,9 +23147,9 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
const operand_src = block.builtinCallArgSrc(inst_data.src_node, 3);
const order_src = block.builtinCallArgSrc(inst_data.src_node, 4);
// zig fmt: on
- const operand = try sema.resolveInst(extra.operand);
+ const operand = sema.resolveInst(extra.operand);
const elem_ty = sema.typeOf(operand);
- const uncasted_ptr = try sema.resolveInst(extra.ptr);
+ const uncasted_ptr = sema.resolveInst(extra.ptr);
const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false);
const op = try sema.resolveAtomicRmwOp(block, op_src, extra.operation);
@@ -24009,12 +23173,10 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
}
// special case zero bit types
- if (try sema.typeHasOnePossibleValue(elem_ty)) |val| {
- return Air.internedToRef(val.toIntern());
- }
+ if (try elem_ty.onePossibleValue(pt)) |opv| return .fromValue(opv);
const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: {
- const maybe_operand_val = try sema.resolveValue(operand);
+ const maybe_operand_val = sema.resolveValue(operand);
const operand_val = maybe_operand_val orelse {
try sema.checkPtrIsNotComptimeMutable(block, ptr_val, ptr_src, operand_src);
break :rs operand_src;
@@ -24065,9 +23227,9 @@ fn zirAtomicStore(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
const operand_src = block.builtinCallArgSrc(inst_data.src_node, 2);
const order_src = block.builtinCallArgSrc(inst_data.src_node, 3);
// zig fmt: on
- const operand = try sema.resolveInst(extra.operand);
+ const operand = sema.resolveInst(extra.operand);
const elem_ty = sema.typeOf(operand);
- const uncasted_ptr = try sema.resolveInst(extra.ptr);
+ const uncasted_ptr = sema.resolveInst(extra.ptr);
const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false);
const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering, .{ .simple = .atomic_order });
@@ -24098,14 +23260,14 @@ fn zirMulAdd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
const mulend2_src = block.builtinCallArgSrc(inst_data.src_node, 2);
const addend_src = block.builtinCallArgSrc(inst_data.src_node, 3);
- const addend = try sema.resolveInst(extra.addend);
+ const addend = sema.resolveInst(extra.addend);
const ty = sema.typeOf(addend);
- const mulend1 = try sema.coerce(block, ty, try sema.resolveInst(extra.mulend1), mulend1_src);
- const mulend2 = try sema.coerce(block, ty, try sema.resolveInst(extra.mulend2), mulend2_src);
+ const mulend1 = try sema.coerce(block, ty, sema.resolveInst(extra.mulend1), mulend1_src);
+ const mulend2 = try sema.coerce(block, ty, sema.resolveInst(extra.mulend2), mulend2_src);
- const maybe_mulend1 = try sema.resolveValue(mulend1);
- const maybe_mulend2 = try sema.resolveValue(mulend2);
- const maybe_addend = try sema.resolveValue(addend);
+ const maybe_mulend1 = sema.resolveValue(mulend1);
+ const maybe_mulend2 = sema.resolveValue(mulend2);
+ const maybe_addend = sema.resolveValue(addend);
const pt = sema.pt;
const zcu = pt.zcu;
@@ -24167,10 +23329,10 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
const call_src = block.nodeOffset(inst_data.src_node);
const extra = sema.code.extraData(Zir.Inst.BuiltinCall, inst_data.payload_index).data;
- const func = try sema.resolveInst(extra.callee);
+ const func = sema.resolveInst(extra.callee);
const modifier_ty = try sema.getBuiltinType(call_src, .CallModifier);
- const air_ref = try sema.resolveInst(extra.modifier);
+ const air_ref = sema.resolveInst(extra.modifier);
const modifier_ref = try sema.coerce(block, modifier_ty, air_ref, modifier_src);
const modifier_val = try sema.resolveConstDefinedValue(block, modifier_src, modifier_ref, .{ .simple = .call_modifier });
var modifier = try sema.interpretBuiltinType(block, modifier_src, modifier_val, std.builtin.CallModifier);
@@ -24208,7 +23370,7 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
},
}
- const args = try sema.resolveInst(extra.args);
+ const args = sema.resolveInst(extra.args);
const args_ty = sema.typeOf(args);
if (!args_ty.isTuple(zcu)) {
@@ -24253,18 +23415,23 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
const field_name_src = block.builtinCallArgSrc(extra.src_node, 0);
const field_ptr_src = block.builtinCallArgSrc(extra.src_node, 1);
- const parent_ptr_ty = try sema.resolveDestType(block, inst_src, extra.parent_ptr_type, .remove_eu, "@fieldParentPtr");
- try sema.checkPtrType(block, inst_src, parent_ptr_ty, true);
+ const maybe_opt_parent_ptr_ty = try sema.resolveDestType(block, inst_src, extra.parent_ptr_type, .remove_eu, "@fieldParentPtr");
+ try sema.checkPtrType(block, inst_src, maybe_opt_parent_ptr_ty, true);
+ const parent_ptr_ty = switch (maybe_opt_parent_ptr_ty.zigTypeTag(zcu)) {
+ .optional => maybe_opt_parent_ptr_ty.optionalChild(zcu),
+ .pointer => maybe_opt_parent_ptr_ty,
+ else => unreachable,
+ };
const parent_ptr_info = parent_ptr_ty.ptrInfo(zcu);
if (parent_ptr_info.flags.size != .one) {
return sema.fail(block, inst_src, "expected single pointer type, found '{f}'", .{parent_ptr_ty.fmt(pt)});
}
const parent_ty: Type = .fromInterned(parent_ptr_info.child);
+ try sema.ensureLayoutResolved(parent_ty, inst_src, .field_used);
switch (parent_ty.zigTypeTag(zcu)) {
.@"struct", .@"union" => {},
else => return sema.fail(block, inst_src, "expected pointer to struct or union type, found '{f}'", .{parent_ptr_ty.fmt(pt)}),
}
- try parent_ty.resolveLayout(pt);
const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.field_name, .{ .simple = .field_name });
const field_index = switch (parent_ty.zigTypeTag(zcu)) {
@@ -24285,144 +23452,77 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
return sema.fail(block, field_name_src, "cannot get @fieldParentPtr of a comptime field", .{});
}
- const field_ptr = try sema.resolveInst(extra.field_ptr);
+ const field_ptr = sema.resolveInst(extra.field_ptr);
const field_ptr_ty = sema.typeOf(field_ptr);
try sema.checkPtrOperand(block, field_ptr_src, field_ptr_ty);
- const field_ptr_info = field_ptr_ty.ptrInfo(zcu);
- var actual_parent_ptr_info: InternPool.Key.PtrType = .{
- .child = parent_ty.toIntern(),
- .flags = .{
- .alignment = try parent_ptr_ty.ptrAlignmentSema(pt),
- .is_const = field_ptr_info.flags.is_const,
- .is_volatile = field_ptr_info.flags.is_volatile,
- .is_allowzero = field_ptr_info.flags.is_allowzero,
- .address_space = field_ptr_info.flags.address_space,
- },
- .packed_offset = parent_ptr_info.packed_offset,
- };
- const field_ty = parent_ty.fieldType(field_index, zcu);
- var actual_field_ptr_info: InternPool.Key.PtrType = .{
- .child = field_ty.toIntern(),
- .flags = .{
- .alignment = try field_ptr_ty.ptrAlignmentSema(pt),
- .is_const = field_ptr_info.flags.is_const,
- .is_volatile = field_ptr_info.flags.is_volatile,
- .is_allowzero = field_ptr_info.flags.is_allowzero,
- .address_space = field_ptr_info.flags.address_space,
- },
- .packed_offset = field_ptr_info.packed_offset,
- };
- switch (parent_ty.containerLayout(zcu)) {
- .auto => {
- actual_parent_ptr_info.flags.alignment = actual_field_ptr_info.flags.alignment.minStrict(
- if (zcu.typeToStruct(parent_ty)) |struct_obj|
- try field_ty.structFieldAlignmentSema(
- struct_obj.fieldAlign(ip, field_index),
- struct_obj.layout,
- pt,
- )
- else if (zcu.typeToUnion(parent_ty)) |union_obj|
- try field_ty.unionFieldAlignmentSema(
- union_obj.fieldAlign(ip, field_index),
- union_obj.flagsUnordered(ip).layout,
- pt,
- )
- else
- actual_field_ptr_info.flags.alignment,
- );
+ const hypothetical_field_ptr_ty = try parent_ptr_ty.fieldPtrType(field_index, pt);
+ const casted_field_ptr = try sema.ptrCastFull(
+ block,
+ flags,
+ inst_src,
+ field_ptr,
+ field_ptr_src,
+ hypothetical_field_ptr_ty,
+ "@fieldParentPtr",
+ );
- actual_parent_ptr_info.packed_offset = .{ .bit_offset = 0, .host_size = 0 };
- actual_field_ptr_info.packed_offset = .{ .bit_offset = 0, .host_size = 0 };
- },
- .@"extern" => {
- const field_offset = parent_ty.structFieldOffset(field_index, zcu);
- actual_parent_ptr_info.flags.alignment = actual_field_ptr_info.flags.alignment.minStrict(if (field_offset > 0)
- Alignment.fromLog2Units(@ctz(field_offset))
- else
- actual_field_ptr_info.flags.alignment);
+ const unaligned_parent_ptr_ty = try pt.ptrType(info: {
+ var info = parent_ptr_info;
+ info.flags.alignment = hypothetical_field_ptr_ty.ptrAlignment(zcu);
+ break :info info;
+ });
- actual_parent_ptr_info.packed_offset = .{ .bit_offset = 0, .host_size = 0 };
- actual_field_ptr_info.packed_offset = .{ .bit_offset = 0, .host_size = 0 };
- },
- .@"packed" => {
- const byte_offset = std.math.divExact(u32, @abs(@as(i32, actual_parent_ptr_info.packed_offset.bit_offset) +
- (if (zcu.typeToStruct(parent_ty)) |struct_obj| zcu.structPackedFieldBitOffset(struct_obj, field_index) else 0) -
- actual_field_ptr_info.packed_offset.bit_offset), 8) catch
- return sema.fail(block, inst_src, "pointer bit-offset mismatch", .{});
- actual_parent_ptr_info.flags.alignment = actual_field_ptr_info.flags.alignment.minStrict(if (byte_offset > 0)
- Alignment.fromLog2Units(@ctz(byte_offset))
- else
- actual_field_ptr_info.flags.alignment);
- },
- }
-
- const actual_field_ptr_ty = try pt.ptrTypeSema(actual_field_ptr_info);
- const casted_field_ptr = try sema.coerce(block, actual_field_ptr_ty, field_ptr, field_ptr_src);
- const actual_parent_ptr_ty = try pt.ptrTypeSema(actual_parent_ptr_info);
-
- const result = if (try sema.resolveDefinedValue(block, field_ptr_src, casted_field_ptr)) |field_ptr_val| result: {
- switch (parent_ty.zigTypeTag(zcu)) {
- .@"struct" => switch (parent_ty.containerLayout(zcu)) {
- .auto => {},
- .@"extern" => {
- const byte_offset = parent_ty.structFieldOffset(field_index, zcu);
- const parent_ptr_val = try sema.ptrSubtract(block, field_ptr_src, field_ptr_val, byte_offset, actual_parent_ptr_ty);
- break :result Air.internedToRef(parent_ptr_val.toIntern());
- },
- .@"packed" => {
- // Logic lifted from type computation above - I'm just assuming it's correct.
- // `catch unreachable` since error case handled above.
- const byte_offset = std.math.divExact(u32, @abs(@as(i32, actual_parent_ptr_info.packed_offset.bit_offset) +
- zcu.structPackedFieldBitOffset(zcu.typeToStruct(parent_ty).?, field_index) -
- actual_field_ptr_info.packed_offset.bit_offset), 8) catch unreachable;
- const parent_ptr_val = try sema.ptrSubtract(block, field_ptr_src, field_ptr_val, byte_offset, actual_parent_ptr_ty);
- break :result Air.internedToRef(parent_ptr_val.toIntern());
- },
- },
- .@"union" => switch (parent_ty.containerLayout(zcu)) {
- .auto => {},
- .@"extern", .@"packed" => {
- // For an extern or packed union, just coerce the pointer.
- const parent_ptr_val = try pt.getCoerced(field_ptr_val, actual_parent_ptr_ty);
- break :result Air.internedToRef(parent_ptr_val.toIntern());
- },
- },
+ const unaligned_parent_ptr: Air.Inst.Ref = if (try sema.resolveDefinedValue(
+ block,
+ field_ptr_src,
+ casted_field_ptr,
+ )) |field_ptr_val| switch (parent_ty.containerLayout(zcu)) {
+ .@"packed" => .fromValue(try pt.getCoerced(field_ptr_val, unaligned_parent_ptr_ty)),
+ .@"extern" => switch (parent_ty.zigTypeTag(zcu)) {
+ .@"struct" => .fromValue(try sema.ptrSubtract(
+ block,
+ field_ptr_src,
+ field_ptr_val,
+ parent_ty.structFieldOffset(field_index, zcu),
+ unaligned_parent_ptr_ty,
+ )),
+ .@"union" => .fromValue(try pt.getCoerced(field_ptr_val, unaligned_parent_ptr_ty)),
else => unreachable,
- }
-
- const opt_field: ?InternPool.Key.Ptr.BaseAddr.BaseIndex = opt_field: {
- const ptr = switch (ip.indexToKey(field_ptr_val.toIntern())) {
- .ptr => |ptr| ptr,
- else => break :opt_field null,
- };
- if (ptr.byte_offset != 0) break :opt_field null;
- break :opt_field switch (ptr.base_addr) {
- .field => |field| field,
- else => null,
+ },
+ .auto => result: {
+ const opt_field: ?InternPool.Key.Ptr.BaseAddr.BaseIndex = opt_field: {
+ const ptr = switch (ip.indexToKey(field_ptr_val.toIntern())) {
+ .ptr => |ptr| ptr,
+ else => break :opt_field null,
+ };
+ if (ptr.byte_offset != 0) break :opt_field null;
+ break :opt_field switch (ptr.base_addr) {
+ .field => |field| field,
+ else => null,
+ };
};
- };
- const field = opt_field orelse {
- return sema.fail(block, field_ptr_src, "pointer value not based on parent struct", .{});
- };
+ const field = opt_field orelse {
+ return sema.fail(block, field_ptr_src, "pointer value not based on parent struct", .{});
+ };
- if (Value.fromInterned(field.base).typeOf(zcu).childType(zcu).toIntern() != parent_ty.toIntern()) {
- return sema.fail(block, field_ptr_src, "pointer value not based on parent struct", .{});
- }
+ if (Value.fromInterned(field.base).typeOf(zcu).childType(zcu).toIntern() != parent_ty.toIntern()) {
+ return sema.fail(block, field_ptr_src, "pointer value not based on parent struct", .{});
+ }
- if (field.index != field_index) {
- return sema.fail(block, inst_src, "field '{f}' has index '{d}' but pointer value is index '{d}' of struct '{f}'", .{
- field_name.fmt(ip), field_index, field.index, parent_ty.fmt(pt),
- });
- }
- break :result try sema.coerce(block, actual_parent_ptr_ty, Air.internedToRef(field.base), inst_src);
+ if (field.index != field_index) {
+ return sema.fail(block, inst_src, "field '{f}' has index '{d}' but pointer value is index '{d}' of struct '{f}'", .{
+ field_name.fmt(ip), field_index, field.index, parent_ty.fmt(pt),
+ });
+ }
+ break :result .fromValue(try pt.getCoerced(.fromInterned(field.base), unaligned_parent_ptr_ty));
+ },
} else result: {
- try sema.requireRuntimeBlock(block, inst_src, field_ptr_src);
break :result try block.addInst(.{
.tag = .field_parent_ptr,
.data = .{ .ty_pl = .{
- .ty = Air.internedToRef(actual_parent_ptr_ty.toIntern()),
+ .ty = .fromType(unaligned_parent_ptr_ty),
.payload = try block.sema.addExtra(Air.FieldParentPtr{
.field_ptr = casted_field_ptr,
.field_index = @intCast(field_index),
@@ -24430,14 +23530,61 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
} },
});
};
- return sema.ptrCastFull(block, flags, inst_src, result, inst_src, parent_ptr_ty, "@fieldParentPtr");
+
+ // There's one more error condition: if the hypothetical field pointer type has a lower
+ // alignment than the parent pointer type, then we need an `@alignCast`. Note that the earlier
+ // `ptrCastFull` may *also* have "used" the `@alignCast`; that would be a case where the field
+ // is naturally less aligned than the rest of the struct, *and* the field pointer is itself
+ // underaligned compared to the field alignment. For example, `struct { a: u32, b: u16 }` with
+ // a field pointer of type `*align(1) u16`.
+ switch (hypothetical_field_ptr_ty.ptrAlignment(zcu).order(parent_ptr_ty.ptrAlignment(zcu))) {
+ .gt => unreachable, // getting a field pointer can never increase alignment
+ .eq => return sema.coerce(block, maybe_opt_parent_ptr_ty, unaligned_parent_ptr, inst_src),
+ .lt => if (flags.align_cast) {
+ // Go through `ptrCastFull` for the safety check.
+ return sema.ptrCastFull(
+ block,
+ flags,
+ inst_src,
+ unaligned_parent_ptr,
+ inst_src,
+ maybe_opt_parent_ptr_ty,
+ "@fieldParentPtr",
+ );
+ } else return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(inst_src, "@fieldParentPtr increases pointer alignment", .{});
+ errdefer msg.destroy(sema.gpa);
+ try sema.errNote(inst_src, msg, "parent pointer type '{f}' has alignment '{d}'", .{
+ parent_ptr_ty.fmt(pt),
+ parent_ptr_ty.abiAlignment(zcu),
+ });
+ if (parent_ty.isTuple(zcu)) {
+ try sema.errNote(field_ptr_src, msg, "tuple field '{d}' limits alignment to '{d}'", .{
+ field_index,
+ field_ptr_ty.ptrAlignment(zcu),
+ });
+ } else {
+ try sema.errNote(parent_ty.srcLoc(zcu), msg, "{t} field '{f}' limits alignment to '{d}'", .{
+ parent_ty.zigTypeTag(zcu),
+ switch (parent_ty.zigTypeTag(zcu)) {
+ .@"struct" => parent_ty.structFieldName(field_index, zcu).unwrap().?.fmt(ip),
+ .@"union" => parent_ty.unionTagTypeHypothetical(zcu).enumFieldName(field_index, zcu).fmt(ip),
+ else => unreachable,
+ },
+ field_ptr_ty.ptrAlignment(zcu),
+ });
+ }
+ try sema.errNote(inst_src, msg, "use @alignCast to assert pointer alignment", .{});
+ break :msg msg;
+ }),
+ }
}
fn ptrSubtract(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, byte_subtract: u64, new_ty: Type) !Value {
const pt = sema.pt;
const zcu = pt.zcu;
if (byte_subtract == 0) return pt.getCoerced(ptr_val, new_ty);
- var ptr = switch (zcu.intern_pool.indexToKey(ptr_val.toIntern())) {
+ const ptr = switch (zcu.intern_pool.indexToKey(ptr_val.toIntern())) {
.undef => return sema.failWithUseOfUndef(block, src, null),
.ptr => |ptr| ptr,
else => unreachable,
@@ -24450,9 +23597,11 @@ fn ptrSubtract(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, byte
break :msg msg;
});
}
- ptr.byte_offset -= byte_subtract;
- ptr.ty = new_ty.toIntern();
- return Value.fromInterned(try pt.intern(.{ .ptr = ptr }));
+ return Value.fromInterned(try pt.intern(.{ .ptr = .{
+ .ty = new_ty.toIntern(),
+ .base_addr = ptr.base_addr,
+ .byte_offset = ptr.byte_offset - byte_subtract,
+ } }));
}
fn zirMinMax(
@@ -24466,8 +23615,8 @@ fn zirMinMax(
const src = block.nodeOffset(inst_data.src_node);
const lhs_src = block.builtinCallArgSrc(inst_data.src_node, 0);
const rhs_src = block.builtinCallArgSrc(inst_data.src_node, 1);
- const lhs = try sema.resolveInst(extra.lhs);
- const rhs = try sema.resolveInst(extra.rhs);
+ const lhs = sema.resolveInst(extra.lhs);
+ const rhs = sema.resolveInst(extra.rhs);
return sema.analyzeMinMax(block, src, air_tag, &.{ lhs, rhs }, &.{ lhs_src, rhs_src });
}
@@ -24487,7 +23636,7 @@ fn zirMinMaxMulti(
for (operands, air_refs, operand_srcs, 0..) |zir_ref, *air_ref, *op_src, i| {
op_src.* = block.builtinCallArgSrc(src_node, @intCast(i));
- air_ref.* = try sema.resolveInst(zir_ref);
+ air_ref.* = sema.resolveInst(zir_ref);
}
return sema.analyzeMinMax(block, src, air_tag, air_refs, operand_srcs);
@@ -24590,7 +23739,7 @@ fn analyzeMinMax(
const operand_scalar_ty = sema.typeOf(operand).scalarType(zcu);
const want_strat: TypeStrat = switch (operand_scalar_ty.zigTypeTag(zcu)) {
.comptime_int => s: {
- const val = (try sema.resolveValueResolveLazy(operand)).?;
+ const val = sema.resolveValue(operand).?;
if (val.isUndef(zcu)) break :s .none;
break :s .{ .int = .{
.all_comptime_int = true,
@@ -24609,7 +23758,7 @@ fn analyzeMinMax(
// (replaced with just the simple calls to `Type.minInt`/`Type.maxInt`) so that we only
// use the input *types* to determine the result type.
const min: Value, const max: Value = bounds: {
- if (try sema.resolveValueResolveLazy(operand)) |operand_val| {
+ if (sema.resolveValue(operand)) |operand_val| {
if (vector_len) |len| {
var min = try operand_val.elemValue(pt, 0);
var max = min;
@@ -24696,6 +23845,9 @@ fn analyzeMinMax(
.child = intermediate_scalar_ty.toIntern(),
}) else intermediate_scalar_ty;
+ // We might have refined all the way down to an OPV type---check now.
+ if (try result_ty.onePossibleValue(pt)) |opv| return .fromValue(opv);
+
// This value, if not `null`, will have type `intermediate_ty`.
const comptime_part: ?Value = ct: {
// Contains the comptime-known scalar result values.
@@ -24712,7 +23864,7 @@ fn analyzeMinMax(
var opt_runtime_src: ?LazySrcLoc = null;
for (operands, operand_srcs) |operand, operand_src| {
- const operand_val = try sema.resolveValueResolveLazy(operand) orelse {
+ const operand_val = sema.resolveValue(operand) orelse {
if (opt_runtime_src == null) opt_runtime_src = operand_src;
continue;
};
@@ -24819,7 +23971,7 @@ fn upgradeToArrayPtr(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, len: u64) !A
// Already an array pointer.
return ptr;
}
- const new_ty = try pt.ptrTypeSema(.{
+ const new_ty = try pt.ptrType(.{
.child = (try pt.arrayType(.{
.len = len,
.sentinel = info.sentinel,
@@ -24852,8 +24004,8 @@ fn zirMemcpy(
const src = block.nodeOffset(inst_data.src_node);
const dest_src = block.builtinCallArgSrc(inst_data.src_node, 0);
const src_src = block.builtinCallArgSrc(inst_data.src_node, 1);
- const dest_ptr = try sema.resolveInst(extra.lhs);
- const src_ptr = try sema.resolveInst(extra.rhs);
+ const dest_ptr = sema.resolveInst(extra.lhs);
+ const src_ptr = sema.resolveInst(extra.rhs);
const dest_ty = sema.typeOf(dest_ptr);
const src_ty = sema.typeOf(src_ptr);
const dest_len = try indexablePtrLenOrNone(sema, block, dest_src, dest_ptr);
@@ -24880,8 +24032,11 @@ fn zirMemcpy(
return sema.failWithOwnedErrorMsg(block, msg);
}
- const dest_elem_ty = dest_ty.indexablePtrElem(zcu);
- const src_elem_ty = src_ty.indexablePtrElem(zcu);
+ const dest_elem_ty = dest_ty.indexableElem(zcu);
+ const src_elem_ty = src_ty.indexableElem(zcu);
+
+ try sema.ensureLayoutResolved(dest_elem_ty, dest_src, .ptr_access);
+ try sema.ensureLayoutResolved(src_elem_ty, src_src, .ptr_access);
const imc = try sema.coerceInMemoryAllowed(
block,
@@ -24946,13 +24101,13 @@ fn zirMemcpy(
}
zero_bit: {
- const src_comptime = try src_elem_ty.comptimeOnlySema(pt);
- const dest_comptime = try dest_elem_ty.comptimeOnlySema(pt);
+ const src_comptime = src_elem_ty.comptimeOnly(zcu);
+ const dest_comptime = dest_elem_ty.comptimeOnly(zcu);
assert(src_comptime == dest_comptime); // IMC
if (src_comptime) break :zero_bit;
- const src_has_bits = try src_elem_ty.hasRuntimeBitsIgnoreComptimeSema(pt);
- const dest_has_bits = try dest_elem_ty.hasRuntimeBitsIgnoreComptimeSema(pt);
+ const src_has_bits = src_elem_ty.hasRuntimeBits(zcu);
+ const dest_has_bits = dest_elem_ty.hasRuntimeBits(zcu);
assert(src_has_bits == dest_has_bits); // IMC
if (src_has_bits) break :zero_bit;
@@ -24968,7 +24123,7 @@ fn zirMemcpy(
const raw_dest_ptr = if (dest_ty.isSlice(zcu)) dest_ptr_val.slicePtr(zcu) else dest_ptr_val;
const raw_src_ptr = if (src_ty.isSlice(zcu)) src_ptr_val.slicePtr(zcu) else src_ptr_val;
- const len_u64 = try len_val.?.toUnsignedIntSema(pt);
+ const len_u64 = len_val.?.toUnsignedInt(zcu);
if (check_aliasing) {
if (Value.doPointersOverlap(
@@ -25018,7 +24173,7 @@ fn zirMemcpy(
var new_dest_ptr = dest_ptr;
var new_src_ptr = src_ptr;
if (len_val) |val| {
- const len = try val.toUnsignedIntSema(pt);
+ const len = val.toUnsignedInt(zcu);
if (len == 0) {
// This AIR instruction guarantees length > 0 if it is comptime-known.
return;
@@ -25036,7 +24191,7 @@ fn zirMemcpy(
}
} else if (dest_len == .none and len_val == null) {
// Change the dest to a slice, since its type must have the length.
- const dest_ptr_ptr = try sema.analyzeRef(block, dest_src, new_dest_ptr);
+ const dest_ptr_ptr = try sema.analyzeRef(block, dest_src, new_dest_ptr, .none);
new_dest_ptr = try sema.analyzeSlice(block, dest_src, dest_ptr_ptr, .zero, src_len, .none, LazySrcLoc.unneeded, dest_src, dest_src, dest_src, false);
const new_src_ptr_ty = sema.typeOf(new_src_ptr);
if (new_src_ptr_ty.isSlice(zcu)) {
@@ -25067,7 +24222,7 @@ fn zirMemcpy(
assert(dest_manyptr_ty_key.flags.size == .one);
dest_manyptr_ty_key.child = dest_elem_ty.toIntern();
dest_manyptr_ty_key.flags.size = .many;
- break :ptr try sema.coerceCompatiblePtrs(block, try pt.ptrTypeSema(dest_manyptr_ty_key), new_dest_ptr, dest_src);
+ break :ptr try sema.coerceCompatiblePtrs(block, try pt.ptrType(dest_manyptr_ty_key), new_dest_ptr, dest_src);
} else new_dest_ptr;
const new_src_ptr_ty = sema.typeOf(new_src_ptr);
@@ -25078,13 +24233,13 @@ fn zirMemcpy(
assert(src_manyptr_ty_key.flags.size == .one);
src_manyptr_ty_key.child = src_elem_ty.toIntern();
src_manyptr_ty_key.flags.size = .many;
- break :ptr try sema.coerceCompatiblePtrs(block, try pt.ptrTypeSema(src_manyptr_ty_key), new_src_ptr, src_src);
+ break :ptr try sema.coerceCompatiblePtrs(block, try pt.ptrType(src_manyptr_ty_key), new_src_ptr, src_src);
} else new_src_ptr;
// ok1: dest >= src + len
// ok2: src >= dest + len
- const src_plus_len = try sema.analyzePtrArithmetic(block, src, raw_src_ptr, len, .ptr_add, src_src, src);
- const dest_plus_len = try sema.analyzePtrArithmetic(block, src, raw_dest_ptr, len, .ptr_add, dest_src, src);
+ const src_plus_len = try sema.analyzePtrArithmetic(block, src, raw_src_ptr, len, .ptr_add, src);
+ const dest_plus_len = try sema.analyzePtrArithmetic(block, src, raw_dest_ptr, len, .ptr_add, src);
const ok1 = try block.addBinOp(.cmp_gte, raw_dest_ptr, src_plus_len);
const ok2 = try block.addBinOp(.cmp_gte, new_src_ptr, dest_plus_len);
const ok = try block.addBinOp(.bool_or, ok1, ok2);
@@ -25113,8 +24268,8 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
const src = block.nodeOffset(inst_data.src_node);
const dest_src = block.builtinCallArgSrc(inst_data.src_node, 0);
const value_src = block.builtinCallArgSrc(inst_data.src_node, 1);
- const dest_ptr = try sema.resolveInst(extra.lhs);
- const uncoerced_elem = try sema.resolveInst(extra.rhs);
+ const dest_ptr = sema.resolveInst(extra.lhs);
+ const uncoerced_elem = sema.resolveInst(extra.rhs);
const dest_ptr_ty = sema.typeOf(dest_ptr);
try checkMemOperand(sema, block, dest_src, dest_ptr_ty);
@@ -25145,10 +24300,17 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
const elem = try sema.coerce(block, dest_elem_ty, uncoerced_elem, value_src);
+ const comptime_only_elem = switch (dest_elem_ty.classify(zcu)) {
+ .no_possible_value => unreachable, // `elem` is a value of this type
+ .one_possible_value => return, // no work to do
+ .runtime => false,
+ .partially_comptime, .fully_comptime => true,
+ };
+
const runtime_src = rs: {
const len_air_ref = try sema.fieldVal(block, src, dest_ptr, try ip.getOrPutString(gpa, io, pt.tid, "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.toUnsignedIntSema(pt);
+ const len_u64 = len_val.toUnsignedInt(zcu);
const len = try sema.usizeCast(block, dest_src, len_u64);
if (len == 0) {
// This AIR instruction guarantees length > 0 if it is comptime-known.
@@ -25157,7 +24319,7 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
const ptr_val = try sema.resolveDefinedValue(block, dest_src, dest_ptr) orelse break :rs dest_src;
if (!sema.isComptimeMutablePtr(ptr_val)) break :rs dest_src;
- const elem_val = try sema.resolveValue(elem) orelse break :rs value_src;
+ const elem_val = sema.resolveValue(elem) orelse break :rs value_src;
const array_ty = try pt.arrayType(.{
.child = dest_elem_ty.toIntern(),
.len = len_u64,
@@ -25174,6 +24336,15 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
return sema.storePtrVal(block, src, array_ptr_val, array_val, array_ty);
};
+ if (comptime_only_elem) {
+ return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(src, "cannot store comptime-only element '{f}' at runtime", .{dest_elem_ty.fmt(pt)});
+ errdefer msg.destroy(sema.gpa);
+ try sema.errNote(dest_src, msg, "operation is runtime due to destination pointer", .{});
+ break :msg msg;
+ });
+ }
+
try sema.requireRuntimeBlock(block, src, runtime_src);
try sema.validateRuntimeValue(block, dest_src, dest_ptr);
try sema.validateRuntimeValue(block, value_src, elem);
@@ -25227,7 +24398,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
const cc_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);
extra_index += 1;
const cc_ty = try sema.getBuiltinType(cc_src, .CallingConvention);
- const uncoerced_cc = try sema.resolveInst(cc_ref);
+ const uncoerced_cc = sema.resolveInst(cc_ref);
const coerced_cc = try sema.coerce(block, cc_ty, uncoerced_cc, cc_src);
const cc_val = try sema.resolveConstDefinedValue(block, cc_src, coerced_cc, .{ .simple = .@"callconv" });
break :blk try sema.analyzeValueAsCallconv(block, cc_src, cc_val);
@@ -25344,7 +24515,7 @@ fn zirCDefine(
const val_src = block.builtinCallArgSrc(extra.node, 1);
const name = try sema.resolveConstString(block, name_src, extra.lhs, .{ .simple = .operand_cDefine_macro_name });
- const rhs = try sema.resolveInst(extra.rhs);
+ const rhs = sema.resolveInst(extra.rhs);
if (sema.typeOf(rhs).zigTypeTag(zcu) != .void) {
const value = try sema.resolveConstString(block, val_src, extra.rhs, .{ .simple = .operand_cDefine_macro_value });
try block.c_import_buf.?.print("#define {s} {s}\n", .{ name, value });
@@ -25393,7 +24564,7 @@ fn zirWasmMemoryGrow(
}
const index: u32 = @intCast(try sema.resolveInt(block, index_src, extra.lhs, .u32, .{ .simple = .wasm_memory_index }));
- const delta = try sema.coerce(block, .usize, try sema.resolveInst(extra.rhs), delta_src);
+ const delta = try sema.coerce(block, .usize, sema.resolveInst(extra.rhs), delta_src);
try sema.requireRuntimeBlock(block, builtin_src, null);
return block.addInst(.{
@@ -25419,7 +24590,7 @@ fn resolvePrefetchOptions(
const ip = &zcu.intern_pool;
const options_ty = try sema.getBuiltinType(src, .PrefetchOptions);
- const options = try sema.coerce(block, options_ty, try sema.resolveInst(zir_ref), src);
+ const options = try sema.coerce(block, options_ty, sema.resolveInst(zir_ref), src);
const rw_src = block.src(.{ .init_field_rw = src.offset.node_offset_builtin_call_arg.builtin_call_node });
const locality_src = block.src(.{ .init_field_locality = src.offset.node_offset_builtin_call_arg.builtin_call_node });
@@ -25436,7 +24607,7 @@ fn resolvePrefetchOptions(
return std.builtin.PrefetchOptions{
.rw = try sema.interpretBuiltinType(block, rw_src, rw_val, std.builtin.PrefetchOptions.Rw),
- .locality = @intCast(try locality_val.toUnsignedIntSema(pt)),
+ .locality = @intCast(locality_val.toUnsignedInt(zcu)),
.cache = try sema.interpretBuiltinType(block, cache_src, cache_val, std.builtin.PrefetchOptions.Cache),
};
}
@@ -25449,7 +24620,7 @@ fn zirPrefetch(
const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
const ptr_src = block.builtinCallArgSrc(extra.node, 0);
const opts_src = block.builtinCallArgSrc(extra.node, 1);
- const ptr = try sema.resolveInst(extra.lhs);
+ const ptr = sema.resolveInst(extra.lhs);
try sema.checkPtrOperand(block, ptr_src, sema.typeOf(ptr));
const options = try sema.resolvePrefetchOptions(block, opts_src, extra.rhs);
@@ -25491,7 +24662,7 @@ fn resolveExternOptions(
const io = comp.io;
const ip = &zcu.intern_pool;
- const options_inst = try sema.resolveInst(zir_ref);
+ const options_inst = sema.resolveInst(zir_ref);
const extern_options_ty = try sema.getBuiltinType(src, .ExternOptions);
const options = try sema.coerce(block, extern_options_ty, options_inst, src);
@@ -25574,18 +24745,32 @@ fn zirBuiltinExtern(
const ty_src = block.builtinCallArgSrc(extra.node, 0);
const options_src = block.builtinCallArgSrc(extra.node, 1);
- var ty = try sema.resolveType(block, ty_src, extra.lhs);
- if (!ty.isPtrAtRuntime(zcu)) {
+ const ptr_ty = try sema.resolveType(block, ty_src, extra.lhs);
+ if (!ptr_ty.isPtrAtRuntime(zcu)) {
return sema.fail(block, ty_src, "expected (optional) pointer", .{});
}
- if (!try sema.validateExternType(ty, .other)) {
- const msg = msg: {
- const msg = try sema.errMsg(ty_src, "extern symbol cannot have type '{f}'", .{ty.fmt(pt)});
+
+ const ptr_info = ptr_ty.ptrInfo(zcu);
+
+ const elem_ty: Type = .fromInterned(ptr_info.child);
+ try sema.ensureLayoutResolved(elem_ty, src, .@"extern");
+
+ if (!elem_ty.validateExtern(.other, zcu)) {
+ return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(ty_src, "extern symbol cannot have type '{f}'", .{ptr_ty.fmt(pt)});
errdefer msg.destroy(sema.gpa);
- try sema.explainWhyTypeIsNotExtern(msg, ty_src, ty, .other);
+ try sema.errNote(ty_src, msg, "pointer element type '{f}' is not extern compatible", .{elem_ty.fmt(pt)});
+ try sema.explainWhyTypeIsNotExtern(msg, ty_src, elem_ty, .other);
break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(block, msg);
+ });
+ }
+ if (elem_ty.zigTypeTag(zcu) == .@"fn" and !ptr_info.flags.is_const) {
+ return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(ty_src, "extern symbol cannot have type '{f}'", .{ptr_ty.fmt(pt)});
+ errdefer msg.destroy(sema.gpa);
+ try sema.errNote(ty_src, msg, "pointer to extern function must be 'const'", .{});
+ break :msg msg;
+ });
}
const options = try sema.resolveExternOptions(block, options_src, extra.rhs);
@@ -25603,14 +24788,9 @@ fn zirBuiltinExtern(
// TODO: error for threadlocal functions, non-const functions, etc
- if (options.linkage == .weak and !ty.ptrAllowsZero(zcu)) {
- ty = try pt.optionalType(ty.toIntern());
- }
- const ptr_info = ty.ptrInfo(zcu);
-
const extern_val = try pt.getExtern(.{
.name = options.name,
- .ty = ptr_info.child,
+ .ty = elem_ty.toIntern(),
.lib_name = options.library_name,
.linkage = options.linkage,
.visibility = options.visibility,
@@ -25626,7 +24806,7 @@ fn zirBuiltinExtern(
// So, for now, just use our containing `declaration`.
.zir_index = switch (sema.owner.unwrap()) {
.@"comptime" => |cu| ip.getComptimeUnit(cu).zir_index,
- .type => |owner_ty| Type.fromInterned(owner_ty).typeDeclInst(zcu).?,
+ .type_layout, .struct_defaults => |owner_ty| Type.fromInterned(owner_ty).typeDeclInstAllowGeneratedTag(zcu).?,
.memoized_state => unreachable,
.nav_ty, .nav_val => |nav| ip.getNav(nav).analysis.?.zir_index,
.func => |func| zir_index: {
@@ -25641,13 +24821,17 @@ fn zirBuiltinExtern(
.source = .builtin,
});
+ // For a weak symbol where the given type is not nullable, make the pointer optional.
+ const result_ptr_ty: Type = if (options.linkage == .weak and !ptr_ty.ptrAllowsZero(zcu)) ty: {
+ break :ty try pt.optionalType(ptr_ty.toIntern());
+ } else ptr_ty;
+
const uncasted_ptr = try sema.analyzeNavRef(block, src, ip.indexToKey(extern_val).@"extern".owner_nav);
- // We want to cast to `ty`, but that isn't necessarily an allowed coercion.
- if (try sema.resolveValue(uncasted_ptr)) |uncasted_ptr_val| {
- const casted_ptr_val = try pt.getCoerced(uncasted_ptr_val, ty);
+ if (sema.resolveValue(uncasted_ptr)) |uncasted_ptr_val| {
+ const casted_ptr_val = try pt.getCoerced(uncasted_ptr_val, result_ptr_ty);
return Air.internedToRef(casted_ptr_val.toIntern());
} else {
- return block.addBitCast(ty, uncasted_ptr);
+ return block.addBitCast(result_ptr_ty, uncasted_ptr);
}
}
@@ -25732,6 +24916,7 @@ fn zirBuiltinValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD
// Values are handled here.
.calling_convention_c => {
const callconv_ty = try sema.getBuiltinType(src, .CallingConvention);
+ // Cannot use `Value.uninterpret` because `c` is a *declaration* whose value depends on the target.
return try sema.namespaceLookupVal(
block,
src,
@@ -25740,17 +24925,15 @@ fn zirBuiltinValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD
) orelse @panic("std.builtin is corrupt");
},
.calling_convention_inline => {
- comptime assert(@typeInfo(std.builtin.CallingConvention.Tag).@"enum".tag_type == u8);
const callconv_ty = try sema.getBuiltinType(src, .CallingConvention);
- const callconv_tag_ty = callconv_ty.unionTagType(zcu) orelse @panic("std.builtin is corrupt");
- const inline_tag_val = try pt.enumValue(
- callconv_tag_ty,
- (try pt.intValue(
- .u8,
- @intFromEnum(std.builtin.CallingConvention.@"inline"),
- )).toIntern(),
- );
- return sema.coerce(block, callconv_ty, Air.internedToRef(inline_tag_val.toIntern()), src);
+ return .fromValue(Value.uninterpret(
+ @as(std.builtin.CallingConvention, .@"inline"),
+ callconv_ty,
+ pt,
+ ) catch |err| switch (err) {
+ error.TypeMismatch => @panic("std.builtin is corrupt"),
+ error.OutOfMemory => |e| return e,
+ });
},
};
return .fromType(try sema.getBuiltinType(src, builtin_type));
@@ -25760,7 +24943,7 @@ fn zirInplaceArithResultTy(sema: *Sema, extended: Zir.Inst.Extended.InstData) Co
const pt = sema.pt;
const zcu = pt.zcu;
- const lhs = try sema.resolveInst(@enumFromInt(extended.operand));
+ const lhs = sema.resolveInst(@enumFromInt(extended.operand));
const lhs_ty = sema.typeOf(lhs);
const op: Zir.Inst.InplaceOp = @enumFromInt(extended.small);
@@ -25785,7 +24968,7 @@ fn zirInplaceArithResultTy(sema: *Sema, extended: Zir.Inst.Extended.InstData) Co
fn zirBranchHint(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {
const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
- const uncoerced_hint = try sema.resolveInst(extra.operand);
+ const uncoerced_hint = sema.resolveInst(extra.operand);
const operand_src = block.builtinCallArgSrc(extra.node, 0);
const hint_ty = try sema.getBuiltinType(operand_src, .BranchHint);
@@ -25839,7 +25022,8 @@ fn requireRuntimeBlock(sema: *Sema, block: *Block, src: LazySrcLoc, runtime_src:
}
}
-/// Emit a compile error if type cannot be used for a runtime variable.
+/// Emit a compile error if `var_ty` cannot be used for a runtime variable.
+/// Asserts that the layout of `var_ty` is already resolved.
pub fn validateVarType(
sema: *Sema,
block: *Block,
@@ -25849,8 +25033,9 @@ pub fn validateVarType(
) CompileError!void {
const pt = sema.pt;
const zcu = pt.zcu;
+ var_ty.assertHasLayout(zcu);
if (is_extern) {
- if (!try sema.validateExternType(var_ty, .other)) {
+ if (!var_ty.validateExtern(.other, zcu)) {
const msg = msg: {
const msg = try sema.errMsg(src, "extern variable cannot have type '{f}'", .{var_ty.fmt(pt)});
errdefer msg.destroy(sema.gpa);
@@ -25870,7 +25055,7 @@ pub fn validateVarType(
}
}
- if (!try var_ty.comptimeOnlySema(pt)) return;
+ if (!var_ty.comptimeOnly(zcu)) return;
const msg = msg: {
const msg = try sema.errMsg(src, "variable of type '{f}' must be const or comptime", .{var_ty.fmt(pt)});
@@ -25886,49 +25071,28 @@ pub fn validateVarType(
return sema.failWithOwnedErrorMsg(block, msg);
}
-const TypeSet = std.AutoHashMapUnmanaged(InternPool.Index, void);
-
fn explainWhyTypeIsComptime(
sema: *Sema,
msg: *Zcu.ErrorMsg,
- src_loc: LazySrcLoc,
+ src: LazySrcLoc,
ty: Type,
-) CompileError!void {
- var type_set = TypeSet{};
- defer type_set.deinit(sema.gpa);
-
- try ty.resolveFully(sema.pt);
- return sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty, &type_set);
-}
-
-fn explainWhyTypeIsComptimeInner(
- sema: *Sema,
- msg: *Zcu.ErrorMsg,
- src_loc: LazySrcLoc,
- ty: Type,
- type_set: *TypeSet,
) CompileError!void {
const pt = sema.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
+ assert(ty.comptimeOnly(zcu));
switch (ty.zigTypeTag(zcu)) {
.bool,
.int,
.float,
.error_set,
- .@"enum",
.frame,
.@"anyframe",
.void,
- => return,
-
- .@"fn" => {
- try sema.errNote(src_loc, msg, "use '*const {f}' for a function pointer type", .{ty.fmt(pt)});
- },
-
- .type => {
- try sema.errNote(src_loc, msg, "types are not available at runtime", .{});
- },
+ .@"enum",
+ .@"opaque",
+ .pointer,
+ => unreachable, // not comptime-only
.comptime_float,
.comptime_int,
@@ -25936,177 +25100,68 @@ fn explainWhyTypeIsComptimeInner(
.noreturn,
.undefined,
.null,
- => return,
+ => return, // no explanation needed
- .@"opaque" => {
- try sema.errNote(src_loc, msg, "opaque type '{f}' has undefined size", .{ty.fmt(pt)});
- },
+ .array, .vector => try sema.explainWhyTypeIsComptime(msg, src, ty.childType(zcu)),
+ .optional => try sema.explainWhyTypeIsComptime(msg, src, ty.optionalChild(zcu)),
+ .error_union => try sema.explainWhyTypeIsComptime(msg, src, ty.errorUnionPayload(zcu)),
- .array, .vector => {
- try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.childType(zcu), type_set);
- },
- .pointer => {
- const elem_ty = ty.elemType2(zcu);
- if (elem_ty.zigTypeTag(zcu) == .@"fn") {
- const fn_info = zcu.typeToFunc(elem_ty).?;
- if (fn_info.is_generic) {
- try sema.errNote(src_loc, msg, "function is generic", .{});
- }
- switch (fn_info.cc) {
- .@"inline" => try sema.errNote(src_loc, msg, "function has inline calling convention", .{}),
- else => {},
- }
- if (Type.fromInterned(fn_info.return_type).comptimeOnly(zcu)) {
- try sema.errNote(src_loc, msg, "function has a comptime-only return type", .{});
- }
- return;
- }
- try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.childType(zcu), type_set);
- },
-
- .optional => {
- try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.optionalChild(zcu), type_set);
- },
- .error_union => {
- try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.errorUnionPayload(zcu), type_set);
- },
-
- .@"struct" => {
- if ((try type_set.getOrPut(sema.gpa, ty.toIntern())).found_existing) return;
+ .@"fn" => try sema.errNote(src, msg, "use '*const {f}' for a function pointer type", .{ty.fmt(pt)}),
+ .type => try sema.errNote(src, msg, "types are not available at runtime", .{}),
- if (zcu.typeToStruct(ty)) |struct_type| {
- for (0..struct_type.field_types.len) |i| {
- const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[i]);
- const field_src: LazySrcLoc = .{
- .base_node_inst = struct_type.zir_index,
- .offset = .{ .container_field_type = @intCast(i) },
- };
-
- if (try field_ty.comptimeOnlySema(pt)) {
- try sema.errNote(field_src, msg, "struct requires comptime because of this field", .{});
- try sema.explainWhyTypeIsComptimeInner(msg, field_src, field_ty, type_set);
- }
- }
+ .@"struct" => if (zcu.typeToStruct(ty)) |struct_type| {
+ ty.assertHasLayout(zcu);
+ for (0..struct_type.field_types.len) |i| {
+ const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[i]);
+ if (!field_ty.comptimeOnly(zcu)) continue;
+ const field_src: LazySrcLoc = .{
+ .base_node_inst = struct_type.zir_index,
+ .offset = .{ .container_field_type = @intCast(i) },
+ };
+ try sema.errNote(field_src, msg, "struct requires comptime because of this field", .{});
+ return sema.explainWhyTypeIsComptime(msg, field_src, field_ty);
+ }
+ unreachable;
+ } else {
+ const tuple = ip.indexToKey(ty.toIntern()).tuple_type;
+ for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty_ip, field_val_ip| {
+ if (field_val_ip != .none) continue;
+ const field_ty: Type = .fromInterned(field_ty_ip);
+ if (!field_ty.comptimeOnly(zcu)) continue;
+ try sema.errNote(src, msg, "tuple requires comptime because of field of type '{f}'", .{field_ty.fmt(pt)});
+ return sema.explainWhyTypeIsComptime(msg, src, field_ty);
}
- // TODO tuples
+ unreachable;
},
.@"union" => {
- if ((try type_set.getOrPut(sema.gpa, ty.toIntern())).found_existing) return;
-
- if (zcu.typeToUnion(ty)) |union_obj| {
- for (0..union_obj.field_types.len) |i| {
- const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[i]);
- const field_src: LazySrcLoc = .{
- .base_node_inst = union_obj.zir_index,
- .offset = .{ .container_field_type = @intCast(i) },
- };
-
- if (try field_ty.comptimeOnlySema(pt)) {
- try sema.errNote(field_src, msg, "union requires comptime because of this field", .{});
- try sema.explainWhyTypeIsComptimeInner(msg, field_src, field_ty, type_set);
- }
- }
- }
- },
- }
-}
-
-const ExternPosition = enum {
- ret_ty,
- param_ty,
- union_field,
- struct_field,
- element,
- other,
-};
-
-/// Returns true if `ty` is allowed in extern types.
-/// Does *NOT* require `ty` to be resolved in any way.
-/// Calls `resolveLayout` for packed containers.
-fn validateExternType(
- sema: *Sema,
- ty: Type,
- position: ExternPosition,
-) !bool {
- const pt = sema.pt;
- const zcu = pt.zcu;
- switch (ty.zigTypeTag(zcu)) {
- .type,
- .comptime_float,
- .comptime_int,
- .enum_literal,
- .undefined,
- .null,
- .error_union,
- .error_set,
- .frame,
- => return false,
- .void => return position == .union_field or position == .ret_ty or position == .struct_field or position == .element,
- .noreturn => return position == .ret_ty,
- .@"opaque",
- .bool,
- .float,
- .@"anyframe",
- => return true,
- .pointer => {
- if (ty.childType(zcu).zigTypeTag(zcu) == .@"fn") {
- return ty.isConstPtr(zcu) and try sema.validateExternType(ty.childType(zcu), .other);
- }
- return !(ty.isSlice(zcu) or try ty.comptimeOnlySema(pt));
- },
- .int => switch (ty.intInfo(zcu).bits) {
- 0, 8, 16, 32, 64, 128 => return true,
- else => return false,
- },
- .@"fn" => {
- if (position != .other) return false;
- // For now we want to authorize PTX kernel to use zig objects, even if we end up exposing the ABI.
- // The goal is to experiment with more integrated CPU/GPU code.
- if (ty.fnCallingConvention(zcu) == .nvptx_kernel) {
- return true;
+ const union_obj = zcu.typeToUnion(ty).?;
+ for (0..union_obj.field_types.len) |i| {
+ const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[i]);
+ if (!field_ty.comptimeOnly(zcu)) continue;
+ const field_src: LazySrcLoc = .{
+ .base_node_inst = union_obj.zir_index,
+ .offset = .{ .container_field_type = @intCast(i) },
+ };
+ try sema.errNote(field_src, msg, "union requires comptime because of this field", .{});
+ return sema.explainWhyTypeIsComptime(msg, field_src, field_ty);
}
- return !target_util.fnCallConvAllowsZigTypes(ty.fnCallingConvention(zcu));
- },
- .@"enum" => {
- return sema.validateExternType(ty.intTagType(zcu), position);
- },
- .@"struct", .@"union" => switch (ty.containerLayout(zcu)) {
- .@"extern" => return true,
- .@"packed" => {
- const bit_size = try ty.bitSizeSema(pt);
- switch (bit_size) {
- 0, 8, 16, 32, 64, 128 => return true,
- else => return false,
- }
- },
- .auto => return !(try ty.hasRuntimeBitsSema(pt)),
- },
- .array => {
- if (position == .ret_ty or position == .param_ty) return false;
- return sema.validateExternType(ty.elemType2(zcu), .element);
+ unreachable;
},
- .vector => return sema.validateExternType(ty.elemType2(zcu), .element),
- .optional => return ty.isPtrLikeOptional(zcu),
}
}
-fn explainWhyTypeIsNotExtern(
+/// Keep in sync with `Type.validateExtern`.
+pub fn explainWhyTypeIsNotExtern(
sema: *Sema,
msg: *Zcu.ErrorMsg,
src_loc: LazySrcLoc,
ty: Type,
- position: ExternPosition,
-) CompileError!void {
+ position: Type.ExternPosition,
+) SemaError!void {
const pt = sema.pt;
const zcu = pt.zcu;
switch (ty.zigTypeTag(zcu)) {
- .@"opaque",
- .bool,
- .float,
- .@"anyframe",
- => return,
-
.type,
.comptime_float,
.comptime_int,
@@ -26118,140 +25173,120 @@ fn explainWhyTypeIsNotExtern(
.frame,
=> return,
- .pointer => {
- if (ty.isSlice(zcu)) {
- try sema.errNote(src_loc, msg, "slices have no guaranteed in-memory representation", .{});
- } else {
- const pointee_ty = ty.childType(zcu);
- if (!ty.isConstPtr(zcu) and pointee_ty.zigTypeTag(zcu) == .@"fn") {
- try sema.errNote(src_loc, msg, "pointer to extern function must be 'const'", .{});
- } else if (try ty.comptimeOnlySema(pt)) {
- try sema.errNote(src_loc, msg, "pointer to comptime-only type '{f}'", .{pointee_ty.fmt(pt)});
- try sema.explainWhyTypeIsComptime(msg, src_loc, ty);
- }
- try sema.explainWhyTypeIsNotExtern(msg, src_loc, pointee_ty, .other);
- }
- },
- .void => try sema.errNote(src_loc, msg, "'void' is a zero bit type; for C 'void' use 'anyopaque'", .{}),
+ .void => try sema.errNote(src_loc, msg, "'void' is a zero bit type", .{}),
.noreturn => try sema.errNote(src_loc, msg, "'noreturn' is only allowed as a return type", .{}),
+
+ .@"opaque",
+ .bool,
+ .float,
+ .@"anyframe",
+ => unreachable, // these *are* allowed
+
+ .pointer => if (ty.isSlice(zcu)) {
+ try sema.errNote(src_loc, msg, "slices have no guaranteed in-memory representation", .{});
+ } else {
+ assert(ty.childType(zcu).zigTypeTag(zcu) == .@"fn");
+ if (!ty.isConstPtr(zcu)) {
+ try sema.errNote(src_loc, msg, "pointer to extern function must be 'const'", .{});
+ } else {
+ try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.childType(zcu), .other);
+ }
+ },
.int => if (!std.math.isPowerOfTwo(ty.intInfo(zcu).bits)) {
try sema.errNote(src_loc, msg, "only integers with 0 or power of two bits are extern compatible", .{});
} else {
try sema.errNote(src_loc, msg, "only integers with 0, 8, 16, 32, 64 and 128 bits are extern compatible", .{});
},
- .@"fn" => {
- if (position != .other) {
- try sema.errNote(src_loc, msg, "type has no guaranteed in-memory representation", .{});
- try sema.errNote(src_loc, msg, "use '*const ' to make a function pointer type", .{});
- return;
- }
- switch (ty.fnCallingConvention(zcu)) {
- .auto => try sema.errNote(src_loc, msg, "extern function must specify calling convention", .{}),
- .async => try sema.errNote(src_loc, msg, "async function cannot be extern", .{}),
- .@"inline" => try sema.errNote(src_loc, msg, "inline function cannot be extern", .{}),
- else => return,
- }
- },
- .@"enum" => {
- const tag_ty = ty.intTagType(zcu);
- try sema.errNote(src_loc, msg, "enum tag type '{f}' is not extern compatible", .{tag_ty.fmt(pt)});
- try sema.explainWhyTypeIsNotExtern(msg, src_loc, tag_ty, position);
- },
- .@"struct" => try sema.errNote(src_loc, msg, "only extern structs and ABI sized packed structs are extern compatible", .{}),
- .@"union" => try sema.errNote(src_loc, msg, "only extern unions and ABI sized packed unions are extern compatible", .{}),
- .array => {
- if (position == .ret_ty) {
- return sema.errNote(src_loc, msg, "arrays are not allowed as a return type", .{});
- } else if (position == .param_ty) {
- return sema.errNote(src_loc, msg, "arrays are not allowed as a parameter type", .{});
- }
- try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.elemType2(zcu), .element);
- },
- .vector => try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.elemType2(zcu), .element),
- .optional => try sema.errNote(src_loc, msg, "only pointer like optionals are extern compatible", .{}),
- }
-}
-
-/// Returns true if `ty` is allowed in packed types.
-/// Does not require `ty` to be resolved in any way, but may resolve whether it is comptime-only.
-fn validatePackedType(sema: *Sema, ty: Type) !bool {
- const pt = sema.pt;
- const zcu = pt.zcu;
- return switch (ty.zigTypeTag(zcu)) {
- .type,
- .comptime_float,
- .comptime_int,
- .enum_literal,
- .undefined,
- .null,
- .error_union,
- .error_set,
- .frame,
- .noreturn,
- .@"opaque",
- .@"anyframe",
- .@"fn",
- .array,
- => false,
- .optional => return ty.isPtrLikeOptional(zcu),
- .void,
- .bool,
- .float,
- .int,
- .vector,
- => true,
- .@"enum" => switch (zcu.intern_pool.loadEnumType(ty.toIntern()).tag_mode) {
- .auto => false,
- .explicit, .nonexhaustive => true,
- },
- .pointer => !ty.isSlice(zcu) and !try ty.comptimeOnlySema(pt),
- .@"struct", .@"union" => ty.containerLayout(zcu) == .@"packed",
- };
-}
-
-fn explainWhyTypeIsNotPacked(
- sema: *Sema,
- msg: *Zcu.ErrorMsg,
- src_loc: LazySrcLoc,
- ty: Type,
-) CompileError!void {
- const pt = sema.pt;
- const zcu = pt.zcu;
- switch (ty.zigTypeTag(zcu)) {
- .void,
- .bool,
- .float,
- .int,
- .vector,
- .@"enum",
- => return,
- .type,
- .comptime_float,
- .comptime_int,
- .enum_literal,
- .undefined,
- .null,
- .frame,
- .noreturn,
- .@"opaque",
- .error_union,
- .error_set,
- .@"anyframe",
- .optional,
- .array,
- => try sema.errNote(src_loc, msg, "type has no guaranteed in-memory representation", .{}),
- .pointer => if (ty.isSlice(zcu)) {
- try sema.errNote(src_loc, msg, "slices have no guaranteed in-memory representation", .{});
- } else {
- try sema.errNote(src_loc, msg, "comptime-only pointer has no guaranteed in-memory representation", .{});
- try sema.explainWhyTypeIsComptime(msg, src_loc, ty);
- },
- .@"fn" => {
+ .@"fn" => if (position != .other) {
try sema.errNote(src_loc, msg, "type has no guaranteed in-memory representation", .{});
try sema.errNote(src_loc, msg, "use '*const ' to make a function pointer type", .{});
+ } else switch (ty.fnCallingConvention(zcu)) {
+ .auto => try sema.errNote(src_loc, msg, "extern function must specify calling convention", .{}),
+ else => |cc| try sema.errNote(src_loc, msg, "{t} function cannot be extern", .{cc}),
},
- .@"struct" => try sema.errNote(src_loc, msg, "only packed structs layout are allowed in packed types", .{}),
- .@"union" => try sema.errNote(src_loc, msg, "only packed unions layout are allowed in packed types", .{}),
+ .@"enum" => {
+ const enum_obj = zcu.intern_pool.loadEnumType(ty.toIntern());
+ switch (enum_obj.int_tag_mode) {
+ .auto => {
+ try sema.errNote(ty.srcLoc(zcu), msg, "integer tag type of enum is inferred", .{});
+ try sema.errNote(ty.srcLoc(zcu), msg, "consider explicitly specifying the integer tag type", .{});
+ },
+ .explicit => {
+ const tag_ty: Type = .fromInterned(enum_obj.int_tag_type);
+ try sema.errNote(ty.srcLoc(zcu), msg, "enum tag type '{f}' is not extern compatible", .{tag_ty.fmt(pt)});
+ try sema.explainWhyTypeIsNotExtern(msg, ty.srcLoc(zcu), tag_ty, position);
+ },
+ }
+ },
+ .@"struct" => {
+ const struct_obj = zcu.intern_pool.loadStructType(ty.toIntern());
+ switch (struct_obj.layout) {
+ .auto => try sema.errNote(src_loc, msg, "struct with automatic layout has no guaranteed in-memory representation", .{}),
+ .@"extern" => unreachable,
+ .@"packed" => switch (struct_obj.packed_backing_mode) {
+ .auto => try sema.errNote(src_loc, msg, "inferred backing integer of packed struct has unspecified signedness", .{}),
+ .explicit => {
+ const backing_int_ty: Type = .fromInterned(struct_obj.packed_backing_int_type);
+ try sema.errNote(src_loc, msg, "packed struct backing integer type '{f}' is not extern compatible", .{backing_int_ty.fmt(pt)});
+ try sema.explainWhyTypeIsNotExtern(msg, src_loc, backing_int_ty, position);
+ },
+ },
+ }
+ },
+ .@"union" => {
+ const union_obj = zcu.intern_pool.loadUnionType(ty.toIntern());
+ switch (union_obj.layout) {
+ .auto => try sema.errNote(src_loc, msg, "union with automatic layout has no guaranteed in-memory representation", .{}),
+ .@"extern" => unreachable,
+ .@"packed" => switch (union_obj.packed_backing_mode) {
+ .auto => try sema.errNote(src_loc, msg, "inferred backing integer of packed union has unspecified signedness", .{}),
+ .explicit => {
+ const backing_int_ty: Type = .fromInterned(union_obj.packed_backing_int_type);
+ try sema.errNote(src_loc, msg, "packed union backing integer type '{f}' is not extern compatible", .{backing_int_ty.fmt(pt)});
+ try sema.explainWhyTypeIsNotExtern(msg, src_loc, backing_int_ty, position);
+ },
+ },
+ }
+ },
+ .array => switch (position) {
+ .ret_ty => try sema.errNote(src_loc, msg, "arrays are not allowed as a return type", .{}),
+ .param_ty => try sema.errNote(src_loc, msg, "arrays are not allowed as a parameter type", .{}),
+ else => try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.childType(zcu), .element),
+ },
+ .vector => try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.childType(zcu), .element),
+ .optional => try sema.errNote(src_loc, msg, "non-pointer optionals have no guaranteed in-memory representation", .{}),
+ }
+}
+
+pub fn explainWhyTypeIsUnpackable(
+ sema: *Sema,
+ msg: *Zcu.ErrorMsg,
+ src: LazySrcLoc,
+ reason: Type.UnpackableReason,
+) CompileError!void {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
+ switch (reason) {
+ .comptime_only => try sema.errNote(src, msg, "comptime-only types have no bit-packed representation", .{}),
+ .pointer => {
+ try sema.errNote(src, msg, "pointers cannot be directly bitpacked", .{});
+ try sema.errNote(src, msg, "consider using 'usize' and '@intFromPtr'", .{});
+ },
+ .enum_inferred_int_tag => |enum_ty| {
+ const enum_src = enum_ty.srcLoc(zcu);
+ try sema.errNote(enum_src, msg, "integer tag type of enum is inferred", .{});
+ try sema.errNote(enum_src, msg, "consider explicitly specifying the integer tag type", .{});
+ },
+ .non_packed_struct => |struct_ty| {
+ try sema.errNote(src, msg, "non-packed structs do not have a bit-packed representation", .{});
+ try sema.addDeclaredHereNote(msg, struct_ty);
+ },
+ .non_packed_union => |union_ty| {
+ try sema.errNote(src, msg, "non-packed unions do not have a bit-packed representation", .{});
+ try sema.addDeclaredHereNote(msg, union_ty);
+ },
+ .slice => try sema.errNote(src, msg, "slices do not have a bit-packed representation", .{}),
+ .other => try sema.errNote(src, msg, "type does not have a bit-packed representation", .{}),
}
}
@@ -26277,7 +25312,14 @@ fn getPanicIdFunc(sema: *Sema, src: LazySrcLoc, panic_id: Zcu.SimplePanicId) !In
try sema.ensureMemoizedStateResolved(src, .panic);
const panic_fn_index = zcu.builtin_decl_values.get(panic_id.toBuiltin());
switch (sema.owner.unwrap()) {
- .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {},
+ .@"comptime",
+ .nav_ty,
+ .nav_val,
+ .type_layout,
+ .struct_defaults,
+ .memoized_state,
+ => {},
+
.func => |owner_func| zcu.intern_pool.funcSetHasErrorTrace(io, owner_func, true),
}
return panic_fn_index;
@@ -26297,7 +25339,7 @@ fn addSafetyCheck(
.parent = parent_block,
.sema = sema,
.namespace = parent_block.namespace,
- .instructions = .{},
+ .instructions = .empty,
.inlining = parent_block.inlining,
.comptime_reason = null,
.src_base_inst = parent_block.src_base_inst,
@@ -26391,7 +25433,7 @@ fn addSafetyCheckUnwrapError(
.parent = parent_block,
.sema = sema,
.namespace = parent_block.namespace,
- .instructions = .{},
+ .instructions = .empty,
.inlining = parent_block.inlining,
.comptime_reason = null,
.src_base_inst = parent_block.src_base_inst,
@@ -26458,21 +25500,39 @@ fn addSafetyCheckSentinelMismatch(
const expected_sentinel = Air.internedToRef(expected_sentinel_val.toIntern());
const ptr_ty = sema.typeOf(ptr);
- const actual_sentinel = if (ptr_ty.isSlice(zcu))
- try parent_block.addBinOp(.slice_elem_val, ptr, sentinel_index)
- else blk: {
- const elem_ptr_ty = try ptr_ty.elemPtrType(null, pt);
- const sentinel_ptr = try parent_block.addPtrElemPtr(ptr, sentinel_index, elem_ptr_ty);
- break :blk try parent_block.addTyOp(.load, sentinel_ty, sentinel_ptr);
- };
-
- const ok = if (sentinel_ty.zigTypeTag(zcu) == .vector) ok: {
- const eql = try parent_block.addCmpVector(expected_sentinel, actual_sentinel, .eq);
- break :ok try parent_block.addReduce(eql, .And);
- } else ok: {
- assert(sentinel_ty.isSelfComparable(zcu, true));
- break :ok try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel);
+ const ptr_info = ptr_ty.ptrInfo(zcu);
+ const actual_sentinel: Air.Inst.Ref = switch (ptr_ty.ptrSize(zcu)) {
+ .slice => try parent_block.addBinOp(.slice_elem_val, ptr, sentinel_index),
+ .one => s: {
+ const array_ty: Type = .fromInterned(ptr_info.child);
+ assert(array_ty.zigTypeTag(zcu) == .array);
+ assert(array_ty.childType(zcu).toIntern() == sentinel_ty.toIntern());
+ const many_ptr_ty = try pt.ptrType(.{
+ .child = sentinel_ty.toIntern(),
+ .flags = .{
+ .size = .many,
+ .is_const = ptr_info.flags.is_const,
+ .is_volatile = ptr_info.flags.is_volatile,
+ .is_allowzero = ptr_info.flags.is_allowzero,
+ .alignment = switch (ptr_info.flags.alignment) {
+ .none => .none,
+ else => |ptr_align| .minStrict(ptr_align, sentinel_ty.abiAlignment(zcu)),
+ },
+ .address_space = ptr_info.flags.address_space,
+ },
+ });
+ const many_ptr = try parent_block.addBitCast(many_ptr_ty, ptr);
+ break :s try parent_block.addBinOp(.ptr_elem_val, many_ptr, sentinel_index);
+ },
+ .many => unreachable,
+ .c => unreachable,
};
+ assert(sema.typeOf(actual_sentinel).toIntern() == sentinel_ty.toIntern());
+ assert(sentinel_ty.isSelfComparable(zcu, true));
+ const ok: Air.Inst.Ref = if (sentinel_ty.zigTypeTag(zcu) == .vector) ok: {
+ const elementwise = try parent_block.addCmpVector(expected_sentinel, actual_sentinel, .eq);
+ break :ok try parent_block.addReduce(elementwise, .And);
+ } else try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel);
return addSafetyCheckCall(sema, parent_block, src, ok, .@"panic.sentinelMismatch", &.{
expected_sentinel, actual_sentinel,
@@ -26496,7 +25556,7 @@ fn addSafetyCheckCall(
.parent = parent_block,
.sema = sema,
.namespace = parent_block.namespace,
- .instructions = .{},
+ .instructions = .empty,
.inlining = parent_block.inlining,
.comptime_reason = null,
.src_base_inst = parent_block.src_base_inst,
@@ -26554,8 +25614,10 @@ fn fieldPtrLoad(
const pt = sema.pt;
const zcu = pt.zcu;
const object_ptr_ty = sema.typeOf(object_ptr);
+ assert(object_ptr_ty.zigTypeTag(zcu) == .pointer);
const pointee_ty = object_ptr_ty.childType(zcu);
- if (try typeHasOnePossibleValue(sema, pointee_ty)) |opv| {
+ try sema.ensureLayoutResolved(pointee_ty, src, .ptr_access);
+ if (try pointee_ty.onePossibleValue(pt)) |opv| {
const object: Air.Inst.Ref = .fromValue(opv);
return fieldVal(sema, block, src, object, field_name, field_name_src);
}
@@ -26603,7 +25665,7 @@ fn fieldVal(
return Air.internedToRef((try pt.intValue(.usize, inner_ty.arrayLen(zcu))).toIntern());
} else if (field_name.eqlSlice("ptr", ip) and is_pointer_to) {
const ptr_info = object_ty.ptrInfo(zcu);
- const result_ty = try pt.ptrTypeSema(.{
+ const result_ty = try pt.ptrType(.{
.child = Type.fromInterned(ptr_info.child).childType(zcu).toIntern(),
.sentinel = if (inner_ty.sentinel(zcu)) |s| s.toIntern() else .none,
.flags = .{
@@ -26663,37 +25725,34 @@ fn fieldVal(
switch (child_type.zigTypeTag(zcu)) {
.error_set => {
- switch (ip.indexToKey(child_type.toIntern())) {
- .error_set_type => |error_set_type| blk: {
- if (error_set_type.nameIndex(ip, field_name) != null) break :blk;
+ const err_set_ty: Type = err_set: switch (ip.indexToKey(child_type.toIntern())) {
+ .inferred_error_set_type => |func_index| {
+ try sema.ensureFuncIesResolved(block, src, func_index);
+ const resolved_ies = ip.funcIesResolvedUnordered(func_index);
+ continue :err_set ip.indexToKey(resolved_ies);
+ },
+ .error_set_type => |err_set| if (err_set.nameIndex(ip, field_name) == null) {
return sema.fail(block, src, "no error named '{f}' in '{f}'", .{
field_name.fmt(ip), child_type.fmt(pt),
});
- },
- .inferred_error_set_type => {
- return sema.fail(block, src, "TODO handle inferred error sets here", .{});
- },
+ } else child_type,
.simple_type => |t| {
assert(t == .anyerror);
_ = try pt.getErrorValue(field_name);
+ break :err_set try pt.singleErrorSetType(field_name);
},
else => unreachable,
- }
-
- const error_set_type = if (!child_type.isAnyError(zcu))
- child_type
- else
- try pt.singleErrorSetType(field_name);
- return Air.internedToRef((try pt.intern(.{ .err = .{
- .ty = error_set_type.toIntern(),
+ };
+ return .fromIntern(try pt.intern(.{ .err = .{
+ .ty = err_set_ty.toIntern(),
.name = field_name,
- } })));
+ } }));
},
.@"union" => {
if (try sema.namespaceLookupVal(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {
return inst;
}
- try child_type.resolveFields(pt);
+ try sema.ensureLayoutResolved(child_type, src, .field_used);
if (child_type.unionTagType(zcu)) |enum_ty| {
if (enum_ty.enumFieldIndex(field_name, zcu)) |field_index_usize| {
const field_index: u32 = @intCast(field_index_usize);
@@ -26706,6 +25765,7 @@ fn fieldVal(
if (try sema.namespaceLookupVal(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {
return inst;
}
+ try sema.ensureLayoutResolved(child_type, src, .field_used);
const field_index_usize = child_type.enumFieldIndex(field_name, zcu) orelse
return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
const field_index: u32 = @intCast(field_index_usize);
@@ -26731,13 +25791,15 @@ fn fieldVal(
},
.@"struct" => if (is_pointer_to) {
// Avoid loading the entire struct by fetching a pointer and loading that
- const field_ptr = try sema.structFieldPtr(block, src, object, field_name, field_name_src, inner_ty, false);
+ try sema.ensureLayoutResolved(inner_ty, src, .ptr_access);
+ const field_ptr = try sema.structFieldPtr(block, src, object, field_name, field_name_src, inner_ty);
return sema.analyzeLoad(block, src, field_ptr, object_src);
} else {
return sema.structFieldVal(block, object, field_name, field_name_src, inner_ty);
},
.@"union" => if (is_pointer_to) {
// Avoid loading the entire union by fetching a pointer and loading that
+ try sema.ensureLayoutResolved(inner_ty, src, .ptr_access);
const field_ptr = try sema.unionFieldPtr(block, src, object, field_name, field_name_src, inner_ty, false);
return sema.analyzeLoad(block, src, field_ptr, object_src);
} else {
@@ -26784,10 +25846,10 @@ fn fieldPtr(
.array => {
if (field_name.eqlSlice("len", ip)) {
const int_val = try pt.intValue(.usize, inner_ty.arrayLen(zcu));
- return uavRef(sema, int_val.toIntern());
+ return uavRef(sema, int_val);
} else if (field_name.eqlSlice("ptr", ip) and is_pointer_to) {
const ptr_info = object_ty.ptrInfo(zcu);
- const new_ptr_ty = try pt.ptrTypeSema(.{
+ const new_ptr_ty = try pt.ptrType(.{
.child = Type.fromInterned(ptr_info.child).childType(zcu).toIntern(),
.sentinel = if (inner_ty.sentinel(zcu)) |s| s.toIntern() else .none,
.flags = .{
@@ -26802,10 +25864,11 @@ fn fieldPtr(
.packed_offset = ptr_info.packed_offset,
});
const ptr_ptr_info = object_ptr_ty.ptrInfo(zcu);
- const result_ty = try pt.ptrTypeSema(.{
+ const result_ty = try pt.ptrType(.{
.child = new_ptr_ty.toIntern(),
.sentinel = if (object_ptr_ty.sentinel(zcu)) |s| s.toIntern() else .none,
.flags = .{
+ .size = .one,
.alignment = ptr_ptr_info.flags.alignment,
.is_const = ptr_ptr_info.flags.is_const,
.is_volatile = ptr_ptr_info.flags.is_volatile,
@@ -26836,7 +25899,7 @@ fn fieldPtr(
if (field_name.eqlSlice("ptr", ip)) {
const slice_ptr_ty = inner_ty.slicePtrFieldType(zcu);
- const result_ty = try pt.ptrTypeSema(.{
+ const result_ty = try pt.ptrType(.{
.child = slice_ptr_ty.toIntern(),
.flags = .{
.is_const = !attr_ptr_ty.ptrIsMutable(zcu),
@@ -26854,7 +25917,7 @@ fn fieldPtr(
try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr);
return field_ptr;
} else if (field_name.eqlSlice("len", ip)) {
- const result_ty = try pt.ptrTypeSema(.{
+ const result_ty = try pt.ptrType(.{
.child = .usize_type,
.flags = .{
.is_const = !attr_ptr_ty.ptrIsMutable(zcu),
@@ -26881,7 +25944,6 @@ fn fieldPtr(
}
},
.type => {
- _ = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, object_ptr, undefined);
const result = try sema.analyzeLoad(block, src, object_ptr, object_ptr_src);
const inner = if (is_pointer_to)
try sema.analyzeLoad(block, src, result, object_ptr_src)
@@ -26893,44 +25955,39 @@ fn fieldPtr(
switch (child_type.zigTypeTag(zcu)) {
.error_set => {
- switch (ip.indexToKey(child_type.toIntern())) {
- .error_set_type => |error_set_type| blk: {
- if (error_set_type.nameIndex(ip, field_name) != null) {
- break :blk;
- }
+ const err_set_ty: Type = err_set: switch (ip.indexToKey(child_type.toIntern())) {
+ .inferred_error_set_type => |func_index| {
+ try sema.ensureFuncIesResolved(block, src, func_index);
+ const resolved_ies = ip.funcIesResolvedUnordered(func_index);
+ continue :err_set ip.indexToKey(resolved_ies);
+ },
+ .error_set_type => |err_set| if (err_set.nameIndex(ip, field_name) == null) {
return sema.fail(block, src, "no error named '{f}' in '{f}'", .{
field_name.fmt(ip), child_type.fmt(pt),
});
- },
- .inferred_error_set_type => {
- return sema.fail(block, src, "TODO handle inferred error sets here", .{});
- },
+ } else child_type,
.simple_type => |t| {
assert(t == .anyerror);
_ = try pt.getErrorValue(field_name);
+ break :err_set try pt.singleErrorSetType(field_name);
},
else => unreachable,
- }
-
- const error_set_type = if (!child_type.isAnyError(zcu))
- child_type
- else
- try pt.singleErrorSetType(field_name);
- return uavRef(sema, try pt.intern(.{ .err = .{
- .ty = error_set_type.toIntern(),
+ };
+ return uavRef(sema, .fromInterned(try pt.intern(.{ .err = .{
+ .ty = err_set_ty.toIntern(),
.name = field_name,
- } }));
+ } })));
},
.@"union" => {
if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {
return inst;
}
- try child_type.resolveFields(pt);
+ try sema.ensureLayoutResolved(child_type, src, .field_used);
if (child_type.unionTagType(zcu)) |enum_ty| {
if (enum_ty.enumFieldIndex(field_name, zcu)) |field_index| {
const field_index_u32: u32 = @intCast(field_index);
const idx_val = try pt.enumValueFieldIndex(enum_ty, field_index_u32);
- return uavRef(sema, idx_val.toIntern());
+ return uavRef(sema, idx_val);
}
}
return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
@@ -26939,12 +25996,13 @@ fn fieldPtr(
if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {
return inst;
}
+ try sema.ensureLayoutResolved(child_type, src, .field_used);
const field_index = child_type.enumFieldIndex(field_name, zcu) orelse {
return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
};
const field_index_u32: u32 = @intCast(field_index);
const idx_val = try pt.enumValueFieldIndex(child_type, field_index_u32);
- return uavRef(sema, idx_val.toIntern());
+ return uavRef(sema, idx_val);
},
.@"struct", .@"opaque" => {
if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {
@@ -26960,7 +26018,8 @@ fn fieldPtr(
try sema.analyzeLoad(block, src, object_ptr, object_ptr_src)
else
object_ptr;
- const field_ptr = try sema.structFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty, initializing);
+ try sema.ensureLayoutResolved(inner_ty, src, .ptr_access);
+ const field_ptr = try sema.structFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty);
try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr);
return field_ptr;
},
@@ -26969,6 +26028,7 @@ fn fieldPtr(
try sema.analyzeLoad(block, src, object_ptr, object_ptr_src)
else
object_ptr;
+ try sema.ensureLayoutResolved(inner_ty, src, .ptr_access);
const field_ptr = try sema.unionFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty, initializing);
try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr);
return field_ptr;
@@ -27012,6 +26072,7 @@ fn fieldCallBind(
// Optionally dereference a second pointer to get the concrete type.
const is_double_ptr = inner_ty.zigTypeTag(zcu) == .pointer and inner_ty.ptrSize(zcu) == .one;
const concrete_ty = if (is_double_ptr) inner_ty.childType(zcu) else inner_ty;
+ try sema.ensureLayoutResolved(concrete_ty, src, .ptr_access);
const ptr_ty = if (is_double_ptr) inner_ty else raw_ptr_ty;
const object_ptr = if (is_double_ptr)
try sema.analyzeLoad(block, src, raw_ptr, src)
@@ -27021,10 +26082,8 @@ fn fieldCallBind(
find_field: {
switch (concrete_ty.zigTypeTag(zcu)) {
.@"struct" => {
- try concrete_ty.resolveFields(pt);
if (zcu.typeToStruct(concrete_ty)) |struct_type| {
- const field_index = struct_type.nameIndex(ip, field_name) orelse
- break :find_field;
+ const field_index = struct_type.nameIndex(ip, field_name) orelse break :find_field;
const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);
return sema.finishFieldCallBind(block, src, ptr_ty, field_ty, field_index, object_ptr);
@@ -27047,9 +26106,9 @@ fn fieldCallBind(
}
},
.@"union" => {
- try concrete_ty.resolveFields(pt);
const union_obj = zcu.typeToUnion(concrete_ty).?;
- _ = union_obj.loadTagType(ip).nameIndex(ip, field_name) orelse break :find_field;
+ const enum_obj = ip.loadEnumType(union_obj.enum_tag_type);
+ if (enum_obj.nameIndex(ip, field_name) == null) break :find_field;
const field_ptr = try unionFieldPtr(sema, block, src, object_ptr, field_name, field_name_src, concrete_ty, false);
return .{ .direct = try sema.analyzeLoad(block, src, field_ptr, src) };
},
@@ -27163,7 +26222,7 @@ fn finishFieldCallBind(
) CompileError!ResolvedFieldCallee {
const pt = sema.pt;
const zcu = pt.zcu;
- const ptr_field_ty = try pt.ptrTypeSema(.{
+ const ptr_field_ty = try pt.ptrType(.{
.child = field_ty.toIntern(),
.flags = .{
.is_const = !ptr_ty.ptrIsMutable(zcu),
@@ -27174,7 +26233,6 @@ fn finishFieldCallBind(
const container_ty = ptr_ty.childType(zcu);
if (container_ty.zigTypeTag(zcu) == .@"struct") {
if (container_ty.structFieldIsComptime(field_index, zcu)) {
- try container_ty.resolveStructFieldInits(pt);
const default_val = (try container_ty.structFieldValueComptime(pt, field_index)).?;
return .{ .direct = Air.internedToRef(default_val.toIntern()) };
}
@@ -27239,6 +26297,7 @@ fn namespaceLookupVal(
return try sema.analyzeNavVal(block, src, nav);
}
+/// Asserts that the layout of `struct_ty` is already resolved.
fn structFieldPtr(
sema: *Sema,
block: *Block,
@@ -27247,33 +26306,33 @@ fn structFieldPtr(
field_name: InternPool.NullTerminatedString,
field_name_src: LazySrcLoc,
struct_ty: Type,
- initializing: bool,
) CompileError!Air.Inst.Ref {
const pt = sema.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
+
assert(struct_ty.zigTypeTag(zcu) == .@"struct");
+ struct_ty.assertHasLayout(zcu);
- try struct_ty.resolveFields(pt);
- try struct_ty.resolveLayout(pt);
-
- if (struct_ty.isTuple(zcu)) {
+ const field_index: u32 = if (struct_ty.isTuple(zcu)) field_index: {
if (field_name.eqlSlice("len", ip)) {
const len_inst = try pt.intRef(.usize, struct_ty.structFieldCount(zcu));
- return sema.analyzeRef(block, src, len_inst);
+ return sema.analyzeRef(block, src, len_inst, .none);
}
- const field_index = try sema.tupleFieldIndex(block, struct_ty, field_name, field_name_src);
- return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index, initializing);
- }
-
- const struct_type = zcu.typeToStruct(struct_ty).?;
-
- const field_index = struct_type.nameIndex(ip, field_name) orelse
- return sema.failWithBadStructFieldAccess(block, struct_ty, struct_type, field_name_src, field_name);
+ break :field_index try sema.tupleFieldIndex(block, struct_ty, field_name, field_name_src);
+ } else field_index: {
+ const struct_type = zcu.typeToStruct(struct_ty).?;
+ break :field_index struct_type.nameIndex(ip, field_name) orelse {
+ return sema.failWithBadStructFieldAccess(block, struct_ty, struct_type, field_name_src, field_name);
+ };
+ };
return sema.structFieldPtrByIndex(block, src, struct_ptr, field_index, struct_ty);
}
+/// Supports both structs and unions.
+///
+/// Asserts that the layout of `struct_ty` is already resolved.
fn structFieldPtrByIndex(
sema: *Sema,
block: *Block,
@@ -27284,78 +26343,23 @@ fn structFieldPtrByIndex(
) CompileError!Air.Inst.Ref {
const pt = sema.pt;
const zcu = pt.zcu;
- const ip = &zcu.intern_pool;
- const struct_type = zcu.typeToStruct(struct_ty).?;
- const field_is_comptime = struct_type.fieldIsComptime(ip, field_index);
-
- // Comptime fields are handled later
- if (!field_is_comptime) {
- if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| {
- const val = try struct_ptr_val.ptrField(field_index, pt);
- return Air.internedToRef(val.toIntern());
- }
- }
-
- const field_ty = struct_type.field_types.get(ip)[field_index];
+ struct_ty.assertHasLayout(zcu);
const struct_ptr_ty = sema.typeOf(struct_ptr);
- const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(zcu);
- var ptr_ty_data: InternPool.Key.PtrType = .{
- .child = field_ty,
- .flags = .{
- .is_const = struct_ptr_ty_info.flags.is_const,
- .is_volatile = struct_ptr_ty_info.flags.is_volatile,
- .address_space = struct_ptr_ty_info.flags.address_space,
- },
- };
-
- const parent_align = if (struct_ptr_ty_info.flags.alignment != .none)
- struct_ptr_ty_info.flags.alignment
- else
- try Type.fromInterned(struct_ptr_ty_info.child).abiAlignmentSema(pt);
-
- if (struct_type.layout == .@"packed") {
- assert(!field_is_comptime);
- const packed_offset = struct_ty.packedStructFieldPtrInfo(struct_ptr_ty, field_index, pt);
- ptr_ty_data.flags.alignment = parent_align;
- ptr_ty_data.packed_offset = packed_offset;
- } else if (struct_type.layout == .@"extern") {
- assert(!field_is_comptime);
- // For extern structs, field alignment might be bigger than type's
- // natural alignment. Eg, in `extern struct { x: u32, y: u16 }` the
- // second field is aligned as u32.
- const field_offset = struct_ty.structFieldOffset(field_index, zcu);
- ptr_ty_data.flags.alignment = if (parent_align == .none)
- .none
- else
- @enumFromInt(@min(@intFromEnum(parent_align), @ctz(field_offset)));
- } else {
- // Our alignment is capped at the field alignment.
- const field_align = try Type.fromInterned(field_ty).structFieldAlignmentSema(
- struct_type.fieldAlign(ip, field_index),
- struct_type.layout,
- pt,
- );
- ptr_ty_data.flags.alignment = if (struct_ptr_ty_info.flags.alignment == .none)
- field_align
- else
- field_align.min(parent_align);
- }
-
- const ptr_field_ty = try pt.ptrTypeSema(ptr_ty_data);
-
- if (field_is_comptime) {
- try struct_ty.resolveStructFieldInits(pt);
- const val = try pt.intern(.{ .ptr = .{
- .ty = ptr_field_ty.toIntern(),
- .base_addr = .{ .comptime_field = struct_type.field_inits.get(ip)[field_index] },
+ if (struct_ty.structFieldIsComptime(field_index, zcu)) {
+ const field_ptr_ty = try struct_ptr_ty.fieldPtrType(field_index, pt);
+ return .fromIntern(try pt.intern(.{ .ptr = .{
+ .ty = field_ptr_ty.toIntern(),
+ .base_addr = .{ .comptime_field = struct_ty.structFieldDefaultValue(field_index, zcu).?.toIntern() },
.byte_offset = 0,
- } });
- return Air.internedToRef(val);
+ } }));
+ } else if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| {
+ return .fromValue(try struct_ptr_val.ptrField(field_index, pt));
+ } else {
+ const field_ptr_ty = try struct_ptr_ty.fieldPtrType(field_index, pt);
+ return block.addStructFieldPtr(struct_ptr, field_index, field_ptr_ty);
}
-
- return block.addStructFieldPtr(struct_ptr, field_index, ptr_field_ty);
}
fn structFieldVal(
@@ -27370,8 +26374,8 @@ fn structFieldVal(
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
assert(struct_ty.zigTypeTag(zcu) == .@"struct");
-
- try struct_ty.resolveFields(pt);
+ assert(sema.typeOf(struct_byval).toIntern() == struct_ty.toIntern());
+ struct_ty.assertHasLayout(zcu);
switch (ip.indexToKey(struct_ty.toIntern())) {
.struct_type => {
@@ -27379,24 +26383,19 @@ fn structFieldVal(
const field_index = struct_type.nameIndex(ip, field_name) orelse
return sema.failWithBadStructFieldAccess(block, struct_ty, struct_type, field_name_src, field_name);
- if (struct_type.fieldIsComptime(ip, field_index)) {
- try struct_ty.resolveStructFieldInits(pt);
- return Air.internedToRef(struct_type.field_inits.get(ip)[field_index]);
+ if (struct_type.field_is_comptime_bits.get(ip, field_index)) {
+ return .fromIntern(struct_type.field_defaults.get(ip)[field_index]);
}
const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);
- if (try sema.typeHasOnePossibleValue(field_ty)) |field_val|
- return Air.internedToRef(field_val.toIntern());
+ if (try field_ty.onePossibleValue(pt)) |field_val|
+ return .fromValue(field_val);
- if (try sema.resolveValue(struct_byval)) |struct_val| {
+ if (sema.resolveValue(struct_byval)) |struct_val| {
if (struct_val.isUndef(zcu)) return pt.undefRef(field_ty);
- if ((try sema.typeHasOnePossibleValue(field_ty))) |opv| {
- return Air.internedToRef(opv.toIntern());
- }
- return Air.internedToRef((try struct_val.fieldValue(pt, field_index)).toIntern());
+ return .fromValue(try struct_val.fieldValue(pt, field_index));
}
- try field_ty.resolveLayout(pt);
return block.addStructFieldVal(struct_byval, field_index, field_ty);
},
.tuple_type => {
@@ -27457,16 +26456,13 @@ fn tupleFieldValByIndex(
const zcu = pt.zcu;
const field_ty = tuple_ty.fieldType(field_index, zcu);
- if (tuple_ty.structFieldIsComptime(field_index, zcu))
- try tuple_ty.resolveStructFieldInits(pt);
if (try tuple_ty.structFieldValueComptime(pt, field_index)) |default_value| {
return Air.internedToRef(default_value.toIntern());
}
- if (try sema.resolveValue(tuple_byval)) |tuple_val| {
- if ((try sema.typeHasOnePossibleValue(field_ty))) |opv| {
- return Air.internedToRef(opv.toIntern());
- }
+ if (try field_ty.onePossibleValue(pt)) |opv| return .fromValue(opv);
+
+ if (sema.resolveValue(tuple_byval)) |tuple_val| {
return switch (zcu.intern_pool.indexToKey(tuple_val.toIntern())) {
.undef => pt.undefRef(field_ty),
.aggregate => |aggregate| Air.internedToRef(switch (aggregate.storage) {
@@ -27478,10 +26474,10 @@ fn tupleFieldValByIndex(
};
}
- try field_ty.resolveLayout(pt);
return block.addStructFieldVal(tuple_byval, field_index, field_ty);
}
+/// Asserts that the layout of `union_ty` is already resolved.
fn unionFieldPtr(
sema: *Sema,
block: *Block,
@@ -27497,35 +26493,17 @@ fn unionFieldPtr(
const ip = &zcu.intern_pool;
assert(union_ty.zigTypeTag(zcu) == .@"union");
+ union_ty.assertHasLayout(zcu);
- const union_ptr_ty = sema.typeOf(union_ptr);
- const union_ptr_info = union_ptr_ty.ptrInfo(zcu);
- try union_ty.resolveFields(pt);
const union_obj = zcu.typeToUnion(union_ty).?;
+ const tag_ty: Type = .fromInterned(union_obj.enum_tag_type);
+
const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);
- const ptr_field_ty = try pt.ptrTypeSema(.{
- .child = field_ty.toIntern(),
- .flags = .{
- .is_const = union_ptr_info.flags.is_const,
- .is_volatile = union_ptr_info.flags.is_volatile,
- .address_space = union_ptr_info.flags.address_space,
- .alignment = if (union_obj.flagsUnordered(ip).layout == .auto) blk: {
- const union_align = if (union_ptr_info.flags.alignment != .none)
- union_ptr_info.flags.alignment
- else
- try union_ty.abiAlignmentSema(pt);
- const field_align = try union_ty.fieldAlignmentSema(field_index, pt);
- break :blk union_align.min(field_align);
- } else union_ptr_info.flags.alignment,
- },
- .packed_offset = union_ptr_info.packed_offset,
- });
- const enum_field_index: u32 = @intCast(Type.fromInterned(union_obj.enum_tag_ty).enumFieldIndex(field_name, zcu).?);
- if (initializing and field_ty.zigTypeTag(zcu) == .noreturn) {
+ if (initializing and field_ty.classify(zcu) == .no_possible_value) {
const msg = msg: {
- const msg = try sema.errMsg(src, "cannot initialize 'noreturn' field of union", .{});
+ const msg = try sema.errMsg(src, "cannot initialize union field with uninstantiable type '{f}'", .{field_ty.fmt(pt)});
errdefer msg.destroy(sema.gpa);
try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' declared here", .{
@@ -27538,30 +26516,24 @@ fn unionFieldPtr(
}
if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| ct: {
- switch (union_obj.flagsUnordered(ip).layout) {
+ switch (union_obj.layout) {
.auto => if (initializing) {
if (!sema.isComptimeMutablePtr(union_ptr_val)) {
// The initialization is a runtime operation.
break :ct;
}
// Store to the union to initialize the tag.
- const field_tag = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_ty), enum_field_index);
- const payload_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);
- const new_union_val = try pt.unionValue(union_ty, field_tag, try pt.undefValue(payload_ty));
+ const field_tag = try pt.enumValueFieldIndex(tag_ty, field_index);
+ const payload_val = try field_ty.onePossibleValue(pt) orelse try pt.undefValue(field_ty);
+ const new_union_val = try pt.unionValue(union_ty, field_tag, payload_val);
try sema.storePtrVal(block, src, union_ptr_val, new_union_val, union_ty);
} else {
- const union_val = (try sema.pointerDeref(block, src, union_ptr_val, union_ptr_ty)) orelse
- break :ct;
- if (union_val.isUndef(zcu)) {
- return sema.failWithUseOfUndef(block, src, null);
- }
- const un = ip.indexToKey(union_val.toIntern()).un;
- const field_tag = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_ty), enum_field_index);
- const tag_matches = un.tag == field_tag.toIntern();
- if (!tag_matches) {
+ const union_val = try sema.pointerDeref(block, src, union_ptr_val, union_ptr_val.typeOf(zcu)) orelse break :ct;
+ if (union_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, src, null);
+ const active_index = tag_ty.enumTagFieldIndex(union_val.unionTag(zcu).?, zcu).?;
+ if (active_index != field_index) {
const msg = msg: {
- const active_index = Type.fromInterned(union_obj.enum_tag_ty).enumTagFieldIndex(Value.fromInterned(un.tag), zcu).?;
- const active_field_name = Type.fromInterned(union_obj.enum_tag_ty).enumFieldName(active_index, zcu);
+ const active_field_name = tag_ty.enumFieldName(active_index, zcu);
const msg = try sema.errMsg(src, "access of union field '{f}' while field '{f}' is active", .{
field_name.fmt(ip),
active_field_name.fmt(ip),
@@ -27575,34 +26547,34 @@ fn unionFieldPtr(
},
.@"packed", .@"extern" => {},
}
- const field_ptr_val = try union_ptr_val.ptrField(field_index, pt);
- return Air.internedToRef(field_ptr_val.toIntern());
+ return .fromValue(try union_ptr_val.ptrField(field_index, pt));
}
// If the union has a tag, we must either set or or safety check it depending on `initializing`.
tag: {
if (union_ty.containerLayout(zcu) != .auto) break :tag;
- const tag_ty: Type = .fromInterned(union_obj.enum_tag_ty);
- if (try sema.typeHasOnePossibleValue(tag_ty) != null) break :tag;
+ if (tag_ty.classify(zcu) == .one_possible_value) break :tag;
// There is a hypothetical non-trivial tag. We must set it even if not there at runtime, but
// only emit a safety check if it's available at runtime (i.e. it's safety-tagged).
- const want_tag = try pt.enumValueFieldIndex(tag_ty, enum_field_index);
+ const want_tag = try pt.enumValueFieldIndex(tag_ty, field_index);
if (initializing) {
const set_tag_inst = try block.addBinOp(.set_union_tag, union_ptr, .fromValue(want_tag));
try sema.checkComptimeKnownStore(block, set_tag_inst, .unneeded); // `unneeded` since this isn't a "proper" store
- } else if (block.wantSafety() and union_obj.hasTag(ip)) {
- // The tag exists at runtime (safety tag), so emit a safety check.
+ } else if (block.wantSafety() and union_obj.has_runtime_tag) {
+ // The tag exists at runtime (actual or safety tag), so emit a safety check.
// TODO would it be better if get_union_tag supported pointers to unions?
const union_val = try block.addTyOp(.load, union_ty, union_ptr);
const active_tag = try block.addTyOp(.get_union_tag, tag_ty, union_val);
try sema.addSafetyCheckInactiveUnionField(block, src, active_tag, .fromValue(want_tag));
}
}
- if (field_ty.zigTypeTag(zcu) == .noreturn) {
+ if (field_ty.classify(zcu) == .no_possible_value) {
_ = try block.addNoOp(.unreach);
return .unreachable_value;
}
- return block.addStructFieldPtr(union_ptr, field_index, ptr_field_ty);
+
+ const field_ptr_ty = try sema.typeOf(union_ptr).fieldPtrType(field_index, pt);
+ return block.addStructFieldPtr(union_ptr, field_index, field_ptr_ty);
}
fn unionFieldVal(
@@ -27618,71 +26590,57 @@ fn unionFieldVal(
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
assert(union_ty.zigTypeTag(zcu) == .@"union");
+ assert(sema.typeOf(union_byval).toIntern() == union_ty.toIntern());
+ union_ty.assertHasLayout(zcu);
- try union_ty.resolveFields(pt);
const union_obj = zcu.typeToUnion(union_ty).?;
const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);
- const enum_field_index: u32 = @intCast(Type.fromInterned(union_obj.enum_tag_ty).enumFieldIndex(field_name, zcu).?);
+ const enum_tag_ty: Type = .fromInterned(union_obj.enum_tag_type);
- if (try sema.resolveValue(union_byval)) |union_val| {
+ if (sema.resolveValue(union_byval)) |union_val| {
if (union_val.isUndef(zcu)) return pt.undefRef(field_ty);
-
- const un = ip.indexToKey(union_val.toIntern()).un;
- const field_tag = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_ty), enum_field_index);
- const tag_matches = un.tag == field_tag.toIntern();
- switch (union_obj.flagsUnordered(ip).layout) {
+ switch (union_obj.layout) {
.auto => {
- if (tag_matches) {
- return Air.internedToRef(un.val);
- } else {
- const msg = msg: {
- const active_index = Type.fromInterned(union_obj.enum_tag_ty).enumTagFieldIndex(Value.fromInterned(un.tag), zcu).?;
- const active_field_name = Type.fromInterned(union_obj.enum_tag_ty).enumFieldName(active_index, zcu);
- const msg = try sema.errMsg(src, "access of union field '{f}' while field '{f}' is active", .{
- field_name.fmt(ip), active_field_name.fmt(ip),
- });
- errdefer msg.destroy(sema.gpa);
- try sema.addDeclaredHereNote(msg, union_ty);
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(block, msg);
- }
+ const active_tag_val = union_val.unionTag(zcu).?;
+ const active_index = enum_tag_ty.enumTagFieldIndex(active_tag_val, zcu).?;
+ if (active_index == field_index) return .fromValue(union_val.unionPayload(zcu));
+ return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(src, "access of union field '{f}' while field '{f}' is active", .{
+ field_name.fmt(ip), enum_tag_ty.enumFieldName(active_index, zcu).fmt(ip),
+ });
+ errdefer msg.destroy(zcu.comp.gpa);
+ try sema.addDeclaredHereNote(msg, union_ty);
+ break :msg msg;
+ });
},
- .@"extern" => if (tag_matches) {
- // Fast path - no need to use bitcast logic.
- return Air.internedToRef(un.val);
- } else if (try sema.bitCastVal(union_val, field_ty, 0, 0, 0)) |field_val| {
- return Air.internedToRef(field_val.toIntern());
+ .@"extern" => if (try sema.bitCastVal(union_val, field_ty, 0, 0, 0)) |field_val| {
+ return .fromValue(field_val);
+ } else {
+ // Runtime-known due to a pointer-to-integer conversion.
},
- .@"packed" => if (tag_matches) {
- // Fast path - no need to use bitcast logic.
- return Air.internedToRef(un.val);
- } else if (try sema.bitCastVal(union_val, field_ty, 0, try union_ty.bitSizeSema(pt), 0)) |field_val| {
- return Air.internedToRef(field_val.toIntern());
+ .@"packed" => {
+ const field_val = try sema.bitCastVal(union_val, field_ty, 0, union_ty.bitSize(zcu), 0) orelse {
+ unreachable; // `null` is only possible if the input value contains a pointer, which a packed union cannot.
+ };
+ return .fromValue(field_val);
},
}
}
- if (union_obj.flagsUnordered(ip).layout == .auto and block.wantSafety() and
- union_ty.unionTagTypeSafety(zcu) != null and union_obj.field_types.len > 1)
- {
- const wanted_tag_val = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_ty), enum_field_index);
- const wanted_tag = Air.internedToRef(wanted_tag_val.toIntern());
- const active_tag = try block.addTyOp(.get_union_tag, .fromInterned(union_obj.enum_tag_ty), union_byval);
- try sema.addSafetyCheckInactiveUnionField(block, src, active_tag, wanted_tag);
+ if (union_obj.layout == .auto and block.wantSafety() and union_obj.has_runtime_tag) {
+ const wanted_tag_val = try pt.enumValueFieldIndex(enum_tag_ty, field_index);
+ const active_tag = try block.addTyOp(.get_union_tag, enum_tag_ty, union_byval);
+ try sema.addSafetyCheckInactiveUnionField(block, src, active_tag, .fromValue(wanted_tag_val));
}
- if (field_ty.zigTypeTag(zcu) == .noreturn) {
+ if (field_ty.classify(zcu) == .no_possible_value) {
_ = try block.addNoOp(.unreach);
return .unreachable_value;
}
- if (try sema.typeHasOnePossibleValue(field_ty)) |field_only_value| {
- return Air.internedToRef(field_only_value.toIntern());
- }
+ if (try field_ty.onePossibleValue(pt)) |opv| return .fromValue(opv);
- try field_ty.resolveLayout(pt);
return block.addStructFieldVal(union_byval, field_index, field_ty);
}
@@ -27706,17 +26664,15 @@ fn elemPtr(
else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{f}'", .{indexable_ptr_ty.fmt(pt)}),
};
try sema.checkIndexable(block, src, indexable_ty);
+ try sema.ensureLayoutResolved(indexable_ty, src, .ptr_access);
const elem_ptr = switch (indexable_ty.zigTypeTag(zcu)) {
- .array, .vector => try sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init, oob_safety),
- .@"struct" => blk: {
- // Tuple field access.
- const index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{ .simple = .tuple_field_index });
- const index: u32 = @intCast(try index_val.toUnsignedIntSema(pt));
- break :blk try sema.tupleFieldPtr(block, src, indexable_ptr, elem_index_src, index, init);
- },
+ .vector => try sema.elemPtrVector(block, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init),
+ .array => try sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init, oob_safety),
+ .@"struct" => try sema.tupleElemPtr(block, src, indexable_ptr, elem_index, elem_index_src),
else => {
const indexable = try sema.analyzeLoad(block, indexable_ptr_src, indexable_ptr, indexable_ptr_src);
+ try sema.ensureLayoutResolved(sema.typeOf(indexable).childType(zcu), src, .ptr_access);
return elemPtrOneLayerOnly(sema, block, src, indexable, elem_index, elem_index_src, init, oob_safety);
},
};
@@ -27725,7 +26681,7 @@ fn elemPtr(
return elem_ptr;
}
-/// Asserts that the type of indexable is pointer.
+/// Asserts that `indexable` is an indexable pointer whose child type has its layout already resolved.
fn elemPtrOneLayerOnly(
sema: *Sema,
block: *Block,
@@ -27741,28 +26697,31 @@ fn elemPtrOneLayerOnly(
const pt = sema.pt;
const zcu = pt.zcu;
- try sema.checkIndexable(block, src, indexable_ty);
+ assert(indexable_ty.isIndexable(zcu));
+ assert(indexable_ty.zigTypeTag(zcu) == .pointer);
+ const child_ty = indexable_ty.childType(zcu);
+ child_ty.assertHasLayout(zcu);
switch (indexable_ty.ptrSize(zcu)) {
.slice => return sema.elemPtrSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety),
.many, .c => {
const maybe_ptr_val = try sema.resolveDefinedValue(block, indexable_src, indexable);
const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
+ const maybe_index: ?u64 = if (maybe_index_val) |val| val.toUnsignedInt(zcu) else null;
ct: {
const ptr_val = maybe_ptr_val orelse break :ct;
- const index_val = maybe_index_val orelse break :ct;
- const index: usize = @intCast(try index_val.toUnsignedIntSema(pt));
- const elem_ptr = try ptr_val.ptrElem(index, pt);
- return Air.internedToRef(elem_ptr.toIntern());
+ const index: usize = @intCast(maybe_index orelse break :ct);
+ return .fromValue(try ptr_val.ptrElem(index, pt));
}
try sema.checkLogicalPtrOperation(block, src, indexable_ty);
- const result_ty = try indexable_ty.elemPtrType(null, pt);
+
+ const result_ty = try indexable_ty.elemPtrType(maybe_index, pt);
try sema.validateRuntimeElemAccess(block, elem_index_src, result_ty, indexable_ty, indexable_src);
try sema.validateRuntimeValue(block, indexable_src, indexable);
- if (!try result_ty.childType(zcu).hasRuntimeBitsIgnoreComptimeSema(pt)) {
+ if (child_ty.abiSize(zcu) == 0) {
// zero-bit child type; just bitcast the pointer
return block.addBitCast(result_ty, indexable);
}
@@ -27770,15 +26729,10 @@ fn elemPtrOneLayerOnly(
return block.addPtrElemPtr(indexable, elem_index, result_ty);
},
.one => {
- const child_ty = indexable_ty.childType(zcu);
const elem_ptr = switch (child_ty.zigTypeTag(zcu)) {
- .array, .vector => try sema.elemPtrArray(block, src, indexable_src, indexable, elem_index_src, elem_index, init, oob_safety),
- .@"struct" => blk: {
- assert(child_ty.isTuple(zcu));
- const index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{ .simple = .tuple_field_index });
- const index: u32 = @intCast(try index_val.toUnsignedIntSema(pt));
- break :blk try sema.tupleFieldPtr(block, indexable_src, indexable, elem_index_src, index, false);
- },
+ .vector => try sema.elemPtrVector(block, indexable_src, indexable, elem_index_src, elem_index, init),
+ .array => try sema.elemPtrArray(block, src, indexable_src, indexable, elem_index_src, elem_index, init, oob_safety),
+ .@"struct" => try sema.tupleElemPtr(block, indexable_src, indexable, elem_index, elem_index_src),
else => unreachable, // Guaranteed by checkIndexable
};
try sema.checkKnownAllocPtr(block, indexable, elem_ptr);
@@ -27808,45 +26762,51 @@ fn elemVal(
const elem_index = try sema.coerce(block, .usize, elem_index_uncasted, elem_index_src);
switch (indexable_ty.zigTypeTag(zcu)) {
- .pointer => switch (indexable_ty.ptrSize(zcu)) {
- .slice => return sema.elemValSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety),
- .many, .c => {
- const maybe_indexable_val = try sema.resolveDefinedValue(block, indexable_src, indexable);
- const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
- const elem_ty = indexable_ty.elemType2(zcu);
+ .pointer => {
+ const child_ty = indexable_ty.childType(zcu);
+ try sema.ensureLayoutResolved(child_ty, src, .ptr_access);
+ switch (indexable_ty.ptrSize(zcu)) {
+ .slice => return sema.elemValSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety),
+ .many, .c => {
+ const maybe_indexable_val = try sema.resolveDefinedValue(block, indexable_src, indexable);
+ const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
- ct: {
- const indexable_val = maybe_indexable_val orelse break :ct;
- const index_val = maybe_index_val orelse break :ct;
- const index: usize = @intCast(try index_val.toUnsignedIntSema(pt));
- const many_ptr_ty = try pt.manyConstPtrType(elem_ty);
- const many_ptr_val = try pt.getCoerced(indexable_val, many_ptr_ty);
- const elem_ptr_ty = try pt.singleConstPtrType(elem_ty);
- const elem_ptr_val = try many_ptr_val.ptrElem(index, pt);
- const elem_val = try sema.pointerDeref(block, indexable_src, elem_ptr_val, elem_ptr_ty) orelse break :ct;
- return Air.internedToRef((try pt.getCoerced(elem_val, elem_ty)).toIntern());
- }
+ ct: {
+ const indexable_val = maybe_indexable_val orelse break :ct;
+ const index_val = maybe_index_val orelse break :ct;
+ const index: usize = @intCast(index_val.toUnsignedInt(zcu));
+ const many_ptr_ty = try pt.manyConstPtrType(child_ty);
+ const many_ptr_val = try pt.getCoerced(indexable_val, many_ptr_ty);
+ const elem_ptr_val = try many_ptr_val.ptrElem(index, pt);
+ return sema.analyzeLoad(block, src, .fromValue(elem_ptr_val), indexable_src);
+ }
- if (try sema.typeHasOnePossibleValue(elem_ty)) |elem_only_value| {
- return Air.internedToRef(elem_only_value.toIntern());
- }
+ try sema.validateRuntimeElemAccess(block, elem_index_src, child_ty, indexable_ty, src);
+ switch (child_ty.classify(zcu)) {
+ .runtime => {},
+ .one_possible_value => return .fromValue((try child_ty.onePossibleValue(pt)).?),
+ .no_possible_value => switch (child_ty.zigTypeTag(zcu)) {
+ .@"opaque" => return sema.fail(block, src, "cannot load opaque type '{f}'", .{child_ty.fmt(pt)}),
+ else => return sema.fail(block, src, "cannot load uninstantiable type '{f}'", .{child_ty.fmt(pt)}),
+ },
+ .partially_comptime, .fully_comptime => unreachable, // caught by `validateRuntimeElemAccess`
+ }
- try sema.checkLogicalPtrOperation(block, src, indexable_ty);
- return block.addBinOp(.ptr_elem_val, indexable, elem_index);
- },
- .one => {
- arr_sent: {
- const inner_ty = indexable_ty.childType(zcu);
- if (inner_ty.zigTypeTag(zcu) != .array) break :arr_sent;
- const sentinel = inner_ty.sentinel(zcu) orelse break :arr_sent;
- const index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index) orelse break :arr_sent;
- const index = try sema.usizeCast(block, src, try index_val.toUnsignedIntSema(pt));
- if (index != inner_ty.arrayLen(zcu)) break :arr_sent;
- return Air.internedToRef(sentinel.toIntern());
- }
- const elem_ptr = try sema.elemPtr(block, indexable_src, indexable, elem_index, elem_index_src, false, oob_safety);
- return sema.analyzeLoad(block, indexable_src, elem_ptr, elem_index_src);
- },
+ return block.addBinOp(.ptr_elem_val, indexable, elem_index);
+ },
+ .one => {
+ arr_sent: {
+ if (child_ty.zigTypeTag(zcu) != .array) break :arr_sent;
+ const sentinel = child_ty.sentinel(zcu) orelse break :arr_sent;
+ const index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index) orelse break :arr_sent;
+ const index = try sema.usizeCast(block, src, index_val.toUnsignedInt(zcu));
+ if (index != child_ty.arrayLen(zcu)) break :arr_sent;
+ return .fromValue(sentinel);
+ }
+ const elem_ptr = try sema.elemPtr(block, indexable_src, indexable, elem_index, elem_index_src, false, oob_safety);
+ return sema.analyzeLoad(block, indexable_src, elem_ptr, elem_index_src);
+ },
+ }
},
.array => return sema.elemValArray(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety),
.vector => {
@@ -27856,7 +26816,7 @@ fn elemVal(
.@"struct" => {
// Tuple field access.
const index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{ .simple = .tuple_field_index });
- const index: u32 = @intCast(try index_val.toUnsignedIntSema(pt));
+ const index: u32 = @intCast(index_val.toUnsignedInt(zcu));
return sema.tupleField(block, indexable_src, indexable, elem_index_src, index);
},
else => unreachable,
@@ -27864,6 +26824,7 @@ fn elemVal(
}
/// Called when the index or indexable is runtime known.
+/// Asserts that the layout of `elem_ty` is already resolved.
fn validateRuntimeElemAccess(
sema: *Sema,
block: *Block,
@@ -27875,16 +26836,16 @@ fn validateRuntimeElemAccess(
const pt = sema.pt;
const zcu = pt.zcu;
- if (try elem_ty.comptimeOnlySema(sema.pt)) {
+ if (elem_ty.comptimeOnly(zcu)) {
const msg = msg: {
const msg = try sema.errMsg(
elem_index_src,
"values of type '{f}' must be comptime-known, but index value is runtime-known",
- .{parent_ty.fmt(sema.pt)},
+ .{elem_ty.fmt(sema.pt)},
);
errdefer msg.destroy(sema.gpa);
- try sema.explainWhyTypeIsComptime(msg, parent_src, parent_ty);
+ try sema.explainWhyTypeIsComptime(msg, parent_src, elem_ty);
break :msg msg;
};
@@ -27900,71 +26861,38 @@ fn validateRuntimeElemAccess(
}
}
-fn tupleFieldPtr(
+/// Validates `elem_index`, and returns a pointer to that field using `structFieldPtrByIndex`.
+///
+/// Asserts that the type of `tuple_ptr` is a single-item pointer whose child type is a tuple.
+fn tupleElemPtr(
sema: *Sema,
block: *Block,
- tuple_ptr_src: LazySrcLoc,
+ src: LazySrcLoc,
tuple_ptr: Air.Inst.Ref,
- field_index_src: LazySrcLoc,
- field_index: u32,
- init: bool,
+ elem_index: Air.Inst.Ref,
+ elem_index_src: LazySrcLoc,
) CompileError!Air.Inst.Ref {
const pt = sema.pt;
const zcu = pt.zcu;
const tuple_ptr_ty = sema.typeOf(tuple_ptr);
- const tuple_ptr_info = tuple_ptr_ty.ptrInfo(zcu);
- const tuple_ty: Type = .fromInterned(tuple_ptr_info.child);
- try tuple_ty.resolveFields(pt);
+ assert(tuple_ptr_ty.isSinglePointer(zcu));
+ const tuple_ty = tuple_ptr_ty.childType(zcu);
+ assert(tuple_ty.isTuple(zcu));
+
const field_count = tuple_ty.structFieldCount(zcu);
-
if (field_count == 0) {
- return sema.fail(block, tuple_ptr_src, "indexing into empty tuple is not allowed", .{});
+ return sema.fail(block, src, "indexing into empty tuple is not allowed", .{});
}
- if (field_index >= field_count) {
- return sema.fail(block, field_index_src, "index {d} outside tuple of length {d}", .{
- field_index, field_count,
+ const elem_index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{ .simple = .tuple_field_index });
+ const index = elem_index_val.getUnsignedInt(zcu);
+ if (index == null or index.? >= field_count) {
+ return sema.fail(block, elem_index_src, "index '{f}' out of bounds of tuple '{f}'", .{
+ elem_index_val.fmtValueSema(pt, sema), tuple_ty.fmt(pt),
});
}
- const field_ty = tuple_ty.fieldType(field_index, zcu);
- const ptr_field_ty = try pt.ptrTypeSema(.{
- .child = field_ty.toIntern(),
- .flags = .{
- .is_const = tuple_ptr_info.flags.is_const,
- .is_volatile = tuple_ptr_info.flags.is_volatile,
- .address_space = tuple_ptr_info.flags.address_space,
- .alignment = a: {
- if (tuple_ptr_info.flags.alignment == .none) break :a .none;
- // The tuple pointer isn't naturally aligned, so the field pointer might be underaligned.
- const tuple_align = tuple_ptr_info.flags.alignment;
- const field_align = try field_ty.abiAlignmentSema(pt);
- break :a tuple_align.min(field_align);
- },
- },
- });
-
- if (tuple_ty.structFieldIsComptime(field_index, zcu))
- try tuple_ty.resolveStructFieldInits(pt);
-
- if (try tuple_ty.structFieldValueComptime(pt, field_index)) |default_val| {
- return Air.internedToRef((try pt.intern(.{ .ptr = .{
- .ty = ptr_field_ty.toIntern(),
- .base_addr = .{ .comptime_field = default_val.toIntern() },
- .byte_offset = 0,
- } })));
- }
-
- if (try sema.resolveValue(tuple_ptr)) |tuple_ptr_val| {
- const field_ptr_val = try tuple_ptr_val.ptrField(field_index, pt);
- return Air.internedToRef(field_ptr_val.toIntern());
- }
-
- if (!init) {
- try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_ptr_src);
- }
-
- return block.addStructFieldPtr(tuple_ptr, field_index, ptr_field_ty);
+ return sema.structFieldPtrByIndex(block, src, tuple_ptr, @intCast(index.?), tuple_ty);
}
fn tupleField(
@@ -27978,7 +26906,6 @@ fn tupleField(
const pt = sema.pt;
const zcu = pt.zcu;
const tuple_ty = sema.typeOf(tuple);
- try tuple_ty.resolveFields(pt);
const field_count = tuple_ty.structFieldCount(zcu);
if (field_count == 0) {
@@ -27993,20 +26920,17 @@ fn tupleField(
const field_ty = tuple_ty.fieldType(field_index, zcu);
- if (tuple_ty.structFieldIsComptime(field_index, zcu))
- try tuple_ty.resolveStructFieldInits(pt);
if (try tuple_ty.structFieldValueComptime(pt, field_index)) |default_value| {
return Air.internedToRef(default_value.toIntern()); // comptime field
}
- if (try sema.resolveValue(tuple)) |tuple_val| {
+ if (sema.resolveValue(tuple)) |tuple_val| {
if (tuple_val.isUndef(zcu)) return pt.undefRef(field_ty);
return Air.internedToRef((try tuple_val.fieldValue(pt, field_index)).toIntern());
}
try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src);
- try field_ty.resolveLayout(pt);
return block.addStructFieldVal(tuple, field_index, field_ty);
}
@@ -28032,12 +26956,12 @@ fn elemValArray(
return sema.fail(block, array_src, "indexing into empty array is not allowed", .{});
}
- const maybe_undef_array_val = try sema.resolveValue(array);
+ const maybe_undef_array_val = sema.resolveValue(array);
// index must be defined since it can access out of bounds
const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
if (maybe_index_val) |index_val| {
- const index: usize = @intCast(try index_val.toUnsignedIntSema(pt));
+ const index: usize = @intCast(index_val.toUnsignedInt(zcu));
if (array_sent) |s| {
if (index == array_len) {
return Air.internedToRef(s.toIntern());
@@ -28053,10 +26977,11 @@ fn elemValArray(
return pt.undefRef(elem_ty);
}
if (maybe_index_val) |index_val| {
- const index: usize = @intCast(try index_val.toUnsignedIntSema(pt));
- const elem_val = try array_val.elemValue(pt, index);
- return Air.internedToRef(elem_val.toIntern());
+ const index: usize = @intCast(index_val.toUnsignedInt(zcu));
+ return .fromValue(try array_val.elemValue(pt, index));
}
+ // Since the array is comptime-known, it might be OPV, in which case the index is irrelevant.
+ if (try elem_ty.onePossibleValue(pt)) |opv| return .fromValue(opv);
}
try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, array_ty, array_src);
@@ -28071,12 +26996,105 @@ fn elemValArray(
}
}
- if (try sema.typeHasOnePossibleValue(elem_ty)) |elem_val|
- return Air.internedToRef(elem_val.toIntern());
-
return block.addBinOp(.array_elem_val, array, elem_index);
}
+fn elemPtrVector(
+ sema: *Sema,
+ block: *Block,
+ vector_ptr_src: LazySrcLoc,
+ vector_ptr: Air.Inst.Ref,
+ elem_index_src: LazySrcLoc,
+ elem_index: Air.Inst.Ref,
+ init: bool,
+) CompileError!Air.Inst.Ref {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
+ const vector_ptr_ty = sema.typeOf(vector_ptr);
+ const vector_ty = vector_ptr_ty.childType(zcu);
+ assert(vector_ty.zigTypeTag(zcu) == .vector);
+ const vector_len = vector_ty.vectorLen(zcu);
+
+ if (vector_len == 0) {
+ return sema.fail(block, vector_ptr_src, "cannot index into empty vector", .{});
+ }
+
+ const maybe_vector_ptr_val = sema.resolveValue(vector_ptr);
+ // The index must not be undefined since it can be out of bounds.
+ const index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index) orelse {
+ return sema.fail(block, elem_index_src, "vector index not comptime known", .{});
+ };
+ const index = index_val.toUnsignedInt(zcu);
+ if (index >= vector_len) {
+ return sema.fail(block, elem_index_src, "index {d} outside vector of length {d}", .{ index, vector_len });
+ }
+
+ const elem_ty = vector_ty.childType(zcu);
+ const elem_bits = elem_ty.bitSize(zcu);
+ // Exiting this block means the operation is a runtime one.
+ const elem_ptr_ty: Type = if (elem_bits < 8 or !std.math.isPowerOfTwo(elem_bits)) elem_ptr_ty: {
+ // Use a packed pointer (i.e. vector_index != 0)
+ const vector_ptr_info = vector_ptr_ty.ptrInfo(zcu);
+ const elem_ptr_ty = try pt.ptrType(.{
+ .child = elem_ty.toIntern(),
+ .flags = .{
+ .size = .one,
+ .alignment = vector_ptr_info.flags.alignment,
+ .is_const = vector_ptr_info.flags.is_const,
+ .is_volatile = vector_ptr_info.flags.is_volatile,
+ .is_allowzero = vector_ptr_info.flags.is_allowzero,
+ .address_space = vector_ptr_info.flags.address_space,
+ .vector_index = @enumFromInt(index),
+ },
+ .packed_offset = .{
+ .host_size = @intCast(vector_len),
+ .bit_offset = 0,
+ },
+ });
+ if (maybe_vector_ptr_val) |ptr_val| {
+ if (ptr_val.isUndef(zcu)) return pt.undefRef(elem_ptr_ty);
+ return .fromValue(try pt.getCoerced(ptr_val, elem_ptr_ty));
+ }
+ break :elem_ptr_ty elem_ptr_ty;
+ } else elem_ptr_ty: {
+ // Use a normal pointer (i.e. vector_index == 0)
+ const vector_ptr_info = vector_ptr_ty.ptrInfo(zcu);
+ const elem_ptr_ty = try pt.ptrType(.{
+ .child = elem_ty.toIntern(),
+ .flags = .{
+ .size = .one,
+ // TODO: this logic was ported from old code, but it's bogus. This entire block will
+ // go away when https://github.com/ziglang/zig/issues/24061 is implemented anyway.
+ .alignment = switch (vector_ptr_info.flags.alignment) {
+ .none => .none,
+ else => |vec_align| switch (index * elem_ty.abiSize(zcu)) {
+ 0 => vec_align,
+ else => |byte_offset| .minStrict(vec_align, .fromLog2Units(@ctz(byte_offset))),
+ },
+ },
+ .is_const = vector_ptr_info.flags.is_const,
+ .is_volatile = vector_ptr_info.flags.is_volatile,
+ .is_allowzero = vector_ptr_info.flags.is_allowzero,
+ .address_space = vector_ptr_info.flags.address_space,
+ },
+ });
+ if (maybe_vector_ptr_val) |ptr_val| {
+ if (ptr_val.isUndef(zcu)) return pt.undefRef(elem_ptr_ty);
+ const bit_offset = index * @divExact(elem_ty.bitSize(zcu), 8);
+ return .fromValue(try ptr_val.getOffsetPtr(bit_offset, elem_ptr_ty, pt));
+ }
+ break :elem_ptr_ty elem_ptr_ty;
+ };
+
+ if (!init) {
+ try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, vector_ty, vector_ptr_src);
+ try sema.validateRuntimeValue(block, vector_ptr_src, vector_ptr);
+ }
+
+ return block.addPtrElemPtr(vector_ptr, elem_index, elem_ptr_ty);
+}
+
+/// Asserts that the layout of the array is already resolved.
fn elemPtrArray(
sema: *Sema,
block: *Block,
@@ -28091,19 +27109,21 @@ fn elemPtrArray(
const pt = sema.pt;
const zcu = pt.zcu;
const array_ptr_ty = sema.typeOf(array_ptr);
+ assert(array_ptr_ty.ptrSize(zcu) == .one);
const array_ty = array_ptr_ty.childType(zcu);
+ assert(array_ty.zigTypeTag(zcu) == .array);
const array_sent = array_ty.sentinel(zcu) != null;
const array_len = array_ty.arrayLen(zcu);
const array_len_s = array_len + @intFromBool(array_sent);
if (array_len_s == 0) {
- return sema.fail(block, array_ptr_src, "indexing into empty array is not allowed", .{});
+ return sema.fail(block, array_ptr_src, "cannot index into empty array", .{});
}
- const maybe_undef_array_ptr_val = try sema.resolveValue(array_ptr);
+ const maybe_undef_array_ptr_val = sema.resolveValue(array_ptr);
// The index must not be undefined since it can be out of bounds.
- const offset: ?usize = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: {
- const index = try sema.usizeCast(block, elem_index_src, try index_val.toUnsignedIntSema(pt));
+ const maybe_index: ?u64 = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: {
+ const index = index_val.toUnsignedInt(zcu);
if (index >= array_len_s) {
const sentinel_label: []const u8 = if (array_sent) " +1 (sentinel)" else "";
return sema.fail(block, elem_index_src, "index {d} outside array of length {d}{s}", .{ index, array_len, sentinel_label });
@@ -28111,37 +27131,39 @@ fn elemPtrArray(
break :o index;
} else null;
- if (offset == null and array_ty.zigTypeTag(zcu) == .vector) {
- return sema.fail(block, elem_index_src, "vector index not comptime known", .{});
- }
-
- const elem_ptr_ty = try array_ptr_ty.elemPtrType(offset, pt);
+ array_ty.assertHasLayout(zcu);
+ const elem_ptr_ty = try array_ptr_ty.elemPtrType(maybe_index, pt);
if (maybe_undef_array_ptr_val) |array_ptr_val| {
if (array_ptr_val.isUndef(zcu)) {
return pt.undefRef(elem_ptr_ty);
}
- if (offset) |index| {
- const elem_ptr = try array_ptr_val.ptrElem(index, pt);
- return Air.internedToRef(elem_ptr.toIntern());
+ if (maybe_index) |index| {
+ return .fromValue(try array_ptr_val.ptrElem(index, pt));
}
}
if (!init) {
- try sema.validateRuntimeElemAccess(block, elem_index_src, array_ty.elemType2(zcu), array_ty, array_ptr_src);
+ try sema.validateRuntimeElemAccess(block, elem_index_src, array_ty.childType(zcu), array_ty, array_ptr_src);
try sema.validateRuntimeValue(block, array_ptr_src, array_ptr);
}
// Runtime check is only needed if unable to comptime check.
- if (oob_safety and block.wantSafety() and offset == null) {
+ if (oob_safety and block.wantSafety() and maybe_index == null) {
const len_inst = try pt.intRef(.usize, array_len);
const cmp_op: Air.Inst.Tag = if (array_sent) .cmp_lte else .cmp_lt;
try sema.addSafetyCheckIndexOob(block, src, elem_index, len_inst, cmp_op);
}
+ if (array_ty.childType(zcu).abiSize(zcu) == 0) {
+ // zero-bit child type; just bitcast the pointer
+ return block.addBitCast(elem_ptr_ty, array_ptr);
+ }
+
return block.addPtrElemPtr(array_ptr, elem_index, elem_ptr_ty);
}
+/// Asserts that the layout of the slice element type is already resolved.
fn elemValSlice(
sema: *Sema,
block: *Block,
@@ -28155,9 +27177,11 @@ fn elemValSlice(
const pt = sema.pt;
const zcu = pt.zcu;
const slice_ty = sema.typeOf(slice);
+ assert(slice_ty.isSlice(zcu));
const slice_sent = slice_ty.sentinel(zcu) != null;
- const elem_ty = slice_ty.elemType2(zcu);
- var runtime_src = slice_src;
+ const elem_ty = slice_ty.childType(zcu);
+
+ elem_ty.assertHasLayout(zcu);
// slice must be defined since it can dereferenced as null
const maybe_slice_val = try sema.resolveDefinedValue(block, slice_src, slice);
@@ -28165,37 +27189,30 @@ fn elemValSlice(
const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
if (maybe_slice_val) |slice_val| {
- runtime_src = elem_index_src;
- const slice_len = try slice_val.sliceLen(pt);
+ const slice_len = slice_val.sliceLen(zcu);
const slice_len_s = slice_len + @intFromBool(slice_sent);
if (slice_len_s == 0) {
return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{});
}
if (maybe_index_val) |index_val| {
- const index: usize = @intCast(try index_val.toUnsignedIntSema(pt));
+ const index: usize = @intCast(index_val.toUnsignedInt(zcu));
if (index >= slice_len_s) {
const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else "";
return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label });
}
- const elem_ptr_ty = try slice_ty.elemPtrType(index, pt);
const elem_ptr_val = try slice_val.ptrElem(index, pt);
- if (try sema.pointerDeref(block, slice_src, elem_ptr_val, elem_ptr_ty)) |elem_val| {
- return Air.internedToRef(elem_val.toIntern());
- }
- runtime_src = slice_src;
+ return sema.analyzeLoad(block, src, .fromValue(elem_ptr_val), slice_src);
}
}
- if (try sema.typeHasOnePossibleValue(elem_ty)) |elem_only_value| {
- return Air.internedToRef(elem_only_value.toIntern());
- }
+ if (try elem_ty.onePossibleValue(pt)) |opv| return .fromValue(opv);
try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, slice_ty, slice_src);
try sema.validateRuntimeValue(block, slice_src, slice);
if (oob_safety and block.wantSafety()) {
const len_inst = if (maybe_slice_val) |slice_val|
- try pt.intRef(.usize, try slice_val.sliceLen(pt))
+ try pt.intRef(.usize, slice_val.sliceLen(zcu))
else
try block.addTyOp(.slice_len, .usize, slice);
const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt;
@@ -28204,6 +27221,7 @@ fn elemValSlice(
return block.addBinOp(.slice_elem_val, slice, elem_index);
}
+/// Asserts that the layout of the slice element type is already resolved.
fn elemPtrSlice(
sema: *Sema,
block: *Block,
@@ -28217,33 +27235,35 @@ fn elemPtrSlice(
const pt = sema.pt;
const zcu = pt.zcu;
const slice_ty = sema.typeOf(slice);
+ assert(slice_ty.isSlice(zcu));
const slice_sent = slice_ty.sentinel(zcu) != null;
+ const elem_ty = slice_ty.childType(zcu);
+ elem_ty.assertHasLayout(zcu);
- const maybe_undef_slice_val = try sema.resolveValue(slice);
+ const maybe_undef_slice_val = sema.resolveValue(slice);
// The index must not be undefined since it can be out of bounds.
- const offset: ?usize = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: {
- const index = try sema.usizeCast(block, elem_index_src, try index_val.toUnsignedIntSema(pt));
- break :o index;
+ const offset: ?u64 = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: {
+ break :o index_val.toUnsignedInt(zcu);
} else null;
const elem_ptr_ty = try slice_ty.elemPtrType(offset, pt);
+ assert(elem_ptr_ty.childType(zcu).toIntern() == elem_ty.toIntern());
if (maybe_undef_slice_val) |slice_val| {
if (slice_val.isUndef(zcu)) {
return pt.undefRef(elem_ptr_ty);
}
- const slice_len = try slice_val.sliceLen(pt);
+ const slice_len = slice_val.sliceLen(zcu);
const slice_len_s = slice_len + @intFromBool(slice_sent);
if (slice_len_s == 0) {
- return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{});
+ return sema.fail(block, slice_src, "cannot index into empty slice", .{});
}
if (offset) |index| {
if (index >= slice_len_s) {
const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else "";
return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label });
}
- const elem_ptr_val = try slice_val.ptrElem(index, pt);
- return Air.internedToRef(elem_ptr_val.toIntern());
+ return .fromValue(try slice_val.ptrElem(index, pt));
}
}
@@ -28254,13 +27274,13 @@ fn elemPtrSlice(
const len_inst = len: {
if (maybe_undef_slice_val) |slice_val|
if (!slice_val.isUndef(zcu))
- break :len try pt.intRef(.usize, try slice_val.sliceLen(pt));
+ break :len try pt.intRef(.usize, slice_val.sliceLen(zcu));
break :len try block.addTyOp(.slice_len, .usize, slice);
};
const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt;
try sema.addSafetyCheckIndexOob(block, src, elem_index, len_inst, cmp_op);
}
- if (!try slice_ty.childType(zcu).hasRuntimeBitsIgnoreComptimeSema(pt)) {
+ if (elem_ty.abiSize(zcu) == 0) {
// zero-bit child type; just extract the pointer and bitcast it
const slice_ptr = try block.addTyOp(.slice_ptr, slice_ty.slicePtrFieldType(zcu), slice);
return block.addBitCast(elem_ptr_ty, slice_ptr);
@@ -28331,15 +27351,17 @@ fn coerceExtra(
if (dest_ty.isGenericPoison()) return inst;
const dest_ty_src = inst_src; // TODO better source location
- try dest_ty.resolveFields(pt);
const inst_ty = sema.typeOf(inst);
- try inst_ty.resolveFields(pt);
const target = zcu.getTarget();
+
+ inst_ty.assertHasLayout(zcu);
+ try sema.ensureLayoutResolved(dest_ty, inst_src, .coerce);
+
// If the types are the same, we can return the operand.
if (dest_ty.eql(inst_ty, zcu))
return inst;
- const maybe_inst_val = try sema.resolveValue(inst);
+ const maybe_inst_val = sema.resolveValue(inst);
var in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src, maybe_inst_val);
if (in_memory_result == .ok) {
@@ -28357,7 +27379,7 @@ fn coerceExtra(
if (maybe_inst_val) |val| {
// undefined sets the optional bit also to undefined.
if (val.toIntern() == .undef) {
- return pt.undefRef(dest_ty);
+ return .fromValue(try dest_ty.onePossibleValue(pt) orelse try pt.undefValue(dest_ty));
}
// null to ?T
@@ -28372,11 +27394,11 @@ fn coerceExtra(
// cast from ?*T and ?[*]T to ?*anyopaque
// but don't do it if the source type is a double pointer
if (dest_ty.isPtrLikeOptional(zcu) and
- dest_ty.elemType2(zcu).toIntern() == .anyopaque_type and
+ dest_ty.nullablePtrElem(zcu).toIntern() == .anyopaque_type and
inst_ty.isPtrAtRuntime(zcu))
anyopaque_check: {
if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :optional;
- const elem_ty = inst_ty.elemType2(zcu);
+ const elem_ty = inst_ty.nullablePtrElem(zcu);
if (elem_ty.zigTypeTag(zcu) == .pointer or elem_ty.isPtrLikeOptional(zcu)) {
in_memory_result = .{ .double_ptr_to_anyopaque = .{
.actual = inst_ty,
@@ -28409,7 +27431,7 @@ fn coerceExtra(
// Function body to function pointer.
if (inst_ty.zigTypeTag(zcu) == .@"fn") {
- const fn_val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, inst, undefined);
+ const fn_val = sema.resolveValue(inst).?;
const fn_nav = switch (zcu.intern_pool.indexToKey(fn_val.toIntern())) {
.func => |f| f.owner_nav,
.@"extern" => |e| e.owner_nav,
@@ -28430,7 +27452,7 @@ fn coerceExtra(
const array_elem_ty = array_ty.childType(zcu);
if (array_ty.arrayLen(zcu) != 1) break :single_item;
const dest_is_mut = !dest_info.flags.is_const;
- switch (try sema.coerceInMemoryAllowed(block, array_elem_ty, ptr_elem_ty, dest_is_mut, target, dest_ty_src, inst_src, maybe_inst_val)) {
+ switch (try sema.coerceInMemoryAllowed(block, array_elem_ty, ptr_elem_ty, dest_is_mut, target, dest_ty_src, inst_src, null)) {
.ok => {},
else => break :single_item,
}
@@ -28448,7 +27470,7 @@ fn coerceExtra(
const dest_is_mut = !dest_info.flags.is_const;
const dst_elem_type: Type = .fromInterned(dest_info.child);
- const elem_res = try sema.coerceInMemoryAllowed(block, dst_elem_type, array_elem_type, dest_is_mut, target, dest_ty_src, inst_src, maybe_inst_val);
+ const elem_res = try sema.coerceInMemoryAllowed(block, dst_elem_type, array_elem_type, dest_is_mut, target, dest_ty_src, inst_src, null);
switch (elem_res) {
.ok => {},
else => {
@@ -28509,7 +27531,7 @@ fn coerceExtra(
const src_elem_ty = inst_ty.childType(zcu);
const dest_is_mut = !dest_info.flags.is_const;
const dst_elem_type: Type = .fromInterned(dest_info.child);
- switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, src_elem_ty, dest_is_mut, target, dest_ty_src, inst_src, maybe_inst_val)) {
+ switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, src_elem_ty, dest_is_mut, target, dest_ty_src, inst_src, null)) {
.ok => {},
else => break :src_c_ptr,
}
@@ -28520,7 +27542,7 @@ fn coerceExtra(
// but don't do it if the source type is a double pointer
if (dest_info.child == .anyopaque_type and inst_ty.zigTypeTag(zcu) == .pointer) to_anyopaque: {
if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer;
- const elem_ty = inst_ty.elemType2(zcu);
+ const elem_ty = inst_ty.childType(zcu);
if (elem_ty.zigTypeTag(zcu) == .pointer or elem_ty.isPtrLikeOptional(zcu)) {
in_memory_result = .{ .double_ptr_to_anyopaque = .{
.actual = inst_ty,
@@ -28580,7 +27602,7 @@ fn coerceExtra(
target,
dest_ty_src,
inst_src,
- maybe_inst_val,
+ null,
)) {
.ok => {},
else => break :p,
@@ -28616,16 +27638,14 @@ fn coerceExtra(
// empty tuple to zero-length slice
// note that this allows coercing to a mutable slice.
if (inst_child_ty.structFieldCount(zcu) == 0) {
- const align_val = try dest_ty.ptrAlignmentSema(pt);
- return Air.internedToRef(try pt.intern(.{ .slice = .{
- .ty = dest_ty.toIntern(),
- .ptr = try pt.intern(.{ .ptr = .{
- .ty = dest_ty.slicePtrFieldType(zcu).toIntern(),
- .base_addr = .int,
- .byte_offset = align_val.toByteUnits().?,
- } }),
- .len = .zero_usize,
- } }));
+ const empty_array_ty = try pt.arrayType(.{
+ .len = 0,
+ .child = dest_info.child,
+ .sentinel = dest_info.sentinel,
+ });
+ const empty_array_val = try pt.aggregateValue(empty_array_ty, &.{});
+ const empty_array_ptr = try sema.uavRef(empty_array_val);
+ return sema.coerceArrayPtrToSlice(block, dest_ty, empty_array_ptr, inst_src);
}
// pointer to tuple to slice
@@ -28653,7 +27673,7 @@ fn coerceExtra(
target,
dest_ty_src,
inst_src,
- maybe_inst_val,
+ null,
)) {
.ok => {},
else => break :p,
@@ -28684,12 +27704,12 @@ fn coerceExtra(
.int, .comptime_int => {
if (maybe_inst_val) |val| {
// comptime-known integer to other number
- if (!(try sema.intFitsInType(val, dest_ty, null))) {
+ if (!val.intFitsInType(dest_ty, null, zcu)) {
if (!opts.report_err) return error.NotCoercible;
return sema.fail(block, inst_src, "type '{f}' cannot represent integer value '{f}'", .{ dest_ty.fmt(pt), val.fmtValueSema(pt, sema) });
}
return switch (zcu.intern_pool.indexToKey(val.toIntern())) {
- .undef => try pt.undefRef(dest_ty),
+ .undef => .fromValue(try dest_ty.onePossibleValue(pt) orelse try pt.undefValue(dest_ty)),
.int => |int| Air.internedToRef(
try zcu.intern_pool.getCoercedInts(gpa, io, pt.tid, int, dest_ty.toIntern()),
),
@@ -28717,7 +27737,7 @@ fn coerceExtra(
},
.float, .comptime_float => switch (inst_ty.zigTypeTag(zcu)) {
.comptime_float => {
- const val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, inst, undefined);
+ const val = sema.resolveValue(inst).?;
const result_val = try val.floatCast(dest_ty, pt);
return Air.internedToRef(result_val.toIntern());
},
@@ -28768,28 +27788,26 @@ fn coerceExtra(
}
break :int;
};
- const result_val = try val.floatFromIntAdvanced(sema.arena, inst_ty, dest_ty, pt, .sema);
- const fits: bool = switch (ip.indexToKey(result_val.toIntern())) {
- else => unreachable,
- .undef => true,
- .float => |float| fits: {
- var buffer: InternPool.Key.Int.Storage.BigIntSpace = undefined;
- const operand_big_int = val.toBigInt(&buffer, zcu);
- switch (float.storage) {
- inline else => |x| {
- if (!std.math.isFinite(x)) break :fits false;
- var result_big_int: std.math.big.int.Mutable = .{
- .limbs = try sema.arena.alloc(std.math.big.Limb, std.math.big.int.calcLimbLen(x)),
- .len = undefined,
- .positive = undefined,
- };
- switch (result_big_int.setFloat(x, .nearest_even)) {
- .inexact => break :fits false,
- .exact => {},
- }
- break :fits result_big_int.toConst().eql(operand_big_int);
- },
+ if (val.isUndef(zcu)) {
+ return .fromValue(try pt.undefValue(dest_ty));
+ }
+ const result_val = try pt.floatValue(dest_ty, val.toFloat(f128, zcu));
+ const float = ip.indexToKey(result_val.toIntern()).float;
+ var buffer: InternPool.Key.Int.Storage.BigIntSpace = undefined;
+ const operand_big_int = val.toBigInt(&buffer, zcu);
+ const fits = switch (float.storage) {
+ inline else => |x| fits: {
+ if (!std.math.isFinite(x)) break :fits false;
+ var result_big_int: std.math.big.int.Mutable = .{
+ .limbs = try sema.arena.alloc(std.math.big.Limb, std.math.big.int.calcLimbLen(x)),
+ .len = undefined,
+ .positive = undefined,
+ };
+ switch (result_big_int.setFloat(x, .nearest_even)) {
+ .inexact => break :fits false,
+ .exact => {},
}
+ break :fits result_big_int.toConst().eql(operand_big_int);
},
};
if (!fits) return sema.fail(
@@ -28805,7 +27823,7 @@ fn coerceExtra(
.@"enum" => switch (inst_ty.zigTypeTag(zcu)) {
.enum_literal => {
// enum literal to enum
- const val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, inst, undefined);
+ const val = sema.resolveValue(inst).?;
const string = zcu.intern_pool.indexToKey(val.toIntern()).enum_literal;
const field_index = dest_ty.enumFieldIndex(string, zcu) orelse {
return sema.fail(block, inst_src, "no field named '{f}' in enum '{f}'", .{
@@ -28814,33 +27832,36 @@ fn coerceExtra(
};
return Air.internedToRef((try pt.enumValueFieldIndex(dest_ty, @intCast(field_index))).toIntern());
},
- .@"union" => blk: {
+ .@"union" => if (inst_ty.unionTagType(zcu)) |enum_tag_ty| {
// union to its own tag type
- const union_tag_ty = inst_ty.unionTagType(zcu) orelse break :blk;
- if (union_tag_ty.eql(dest_ty, zcu)) {
- return sema.unionToTag(block, dest_ty, inst, inst_src);
+ if (enum_tag_ty.toIntern() == dest_ty.toIntern()) {
+ return sema.unionToTag(block, inst);
}
},
else => {},
},
.error_union => switch (inst_ty.zigTypeTag(zcu)) {
- .error_set => {
- // E to E!T
- return sema.wrapErrorUnionSet(block, dest_ty, inst, inst_src);
+ // E to E!T
+ .error_set => if (sema.wrapErrorUnionSet(block, dest_ty, inst, inst_src)) |res| {
+ return res;
+ } else |err| switch (err) {
+ error.NotCoercible => if (in_memory_result == .no_match) {
+ // Try to give more useful notes
+ const err_set_type = dest_ty.errorUnionSet(zcu);
+ in_memory_result = try sema.coerceInMemoryAllowed(block, err_set_type, inst_ty, false, target, dest_ty_src, inst_src, maybe_inst_val);
+ },
+ else => |e| return e,
},
- else => eu: {
- // T to E!T
- return sema.wrapErrorUnionPayload(block, dest_ty, inst, inst_src) catch |err| switch (err) {
- error.NotCoercible => {
- if (in_memory_result == .no_match) {
- const payload_type = dest_ty.errorUnionPayload(zcu);
- // Try to give more useful notes
- in_memory_result = try sema.coerceInMemoryAllowed(block, payload_type, inst_ty, false, target, dest_ty_src, inst_src, maybe_inst_val);
- }
- break :eu;
- },
- else => |e| return e,
- };
+ // T to E!T
+ else => if (sema.wrapErrorUnionPayload(block, dest_ty, inst, inst_src)) |res| {
+ return res;
+ } else |err| switch (err) {
+ error.NotCoercible => if (in_memory_result == .no_match) {
+ // Try to give more useful notes
+ const payload_type = dest_ty.errorUnionPayload(zcu);
+ in_memory_result = try sema.coerceInMemoryAllowed(block, payload_type, inst_ty, false, target, dest_ty_src, inst_src, maybe_inst_val);
+ },
+ else => |e| return e,
},
},
.@"union" => switch (inst_ty.zigTypeTag(zcu)) {
@@ -28858,7 +27879,7 @@ fn coerceExtra(
target,
dest_ty_src,
inst_src,
- maybe_inst_val,
+ null,
)) {
break :array_to_array;
}
@@ -28900,18 +27921,16 @@ fn coerceExtra(
else => {},
}
- const can_coerce_to = switch (dest_ty.zigTypeTag(zcu)) {
- .noreturn, .@"opaque" => false,
- else => true,
+ const dest_is_npv = switch (dest_ty.classify(zcu)) {
+ .no_possible_value => true,
+ .one_possible_value => if (inst == .undef) {
+ return .fromValue((try dest_ty.onePossibleValue(pt)).?);
+ } else false,
+ .runtime, .fully_comptime, .partially_comptime => if (inst == .undef) {
+ return .fromValue(try pt.undefValue(dest_ty));
+ } else false,
};
- if (can_coerce_to) {
- // undefined to anything. We do this after the big switch above so that
- // special logic has a chance to run first, such as `*[N]T` to `[]T` which
- // should initialize the length field of the slice.
- if (maybe_inst_val) |val| if (val.toIntern() == .undef) return pt.undefRef(dest_ty);
- }
-
if (!opts.report_err) return error.NotCoercible;
if (opts.is_ret and dest_ty.zigTypeTag(zcu) == .noreturn) {
@@ -28933,13 +27952,13 @@ fn coerceExtra(
const msg = try sema.typeMismatchErrMsg(inst_src, dest_ty, inst_ty);
errdefer msg.destroy(sema.gpa);
- if (!can_coerce_to) {
- try sema.errNote(inst_src, msg, "cannot coerce to '{f}'", .{dest_ty.fmt(pt)});
+ if (dest_is_npv) {
+ try sema.errNote(inst_src, msg, "cannot coerce to uninstantiable type '{f}'", .{dest_ty.fmt(pt)});
}
// E!T to T
if (inst_ty.zigTypeTag(zcu) == .error_union and
- (try sema.coerceInMemoryAllowed(block, inst_ty.errorUnionPayload(zcu), dest_ty, false, target, dest_ty_src, inst_src, maybe_inst_val)) == .ok)
+ (try sema.coerceInMemoryAllowed(block, inst_ty.errorUnionPayload(zcu), dest_ty, false, target, dest_ty_src, inst_src, null)) == .ok)
{
try sema.errNote(inst_src, msg, "cannot convert error union to payload type", .{});
try sema.errNote(inst_src, msg, "consider using 'try', 'catch', or 'if'", .{});
@@ -28947,7 +27966,7 @@ fn coerceExtra(
// ?T to T
if (inst_ty.zigTypeTag(zcu) == .optional and
- (try sema.coerceInMemoryAllowed(block, inst_ty.optionalChild(zcu), dest_ty, false, target, dest_ty_src, inst_src, maybe_inst_val)) == .ok)
+ (try sema.coerceInMemoryAllowed(block, inst_ty.optionalChild(zcu), dest_ty, false, target, dest_ty_src, inst_src, null)) == .ok)
{
try sema.errNote(inst_src, msg, "cannot convert optional to payload type", .{});
try sema.errNote(inst_src, msg, "consider using '.?', 'orelse', or 'if'", .{});
@@ -29394,6 +28413,10 @@ pub fn coerceInMemoryAllowed(
const pt = sema.pt;
const zcu = pt.zcu;
+ if (src_val) |val| {
+ assert(val.typeOf(zcu).toIntern() == src_ty.toIntern());
+ }
+
if (dest_ty.eql(src_ty, zcu))
return .ok;
@@ -29428,7 +28451,7 @@ pub fn coerceInMemoryAllowed(
// Comptime int to regular int.
if (dest_tag == .int and src_tag == .comptime_int) {
if (src_val) |val| {
- if (!(try sema.intFitsInType(val, dest_ty, null))) {
+ if (!val.intFitsInType(dest_ty, null, zcu)) {
return .{ .comptime_int_not_coercible = .{ .wanted = dest_ty, .actual = val } };
}
}
@@ -29444,17 +28467,13 @@ pub fn coerceInMemoryAllowed(
}
// Pointers / Pointer-like Optionals
- const maybe_dest_ptr_ty = try sema.typePtrOrOptionalPtrTy(dest_ty);
- const maybe_src_ptr_ty = try sema.typePtrOrOptionalPtrTy(src_ty);
- if (maybe_dest_ptr_ty) |dest_ptr_ty| {
- if (maybe_src_ptr_ty) |src_ptr_ty| {
- return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_ptr_ty, src_ptr_ty, dest_is_mut, target, dest_src, src_src);
- }
+ if (dest_ty.isPtrAtRuntime(zcu) and src_ty.isPtrAtRuntime(zcu)) {
+ return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_is_mut, target, dest_src, src_src);
}
// Slices
if (dest_ty.isSlice(zcu) and src_ty.isSlice(zcu)) {
- return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_ty, src_ty, dest_is_mut, target, dest_src, src_src);
+ return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_is_mut, target, dest_src, src_src);
}
// Functions
@@ -29554,7 +28573,8 @@ pub fn coerceInMemoryAllowed(
// Optionals
if (dest_tag == .optional and src_tag == .optional) {
- if ((maybe_dest_ptr_ty != null) != (maybe_src_ptr_ty != null)) {
+ if (dest_ty.isPtrAtRuntime(zcu) or src_ty.isPtrAtRuntime(zcu)) {
+ // Only one is, because we already handled when both are.
return .{ .optional_shape = .{
.actual = src_ty,
.wanted = dest_ty,
@@ -29581,7 +28601,6 @@ pub fn coerceInMemoryAllowed(
const field_count = dest_ty.structFieldCount(zcu);
for (0..field_count) |field_idx| {
if (dest_ty.structFieldIsComptime(field_idx, zcu) != src_ty.structFieldIsComptime(field_idx, zcu)) break :tuple;
- if (dest_ty.fieldAlignment(field_idx, zcu) != src_ty.fieldAlignment(field_idx, zcu)) break :tuple;
const dest_field_ty = dest_ty.fieldType(field_idx, zcu);
const src_field_ty = src_ty.fieldType(field_idx, zcu);
const field = try sema.coerceInMemoryAllowed(block, dest_field_ty, src_field_ty, dest_is_mut, target, dest_src, src_src, null);
@@ -29609,89 +28628,62 @@ fn coerceInMemoryAllowedErrorSets(
const gpa = sema.gpa;
const ip = &zcu.intern_pool;
- // Coercion to `anyerror`. Note that this check can return false negatives
- // in case the error sets did not get resolved.
- if (dest_ty.isAnyError(zcu)) {
- return .ok;
- }
-
- if (dest_ty.toIntern() == .adhoc_inferred_error_set_type) {
- // We are trying to coerce an error set to the current function's
- // inferred error set.
- const dst_ies = sema.fn_ret_ty_ies.?;
- try dst_ies.addErrorSet(src_ty, ip, sema.arena);
- return .ok;
- }
-
- if (ip.isInferredErrorSetType(dest_ty.toIntern())) {
- const dst_ies_func_index = ip.iesFuncIndex(dest_ty.toIntern());
- if (sema.fn_ret_ty_ies) |dst_ies| {
- if (dst_ies.func == dst_ies_func_index) {
- // We are trying to coerce an error set to the current function's
- // inferred error set.
- try dst_ies.addErrorSet(src_ty, ip, sema.arena);
- return .ok;
- }
- }
- switch (try sema.resolveInferredErrorSet(block, dest_src, dest_ty.toIntern())) {
- // isAnyError might have changed from a false negative to a true
- // positive after resolution.
- .anyerror_type => return .ok,
- else => {},
- }
- }
-
- var missing_error_buf = std.array_list.Managed(InternPool.NullTerminatedString).init(gpa);
- defer missing_error_buf.deinit();
-
- switch (src_ty.toIntern()) {
- .anyerror_type => switch (ip.indexToKey(dest_ty.toIntern())) {
- .simple_type => unreachable, // filtered out above
- .error_set_type, .inferred_error_set_type => return .from_anyerror,
- else => unreachable,
+ const dest_set: InternPool.Key.ErrorSetType = err_set: switch (dest_ty.toIntern()) {
+ .anyerror_type => return .ok,
+ .adhoc_inferred_error_set_type => {
+ // We are trying to coerce an error set to the current function's
+ // inferred error set.
+ const dst_ies = sema.fn_ret_ty_ies.?;
+ try dst_ies.addErrorSet(src_ty, ip, sema.arena);
+ return .ok;
},
-
- else => switch (ip.indexToKey(src_ty.toIntern())) {
- .inferred_error_set_type => {
- const resolved_src_ty = try sema.resolveInferredErrorSet(block, src_src, src_ty.toIntern());
- // src anyerror status might have changed after the resolution.
- if (resolved_src_ty == .anyerror_type) {
- // dest_ty.isAnyError(zcu) == true is already checked for at this point.
- return .from_anyerror;
- }
-
- for (ip.indexToKey(resolved_src_ty).error_set_type.names.get(ip)) |key| {
- if (!Type.errorSetHasFieldIp(ip, dest_ty.toIntern(), key)) {
- try missing_error_buf.append(key);
+ else => |err_set_ty| switch (ip.indexToKey(err_set_ty)) {
+ .inferred_error_set_type => |func_index| {
+ if (sema.fn_ret_ty_ies) |dst_ies| {
+ if (dst_ies.func == func_index) {
+ // We are trying to coerce an error set to the current function's
+ // inferred error set.
+ try dst_ies.addErrorSet(src_ty, ip, sema.arena);
+ return .ok;
}
}
-
- if (missing_error_buf.items.len != 0) {
- return InMemoryCoercionResult{
- .missing_error = try sema.arena.dupe(InternPool.NullTerminatedString, missing_error_buf.items),
- };
- }
-
- return .ok;
+ try sema.ensureFuncIesResolved(block, dest_src, func_index);
+ continue :err_set ip.funcIesResolvedUnordered(func_index);
},
- .error_set_type => |error_set_type| {
- for (error_set_type.names.get(ip)) |name| {
- if (!Type.errorSetHasFieldIp(ip, dest_ty.toIntern(), name)) {
- try missing_error_buf.append(name);
- }
- }
-
- if (missing_error_buf.items.len != 0) {
- return InMemoryCoercionResult{
- .missing_error = try sema.arena.dupe(InternPool.NullTerminatedString, missing_error_buf.items),
- };
- }
-
- return .ok;
+ .error_set_type => |err_set| err_set,
+ else => unreachable,
+ },
+ };
+
+ const src_names: InternPool.NullTerminatedString.Slice = err_set: switch (src_ty.toIntern()) {
+ .anyerror_type => return .from_anyerror,
+ else => |err_set_ty| switch (ip.indexToKey(err_set_ty)) {
+ .inferred_error_set_type => |func_index| {
+ try sema.ensureFuncIesResolved(block, src_src, func_index);
+ continue :err_set ip.funcIesResolvedUnordered(func_index);
},
+ .error_set_type => |err_set| err_set.names,
else => unreachable,
},
+ };
+
+ var missing_error_buf: std.ArrayList(InternPool.NullTerminatedString) = .empty;
+ defer missing_error_buf.deinit(gpa);
+
+ for (src_names.get(ip)) |name| {
+ if (dest_set.nameIndex(ip, name) == null) {
+ try missing_error_buf.append(gpa, name);
+ }
}
+
+ if (missing_error_buf.items.len != 0) {
+ return .{ .missing_error = try sema.arena.dupe(
+ InternPool.NullTerminatedString,
+ missing_error_buf.items,
+ ) };
+ }
+
+ return .ok;
}
fn coerceInMemoryAllowedFns(
@@ -29714,11 +28706,7 @@ fn coerceInMemoryAllowedFns(
{
if (dest_info.is_var_args != src_info.is_var_args) {
- return InMemoryCoercionResult{ .fn_var_args = dest_info.is_var_args };
- }
-
- if (dest_info.is_generic != src_info.is_generic) {
- return InMemoryCoercionResult{ .fn_generic = dest_info.is_generic };
+ return .{ .fn_var_args = dest_info.is_var_args };
}
const callconv_ok = callconvCoerceAllowed(target, src_info.cc, dest_info.cc) and
@@ -29731,6 +28719,12 @@ fn coerceInMemoryAllowedFns(
} };
}
+ try sema.ensureLayoutResolved(src_ty, src_src, .coerce);
+ try sema.ensureLayoutResolved(dest_ty, dest_src, .coerce);
+ const src_is_runtime = src_ty.fnHasRuntimeBits(zcu);
+ const dest_is_runtime = dest_ty.fnHasRuntimeBits(zcu);
+ if (src_is_runtime != dest_is_runtime) return .{ .fn_generic = !dest_is_runtime };
+
if (!switch (src_info.return_type) {
.generic_poison_type => true,
.noreturn_type => !dest_is_mut,
@@ -29780,7 +28774,7 @@ fn coerceInMemoryAllowedFns(
const src_is_comptime = src_info.paramIsComptime(@intCast(param_i));
const dest_is_comptime = dest_info.paramIsComptime(@intCast(param_i));
if (src_is_comptime == dest_is_comptime) break :comptime_param;
- if (!dest_is_mut and src_is_comptime and !dest_is_comptime and try dest_param_ty.comptimeOnlySema(pt)) {
+ if (!dest_is_mut and src_is_comptime and !dest_is_comptime and dest_param_ty.comptimeOnly(zcu)) {
// A parameter which is marked `comptime` can drop that annotation if the type is comptime-only.
// The function remains generic, and the parameter is going to be comptime-resolved either way,
// so this just affects whether or not the argument is comptime-evaluated at the call site.
@@ -29861,8 +28855,6 @@ fn coerceInMemoryAllowedPtrs(
block: *Block,
dest_ty: Type,
src_ty: Type,
- dest_ptr_ty: Type,
- src_ptr_ty: Type,
/// If set, the coercion must be valid in both directions.
dest_is_mut: bool,
target: *const std.Target,
@@ -29875,8 +28867,8 @@ fn coerceInMemoryAllowedPtrs(
const gpa = comp.gpa;
const io = comp.io;
- const dest_info = dest_ptr_ty.ptrInfo(zcu);
- const src_info = src_ptr_ty.ptrInfo(zcu);
+ const dest_info = dest_ty.ptrInfo(zcu);
+ const src_info = src_ty.ptrInfo(zcu);
const ok_ptr_size = src_info.flags.size == dest_info.flags.size or
src_info.flags.size == .c or dest_info.flags.size == .c;
@@ -30008,16 +29000,14 @@ fn coerceInMemoryAllowedPtrs(
if (src_info.flags.alignment != .none or dest_info.flags.alignment != .none or
dest_info.child != src_info.child)
{
- const src_align = if (src_info.flags.alignment != .none)
- src_info.flags.alignment
- else
- try Type.fromInterned(src_info.child).abiAlignmentSema(pt);
-
- const dest_align = if (dest_info.flags.alignment != .none)
- dest_info.flags.alignment
- else
- try Type.fromInterned(dest_info.child).abiAlignmentSema(pt);
-
+ const src_align = if (src_info.flags.alignment == .none) a: {
+ try sema.ensureLayoutResolved(src_child, src_src, .align_check);
+ break :a src_child.abiAlignment(zcu);
+ } else src_info.flags.alignment;
+ const dest_align = if (dest_info.flags.alignment == .none) a: {
+ try sema.ensureLayoutResolved(dest_child, dest_src, .align_check);
+ break :a dest_child.abiAlignment(zcu);
+ } else dest_info.flags.alignment;
if (dest_align.compare(if (dest_is_mut) .neq else .gt, src_align)) {
return InMemoryCoercionResult{ .ptr_alignment = .{
.actual = src_align,
@@ -30049,7 +29039,7 @@ fn coerceVarArgParam(
.{},
),
.@"fn" => fn_ptr: {
- const fn_val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, inst, undefined);
+ const fn_val = sema.resolveValue(inst).?;
const fn_nav = zcu.funcInfo(fn_val.toIntern()).owner_nav;
break :fn_ptr try sema.analyzeNavRef(block, inst_src, fn_nav);
},
@@ -30066,7 +29056,7 @@ fn coerceVarArgParam(
}
},
else => if (uncasted_ty.isAbiInt(zcu)) int: {
- if (!try sema.validateExternType(uncasted_ty, .param_ty)) break :int inst;
+ if (!uncasted_ty.validateExtern(.param_ty, zcu)) break :int inst;
const target = zcu.getTarget();
const uncasted_info = uncasted_ty.intInfo(zcu);
if (uncasted_info.bits <= target.cTypeBitSize(switch (uncasted_info.signedness) {
@@ -30095,7 +29085,7 @@ fn coerceVarArgParam(
};
const coerced_ty = sema.typeOf(coerced);
- if (!try sema.validateExternType(coerced_ty, .param_ty)) {
+ if (!coerced_ty.validateExtern(.param_ty, zcu)) {
const msg = msg: {
const msg = try sema.errMsg(inst_src, "cannot pass '{f}' to variadic function", .{coerced_ty.fmt(pt)});
errdefer msg.destroy(sema.gpa);
@@ -30140,38 +29130,20 @@ fn storePtr2(
const elem_ty = ptr_ty.childType(zcu);
- // To generate better code for tuples, we detect a tuple operand here, and
- // analyze field loads and stores directly. This avoids an extra allocation + memcpy
- // which would occur if we used `coerce`.
- // However, we avoid this mechanism if the destination element type is a tuple,
- // because the regular store will be better for this case.
- // If the destination type is a struct we don't want this mechanism to trigger, because
- // this code does not handle tuple-to-struct coercion which requires dealing with missing
- // fields.
- const operand_ty = sema.typeOf(uncasted_operand);
- if (operand_ty.isTuple(zcu) and elem_ty.zigTypeTag(zcu) == .array) {
- const field_count = operand_ty.structFieldCount(zcu);
- var i: u32 = 0;
- while (i < field_count) : (i += 1) {
- const elem_src = operand_src; // TODO better source location
- const elem = try sema.tupleField(block, operand_src, uncasted_operand, elem_src, i);
- const elem_index = try pt.intRef(.usize, i);
- const elem_ptr = try sema.elemPtr(block, ptr_src, ptr, elem_index, elem_src, false, true);
- try sema.storePtr2(block, src, elem_ptr, elem_src, elem, elem_src, .store);
- }
- return;
- }
-
- // TODO do the same thing for anon structs as for tuples above.
- // However, beware of the need to handle missing/extra fields.
-
const is_ret = air_tag == .ret_ptr;
const operand = sema.coerceExtra(block, elem_ty, uncasted_operand, operand_src, .{ .is_ret = is_ret }) catch |err| switch (err) {
error.NotCoercible => unreachable,
else => |e| return e,
};
- const maybe_operand_val = try sema.resolveValue(operand);
+ const maybe_operand_val = sema.resolveValue(operand);
+
+ const comptime_only = switch (elem_ty.classify(zcu)) {
+ .no_possible_value => unreachable, // the coercion should have failed
+ .one_possible_value => return, // no actual store operation is necessary
+ .runtime => false,
+ .partially_comptime, .fully_comptime => true,
+ };
const runtime_src = rs: {
const ptr_val = try sema.resolveDefinedValue(block, ptr_src, ptr) orelse break :rs ptr_src;
@@ -30180,22 +29152,13 @@ fn storePtr2(
return sema.storePtrVal(block, src, ptr_val, operand_val, elem_ty);
};
- // We're performing the store at runtime; as such, we need to make sure the pointee type
- // is not comptime-only. We can hit this case with a `@ptrFromInt` pointer.
- if (try elem_ty.comptimeOnlySema(pt)) {
- return sema.failWithOwnedErrorMsg(block, msg: {
- const msg = try sema.errMsg(src, "cannot store comptime-only type '{f}' at runtime", .{elem_ty.fmt(pt)});
- errdefer msg.destroy(sema.gpa);
- try sema.errNote(ptr_src, msg, "operation is runtime due to this pointer", .{});
- break :msg msg;
- });
- }
-
- // We do this after the possible comptime store above, for the case of field_ptr stores
- // to unions because we want the comptime tag to be set, even if the field type is void.
- if ((try sema.typeHasOnePossibleValue(elem_ty)) != null) {
- return;
- }
+ // We're performing the store at runtime, so the pointee type must not be comptime-only.
+ if (comptime_only) return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(src, "cannot store comptime-only type '{f}' at runtime", .{elem_ty.fmt(pt)});
+ errdefer msg.destroy(sema.gpa);
+ try sema.errNote(ptr_src, msg, "operation is runtime due to this pointer", .{});
+ break :msg msg;
+ });
try sema.requireRuntimeBlock(block, src, runtime_src);
@@ -30223,7 +29186,7 @@ fn checkComptimeKnownStore(sema: *Sema, block: *Block, store_inst_ref: Air.Inst.
const maybe_base_alloc = sema.base_allocs.get(ptr) orelse break :known;
const maybe_comptime_alloc = sema.maybe_comptime_allocs.getPtr(maybe_base_alloc) orelse break :known;
- if ((try sema.resolveValue(operand)) != null and
+ if (sema.resolveValue(operand) != null and
block.runtime_index == maybe_comptime_alloc.runtime_index)
{
try maybe_comptime_alloc.stores.append(sema.arena, .{
@@ -30272,7 +29235,7 @@ fn checkKnownAllocPtr(sema: *Sema, block: *Block, base_ptr: Air.Inst.Ref, new_pt
// If the index value is runtime-known, this pointer is also runtime-known, so
// we must in turn make the alloc value runtime-known.
- if (null == try sema.resolveValue(index_ref)) {
+ if (null == sema.resolveValue(index_ref)) {
try sema.markMaybeComptimeAllocRuntime(block, alloc_inst);
}
},
@@ -30361,10 +29324,10 @@ fn bitCast(
) CompileError!Air.Inst.Ref {
const pt = sema.pt;
const zcu = pt.zcu;
- try dest_ty.resolveLayout(pt);
-
const old_ty = sema.typeOf(inst);
- try old_ty.resolveLayout(pt);
+
+ old_ty.assertHasLayout(zcu);
+ try sema.ensureLayoutResolved(dest_ty, inst_src, .init);
const dest_bits = dest_ty.bitSize(zcu);
const old_bits = old_ty.bitSize(zcu);
@@ -30378,7 +29341,7 @@ fn bitCast(
});
}
- if (try sema.resolveValue(inst)) |val| {
+ if (sema.resolveValue(inst)) |val| {
if (val.isUndef(zcu))
return pt.undefRef(dest_ty);
if (old_ty.zigTypeTag(zcu) == .error_set and dest_ty.zigTypeTag(zcu) == .error_set) {
@@ -30404,7 +29367,7 @@ fn coerceArrayPtrToSlice(
) CompileError!Air.Inst.Ref {
const pt = sema.pt;
const zcu = pt.zcu;
- if (try sema.resolveValue(inst)) |val| {
+ if (sema.resolveValue(inst)) |val| {
const ptr_array_ty = sema.typeOf(inst);
const array_ty = ptr_array_ty.childType(zcu);
const slice_ptr_ty = dest_ty.slicePtrFieldType(zcu);
@@ -30499,7 +29462,7 @@ fn coerceCompatiblePtrs(
const pt = sema.pt;
const zcu = pt.zcu;
const inst_ty = sema.typeOf(inst);
- if (try sema.resolveValue(inst)) |val| {
+ if (sema.resolveValue(inst)) |val| {
if (!val.isUndef(zcu) and val.isNull(zcu) and !dest_ty.isAllowzeroPtr(zcu)) {
return sema.fail(block, inst_src, "null pointer casted to type '{f}'", .{dest_ty.fmt(pt)});
}
@@ -30510,9 +29473,7 @@ fn coerceCompatiblePtrs(
}
try sema.requireRuntimeBlock(block, inst_src, null);
const inst_allows_zero = inst_ty.zigTypeTag(zcu) != .pointer or inst_ty.ptrAllowsZero(zcu);
- if (block.wantSafety() and inst_allows_zero and !dest_ty.ptrAllowsZero(zcu) and
- (try dest_ty.elemType2(zcu).hasRuntimeBitsSema(pt) or dest_ty.elemType2(zcu).zigTypeTag(zcu) == .@"fn"))
- {
+ if (block.wantSafety() and inst_allows_zero and !dest_ty.ptrAllowsZero(zcu)) {
try sema.checkLogicalPtrOperation(block, inst_src, inst_ty);
const actual_ptr = if (inst_ty.isSlice(zcu))
try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty)
@@ -30532,6 +29493,7 @@ fn coerceCompatiblePtrs(
return new_ptr;
}
+/// Asserts that the layout of `union_ty` is already resolved.
fn coerceEnumToUnion(
sema: *Sema,
block: *Block,
@@ -30545,18 +29507,21 @@ fn coerceEnumToUnion(
const ip = &zcu.intern_pool;
const inst_ty = sema.typeOf(inst);
- const tag_ty = union_ty.unionTagType(zcu) orelse {
- const msg = msg: {
- const msg = try sema.typeMismatchErrMsg(inst_src, union_ty, inst_ty);
- errdefer msg.destroy(sema.gpa);
- try sema.errNote(union_ty_src, msg, "cannot coerce enum to untagged union", .{});
- try sema.addDeclaredHereNote(msg, union_ty);
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(block, msg);
- };
+ union_ty.assertHasLayout(zcu);
- const enum_tag = try sema.coerce(block, tag_ty, inst, inst_src);
+ const union_obj = zcu.typeToUnion(union_ty).?;
+ const enum_ty: Type = .fromInterned(union_obj.enum_tag_type);
+ const enum_obj = ip.loadEnumType(enum_ty.toIntern());
+
+ if (union_obj.tag_usage != .tagged) return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.typeMismatchErrMsg(inst_src, union_ty, inst_ty);
+ errdefer msg.destroy(sema.gpa);
+ try sema.errNote(union_ty_src, msg, "cannot coerce enum to untagged union", .{});
+ try sema.addDeclaredHereNote(msg, union_ty);
+ break :msg msg;
+ });
+
+ const enum_tag = try sema.coerce(block, enum_ty, inst, inst_src);
if (try sema.resolveDefinedValue(block, inst_src, enum_tag)) |val| {
const field_index = union_ty.unionTagFieldIndex(val, pt.zcu) orelse {
return sema.fail(block, inst_src, "union '{f}' has no tag with value '{f}'", .{
@@ -30564,101 +29529,88 @@ fn coerceEnumToUnion(
});
};
- const union_obj = zcu.typeToUnion(union_ty).?;
+ const field_name = enum_obj.field_names.get(ip)[field_index];
const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);
- try field_ty.resolveFields(pt);
- if (field_ty.zigTypeTag(zcu) == .noreturn) {
- const msg = msg: {
- const msg = try sema.errMsg(inst_src, "cannot initialize 'noreturn' field of union", .{});
+ switch (field_ty.classify(zcu)) {
+ .one_possible_value => return .fromValue(try pt.unionValue(
+ union_ty,
+ val,
+ (try field_ty.onePossibleValue(pt)).?,
+ )),
+
+ .no_possible_value => return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(inst_src, "cannot initialize union field with uninstantiable type '{f}'", .{field_ty.fmt(pt)});
errdefer msg.destroy(sema.gpa);
-
- const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index];
try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' declared here", .{
field_name.fmt(ip),
});
try sema.addDeclaredHereNote(msg, union_ty);
break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(block, msg);
- }
- const opv = (try sema.typeHasOnePossibleValue(field_ty)) orelse {
- const msg = msg: {
- const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index];
+ }),
+
+ else => return sema.failWithOwnedErrorMsg(block, msg: {
const msg = try sema.errMsg(inst_src, "coercion from enum '{f}' to union '{f}' must initialize '{f}' field '{f}'", .{
inst_ty.fmt(pt), union_ty.fmt(pt),
field_ty.fmt(pt), field_name.fmt(ip),
});
errdefer msg.destroy(sema.gpa);
- try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' declared here", .{
- field_name.fmt(ip),
- });
+ try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' declared here", .{field_name.fmt(ip)});
try sema.addDeclaredHereNote(msg, union_ty);
break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(block, msg);
- };
-
- return Air.internedToRef((try pt.unionValue(union_ty, val, opv)).toIntern());
+ }),
+ }
}
try sema.requireRuntimeBlock(block, inst_src, null);
- if (tag_ty.isNonexhaustiveEnum(zcu)) {
+ if (enum_ty.isNonexhaustiveEnum(zcu)) {
const msg = msg: {
const msg = try sema.errMsg(inst_src, "runtime coercion to union '{f}' from non-exhaustive enum", .{
union_ty.fmt(pt),
});
errdefer msg.destroy(sema.gpa);
- try sema.addDeclaredHereNote(msg, tag_ty);
+ try sema.addDeclaredHereNote(msg, enum_ty);
break :msg msg;
};
return sema.failWithOwnedErrorMsg(block, msg);
}
- const union_obj = zcu.typeToUnion(union_ty).?;
- {
- var msg: ?*Zcu.ErrorMsg = null;
- errdefer if (msg) |some| some.destroy(sema.gpa);
-
- for (union_obj.field_types.get(ip), 0..) |field_ty, field_index| {
- if (Type.fromInterned(field_ty).zigTypeTag(zcu) == .noreturn) {
- const err_msg = msg orelse try sema.errMsg(
- inst_src,
- "runtime coercion from enum '{f}' to union '{f}' which has a 'noreturn' field",
- .{ tag_ty.fmt(pt), union_ty.fmt(pt) },
- );
- msg = err_msg;
-
- try sema.addFieldErrNote(union_ty, field_index, err_msg, "'noreturn' field here", .{});
- }
- }
- if (msg) |some| {
- msg = null;
- try sema.addDeclaredHereNote(some, union_ty);
- return sema.failWithOwnedErrorMsg(block, some);
+ for (union_obj.field_types.get(ip)) |field_ty_ip| {
+ if (Type.fromInterned(field_ty_ip).classify(zcu) != .one_possible_value) break;
+ } else {
+ // All fields are OPV, so the coercion is okay.
+ if (try union_ty.onePossibleValue(pt)) |opv| {
+ // The tag had redundant bits, but we've omitted the tag from the union's runtime layout, so the union is OPV and hence runtime-known.
+ return .fromValue(opv);
+ } else {
+ // The union layout is just the tag, so we can bitcast the enum straight to the union.
+ return block.addBitCast(union_ty, enum_tag);
}
}
- // If the union has all fields 0 bits, the union value is just the enum value.
- if (union_ty.unionHasAllZeroBitFieldTypes(zcu)) {
- return block.addBitCast(union_ty, enum_tag);
- }
+ // The coercion is invalid because one or more fields is not OPV.
const msg = msg: {
const msg = try sema.errMsg(
inst_src,
"runtime coercion from enum '{f}' to union '{f}' which has non-void fields",
- .{ tag_ty.fmt(pt), union_ty.fmt(pt) },
+ .{ enum_ty.fmt(pt), union_ty.fmt(pt) },
);
errdefer msg.destroy(sema.gpa);
for (0..union_obj.field_types.len) |field_index| {
- const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index];
+ const field_name = enum_obj.field_names.get(ip)[field_index];
const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);
- if (!(try field_ty.hasRuntimeBitsSema(pt))) continue;
- try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' has type '{f}'", .{
+ const ty_description: []const u8 = switch (field_ty.classify(zcu)) {
+ .one_possible_value => continue,
+ .no_possible_value => "uninstantiable type",
+ else => "type",
+ };
+ if (field_ty.classify(zcu) == .one_possible_value) continue;
+ try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' has {s} '{f}'", .{
field_name.fmt(ip),
+ ty_description,
field_ty.fmt(pt),
});
}
@@ -30685,7 +29637,7 @@ fn coerceArrayLike(
// try coercion of the whole array
const in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src, null);
if (in_memory_result == .ok) {
- if (try sema.resolveValue(inst)) |inst_val| {
+ if (sema.resolveValue(inst)) |inst_val| {
// These types share the same comptime value representation.
return sema.coerceInMemory(inst_val, dest_ty);
}
@@ -30708,7 +29660,7 @@ fn coerceArrayLike(
}
const dest_elem_ty = dest_ty.childType(zcu);
- if (dest_ty.isVector(zcu) and inst_ty.isVector(zcu) and (try sema.resolveValue(inst)) == null) {
+ if (dest_ty.isVector(zcu) and inst_ty.isVector(zcu) and sema.resolveValue(inst) == null) {
const inst_elem_ty = inst_ty.childType(zcu);
switch (dest_elem_ty.zigTypeTag(zcu)) {
.int => if (inst_elem_ty.isInt(zcu)) {
@@ -30748,7 +29700,7 @@ fn coerceArrayLike(
const coerced = try sema.coerce(block, dest_elem_ty, elem_ref, elem_src);
ref.* = coerced;
if (runtime_src == null) {
- if (try sema.resolveValue(coerced)) |elem_val| {
+ if (sema.resolveValue(coerced)) |elem_val| {
val.* = elem_val.toIntern();
} else {
runtime_src = elem_src;
@@ -30809,7 +29761,7 @@ fn coerceTupleToArray(
const coerced = try sema.coerce(block, dest_elem_ty, elem_ref, elem_src);
ref.* = coerced;
if (runtime_src == null) {
- if (try sema.resolveValue(coerced)) |elem_val| {
+ if (sema.resolveValue(coerced)) |elem_val| {
val.* = elem_val.toIntern();
} else {
runtime_src = elem_src;
@@ -30845,10 +29797,7 @@ fn coerceTupleToSlicePtrs(
.child = slice_info.child,
});
const array_inst = try sema.coerceTupleToArray(block, array_ty, slice_ty_src, tuple, tuple_src);
- if (slice_info.flags.alignment != .none) {
- return sema.fail(block, slice_ty_src, "TODO: override the alignment of the array decl we create here", .{});
- }
- const ptr_array = try sema.analyzeRef(block, slice_ty_src, array_inst);
+ const ptr_array = try sema.analyzeRef(block, slice_ty_src, array_inst, slice_info.flags.alignment);
return sema.coerceArrayPtrToSlice(block, slice_ty, ptr_array, slice_ty_src);
}
@@ -30867,10 +29816,7 @@ fn coerceTupleToArrayPtrs(
const ptr_info = ptr_array_ty.ptrInfo(zcu);
const array_ty: Type = .fromInterned(ptr_info.child);
const array_inst = try sema.coerceTupleToArray(block, array_ty, array_ty_src, tuple, tuple_src);
- if (ptr_info.flags.alignment != .none) {
- return sema.fail(block, array_ty_src, "TODO: override the alignment of the array decl we create here", .{});
- }
- const ptr_array = try sema.analyzeRef(block, array_ty_src, array_inst);
+ const ptr_array = try sema.analyzeRef(block, array_ty_src, array_inst, ptr_info.flags.alignment);
return ptr_array;
}
@@ -30904,24 +29850,21 @@ fn coerceTupleToTuple(
const field_i: u32 = @intCast(field_index_usize);
const field_src = inst_src; // TODO better source location
- const field_ty = switch (ip.indexToKey(tuple_ty.toIntern())) {
- .tuple_type => |tuple_type| tuple_type.types.get(ip)[field_index_usize],
- .struct_type => ip.loadStructType(tuple_ty.toIntern()).field_types.get(ip)[field_index_usize],
- else => unreachable,
- };
- const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) {
- .tuple_type => |tuple_type| tuple_type.values.get(ip)[field_index_usize],
- .struct_type => ip.loadStructType(tuple_ty.toIntern()).fieldInit(ip, field_index_usize),
- else => unreachable,
- };
-
const field_index: u32 = @intCast(field_index_usize);
+ const field_ty, const default_val = field: {
+ const tuple_type = ip.indexToKey(tuple_ty.toIntern()).tuple_type;
+ break :field .{
+ tuple_type.types.get(ip)[field_index],
+ tuple_type.values.get(ip)[field_index],
+ };
+ };
+
const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i);
const coerced = try sema.coerce(block, .fromInterned(field_ty), elem_ref, field_src);
field_refs[field_index] = coerced;
if (default_val != .none) {
- const init_val = (try sema.resolveValue(coerced)) orelse {
+ const init_val = sema.resolveValue(coerced) orelse {
return sema.failWithNeededComptime(block, field_src, .{ .simple = .stored_to_comptime_field });
};
@@ -30930,7 +29873,7 @@ fn coerceTupleToTuple(
}
}
if (runtime_src == null) {
- if (try sema.resolveValue(coerced)) |field_val| {
+ if (sema.resolveValue(coerced)) |field_val| {
field_vals[field_index] = field_val.toIntern();
} else {
runtime_src = field_src;
@@ -30946,11 +29889,7 @@ fn coerceTupleToTuple(
const i: u32 = @intCast(i_usize);
if (field_ref.* != .none) continue;
- const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) {
- .tuple_type => |tuple_type| tuple_type.values.get(ip)[i],
- .struct_type => ip.loadStructType(tuple_ty.toIntern()).fieldInit(ip, i),
- else => unreachable,
- };
+ const default_val = ip.indexToKey(tuple_ty.toIntern()).tuple_type.values.get(ip)[i];
const field_src = inst_src; // TODO better source location
if (default_val == .none) {
@@ -30993,7 +29932,7 @@ fn analyzeNavVal(
return sema.analyzeLoad(block, src, ref, src);
}
-fn addReferenceEntry(
+pub fn addReferenceEntry(
sema: *Sema,
opt_block: ?*Block,
src: LazySrcLoc,
@@ -31005,7 +29944,6 @@ fn addReferenceEntry(
.func => |f| assert(ip.unwrapCoercedFunc(f) == f), // for `.{ .func = f }`, `f` must be uncoerced
else => {},
}
- if (!zcu.comp.config.incremental and zcu.comp.reference_trace == 0) return;
const gop = try sema.references.getOrPut(sema.gpa, referenced_unit);
if (gop.found_existing) return;
try zcu.addUnitReference(sema.owner, referenced_unit, src, inline_frame: {
@@ -31019,13 +29957,12 @@ fn addReferenceEntry(
pub fn addTypeReferenceEntry(
sema: *Sema,
src: LazySrcLoc,
- referenced_type: InternPool.Index,
+ referenced_type: Type,
) !void {
const zcu = sema.pt.zcu;
- if (!zcu.comp.config.incremental and zcu.comp.reference_trace == 0) return;
- const gop = try sema.type_references.getOrPut(sema.gpa, referenced_type);
+ const gop = try sema.type_references.getOrPut(sema.gpa, referenced_type.toIntern());
if (gop.found_existing) return;
- try zcu.addTypeReference(sema.owner, referenced_type, src);
+ try zcu.addTypeReference(sema.owner, referenced_type.toIntern(), src);
}
fn ensureMemoizedStateResolved(sema: *Sema, src: LazySrcLoc, stage: InternPool.MemoizedStateStage) SemaError!void {
@@ -31035,10 +29972,11 @@ fn ensureMemoizedStateResolved(sema: *Sema, src: LazySrcLoc, stage: InternPool.M
try sema.addReferenceEntry(null, src, unit);
try sema.declareDependency(.{ .memoized_state = stage });
+ const reason: Zcu.DependencyReason = .{ .src = src, .type_layout_reason = undefined };
if (pt.zcu.analysis_in_progress.contains(unit)) {
- return sema.failWithOwnedErrorMsg(null, try sema.errMsg(src, "dependency loop detected", .{}));
+ return sema.failWithDependencyLoop(unit, &reason);
}
- try pt.ensureMemoizedStateUpToDate(stage);
+ try pt.ensureMemoizedStateUpToDate(stage, &reason);
}
pub fn ensureNavResolved(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index: InternPool.Nav.Index, kind: enum { type, fully }) CompileError!void {
@@ -31052,11 +29990,6 @@ pub fn ensureNavResolved(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index:
return;
}
- try sema.declareDependency(switch (kind) {
- .type => .{ .nav_ty = nav_index },
- .fully => .{ .nav_val = nav_index },
- });
-
// Note that even if `nav.status == .resolved`, we must still trigger `ensureNavValUpToDate`
// to make sure the value is up-to-date on incremental updates.
@@ -31065,32 +29998,37 @@ pub fn ensureNavResolved(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index:
.fully => .{ .nav_val = nav_index },
});
try sema.addReferenceEntry(block, src, anal_unit);
+ try sema.declareDependency(switch (kind) {
+ .type => .{ .nav_ty = nav_index },
+ .fully => .{ .nav_val = nav_index },
+ });
+
+ const reason: Zcu.DependencyReason = .{ .src = src, .type_layout_reason = undefined };
if (zcu.analysis_in_progress.contains(anal_unit)) {
- return sema.failWithOwnedErrorMsg(null, try sema.errMsg(.{
- .base_node_inst = nav.analysis.?.zir_index,
- .offset = LazySrcLoc.Offset.nodeOffset(.zero),
- }, "dependency loop detected", .{}));
+ return sema.failWithDependencyLoop(anal_unit, &reason);
}
switch (kind) {
.type => {
try zcu.ensureNavValAnalysisQueued(nav_index);
- return pt.ensureNavTypeUpToDate(nav_index);
+ return pt.ensureNavTypeUpToDate(nav_index, &reason);
},
- .fully => return pt.ensureNavValUpToDate(nav_index),
+ .fully => return pt.ensureNavValUpToDate(nav_index, &reason),
}
}
fn optRefValue(sema: *Sema, opt_val: ?Value) !Value {
const pt = sema.pt;
const ptr_anyopaque_ty = try pt.singleConstPtrType(.anyopaque);
- return Value.fromInterned(try pt.intern(.{ .opt = .{
- .ty = (try pt.optionalType(ptr_anyopaque_ty.toIntern())).toIntern(),
- .val = if (opt_val) |val| (try pt.getCoerced(
- Value.fromInterned(try pt.refValue(val.toIntern())),
- ptr_anyopaque_ty,
- )).toIntern() else .none,
+ const opt_ptr_anyopaque_ty = try pt.optionalType(ptr_anyopaque_ty.toIntern());
+ return .fromInterned(try pt.intern(.{ .opt = .{
+ .ty = opt_ptr_anyopaque_ty.toIntern(),
+ .val = payload: {
+ const val = opt_val orelse break :payload .none;
+ const ptr_val = try pt.getCoerced(try pt.uavValue(val), ptr_anyopaque_ty);
+ break :payload ptr_val.toIntern();
+ },
} }));
}
@@ -31143,7 +30081,7 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde
.type_resolved => |r| .{ r.type, r.alignment, r.@"addrspace", r.is_const },
.fully_resolved => |r| .{ ip.typeOf(r.val), r.alignment, r.@"addrspace", r.is_const },
};
- const ptr_ty = try pt.ptrTypeSema(.{
+ const ptr_ty = try pt.ptrType(.{
.child = ty,
.flags = .{
.alignment = alignment,
@@ -31185,7 +30123,7 @@ fn maybeQueueFuncBodyAnalysis(sema: *Sema, block: *Block, src: LazySrcLoc, nav_i
try sema.ensureNavResolved(block, src, nav_index, .type);
const nav_ty: Type = .fromInterned(ip.getNav(nav_index).typeOf(ip));
if (nav_ty.zigTypeTag(zcu) != .@"fn") return;
- if (!try nav_ty.fnHasRuntimeBitsSema(pt)) return;
+ if (!nav_ty.fnHasRuntimeBits(zcu)) return;
try sema.ensureNavResolved(block, src, nav_index, .fully);
const nav_val = zcu.navValue(nav_index);
@@ -31201,34 +30139,48 @@ fn analyzeRef(
block: *Block,
src: LazySrcLoc,
operand: Air.Inst.Ref,
+ alignment: Alignment,
) CompileError!Air.Inst.Ref {
const pt = sema.pt;
const zcu = pt.zcu;
const operand_ty = sema.typeOf(operand);
- if (try sema.resolveValue(operand)) |val| {
+ const address_space = target_util.defaultAddressSpace(zcu.getTarget(), .local);
+ const ptr_type = try pt.ptrType(.{
+ .child = operand_ty.toIntern(),
+ .flags = .{
+ .alignment = alignment,
+ .is_const = true,
+ .address_space = address_space,
+ },
+ });
+
+ if (sema.resolveValue(operand)) |val| {
switch (zcu.intern_pool.indexToKey(val.toIntern())) {
.@"extern" => |e| return sema.analyzeNavRef(block, src, e.owner_nav),
.func => |f| return sema.analyzeNavRef(block, src, f.owner_nav),
- else => return uavRef(sema, val.toIntern()),
+ else => return .fromIntern(try pt.intern(.{ .ptr = .{
+ .ty = ptr_type.toIntern(),
+ .base_addr = .{ .uav = .{
+ .val = val.toIntern(),
+ .orig_ty = ptr_type.toIntern(),
+ } },
+ .byte_offset = 0,
+ } })),
}
}
// No `requireRuntimeBlock`; it's okay to `ref` to a runtime value in a comptime context,
// it's just that we can only use the *type* of the result, since the value is runtime-known.
- const address_space = target_util.defaultAddressSpace(zcu.getTarget(), .local);
- const ptr_type = try pt.ptrTypeSema(.{
+ const mut_ptr_type = try pt.ptrType(.{
.child = operand_ty.toIntern(),
.flags = .{
- .is_const = true,
+ .alignment = alignment,
+ .is_const = false,
.address_space = address_space,
},
});
- const mut_ptr_type = try pt.ptrTypeSema(.{
- .child = operand_ty.toIntern(),
- .flags = .{ .address_space = address_space },
- });
const alloc = try block.addTy(.alloc, mut_ptr_type);
// In a comptime context, the store would fail, since the operand is runtime-known. But that's
@@ -31257,13 +30209,18 @@ fn analyzeLoad(
.pointer => ptr_ty.childType(zcu),
else => return sema.fail(block, ptr_src, "expected pointer, found '{f}'", .{ptr_ty.fmt(pt)}),
};
- if (elem_ty.zigTypeTag(zcu) == .@"opaque") {
- return sema.fail(block, ptr_src, "cannot load opaque type '{f}'", .{elem_ty.fmt(pt)});
- }
- if (try sema.typeHasOnePossibleValue(elem_ty)) |opv| {
- return Air.internedToRef(opv.toIntern());
- }
+ try sema.ensureLayoutResolved(elem_ty, src, .ptr_access);
+
+ const comptime_only = switch (elem_ty.classify(zcu)) {
+ .no_possible_value => switch (elem_ty.zigTypeTag(zcu)) {
+ .@"opaque" => return sema.fail(block, src, "cannot load opaque type '{f}'", .{elem_ty.fmt(pt)}),
+ else => return sema.fail(block, src, "cannot load uninstantiable type '{f}'", .{elem_ty.fmt(pt)}),
+ },
+ .one_possible_value => return .fromValue((try elem_ty.onePossibleValue(pt)).?),
+ .runtime => false,
+ .partially_comptime, .fully_comptime => true,
+ };
if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| {
if (try sema.pointerDeref(block, src, ptr_val, ptr_ty)) |elem_val| {
@@ -31271,6 +30228,13 @@ fn analyzeLoad(
}
}
+ if (comptime_only) return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(src, "cannot load comptime-only type '{f}'", .{elem_ty.fmt(pt)});
+ errdefer msg.destroy(zcu.gpa);
+ try sema.errNote(ptr_src, msg, "pointer of type '{f}' is runtime-known", .{ptr_ty.fmt(pt)});
+ break :msg msg;
+ });
+
return block.addTyOp(.load, elem_ty, ptr);
}
@@ -31284,7 +30248,7 @@ fn analyzeSlicePtr(
const pt = sema.pt;
const zcu = pt.zcu;
const result_ty = slice_ty.slicePtrFieldType(zcu);
- if (try sema.resolveValue(slice)) |val| {
+ if (sema.resolveValue(slice)) |val| {
if (val.isUndef(zcu)) return pt.undefRef(result_ty);
return Air.internedToRef(val.slicePtr(zcu).toIntern());
}
@@ -31304,7 +30268,7 @@ fn analyzeOptionalSlicePtr(
const slice_ty = opt_slice_ty.optionalChild(zcu);
const result_ty = slice_ty.slicePtrFieldType(zcu);
- if (try sema.resolveValue(opt_slice)) |opt_val| {
+ if (sema.resolveValue(opt_slice)) |opt_val| {
if (opt_val.isUndef(zcu)) return pt.undefRef(result_ty);
const slice_ptr: InternPool.Index = if (opt_val.optionalValue(zcu)) |val|
val.slicePtr(zcu).toIntern()
@@ -31328,11 +30292,11 @@ fn analyzeSliceLen(
) CompileError!Air.Inst.Ref {
const pt = sema.pt;
const zcu = pt.zcu;
- if (try sema.resolveValue(slice_inst)) |slice_val| {
+ if (sema.resolveValue(slice_inst)) |slice_val| {
if (slice_val.isUndef(zcu)) {
return .undef_usize;
}
- return pt.intRef(.usize, try slice_val.sliceLen(pt));
+ return pt.intRef(.usize, slice_val.sliceLen(zcu));
}
try sema.requireRuntimeBlock(block, src, null);
return block.addTyOp(.slice_len, .usize, slice_inst);
@@ -31341,25 +30305,25 @@ fn analyzeSliceLen(
fn analyzeIsNull(
sema: *Sema,
block: *Block,
+ src: LazySrcLoc,
operand: Air.Inst.Ref,
invert_logic: bool,
) CompileError!Air.Inst.Ref {
const pt = sema.pt;
const zcu = pt.zcu;
- const result_ty: Type = .bool;
- if (try sema.resolveValue(operand)) |opt_val| {
+
+ if (try sema.resolveIsNullFromType(block, src, sema.typeOf(operand))) |is_null| {
+ return .fromValue(.makeBool(is_null != invert_logic)); // XOR
+ }
+
+ if (sema.resolveValue(operand)) |opt_val| {
if (opt_val.isUndef(zcu)) {
- return pt.undefRef(result_ty);
+ return pt.undefRef(.bool);
}
const is_null = opt_val.isNull(zcu);
- const bool_value = if (invert_logic) !is_null else is_null;
- return if (bool_value) .bool_true else .bool_false;
+ return .fromValue(.makeBool(is_null != invert_logic)); // XOR
}
- if (sema.typeOf(operand).isNullFromType(zcu)) |is_null| {
- const result = is_null != invert_logic;
- return if (result) .bool_true else .bool_false;
- }
const air_tag: Air.Inst.Tag = if (invert_logic) .is_non_null else .is_null;
return block.addUnOp(air_tag, operand);
}
@@ -31381,7 +30345,7 @@ fn resolvePtrIsNonErrVal(
}
assert(child_ty.zigTypeTag(zcu) == .error_union);
- if (try sema.resolveValue(operand)) |eu_ptr_val| {
+ if (sema.resolveValue(operand)) |eu_ptr_val| {
if (eu_ptr_val.isUndef(zcu)) return .undef_bool;
if (try sema.pointerDeref(block, src, eu_ptr_val, ptr_ty)) |err_union| {
if (err_union.isUndef(zcu)) return .undef_bool;
@@ -31404,7 +30368,7 @@ fn resolveIsNonErrVal(
}
assert(sema.typeOf(operand).zigTypeTag(zcu) == .error_union);
- if (try sema.resolveValue(operand)) |err_union| {
+ if (sema.resolveValue(operand)) |err_union| {
if (err_union.isUndef(zcu)) return .undef_bool;
return .makeBool(err_union.getErrorName(zcu) == .none);
}
@@ -31412,6 +30376,35 @@ fn resolveIsNonErrVal(
return null;
}
+fn resolveIsNullFromType(
+ sema: *Sema,
+ block: *Block,
+ src: LazySrcLoc,
+ ty: Type,
+) CompileError!?bool {
+ const zcu = sema.pt.zcu;
+ return switch (ty.zigTypeTag(zcu)) {
+ else => false,
+ .null => true,
+ .pointer => switch (ty.ptrSize(zcu)) {
+ .c => null,
+ else => false,
+ },
+ .optional => {
+ const payload_ty = ty.optionalChild(zcu);
+ if (payload_ty.classify(zcu) == .no_possible_value) {
+ return true; // e.g. `?noreturn`
+ }
+ if (payload_ty.zigTypeTag(zcu) == .error_set and
+ try sema.resolveErrSetIsEmpty(block, src, payload_ty))
+ {
+ return true; // e.g. `?error{}`
+ }
+ return null;
+ },
+ };
+}
+
fn resolveIsNonErrFromType(
sema: *Sema,
block: *Block,
@@ -31420,89 +30413,71 @@ fn resolveIsNonErrFromType(
) CompileError!?Value {
const pt = sema.pt;
const zcu = pt.zcu;
- const ip = &zcu.intern_pool;
const ot = operand_ty.zigTypeTag(zcu);
if (ot != .error_set and ot != .error_union) return .true;
if (ot == .error_set) return .false;
assert(ot == .error_union);
const payload_ty = operand_ty.errorUnionPayload(zcu);
- if (payload_ty.zigTypeTag(zcu) == .noreturn) {
+ if (payload_ty.classify(zcu) == .no_possible_value) {
return .false;
}
+ if (try sema.resolveErrSetIsEmpty(block, src, operand_ty.errorUnionSet(zcu))) {
+ return .true;
+ }
+ return null;
+}
- // exception if the error union error set is known to be empty,
- // we allow the comparison but always make it comptime-known.
- const set_ty = ip.errorUnionSet(operand_ty.toIntern());
- switch (set_ty) {
- .anyerror_type => {},
- .adhoc_inferred_error_set_type => if (sema.fn_ret_ty_ies) |ies| blk: {
- // If the error set is empty, we must return a comptime true or false.
- // However we want to avoid unnecessarily resolving an inferred error set
- // in case it is already non-empty.
- switch (ies.resolved) {
- .anyerror_type => break :blk,
- .none => {},
- else => |i| if (ip.indexToKey(i).error_set_type.names.len != 0) break :blk,
- }
-
- if (ies.errors.count() != 0) return null;
- switch (ies.resolved) {
- .anyerror_type => return null,
- .none => {},
- else => switch (ip.indexToKey(ies.resolved).error_set_type.names.len) {
- 0 => return .true,
- else => return null,
- },
- }
- // We do not have a comptime answer because this inferred error
- // set is not resolved, and an instruction later in this function
- // body may or may not cause an error to be added to this set.
- return null;
+/// Returns `true` iff the error set type `orig_err_set_ty` contains no errors.
+///
+/// This is used to give comptime answers for whether `error{}!T` is an error or a payload, as well
+/// as whether `?error{}` is null. The type `error{}` cannot be NPV, as it has runtime bits, but the
+/// only value of that type which can exist is `undefined`; semantically it has no "legal" value.
+/// TODO: this runs into some unsolved language design questions about such types. Performing a
+/// coercion from `@as(E, undefined)` to `E!T` needs to semantically result in an `undefined` error
+/// union if our implementation is to be legal, and likewise for coercing `@as(E, undefined)` to
+/// `?E` (for an error set `E`) because our implementation uses the zero error value at runtime to
+/// represent `null`. The unsolved problem is the exact rules for `undefined` propagation through
+/// these types: for instance, what if `@as(u32, undfined)` is coerced to `?u32`? What about error
+/// union *payloads*, i.e. `@as(u32, undefined)` to `E!u32`? That one is analagous to the optional
+/// example in some ways, but right now I believe there is code which relies on that coercion giving
+/// a well-defined error union with an `undefined` payload.
+/// Relevant issues/discussions:
+/// * https://github.com/ziglang/zig/issues/1831
+/// * https://github.com/ziglang/zig/issues/6762
+/// * https://github.com/ziglang/zig/issues/1831#issuecomment-722129239
+fn resolveErrSetIsEmpty(
+ sema: *Sema,
+ block: *Block,
+ src: LazySrcLoc,
+ orig_err_set_ty: Type,
+) CompileError!bool {
+ const ip = &sema.pt.zcu.intern_pool;
+ err_set: switch (orig_err_set_ty.toIntern()) {
+ .anyerror_type => return false,
+ .adhoc_inferred_error_set_type => {
+ // This is *our* error set; that is, we're currently analyzing the function
+ // which owns it. Trying to resolve it now would cause a dependency loop.
+ // Instead, accept that we don't know.
+ return false;
},
- else => switch (ip.indexToKey(set_ty)) {
- .error_set_type => |error_set_type| {
- if (error_set_type.names.len == 0) return .true;
- },
- .inferred_error_set_type => |func_index| blk: {
- // If the error set is empty, we must return a comptime true or false.
- // However we want to avoid unnecessarily resolving an inferred error set
- // in case it is already non-empty.
- try zcu.maybeUnresolveIes(func_index);
- switch (ip.funcIesResolvedUnordered(func_index)) {
- .anyerror_type => break :blk,
- .none => {},
- else => |i| if (ip.indexToKey(i).error_set_type.names.len != 0) break :blk,
- }
+ else => |err_set_ty| switch (ip.indexToKey(err_set_ty)) {
+ .error_set_type => |es| return es.names.len == 0,
+ .inferred_error_set_type => |func_index| {
if (sema.fn_ret_ty_ies) |ies| {
if (ies.func == func_index) {
- // Try to avoid resolving inferred error set if possible.
- if (ies.errors.count() != 0) return null;
- switch (ies.resolved) {
- .anyerror_type => return null,
- .none => {},
- else => switch (ip.indexToKey(ies.resolved).error_set_type.names.len) {
- 0 => return .true,
- else => return null,
- },
- }
- // We do not have a comptime answer because this inferred error
- // set is not resolved, and an instruction later in this function
- // body may or may not cause an error to be added to this set.
- return null;
+ // This is *our* error set; that is, we're currently analyzing the function
+ // which owns it. Trying to resolve it now would cause a dependency loop.
+ // Instead, accept that we don't know.
+ return false;
}
}
- const resolved_ty = try sema.resolveInferredErrorSet(block, src, set_ty);
- if (resolved_ty == .anyerror_type)
- break :blk;
- if (ip.indexToKey(resolved_ty).error_set_type.names.len == 0)
- return .true;
+ try sema.ensureFuncIesResolved(block, src, func_index);
+ continue :err_set ip.funcIesResolvedUnordered(func_index);
},
else => unreachable,
},
}
-
- return null;
}
fn analyzeIsNonErr(
@@ -31682,6 +30657,8 @@ fn analyzeSlice(
else => return sema.fail(block, src, "slice of non-array type '{f}'", .{ptr_ptr_child_ty.fmt(pt)}),
}
+ try sema.ensureLayoutResolved(elem_ty, src, .ptr_access);
+
const ptr = if (slice_ty.isSlice(zcu))
try sema.analyzeSlicePtr(block, ptr_src, ptr_or_slice, slice_ty)
else if (array_ty.zigTypeTag(zcu) == .array) ptr: {
@@ -31690,11 +30667,11 @@ fn analyzeSlice(
assert(manyptr_ty_key.flags.size == .one);
manyptr_ty_key.child = elem_ty.toIntern();
manyptr_ty_key.flags.size = .many;
- break :ptr try sema.coerceCompatiblePtrs(block, try pt.ptrTypeSema(manyptr_ty_key), ptr_or_slice, ptr_src);
+ break :ptr try sema.coerceCompatiblePtrs(block, try pt.ptrType(manyptr_ty_key), ptr_or_slice, ptr_src);
} else ptr_or_slice;
const start = try sema.coerce(block, .usize, uncasted_start, start_src);
- const new_ptr = try sema.analyzePtrArithmetic(block, src, ptr, start, .ptr_add, ptr_src, start_src);
+ const new_ptr = try sema.analyzePtrArithmetic(block, src, ptr, start, .ptr_add, start_src);
const new_ptr_ty = sema.typeOf(new_ptr);
// true if and only if the end index of the slice, implicitly or explicitly, equals
@@ -31754,12 +30731,12 @@ fn analyzeSlice(
break :end try sema.coerce(block, .usize, uncasted_end, end_src);
} else try sema.coerce(block, .usize, uncasted_end_opt, end_src);
if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| {
- if (try sema.resolveValue(ptr_or_slice)) |slice_val| {
+ if (sema.resolveValue(ptr_or_slice)) |slice_val| {
if (slice_val.isUndef(zcu)) {
return sema.fail(block, src, "slice of undefined", .{});
}
const has_sentinel = slice_ty.sentinel(zcu) != null;
- const slice_len = try slice_val.sliceLen(pt);
+ const slice_len = slice_val.sliceLen(zcu);
const len_plus_sent = slice_len + @intFromBool(has_sentinel);
const slice_len_val_with_sentinel = try pt.intValue(.usize, len_plus_sent);
if (!(try sema.compareAll(end_val, .lte, slice_len_val_with_sentinel, .usize))) {
@@ -31774,7 +30751,7 @@ fn analyzeSlice(
"end index {f} out of bounds for slice of length {d}{s}",
.{
end_val.fmtValueSema(pt, sema),
- try slice_val.sliceLen(pt),
+ slice_val.sliceLen(zcu),
sentinel_label,
},
);
@@ -31832,7 +30809,7 @@ fn analyzeSlice(
break :msg msg;
});
}
- return sema.analyzePtrArithmetic(block, src, ptr, start, .ptr_add, ptr_src, start_src);
+ return sema.analyzePtrArithmetic(block, src, ptr, start, .ptr_add, start_src);
};
const sentinel = s: {
@@ -31876,7 +30853,7 @@ fn analyzeSlice(
);
}
checked_start_lte_end = true;
- if (try sema.resolveValue(new_ptr)) |ptr_val| sentinel_check: {
+ if (sema.resolveValue(new_ptr)) |ptr_val| sentinel_check: {
const expected_sentinel = sentinel orelse break :sentinel_check;
const start_int = start_val.toUnsignedInt(zcu);
const end_int = end_val.toUnsignedInt(zcu);
@@ -31943,9 +30920,9 @@ fn analyzeSlice(
const new_allowzero = new_ptr_ty_info.flags.is_allowzero and sema.typeOf(ptr).ptrSize(zcu) != .c;
if (opt_new_len_val) |new_len_val| {
- const new_len_int = try new_len_val.toUnsignedIntSema(pt);
+ const new_len_int = new_len_val.toUnsignedInt(zcu);
- const return_ty = try pt.ptrTypeSema(.{
+ const return_ty = try pt.ptrType(.{
.child = (try pt.arrayType(.{
.len = new_len_int,
.sentinel = if (sentinel) |s| s.toIntern() else .none,
@@ -31960,13 +30937,13 @@ fn analyzeSlice(
},
});
- const opt_new_ptr_val = try sema.resolveValue(new_ptr);
+ const opt_new_ptr_val = sema.resolveValue(new_ptr);
const new_ptr_val = opt_new_ptr_val orelse {
const result = try block.addBitCast(return_ty, new_ptr);
if (block.wantSafety()) {
// requirement: slicing C ptr is non-null
if (ptr_ptr_child_ty.isCPtr(zcu)) {
- const is_non_null = try sema.analyzeIsNull(block, ptr, true);
+ const is_non_null = try block.addUnOp(.is_non_null, ptr);
try sema.addSafetyCheck(block, src, is_non_null, .unwrap_null);
}
@@ -32009,7 +30986,7 @@ fn analyzeSlice(
return sema.fail(block, src, "non-zero length slice of undefined pointer", .{});
}
- const return_ty = try pt.ptrTypeSema(.{
+ const return_ty = try pt.ptrType(.{
.child = elem_ty.toIntern(),
.sentinel = if (sentinel) |s| s.toIntern() else .none,
.flags = .{
@@ -32026,7 +31003,7 @@ fn analyzeSlice(
if (block.wantSafety()) {
// requirement: slicing C ptr is non-null
if (ptr_ptr_child_ty.isCPtr(zcu)) {
- const is_non_null = try sema.analyzeIsNull(block, ptr, true);
+ const is_non_null = try block.addUnOp(.is_non_null, ptr);
try sema.addSafetyCheck(block, src, is_non_null, .unwrap_null);
}
@@ -32037,7 +31014,7 @@ fn analyzeSlice(
if (try sema.resolveDefinedValue(block, src, ptr_or_slice)) |slice_val| {
// we don't need to add one for sentinels because the
// underlying value data includes the sentinel
- break :blk try pt.intRef(.usize, try slice_val.sliceLen(pt));
+ break :blk try pt.intRef(.usize, slice_val.sliceLen(zcu));
}
const slice_len_inst = try block.addTyOp(.slice_len, .usize, ptr_or_slice);
@@ -32107,8 +31084,8 @@ fn cmpNumeric(
else
uncasted_rhs;
- const maybe_lhs_val = try sema.resolveValue(lhs);
- const maybe_rhs_val = try sema.resolveValue(rhs);
+ const maybe_lhs_val = sema.resolveValue(lhs);
+ const maybe_rhs_val = sema.resolveValue(rhs);
// If the LHS is const, check if there is a guaranteed result which does not depend on ths RHS value.
if (maybe_lhs_val) |lhs_val| {
@@ -32158,16 +31135,10 @@ fn cmpNumeric(
const runtime_src: LazySrcLoc = if (maybe_lhs_val) |lhs_val| rs: {
if (maybe_rhs_val) |rhs_val| {
- const res = try Value.compareHeteroSema(lhs_val, op, rhs_val, pt);
- return if (res) .bool_true else .bool_false;
+ return .fromValue(.makeBool(Value.compareHetero(lhs_val, op, rhs_val, zcu)));
} else break :rs rhs_src;
} else lhs_src;
- // TODO handle comparisons against lazy zero values
- // Some values can be compared against zero without being runtime-known or without forcing
- // a full resolution of their value, for example `@sizeOf(@Frame(function))` is known to
- // always be nonzero, and we benefit from not forcing the full evaluation and stack frame layout
- // of this function if we don't need to.
try sema.requireRuntimeBlock(block, src, runtime_src);
// For floats, emit a float comparison instruction.
@@ -32207,11 +31178,11 @@ fn cmpNumeric(
// a signed integer with mantissa bits + 1, and if there was any non-integral part of the float,
// add/subtract 1.
const lhs_is_signed = if (maybe_lhs_val) |lhs_val|
- !(try lhs_val.compareAllWithZeroSema(.gte, pt))
+ !lhs_val.compareAllWithZero(.gte, zcu)
else
(lhs_ty.isRuntimeFloat() or lhs_ty.isSignedInt(zcu));
const rhs_is_signed = if (maybe_rhs_val) |rhs_val|
- !(try rhs_val.compareAllWithZeroSema(.gte, pt))
+ !rhs_val.compareAllWithZero(.gte, zcu)
else
(rhs_ty.isRuntimeFloat() or rhs_ty.isSignedInt(zcu));
const dest_int_is_signed = lhs_is_signed or rhs_is_signed;
@@ -32219,10 +31190,9 @@ fn cmpNumeric(
var dest_float_type: ?Type = null;
var lhs_bits: usize = undefined;
- if (maybe_lhs_val) |unresolved_lhs_val| {
- const lhs_val = try sema.resolveLazyValue(unresolved_lhs_val);
+ if (maybe_lhs_val) |lhs_val| {
if (!rhs_is_signed) {
- switch (lhs_val.orderAgainstZero(zcu)) {
+ switch (Value.order(lhs_val, .zero_comptime_int, zcu)) {
.gt => {},
.eq => switch (op) { // LHS = 0, RHS is unsigned
.lte => return .bool_true,
@@ -32263,10 +31233,9 @@ fn cmpNumeric(
}
var rhs_bits: usize = undefined;
- if (maybe_rhs_val) |unresolved_rhs_val| {
- const rhs_val = try sema.resolveLazyValue(unresolved_rhs_val);
+ if (maybe_rhs_val) |rhs_val| {
if (!lhs_is_signed) {
- switch (rhs_val.orderAgainstZero(zcu)) {
+ switch (Value.order(rhs_val, .zero_comptime_int, zcu)) {
.gt => {},
.eq => switch (op) { // RHS = 0, LHS is unsigned
.gte => return .bool_true,
@@ -32328,7 +31297,7 @@ fn compareIntsOnlyPossibleResult(
lhs_val: Value,
op: std.math.CompareOperator,
rhs_ty: Type,
-) SemaError!?bool {
+) Allocator.Error!?bool {
const pt = sema.pt;
const zcu = pt.zcu;
@@ -32337,11 +31306,11 @@ fn compareIntsOnlyPossibleResult(
if (min_rhs.toIntern() == max_rhs.toIntern()) {
// RHS is effectively comptime-known.
- return try Value.compareHeteroSema(lhs_val, op, min_rhs, pt);
+ return Value.compareHetero(lhs_val, op, min_rhs, zcu);
}
- const against_min = try lhs_val.orderAdvanced(min_rhs, .sema, zcu, pt.tid);
- const against_max = try lhs_val.orderAdvanced(max_rhs, .sema, zcu, pt.tid);
+ const against_min = lhs_val.order(min_rhs, zcu);
+ const against_max = lhs_val.order(max_rhs, zcu);
switch (op) {
.eq => {
@@ -32401,8 +31370,8 @@ fn cmpVector(
.child = .bool_type,
});
- const maybe_lhs_val = try sema.resolveValue(casted_lhs);
- const maybe_rhs_val = try sema.resolveValue(casted_rhs);
+ const maybe_lhs_val = sema.resolveValue(casted_lhs);
+ const maybe_rhs_val = sema.resolveValue(casted_rhs);
if (maybe_lhs_val) |v| if (v.isUndef(zcu)) return pt.undefRef(result_ty);
if (maybe_rhs_val) |v| if (v.isUndef(zcu)) return pt.undefRef(result_ty);
@@ -32424,7 +31393,7 @@ fn wrapOptional(
inst: Air.Inst.Ref,
inst_src: LazySrcLoc,
) !Air.Inst.Ref {
- if (try sema.resolveValue(inst)) |val| {
+ if (sema.resolveValue(inst)) |val| {
return Air.internedToRef((try sema.pt.intern(.{ .opt = .{
.ty = dest_ty.toIntern(),
.val = val.toIntern(),
@@ -32446,7 +31415,7 @@ fn wrapErrorUnionPayload(
const zcu = pt.zcu;
const dest_payload_ty = dest_ty.errorUnionPayload(zcu);
const coerced = try sema.coerceExtra(block, dest_payload_ty, inst, inst_src, .{ .report_err = false });
- if (try sema.resolveValue(coerced)) |val| {
+ if (sema.resolveValue(coerced)) |val| {
return Air.internedToRef((try pt.intern(.{ .error_union = .{
.ty = dest_ty.toIntern(),
.val = .{ .payload = val.toIntern() },
@@ -32466,80 +31435,40 @@ fn wrapErrorUnionSet(
const pt = sema.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
- const inst_ty = sema.typeOf(inst);
const dest_err_set_ty = dest_ty.errorUnionSet(zcu);
- if (try sema.resolveValue(inst)) |val| {
- const expected_name = zcu.intern_pool.indexToKey(val.toIntern()).err.name;
- switch (dest_err_set_ty.toIntern()) {
- .anyerror_type => {},
- .adhoc_inferred_error_set_type => ok: {
- const ies = sema.fn_ret_ty_ies.?;
- switch (ies.resolved) {
- .anyerror_type => break :ok,
- .none => if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, dest_err_set_ty, inst_ty, inst_src, inst_src)) {
- break :ok;
- },
- else => |i| if (ip.indexToKey(i).error_set_type.nameIndex(ip, expected_name) != null) {
- break :ok;
- },
- }
- return sema.failWithTypeMismatch(block, inst_src, dest_err_set_ty, inst_ty);
- },
- else => switch (ip.indexToKey(dest_err_set_ty.toIntern())) {
- .error_set_type => |error_set_type| ok: {
- if (error_set_type.nameIndex(ip, expected_name) != null) break :ok;
- return sema.failWithTypeMismatch(block, inst_src, dest_err_set_ty, inst_ty);
- },
- .inferred_error_set_type => |func_index| ok: {
- // We carefully do this in an order that avoids unnecessarily
- // resolving the destination error set type.
- try zcu.maybeUnresolveIes(func_index);
- switch (ip.funcIesResolvedUnordered(func_index)) {
- .anyerror_type => break :ok,
- .none => if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, dest_err_set_ty, inst_ty, inst_src, inst_src)) {
- break :ok;
- },
- else => |i| if (ip.indexToKey(i).error_set_type.nameIndex(ip, expected_name) != null) {
- break :ok;
- },
- }
-
- return sema.failWithTypeMismatch(block, inst_src, dest_err_set_ty, inst_ty);
- },
- else => unreachable,
- },
- }
- return Air.internedToRef((try pt.intern(.{ .error_union = .{
+ const coerced = try sema.coerceExtra(block, dest_err_set_ty, inst, inst_src, .{ .report_err = false });
+ if (try sema.resolveDefinedValue(block, inst_src, coerced)) |error_val| {
+ return .fromIntern(try pt.intern(.{ .error_union = .{
.ty = dest_ty.toIntern(),
- .val = .{ .err_name = expected_name },
- } })));
+ .val = .{ .err_name = ip.indexToKey(error_val.toIntern()).err.name },
+ } }));
+ } else {
+ return block.addTyOp(.wrap_errunion_err, dest_ty, coerced);
}
-
- try sema.requireRuntimeBlock(block, inst_src, null);
- const coerced = try sema.coerce(block, dest_err_set_ty, inst, inst_src);
- return block.addTyOp(.wrap_errunion_err, dest_ty, coerced);
}
-fn unionToTag(
- sema: *Sema,
- block: *Block,
- enum_ty: Type,
- un: Air.Inst.Ref,
- un_src: LazySrcLoc,
-) !Air.Inst.Ref {
+/// Returns the enum tag value for the active tag of a tagged union value.
+///
+/// Asserts that the type of `un` is a tagged union type.
+fn unionToTag(sema: *Sema, block: *Block, un: Air.Inst.Ref) !Air.Inst.Ref {
const pt = sema.pt;
const zcu = pt.zcu;
- if ((try sema.typeHasOnePossibleValue(enum_ty))) |opv| {
- return Air.internedToRef(opv.toIntern());
+ const ip = &zcu.intern_pool;
+ const union_obj = ip.loadUnionType(sema.typeOf(un).toIntern());
+ assert(union_obj.tag_usage == .tagged);
+ if (sema.resolveValue(un)) |un_val| {
+ return .fromValue(un_val.unionTag(zcu).?);
}
- if (try sema.resolveValue(un)) |un_val| {
- const tag_val = un_val.unionTag(zcu).?;
- if (tag_val.isUndef(zcu))
- return try pt.undefRef(enum_ty);
- return Air.internedToRef(tag_val.toIntern());
+ const enum_tag_ty: Type = .fromInterned(union_obj.enum_tag_type);
+ if (!union_obj.has_runtime_tag) {
+ // This means that only one field is possible.
+ const field_index = for (union_obj.field_types.get(ip), 0..) |field_ty_ip, field_index| {
+ const field_ty: Type = .fromInterned(field_ty_ip);
+ if (field_ty.classify(zcu) != .no_possible_value) break field_index;
+ } else unreachable;
+ return .fromValue(try pt.enumValueFieldIndex(enum_tag_ty, @intCast(field_index)));
}
- try sema.requireRuntimeBlock(block, un_src, null);
- return block.addTyOp(.get_union_tag, enum_ty, un);
+ return block.addTyOp(.get_union_tag, enum_tag_ty, un);
}
const PeerResolveStrategy = enum {
@@ -32879,7 +31808,7 @@ fn resolvePeerTypes(
for (instructions, peer_tys, peer_vals) |inst, *ty, *val| {
ty.* = sema.typeOf(inst);
- val.* = try sema.resolveValue(inst);
+ val.* = sema.resolveValue(inst);
}
switch (try sema.resolvePeerTypesInner(block, src, peer_tys, peer_vals)) {
@@ -33240,18 +32169,24 @@ fn resolvePeerTypesInner(
ptr_info.sentinel = .none;
}
- // Note that the align can be always non-zero; Zcu.ptrType will canonicalize it
- ptr_info.flags.alignment = InternPool.Alignment.min(
- if (ptr_info.flags.alignment != .none)
- ptr_info.flags.alignment
- else
- Type.fromInterned(ptr_info.child).abiAlignment(zcu),
-
- if (peer_info.flags.alignment != .none)
- peer_info.flags.alignment
- else
- Type.fromInterned(peer_info.child).abiAlignment(zcu),
- );
+ ptr_info.flags.alignment = a: {
+ // If both alignments are implicit, the result alignment is implicit.
+ // e.g. '[*c]u32' + '[*c]c_uint' -> '[*c]u32'
+ if (ptr_info.flags.alignment == .none and peer_info.flags.alignment == .none) {
+ break :a .none;
+ }
+ // Otherwise (if either alignment is explicit), the result alignment is explicit.
+ // e.g. '[*c]u32' + '[*c]align(4) c_uint' -> '[*c]align(4) u32'
+ const cur_align = switch (ptr_info.flags.alignment) {
+ .none => Type.fromInterned(ptr_info.child).abiAlignment(zcu),
+ else => ptr_info.flags.alignment,
+ };
+ const new_align = switch (peer_info.flags.alignment) {
+ .none => Type.fromInterned(peer_info.child).abiAlignment(zcu),
+ else => peer_info.flags.alignment,
+ };
+ break :a .minStrict(cur_align, new_align);
+ };
if (ptr_info.flags.address_space != peer_info.flags.address_space) {
return .{ .conflict = .{
.peer_idx_a = first_idx,
@@ -33273,7 +32208,7 @@ fn resolvePeerTypesInner(
opt_ptr_info = ptr_info;
}
- return .{ .success = try pt.ptrTypeSema(opt_ptr_info.?) };
+ return .{ .success = try pt.ptrType(opt_ptr_info.?) };
},
.ptr => {
@@ -33281,7 +32216,6 @@ fn resolvePeerTypesInner(
// if there were no actual slices. Else, we want the slice index to report a conflict.
var opt_slice_idx: ?usize = null;
- var any_abi_aligned = false;
var opt_ptr_info: ?InternPool.Key.PtrType = null;
var first_idx: usize = undefined;
var other_idx: usize = undefined; // We sometimes need a second peer index to report a generic error
@@ -33325,15 +32259,24 @@ fn resolvePeerTypesInner(
.peer_idx_b = i,
} };
- // Note that the align can be always non-zero; Type.ptr will canonicalize it
- if (peer_info.flags.alignment == .none) {
- any_abi_aligned = true;
- } else if (ptr_info.flags.alignment == .none) {
- any_abi_aligned = true;
- ptr_info.flags.alignment = peer_info.flags.alignment;
- } else {
- ptr_info.flags.alignment = ptr_info.flags.alignment.minStrict(peer_info.flags.alignment);
- }
+ ptr_info.flags.alignment = a: {
+ // If both alignments are implicit, the result alignment is implicit.
+ // e.g. '*u32' + '*c_uint' -> '*u32'
+ if (ptr_info.flags.alignment == .none and peer_info.flags.alignment == .none) {
+ break :a .none;
+ }
+ // Otherwise (if either alignment is explicit), the result alignment is explicit.
+ // e.g. '*u32' + '*align(4) c_uint' -> '*align(4) u32'
+ const cur_align = switch (ptr_info.flags.alignment) {
+ .none => Type.fromInterned(ptr_info.child).abiAlignment(zcu),
+ else => ptr_info.flags.alignment,
+ };
+ const new_align = switch (peer_info.flags.alignment) {
+ .none => Type.fromInterned(peer_info.child).abiAlignment(zcu),
+ else => peer_info.flags.alignment,
+ };
+ break :a .minStrict(cur_align, new_align);
+ };
if (ptr_info.flags.address_space != peer_info.flags.address_space) {
return generic_err;
@@ -33582,13 +32525,7 @@ fn resolvePeerTypesInner(
},
}
- if (any_abi_aligned and opt_ptr_info.?.flags.alignment != .none) {
- opt_ptr_info.?.flags.alignment = opt_ptr_info.?.flags.alignment.minStrict(
- try Type.fromInterned(pointee).abiAlignmentSema(pt),
- );
- }
-
- return .{ .success = try pt.ptrTypeSema(opt_ptr_info.?) };
+ return .{ .success = try pt.ptrType(opt_ptr_info.?) };
},
.func => {
@@ -33731,7 +32668,7 @@ fn resolvePeerTypesInner(
.peer_idx_b = i,
} };
any_comptime_known = true;
- ptr_opt_val.* = try sema.resolveLazyValue(opt_val.?);
+ ptr_opt_val.* = opt_val.?;
continue;
},
.int => {},
@@ -33924,7 +32861,6 @@ fn resolvePeerTypesInner(
var comptime_val: ?Value = null;
for (peer_tys) |opt_ty| {
const struct_ty = opt_ty orelse continue;
- try struct_ty.resolveStructFieldInits(pt);
const uncoerced_field_val = try struct_ty.structFieldValueComptime(pt, field_index) orelse {
comptime_val = null;
@@ -33939,7 +32875,7 @@ fn resolvePeerTypesInner(
},
else => |e| return e,
};
- const coerced_val = (try sema.resolveValue(coerced_inst)) orelse continue;
+ const coerced_val = sema.resolveValue(coerced_inst) orelse continue;
const existing = comptime_val orelse {
comptime_val = coerced_val;
continue;
@@ -34025,12 +32961,12 @@ fn typeIsArrayLike(sema: *Sema, ty: Type) ?ArrayLike {
.elem_ty = ty.childType(zcu),
},
.@"struct" => {
+ if (!ty.isTuple(zcu)) return null;
const field_count = ty.structFieldCount(zcu);
if (field_count == 0) return .{
.len = 0,
.elem_ty = .noreturn,
};
- if (!ty.isTuple(zcu)) return null;
const elem_ty = ty.fieldType(0, zcu);
for (1..field_count) |i| {
if (!ty.fieldType(i, zcu).eql(elem_ty, zcu)) {
@@ -34046,356 +32982,6 @@ fn typeIsArrayLike(sema: *Sema, ty: Type) ?ArrayLike {
};
}
-pub fn resolveIes(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError!void {
- const pt = sema.pt;
- const zcu = pt.zcu;
- const ip = &zcu.intern_pool;
-
- if (sema.fn_ret_ty_ies) |ies| {
- try sema.resolveInferredErrorSetPtr(block, src, ies);
- assert(ies.resolved != .none);
- ip.funcIesResolved(sema.func_index).* = ies.resolved;
- }
-}
-
-pub fn resolveFnTypes(sema: *Sema, fn_ty: Type, src: LazySrcLoc) CompileError!void {
- const pt = sema.pt;
- const zcu = pt.zcu;
- const ip = &zcu.intern_pool;
- const fn_ty_info = zcu.typeToFunc(fn_ty).?;
-
- try Type.fromInterned(fn_ty_info.return_type).resolveFully(pt);
-
- if (zcu.comp.config.any_error_tracing and
- Type.fromInterned(fn_ty_info.return_type).isError(zcu))
- {
- // Ensure the type exists so that backends can assume that.
- _ = try sema.getBuiltinType(src, .StackTrace);
- }
-
- for (0..fn_ty_info.param_types.len) |i| {
- try Type.fromInterned(fn_ty_info.param_types.get(ip)[i]).resolveFully(pt);
- }
-}
-
-fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {
- return val.resolveLazy(sema.arena, sema.pt);
-}
-
-/// Resolve a struct's alignment only without triggering resolution of its layout.
-/// Asserts that the alignment is not yet resolved and the layout is non-packed.
-pub fn resolveStructAlignment(
- sema: *Sema,
- ty: InternPool.Index,
- struct_type: InternPool.LoadedStructType,
-) SemaError!void {
- const pt = sema.pt;
- const zcu = pt.zcu;
- const io = zcu.comp.io;
- const ip = &zcu.intern_pool;
- const target = zcu.getTarget();
-
- assert(sema.owner.unwrap().type == ty);
-
- assert(struct_type.layout != .@"packed");
- assert(struct_type.flagsUnordered(ip).alignment == .none);
-
- const ptr_align = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));
-
- // We'll guess "pointer-aligned", if the struct has an
- // underaligned pointer field then some allocations
- // might require explicit alignment.
- if (struct_type.assumePointerAlignedIfFieldTypesWip(ip, io, ptr_align)) return;
-
- try sema.resolveStructFieldTypes(ty, struct_type);
-
- // We'll guess "pointer-aligned", if the struct has an
- // underaligned pointer field then some allocations
- // might require explicit alignment.
- if (struct_type.assumePointerAlignedIfWip(ip, io, ptr_align)) return;
- defer struct_type.clearAlignmentWip(ip, io);
-
- // No `zcu.trackUnitSema` calls, since this phase isn't really doing any semantic analysis.
- // It's just triggering *other* analysis, alongside a simple loop over already-resolved info.
-
- var alignment: Alignment = .@"1";
-
- for (0..struct_type.field_types.len) |i| {
- const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[i]);
- if (struct_type.fieldIsComptime(ip, i) or try field_ty.comptimeOnlySema(pt))
- continue;
- const field_align = try field_ty.structFieldAlignmentSema(
- struct_type.fieldAlign(ip, i),
- struct_type.layout,
- pt,
- );
- alignment = alignment.maxStrict(field_align);
- }
-
- struct_type.setAlignment(ip, io, alignment);
-}
-
-pub fn resolveStructLayout(sema: *Sema, ty: Type) SemaError!void {
- const pt = sema.pt;
- const zcu = pt.zcu;
- const ip = &zcu.intern_pool;
- const io = zcu.comp.io;
- const struct_type = zcu.typeToStruct(ty) orelse return;
-
- assert(sema.owner.unwrap().type == ty.toIntern());
-
- if (struct_type.haveLayout(ip))
- return;
-
- try sema.resolveStructFieldTypes(ty.toIntern(), struct_type);
-
- // No `zcu.trackUnitSema` calls, since this phase isn't really doing any semantic analysis.
- // It's just triggering *other* analysis, alongside a simple loop over already-resolved info.
-
- if (struct_type.layout == .@"packed") {
- sema.backingIntType(struct_type) catch |err| switch (err) {
- error.AnalysisFail, error.OutOfMemory, error.Canceled => |e| return e,
- error.ComptimeBreak, error.ComptimeReturn => unreachable,
- };
- return;
- }
-
- if (struct_type.setLayoutWip(ip, io)) {
- const msg = try sema.errMsg(
- ty.srcLoc(zcu),
- "struct '{f}' depends on itself",
- .{ty.fmt(pt)},
- );
- return sema.failWithOwnedErrorMsg(null, msg);
- }
- defer struct_type.clearLayoutWip(ip, io);
-
- const aligns = try sema.arena.alloc(Alignment, struct_type.field_types.len);
- const sizes = try sema.arena.alloc(u64, struct_type.field_types.len);
-
- var big_align: Alignment = .@"1";
-
- for (aligns, sizes, 0..) |*field_align, *field_size, i| {
- const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[i]);
- if (struct_type.fieldIsComptime(ip, i) or try field_ty.comptimeOnlySema(pt)) {
- struct_type.offsets.get(ip)[i] = 0;
- field_size.* = 0;
- field_align.* = .none;
- continue;
- }
-
- field_size.* = field_ty.abiSizeSema(pt) catch |err| switch (err) {
- error.AnalysisFail => {
- const msg = sema.err orelse return err;
- try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{});
- return err;
- },
- else => return err,
- };
- field_align.* = try field_ty.structFieldAlignmentSema(
- struct_type.fieldAlign(ip, i),
- struct_type.layout,
- pt,
- );
- big_align = big_align.maxStrict(field_align.*);
- }
-
- if (struct_type.flagsUnordered(ip).assumed_runtime_bits and !(try ty.hasRuntimeBitsSema(pt))) {
- const msg = try sema.errMsg(
- ty.srcLoc(zcu),
- "struct layout depends on it having runtime bits",
- .{},
- );
- return sema.failWithOwnedErrorMsg(null, msg);
- }
-
- if (struct_type.flagsUnordered(ip).assumed_pointer_aligned and
- big_align.compareStrict(.neq, Alignment.fromByteUnits(@divExact(zcu.getTarget().ptrBitWidth(), 8))))
- {
- const msg = try sema.errMsg(
- ty.srcLoc(zcu),
- "struct layout depends on being pointer aligned",
- .{},
- );
- return sema.failWithOwnedErrorMsg(null, msg);
- }
-
- if (struct_type.hasReorderedFields()) {
- const runtime_order = struct_type.runtime_order.get(ip);
-
- for (runtime_order, 0..) |*ro, i| {
- const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[i]);
- if (struct_type.fieldIsComptime(ip, i) or try field_ty.comptimeOnlySema(pt)) {
- ro.* = .omitted;
- } else {
- ro.* = @enumFromInt(i);
- }
- }
-
- const RuntimeOrder = InternPool.LoadedStructType.RuntimeOrder;
-
- const AlignSortContext = struct {
- aligns: []const Alignment,
-
- fn lessThan(ctx: @This(), a: RuntimeOrder, b: RuntimeOrder) bool {
- if (a == .omitted) return false;
- if (b == .omitted) return true;
- const a_align = ctx.aligns[@intFromEnum(a)];
- const b_align = ctx.aligns[@intFromEnum(b)];
- return a_align.compare(.gt, b_align);
- }
- };
- if (!zcu.backendSupportsFeature(.field_reordering)) {
- // TODO: we should probably also reorder tuple fields? This is a bit weird because it'll involve
- // mutating the `InternPool` for a non-container type.
- //
- // TODO: implement field reordering support in all the backends!
- //
- // This logic does not reorder fields; it only moves the omitted ones to the end
- // so that logic elsewhere does not need to special-case here.
- var i: usize = 0;
- var off: usize = 0;
- while (i + off < runtime_order.len) {
- if (runtime_order[i + off] == .omitted) {
- off += 1;
- continue;
- }
- runtime_order[i] = runtime_order[i + off];
- i += 1;
- }
- @memset(runtime_order[i..], .omitted);
- } else {
- mem.sortUnstable(RuntimeOrder, runtime_order, AlignSortContext{
- .aligns = aligns,
- }, AlignSortContext.lessThan);
- }
- }
-
- // Calculate size, alignment, and field offsets.
- const offsets = struct_type.offsets.get(ip);
- var it = struct_type.iterateRuntimeOrder(ip);
- var offset: u64 = 0;
- while (it.next()) |i| {
- offsets[i] = @intCast(aligns[i].forward(offset));
- offset = offsets[i] + sizes[i];
- }
- const size = std.math.cast(u32, big_align.forward(offset)) orelse {
- const msg = try sema.errMsg(
- ty.srcLoc(zcu),
- "struct layout requires size {d}, this compiler implementation supports up to {d}",
- .{ big_align.forward(offset), std.math.maxInt(u32) },
- );
- return sema.failWithOwnedErrorMsg(null, msg);
- };
- struct_type.setLayoutResolved(ip, io, size, big_align);
- _ = try ty.comptimeOnlySema(pt);
-}
-
-fn backingIntType(
- sema: *Sema,
- struct_type: InternPool.LoadedStructType,
-) CompileError!void {
- const pt = sema.pt;
- const zcu = pt.zcu;
- const comp = zcu.comp;
- const gpa = comp.gpa;
- const io = comp.io;
- const ip = &zcu.intern_pool;
-
- var analysis_arena = std.heap.ArenaAllocator.init(gpa);
- defer analysis_arena.deinit();
-
- var block: Block = .{
- .parent = null,
- .sema = sema,
- .namespace = struct_type.namespace,
- .instructions = .{},
- .inlining = null,
- .comptime_reason = null, // set below if needed
- .src_base_inst = struct_type.zir_index,
- .type_name_ctx = struct_type.name,
- };
- defer assert(block.instructions.items.len == 0);
-
- const fields_bit_sum = blk: {
- var accumulator: u64 = 0;
- for (0..struct_type.field_types.len) |i| {
- const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[i]);
- accumulator += try field_ty.bitSizeSema(pt);
- }
- break :blk accumulator;
- };
-
- const zir = zcu.namespacePtr(struct_type.namespace).fileScope(zcu).zir.?;
- const zir_index = struct_type.zir_index.resolve(ip) orelse return error.AnalysisFail;
- const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;
- assert(extended.opcode == .struct_decl);
- const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
-
- if (small.has_backing_int) {
- var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).@"struct".fields.len;
- const captures_len = if (small.has_captures_len) blk: {
- const captures_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk captures_len;
- } else 0;
- extra_index += @intFromBool(small.has_fields_len);
- extra_index += @intFromBool(small.has_decls_len);
-
- extra_index += captures_len * 2;
-
- const backing_int_body_len = zir.extra[extra_index];
- extra_index += 1;
-
- const backing_int_src: LazySrcLoc = .{
- .base_node_inst = struct_type.zir_index,
- .offset = .{ .node_offset_container_tag = .zero },
- };
- block.comptime_reason = .{ .reason = .{
- .src = backing_int_src,
- .r = .{ .simple = .type },
- } };
- const backing_int_ty = blk: {
- if (backing_int_body_len == 0) {
- const backing_int_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]);
- break :blk try sema.resolveType(&block, backing_int_src, backing_int_ref);
- } else {
- const body = zir.bodySlice(extra_index, backing_int_body_len);
- const ty_ref = try sema.resolveInlineBody(&block, body, zir_index);
- break :blk try sema.analyzeAsType(&block, backing_int_src, ty_ref);
- }
- };
-
- try sema.checkBackingIntType(&block, backing_int_src, backing_int_ty, fields_bit_sum);
- struct_type.setBackingIntType(ip, io, backing_int_ty.toIntern());
- } else {
- if (fields_bit_sum > std.math.maxInt(u16)) {
- return sema.fail(&block, block.nodeOffset(.zero), "size of packed struct '{d}' exceeds maximum bit width of 65535", .{fields_bit_sum});
- }
- const backing_int_ty = try pt.intType(.unsigned, @intCast(fields_bit_sum));
- struct_type.setBackingIntType(ip, io, backing_int_ty.toIntern());
- }
-
- try sema.flushExports();
-}
-
-fn checkBackingIntType(sema: *Sema, block: *Block, src: LazySrcLoc, backing_int_ty: Type, fields_bit_sum: u64) CompileError!void {
- const pt = sema.pt;
- const zcu = pt.zcu;
-
- if (!backing_int_ty.isInt(zcu)) {
- return sema.fail(block, src, "expected backing integer type, found '{f}'", .{backing_int_ty.fmt(pt)});
- }
- if (backing_int_ty.bitSize(zcu) != fields_bit_sum) {
- return sema.fail(
- block,
- src,
- "backing integer type '{f}' has bit size {d} but the struct fields have a total bit size of {d}",
- .{ backing_int_ty.fmt(pt), backing_int_ty.bitSize(zcu), fields_bit_sum },
- );
- }
-}
-
fn checkIndexable(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void {
const pt = sema.pt;
if (!ty.isIndexable(pt.zcu)) {
@@ -34432,414 +33018,33 @@ fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void
return sema.failWithOwnedErrorMsg(block, msg);
}
-/// Resolve a unions's alignment only without triggering resolution of its layout.
-/// Asserts that the alignment is not yet resolved.
-pub fn resolveUnionAlignment(
- sema: *Sema,
- ty: Type,
- union_type: InternPool.LoadedUnionType,
-) SemaError!void {
- const pt = sema.pt;
- const zcu = pt.zcu;
- const io = zcu.comp.io;
- const ip = &zcu.intern_pool;
- const target = zcu.getTarget();
-
- assert(sema.owner.unwrap().type == ty.toIntern());
-
- assert(!union_type.haveLayout(ip));
-
- const ptr_align = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));
-
- // We'll guess "pointer-aligned", if the union has an
- // underaligned pointer field then some allocations
- // might require explicit alignment.
- if (union_type.assumePointerAlignedIfFieldTypesWip(ip, io, ptr_align)) return;
-
- try sema.resolveUnionFieldTypes(ty, union_type);
-
- // No `zcu.trackUnitSema` calls, since this phase isn't really doing any semantic analysis.
- // It's just triggering *other* analysis, alongside a simple loop over already-resolved info.
-
- var max_align: Alignment = .@"1";
- for (0..union_type.field_types.len) |field_index| {
- const field_ty: Type = .fromInterned(union_type.field_types.get(ip)[field_index]);
- if (!(try field_ty.hasRuntimeBitsSema(pt))) continue;
-
- const explicit_align = union_type.fieldAlign(ip, field_index);
- const field_align = if (explicit_align != .none)
- explicit_align
- else
- try field_ty.abiAlignmentSema(sema.pt);
-
- max_align = max_align.max(field_align);
- }
-
- union_type.setAlignment(ip, io, max_align);
-}
-
-/// This logic must be kept in sync with `Type.getUnionLayout`.
-pub fn resolveUnionLayout(sema: *Sema, ty: Type) SemaError!void {
- const pt = sema.pt;
- const io = pt.zcu.comp.io;
- const ip = &pt.zcu.intern_pool;
-
- try sema.resolveUnionFieldTypes(ty, ip.loadUnionType(ty.ip_index));
-
- // Load again, since the tag type might have changed due to resolution.
- const union_type = ip.loadUnionType(ty.ip_index);
-
- assert(sema.owner.unwrap().type == ty.toIntern());
-
- const old_flags = union_type.flagsUnordered(ip);
- switch (old_flags.status) {
- .none, .have_field_types => {},
- .field_types_wip, .layout_wip => {
- const msg = try sema.errMsg(
- ty.srcLoc(pt.zcu),
- "union '{f}' depends on itself",
- .{ty.fmt(pt)},
- );
- return sema.failWithOwnedErrorMsg(null, msg);
- },
- .have_layout, .fully_resolved_wip, .fully_resolved => return,
- }
-
- errdefer union_type.setStatusIfLayoutWip(ip, io, old_flags.status);
-
- union_type.setStatus(ip, io, .layout_wip);
-
- // No `zcu.trackUnitSema` calls, since this phase isn't really doing any semantic analysis.
- // It's just triggering *other* analysis, alongside a simple loop over already-resolved info.
-
- var max_size: u64 = 0;
- var max_align: Alignment = .@"1";
- for (0..union_type.field_types.len) |field_index| {
- const field_ty: Type = .fromInterned(union_type.field_types.get(ip)[field_index]);
- if (field_ty.isNoReturn(pt.zcu)) continue;
-
- // We need to call `hasRuntimeBits` before calling `abiSize` to prevent reachable `unreachable`s,
- // but `hasRuntimeBits` only resolves field types and so may infinite recurse on a layout wip type,
- // so we must resolve the layout manually first, instead of waiting for `abiSize` to do it for us.
- // This is arguably just hacking around bugs in both `abiSize` for not allowing arbitrary types to
- // be queried, enabling failures to be handled with the emission of a compile error, and also in
- // `hasRuntimeBits` for ever being able to infinite recurse in the first place.
- try field_ty.resolveLayout(pt);
-
- if (try field_ty.hasRuntimeBitsSema(pt)) {
- max_size = @max(max_size, field_ty.abiSizeSema(pt) catch |err| switch (err) {
- error.AnalysisFail => {
- const msg = sema.err orelse return err;
- try sema.addFieldErrNote(ty, field_index, msg, "while checking this field", .{});
- return err;
- },
- else => return err,
- });
- }
-
- const explicit_align = union_type.fieldAlign(ip, field_index);
- const field_align = if (explicit_align != .none)
- explicit_align
- else
- try field_ty.abiAlignmentSema(pt);
- max_align = max_align.max(field_align);
- }
-
- const has_runtime_tag = union_type.flagsUnordered(ip).runtime_tag.hasTag() and
- try Type.fromInterned(union_type.enum_tag_ty).hasRuntimeBitsSema(pt);
- const size, const alignment, const padding = if (has_runtime_tag) layout: {
- const enum_tag_type: Type = .fromInterned(union_type.enum_tag_ty);
- const tag_align = try enum_tag_type.abiAlignmentSema(pt);
- const tag_size = try enum_tag_type.abiSizeSema(pt);
-
- // Put the tag before or after the payload depending on which one's
- // alignment is greater.
- var size: u64 = 0;
- var padding: u32 = 0;
- if (tag_align.order(max_align).compare(.gte)) {
- // {Tag, Payload}
- size += tag_size;
- size = max_align.forward(size);
- size += max_size;
- const prev_size = size;
- size = tag_align.forward(size);
- padding = @intCast(size - prev_size);
- } else {
- // {Payload, Tag}
- size += max_size;
- size = switch (pt.zcu.getTarget().ofmt) {
- .c => max_align,
- else => tag_align,
- }.forward(size);
- size += tag_size;
- const prev_size = size;
- size = max_align.forward(size);
- padding = @intCast(size - prev_size);
- }
-
- break :layout .{ size, max_align.max(tag_align), padding };
- } else .{ max_align.forward(max_size), max_align, 0 };
-
- const casted_size = std.math.cast(u32, size) orelse {
- const msg = try sema.errMsg(
- ty.srcLoc(pt.zcu),
- "union layout requires size {d}, this compiler implementation supports up to {d}",
- .{ size, std.math.maxInt(u32) },
- );
- return sema.failWithOwnedErrorMsg(null, msg);
- };
- union_type.setHaveLayout(ip, io, casted_size, padding, alignment);
-
- if (union_type.flagsUnordered(ip).assumed_runtime_bits and !(try ty.hasRuntimeBitsSema(pt))) {
- const msg = try sema.errMsg(
- ty.srcLoc(pt.zcu),
- "union layout depends on it having runtime bits",
- .{},
- );
- return sema.failWithOwnedErrorMsg(null, msg);
- }
-
- if (union_type.flagsUnordered(ip).assumed_pointer_aligned and
- alignment.compareStrict(.neq, Alignment.fromByteUnits(@divExact(pt.zcu.getTarget().ptrBitWidth(), 8))))
- {
- const msg = try sema.errMsg(
- ty.srcLoc(pt.zcu),
- "union layout depends on being pointer aligned",
- .{},
- );
- return sema.failWithOwnedErrorMsg(null, msg);
- }
- _ = try ty.comptimeOnlySema(pt);
-}
-
-/// Returns `error.AnalysisFail` if any of the types (recursively) failed to
-/// be resolved.
-pub fn resolveStructFully(sema: *Sema, ty: Type) SemaError!void {
- try sema.resolveStructLayout(ty);
- try sema.resolveStructFieldInits(ty);
-
- const pt = sema.pt;
- const zcu = pt.zcu;
- const io = zcu.comp.io;
- const ip = &zcu.intern_pool;
- const struct_type = zcu.typeToStruct(ty).?;
-
- assert(sema.owner.unwrap().type == ty.toIntern());
-
- if (struct_type.setFullyResolved(ip, io)) return;
- errdefer struct_type.clearFullyResolved(ip, io);
-
- // No `zcu.trackUnitSema` calls, since this phase isn't really doing any semantic analysis.
- // It's just triggering *other* analysis, alongside a simple loop over already-resolved info.
-
- // After we have resolve struct layout we have to go over the fields again to
- // make sure pointer fields get their child types resolved as well.
- // See also similar code for unions.
-
- for (0..struct_type.field_types.len) |i| {
- const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[i]);
- try field_ty.resolveFully(pt);
- }
-}
-
-pub fn resolveUnionFully(sema: *Sema, ty: Type) SemaError!void {
- try sema.resolveUnionLayout(ty);
-
- const pt = sema.pt;
- const zcu = pt.zcu;
- const io = zcu.comp.io;
- const ip = &zcu.intern_pool;
- const union_obj = zcu.typeToUnion(ty).?;
-
- assert(sema.owner.unwrap().type == ty.toIntern());
-
- switch (union_obj.flagsUnordered(ip).status) {
- .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {},
- .fully_resolved_wip, .fully_resolved => return,
- }
-
- // No `zcu.trackUnitSema` calls, since this phase isn't really doing any semantic analysis.
- // It's just triggering *other* analysis, alongside a simple loop over already-resolved info.
-
- {
- // After we have resolve union layout we have to go over the fields again to
- // make sure pointer fields get their child types resolved as well.
- // See also similar code for structs.
- const prev_status = union_obj.flagsUnordered(ip).status;
- errdefer union_obj.setStatus(ip, io, prev_status);
-
- union_obj.setStatus(ip, io, .fully_resolved_wip);
- for (0..union_obj.field_types.len) |field_index| {
- const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);
- try field_ty.resolveFully(pt);
- }
- union_obj.setStatus(ip, io, .fully_resolved);
- }
-
- // And let's not forget comptime-only status.
- _ = try ty.comptimeOnlySema(pt);
-}
-
-pub fn resolveStructFieldTypes(
- sema: *Sema,
- ty: InternPool.Index,
- struct_type: InternPool.LoadedStructType,
-) SemaError!void {
- const pt = sema.pt;
- const zcu = pt.zcu;
- const io = zcu.comp.io;
- const ip = &zcu.intern_pool;
-
- assert(sema.owner.unwrap().type == ty);
-
- if (struct_type.haveFieldTypes(ip)) return;
-
- if (struct_type.setFieldTypesWip(ip, io)) {
- const msg = try sema.errMsg(
- Type.fromInterned(ty).srcLoc(zcu),
- "struct '{f}' depends on itself",
- .{Type.fromInterned(ty).fmt(pt)},
- );
- return sema.failWithOwnedErrorMsg(null, msg);
- }
- defer struct_type.clearFieldTypesWip(ip, io);
-
- // can't happen earlier than this because we only want the progress node if not already resolved
- const tracked_unit = zcu.trackUnitSema(struct_type.name.toSlice(ip), null);
- defer tracked_unit.end(zcu);
-
- sema.structFields(struct_type) catch |err| switch (err) {
- error.AnalysisFail, error.OutOfMemory, error.Canceled => |e| return e,
- error.ComptimeBreak, error.ComptimeReturn => unreachable,
- };
-}
-
-pub fn resolveStructFieldInits(sema: *Sema, ty: Type) SemaError!void {
- const pt = sema.pt;
- const zcu = pt.zcu;
- const io = zcu.comp.io;
- const ip = &zcu.intern_pool;
- const struct_type = zcu.typeToStruct(ty) orelse return;
-
- assert(sema.owner.unwrap().type == ty.toIntern());
-
- // Inits can start as resolved
- if (struct_type.haveFieldInits(ip)) return;
-
- try sema.resolveStructLayout(ty);
-
- if (struct_type.setInitsWip(ip, io)) {
- const msg = try sema.errMsg(
- ty.srcLoc(zcu),
- "struct '{f}' depends on itself",
- .{ty.fmt(pt)},
- );
- return sema.failWithOwnedErrorMsg(null, msg);
- }
- defer struct_type.clearInitsWip(ip, io);
-
- // can't happen earlier than this because we only want the progress node if not already resolved
- const tracked_unit = zcu.trackUnitSema(struct_type.name.toSlice(ip), null);
- defer tracked_unit.end(zcu);
-
- sema.structFieldInits(struct_type) catch |err| switch (err) {
- error.AnalysisFail, error.OutOfMemory, error.Canceled => |e| return e,
- error.ComptimeBreak, error.ComptimeReturn => unreachable,
- };
- struct_type.setHaveFieldInits(ip, io);
-}
-
-pub fn resolveUnionFieldTypes(sema: *Sema, ty: Type, union_type: InternPool.LoadedUnionType) SemaError!void {
- const pt = sema.pt;
- const zcu = pt.zcu;
- const io = zcu.comp.io;
- const ip = &zcu.intern_pool;
-
- assert(sema.owner.unwrap().type == ty.toIntern());
-
- switch (union_type.flagsUnordered(ip).status) {
- .none => {},
- .field_types_wip => {
- const msg = try sema.errMsg(ty.srcLoc(zcu), "union '{f}' depends on itself", .{ty.fmt(pt)});
- return sema.failWithOwnedErrorMsg(null, msg);
- },
- .have_field_types,
- .have_layout,
- .layout_wip,
- .fully_resolved_wip,
- .fully_resolved,
- => return,
- }
-
- // can't happen earlier than this because we only want the progress node if not already resolved
- const tracked_unit = zcu.trackUnitSema(union_type.name.toSlice(ip), null);
- defer tracked_unit.end(zcu);
-
- union_type.setStatus(ip, io, .field_types_wip);
- errdefer union_type.setStatus(ip, io, .none);
- sema.unionFields(ty.toIntern(), union_type) catch |err| switch (err) {
- error.AnalysisFail, error.OutOfMemory, error.Canceled => |e| return e,
- error.ComptimeBreak, error.ComptimeReturn => unreachable,
- };
- union_type.setStatus(ip, io, .have_field_types);
-}
-
-/// Returns a normal error set corresponding to the fully populated inferred
-/// error set.
-fn resolveInferredErrorSet(
+/// Resolves the inferred error set of the given function, so that the corresponding concrete error
+/// set is available by calling `InternPool.funcIesResolvedUnordered` on `func_index`.
+///
+/// Asserts that `func_index` is a function. Also asserts that it is not a coerced function, because
+/// coerced functions do not own inferred error sets.
+fn ensureFuncIesResolved(
sema: *Sema,
block: *Block,
src: LazySrcLoc,
- ies_index: InternPool.Index,
-) CompileError!InternPool.Index {
+ func_index: InternPool.Index,
+) CompileError!void {
const pt = sema.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
- const func_index = ip.iesFuncIndex(ies_index);
- const func = zcu.funcInfo(func_index);
- try sema.declareDependency(.{ .interned = func_index }); // resolved IES
+ assert(ip.unwrapCoercedFunc(func_index) == func_index);
- try zcu.maybeUnresolveIes(func_index);
- const resolved_ty = func.resolvedErrorSetUnordered(ip);
- if (resolved_ty != .none) return resolved_ty;
+ try sema.declareDependency(.{ .func_ies = func_index });
+ try sema.addReferenceEntry(block, src, .wrap(.{ .func = func_index }));
+
+ const reason: Zcu.DependencyReason = .{ .src = src, .type_layout_reason = undefined };
if (zcu.analysis_in_progress.contains(.wrap(.{ .func = func_index }))) {
- return sema.fail(block, src, "unable to resolve inferred error set", .{});
+ return sema.failWithDependencyLoop(.wrap(.{ .func = func_index }), &reason);
}
- // In order to ensure that all dependencies are properly added to the set,
- // we need to ensure the function body is analyzed of the inferred error
- // set. However, in the case of comptime/inline function calls with
- // inferred error sets, each call gets an adhoc InferredErrorSet object, which
- // has no corresponding function body.
- const ies_func_info = zcu.typeToFunc(.fromInterned(func.ty)).?;
- // if ies declared by a inline function with generic return type, the return_type should be generic_poison,
- // because inline function does not create a new declaration, and the ies has been filled with analyzeCall,
- // so here we can simply skip this case.
- if (ies_func_info.return_type == .generic_poison_type) {
- assert(ies_func_info.cc == .@"inline");
- } else if (ip.errorUnionSet(ies_func_info.return_type) == ies_index) {
- if (ies_func_info.is_generic) {
- return sema.failWithOwnedErrorMsg(block, msg: {
- const msg = try sema.errMsg(src, "unable to resolve inferred error set of generic function", .{});
- errdefer msg.destroy(sema.gpa);
- try sema.errNote(zcu.navSrcLoc(func.owner_nav), msg, "generic function declared here", .{});
- break :msg msg;
- });
- }
- // In this case we are dealing with the actual InferredErrorSet object that
- // corresponds to the function, not one created to track an inline/comptime call.
- const orig_func_index = ip.unwrapCoercedFunc(func_index);
- try sema.addReferenceEntry(block, src, .wrap(.{ .func = orig_func_index }));
- try pt.ensureFuncBodyUpToDate(orig_func_index);
- }
-
- // This will now have been resolved by the logic at the end of `Zcu.analyzeFnBody`
- // which calls `resolveInferredErrorSetPtr`.
- const final_resolved_ty = func.resolvedErrorSetUnordered(ip);
- assert(final_resolved_ty != .none);
- return final_resolved_ty;
+ try pt.ensureFuncBodyUpToDate(func_index, &reason);
}
pub fn resolveInferredErrorSetPtr(
@@ -34857,7 +33062,9 @@ pub fn resolveInferredErrorSetPtr(
for (ies.inferred_error_sets.keys()) |other_ies_index| {
if (ies_index == other_ies_index) continue;
- switch (try sema.resolveInferredErrorSet(block, src, other_ies_index)) {
+ const other_func_index = ip.iesFuncIndex(other_ies_index);
+ try sema.ensureFuncIesResolved(block, src, other_func_index);
+ switch (ip.funcIesResolvedUnordered(other_func_index)) {
.anyerror_type => {
ies.resolved = .anyerror_type;
return;
@@ -34930,1253 +33137,14 @@ fn resolveInferredErrorSetTy(
if (ty == .anyerror_type) return ty;
switch (ip.indexToKey(ty)) {
.error_set_type => return ty,
- .inferred_error_set_type => return sema.resolveInferredErrorSet(block, src, ty),
+ .inferred_error_set_type => |func_index| {
+ try sema.ensureFuncIesResolved(block, src, func_index);
+ return ip.funcIesResolvedUnordered(func_index);
+ },
else => unreachable,
}
}
-fn structZirInfo(zir: Zir, zir_index: Zir.Inst.Index) struct {
- /// fields_len
- usize,
- Zir.Inst.StructDecl.Small,
- /// extra_index
- usize,
-} {
- const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;
- assert(extended.opcode == .struct_decl);
- const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
- var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).@"struct".fields.len;
-
- const captures_len = if (small.has_captures_len) blk: {
- const captures_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk captures_len;
- } else 0;
-
- const fields_len = if (small.has_fields_len) blk: {
- const fields_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk fields_len;
- } else 0;
-
- const decls_len = if (small.has_decls_len) decls_len: {
- const decls_len = zir.extra[extra_index];
- extra_index += 1;
- break :decls_len decls_len;
- } else 0;
-
- extra_index += captures_len * 2;
-
- // The backing integer cannot be handled until `resolveStructLayout()`.
- if (small.has_backing_int) {
- const backing_int_body_len = zir.extra[extra_index];
- extra_index += 1; // backing_int_body_len
- if (backing_int_body_len == 0) {
- extra_index += 1; // backing_int_ref
- } else {
- extra_index += backing_int_body_len; // backing_int_body_inst
- }
- }
-
- // Skip over decls.
- extra_index += decls_len;
-
- return .{ fields_len, small, extra_index };
-}
-
-fn structFields(
- sema: *Sema,
- struct_type: InternPool.LoadedStructType,
-) CompileError!void {
- const pt = sema.pt;
- const zcu = pt.zcu;
- const comp = zcu.comp;
- const gpa = comp.gpa;
- const io = comp.io;
- const ip = &zcu.intern_pool;
-
- const namespace_index = struct_type.namespace;
- const zir = zcu.namespacePtr(namespace_index).fileScope(zcu).zir.?;
- const zir_index = struct_type.zir_index.resolve(ip) orelse return error.AnalysisFail;
-
- const fields_len, _, var extra_index = structZirInfo(zir, zir_index);
-
- if (fields_len == 0) switch (struct_type.layout) {
- .@"packed" => {
- try sema.backingIntType(struct_type);
- return;
- },
- .auto, .@"extern" => {
- struct_type.setLayoutResolved(ip, io, 0, .none);
- return;
- },
- };
-
- var block_scope: Block = .{
- .parent = null,
- .sema = sema,
- .namespace = namespace_index,
- .instructions = .{},
- .inlining = null,
- .comptime_reason = .{ .reason = .{
- .src = .{
- .base_node_inst = struct_type.zir_index,
- .offset = .nodeOffset(.zero),
- },
- .r = .{ .simple = .type },
- } },
- .src_base_inst = struct_type.zir_index,
- .type_name_ctx = struct_type.name,
- };
- defer assert(block_scope.instructions.items.len == 0);
-
- const Field = struct {
- type_body_len: u32 = 0,
- align_body_len: u32 = 0,
- init_body_len: u32 = 0,
- type_ref: Zir.Inst.Ref = .none,
- };
- const fields = try sema.arena.alloc(Field, fields_len);
-
- var any_inits = false;
- var any_aligned = false;
-
- {
- const bits_per_field = 4;
- const fields_per_u32 = 32 / bits_per_field;
- const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
- const flags_index = extra_index;
- var bit_bag_index: usize = flags_index;
- extra_index += bit_bags_count;
- var cur_bit_bag: u32 = undefined;
- var field_i: u32 = 0;
- while (field_i < fields_len) : (field_i += 1) {
- if (field_i % fields_per_u32 == 0) {
- cur_bit_bag = zir.extra[bit_bag_index];
- bit_bag_index += 1;
- }
- const has_align = @as(u1, @truncate(cur_bit_bag)) != 0;
- cur_bit_bag >>= 1;
- const has_init = @as(u1, @truncate(cur_bit_bag)) != 0;
- cur_bit_bag >>= 1;
- const is_comptime = @as(u1, @truncate(cur_bit_bag)) != 0;
- cur_bit_bag >>= 1;
- const has_type_body = @as(u1, @truncate(cur_bit_bag)) != 0;
- cur_bit_bag >>= 1;
-
- if (is_comptime) struct_type.setFieldComptime(ip, field_i);
-
- const field_name_zir: [:0]const u8 = zir.nullTerminatedString(@enumFromInt(zir.extra[extra_index]));
- extra_index += 1; // field_name
-
- fields[field_i] = .{};
-
- if (has_type_body) {
- fields[field_i].type_body_len = zir.extra[extra_index];
- } else {
- fields[field_i].type_ref = @enumFromInt(zir.extra[extra_index]);
- }
- extra_index += 1;
-
- // This string needs to outlive the ZIR code.
- const field_name = try ip.getOrPutString(gpa, io, pt.tid, field_name_zir, .no_embedded_nulls);
- assert(struct_type.addFieldName(ip, field_name) == null);
-
- if (has_align) {
- fields[field_i].align_body_len = zir.extra[extra_index];
- extra_index += 1;
- any_aligned = true;
- }
- if (has_init) {
- fields[field_i].init_body_len = zir.extra[extra_index];
- extra_index += 1;
- any_inits = true;
- }
- }
- }
-
- // Next we do only types and alignments, saving the inits for a second pass,
- // so that init values may depend on type layout.
-
- for (fields, 0..) |zir_field, field_i| {
- const ty_src: LazySrcLoc = .{
- .base_node_inst = struct_type.zir_index,
- .offset = .{ .container_field_type = @intCast(field_i) },
- };
- const field_ty: Type = ty: {
- if (zir_field.type_ref != .none) {
- break :ty try sema.resolveType(&block_scope, ty_src, zir_field.type_ref);
- }
- assert(zir_field.type_body_len != 0);
- const body = zir.bodySlice(extra_index, zir_field.type_body_len);
- extra_index += body.len;
- const ty_ref = try sema.resolveInlineBody(&block_scope, body, zir_index);
- break :ty try sema.analyzeAsType(&block_scope, ty_src, ty_ref);
- };
-
- struct_type.field_types.get(ip)[field_i] = field_ty.toIntern();
-
- if (field_ty.zigTypeTag(zcu) == .@"opaque") {
- const msg = msg: {
- const msg = try sema.errMsg(ty_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
- errdefer msg.destroy(sema.gpa);
-
- try sema.addDeclaredHereNote(msg, field_ty);
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(&block_scope, msg);
- }
- if (field_ty.zigTypeTag(zcu) == .noreturn) {
- const msg = msg: {
- const msg = try sema.errMsg(ty_src, "struct fields cannot be 'noreturn'", .{});
- errdefer msg.destroy(sema.gpa);
-
- try sema.addDeclaredHereNote(msg, field_ty);
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(&block_scope, msg);
- }
- switch (struct_type.layout) {
- .@"extern" => if (!try sema.validateExternType(field_ty, .struct_field)) {
- const msg = msg: {
- const msg = try sema.errMsg(ty_src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
- errdefer msg.destroy(sema.gpa);
-
- try sema.explainWhyTypeIsNotExtern(msg, ty_src, field_ty, .struct_field);
-
- try sema.addDeclaredHereNote(msg, field_ty);
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(&block_scope, msg);
- },
- .@"packed" => if (!try sema.validatePackedType(field_ty)) {
- const msg = msg: {
- const msg = try sema.errMsg(ty_src, "packed structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
- errdefer msg.destroy(sema.gpa);
-
- try sema.explainWhyTypeIsNotPacked(msg, ty_src, field_ty);
-
- try sema.addDeclaredHereNote(msg, field_ty);
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(&block_scope, msg);
- },
- else => {},
- }
-
- if (zir_field.align_body_len > 0) {
- const body = zir.bodySlice(extra_index, zir_field.align_body_len);
- extra_index += body.len;
- const align_ref = try sema.resolveInlineBody(&block_scope, body, zir_index);
- const align_src: LazySrcLoc = .{
- .base_node_inst = struct_type.zir_index,
- .offset = .{ .container_field_align = @intCast(field_i) },
- };
- const field_align = try sema.analyzeAsAlign(&block_scope, align_src, align_ref);
- struct_type.field_aligns.get(ip)[field_i] = field_align;
- }
-
- extra_index += zir_field.init_body_len;
- }
-
- struct_type.clearFieldTypesWip(ip, io);
- if (!any_inits) struct_type.setHaveFieldInits(ip, io);
-
- try sema.flushExports();
-}
-
-// This logic must be kept in sync with `structFields`
-fn structFieldInits(
- sema: *Sema,
- struct_type: InternPool.LoadedStructType,
-) CompileError!void {
- const pt = sema.pt;
- const zcu = pt.zcu;
- const ip = &zcu.intern_pool;
-
- assert(!struct_type.haveFieldInits(ip));
-
- const namespace_index = struct_type.namespace;
- const zir = zcu.namespacePtr(namespace_index).fileScope(zcu).zir.?;
- const zir_index = struct_type.zir_index.resolve(ip) orelse return error.AnalysisFail;
- const fields_len, _, var extra_index = structZirInfo(zir, zir_index);
-
- var block_scope: Block = .{
- .parent = null,
- .sema = sema,
- .namespace = namespace_index,
- .instructions = .{},
- .inlining = null,
- .comptime_reason = undefined, // set when `block_scope` is used
- .src_base_inst = struct_type.zir_index,
- .type_name_ctx = struct_type.name,
- };
- defer assert(block_scope.instructions.items.len == 0);
-
- const Field = struct {
- type_body_len: u32 = 0,
- align_body_len: u32 = 0,
- init_body_len: u32 = 0,
- };
- const fields = try sema.arena.alloc(Field, fields_len);
-
- var any_inits = false;
-
- {
- const bits_per_field = 4;
- const fields_per_u32 = 32 / bits_per_field;
- const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
- const flags_index = extra_index;
- var bit_bag_index: usize = flags_index;
- extra_index += bit_bags_count;
- var cur_bit_bag: u32 = undefined;
- var field_i: u32 = 0;
- while (field_i < fields_len) : (field_i += 1) {
- if (field_i % fields_per_u32 == 0) {
- cur_bit_bag = zir.extra[bit_bag_index];
- bit_bag_index += 1;
- }
- const has_align = @as(u1, @truncate(cur_bit_bag)) != 0;
- cur_bit_bag >>= 1;
- const has_init = @as(u1, @truncate(cur_bit_bag)) != 0;
- cur_bit_bag >>= 2;
- const has_type_body = @as(u1, @truncate(cur_bit_bag)) != 0;
- cur_bit_bag >>= 1;
-
- extra_index += 1; // field_name
-
- fields[field_i] = .{};
-
- if (has_type_body) fields[field_i].type_body_len = zir.extra[extra_index];
- extra_index += 1;
-
- if (has_align) {
- fields[field_i].align_body_len = zir.extra[extra_index];
- extra_index += 1;
- }
- if (has_init) {
- fields[field_i].init_body_len = zir.extra[extra_index];
- extra_index += 1;
- any_inits = true;
- }
- }
- }
-
- if (any_inits) {
- for (fields, 0..) |zir_field, field_i| {
- extra_index += zir_field.type_body_len;
- extra_index += zir_field.align_body_len;
- const body = zir.bodySlice(extra_index, zir_field.init_body_len);
- extra_index += zir_field.init_body_len;
-
- if (body.len == 0) continue;
-
- // Pre-populate the type mapping the body expects to be there.
- // In init bodies, the zir index of the struct itself is used
- // to refer to the current field type.
-
- const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_i]);
- const type_ref = Air.internedToRef(field_ty.toIntern());
- try sema.inst_map.ensureSpaceForInstructions(sema.gpa, &.{zir_index});
- sema.inst_map.putAssumeCapacity(zir_index, type_ref);
-
- const init_src: LazySrcLoc = .{
- .base_node_inst = struct_type.zir_index,
- .offset = .{ .container_field_value = @intCast(field_i) },
- };
-
- block_scope.comptime_reason = .{ .reason = .{
- .src = init_src,
- .r = .{ .simple = .struct_field_default_value },
- } };
- const init = try sema.resolveInlineBody(&block_scope, body, zir_index);
- const coerced = try sema.coerce(&block_scope, field_ty, init, init_src);
- const default_val = try sema.resolveConstValue(&block_scope, init_src, coerced, null);
-
- if (default_val.canMutateComptimeVarState(zcu)) {
- return sema.failWithContainsReferenceToComptimeVar(
- &block_scope,
- init_src,
- struct_type.fieldName(ip, field_i),
- "field default value",
- default_val,
- );
- }
- struct_type.field_inits.get(ip)[field_i] = default_val.toIntern();
- }
- }
-
- try sema.flushExports();
-}
-
-fn unionFields(
- sema: *Sema,
- union_ty: InternPool.Index,
- union_type: InternPool.LoadedUnionType,
-) CompileError!void {
- const tracy = trace(@src());
- defer tracy.end();
-
- const pt = sema.pt;
- const zcu = pt.zcu;
- const comp = zcu.comp;
- const gpa = comp.gpa;
- const io = comp.io;
- const ip = &zcu.intern_pool;
-
- const zir = zcu.namespacePtr(union_type.namespace).fileScope(zcu).zir.?;
- const zir_index = union_type.zir_index.resolve(ip) orelse return error.AnalysisFail;
- const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;
- assert(extended.opcode == .union_decl);
- const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
- const extra = zir.extraData(Zir.Inst.UnionDecl, extended.operand);
- var extra_index: usize = extra.end;
-
- const tag_type_ref: Zir.Inst.Ref = if (small.has_tag_type) blk: {
- const ty_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]);
- extra_index += 1;
- break :blk ty_ref;
- } else .none;
-
- const captures_len = if (small.has_captures_len) blk: {
- const captures_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk captures_len;
- } else 0;
-
- const body_len = if (small.has_body_len) blk: {
- const body_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk body_len;
- } else 0;
-
- const fields_len = if (small.has_fields_len) blk: {
- const fields_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk fields_len;
- } else 0;
-
- const decls_len = if (small.has_decls_len) decls_len: {
- const decls_len = zir.extra[extra_index];
- extra_index += 1;
- break :decls_len decls_len;
- } else 0;
-
- // Skip over captures and decls.
- extra_index += captures_len * 2 + decls_len;
-
- const body = zir.bodySlice(extra_index, body_len);
- extra_index += body.len;
-
- const src: LazySrcLoc = .{
- .base_node_inst = union_type.zir_index,
- .offset = .nodeOffset(.zero),
- };
-
- var block_scope: Block = .{
- .parent = null,
- .sema = sema,
- .namespace = union_type.namespace,
- .instructions = .{},
- .inlining = null,
- .comptime_reason = .{ .reason = .{
- .src = src,
- .r = .{ .simple = .type },
- } },
- .src_base_inst = union_type.zir_index,
- .type_name_ctx = union_type.name,
- };
- defer assert(block_scope.instructions.items.len == 0);
-
- if (body.len != 0) {
- _ = try sema.analyzeInlineBody(&block_scope, body, zir_index);
- }
-
- var int_tag_ty: Type = undefined;
- var enum_field_names: []InternPool.NullTerminatedString = &.{};
- var enum_field_vals: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .empty;
- var explicit_tags_seen: []bool = &.{};
- if (tag_type_ref != .none) {
- const tag_ty_src: LazySrcLoc = .{
- .base_node_inst = union_type.zir_index,
- .offset = .{ .node_offset_container_tag = .zero },
- };
- const provided_ty = try sema.resolveType(&block_scope, tag_ty_src, tag_type_ref);
- if (small.auto_enum_tag) {
- // The provided type is an integer type and we must construct the enum tag type here.
- int_tag_ty = provided_ty;
- if (int_tag_ty.zigTypeTag(zcu) != .int and int_tag_ty.zigTypeTag(zcu) != .comptime_int) {
- return sema.fail(&block_scope, tag_ty_src, "expected integer tag type, found '{f}'", .{int_tag_ty.fmt(pt)});
- }
-
- if (fields_len > 0) {
- const field_count_val = try pt.intValue(.comptime_int, fields_len - 1);
- if (!(try sema.intFitsInType(field_count_val, int_tag_ty, null))) {
- const msg = msg: {
- const msg = try sema.errMsg(tag_ty_src, "specified integer tag type cannot represent every field", .{});
- errdefer msg.destroy(sema.gpa);
- try sema.errNote(tag_ty_src, msg, "type '{f}' cannot fit values in range 0...{d}", .{
- int_tag_ty.fmt(pt),
- fields_len - 1,
- });
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(&block_scope, msg);
- }
- enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len);
- try enum_field_vals.ensureTotalCapacity(sema.arena, fields_len);
- }
- } else {
- // The provided type is the enum tag type.
- const enum_type = switch (ip.indexToKey(provided_ty.toIntern())) {
- .enum_type => ip.loadEnumType(provided_ty.toIntern()),
- else => return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{f}'", .{provided_ty.fmt(pt)}),
- };
- union_type.setTagType(ip, io, provided_ty.toIntern());
- // The fields of the union must match the enum exactly.
- // A flag per field is used to check for missing and extraneous fields.
- explicit_tags_seen = try sema.arena.alloc(bool, enum_type.names.len);
- @memset(explicit_tags_seen, false);
- }
- } else {
- // If auto_enum_tag is false, this is an untagged union. However, for semantic analysis
- // purposes, we still auto-generate an enum tag type the same way. That the union is
- // untagged is represented by the Type tag (union vs union_tagged).
- enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len);
- }
-
- var field_types: std.ArrayList(InternPool.Index) = .empty;
- var field_aligns: std.ArrayList(InternPool.Alignment) = .empty;
-
- try field_types.ensureTotalCapacityPrecise(sema.arena, fields_len);
- if (small.any_aligned_fields)
- try field_aligns.ensureTotalCapacityPrecise(sema.arena, fields_len);
-
- var max_bits: u64 = 0;
- var min_bits: u64 = std.math.maxInt(u64);
- var max_bits_src: LazySrcLoc = undefined;
- var min_bits_src: LazySrcLoc = undefined;
- var max_bits_ty: Type = undefined;
- var min_bits_ty: Type = undefined;
- const bits_per_field = 4;
- const fields_per_u32 = 32 / bits_per_field;
- const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
- var bit_bag_index: usize = extra_index;
- extra_index += bit_bags_count;
- var cur_bit_bag: u32 = undefined;
- var field_i: u32 = 0;
- var last_tag_val: ?Value = null;
- const layout = union_type.flagsUnordered(ip).layout;
- while (field_i < fields_len) : (field_i += 1) {
- if (field_i % fields_per_u32 == 0) {
- cur_bit_bag = zir.extra[bit_bag_index];
- bit_bag_index += 1;
- }
- const has_type = @as(u1, @truncate(cur_bit_bag)) != 0;
- cur_bit_bag >>= 1;
- const has_align = @as(u1, @truncate(cur_bit_bag)) != 0;
- cur_bit_bag >>= 1;
- const has_tag = @as(u1, @truncate(cur_bit_bag)) != 0;
- cur_bit_bag >>= 1;
- const unused = @as(u1, @truncate(cur_bit_bag)) != 0;
- cur_bit_bag >>= 1;
- _ = unused;
-
- const field_name_index: Zir.NullTerminatedString = @enumFromInt(zir.extra[extra_index]);
- const field_name_zir = zir.nullTerminatedString(field_name_index);
- extra_index += 1;
-
- const field_type_ref: Zir.Inst.Ref = if (has_type) blk: {
- const field_type_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]);
- extra_index += 1;
- break :blk field_type_ref;
- } else .none;
-
- const align_ref: Zir.Inst.Ref = if (has_align) blk: {
- const align_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]);
- extra_index += 1;
- break :blk align_ref;
- } else .none;
-
- const tag_ref: Air.Inst.Ref = if (has_tag) blk: {
- const tag_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]);
- extra_index += 1;
- break :blk try sema.resolveInst(tag_ref);
- } else .none;
-
- const name_src: LazySrcLoc = .{
- .base_node_inst = union_type.zir_index,
- .offset = .{ .container_field_name = field_i },
- };
- const value_src: LazySrcLoc = .{
- .base_node_inst = union_type.zir_index,
- .offset = .{ .container_field_value = field_i },
- };
- const align_src: LazySrcLoc = .{
- .base_node_inst = union_type.zir_index,
- .offset = .{ .container_field_align = field_i },
- };
- const type_src: LazySrcLoc = .{
- .base_node_inst = union_type.zir_index,
- .offset = .{ .container_field_type = field_i },
- };
-
- if (enum_field_vals.capacity() > 0) {
- const enum_tag_val = if (tag_ref != .none) blk: {
- const coerced = try sema.coerce(&block_scope, int_tag_ty, tag_ref, value_src);
- const val = try sema.resolveConstDefinedValue(&block_scope, value_src, coerced, .{ .simple = .enum_field_tag_value });
- last_tag_val = val;
-
- break :blk val;
- } else blk: {
- if (last_tag_val) |last_tag| {
- const result = try arith.incrementDefinedInt(sema, int_tag_ty, last_tag);
- if (result.overflow) return sema.fail(
- &block_scope,
- value_src,
- "enumeration value '{f}' too large for type '{f}'",
- .{ result.val.fmtValueSema(pt, sema), int_tag_ty.fmt(pt) },
- );
- last_tag_val = result.val;
- } else {
- last_tag_val = try pt.intValue(int_tag_ty, 0);
- }
- break :blk last_tag_val.?;
- };
- const gop = enum_field_vals.getOrPutAssumeCapacity(enum_tag_val.toIntern());
- if (gop.found_existing) {
- const other_value_src: LazySrcLoc = .{
- .base_node_inst = union_type.zir_index,
- .offset = .{ .container_field_value = @intCast(gop.index) },
- };
- const msg = msg: {
- const msg = try sema.errMsg(
- value_src,
- "enum tag value {f} already taken",
- .{enum_tag_val.fmtValueSema(pt, sema)},
- );
- errdefer msg.destroy(gpa);
- try sema.errNote(other_value_src, msg, "other occurrence here", .{});
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(&block_scope, msg);
- }
- }
-
- // This string needs to outlive the ZIR code.
- const field_name = try ip.getOrPutString(gpa, io, pt.tid, field_name_zir, .no_embedded_nulls);
- if (enum_field_names.len != 0) {
- enum_field_names[field_i] = field_name;
- }
-
- const field_ty: Type = if (!has_type)
- .void
- else if (field_type_ref == .none)
- .noreturn
- else
- try sema.resolveType(&block_scope, type_src, field_type_ref);
-
- if (explicit_tags_seen.len > 0) {
- const tag_ty = union_type.tagTypeUnordered(ip);
- const tag_info = ip.loadEnumType(tag_ty);
- const enum_index = tag_info.nameIndex(ip, field_name) orelse {
- return sema.fail(&block_scope, name_src, "no field named '{f}' in enum '{f}'", .{
- field_name.fmt(ip), Type.fromInterned(tag_ty).fmt(pt),
- });
- };
-
- // No check for duplicate because the check already happened in order
- // to create the enum type in the first place.
- assert(!explicit_tags_seen[enum_index]);
- explicit_tags_seen[enum_index] = true;
-
- // Enforce the enum fields and the union fields being in the same order.
- if (enum_index != field_i) {
- const msg = msg: {
- const enum_field_src: LazySrcLoc = .{
- .base_node_inst = Type.fromInterned(tag_ty).typeDeclInstAllowGeneratedTag(zcu).?,
- .offset = .{ .container_field_name = enum_index },
- };
- const msg = try sema.errMsg(name_src, "union field '{f}' ordered differently than corresponding enum field", .{
- field_name.fmt(ip),
- });
- errdefer msg.destroy(sema.gpa);
- try sema.errNote(enum_field_src, msg, "enum field here", .{});
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(&block_scope, msg);
- }
- }
-
- if (field_ty.zigTypeTag(zcu) == .@"opaque") {
- const msg = msg: {
- const msg = try sema.errMsg(type_src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{});
- errdefer msg.destroy(sema.gpa);
-
- try sema.addDeclaredHereNote(msg, field_ty);
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(&block_scope, msg);
- }
- switch (layout) {
- .@"extern" => if (!try sema.validateExternType(field_ty, .union_field)) {
- const msg = msg: {
- const msg = try sema.errMsg(type_src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
- errdefer msg.destroy(sema.gpa);
-
- try sema.explainWhyTypeIsNotExtern(msg, type_src, field_ty, .union_field);
-
- try sema.addDeclaredHereNote(msg, field_ty);
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(&block_scope, msg);
- },
- .@"packed" => {
- if (!try sema.validatePackedType(field_ty)) {
- const msg = msg: {
- const msg = try sema.errMsg(type_src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
- errdefer msg.destroy(sema.gpa);
-
- try sema.explainWhyTypeIsNotPacked(msg, type_src, field_ty);
-
- try sema.addDeclaredHereNote(msg, field_ty);
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(&block_scope, msg);
- }
- const field_bits = try field_ty.bitSizeSema(pt);
- if (field_bits >= max_bits) {
- max_bits = field_bits;
- max_bits_src = type_src;
- max_bits_ty = field_ty;
- }
- if (field_bits <= min_bits) {
- min_bits = field_bits;
- min_bits_src = type_src;
- min_bits_ty = field_ty;
- }
- },
- .auto => {},
- }
-
- field_types.appendAssumeCapacity(field_ty.toIntern());
-
- if (small.any_aligned_fields) {
- field_aligns.appendAssumeCapacity(if (align_ref != .none)
- try sema.resolveAlign(&block_scope, align_src, align_ref)
- else
- .none);
- } else {
- assert(align_ref == .none);
- }
- }
-
- union_type.setFieldTypes(ip, field_types.items);
- union_type.setFieldAligns(ip, field_aligns.items);
-
- if (layout == .@"packed" and fields_len != 0 and min_bits != max_bits) {
- const msg = msg: {
- const msg = try sema.errMsg(src, "packed union has fields with mismatching bit sizes", .{});
- errdefer msg.destroy(sema.gpa);
- try sema.errNote(min_bits_src, msg, "{d} bits here", .{min_bits});
- try sema.addDeclaredHereNote(msg, min_bits_ty);
- try sema.errNote(max_bits_src, msg, "{d} bits here", .{max_bits});
- try sema.addDeclaredHereNote(msg, max_bits_ty);
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(&block_scope, msg);
- }
-
- if (explicit_tags_seen.len > 0) {
- const tag_ty = union_type.tagTypeUnordered(ip);
- const tag_info = ip.loadEnumType(tag_ty);
- if (tag_info.names.len > fields_len) {
- const msg = msg: {
- const msg = try sema.errMsg(src, "enum field(s) missing in union", .{});
- errdefer msg.destroy(sema.gpa);
-
- for (tag_info.names.get(ip), 0..) |field_name, field_index| {
- if (explicit_tags_seen[field_index]) continue;
- try sema.addFieldErrNote(.fromInterned(tag_ty), field_index, msg, "field '{f}' missing, declared here", .{
- field_name.fmt(ip),
- });
- }
- try sema.addDeclaredHereNote(msg, .fromInterned(tag_ty));
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(&block_scope, msg);
- }
- } else if (enum_field_vals.count() > 0) {
- const enum_ty = try sema.generateUnionTagTypeNumbered(&block_scope, enum_field_names, enum_field_vals.keys(), union_ty, union_type.name);
- union_type.setTagType(ip, io, enum_ty);
- } else {
- const enum_ty = try sema.generateUnionTagTypeSimple(&block_scope, enum_field_names, union_ty, union_type.name);
- union_type.setTagType(ip, io, enum_ty);
- }
-
- try sema.flushExports();
-}
-
-fn generateUnionTagTypeNumbered(
- sema: *Sema,
- block: *Block,
- enum_field_names: []const InternPool.NullTerminatedString,
- enum_field_vals: []const InternPool.Index,
- union_type: InternPool.Index,
- union_name: InternPool.NullTerminatedString,
-) !InternPool.Index {
- const pt = sema.pt;
- const zcu = pt.zcu;
- const comp = zcu.comp;
- const gpa = comp.gpa;
- const io = comp.io;
- const ip = &zcu.intern_pool;
-
- const name = try ip.getOrPutStringFmt(
- gpa,
- io,
- pt.tid,
- "@typeInfo({f}).@\"union\".tag_type.?",
- .{union_name.fmt(ip)},
- .no_embedded_nulls,
- );
-
- const enum_ty = try ip.getGeneratedTagEnumType(gpa, io, pt.tid, .{
- .name = name,
- .owner_union_ty = union_type,
- .tag_ty = if (enum_field_vals.len == 0)
- (try pt.intType(.unsigned, 0)).toIntern()
- else
- ip.typeOf(enum_field_vals[0]),
- .names = enum_field_names,
- .values = enum_field_vals,
- .tag_mode = .explicit,
- .parent_namespace = block.namespace,
- });
-
- return enum_ty;
-}
-
-fn generateUnionTagTypeSimple(
- sema: *Sema,
- block: *Block,
- enum_field_names: []const InternPool.NullTerminatedString,
- union_type: InternPool.Index,
- union_name: InternPool.NullTerminatedString,
-) !InternPool.Index {
- const pt = sema.pt;
- const zcu = pt.zcu;
- const comp = zcu.comp;
- const gpa = comp.gpa;
- const io = comp.io;
- const ip = &zcu.intern_pool;
-
- const name = try ip.getOrPutStringFmt(
- gpa,
- io,
- pt.tid,
- "@typeInfo({f}).@\"union\".tag_type.?",
- .{union_name.fmt(ip)},
- .no_embedded_nulls,
- );
-
- const enum_ty = try ip.getGeneratedTagEnumType(gpa, io, pt.tid, .{
- .name = name,
- .owner_union_ty = union_type,
- .tag_ty = (try pt.smallestUnsignedInt(enum_field_names.len -| 1)).toIntern(),
- .names = enum_field_names,
- .values = &.{},
- .tag_mode = .auto,
- .parent_namespace = block.namespace,
- });
-
- return enum_ty;
-}
-
-/// There is another implementation of this in `Type.onePossibleValue`. This one
-/// in `Sema` is for calling during semantic analysis, and performs field resolution
-/// to get the answer. The one in `Type` is for calling during codegen and asserts
-/// that the types are already resolved.
-/// TODO assert the return value matches `ty.onePossibleValue`
-pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
- const pt = sema.pt;
- const zcu = pt.zcu;
- const comp = zcu.comp;
- const gpa = comp.gpa;
- const io = comp.io;
- const ip = &zcu.intern_pool;
-
- return switch (ty.toIntern()) {
- .u0_type,
- .i0_type,
- => try pt.intValue(ty, 0),
- .u1_type,
- .u8_type,
- .i8_type,
- .u16_type,
- .i16_type,
- .u29_type,
- .u32_type,
- .i32_type,
- .u64_type,
- .i64_type,
- .u80_type,
- .u128_type,
- .i128_type,
- .u256_type,
- .usize_type,
- .isize_type,
- .c_char_type,
- .c_short_type,
- .c_ushort_type,
- .c_int_type,
- .c_uint_type,
- .c_long_type,
- .c_ulong_type,
- .c_longlong_type,
- .c_ulonglong_type,
- .c_longdouble_type,
- .f16_type,
- .f32_type,
- .f64_type,
- .f80_type,
- .f128_type,
- .anyopaque_type,
- .bool_type,
- .type_type,
- .anyerror_type,
- .adhoc_inferred_error_set_type,
- .comptime_int_type,
- .comptime_float_type,
- .enum_literal_type,
- .ptr_usize_type,
- .ptr_const_comptime_int_type,
- .manyptr_u8_type,
- .manyptr_const_u8_type,
- .manyptr_const_u8_sentinel_0_type,
- .manyptr_const_slice_const_u8_type,
- .slice_const_u8_type,
- .slice_const_u8_sentinel_0_type,
- .slice_const_slice_const_u8_type,
- .optional_type_type,
- .manyptr_const_type_type,
- .slice_const_type_type,
- .vector_8_i8_type,
- .vector_16_i8_type,
- .vector_32_i8_type,
- .vector_64_i8_type,
- .vector_1_u8_type,
- .vector_2_u8_type,
- .vector_4_u8_type,
- .vector_8_u8_type,
- .vector_16_u8_type,
- .vector_32_u8_type,
- .vector_64_u8_type,
- .vector_2_i16_type,
- .vector_4_i16_type,
- .vector_8_i16_type,
- .vector_16_i16_type,
- .vector_32_i16_type,
- .vector_4_u16_type,
- .vector_8_u16_type,
- .vector_16_u16_type,
- .vector_32_u16_type,
- .vector_2_i32_type,
- .vector_4_i32_type,
- .vector_8_i32_type,
- .vector_16_i32_type,
- .vector_4_u32_type,
- .vector_8_u32_type,
- .vector_16_u32_type,
- .vector_2_i64_type,
- .vector_4_i64_type,
- .vector_8_i64_type,
- .vector_2_u64_type,
- .vector_4_u64_type,
- .vector_8_u64_type,
- .vector_1_u128_type,
- .vector_2_u128_type,
- .vector_1_u256_type,
- .vector_4_f16_type,
- .vector_8_f16_type,
- .vector_16_f16_type,
- .vector_32_f16_type,
- .vector_2_f32_type,
- .vector_4_f32_type,
- .vector_8_f32_type,
- .vector_16_f32_type,
- .vector_2_f64_type,
- .vector_4_f64_type,
- .vector_8_f64_type,
- .anyerror_void_error_union_type,
- => null,
- .void_type => Value.void,
- .noreturn_type => Value.@"unreachable",
- .anyframe_type => unreachable,
- .null_type => Value.null,
- .undefined_type => Value.undef,
- .optional_noreturn_type => try pt.nullValue(ty),
- .generic_poison_type => unreachable,
- .empty_tuple_type => Value.empty_tuple,
- // values, not types
- .undef,
- .undef_bool,
- .undef_usize,
- .undef_u1,
- .zero,
- .zero_usize,
- .zero_u1,
- .zero_u8,
- .one,
- .one_usize,
- .one_u1,
- .one_u8,
- .four_u8,
- .negative_one,
- .void_value,
- .unreachable_value,
- .null_value,
- .bool_true,
- .bool_false,
- .empty_tuple,
- // invalid
- .none,
- => unreachable,
-
- _ => switch (ty.toIntern().unwrap(ip).getTag(ip)) {
- .removed => unreachable,
-
- .type_int_signed, // i0 handled above
- .type_int_unsigned, // u0 handled above
- .type_pointer,
- .type_slice,
- .type_anyframe,
- .type_error_union,
- .type_anyerror_union,
- .type_error_set,
- .type_inferred_error_set,
- .type_opaque,
- .type_function,
- => null,
-
- .simple_type, // handled above
- // values, not types
- .undef,
- .simple_value,
- .ptr_nav,
- .ptr_uav,
- .ptr_uav_aligned,
- .ptr_comptime_alloc,
- .ptr_comptime_field,
- .ptr_int,
- .ptr_eu_payload,
- .ptr_opt_payload,
- .ptr_elem,
- .ptr_field,
- .ptr_slice,
- .opt_payload,
- .opt_null,
- .int_u8,
- .int_u16,
- .int_u32,
- .int_i32,
- .int_usize,
- .int_comptime_int_u32,
- .int_comptime_int_i32,
- .int_small,
- .int_positive,
- .int_negative,
- .int_lazy_align,
- .int_lazy_size,
- .error_set_error,
- .error_union_error,
- .error_union_payload,
- .enum_literal,
- .enum_tag,
- .float_f16,
- .float_f32,
- .float_f64,
- .float_f80,
- .float_f128,
- .float_c_longdouble_f80,
- .float_c_longdouble_f128,
- .float_comptime_float,
- .variable,
- .threadlocal_variable,
- .@"extern",
- .func_decl,
- .func_instance,
- .func_coerced,
- .only_possible_value,
- .union_value,
- .bytes,
- .aggregate,
- .repeated,
- // memoized value, not types
- .memoized_call,
- => unreachable,
-
- .type_array_big,
- .type_array_small,
- .type_vector,
- .type_enum_auto,
- .type_enum_explicit,
- .type_enum_nonexhaustive,
- .type_struct,
- .type_struct_packed,
- .type_struct_packed_inits,
- .type_tuple,
- .type_union,
- => switch (ip.indexToKey(ty.toIntern())) {
- inline .array_type, .vector_type => |seq_type, seq_tag| {
- const has_sentinel = seq_tag == .array_type and seq_type.sentinel != .none;
- if (seq_type.len + @intFromBool(has_sentinel) == 0) return try pt.aggregateValue(ty, &.{});
- if (try sema.typeHasOnePossibleValue(.fromInterned(seq_type.child))) |opv| {
- return try pt.aggregateSplatValue(ty, opv);
- }
- return null;
- },
-
- .struct_type => {
- // Resolving the layout first helps to avoid loops.
- // If the type has a coherent layout, we can recurse through fields safely.
- try ty.resolveLayout(pt);
-
- const struct_type = ip.loadStructType(ty.toIntern());
-
- if (struct_type.field_types.len == 0) {
- // In this case the struct has no fields at all and
- // therefore has one possible value.
- return try pt.aggregateValue(ty, &.{});
- }
-
- const field_vals = try sema.arena.alloc(
- InternPool.Index,
- struct_type.field_types.len,
- );
- for (field_vals, 0..) |*field_val, i| {
- if (struct_type.fieldIsComptime(ip, i)) {
- try ty.resolveStructFieldInits(pt);
- field_val.* = struct_type.field_inits.get(ip)[i];
- continue;
- }
- const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[i]);
- if (try sema.typeHasOnePossibleValue(field_ty)) |field_opv| {
- field_val.* = field_opv.toIntern();
- } else return null;
- }
-
- // In this case the struct has no runtime-known fields and
- // therefore has one possible value.
- return try pt.aggregateValue(ty, field_vals);
- },
-
- .tuple_type => |tuple| {
- try ty.resolveLayout(pt);
-
- if (tuple.types.len == 0) {
- return try pt.aggregateValue(ty, &.{});
- }
-
- const field_vals = try sema.arena.alloc(
- InternPool.Index,
- tuple.types.len,
- );
- for (
- field_vals,
- tuple.types.get(ip),
- tuple.values.get(ip),
- ) |*field_val, field_ty, field_comptime_val| {
- if (field_comptime_val != .none) {
- field_val.* = field_comptime_val;
- continue;
- }
- if (try sema.typeHasOnePossibleValue(.fromInterned(field_ty))) |opv| {
- field_val.* = opv.toIntern();
- } else return null;
- }
-
- return try pt.aggregateValue(ty, field_vals);
- },
-
- .union_type => {
- // Resolving the layout first helps to avoid loops.
- // If the type has a coherent layout, we can recurse through fields safely.
- try ty.resolveLayout(pt);
-
- const union_obj = ip.loadUnionType(ty.toIntern());
- const tag_val = (try sema.typeHasOnePossibleValue(.fromInterned(union_obj.tagTypeUnordered(ip)))) orelse
- return null;
- if (union_obj.field_types.len == 0) {
- const only = try pt.intern(.{ .empty_enum_value = ty.toIntern() });
- return Value.fromInterned(only);
- }
- const only_field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[0]);
- const val_val = (try sema.typeHasOnePossibleValue(only_field_ty)) orelse
- return null;
- const only = try pt.internUnion(.{
- .ty = ty.toIntern(),
- .tag = tag_val.toIntern(),
- .val = val_val.toIntern(),
- });
- return Value.fromInterned(only);
- },
-
- .enum_type => {
- const enum_type = ip.loadEnumType(ty.toIntern());
- switch (enum_type.tag_mode) {
- .nonexhaustive => {
- if (enum_type.tag_ty == .comptime_int_type) return null;
-
- if (try sema.typeHasOnePossibleValue(.fromInterned(enum_type.tag_ty))) |int_opv| {
- const only = try pt.intern(.{ .enum_tag = .{
- .ty = ty.toIntern(),
- .int = int_opv.toIntern(),
- } });
- return Value.fromInterned(only);
- }
-
- return null;
- },
- .auto, .explicit => {
- if (Type.fromInterned(enum_type.tag_ty).hasRuntimeBits(zcu)) return null;
-
- return Value.fromInterned(switch (enum_type.names.len) {
- 0 => try pt.intern(.{ .empty_enum_value = ty.toIntern() }),
- 1 => try pt.intern(.{ .enum_tag = .{
- .ty = ty.toIntern(),
- .int = if (enum_type.values.len == 0)
- (try pt.intValue(.fromInterned(enum_type.tag_ty), 0)).toIntern()
- else
- try ip.getCoercedInts(
- gpa,
- io,
- pt.tid,
- ip.indexToKey(enum_type.values.get(ip)[0]).int,
- enum_type.tag_ty,
- ),
- } }),
- else => return null,
- });
- },
- }
- },
-
- else => unreachable,
- },
-
- .type_optional => {
- const payload_ip = ip.indexToKey(ty.toIntern()).opt_type;
- // Although ?noreturn is handled above, the element type
- // can be effectively noreturn for example via an empty
- // enum or error set.
- if (ip.isNoReturn(payload_ip)) return try pt.nullValue(ty);
- return null;
- },
- },
- };
-}
-
/// Returns the type of the AIR instruction.
fn typeOf(sema: *Sema, inst: Air.Inst.Ref) Type {
return sema.getTmpAir().typeOf(inst, &sema.pt.zcu.intern_pool);
@@ -36232,9 +33200,10 @@ fn isComptimeKnown(
sema: *Sema,
inst: Air.Inst.Ref,
) !bool {
- return (try sema.resolveValue(inst)) != null;
+ return sema.resolveValue(inst) != null;
}
+/// Asserts that the layout of `var_type` has already been resolved.
fn analyzeComptimeAlloc(
sema: *Sema,
block: *Block,
@@ -36245,10 +33214,9 @@ fn analyzeComptimeAlloc(
const pt = sema.pt;
const zcu = pt.zcu;
- // Needed to make an anon decl with type `var_type` (the `finish()` call below).
- _ = try sema.typeHasOnePossibleValue(var_type);
+ var_type.assertHasLayout(zcu);
- const ptr_type = try pt.ptrTypeSema(.{
+ const ptr_type = try pt.ptrType(.{
.child = var_type.toIntern(),
.flags = .{
.alignment = alignment,
@@ -36256,13 +33224,23 @@ fn analyzeComptimeAlloc(
},
});
- const alloc = try sema.newComptimeAlloc(block, src, var_type, alignment);
-
- return Air.internedToRef((try pt.intern(.{ .ptr = .{
- .ty = ptr_type.toIntern(),
- .base_addr = .{ .comptime_alloc = alloc },
- .byte_offset = 0,
- } })));
+ if (try var_type.onePossibleValue(pt)) |opv| {
+ return .fromIntern(try pt.intern(.{ .ptr = .{
+ .ty = ptr_type.toIntern(),
+ .base_addr = .{ .uav = .{
+ .val = opv.toIntern(),
+ .orig_ty = ptr_type.toIntern(),
+ } },
+ .byte_offset = 0,
+ } }));
+ } else {
+ const alloc = try sema.newComptimeAlloc(block, src, var_type, alignment);
+ return .fromIntern(try pt.intern(.{ .ptr = .{
+ .ty = ptr_type.toIntern(),
+ .base_addr = .{ .comptime_alloc = alloc },
+ .byte_offset = 0,
+ } }));
+ }
}
fn resolveAddressSpace(
@@ -36272,7 +33250,7 @@ fn resolveAddressSpace(
zir_ref: Zir.Inst.Ref,
ctx: std.Target.AddressSpaceContext,
) !std.builtin.AddressSpace {
- const air_ref = try sema.resolveInst(zir_ref);
+ const air_ref = sema.resolveInst(zir_ref);
return sema.analyzeAsAddressSpace(block, src, air_ref, ctx);
}
@@ -36363,40 +33341,7 @@ fn usizeCast(sema: *Sema, block: *Block, src: LazySrcLoc, int: u64) CompileError
return std.math.cast(usize, int) orelse return sema.fail(block, src, "expression produces integer value '{d}' which is too big for this compiler implementation to handle", .{int});
}
-/// For pointer-like optionals, it returns the pointer type. For pointers,
-/// the type is returned unmodified.
-/// This can return `error.AnalysisFail` because it sometimes requires resolving whether
-/// a type has zero bits, which can cause a "foo depends on itself" compile error.
-/// This logic must be kept in sync with `Type.isPtrLikeOptional`.
-fn typePtrOrOptionalPtrTy(sema: *Sema, ty: Type) !?Type {
- const pt = sema.pt;
- const zcu = pt.zcu;
- return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
- .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
- .one, .many, .c => ty,
- .slice => null,
- },
- .opt_type => |opt_child| switch (zcu.intern_pool.indexToKey(opt_child)) {
- .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
- .slice, .c => null,
- .many, .one => {
- if (ptr_type.flags.is_allowzero) return null;
-
- // optionals of zero sized types behave like bools, not pointers
- const payload_ty: Type = .fromInterned(opt_child);
- if ((try sema.typeHasOnePossibleValue(payload_ty)) != null) {
- return null;
- }
-
- return payload_ty;
- },
- },
- else => null,
- },
- else => null,
- };
-}
-
+/// Asserts that the layout of `union_ty` is already resolved.
fn unionFieldIndex(
sema: *Sema,
block: *Block,
@@ -36407,13 +33352,14 @@ fn unionFieldIndex(
const pt = sema.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
- try union_ty.resolveFields(pt);
const union_obj = zcu.typeToUnion(union_ty).?;
- const field_index = union_obj.loadTagType(ip).nameIndex(ip, field_name) orelse
+ const enum_obj = ip.loadEnumType(union_obj.enum_tag_type);
+ const field_index = enum_obj.nameIndex(ip, field_name) orelse
return sema.failWithBadUnionFieldAccess(block, union_ty, union_obj, field_src, field_name);
return @intCast(field_index);
}
+/// Asserts that the layout of `struct_ty` is already resolved.
fn structFieldIndex(
sema: *Sema,
block: *Block,
@@ -36424,7 +33370,6 @@ fn structFieldIndex(
const pt = sema.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
- try struct_ty.resolveFields(pt);
const struct_type = zcu.typeToStruct(struct_ty).?;
return struct_type.nameIndex(ip, field_name) orelse
return sema.failWithBadStructFieldAccess(block, struct_ty, struct_type, field_src, field_name);
@@ -36509,102 +33454,25 @@ fn intFromFloatScalar(
return pt.getCoerced(cti_result, int_ty);
}
-/// Asserts the value is an integer, and the destination type is ComptimeInt or Int.
-/// Vectors are also accepted. Vector results are reduced with AND.
-///
-/// If provided, `vector_index` reports the first element that failed the range check.
-fn intFitsInType(
- sema: *Sema,
- val: Value,
- ty: Type,
- vector_index: ?*usize,
-) CompileError!bool {
- const pt = sema.pt;
- const zcu = pt.zcu;
- if (ty.toIntern() == .comptime_int_type) return true;
- const info = ty.intInfo(zcu);
- switch (val.toIntern()) {
- .zero_usize, .zero_u8 => return true,
- else => switch (zcu.intern_pool.indexToKey(val.toIntern())) {
- .undef => return true,
- .variable, .@"extern", .func, .ptr => {
- const target = zcu.getTarget();
- const ptr_bits = target.ptrBitWidth();
- return switch (info.signedness) {
- .signed => info.bits > ptr_bits,
- .unsigned => info.bits >= ptr_bits,
- };
- },
- .int => |int| switch (int.storage) {
- .u64, .i64, .big_int => {
- var buffer: InternPool.Key.Int.Storage.BigIntSpace = undefined;
- const big_int = int.storage.toBigInt(&buffer);
- return big_int.fitsInTwosComp(info.signedness, info.bits);
- },
- .lazy_align => |lazy_ty| {
- const max_needed_bits = @as(u16, 16) + @intFromBool(info.signedness == .signed);
- // If it is u16 or bigger we know the alignment fits without resolving it.
- if (info.bits >= max_needed_bits) return true;
- const x = try Type.fromInterned(lazy_ty).abiAlignmentSema(pt);
- if (x == .none) return true;
- const actual_needed_bits = @as(usize, x.toLog2Units()) + 1 + @intFromBool(info.signedness == .signed);
- return info.bits >= actual_needed_bits;
- },
- .lazy_size => |lazy_ty| {
- const max_needed_bits = @as(u16, 64) + @intFromBool(info.signedness == .signed);
- // If it is u64 or bigger we know the size fits without resolving it.
- if (info.bits >= max_needed_bits) return true;
- const x = try Type.fromInterned(lazy_ty).abiSizeSema(pt);
- if (x == 0) return true;
- const actual_needed_bits = std.math.log2(x) + 1 + @intFromBool(info.signedness == .signed);
- return info.bits >= actual_needed_bits;
- },
- },
- .aggregate => |aggregate| {
- assert(ty.zigTypeTag(zcu) == .vector);
- return switch (aggregate.storage) {
- .bytes => |bytes| for (bytes.toSlice(ty.vectorLen(zcu), &zcu.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;
- if (vector_index) |vi| vi.* = i;
- break false;
- } else true,
- .elems, .repeated_elem => for (switch (aggregate.storage) {
- .bytes => unreachable,
- .elems => |elems| elems,
- .repeated_elem => |elem| @as(*const [1]InternPool.Index, &elem),
- }, 0..) |elem, i| {
- if (try sema.intFitsInType(Value.fromInterned(elem), ty.scalarType(zcu), null)) continue;
- if (vector_index) |vi| vi.* = i;
- break false;
- } else true,
- };
- },
- else => unreachable,
- },
- }
-}
-
fn intInRange(sema: *Sema, tag_ty: Type, int_val: Value, end: usize) !bool {
const pt = sema.pt;
- if (!(try int_val.compareAllWithZeroSema(.gte, pt))) return false;
+ if (!int_val.compareAllWithZero(.gte, pt.zcu)) return false;
const end_val = try pt.intValue(tag_ty, end);
if (!(try sema.compareAll(int_val, .lt, end_val, tag_ty))) return false;
return true;
}
-/// Asserts the type is an enum.
+/// Asserts the type is an exhaustive enum.
fn enumHasInt(sema: *Sema, ty: Type, int: Value) CompileError!bool {
const pt = sema.pt;
const zcu = pt.zcu;
const enum_type = zcu.intern_pool.loadEnumType(ty.toIntern());
- assert(enum_type.tag_mode != .nonexhaustive);
+ assert(!enum_type.nonexhaustive);
// The `tagValueIndex` function call below relies on the type being the integer tag type.
// `getCoerced` assumes the value will fit the new type.
- if (!(try sema.intFitsInType(int, .fromInterned(enum_type.tag_ty), null))) return false;
- const int_coerced = try pt.getCoerced(int, .fromInterned(enum_type.tag_ty));
-
+ const int_tag_ty: Type = .fromInterned(enum_type.int_tag_type);
+ if (!int.intFitsInType(int_tag_ty, null, zcu)) return false;
+ const int_coerced = try pt.getCoerced(int, int_tag_ty);
return enum_type.tagValueIndex(&zcu.intern_pool, int_coerced.toIntern()) != null;
}
@@ -36644,17 +33512,19 @@ fn compareScalar(
ty: Type,
) CompileError!bool {
const pt = sema.pt;
+ const zcu = pt.zcu;
+
const coerced_lhs = try pt.getCoerced(lhs, ty);
const coerced_rhs = try pt.getCoerced(rhs, ty);
// Equality comparisons of signed zero and NaN need to use floating point semantics
- if (coerced_lhs.isFloat(pt.zcu) or coerced_rhs.isFloat(pt.zcu))
- return Value.compareHeteroSema(coerced_lhs, op, coerced_rhs, pt);
+ if (coerced_lhs.isFloat(zcu) or coerced_rhs.isFloat(zcu))
+ return Value.compareHetero(coerced_lhs, op, coerced_rhs, zcu);
switch (op) {
- .eq => return sema.valuesEqual(coerced_lhs, coerced_rhs, ty),
- .neq => return !(try sema.valuesEqual(coerced_lhs, coerced_rhs, ty)),
- else => return Value.compareHeteroSema(coerced_lhs, op, coerced_rhs, pt),
+ .eq => return Value.eql(coerced_lhs, coerced_rhs, ty, zcu),
+ .neq => return !Value.eql(coerced_lhs, coerced_rhs, ty, zcu),
+ else => return Value.compareHetero(coerced_lhs, op, coerced_rhs, zcu),
}
}
@@ -36716,25 +33586,6 @@ fn errorSetMerge(sema: *Sema, lhs: Type, rhs: Type) !Type {
return pt.errorSetFromUnsortedNames(names.keys());
}
-/// Avoids crashing the compiler when asking if inferred allocations are noreturn.
-fn isNoReturn(sema: *Sema, ref: Air.Inst.Ref) bool {
- if (ref == .unreachable_value) return true;
- if (ref.toIndex()) |inst| switch (sema.air_instructions.items(.tag)[@intFromEnum(inst)]) {
- .inferred_alloc, .inferred_alloc_comptime => return false,
- else => {},
- };
- return sema.typeOf(ref).isNoReturn(sema.pt.zcu);
-}
-
-/// Avoids crashing the compiler when asking if inferred allocations are known to be a certain zig type.
-fn isKnownZigType(sema: *Sema, ref: Air.Inst.Ref, tag: std.builtin.TypeId) bool {
- if (ref.toIndex()) |inst| switch (sema.air_instructions.items(.tag)[@intFromEnum(inst)]) {
- .inferred_alloc, .inferred_alloc_comptime => return false,
- else => {},
- };
- return sema.typeOf(ref).zigTypeTag(sema.pt.zcu) == tag;
-}
-
pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void {
const pt = sema.pt;
if (!pt.zcu.comp.config.incremental) return;
@@ -36742,23 +33593,6 @@ pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void {
const gop = try sema.dependencies.getOrPut(sema.gpa, dependee);
if (gop.found_existing) return;
- // Avoid creating dependencies on ourselves. This situation can arise when we analyze the fields
- // of a type and they use `@This()`. This dependency would be unnecessary, and in fact would
- // just result in over-analysis since `Zcu.findOutdatedToAnalyze` would never be able to resolve
- // the loop.
- // Note that this also disallows a `nav_val`
- switch (sema.owner.unwrap()) {
- .nav_val => |this_nav| switch (dependee) {
- .nav_val => |other_nav| if (this_nav == other_nav) return,
- else => {},
- },
- .nav_ty => |this_nav| switch (dependee) {
- .nav_ty => |other_nav| if (this_nav == other_nav) return,
- else => {},
- },
- else => {},
- }
-
try pt.addDependency(sema.owner, dependee);
}
@@ -36799,7 +33633,7 @@ fn validateRuntimeValue(sema: *Sema, block: *Block, val_src: LazySrcLoc, val: Ai
});
}
-fn failWithContainsReferenceToComptimeVar(sema: *Sema, block: *Block, src: LazySrcLoc, value_name: InternPool.NullTerminatedString, kind_of_value: []const u8, val: ?Value) CompileError {
+pub fn failWithContainsReferenceToComptimeVar(sema: *Sema, block: *Block, src: LazySrcLoc, value_name: InternPool.NullTerminatedString, kind_of_value: []const u8, val: ?Value) CompileError {
return sema.failWithOwnedErrorMsg(block, msg: {
const msg = try sema.errMsg(src, "{s} contains reference to comptime var", .{kind_of_value});
errdefer msg.destroy(sema.gpa);
@@ -36867,11 +33701,7 @@ fn notePathToComptimeAllocPtr(
else => {}, // there will be another stage
}
- const derivation = comptime_ptr.pointerDerivationAdvanced(arena, pt, false, sema) catch |err| switch (err) {
- error.OutOfMemory => |e| return e,
- error.Canceled => @panic("TODO"), // pls don't be cancelable mlugg
- error.AnalysisFail => unreachable,
- };
+ const derivation = try comptime_ptr.pointerDerivation(arena, pt, sema);
var second_path_aw: std.Io.Writer.Allocating = .init(arena);
defer second_path_aw.deinit();
@@ -36983,7 +33813,6 @@ fn anyUndef(sema: *Sema, block: *Block, src: LazySrcLoc, val: Value) !bool {
const zcu = pt.zcu;
return switch (zcu.intern_pool.indexToKey(val.toIntern())) {
.undef => true,
- .simple_value => |v| v == .undefined,
.slice => {
// If the slice contents are runtime-known, reification will fail later on with a
// specific error message.
@@ -37058,12 +33887,12 @@ fn maybeDerefSliceAsArray(
else => unreachable,
};
const elem_ty = Type.fromInterned(slice.ty).childType(zcu);
- const len = try Value.fromInterned(slice.len).toUnsignedIntSema(pt);
+ const len = Value.fromInterned(slice.len).toUnsignedInt(zcu);
const array_ty = try pt.arrayType(.{
.child = elem_ty.toIntern(),
.len = len,
});
- const ptr_ty = try pt.ptrTypeSema(p: {
+ const ptr_ty = try pt.ptrType(p: {
var p = Type.fromInterned(slice.ty).ptrInfo(zcu);
p.flags.size = .one;
p.child = array_ty.toIntern();
@@ -37097,19 +33926,9 @@ pub fn flushExports(sema: *Sema) !void {
const zcu = sema.pt.zcu;
const gpa = zcu.gpa;
- // There may be existing exports. For instance, a struct may export
- // things during both field type resolution and field default resolution.
- //
- // So, pick up and delete any existing exports. This strategy performs
- // redundant work, but that's okay, because this case is exceedingly rare.
- if (zcu.single_exports.get(sema.owner)) |export_idx| {
- try sema.exports.append(gpa, export_idx.ptr(zcu).*);
- } else if (zcu.multi_exports.get(sema.owner)) |info| {
- try sema.exports.appendSlice(gpa, zcu.all_exports.items[info.index..][0..info.len]);
- }
- zcu.deleteUnitExports(sema.owner);
+ assert(!zcu.single_exports.contains(sema.owner));
+ assert(!zcu.multi_exports.contains(sema.owner));
- // `sema.exports` is completed; store the data into the `Zcu`.
if (sema.exports.items.len == 1) {
try zcu.single_exports.ensureUnusedCapacity(gpa, 1);
const export_idx: Zcu.Export.Index = zcu.free_exports.pop() orelse idx: {
@@ -37129,238 +33948,6 @@ pub fn flushExports(sema: *Sema) !void {
}
}
-/// Called as soon as a `declared` enum type is created.
-/// Resolves the tag type and field inits.
-/// Marks the `src_inst` dependency on the enum's declaration, so call sites need not do this.
-pub fn resolveDeclaredEnum(
- pt: Zcu.PerThread,
- wip_ty: InternPool.WipEnumType,
- inst: Zir.Inst.Index,
- tracked_inst: InternPool.TrackedInst.Index,
- namespace: InternPool.NamespaceIndex,
- type_name: InternPool.NullTerminatedString,
- small: Zir.Inst.EnumDecl.Small,
- body: []const Zir.Inst.Index,
- tag_type_ref: Zir.Inst.Ref,
- any_values: bool,
- fields_len: u32,
- zir: Zir,
- body_end: usize,
-) Zcu.SemaError!void {
- const zcu = pt.zcu;
- const gpa = zcu.gpa;
-
- const src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = LazySrcLoc.Offset.nodeOffset(.zero) };
-
- var arena: std.heap.ArenaAllocator = .init(gpa);
- defer arena.deinit();
-
- var comptime_err_ret_trace: std.array_list.Managed(Zcu.LazySrcLoc) = .init(gpa);
- defer comptime_err_ret_trace.deinit();
-
- var sema: Sema = .{
- .pt = pt,
- .gpa = gpa,
- .arena = arena.allocator(),
- .code = zir,
- .owner = .wrap(.{ .type = wip_ty.index }),
- .func_index = .none,
- .func_is_naked = false,
- .fn_ret_ty = .void,
- .fn_ret_ty_ies = null,
- .comptime_err_ret_trace = &comptime_err_ret_trace,
- };
- defer sema.deinit();
-
- if (zcu.comp.debugIncremental()) {
- const info = try zcu.incremental_debug_state.getUnitInfo(gpa, sema.owner);
- info.last_update_gen = zcu.generation;
- }
-
- try sema.declareDependency(.{ .src_hash = tracked_inst });
-
- var block: Block = .{
- .parent = null,
- .sema = &sema,
- .namespace = namespace,
- .instructions = .{},
- .inlining = null,
- .comptime_reason = .{ .reason = .{
- .src = src,
- .r = .{ .simple = .enum_field_values },
- } },
- .src_base_inst = tracked_inst,
- .type_name_ctx = type_name,
- };
- defer block.instructions.deinit(gpa);
-
- sema.resolveDeclaredEnumInner(
- &block,
- wip_ty,
- inst,
- tracked_inst,
- src,
- small,
- body,
- tag_type_ref,
- any_values,
- fields_len,
- zir,
- body_end,
- ) catch |err| switch (err) {
- error.ComptimeBreak => unreachable,
- error.ComptimeReturn => unreachable,
- error.OutOfMemory, error.Canceled => |e| return e,
- error.AnalysisFail => {
- if (!zcu.failed_analysis.contains(sema.owner)) {
- try zcu.transitive_failed_analysis.put(gpa, sema.owner, {});
- }
- return error.AnalysisFail;
- },
- };
-}
-
-fn resolveDeclaredEnumInner(
- sema: *Sema,
- block: *Block,
- wip_ty: InternPool.WipEnumType,
- inst: Zir.Inst.Index,
- tracked_inst: InternPool.TrackedInst.Index,
- src: LazySrcLoc,
- small: Zir.Inst.EnumDecl.Small,
- body: []const Zir.Inst.Index,
- tag_type_ref: Zir.Inst.Ref,
- any_values: bool,
- fields_len: u32,
- zir: Zir,
- body_end: usize,
-) Zcu.CompileError!void {
- const pt = sema.pt;
- const zcu = pt.zcu;
- const comp = zcu.comp;
- const gpa = comp.gpa;
- const io = comp.io;
- const ip = &zcu.intern_pool;
-
- const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
-
- const tag_ty_src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = .{ .node_offset_container_tag = .zero } };
-
- const int_tag_ty = ty: {
- if (body.len != 0) {
- _ = try sema.analyzeInlineBody(block, body, inst);
- }
-
- if (tag_type_ref != .none) {
- const ty = try sema.resolveType(block, tag_ty_src, tag_type_ref);
- if (ty.zigTypeTag(zcu) != .int and ty.zigTypeTag(zcu) != .comptime_int) {
- return sema.fail(block, tag_ty_src, "expected integer tag type, found '{f}'", .{ty.fmt(pt)});
- }
- break :ty ty;
- } else if (fields_len == 0) {
- break :ty try pt.intType(.unsigned, 0);
- } else {
- const bits = std.math.log2_int_ceil(usize, fields_len);
- break :ty try pt.intType(.unsigned, bits);
- }
- };
-
- wip_ty.setTagTy(ip, int_tag_ty.toIntern());
-
- var extra_index = body_end + bit_bags_count;
- var bit_bag_index: usize = body_end;
- var cur_bit_bag: u32 = undefined;
- var last_tag_val: ?Value = null;
- for (0..fields_len) |field_i_usize| {
- const field_i: u32 = @intCast(field_i_usize);
- if (field_i % 32 == 0) {
- cur_bit_bag = zir.extra[bit_bag_index];
- bit_bag_index += 1;
- }
- const has_tag_value = @as(u1, @truncate(cur_bit_bag)) != 0;
- cur_bit_bag >>= 1;
-
- const field_name_index: Zir.NullTerminatedString = @enumFromInt(zir.extra[extra_index]);
- const field_name_zir = zir.nullTerminatedString(field_name_index);
- extra_index += 1; // field name
-
- const field_name = try ip.getOrPutString(gpa, io, pt.tid, field_name_zir, .no_embedded_nulls);
-
- const value_src: LazySrcLoc = .{
- .base_node_inst = tracked_inst,
- .offset = .{ .container_field_value = field_i },
- };
-
- const tag_overflow = if (has_tag_value) overflow: {
- const tag_val_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]);
- extra_index += 1;
- const tag_inst = try sema.resolveInst(tag_val_ref);
- last_tag_val = try sema.resolveConstDefinedValue(block, .{
- .base_node_inst = tracked_inst,
- .offset = .{ .container_field_name = field_i },
- }, tag_inst, .{ .simple = .enum_field_tag_value });
- if (!(try sema.intFitsInType(last_tag_val.?, int_tag_ty, null))) break :overflow true;
- last_tag_val = try pt.getCoerced(last_tag_val.?, int_tag_ty);
- if (wip_ty.nextField(ip, field_name, last_tag_val.?.toIntern())) |conflict| {
- assert(conflict.kind == .value); // AstGen validated names are unique
- const other_field_src: LazySrcLoc = .{
- .base_node_inst = tracked_inst,
- .offset = .{ .container_field_value = conflict.prev_field_idx },
- };
- const msg = msg: {
- const msg = try sema.errMsg(value_src, "enum tag value {f} already taken", .{last_tag_val.?.fmtValueSema(pt, sema)});
- errdefer msg.destroy(gpa);
- try sema.errNote(other_field_src, msg, "other occurrence here", .{});
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(block, msg);
- }
- break :overflow false;
- } else if (any_values) overflow: {
- if (last_tag_val) |last_tag| {
- const result = try arith.incrementDefinedInt(sema, int_tag_ty, last_tag);
- last_tag_val = result.val;
- if (result.overflow) break :overflow true;
- } else {
- last_tag_val = try pt.intValue(int_tag_ty, 0);
- }
- if (wip_ty.nextField(ip, field_name, last_tag_val.?.toIntern())) |conflict| {
- assert(conflict.kind == .value); // AstGen validated names are unique
- const other_field_src: LazySrcLoc = .{
- .base_node_inst = tracked_inst,
- .offset = .{ .container_field_value = conflict.prev_field_idx },
- };
- const msg = msg: {
- const msg = try sema.errMsg(value_src, "enum tag value {f} already taken", .{last_tag_val.?.fmtValueSema(pt, sema)});
- errdefer msg.destroy(gpa);
- try sema.errNote(other_field_src, msg, "other occurrence here", .{});
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(block, msg);
- }
- break :overflow false;
- } else overflow: {
- assert(wip_ty.nextField(ip, field_name, .none) == null);
- last_tag_val = try pt.intValue(.comptime_int, field_i);
- if (!try sema.intFitsInType(last_tag_val.?, int_tag_ty, null)) break :overflow true;
- last_tag_val = try pt.getCoerced(last_tag_val.?, int_tag_ty);
- break :overflow false;
- };
-
- if (tag_overflow) {
- const msg = try sema.errMsg(value_src, "enumeration value '{f}' too large for type '{f}'", .{
- last_tag_val.?.fmtValueSema(pt, sema), int_tag_ty.fmt(pt),
- });
- return sema.failWithOwnedErrorMsg(block, msg);
- }
- }
- if (small.nonexhaustive and int_tag_ty.toIntern() != .comptime_int_type) {
- if (fields_len >= 1 and std.math.log2_int(u64, fields_len) == int_tag_ty.bitSize(zcu)) {
- return sema.fail(block, src, "non-exhaustive enum specifies every value", .{});
- }
- }
-}
-
pub const bitCastVal = @import("Sema/bitcast.zig").bitCast;
pub const bitCastSpliceVal = @import("Sema/bitcast.zig").bitCastSplice;
@@ -37369,6 +33956,10 @@ const ComptimeLoadResult = @import("Sema/comptime_ptr_access.zig").ComptimeLoadR
const storeComptimePtr = @import("Sema/comptime_ptr_access.zig").storeComptimePtr;
const ComptimeStoreResult = @import("Sema/comptime_ptr_access.zig").ComptimeStoreResult;
+pub const type_resolution = @import("Sema/type_resolution.zig");
+pub const ensureLayoutResolved = type_resolution.ensureLayoutResolved;
+pub const ensureStructDefaultsResolved = type_resolution.ensureStructDefaultsResolved;
+
pub fn getBuiltinType(sema: *Sema, src: LazySrcLoc, decl: Zcu.BuiltinDecl) SemaError!Type {
assert(decl.kind() == .type);
try sema.ensureMemoizedStateResolved(src, decl.stage());
@@ -37448,7 +34039,7 @@ pub fn resolveNavPtrModifiers(
};
}
-pub fn analyzeMemoizedState(sema: *Sema, block: *Block, simple_src: LazySrcLoc, builtin_namespace: InternPool.NamespaceIndex, stage: InternPool.MemoizedStateStage) CompileError!bool {
+pub fn analyzeMemoizedState(sema: *Sema, stage: InternPool.MemoizedStateStage) CompileError!bool {
const pt = sema.pt;
const zcu = pt.zcu;
const comp = zcu.comp;
@@ -37456,54 +34047,87 @@ pub fn analyzeMemoizedState(sema: *Sema, block: *Block, simple_src: LazySrcLoc,
const io = comp.io;
const ip = &zcu.intern_pool;
+ // This `Block` acts kind of like it's evaluating a `comptime` declaration in the root source
+ // file of the standard library. In particular, its namespace is the root std namespace.
+ var block: Block = block: {
+ // Get the main struct type of the root source file of `std`. No need for a reference entry
+ // because `std` is always an analysis root.
+ const std_file_index = zcu.module_roots.get(zcu.std_mod).?.unwrap().?;
+ try pt.ensureFilePopulated(std_file_index);
+ const std_type: Type = .fromInterned(zcu.fileRootType(std_file_index));
+ break :block .{
+ .parent = null,
+ .sema = sema,
+ .namespace = std_type.getNamespaceIndex(zcu),
+ .instructions = .empty,
+ .inlining = null,
+ .comptime_reason = null,
+ .src_base_inst = std_type.typeDeclInst(zcu).?,
+ .type_name_ctx = .empty,
+ };
+ };
+ defer block.instructions.deinit(gpa);
+
+ const std_builtin_ty: Type = ty: {
+ const std_src = block.nodeOffset(.zero);
+ const decl_name = try ip.getOrPutString(gpa, io, pt.tid, "builtin", .no_embedded_nulls);
+ const nav = try sema.namespaceLookup(&block, std_src, block.namespace, decl_name) orelse {
+ return sema.fail(&block, std_src, "'std' missing 'builtin'", .{});
+ };
+ const uncoerced_val = try sema.analyzeNavVal(&block, std_src, nav);
+ const decl_src: LazySrcLoc = .{
+ .base_node_inst = ip.getNav(nav).srcInst(ip),
+ .offset = .nodeOffset(.zero),
+ };
+ break :ty try sema.analyzeAsType(&block, decl_src, .std_builtin_decl, uncoerced_val);
+ };
+
var any_changed = false;
inline for (comptime std.enums.values(Zcu.BuiltinDecl)) |builtin_decl| {
if (stage == comptime builtin_decl.stage()) {
- const parent_ns: Zcu.Namespace.Index, const parent_name: []const u8, const name: []const u8 = switch (comptime builtin_decl.access()) {
- .direct => |name| .{ builtin_namespace, "std.builtin", name },
+ const parent_ns_ty: Type, const parent_name: []const u8, const name: []const u8 = switch (comptime builtin_decl.access()) {
+ .direct => |name| .{ std_builtin_ty, "std.builtin", name },
.nested => |nested| access: {
- const parent_ty: Type = .fromInterned(zcu.builtin_decl_values.get(nested[0]));
- const parent_ns = parent_ty.getNamespace(zcu).unwrap() orelse {
- return sema.fail(block, simple_src, "std.builtin.{s} is not a container type", .{@tagName(nested[0])});
- };
- break :access .{ parent_ns, "std.builtin." ++ @tagName(nested[0]), nested[1] };
+ const parent_decl, const name = nested;
+ const parent_ty: Type = .fromInterned(zcu.builtin_decl_values.get(parent_decl));
+ break :access .{ parent_ty, "std.builtin." ++ @tagName(parent_decl), name };
},
};
+ const parent_ns = parent_ns_ty.getNamespace(zcu).unwrap() orelse {
+ return sema.fail(&block, block.nodeOffset(.zero), "'{s}' is not a container type", .{parent_name});
+ };
+ const parent_ty_src = parent_ns_ty.srcLoc(zcu);
const name_nts = try ip.getOrPutString(gpa, io, pt.tid, name, .no_embedded_nulls);
- const nav = try sema.namespaceLookup(block, simple_src, parent_ns, name_nts) orelse
- return sema.fail(block, simple_src, "{s} missing {s}", .{ parent_name, name });
+ const nav = try sema.namespaceLookup(&block, parent_ty_src, parent_ns, name_nts) orelse {
+ return sema.fail(&block, parent_ty_src, "'{s}' missing '{s}'", .{ parent_name, name });
+ };
+ const uncoerced_val = try sema.analyzeNavVal(&block, parent_ty_src, nav);
- const src: LazySrcLoc = .{
+ const decl_src: LazySrcLoc = .{
.base_node_inst = ip.getNav(nav).srcInst(ip),
.offset = .nodeOffset(.zero),
};
- const result = try sema.analyzeNavVal(block, src, nav);
-
- const uncoerced_val = try sema.resolveConstDefinedValue(block, src, result, null);
- const maybe_lazy_val: Value = switch (builtin_decl.kind()) {
- .type => if (uncoerced_val.typeOf(zcu).zigTypeTag(zcu) != .type) {
- return sema.fail(block, src, "{s}.{s} is not a type", .{ parent_name, name });
- } else val: {
- try uncoerced_val.toType().resolveFully(pt);
- break :val uncoerced_val;
+ const val: Value = switch (builtin_decl.kind()) {
+ .type => val: {
+ const ty = try sema.analyzeAsType(&block, decl_src, .std_builtin_decl, uncoerced_val);
+ try sema.ensureLayoutResolved(ty, decl_src, .builtin_type);
+ break :val ty.toValue();
},
.func => val: {
const func_ty = try sema.getExpectedBuiltinFnType(builtin_decl);
- const coerced = try sema.coerce(block, func_ty, Air.internedToRef(uncoerced_val.toIntern()), src);
- break :val .fromInterned(coerced.toInterned().?);
+ const coerced = try sema.coerce(&block, func_ty, uncoerced_val, decl_src);
+ break :val try sema.resolveConstDefinedValue(&block, decl_src, coerced, .{ .simple = .std_builtin_decl });
},
.string => val: {
- const coerced = try sema.coerce(block, .slice_const_u8, Air.internedToRef(uncoerced_val.toIntern()), src);
- break :val .fromInterned(coerced.toInterned().?);
+ const coerced = try sema.coerce(&block, .slice_const_u8, uncoerced_val, decl_src);
+ break :val try sema.resolveConstDefinedValue(&block, decl_src, coerced, .{ .simple = .std_builtin_decl });
},
};
- const val = try sema.resolveLazyValue(maybe_lazy_val);
- const prev = zcu.builtin_decl_values.get(builtin_decl);
- if (val.toIntern() != prev) {
+ if (zcu.builtin_decl_values.get(builtin_decl) != val.toIntern()) {
zcu.builtin_decl_values.set(builtin_decl, val.toIntern());
any_changed = true;
}
@@ -37539,7 +34163,6 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ
=> try pt.funcType(.{
.param_types = &.{ .generic_poison_type, .generic_poison_type },
.return_type = .noreturn_type,
- .is_generic = true,
}),
// `fn (anyerror) noreturn`
@@ -37590,3 +34213,372 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ
else => unreachable,
};
}
+
+pub fn setTypeName(
+ sema: *Sema,
+ block: *Block,
+ wip: *const InternPool.WipContainerType,
+ name_strategy: Zir.Inst.NameStrategy,
+ anon_prefix: []const u8,
+ inst: Zir.Inst.Index,
+) CompileError!void {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
+ const comp = zcu.comp;
+ const gpa = comp.gpa;
+ const io = comp.io;
+ const ip = &zcu.intern_pool;
+
+ strat: switch (name_strategy) {
+ .anon => {
+ // It would be neat to have "struct:line:column" but this name has
+ // to survive incremental updates, where it may have been shifted down
+ // or up to a different line, but unchanged, and thus not unnecessarily
+ // semantically analyzed.
+ // TODO: that would be possible, by detecting line number changes and renaming
+ // types appropriately. However, `@typeName` becomes a problem then. If we remove
+ // that builtin from the language, we can consider this.
+ wip.setName(ip, try ip.getOrPutStringFmt(
+ gpa,
+ io,
+ pt.tid,
+ "{f}__{s}_{d}",
+ .{ block.type_name_ctx.fmt(ip), anon_prefix, @intFromEnum(wip.index) },
+ .no_embedded_nulls,
+ ), .none);
+ },
+ .parent => wip.setName(ip, block.type_name_ctx, sema.owner.unwrap().nav_val.toOptional()),
+ .func => {
+ const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip) orelse return error.AnalysisFail);
+ const zir_tags = sema.code.instructions.items(.tag);
+
+ var aw: std.Io.Writer.Allocating = .init(gpa);
+ defer aw.deinit();
+ const w = &aw.writer;
+ w.print("{f}(", .{block.type_name_ctx.fmt(ip)}) catch return error.OutOfMemory;
+
+ var arg_i: usize = 0;
+ for (fn_info.param_body) |zir_inst| switch (zir_tags[@intFromEnum(zir_inst)]) {
+ .param, .param_comptime, .param_anytype, .param_anytype_comptime => {
+ const arg = sema.inst_map.get(zir_inst).?;
+ // If this is being called in a generic function then analyzeCall will
+ // have already resolved the args and this will work.
+ // If not then this is a struct type being returned from a non-generic
+ // function and the name doesn't matter since it will later
+ // result in a compile error.
+ const arg_val = sema.resolveValue(arg) orelse {
+ continue :strat .anon;
+ };
+
+ if (arg_i != 0) w.writeByte(',') catch return error.OutOfMemory;
+
+ // Limiting the depth here helps avoid type names getting too long, which
+ // in turn helps to avoid unreasonably long symbol names for namespaced
+ // symbols. Such names should ideally be human-readable, and additionally,
+ // some tooling may not support very long symbol names.
+ w.print("{f}", .{Value.fmtValueSemaFull(.{
+ .val = arg_val,
+ .pt = pt,
+ .opt_sema = sema,
+ .depth = 1,
+ })}) catch return error.OutOfMemory;
+
+ arg_i += 1;
+ continue;
+ },
+ else => continue,
+ };
+
+ w.writeByte(')') catch return error.OutOfMemory;
+ const name = try ip.getOrPutString(gpa, io, pt.tid, aw.written(), .no_embedded_nulls);
+ wip.setName(ip, name, .none);
+ },
+ .dbg_var => {
+ // TODO: this logic is questionable. We ideally should be traversing the `Block` rather than relying on the order of AstGen instructions.
+ const ref = inst.toRef();
+ const zir_tags = sema.code.instructions.items(.tag);
+ const zir_data = sema.code.instructions.items(.data);
+ const var_name = for (@intFromEnum(inst)..zir_tags.len) |i| switch (zir_tags[i]) {
+ .dbg_var_ptr, .dbg_var_val => if (zir_data[i].str_op.operand == ref) {
+ break zir_data[i].str_op.getStr(sema.code);
+ },
+ else => {},
+ } else {
+ continue :strat .anon;
+ };
+ const name = try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}.{s}", .{
+ block.type_name_ctx.fmt(ip), var_name,
+ }, .no_embedded_nulls);
+ wip.setName(ip, name, .none);
+ },
+ }
+}
+
+fn zirStructDecl(
+ sema: *Sema,
+ block: *Block,
+ inst: Zir.Inst.Index,
+) CompileError!Air.Inst.Ref {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
+ const comp = zcu.comp;
+ const gpa = comp.gpa;
+ const io = comp.io;
+ const ip = &zcu.intern_pool;
+
+ const tracked_inst = try block.trackZir(inst);
+
+ const src: LazySrcLoc = .{
+ .base_node_inst = tracked_inst,
+ .offset = .nodeOffset(.zero),
+ };
+
+ const struct_decl = sema.code.getStructDecl(inst);
+
+ const captures = try sema.getCaptures(block, src, struct_decl.captures, struct_decl.capture_names);
+
+ const ty: Type = switch (try ip.getDeclaredStructType(gpa, io, pt.tid, .{
+ .zir_index = tracked_inst,
+ .captures = captures,
+ .fields_len = @intCast(struct_decl.field_names.len),
+ .layout = struct_decl.layout,
+ .any_comptime_fields = struct_decl.field_comptime_bits != null,
+ .any_field_defaults = struct_decl.field_default_body_lens != null,
+ .any_field_aligns = struct_decl.field_align_body_lens != null,
+ .packed_backing_mode = if (struct_decl.backing_int_type_body != null) .explicit else .auto,
+ })) {
+ .existing => |ty| .fromInterned(ty),
+ .wip => |wip| ty: {
+ errdefer wip.cancel(ip, pt.tid);
+ try sema.setTypeName(block, &wip, struct_decl.name_strategy, "struct", inst);
+ const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
+ .parent = block.namespace.toOptional(),
+ .owner_type = wip.index,
+ .file_scope = block.getFileScopeIndex(zcu),
+ .generation = zcu.generation,
+ });
+ errdefer pt.destroyNamespace(new_namespace_index);
+ try pt.scanNamespace(new_namespace_index, struct_decl.decls);
+ if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
+ break :ty .fromInterned(wip.finish(ip, new_namespace_index));
+ },
+ };
+
+ try sema.addTypeReferenceEntry(src, ty);
+ try pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu));
+
+ return .fromType(ty);
+}
+fn zirUnionDecl(
+ sema: *Sema,
+ block: *Block,
+ inst: Zir.Inst.Index,
+) CompileError!Air.Inst.Ref {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
+ const comp = zcu.comp;
+ const gpa = comp.gpa;
+ const io = comp.io;
+ const ip = &zcu.intern_pool;
+
+ const tracked_inst = try block.trackZir(inst);
+
+ const src: LazySrcLoc = .{
+ .base_node_inst = tracked_inst,
+ .offset = .nodeOffset(.zero),
+ };
+
+ const union_decl = sema.code.getUnionDecl(inst);
+
+ const captures = try sema.getCaptures(block, src, union_decl.captures, union_decl.capture_names);
+
+ const ty: Type = switch (try ip.getDeclaredUnionType(gpa, io, pt.tid, .{
+ .zir_index = tracked_inst,
+ .captures = captures,
+ .fields_len = @intCast(union_decl.field_names.len),
+ .layout = union_decl.kind.layout(),
+ .any_field_aligns = union_decl.field_align_body_lens != null,
+ .tag_usage = switch (union_decl.kind) {
+ .auto => if (block.wantSafeTypes()) .safety else .none,
+
+ .tagged_explicit,
+ .tagged_enum,
+ .tagged_enum_explicit,
+ => .tagged,
+
+ .@"extern",
+ .@"packed",
+ .packed_explicit,
+ => .none,
+ },
+ .enum_tag_mode = switch (union_decl.kind) {
+ .tagged_explicit => .explicit,
+ else => .auto,
+ },
+ .packed_backing_mode = switch (union_decl.kind) {
+ .packed_explicit => .explicit,
+ else => .auto,
+ },
+ })) {
+ .existing => |ty| .fromInterned(ty),
+ .wip => |wip| ty: {
+ errdefer wip.cancel(ip, pt.tid);
+ try sema.setTypeName(block, &wip, union_decl.name_strategy, "union", inst);
+ const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
+ .parent = block.namespace.toOptional(),
+ .owner_type = wip.index,
+ .file_scope = block.getFileScopeIndex(zcu),
+ .generation = zcu.generation,
+ });
+ errdefer pt.destroyNamespace(new_namespace_index);
+ try pt.scanNamespace(new_namespace_index, union_decl.decls);
+ if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
+ break :ty .fromInterned(wip.finish(ip, new_namespace_index));
+ },
+ };
+
+ try sema.addTypeReferenceEntry(src, ty);
+ try pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu));
+
+ return .fromType(ty);
+}
+fn zirEnumDecl(
+ sema: *Sema,
+ block: *Block,
+ inst: Zir.Inst.Index,
+) CompileError!Air.Inst.Ref {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
+ const comp = zcu.comp;
+ const gpa = comp.gpa;
+ const io = comp.io;
+ const ip = &zcu.intern_pool;
+
+ const tracked_inst = try block.trackZir(inst);
+
+ const src: LazySrcLoc = .{
+ .base_node_inst = tracked_inst,
+ .offset = .nodeOffset(.zero),
+ };
+
+ const enum_decl = sema.code.getEnumDecl(inst);
+
+ const captures = try sema.getCaptures(block, src, enum_decl.captures, enum_decl.capture_names);
+
+ const ty: Type = switch (try ip.getDeclaredEnumType(gpa, io, pt.tid, .{
+ .zir_index = tracked_inst,
+ .captures = captures,
+ .fields_len = @intCast(enum_decl.field_names.len),
+ .nonexhaustive = enum_decl.nonexhaustive,
+ .int_tag_mode = if (enum_decl.tag_type_body != null) .explicit else .auto,
+ })) {
+ .existing => |ty| .fromInterned(ty),
+ .wip => |wip| ty: {
+ errdefer wip.cancel(ip, pt.tid);
+ try sema.setTypeName(block, &wip, enum_decl.name_strategy, "enum", inst);
+ const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
+ .parent = block.namespace.toOptional(),
+ .owner_type = wip.index,
+ .file_scope = block.getFileScopeIndex(zcu),
+ .generation = zcu.generation,
+ });
+ errdefer pt.destroyNamespace(new_namespace_index);
+ try pt.scanNamespace(new_namespace_index, enum_decl.decls);
+ if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
+ break :ty .fromInterned(wip.finish(ip, new_namespace_index));
+ },
+ };
+
+ try sema.addTypeReferenceEntry(src, ty);
+ try pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu));
+
+ return .fromType(ty);
+}
+fn zirOpaqueDecl(
+ sema: *Sema,
+ block: *Block,
+ inst: Zir.Inst.Index,
+) CompileError!Air.Inst.Ref {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
+ const comp = zcu.comp;
+ const gpa = comp.gpa;
+ const io = comp.io;
+ const ip = &zcu.intern_pool;
+
+ const tracked_inst = try block.trackZir(inst);
+
+ const src: LazySrcLoc = .{
+ .base_node_inst = tracked_inst,
+ .offset = .nodeOffset(.zero),
+ };
+
+ const opaque_decl = sema.code.getOpaqueDecl(inst);
+
+ const captures = try sema.getCaptures(block, src, opaque_decl.captures, opaque_decl.capture_names);
+
+ const ty: Type = switch (try ip.getDeclaredOpaqueType(gpa, io, pt.tid, .{
+ .zir_index = tracked_inst,
+ .captures = captures,
+ })) {
+ .existing => |ty| .fromInterned(ty),
+ .wip => |wip| ty: {
+ errdefer wip.cancel(ip, pt.tid);
+ try sema.setTypeName(block, &wip, opaque_decl.name_strategy, "opaque", inst);
+ const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
+ .parent = block.namespace.toOptional(),
+ .owner_type = wip.index,
+ .file_scope = block.getFileScopeIndex(zcu),
+ .generation = zcu.generation,
+ });
+ errdefer pt.destroyNamespace(new_namespace_index);
+ try pt.scanNamespace(new_namespace_index, opaque_decl.decls);
+ if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
+ break :ty .fromInterned(wip.finish(ip, new_namespace_index));
+ },
+ };
+
+ try sema.addTypeReferenceEntry(src, ty);
+ try pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu));
+
+ return .fromType(ty);
+}
+
+/// Registers an error indicating a dependency loop: we have introduced a dependency on `want` (with
+/// reason `want_reason`) but have learnt that `want` is already in `zcu.analysis_in_progress`.
+pub fn failWithDependencyLoop(
+ sema: *Sema,
+ want: AnalUnit,
+ want_reason: *const Zcu.DependencyReason,
+) SemaError {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
+ const gpa = zcu.comp.gpa;
+
+ const in_progress_len = zcu.analysis_in_progress.count();
+ var index = zcu.analysis_in_progress.getIndex(want).? + 1;
+
+ try zcu.dependency_loops.ensureUnusedCapacity(gpa, 1);
+ try zcu.dependency_loop_nodes.ensureUnusedCapacity(gpa, in_progress_len - index + 1);
+
+ zcu.dependency_loops.putAssumeCapacityNoClobber(want, {});
+
+ while (index <= in_progress_len) : (index += 1) {
+ const parent_unit = zcu.analysis_in_progress.keys()[index - 1];
+ const unit, const reason = if (index == in_progress_len) .{
+ want,
+ want_reason,
+ } else .{
+ zcu.analysis_in_progress.keys()[index],
+ zcu.analysis_in_progress.values()[index],
+ };
+
+ zcu.dependency_loop_nodes.putAssumeCapacityNoClobber(parent_unit, .{
+ .unit = unit,
+ .reason = reason.?.*,
+ });
+ }
+
+ // A dependency loop error will be reported. Mark us all as transitive failures.
+ return error.AnalysisFail;
+}
diff --git a/src/Sema/LowerZon.zig b/src/Sema/LowerZon.zig
index 76cf3d7f2cc05310e4402cc3fe43072d2a07fc59..2012d5167c2111f133aac6916d7aa6e697395f2a 100644
--- a/src/Sema/LowerZon.zig
+++ b/src/Sema/LowerZon.zig
@@ -129,84 +129,73 @@ fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!Inter
for (0..init.names.len) |i| {
elems[i] = try self.lowerExprAnonResTy(init.vals.at(@intCast(i)));
}
- const struct_ty = switch (try ip.getStructType(
- gpa,
- io,
- pt.tid,
- .{
- .layout = .auto,
- .fields_len = @intCast(init.names.len),
- .known_non_opv = false,
- .requires_comptime = .no,
- .any_comptime_fields = true,
- .any_default_inits = true,
- .inits_resolved = true,
- .any_aligned_fields = false,
- .key = .{ .reified = .{
- .zir_index = self.base_node_inst,
- .type_hash = hash: {
- var hasher: std.hash.Wyhash = .init(0);
- hasher.update(std.mem.asBytes(&node));
- hasher.update(std.mem.sliceAsBytes(elems));
- hasher.update(std.mem.sliceAsBytes(init.names));
- break :hash hasher.final();
- },
- } },
+ const struct_ty: Type = switch (try ip.getReifiedStructType(gpa, io, pt.tid, .{
+ .zir_index = self.base_node_inst,
+ .type_hash = hash: {
+ var hasher: std.hash.Wyhash = .init(0);
+ hasher.update(std.mem.asBytes(&node));
+ hasher.update(std.mem.sliceAsBytes(elems));
+ hasher.update(std.mem.sliceAsBytes(init.names));
+ break :hash hasher.final();
},
- false,
- )) {
+ .fields_len = @intCast(init.names.len),
+ .layout = .auto,
+ .any_comptime_fields = true,
+ .any_field_defaults = true,
+ .any_field_aligns = false,
+ .packed_backing_int_type = .none,
+ })) {
+ .existing => |ty| .fromInterned(ty),
.wip => |wip| ty: {
errdefer wip.cancel(ip, pt.tid);
- const type_name = try self.sema.createTypeName(
- self.block,
- .anon,
- "struct",
- self.base_node_inst.resolve(ip),
- wip.index,
- );
- wip.setName(ip, type_name.name, type_name.nav);
+ const block = self.block;
+ const zcu = pt.zcu;
+ try self.sema.setTypeName(block, &wip, .anon, "struct", self.base_node_inst.resolve(ip).?);
- const struct_type = ip.loadStructType(wip.index);
-
- for (init.names, 0..) |name, field_idx| {
- const name_interned = try ip.getOrPutString(
+ // Reified structs have field information populated immediately.
+ @memcpy(wip.field_values.get(ip), elems);
+ if (init.names.len > 0) {
+ // All fields are comptime, but unused bits remain zeroed.
+ const unused_bits = switch (init.names.len % 32) {
+ 0 => 0,
+ else => |n| 32 - n,
+ };
+ const comptime_bits = wip.field_is_comptime_bits.getAll(ip);
+ @memset(comptime_bits[0 .. comptime_bits.len - 1], std.math.maxInt(u32));
+ comptime_bits[comptime_bits.len - 1] = @as(u32, std.math.maxInt(u32)) >> @intCast(unused_bits);
+ }
+ for (
+ init.names,
+ wip.field_names.get(ip),
+ wip.field_types.get(ip),
+ wip.field_values.get(ip),
+ ) |zoir_name, *field_name, *field_ty, field_val| {
+ field_name.* = try ip.getOrPutString(
gpa,
io,
pt.tid,
- name.get(self.file.zoir.?),
+ zoir_name.get(self.file.zoir.?),
.no_embedded_nulls,
);
- assert(struct_type.addFieldName(ip, name_interned) == null);
- struct_type.setFieldComptime(ip, field_idx);
- }
-
- @memcpy(struct_type.field_inits.get(ip), elems);
- const types = struct_type.field_types.get(ip);
- for (0..init.names.len) |i| {
- types[i] = Value.fromInterned(elems[i]).typeOf(pt.zcu).toIntern();
+ field_ty.* = ip.typeOf(field_val);
}
const new_namespace_index = try pt.createNamespace(.{
- .parent = self.block.namespace.toOptional(),
+ .parent = block.namespace.toOptional(),
.owner_type = wip.index,
- .file_scope = self.block.getFileScopeIndex(pt.zcu),
- .generation = pt.zcu.generation,
+ .file_scope = block.getFileScopeIndex(zcu),
+ .generation = zcu.generation,
});
- try pt.zcu.comp.queueJob(.{ .resolve_type_fully = wip.index });
- codegen_type: {
- if (pt.zcu.comp.config.use_llvm) break :codegen_type;
- if (self.block.ownerModule().strip) break :codegen_type;
- pt.zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
- try pt.zcu.comp.queueJob(.{ .link_type = wip.index });
- }
- break :ty wip.finish(ip, new_namespace_index);
+ errdefer pt.destroyNamespace(new_namespace_index);
+ if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
+ break :ty .fromInterned(wip.finish(ip, new_namespace_index));
},
- .existing => |ty| ty,
};
- try self.sema.declareDependency(.{ .interned = struct_ty });
try self.sema.addTypeReferenceEntry(self.nodeSrc(node), struct_ty);
+ // No need for `ensureNamespaceUpToDate` because this type's namespace is always empty.
+ try self.sema.ensureLayoutResolved(struct_ty, self.nodeSrc(node), .init);
- return (try pt.aggregateValue(.fromInterned(struct_ty), elems)).toIntern();
+ return (try pt.aggregateValue(struct_ty, elems)).toIntern();
},
}
}
@@ -299,7 +288,7 @@ fn checkTypeInner(
} else {
const gop = try visited.getOrPut(sema.arena, ty.toIntern());
if (gop.found_existing) return;
- try ty.resolveFields(pt);
+ try sema.ensureLayoutResolved(ty, self.import_loc, .init);
const struct_info = zcu.typeToStruct(ty).?;
for (struct_info.field_types.get(ip)) |field_type| {
try self.checkTypeInner(.fromInterned(field_type), null, visited);
@@ -308,7 +297,7 @@ fn checkTypeInner(
.@"union" => {
const gop = try visited.getOrPut(sema.arena, ty.toIntern());
if (gop.found_existing) return;
- try ty.resolveFields(pt);
+ try sema.ensureLayoutResolved(ty, self.import_loc, .init);
const union_info = zcu.typeToUnion(ty).?;
for (union_info.field_types.get(ip)) |field_type| {
if (field_type != .void_type) {
@@ -645,6 +634,7 @@ fn lowerEnum(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.I
const gpa = comp.gpa;
const io = comp.io;
const ip = &pt.zcu.intern_pool;
+ try self.sema.ensureLayoutResolved(res_ty, self.import_loc, .init);
switch (node.get(self.file.zoir.?)) {
.enum_literal => |field_name| {
const field_name_interned = try ip.getOrPutString(
@@ -767,8 +757,8 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool
const io = comp.io;
const ip = &pt.zcu.intern_pool;
- try res_ty.resolveFields(self.sema.pt);
- try res_ty.resolveStructFieldInits(self.sema.pt);
+ try self.sema.ensureLayoutResolved(res_ty, self.import_loc, .init);
+ try self.sema.ensureStructDefaultsResolved(res_ty, self.import_loc);
const struct_info = self.sema.pt.zcu.typeToStruct(res_ty).?;
const fields: @FieldType(Zoir.Node, "struct_literal") = switch (node.get(self.file.zoir.?)) {
@@ -779,7 +769,7 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool
const field_values = try self.sema.arena.alloc(InternPool.Index, struct_info.field_names.len);
- const field_defaults = struct_info.field_inits.get(ip);
+ const field_defaults = struct_info.field_defaults.get(ip);
if (field_defaults.len > 0) {
@memcpy(field_values, field_defaults);
} else {
@@ -803,7 +793,7 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool
const field_type: Type = .fromInterned(struct_info.field_types.get(ip)[name_index]);
field_values[name_index] = try self.lowerExprKnownResTy(field_node, field_type);
- if (struct_info.comptime_bits.getBit(ip, name_index)) {
+ if (struct_info.field_is_comptime_bits.get(ip, name_index)) {
const val = ip.indexToKey(field_values[name_index]);
const default = ip.indexToKey(field_defaults[name_index]);
if (!val.eql(default, ip)) {
@@ -918,9 +908,9 @@ fn lowerUnion(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.
const gpa = comp.gpa;
const io = comp.io;
const ip = &pt.zcu.intern_pool;
- try res_ty.resolveFields(self.sema.pt);
- const union_info = self.sema.pt.zcu.typeToUnion(res_ty).?;
- const enum_tag_info = union_info.loadTagType(ip);
+ try self.sema.ensureLayoutResolved(res_ty, self.import_loc, .init);
+ const union_info = pt.zcu.typeToUnion(res_ty).?;
+ const enum_tag_info = ip.loadEnumType(union_info.enum_tag_type);
const field_name, const maybe_field_node = switch (node.get(self.file.zoir.?)) {
.enum_literal => |name| b: {
@@ -956,7 +946,7 @@ fn lowerUnion(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.
const name_index = enum_tag_info.nameIndex(ip, field_name) orelse {
return error.WrongType;
};
- const tag = try self.sema.pt.enumValueFieldIndex(.fromInterned(union_info.enum_tag_ty), name_index);
+ const tag = try self.sema.pt.enumValueFieldIndex(.fromInterned(union_info.enum_tag_type), name_index);
const field_type: Type = .fromInterned(union_info.field_types.get(ip)[name_index]);
const val = if (maybe_field_node) |field_node| b: {
if (field_type.toIntern() == .void_type) {
diff --git a/src/Sema/arith.zig b/src/Sema/arith.zig
index c646dc7b2167450ba54779bf2d83af6e0de86cc1..024fc5da62cfb75b87d2f822b3450e8a5f431241 100644
--- a/src/Sema/arith.zig
+++ b/src/Sema/arith.zig
@@ -20,6 +20,9 @@ pub fn incrementDefinedInt(
const zcu = pt.zcu;
assert(prev_val.typeOf(zcu).toIntern() == ty.toIntern());
assert(!prev_val.isUndef(zcu));
+ if (ty.intInfo(zcu).bits == 0) {
+ return .{ .overflow = true, .val = try comptimeIntAdd(sema, prev_val, .one_comptime_int) };
+ }
const res = try intAdd(sema, prev_val, try pt.intValue(ty, 1), ty);
return .{ .overflow = res.overflow, .val = res.val };
}
@@ -1053,7 +1056,7 @@ fn shlScalar(
if (rhs_val.isUndef(zcu)) return rhs_val;
},
}
- switch (try rhs_val.orderAgainstZeroSema(pt)) {
+ switch (Value.order(rhs_val, .zero_comptime_int, zcu)) {
.gt => {},
.eq => return lhs_val,
.lt => return sema.failWithNegativeShiftAmount(block, rhs_src, rhs_val, vec_idx),
@@ -1090,7 +1093,7 @@ fn shlWithOverflowScalar(
if (lhs_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, lhs_src, vec_idx);
if (rhs_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, rhs_src, vec_idx);
- switch (try rhs_val.orderAgainstZeroSema(pt)) {
+ switch (Value.order(rhs_val, .zero_comptime_int, zcu)) {
.gt => {},
.eq => return .{ .overflow_bit = .zero_u1, .wrapped_result = lhs_val },
.lt => return sema.failWithNegativeShiftAmount(block, rhs_src, rhs_val, vec_idx),
@@ -1169,7 +1172,7 @@ fn shrScalar(
if (lhs_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, lhs_src, vec_idx);
if (rhs_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, rhs_src, vec_idx);
- switch (try rhs_val.orderAgainstZeroSema(pt)) {
+ switch (Value.order(rhs_val, .zero_comptime_int, zcu)) {
.gt => {},
.eq => return lhs_val,
.lt => return sema.failWithNegativeShiftAmount(block, rhs_src, rhs_val, vec_idx),
@@ -1430,8 +1433,8 @@ fn intAddWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value
const info = ty.intInfo(zcu);
var lhs_space: Value.BigIntSpace = undefined;
var rhs_space: Value.BigIntSpace = undefined;
- const lhs_bigint = try lhs.toBigIntSema(&lhs_space, pt);
- const rhs_bigint = try rhs.toBigIntSema(&rhs_space, pt);
+ const lhs_bigint = lhs.toBigInt(&lhs_space, zcu);
+ const rhs_bigint = rhs.toBigInt(&rhs_space, zcu);
const limbs = try sema.arena.alloc(
std.math.big.Limb,
std.math.big.int.calcTwosCompLimbCount(info.bits),
@@ -1512,8 +1515,8 @@ fn intSubWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value
const info = ty.intInfo(zcu);
var lhs_space: Value.BigIntSpace = undefined;
var rhs_space: Value.BigIntSpace = undefined;
- const lhs_bigint = try lhs.toBigIntSema(&lhs_space, pt);
- const rhs_bigint = try rhs.toBigIntSema(&rhs_space, pt);
+ const lhs_bigint = lhs.toBigInt(&lhs_space, zcu);
+ const rhs_bigint = rhs.toBigInt(&rhs_space, zcu);
const limbs = try sema.arena.alloc(
std.math.big.Limb,
std.math.big.int.calcTwosCompLimbCount(info.bits),
@@ -1597,8 +1600,8 @@ fn intMulWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value
const info = ty.intInfo(zcu);
var lhs_space: Value.BigIntSpace = undefined;
var rhs_space: Value.BigIntSpace = undefined;
- const lhs_bigint = try lhs.toBigIntSema(&lhs_space, pt);
- const rhs_bigint = try rhs.toBigIntSema(&rhs_space, pt);
+ const lhs_bigint = lhs.toBigInt(&lhs_space, zcu);
+ const rhs_bigint = rhs.toBigInt(&rhs_space, zcu);
const limbs = try sema.arena.alloc(
std.math.big.Limb,
lhs_bigint.limbs.len + rhs_bigint.limbs.len,
@@ -1840,7 +1843,7 @@ fn intShl(
var lhs_space: Value.BigIntSpace = undefined;
const lhs_bigint = lhs.toBigInt(&lhs_space, zcu);
- const shift_amt: usize = @intCast(try rhs.toUnsignedIntSema(pt));
+ const shift_amt: usize = @intCast(rhs.toUnsignedInt(zcu));
if (shift_amt >= info.bits) {
return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs, rhs_src, vec_idx);
}
@@ -1862,7 +1865,7 @@ fn intShlSat(
const lhs_bigint = lhs.toBigInt(&lhs_space, zcu);
const shift_amt: usize = amt: {
- if (try rhs.getUnsignedIntSema(pt)) |shift_amt_u64| {
+ if (rhs.getUnsignedInt(zcu)) |shift_amt_u64| {
if (std.math.cast(usize, shift_amt_u64)) |shift_amt| break :amt shift_amt;
}
// We only support ints with up to 2^16 - 1 bits, so this
@@ -1895,9 +1898,9 @@ fn intShlWithOverflow(
const info = lhs_ty.intInfo(zcu);
var lhs_space: Value.BigIntSpace = undefined;
- const lhs_bigint = try lhs.toBigIntSema(&lhs_space, pt);
+ const lhs_bigint = lhs.toBigInt(&lhs_space, zcu);
- const shift_amt: usize = @intCast(try rhs.toUnsignedIntSema(pt));
+ const shift_amt: usize = @intCast(rhs.toUnsignedInt(zcu));
if (shift_amt >= info.bits) {
return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs, rhs_src, vec_idx);
}
@@ -1924,9 +1927,10 @@ fn comptimeIntShl(
vec_idx: ?usize,
) !Value {
const pt = sema.pt;
+ const zcu = pt.zcu;
var lhs_space: Value.BigIntSpace = undefined;
- const lhs_bigint = try lhs.toBigIntSema(&lhs_space, pt);
- if (try rhs.getUnsignedIntSema(pt)) |shift_amt_u64| {
+ const lhs_bigint = lhs.toBigInt(&lhs_space, zcu);
+ if (rhs.getUnsignedInt(zcu)) |shift_amt_u64| {
if (std.math.cast(usize, shift_amt_u64)) |shift_amt| {
const result_bigint = try intShlInner(sema, lhs_bigint, shift_amt);
return pt.intValue_big(.comptime_int, result_bigint.toConst());
@@ -1963,15 +1967,15 @@ fn intShr(
const lhs_bigint = lhs.toBigInt(&lhs_space, zcu);
const shift_amt: usize = if (rhs_ty.toIntern() == .comptime_int_type) amt: {
- if (try rhs.getUnsignedIntSema(pt)) |shift_amt_u64| {
+ if (rhs.getUnsignedInt(zcu)) |shift_amt_u64| {
if (std.math.cast(usize, shift_amt_u64)) |shift_amt| break :amt shift_amt;
}
- if (try rhs.compareAllWithZeroSema(.lt, pt)) {
+ if (rhs.compareAllWithZero(.lt, zcu)) {
return sema.failWithNegativeShiftAmount(block, rhs_src, rhs, vec_idx);
} else {
return sema.failWithUnsupportedComptimeShiftAmount(block, rhs_src, vec_idx);
}
- } else @intCast(try rhs.toUnsignedIntSema(pt));
+ } else @intCast(rhs.toUnsignedInt(zcu));
if (lhs_ty.toIntern() != .comptime_int_type and shift_amt >= lhs_ty.intInfo(zcu).bits) {
return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs, rhs_src, vec_idx);
@@ -2006,7 +2010,7 @@ fn intBitReverse(sema: *Sema, val: Value, ty: Type) !Value {
const info = ty.intInfo(zcu);
var val_space: Value.BigIntSpace = undefined;
- const val_bigint = try val.toBigIntSema(&val_space, pt);
+ const val_bigint = val.toBigInt(&val_space, zcu);
const limbs = try sema.arena.alloc(
std.math.big.Limb,
diff --git a/src/Sema/bitcast.zig b/src/Sema/bitcast.zig
index bc1859e51b4a60d58d628efef3c0158fc295aa6e..43456c218ba08f987b444d35b8ef5dc8ad053cb7 100644
--- a/src/Sema/bitcast.zig
+++ b/src/Sema/bitcast.zig
@@ -79,8 +79,8 @@ fn bitCastInner(
const val_ty = val.typeOf(zcu);
- try val_ty.resolveLayout(pt);
- try dest_ty.resolveLayout(pt);
+ val_ty.assertHasLayout(zcu);
+ dest_ty.assertHasLayout(zcu);
assert(val_ty.hasWellDefinedLayout(zcu));
@@ -138,8 +138,8 @@ fn bitCastSpliceInner(
const val_ty = val.typeOf(zcu);
const splice_val_ty = splice_val.typeOf(zcu);
- try val_ty.resolveLayout(pt);
- try splice_val_ty.resolveLayout(pt);
+ val_ty.assertHasLayout(zcu);
+ splice_val_ty.assertHasLayout(zcu);
const splice_bits = splice_val_ty.bitSize(zcu);
@@ -267,12 +267,13 @@ const UnpackValueBits = struct {
.int,
.enum_tag,
.simple_value,
- .empty_enum_value,
.float,
.ptr,
.opt,
=> try unpack.primitive(val),
+ .bitpack => |bitpack| try unpack.primitive(.fromInterned(bitpack.backing_int_val)),
+
.aggregate => switch (ty.zigTypeTag(zcu)) {
.vector => {
const len: usize = @intCast(ty.arrayLen(zcu));
@@ -443,7 +444,7 @@ const UnpackValueBits = struct {
// This @intCast is okay because no primitive can exceed the size of a u16.
const int_ty = try unpack.pt.intType(.unsigned, @intCast(bit_count));
const buf = try unpack.arena.alloc(u8, @intCast((val_bits + 7) / 8));
- try val.writeToPackedMemory(ty, unpack.pt, buf, 0);
+ try val.writeToPackedMemory(unpack.pt, buf, 0);
const sub_val = try Value.readFromPackedMemory(int_ty, unpack.pt, buf, @intCast(bit_offset), unpack.arena);
try unpack.primitive(sub_val);
},
@@ -451,7 +452,6 @@ const UnpackValueBits = struct {
// The only values here with runtime bits are `true` and `false.
// These are both 1 bit, so will never need truncating.
.simple_value => unreachable,
- .empty_enum_value => unreachable, // zero-bit
else => unreachable, // zero-bit or not primitives
}
}
@@ -565,102 +565,103 @@ const PackValueBits = struct {
return pt.aggregateValue(ty, elems);
},
.@"packed" => {
- // All fields are in order with no padding.
- // This is identical between LE and BE targets.
- const elems = try arena.alloc(InternPool.Index, ty.structFieldCount(zcu));
- for (elems, 0..) |*elem, i| {
- const field_ty = ty.fieldType(i, zcu);
- elem.* = (try pack.get(field_ty)).toIntern();
- }
- return pt.aggregateValue(ty, elems);
+ const backing_int_val = try pack.primitive(ty.bitpackBackingInt(zcu));
+ return pt.bitpackValue(ty, backing_int_val);
},
},
- .@"union" => {
- // We will attempt to read as the backing representation. If this emits
- // `error.ReinterpretDeclRef`, we will try each union field, preferring larger ones.
- // We will also attempt smaller fields when we get `undefined`, as if some bits are
- // defined we want to include them.
- // TODO: this is very very bad. We need a more sophisticated union representation.
+ .@"union" => switch (ty.containerLayout(zcu)) {
+ .auto => unreachable, // ill-defined layout
+ .@"extern" => {
+ // We will attempt to read as the backing representation. If this emits
+ // `error.ReinterpretDeclRef`, we will try each union field, preferring larger ones.
+ // We will also attempt smaller fields when we get `undefined`, as if some bits are
+ // defined we want to include them.
+ // TODO: this is very very bad. We need a more sophisticated union representation.
- const prev_unpacked = pack.unpacked;
- const prev_bit_offset = pack.bit_offset;
+ const prev_unpacked = pack.unpacked;
+ const prev_bit_offset = pack.bit_offset;
- const backing_ty = try ty.unionBackingType(pt);
+ const backing_ty = try ty.externUnionBackingType(pt);
- backing: {
- const backing_val = pack.get(backing_ty) catch |err| switch (err) {
- error.ReinterpretDeclRef => {
+ backing: {
+ const backing_val = pack.get(backing_ty) catch |err| switch (err) {
+ error.ReinterpretDeclRef => {
+ pack.unpacked = prev_unpacked;
+ pack.bit_offset = prev_bit_offset;
+ break :backing;
+ },
+ else => |e| return e,
+ };
+ if (backing_val.isUndef(zcu)) {
pack.unpacked = prev_unpacked;
pack.bit_offset = prev_bit_offset;
break :backing;
- },
- else => |e| return e,
+ }
+ return Value.fromInterned(try pt.internUnion(.{
+ .ty = ty.toIntern(),
+ .tag = .none,
+ .val = backing_val.toIntern(),
+ }));
+ }
+
+ const field_order = try pack.arena.alloc(u32, ty.unionTagTypeHypothetical(zcu).enumFieldCount(zcu));
+ for (field_order, 0..) |*f, i| f.* = @intCast(i);
+ // Sort `field_order` to put the fields with the largest bit sizes first.
+ const SizeSortCtx = struct {
+ zcu: *Zcu,
+ field_types: []const InternPool.Index,
+ fn lessThan(ctx: @This(), a_idx: u32, b_idx: u32) bool {
+ const a_ty = Type.fromInterned(ctx.field_types[a_idx]);
+ const b_ty = Type.fromInterned(ctx.field_types[b_idx]);
+ return a_ty.bitSize(ctx.zcu) > b_ty.bitSize(ctx.zcu);
+ }
};
- if (backing_val.isUndef(zcu)) {
- pack.unpacked = prev_unpacked;
- pack.bit_offset = prev_bit_offset;
- break :backing;
+ std.mem.sortUnstable(u32, field_order, SizeSortCtx{
+ .zcu = zcu,
+ .field_types = zcu.typeToUnion(ty).?.field_types.get(ip),
+ }, SizeSortCtx.lessThan);
+
+ const padding_after = endian == .little or ty.containerLayout(zcu) == .@"packed";
+
+ for (field_order) |field_idx| {
+ const field_ty = Type.fromInterned(zcu.typeToUnion(ty).?.field_types.get(ip)[field_idx]);
+ const pad_bits = ty.bitSize(zcu) - field_ty.bitSize(zcu);
+ if (!padding_after) try pack.padding(pad_bits);
+ const field_val = pack.get(field_ty) catch |err| switch (err) {
+ error.ReinterpretDeclRef => {
+ pack.unpacked = prev_unpacked;
+ pack.bit_offset = prev_bit_offset;
+ continue;
+ },
+ else => |e| return e,
+ };
+ if (padding_after) try pack.padding(pad_bits);
+ if (field_val.isUndef(zcu)) {
+ pack.unpacked = prev_unpacked;
+ pack.bit_offset = prev_bit_offset;
+ continue;
+ }
+ const tag_val = try pt.enumValueFieldIndex(ty.unionTagTypeHypothetical(zcu), field_idx);
+ return Value.fromInterned(try pt.internUnion(.{
+ .ty = ty.toIntern(),
+ .tag = tag_val.toIntern(),
+ .val = field_val.toIntern(),
+ }));
}
+
+ // No field could represent the value. Just do whatever happens when we try to read
+ // the backing type - either `undefined` or `error.ReinterpretDeclRef`.
+ const backing_val = try pack.get(backing_ty);
return Value.fromInterned(try pt.internUnion(.{
.ty = ty.toIntern(),
.tag = .none,
.val = backing_val.toIntern(),
}));
- }
-
- const field_order = try pack.arena.alloc(u32, ty.unionTagTypeHypothetical(zcu).enumFieldCount(zcu));
- for (field_order, 0..) |*f, i| f.* = @intCast(i);
- // Sort `field_order` to put the fields with the largest bit sizes first.
- const SizeSortCtx = struct {
- zcu: *Zcu,
- field_types: []const InternPool.Index,
- fn lessThan(ctx: @This(), a_idx: u32, b_idx: u32) bool {
- const a_ty = Type.fromInterned(ctx.field_types[a_idx]);
- const b_ty = Type.fromInterned(ctx.field_types[b_idx]);
- return a_ty.bitSize(ctx.zcu) > b_ty.bitSize(ctx.zcu);
- }
- };
- std.mem.sortUnstable(u32, field_order, SizeSortCtx{
- .zcu = zcu,
- .field_types = zcu.typeToUnion(ty).?.field_types.get(ip),
- }, SizeSortCtx.lessThan);
-
- const padding_after = endian == .little or ty.containerLayout(zcu) == .@"packed";
-
- for (field_order) |field_idx| {
- const field_ty = Type.fromInterned(zcu.typeToUnion(ty).?.field_types.get(ip)[field_idx]);
- const pad_bits = ty.bitSize(zcu) - field_ty.bitSize(zcu);
- if (!padding_after) try pack.padding(pad_bits);
- const field_val = pack.get(field_ty) catch |err| switch (err) {
- error.ReinterpretDeclRef => {
- pack.unpacked = prev_unpacked;
- pack.bit_offset = prev_bit_offset;
- continue;
- },
- else => |e| return e,
- };
- if (padding_after) try pack.padding(pad_bits);
- if (field_val.isUndef(zcu)) {
- pack.unpacked = prev_unpacked;
- pack.bit_offset = prev_bit_offset;
- continue;
- }
- const tag_val = try pt.enumValueFieldIndex(ty.unionTagTypeHypothetical(zcu), field_idx);
- return Value.fromInterned(try pt.internUnion(.{
- .ty = ty.toIntern(),
- .tag = tag_val.toIntern(),
- .val = field_val.toIntern(),
- }));
- }
-
- // No field could represent the value. Just do whatever happens when we try to read
- // the backing type - either `undefined` or `error.ReinterpretDeclRef`.
- const backing_val = try pack.get(backing_ty);
- return Value.fromInterned(try pt.internUnion(.{
- .ty = ty.toIntern(),
- .tag = .none,
- .val = backing_val.toIntern(),
- }));
+ },
+ .@"packed" => {
+ const backing_int_val = try pack.primitive(ty.bitpackBackingInt(zcu));
+ return pt.bitpackValue(ty, backing_int_val);
+ },
},
else => return pack.primitive(ty),
}
@@ -673,6 +674,9 @@ const PackValueBits = struct {
fn primitive(pack: *PackValueBits, want_ty: Type) BitCastError!Value {
const pt = pack.pt;
const zcu = pt.zcu;
+
+ if (try want_ty.onePossibleValue(pt)) |opv| return opv;
+
const vals, const bit_offset = pack.prepareBits(want_ty.bitSize(zcu));
for (vals) |val| {
@@ -719,7 +723,7 @@ const PackValueBits = struct {
const val = Value.fromInterned(ip_val);
const ty = val.typeOf(zcu);
if (!val.isUndef(zcu)) {
- try val.writeToPackedMemory(ty, pt, buf, cur_bit_off);
+ try val.writeToPackedMemory(pt, buf, cur_bit_off);
}
cur_bit_off += @intCast(ty.bitSize(zcu));
}
diff --git a/src/Sema/comptime_ptr_access.zig b/src/Sema/comptime_ptr_access.zig
index 4e101ecd0f962fa49a2aa73ac228ce6c6fe7e3c0..c74b5c2d75fab499c27a973584d3aa0748515a94 100644
--- a/src/Sema/comptime_ptr_access.zig
+++ b/src/Sema/comptime_ptr_access.zig
@@ -67,7 +67,7 @@ pub fn storeComptimePtr(
{
const store_ty: Type = .fromInterned(ptr_info.child);
- if (!try store_ty.comptimeOnlySema(pt) and !try store_ty.hasRuntimeBitsIgnoreComptimeSema(pt)) {
+ if (!store_ty.comptimeOnly(zcu) and !store_ty.hasRuntimeBits(zcu)) {
// zero-bit store; nothing to do
return .success;
}
@@ -354,8 +354,8 @@ fn loadComptimePtrInner(
const load_one_ty, const load_count = load_ty.arrayBase(zcu);
const extra_base_index: u64 = if (ptr.byte_offset == 0) 0 else idx: {
- if (try load_one_ty.comptimeOnlySema(pt)) break :restructure_array;
- const elem_len = try load_one_ty.abiSizeSema(pt);
+ if (load_one_ty.comptimeOnly(zcu)) break :restructure_array;
+ const elem_len = load_one_ty.abiSize(zcu);
if (ptr.byte_offset % elem_len != 0) break :restructure_array;
break :idx @divExact(ptr.byte_offset, elem_len);
};
@@ -401,12 +401,12 @@ fn loadComptimePtrInner(
var cur_offset = ptr.byte_offset;
if (load_ty.zigTypeTag(zcu) == .array and array_offset > 0) {
- cur_offset += try load_ty.childType(zcu).abiSizeSema(pt) * array_offset;
+ cur_offset += load_ty.childType(zcu).abiSize(zcu) * array_offset;
}
- const need_bytes = if (host_bits > 0) (host_bits + 7) / 8 else try load_ty.abiSizeSema(pt);
+ const need_bytes = if (host_bits > 0) (host_bits + 7) / 8 else load_ty.abiSize(zcu);
- if (cur_offset + need_bytes > try cur_val.typeOf(zcu).abiSizeSema(pt)) {
+ if (cur_offset + need_bytes > cur_val.typeOf(zcu).abiSize(zcu)) {
return .{ .out_of_bounds = cur_val.typeOf(zcu) };
}
@@ -441,7 +441,7 @@ fn loadComptimePtrInner(
.optional => break, // this can only be a pointer-like optional so is terminal
.array => {
const elem_ty = cur_ty.childType(zcu);
- const elem_size = try elem_ty.abiSizeSema(pt);
+ const elem_size = elem_ty.abiSize(zcu);
const elem_idx = cur_offset / elem_size;
const next_elem_off = elem_size * (elem_idx + 1);
if (cur_offset + need_bytes <= next_elem_off) {
@@ -457,7 +457,7 @@ fn loadComptimePtrInner(
.@"packed" => break, // let the bitcast logic handle this
.@"extern" => for (0..cur_ty.structFieldCount(zcu)) |field_idx| {
const start_off = cur_ty.structFieldOffset(field_idx, zcu);
- const end_off = start_off + try cur_ty.fieldType(field_idx, zcu).abiSizeSema(pt);
+ const end_off = start_off + cur_ty.fieldType(field_idx, zcu).abiSize(zcu);
if (cur_offset >= start_off and cur_offset + need_bytes <= end_off) {
cur_val = try cur_val.getElem(sema.pt, field_idx);
cur_offset -= start_off;
@@ -484,7 +484,7 @@ fn loadComptimePtrInner(
};
// The payload always has offset 0. If it's big enough
// to represent the whole load type, we can use it.
- if (try payload.typeOf(zcu).abiSizeSema(pt) >= need_bytes) {
+ if (payload.typeOf(zcu).abiSize(zcu) >= need_bytes) {
cur_val = payload;
} else {
break;
@@ -753,8 +753,8 @@ fn prepareComptimePtrStore(
const store_one_ty, const store_count = store_ty.arrayBase(zcu);
const extra_base_index: u64 = if (ptr.byte_offset == 0) 0 else idx: {
- if (try store_one_ty.comptimeOnlySema(pt)) break :restructure_array;
- const elem_len = try store_one_ty.abiSizeSema(pt);
+ if (store_one_ty.comptimeOnly(zcu)) break :restructure_array;
+ const elem_len = store_one_ty.abiSize(zcu);
if (ptr.byte_offset % elem_len != 0) break :restructure_array;
break :idx @divExact(ptr.byte_offset, elem_len);
};
@@ -807,11 +807,11 @@ fn prepareComptimePtrStore(
var cur_val: *MutableValue, var cur_offset: u64 = switch (base_strat) {
.direct => |direct| .{ direct.val, 0 },
// It's okay to do `abiSize` - the comptime-only case will be caught below.
- .index => |index| .{ index.val, index.elem_index * try index.val.typeOf(zcu).childType(zcu).abiSizeSema(pt) },
+ .index => |index| .{ index.val, index.elem_index * index.val.typeOf(zcu).childType(zcu).abiSize(zcu) },
.flat_index => |flat_index| .{
flat_index.val,
// It's okay to do `abiSize` - the comptime-only case will be caught below.
- flat_index.flat_elem_index * try flat_index.val.typeOf(zcu).arrayBase(zcu)[0].abiSizeSema(pt),
+ flat_index.flat_elem_index * flat_index.val.typeOf(zcu).arrayBase(zcu)[0].abiSize(zcu),
},
.reinterpret => |r| .{ r.val, r.byte_offset },
else => unreachable,
@@ -823,12 +823,12 @@ fn prepareComptimePtrStore(
}
if (store_ty.zigTypeTag(zcu) == .array and array_offset > 0) {
- cur_offset += try store_ty.childType(zcu).abiSizeSema(pt) * array_offset;
+ cur_offset += store_ty.childType(zcu).abiSize(zcu) * array_offset;
}
- const need_bytes = try store_ty.abiSizeSema(pt);
+ const need_bytes = store_ty.abiSize(zcu);
- if (cur_offset + need_bytes > try cur_val.typeOf(zcu).abiSizeSema(pt)) {
+ if (cur_offset + need_bytes > cur_val.typeOf(zcu).abiSize(zcu)) {
return .{ .out_of_bounds = cur_val.typeOf(zcu) };
}
@@ -863,7 +863,7 @@ fn prepareComptimePtrStore(
.optional => break, // this can only be a pointer-like optional so is terminal
.array => {
const elem_ty = cur_ty.childType(zcu);
- const elem_size = try elem_ty.abiSizeSema(pt);
+ const elem_size = elem_ty.abiSize(zcu);
const elem_idx = cur_offset / elem_size;
const next_elem_off = elem_size * (elem_idx + 1);
if (cur_offset + need_bytes <= next_elem_off) {
@@ -879,7 +879,7 @@ fn prepareComptimePtrStore(
.@"packed" => break, // let the bitcast logic handle this
.@"extern" => for (0..cur_ty.structFieldCount(zcu)) |field_idx| {
const start_off = cur_ty.structFieldOffset(field_idx, zcu);
- const end_off = start_off + try cur_ty.fieldType(field_idx, zcu).abiSizeSema(pt);
+ const end_off = start_off + cur_ty.fieldType(field_idx, zcu).abiSize(zcu);
if (cur_offset >= start_off and cur_offset + need_bytes <= end_off) {
cur_val = try cur_val.elem(pt, sema.arena, field_idx);
cur_offset -= start_off;
@@ -902,7 +902,7 @@ fn prepareComptimePtrStore(
};
// The payload always has offset 0. If it's big enough
// to represent the whole load type, we can use it.
- if (try payload.typeOf(zcu).abiSizeSema(pt) >= need_bytes) {
+ if (payload.typeOf(zcu).abiSize(zcu) >= need_bytes) {
cur_val = payload;
} else {
break;
diff --git a/src/Sema/type_resolution.zig b/src/Sema/type_resolution.zig
new file mode 100644
index 0000000000000000000000000000000000000000..032f299531509224da563a7347ecd4c2459d8fd3
--- /dev/null
+++ b/src/Sema/type_resolution.zig
@@ -0,0 +1,1398 @@
+const std = @import("std");
+const assert = std.debug.assert;
+const mem = std.mem;
+
+const Sema = @import("../Sema.zig");
+const Block = Sema.Block;
+const Type = @import("../Type.zig");
+const Value = @import("../Value.zig");
+const Zcu = @import("../Zcu.zig");
+const CompileError = Zcu.CompileError;
+const SemaError = Zcu.SemaError;
+const LazySrcLoc = Zcu.LazySrcLoc;
+const InternPool = @import("../InternPool.zig");
+const Alignment = InternPool.Alignment;
+const arith = @import("arith.zig");
+
+pub const LayoutResolveReason = enum {
+ variable,
+ constant,
+ parameter,
+ return_type,
+ field,
+ backing_enum,
+ init,
+ coerce,
+ ptr_access,
+ ptr_offset,
+ field_used,
+ field_queried,
+ size_of,
+ align_of,
+ type_info,
+ align_check,
+ bit_ptr_child,
+ @"export",
+ @"extern",
+ builtin_type,
+
+ /// Written after string: "while resolving type 'T' "
+ /// e.g. "while resolving type 'MyStruct' for variable declared here"
+ pub fn msg(r: LayoutResolveReason) []const u8 {
+ return switch (r) {
+ // zig fmt: off
+ .variable => "for variable declared here",
+ .constant => "for constant declared here",
+ .parameter => "for function parameter declared here",
+ .return_type => "for function return type declared here",
+ .field => "for field declared here",
+ .backing_enum => "for backing enum type declared here",
+ .init => "for initialization performed here",
+ .coerce => "for coercion performed here",
+ .ptr_access => "for pointer access here",
+ .ptr_offset => "for pointer offset here",
+ .field_used => "for field usage here",
+ .field_queried => "for field query here",
+ .size_of => "for size query here",
+ .align_of => "for alignment query here",
+ .type_info => "for type information query here",
+ .align_check => "for alignment check here",
+ .bit_ptr_child => "for bit size check here",
+ .@"export" => "for export here",
+ .@"extern" => "for extern declaration here",
+ .builtin_type => "from 'std.builtin'",
+ // zig fmt: on
+ };
+ }
+};
+
+/// Ensures that `ty` has known layout, including alignment, size, and (where relevant) field offsets.
+/// `ty` may be any type; its layout is resolved *recursively* if necessary.
+/// Adds incremental dependencies tracking any required type resolution.
+pub fn ensureLayoutResolved(sema: *Sema, ty: Type, src: LazySrcLoc, reason: LayoutResolveReason) SemaError!void {
+ return ensureLayoutResolvedInner(sema, ty, ty, &.{
+ .src = src,
+ .type_layout_reason = reason,
+ });
+}
+fn ensureLayoutResolvedInner(sema: *Sema, ty: Type, orig_ty: Type, reason: *const Zcu.DependencyReason) SemaError!void {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
+ const ip = &zcu.intern_pool;
+ switch (ip.indexToKey(ty.toIntern())) {
+ .int_type,
+ .ptr_type,
+ .anyframe_type,
+ .simple_type,
+ .opaque_type,
+ .error_set_type,
+ .inferred_error_set_type,
+ => {},
+
+ .func_type => |func_type| {
+ for (func_type.param_types.get(ip)) |param_ty| {
+ try ensureLayoutResolvedInner(sema, .fromInterned(param_ty), orig_ty, reason);
+ }
+ try ensureLayoutResolvedInner(sema, .fromInterned(func_type.return_type), orig_ty, reason);
+ },
+
+ .array_type => |arr| return ensureLayoutResolvedInner(sema, .fromInterned(arr.child), orig_ty, reason),
+ .vector_type => |vec| return ensureLayoutResolvedInner(sema, .fromInterned(vec.child), orig_ty, reason),
+ .opt_type => |child| return ensureLayoutResolvedInner(sema, .fromInterned(child), orig_ty, reason),
+ .error_union_type => |eu| return ensureLayoutResolvedInner(sema, .fromInterned(eu.payload_type), orig_ty, reason),
+ .tuple_type => |tuple| for (tuple.types.get(ip)) |field_ty| {
+ try ensureLayoutResolvedInner(sema, .fromInterned(field_ty), orig_ty, reason);
+ },
+ .struct_type, .union_type, .enum_type => {
+ try sema.declareDependency(.{ .type_layout = ty.toIntern() });
+ try sema.addReferenceEntry(null, reason.src, .wrap(.{ .type_layout = ty.toIntern() }));
+ if (zcu.analysis_in_progress.contains(.wrap(.{ .type_layout = ty.toIntern() }))) {
+ return sema.failWithDependencyLoop(.wrap(.{ .type_layout = ty.toIntern() }), reason);
+ }
+ try pt.ensureTypeLayoutUpToDate(ty, reason);
+ },
+
+ // values, not types
+ .undef,
+ .simple_value,
+ .variable,
+ .@"extern",
+ .func,
+ .int,
+ .err,
+ .error_union,
+ .enum_literal,
+ .enum_tag,
+ .float,
+ .ptr,
+ .slice,
+ .opt,
+ .aggregate,
+ .un,
+ .bitpack,
+ // memoization, not types
+ .memoized_call,
+ => unreachable,
+ }
+}
+
+/// Asserts that `ty` is a non-tuple `struct` type, and ensures that its fields' default values
+/// are resolved. Adds incremental dependencies tracking the required type resolution.
+///
+/// It is not necessary to call this function to query the values of comptime fields: those values
+/// are available from type *layout* resolution, see `ensureLayoutResolved`.
+///
+/// Asserts that the *layout* of `ty` has already been resolved---see `ensureLayoutResolved`.
+pub fn ensureStructDefaultsResolved(sema: *Sema, ty: Type, src: LazySrcLoc) SemaError!void {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
+ const ip = &zcu.intern_pool;
+
+ assert(ip.indexToKey(ty.toIntern()) == .struct_type);
+ ty.assertHasLayout(zcu);
+
+ try sema.declareDependency(.{ .struct_defaults = ty.toIntern() });
+ try sema.addReferenceEntry(null, src, .wrap(.{ .struct_defaults = ty.toIntern() }));
+
+ const reason: Zcu.DependencyReason = .{ .src = src, .type_layout_reason = undefined };
+
+ if (zcu.analysis_in_progress.contains(.wrap(.{ .struct_defaults = ty.toIntern() }))) {
+ return sema.failWithDependencyLoop(.wrap(.{ .struct_defaults = ty.toIntern() }), &reason);
+ }
+
+ try pt.ensureStructDefaultsUpToDate(ty, &reason);
+}
+
+/// Asserts that `struct_ty` is a non-packed non-tuple struct, and that `sema.owner` is that type.
+/// This function *does* register the `src_hash` dependency on the struct.
+pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
+ const comp = zcu.comp;
+ const io = comp.io;
+ const gpa = comp.gpa;
+ const ip = &zcu.intern_pool;
+
+ assert(sema.owner.unwrap().type_layout == struct_ty.toIntern());
+
+ const struct_obj = ip.loadStructType(struct_ty.toIntern());
+ assert(struct_obj.want_layout);
+ const zir_index = struct_obj.zir_index.resolve(ip) orelse return error.AnalysisFail;
+
+ var block: Block = .{
+ .parent = null,
+ .sema = sema,
+ .namespace = struct_obj.namespace,
+ .instructions = .empty,
+ .inlining = null,
+ .comptime_reason = undefined, // always set before using `block`
+ .src_base_inst = struct_obj.zir_index,
+ .type_name_ctx = struct_obj.name,
+ };
+ defer block.instructions.deinit(gpa);
+
+ // There may be old field names in here from a previous update.
+ struct_obj.field_name_map.get(ip).clearRetainingCapacity();
+
+ if (struct_obj.is_reified) {
+ // The field names are populated, but we haven't checked for duplicates (nor populated the map) yet.
+ for (0..struct_obj.field_names.len) |field_index| {
+ const name = struct_obj.field_names.get(ip)[field_index];
+ if (ip.addFieldName(struct_obj.field_names, struct_obj.field_name_map, name)) |prev_field_index| {
+ return sema.failWithOwnedErrorMsg(&block, msg: {
+ const src = block.builtinCallArgSrc(.zero, 2);
+ const msg = try sema.errMsg(src, "duplicate struct field '{f}' at index '{d}", .{ name.fmt(ip), field_index });
+ errdefer msg.destroy(gpa);
+ try sema.errNote(src, msg, "previous field at index '{d}'", .{prev_field_index});
+ break :msg msg;
+ });
+ }
+ }
+ } else {
+ // Declared structs do not yet have field information populated:
+ // * field names
+ // * field comptime-ness
+ // * field types
+ // * field aligns
+ // It's our job to populate these now.
+ try sema.declareDependency(.{ .src_hash = struct_obj.zir_index });
+
+ // Likewise, comptime bits may be set. We clear them all first because it avoids needing
+ // "unset bit with AND" logic below (instead we only need the "set bit with OR" case).
+ @memset(struct_obj.field_is_comptime_bits.getAll(ip), 0);
+
+ const zir_struct = sema.code.getStructDecl(zir_index);
+ var field_it = zir_struct.iterateFields();
+ var any_comptime_fields = false;
+ while (field_it.next()) |zir_field| {
+ {
+ const name_slice = sema.code.nullTerminatedString(zir_field.name);
+ const name = try ip.getOrPutString(gpa, io, pt.tid, name_slice, .no_embedded_nulls);
+ assert(ip.addFieldName(struct_obj.field_names, struct_obj.field_name_map, name) == null); // AstGen validated this for us
+ }
+
+ if (zir_field.is_comptime) {
+ const bit_bag_index = zir_field.idx / 32;
+ const mask = @as(u32, 1) << @intCast(zir_field.idx % 32);
+ struct_obj.field_is_comptime_bits.getAll(ip)[bit_bag_index] |= mask;
+ any_comptime_fields = true;
+ }
+
+ {
+ const field_ty_src = block.src(.{ .container_field_type = zir_field.idx });
+ const field_ty: Type = field_ty: {
+ block.comptime_reason = .{ .reason = .{
+ .src = field_ty_src,
+ .r = .{ .simple = .struct_field_types },
+ } };
+ const type_ref = try sema.resolveInlineBody(&block, zir_field.type_body, zir_index);
+ break :field_ty try sema.analyzeAsType(&block, field_ty_src, .struct_field_types, type_ref);
+ };
+ struct_obj.field_types.get(ip)[zir_field.idx] = field_ty.toIntern();
+ }
+
+ if (struct_obj.field_aligns.len == 0) {
+ assert(zir_field.align_body == null);
+ } else {
+ const field_align_src = block.src(.{ .container_field_align = zir_field.idx });
+ const field_align: Alignment = a: {
+ block.comptime_reason = .{ .reason = .{
+ .src = field_align_src,
+ .r = .{ .simple = .struct_field_attrs },
+ } };
+ const align_body = zir_field.align_body orelse break :a .none;
+ const align_ref = try sema.resolveInlineBody(&block, align_body, zir_index);
+ break :a try sema.analyzeAsAlign(&block, field_align_src, align_ref);
+ };
+ struct_obj.field_aligns.get(ip)[zir_field.idx] = field_align;
+ }
+ }
+
+ // We also resolve the default values of any `comptime` fields now. This is not necessary in
+ // the case of a reified struct because the the default values were already poulated and
+ // validated by `Sema.zirReifyStruct`.
+ if (any_comptime_fields) {
+ try resolveStructDefaultsInner(sema, &block, &struct_obj, .comptime_fields);
+ }
+ }
+
+ if (struct_obj.layout == .@"packed") {
+ return resolvePackedStructLayout(sema, &block, struct_ty, &struct_obj);
+ }
+
+ // Resolve the layout of all fields, and check their types are allowed.
+ for (struct_obj.field_types.get(ip), 0..) |field_ty_ip, field_index| {
+ const field_ty: Type = .fromInterned(field_ty_ip);
+ assert(!field_ty.isGenericPoison());
+ const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) });
+ try sema.ensureLayoutResolved(field_ty, field_ty_src, .field);
+ if (field_ty.zigTypeTag(zcu) == .@"opaque") {
+ return sema.failWithOwnedErrorMsg(&block, msg: {
+ const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in struct", .{field_ty.fmt(pt)});
+ errdefer msg.destroy(gpa);
+ try sema.errNote(field_ty_src, msg, "opaque types have unknown size", .{});
+ try sema.addDeclaredHereNote(msg, field_ty);
+ break :msg msg;
+ });
+ }
+ if (struct_obj.layout == .@"extern" and !field_ty.validateExtern(.struct_field, zcu)) {
+ return sema.failWithOwnedErrorMsg(&block, msg: {
+ const msg = try sema.errMsg(field_ty_src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
+ errdefer msg.destroy(gpa);
+ try sema.explainWhyTypeIsNotExtern(msg, field_ty_src, field_ty, .struct_field);
+ try sema.addDeclaredHereNote(msg, field_ty);
+ break :msg msg;
+ });
+ }
+ }
+
+ // Fields are okay. Now we need to resolve the struct's overall layout (size, field offsets, etc).
+
+ var any_comptime_fields = false;
+ var struct_align: Alignment = .@"1";
+ var has_no_possible_value = false;
+ var has_runtime_state = false;
+ var has_comptime_state = false;
+ // Unlike `struct_obj.field_aligns`, these are not `.none`.
+ const resolved_field_aligns = try sema.arena.alloc(Alignment, struct_obj.field_names.len);
+ for (resolved_field_aligns, 0..) |*align_out, field_idx| {
+ const field_ty: Type = .fromInterned(struct_obj.field_types.get(ip)[field_idx]);
+ const field_align: Alignment = a: {
+ if (struct_obj.field_aligns.len != 0) {
+ const a = struct_obj.field_aligns.get(ip)[field_idx];
+ if (a != .none) break :a a;
+ }
+ break :a field_ty.defaultStructFieldAlignment(struct_obj.layout, zcu);
+ };
+ align_out.* = field_align;
+ if (struct_obj.field_is_comptime_bits.get(ip, field_idx)) {
+ assert(struct_obj.layout == .auto); // comptime fields not allowed in extern or packed structs
+ struct_obj.field_runtime_order.get(ip)[field_idx] = .omitted; // comptime fields are not in the runtime order
+ any_comptime_fields = true;
+ continue; // `comptime` fields do not contribute to the struct layout
+ }
+ struct_align = struct_align.maxStrict(field_align);
+ if (struct_obj.layout == .auto) {
+ struct_obj.field_runtime_order.get(ip)[field_idx] = @enumFromInt(field_idx);
+ }
+ switch (field_ty.classify(zcu)) {
+ .one_possible_value => {},
+ .no_possible_value => has_no_possible_value = true,
+ .runtime => has_runtime_state = true,
+ .fully_comptime => has_comptime_state = true,
+ .partially_comptime => {
+ has_runtime_state = true;
+ has_comptime_state = true;
+ },
+ }
+ }
+ const class: Type.Class = class: {
+ if (has_no_possible_value) break :class .no_possible_value;
+ if (has_comptime_state) {
+ break :class if (has_runtime_state) .partially_comptime else .fully_comptime;
+ } else {
+ break :class if (has_runtime_state) .runtime else .one_possible_value;
+ }
+ };
+
+ switch (struct_obj.layout) {
+ .auto => {},
+ .@"extern" => assert(class != .no_possible_value), // field types are all extern, so are not NPV
+ .@"packed" => unreachable,
+ }
+
+ if (struct_obj.layout == .auto) {
+ const runtime_order = struct_obj.field_runtime_order.get(ip);
+ // This logic does not reorder fields; it only moves the omitted ones to the end so that logic
+ // elsewhere does not need to special-case. TODO: support field reordering in all the backends!
+ if (!zcu.backendSupportsFeature(.field_reordering)) {
+ var i: usize = 0;
+ var off: usize = 0;
+ while (i + off < runtime_order.len) {
+ if (runtime_order[i + off] == .omitted) {
+ off += 1;
+ } else {
+ runtime_order[i] = runtime_order[i + off];
+ i += 1;
+ }
+ }
+ } else {
+ // Sort by descending alignment to minimize padding.
+ const RuntimeOrder = InternPool.LoadedStructType.RuntimeOrder;
+ const AlignSortCtx = struct {
+ aligns: []const Alignment,
+ fn lessThan(ctx: @This(), a: RuntimeOrder, b: RuntimeOrder) bool {
+ assert(a != .unresolved);
+ assert(b != .unresolved);
+ if (a == .omitted) return false;
+ if (b == .omitted) return true;
+ const a_align = ctx.aligns[@intFromEnum(a)];
+ const b_align = ctx.aligns[@intFromEnum(b)];
+ return a_align.compare(.gt, b_align);
+ }
+ };
+ mem.sortUnstable(
+ RuntimeOrder,
+ runtime_order,
+ @as(AlignSortCtx, .{ .aligns = resolved_field_aligns }),
+ AlignSortCtx.lessThan,
+ );
+ }
+ }
+
+ var runtime_order_it = struct_obj.iterateRuntimeOrder(ip);
+ var cur_offset: u64 = 0;
+ while (runtime_order_it.next()) |field_idx| {
+ const field_ty: Type = .fromInterned(struct_obj.field_types.get(ip)[field_idx]);
+ const offset = resolved_field_aligns[field_idx].forward(cur_offset);
+ struct_obj.field_offsets.get(ip)[field_idx] = @truncate(offset); // truncate because the overflow is handled below
+ cur_offset = offset + field_ty.abiSize(zcu);
+ }
+ const struct_size: u32 = switch (class) {
+ .no_possible_value => 0,
+ else => std.math.cast(u32, struct_align.forward(cur_offset)) orelse return sema.fail(
+ &block,
+ struct_ty.srcLoc(zcu),
+ "struct layout requires size {d}, this compiler implementation supports up to {d}",
+ .{ struct_align.forward(cur_offset), std.math.maxInt(u32) },
+ ),
+ };
+ ip.resolveStructLayout(
+ io,
+ struct_ty.toIntern(),
+ struct_size,
+ struct_align,
+ class,
+ );
+}
+
+/// Asserts that `struct_ty` is a packed struct, and that `sema.owner` is that type.
+/// This function *does* register the `src_hash` dependency on the struct.
+fn resolvePackedStructLayout(
+ sema: *Sema,
+ block: *Block,
+ struct_ty: Type,
+ struct_obj: *const InternPool.LoadedStructType,
+) CompileError!void {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
+ const comp = zcu.comp;
+ const io = comp.io;
+ const gpa = comp.gpa;
+ const ip = &zcu.intern_pool;
+
+ // Resolve the layout of all fields, and check their types are allowed.
+ // Also count the number of bits while we're at it.
+ var field_bits: u64 = 0;
+ for (struct_obj.field_types.get(ip), 0..) |field_ty_ip, field_index| {
+ const field_ty: Type = .fromInterned(field_ty_ip);
+ assert(!field_ty.isGenericPoison());
+ const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) });
+ try sema.ensureLayoutResolved(field_ty, field_ty_src, .field);
+ if (field_ty.zigTypeTag(zcu) == .@"opaque") {
+ return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in struct", .{field_ty.fmt(pt)});
+ errdefer msg.destroy(gpa);
+ try sema.errNote(field_ty_src, msg, "opaque types have unknown size", .{});
+ try sema.addDeclaredHereNote(msg, field_ty);
+ break :msg msg;
+ });
+ }
+ if (field_ty.unpackable(zcu)) |reason| return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(field_ty_src, "packed structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
+ errdefer msg.destroy(gpa);
+ try sema.explainWhyTypeIsUnpackable(msg, field_ty_src, reason);
+ break :msg msg;
+ });
+ switch (field_ty.classify(zcu)) {
+ .one_possible_value, .runtime => {},
+ .no_possible_value => unreachable, // packable types are not NPV
+ .partially_comptime => unreachable, // packable types are not comptime-only
+ .fully_comptime => unreachable, // packable types are not comptime-only
+ }
+ field_bits += field_ty.bitSize(zcu);
+ }
+
+ const explicit_backing_int_ty: ?Type = if (struct_obj.is_reified) ty: {
+ break :ty switch (struct_obj.packed_backing_mode) {
+ .explicit => .fromInterned(struct_obj.packed_backing_int_type),
+ .auto => null,
+ };
+ } else ty: {
+ const zir_index = struct_obj.zir_index.resolve(ip).?;
+ const zir_struct = sema.code.getStructDecl(zir_index);
+ const backing_int_type_body = zir_struct.backing_int_type_body orelse {
+ break :ty null; // inferred backing type
+ };
+ // Explicitly specified, so evaluate the backing int type expression.
+ const backing_int_type_src = block.src(.container_arg);
+ block.comptime_reason = .{ .reason = .{
+ .src = backing_int_type_src,
+ .r = .{ .simple = .packed_struct_backing_int_type },
+ } };
+ const type_ref = try sema.resolveInlineBody(block, backing_int_type_body, zir_index);
+ break :ty try sema.analyzeAsType(block, backing_int_type_src, .packed_struct_backing_int_type, type_ref);
+ };
+
+ // Finally, either validate or infer the backing int type.
+ const backing_int_ty: Type = if (explicit_backing_int_ty) |backing_ty| ty: {
+ if (backing_ty.zigTypeTag(zcu) != .int) return sema.fail(
+ block,
+ block.src(.container_arg),
+ "expected backing integer type, found '{f}'",
+ .{backing_ty.fmt(pt)},
+ );
+ if (field_bits != backing_ty.intInfo(zcu).bits) return sema.failWithOwnedErrorMsg(block, msg: {
+ const src = struct_ty.srcLoc(zcu);
+ const msg = try sema.errMsg(src, "backing integer bit width does not match total bit width of fields", .{});
+ errdefer msg.destroy(gpa);
+ try sema.errNote(
+ block.src(.container_arg),
+ msg,
+ "backing integer '{f}' has bit width '{d}'",
+ .{ backing_ty.fmt(pt), backing_ty.bitSize(zcu) },
+ );
+ try sema.errNote(src, msg, "struct fields have total bit width '{d}'", .{field_bits});
+ break :msg msg;
+ });
+ break :ty backing_ty;
+ } else ty: {
+ // We need to generate the inferred tag.
+ const backing_int_bits = std.math.cast(u16, field_bits) orelse return sema.fail(
+ block,
+ struct_ty.srcLoc(zcu),
+ "packed struct bit width '{d}' exceeds maximum bit width of 65535",
+ .{field_bits},
+ );
+ break :ty try pt.intType(.unsigned, backing_int_bits);
+ };
+ ip.resolvePackedStructLayout(
+ io,
+ struct_ty.toIntern(),
+ backing_int_ty.toIntern(),
+ );
+}
+
+/// Asserts that `struct_ty` is a non-tuple struct, and that `sema.owner` is that type.
+///
+/// Also asserts that the layout of `struct_ty` has *already* been resolved (though it is okay for
+/// that resolution to have failed). This requirement exists to ensure better error messages in the
+/// event of a dependency loop.
+///
+/// This function *does* register the `src_hash` dependency on the struct.
+pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
+ const comp = zcu.comp;
+ const gpa = comp.gpa;
+ const ip = &zcu.intern_pool;
+
+ assert(sema.owner.unwrap().struct_defaults == struct_ty.toIntern());
+
+ // We always depend on the layout of `struct_ty`. However, we don't actually need to resolve it
+ // now, because the caller has done so for us. Just mark the dependency so that the incremental
+ // compilation handling understands the dependency graph.
+ try sema.declareDependency(.{ .type_layout = struct_ty.toIntern() });
+ struct_ty.assertHasLayout(zcu);
+ const layout_unit: InternPool.AnalUnit = .wrap(.{ .type_layout = struct_ty.toIntern() });
+ if (zcu.failed_analysis.contains(layout_unit) or zcu.transitive_failed_analysis.contains(layout_unit)) {
+ return error.AnalysisFail;
+ }
+
+ const struct_obj = ip.loadStructType(struct_ty.toIntern());
+ assert(struct_obj.want_layout);
+
+ if (struct_obj.is_reified) {
+ // `Sema.zirReifyStruct` has already populated the default field values *and* (by loading
+ // the default values from pointers) validated their types, so we have nothing to do.
+ return;
+ }
+
+ try sema.declareDependency(.{ .src_hash = struct_obj.zir_index });
+
+ if (struct_obj.field_defaults.len == 0) {
+ // The struct has no default field values, so the slice has been omitted.
+ return;
+ }
+
+ var block: Block = .{
+ .parent = null,
+ .sema = sema,
+ .namespace = struct_obj.namespace,
+ .instructions = .empty,
+ .inlining = null,
+ .comptime_reason = undefined, // always set before using `block`
+ .src_base_inst = struct_obj.zir_index,
+ .type_name_ctx = struct_obj.name,
+ };
+ defer block.instructions.deinit(gpa);
+
+ return resolveStructDefaultsInner(sema, &block, &struct_obj, .normal_fields);
+}
+
+/// Asserts that the struct is not reified, and that `struct_obj.field_defaults.len` is non-zero.
+fn resolveStructDefaultsInner(
+ sema: *Sema,
+ block: *Block,
+ struct_obj: *const InternPool.LoadedStructType,
+ mode: enum { comptime_fields, normal_fields },
+) CompileError!void {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
+ const comp = zcu.comp;
+ const gpa = comp.gpa;
+ const ip = &zcu.intern_pool;
+
+ assert(struct_obj.field_defaults.len > 0);
+
+ // We'll need to map the struct decl instruction to provide result types
+ const zir_index = struct_obj.zir_index.resolve(ip) orelse return error.AnalysisFail;
+ try sema.inst_map.ensureSpaceForInstructions(gpa, &.{zir_index});
+
+ const field_types = struct_obj.field_types.get(ip);
+
+ const zir_struct = sema.code.getStructDecl(zir_index);
+ var field_it = zir_struct.iterateFields();
+ while (field_it.next()) |zir_field| {
+ switch (mode) {
+ .comptime_fields => if (!zir_field.is_comptime) continue,
+ .normal_fields => if (zir_field.is_comptime) continue,
+ }
+
+ const default_val_src = block.src(.{ .container_field_value = zir_field.idx });
+ block.comptime_reason = .{ .reason = .{
+ .src = default_val_src,
+ .r = .{ .simple = .struct_field_default_value },
+ } };
+ const default_body = zir_field.default_body orelse {
+ struct_obj.field_defaults.get(ip)[zir_field.idx] = .none;
+ continue;
+ };
+ const field_ty: Type = .fromInterned(field_types[zir_field.idx]);
+ const uncoerced = ref: {
+ // Provide the result type
+ sema.inst_map.putAssumeCapacity(zir_index, .fromIntern(field_ty.toIntern()));
+ defer assert(sema.inst_map.remove(zir_index));
+ break :ref try sema.resolveInlineBody(block, default_body, zir_index);
+ };
+ const coerced = try sema.coerce(block, field_ty, uncoerced, default_val_src);
+ const default_val = try sema.resolveConstValue(block, default_val_src, coerced, null);
+ if (default_val.canMutateComptimeVarState(zcu)) {
+ const field_name = struct_obj.field_names.get(ip)[zir_field.idx];
+ return sema.failWithContainsReferenceToComptimeVar(block, default_val_src, field_name, "field default value", default_val);
+ }
+ struct_obj.field_defaults.get(ip)[zir_field.idx] = default_val.toIntern();
+ }
+}
+
+/// This logic must be kept in sync with `Type.getUnionLayout`.
+pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
+ const comp = zcu.comp;
+ const io = comp.io;
+ const gpa = comp.gpa;
+ const ip = &zcu.intern_pool;
+
+ assert(sema.owner.unwrap().type_layout == union_ty.toIntern());
+
+ const union_obj = ip.loadUnionType(union_ty.toIntern());
+ assert(union_obj.want_layout);
+ const zir_index = union_obj.zir_index.resolve(ip) orelse return error.AnalysisFail;
+
+ var block: Block = .{
+ .parent = null,
+ .sema = sema,
+ .namespace = union_obj.namespace,
+ .instructions = .empty,
+ .inlining = null,
+ .comptime_reason = undefined, // always set before using `block`
+ .src_base_inst = union_obj.zir_index,
+ .type_name_ctx = union_obj.name,
+ };
+ defer block.instructions.deinit(gpa);
+
+ const enum_tag_ty: Type = switch (union_obj.enum_tag_mode) {
+ .explicit => validated_tag_ty: {
+ // If the union is reified, its enum tag type is already populated. If the union is
+ // declared, we need to evaluate the enum tag type expression (the `E` in `union(E)`).
+ const tag_ty: Type = switch (union_obj.is_reified) {
+ true => .fromInterned(union_obj.enum_tag_type),
+ false => tag_ty: {
+ const zir_union = sema.code.getUnionDecl(zir_index);
+ assert(zir_union.kind == .tagged_explicit); // `Zcu.mapOldZirToNew` guarantees that the ZIR mapping preserves `kind`
+ const tag_type_body = zir_union.arg_type_body.?;
+ const tag_type_src = block.src(.container_arg);
+ block.comptime_reason = .{ .reason = .{
+ .src = tag_type_src,
+ .r = .{ .simple = .union_enum_tag_type },
+ } };
+ const type_ref = try sema.resolveInlineBody(&block, tag_type_body, zir_index);
+ break :tag_ty try sema.analyzeAsType(&block, tag_type_src, .union_enum_tag_type, type_ref);
+ },
+ };
+ // Because the type is explicitly specified, we need to validate it.
+ if (tag_ty.zigTypeTag(zcu) != .@"enum") return sema.fail(
+ &block,
+ block.src(.container_arg),
+ "expected enum tag type, found '{f}'",
+ .{tag_ty.fmt(pt)},
+ );
+ break :validated_tag_ty tag_ty;
+ },
+ // If no tag type was specified, we generate one keyed on this union type.
+ .auto => switch (try ip.getGeneratedEnumTagType(gpa, io, pt.tid, .{
+ .union_type = union_ty.toIntern(),
+ // The int tag for this enum is usually inferred---the exception is `union(enum(T))`.
+ .int_tag_mode = switch (union_obj.is_reified) {
+ true => .auto,
+ false => switch (sema.code.getUnionDecl(zir_index).kind) {
+ .tagged_enum_explicit => .explicit,
+ else => .auto,
+ },
+ },
+ .fields_len = @intCast(union_obj.field_types.len),
+ })) {
+ .existing => |tag_ty| .fromInterned(tag_ty),
+ .wip => |wip| tag_ty: {
+ errdefer wip.cancel(ip, pt.tid);
+ _ = wip.setName(ip, try ip.getOrPutStringFmt(
+ gpa,
+ io,
+ pt.tid,
+ "@typeInfo({f}).@\"union\".tag_type.?",
+ .{union_obj.name.fmt(ip)},
+ .no_embedded_nulls,
+ ), .none);
+ const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
+ .parent = union_obj.namespace.toOptional(),
+ .owner_type = wip.index,
+ .file_scope = zcu.namespacePtr(union_obj.namespace).file_scope,
+ .generation = zcu.generation,
+ });
+ if (comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
+ break :tag_ty .fromInterned(wip.finish(ip, new_namespace_index));
+ },
+ },
+ };
+
+ try sema.ensureLayoutResolved(enum_tag_ty, block.src(.container_arg), .backing_enum);
+ const enum_obj = ip.loadEnumType(enum_tag_ty.toIntern());
+
+ if (union_obj.is_reified) {
+ // We have field names in `union_obj.reified_field_names`, but we haven't
+ // checked them against the backing type yet.
+ const union_field_names = union_obj.reified_field_names.get(ip);
+ match_fields: {
+ // We can efficiently *check* if the fields match...
+ if (union_field_names.len == enum_obj.field_names.len) {
+ for (union_field_names, enum_obj.field_names.get(ip)) |union_field_name, enum_field_name| {
+ if (!std.mem.eql(u8, union_field_name.toSlice(ip), enum_field_name.toSlice(ip))) break;
+ } else {
+ break :match_fields;
+ }
+ }
+ // ...but if they don't, reporting a nice error is a little more involved. If some field
+ // is present in the enum but not the union, or vice versa, we will report that instead
+ // of a generic "field order mismatch" error. Of course, this error is impossible for a
+ // generated tag type, because we populated that from the union ZIR!
+ assert(enum_obj.owner_union != union_ty.toIntern());
+ return failUnionFieldMismatch(sema, &block, union_field_names, enum_tag_ty, &enum_obj);
+ }
+ } else {
+ // Declared unions do not have field types or aligns populated yet.
+ // We also need to check the field names match the backing enum.
+ try sema.declareDependency(.{ .src_hash = union_obj.zir_index });
+ const zir_union = sema.code.getUnionDecl(zir_index);
+
+ // We'll first check the field names against the backing enum, and only analyze the types
+ // once we know the fields match one-to-one.
+ match_fields: {
+ // We can efficiently *check* if the fields match...
+ if (zir_union.field_names.len == enum_obj.field_names.len) {
+ for (zir_union.field_names, enum_obj.field_names.get(ip)) |union_field_name_zir, enum_field_name| {
+ const union_field_name_slice = sema.code.nullTerminatedString(union_field_name_zir);
+ if (!std.mem.eql(u8, union_field_name_slice, enum_field_name.toSlice(ip))) break;
+ } else {
+ break :match_fields;
+ }
+ }
+ // ...but if they don't, reporting a nice error is a little more involved. If some field
+ // is present in the enum but not the union, or vice versa, we will report that instead
+ // of a generic "field order mismatch" error. Of course, this error is impossible for a
+ // generated tag type, because we populated that from the union ZIR!
+ assert(enum_obj.owner_union != union_ty.toIntern());
+ const union_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, zir_union.field_names.len);
+ for (zir_union.field_names, union_field_names) |name_zir, *name| {
+ name.* = try ip.getOrPutString(gpa, io, pt.tid, sema.code.nullTerminatedString(name_zir), .no_embedded_nulls);
+ }
+ return failUnionFieldMismatch(sema, &block, union_field_names, enum_tag_ty, &enum_obj);
+ }
+
+ // Field names okay; populate types and aligns.
+ var field_it = zir_union.iterateFields();
+ while (field_it.next()) |zir_field| {
+ const field_ty_src = block.src(.{ .container_field_type = zir_field.idx });
+ const field_ty: Type = field_ty: {
+ block.comptime_reason = .{ .reason = .{
+ .src = field_ty_src,
+ .r = .{ .simple = .union_field_types },
+ } };
+ const type_body = zir_field.type_body orelse break :field_ty .void;
+ const type_ref = try sema.resolveInlineBody(&block, type_body, zir_index);
+ break :field_ty try sema.analyzeAsType(&block, field_ty_src, .union_field_types, type_ref);
+ };
+ union_obj.field_types.get(ip)[zir_field.idx] = field_ty.toIntern();
+
+ const field_align_src = block.src(.{ .container_field_align = zir_field.idx });
+ const explicit_field_align: Alignment = a: {
+ block.comptime_reason = .{ .reason = .{
+ .src = field_align_src,
+ .r = .{ .simple = .union_field_attrs },
+ } };
+ const align_body = zir_field.align_body orelse break :a .none;
+ const align_ref = try sema.resolveInlineBody(&block, align_body, zir_index);
+ break :a try sema.analyzeAsAlign(&block, field_align_src, align_ref);
+ };
+ if (union_obj.field_aligns.len != 0) {
+ union_obj.field_aligns.get(ip)[zir_field.idx] = explicit_field_align;
+ } else {
+ assert(explicit_field_align == .none);
+ }
+ }
+ }
+
+ if (union_obj.layout == .@"packed") {
+ return resolvePackedUnionLayout(sema, &block, union_ty, &union_obj, enum_tag_ty);
+ }
+
+ // Resolve the layout of all fields, and check their types are allowed.
+ for (union_obj.field_types.get(ip), 0..) |field_ty_ip, field_index| {
+ const field_ty: Type = .fromInterned(field_ty_ip);
+ assert(!field_ty.isGenericPoison());
+ const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) });
+ try sema.ensureLayoutResolved(field_ty, field_ty_src, .field);
+ if (field_ty.zigTypeTag(zcu) == .@"opaque") {
+ return sema.failWithOwnedErrorMsg(&block, msg: {
+ const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in union", .{field_ty.fmt(pt)});
+ errdefer msg.destroy(gpa);
+ try sema.errNote(field_ty_src, msg, "opaque types have unknown size", .{});
+ try sema.addDeclaredHereNote(msg, field_ty);
+ break :msg msg;
+ });
+ }
+ if (union_obj.layout == .@"extern" and !field_ty.validateExtern(.union_field, zcu)) {
+ return sema.failWithOwnedErrorMsg(&block, msg: {
+ const msg = try sema.errMsg(field_ty_src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
+ errdefer msg.destroy(gpa);
+ try sema.explainWhyTypeIsNotExtern(msg, field_ty_src, field_ty, .union_field);
+ try sema.addDeclaredHereNote(msg, field_ty);
+ break :msg msg;
+ });
+ }
+ }
+
+ // Fields are okay. Now we need to resolve the union's overall layout (size, alignment, etc).
+ var payload_align: Alignment = .@"1";
+ var payload_size: u64 = 0;
+ var possible_tags: u32 = 0;
+ var payload_has_comptime_state = false;
+ for (0..union_obj.field_types.len) |field_idx| {
+ const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_idx]);
+ const field_align: Alignment = a: {
+ if (union_obj.field_aligns.len != 0) {
+ const a = union_obj.field_aligns.get(ip)[field_idx];
+ if (a != .none) break :a a;
+ }
+ break :a field_ty.abiAlignment(zcu);
+ };
+ payload_align = payload_align.maxStrict(field_align);
+ payload_size = @max(payload_size, field_ty.abiSize(zcu));
+
+ switch (field_ty.classify(zcu)) {
+ .no_possible_value => {}, // uninstantiable field has no effect
+ .one_possible_value, .runtime => {
+ possible_tags += 1;
+ },
+ .partially_comptime, .fully_comptime => {
+ possible_tags += 1;
+ payload_has_comptime_state = true;
+ },
+ }
+ }
+
+ // Uninstantiable `extern union`s don't make sense; disallow them.
+ if (possible_tags == 0 and union_obj.layout != .auto) {
+ // Field types are all extern, so not NPV; thus zero possible tags means no tags at all.
+ assert(union_obj.field_types.len == 0);
+ return sema.fail(&block, union_ty.srcLoc(zcu), "extern union has no fields", .{});
+ }
+
+ // We only need a runtime tag if there are multiple possible active fields *and* the union is
+ // not going to be comptime-only. Even if there are still runtime bits in the payload, the tag
+ // does not require runtime bits in a comptime-only union, because it is impossible to get a
+ // pointer to a union's tag.
+ const has_runtime_tag = switch (possible_tags) {
+ 0, 1 => false,
+ else => union_obj.tag_usage != .none and !payload_has_comptime_state,
+ };
+
+ const class: Type.Class = class: {
+ if (possible_tags == 0) {
+ break :class .no_possible_value;
+ }
+ if (payload_has_comptime_state) {
+ break :class if (payload_size > 0) .partially_comptime else .fully_comptime;
+ }
+ const have_runtime_bits = has_runtime_tag or payload_size > 0;
+ break :class if (have_runtime_bits) .runtime else .one_possible_value;
+ };
+
+ const size: u64, const padding: u64, const alignment: Alignment = layout: {
+ if (!has_runtime_tag) {
+ break :layout .{ payload_align.forward(payload_size), 0, payload_align };
+ }
+ const tag_align = enum_tag_ty.abiAlignment(zcu);
+ const tag_size = enum_tag_ty.abiSize(zcu);
+ // The layout will either be (tag, payload, padding) or (payload, tag, padding) depending on
+ // which has larger alignment. So the overall size is just the tag and payload sizes, added,
+ // and padded to the larger alignment.
+ const alignment = tag_align.maxStrict(payload_align);
+ const unpadded_size = tag_size + payload_size;
+ const size = alignment.forward(unpadded_size);
+ break :layout .{ size, size - unpadded_size, alignment };
+ };
+
+ if (class == .no_possible_value or class == .one_possible_value) {
+ assert(size == 0);
+ assert(padding == 0);
+ }
+
+ const casted_size = std.math.cast(u32, size) orelse return sema.fail(
+ &block,
+ union_ty.srcLoc(zcu),
+ "union layout requires size {d}, this compiler implementation supports up to {d}",
+ .{ size, std.math.maxInt(u32) },
+ );
+ ip.resolveUnionLayout(
+ io,
+ union_ty.toIntern(),
+ enum_tag_ty.toIntern(),
+ class,
+ has_runtime_tag,
+ casted_size,
+ @intCast(padding), // okay because padding is no greater than size
+ alignment,
+ );
+}
+fn failUnionFieldMismatch(sema: *Sema, block: *Block, union_field_names: []const InternPool.NullTerminatedString, enum_tag_ty: Type, enum_obj: *const InternPool.LoadedEnumType) CompileError {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
+ const comp = zcu.comp;
+ const gpa = comp.gpa;
+ const ip = &zcu.intern_pool;
+ const enum_to_union_map = try sema.arena.alloc(?u32, enum_obj.field_names.len);
+ @memset(enum_to_union_map, null);
+ for (union_field_names, 0..) |field_name, union_field_index| {
+ if (enum_obj.nameIndex(ip, field_name)) |enum_field_index| {
+ enum_to_union_map[enum_field_index] = @intCast(union_field_index);
+ continue;
+ }
+ const union_field_src = block.src(.{ .container_field_name = @intCast(union_field_index) });
+ return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(union_field_src, "no field named '{f}' in enum '{f}'", .{ field_name.fmt(ip), enum_tag_ty.fmt(pt) });
+ errdefer msg.destroy(gpa);
+ try sema.addDeclaredHereNote(msg, enum_tag_ty);
+ break :msg msg;
+ });
+ }
+ for (enum_to_union_map, 0..) |union_field_index, enum_field_index| {
+ if (union_field_index != null) continue;
+ const field_name_ip = enum_obj.field_names.get(ip)[enum_field_index];
+ const enum_field_src: LazySrcLoc = .{
+ .base_node_inst = enum_tag_ty.typeDeclInstAllowGeneratedTag(zcu).?,
+ .offset = .{ .container_field_name = @intCast(enum_field_index) },
+ };
+ return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(block.nodeOffset(.zero), "enum field '{f}' missing from union", .{field_name_ip.fmt(ip)});
+ errdefer msg.destroy(gpa);
+ try sema.errNote(enum_field_src, msg, "enum field here", .{});
+ break :msg msg;
+ });
+ }
+ // The only problem is the field ordering.
+ for (enum_to_union_map, 0..) |union_field_index, enum_field_index| {
+ if (union_field_index.? == enum_field_index) continue;
+ const field_name = enum_obj.field_names.get(ip)[enum_field_index];
+ const union_field_src = block.src(.{ .container_field_name = union_field_index.? });
+ const enum_field_src: LazySrcLoc = .{
+ .base_node_inst = enum_tag_ty.typeDeclInstAllowGeneratedTag(zcu).?,
+ .offset = .{ .container_field_name = @intCast(enum_field_index) },
+ };
+ return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(block.nodeOffset(.zero), "union field order does not match tag enum field order", .{});
+ errdefer msg.destroy(gpa);
+ try sema.errNote(union_field_src, msg, "union field '{f}' is index {d}", .{ field_name.fmt(ip), union_field_index.? });
+ try sema.errNote(enum_field_src, msg, "enum field '{f}' is index {d}", .{ field_name.fmt(ip), enum_field_index });
+ break :msg msg;
+ });
+ }
+ unreachable; // we already determined that *something* is wrong
+}
+fn resolvePackedUnionLayout(
+ sema: *Sema,
+ block: *Block,
+ union_ty: Type,
+ union_obj: *const InternPool.LoadedUnionType,
+ enum_tag_ty: Type,
+) CompileError!void {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
+ const comp = zcu.comp;
+ const io = comp.io;
+ const gpa = comp.gpa;
+ const ip = &zcu.intern_pool;
+
+ // Uninstantiable `packed union`s don't make sense; disallow them.
+ if (union_obj.field_types.len == 0) {
+ return sema.fail(block, union_ty.srcLoc(zcu), "packed union has no fields", .{});
+ }
+
+ // Resolve the layout of all fields, and check their types are allowed.
+ for (union_obj.field_types.get(ip), 0..) |field_ty_ip, field_index| {
+ const field_ty: Type = .fromInterned(field_ty_ip);
+ assert(!field_ty.isGenericPoison());
+ const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) });
+ try sema.ensureLayoutResolved(field_ty, field_ty_src, .field);
+ if (field_ty.zigTypeTag(zcu) == .@"opaque") {
+ return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in union", .{field_ty.fmt(pt)});
+ errdefer msg.destroy(gpa);
+ try sema.errNote(field_ty_src, msg, "opaque types have unknown size", .{});
+ try sema.addDeclaredHereNote(msg, field_ty);
+ break :msg msg;
+ });
+ }
+ if (field_ty.unpackable(zcu)) |reason| return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(field_ty_src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
+ errdefer msg.destroy(gpa);
+ try sema.explainWhyTypeIsUnpackable(msg, field_ty_src, reason);
+ break :msg msg;
+ });
+ assert(!field_ty.comptimeOnly(zcu)); // packable types are not comptime-only
+ }
+
+ const explicit_backing_int_ty: ?Type = if (union_obj.is_reified) ty: {
+ switch (union_obj.packed_backing_mode) {
+ .explicit => break :ty .fromInterned(union_obj.packed_backing_int_type),
+ .auto => break :ty null,
+ }
+ } else ty: {
+ const zir_index = union_obj.zir_index.resolve(ip).?;
+ const zir_union = sema.code.getUnionDecl(zir_index);
+ const backing_int_type_body = zir_union.arg_type_body orelse {
+ break :ty null; // inferred backing type
+ };
+ // Explicitly specified, so evaluate the backing int type expression.
+ const backing_int_type_src = block.src(.container_arg);
+ block.comptime_reason = .{ .reason = .{
+ .src = backing_int_type_src,
+ .r = .{ .simple = .packed_union_backing_int_type },
+ } };
+ const type_ref = try sema.resolveInlineBody(block, backing_int_type_body, zir_index);
+ break :ty try sema.analyzeAsType(block, backing_int_type_src, .packed_union_backing_int_type, type_ref);
+ };
+
+ // Finally, either validate or infer the backing int type.
+ const backing_int_ty: Type = if (explicit_backing_int_ty) |backing_ty| ty: {
+ if (backing_ty.zigTypeTag(zcu) != .int) return sema.fail(
+ block,
+ block.src(.container_arg),
+ "expected backing integer type, found '{f}'",
+ .{backing_ty.fmt(pt)},
+ );
+ const backing_int_bits = backing_ty.intInfo(zcu).bits;
+ for (union_obj.field_types.get(ip), 0..) |field_type_ip, field_idx| {
+ const field_type: Type = .fromInterned(field_type_ip);
+ const field_bits = field_type.bitSize(zcu);
+ if (field_bits != backing_int_bits) return sema.failWithOwnedErrorMsg(block, msg: {
+ const field_ty_src = block.src(.{ .container_field_type = @intCast(field_idx) });
+ const msg = try sema.errMsg(field_ty_src, "field bit width does not match backing integer", .{});
+ errdefer msg.destroy(gpa);
+ try sema.errNote(field_ty_src, msg, "field type '{f}' has bit width '{d}'", .{ field_type.fmt(pt), field_bits });
+ try sema.errNote(
+ block.src(.container_arg),
+ msg,
+ "backing integer '{f}' has bit width '{d}'",
+ .{ backing_ty.fmt(pt), backing_int_bits },
+ );
+ try sema.errNote(field_ty_src, msg, "all fields in a packed union must have the same bit width", .{});
+ break :msg msg;
+ });
+ }
+ break :ty backing_ty;
+ } else ty: {
+ const field_types = union_obj.field_types.get(ip);
+ const first_field_type: Type = .fromInterned(field_types[0]);
+ const first_field_bits = first_field_type.bitSize(zcu);
+ for (field_types[1..], 1..) |field_type_ip, field_idx| {
+ const field_type: Type = .fromInterned(field_type_ip);
+ const field_bits = field_type.bitSize(zcu);
+ if (field_bits != first_field_bits) return sema.failWithOwnedErrorMsg(block, msg: {
+ const first_field_ty_src = block.src(.{ .container_field_type = 0 });
+ const field_ty_src = block.src(.{ .container_field_type = @intCast(field_idx) });
+ const msg = try sema.errMsg(field_ty_src, "field bit width does not match earlier field", .{});
+ errdefer msg.destroy(gpa);
+ try sema.errNote(field_ty_src, msg, "field type '{f}' has bit width '{d}'", .{ field_type.fmt(pt), field_bits });
+ try sema.errNote(first_field_ty_src, msg, "other field type '{f}' has bit width '{d}'", .{ first_field_type.fmt(pt), first_field_bits });
+ try sema.errNote(field_ty_src, msg, "all fields in a packed union must have the same bit width", .{});
+ break :msg msg;
+ });
+ }
+ const backing_int_bits = std.math.cast(u16, first_field_bits) orelse return sema.fail(
+ block,
+ union_ty.srcLoc(zcu),
+ "packed union bit width '{d}' exceeds maximum bit width of 65535",
+ .{first_field_bits},
+ );
+ break :ty try pt.intType(.unsigned, backing_int_bits);
+ };
+ ip.resolvePackedUnionLayout(
+ io,
+ union_ty.toIntern(),
+ enum_tag_ty.toIntern(),
+ backing_int_ty.toIntern(),
+ );
+}
+
+pub fn resolveEnumLayout(sema: *Sema, enum_ty: Type) CompileError!void {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
+ const comp = zcu.comp;
+ const io = comp.io;
+ const gpa = comp.gpa;
+ const ip = &zcu.intern_pool;
+
+ assert(sema.owner.unwrap().type_layout == enum_ty.toIntern());
+
+ const enum_obj = ip.loadEnumType(enum_ty.toIntern());
+ assert(enum_obj.want_layout);
+
+ const maybe_parent_union_obj: ?InternPool.LoadedUnionType = un: {
+ if (enum_obj.owner_union == .none) break :un null;
+ break :un ip.loadUnionType(enum_obj.owner_union);
+ };
+
+ const tracked_inst = enum_obj.zir_index.unwrap() orelse maybe_parent_union_obj.?.zir_index;
+ const zir_index = tracked_inst.resolve(ip) orelse return error.AnalysisFail;
+
+ var block: Block = .{
+ .parent = null,
+ .sema = sema,
+ .namespace = enum_obj.namespace,
+ .instructions = .empty,
+ .inlining = null,
+ .comptime_reason = undefined, // always set before using `block`
+ .src_base_inst = tracked_inst,
+ .type_name_ctx = enum_obj.name,
+ };
+ defer block.instructions.deinit(gpa);
+
+ // There may be old field names in the map from a previous update.
+ enum_obj.field_name_map.get(ip).clearRetainingCapacity();
+
+ if (maybe_parent_union_obj) |*union_obj| {
+ if (union_obj.is_reified) {
+ // In the case of reification, the union stores the field names, just for us to copy.
+ @memcpy(enum_obj.field_names.get(ip), union_obj.reified_field_names.get(ip));
+ // The list of field names is now populated, but we haven't checked for duplicates yet,
+ // nor have we populated the hash map.
+ for (0..enum_obj.field_names.len) |field_index| {
+ const name = enum_obj.field_names.get(ip)[field_index];
+ if (ip.addFieldName(enum_obj.field_names, enum_obj.field_name_map, name)) |prev_field_index| {
+ return sema.failWithOwnedErrorMsg(&block, msg: {
+ const src = block.builtinCallArgSrc(.zero, 2);
+ const msg = try sema.errMsg(src, "duplicate union field '{f}' at index '{d}", .{ name.fmt(ip), field_index });
+ errdefer msg.destroy(gpa);
+ try sema.errNote(src, msg, "previous field at index '{d}'", .{prev_field_index});
+ break :msg msg;
+ });
+ }
+ }
+ } else {
+ // Generated tag enums for declared unions do not yet have field names populated. It is
+ // our job to populate them now.
+ try sema.declareDependency(.{ .src_hash = union_obj.zir_index });
+ const zir_union = sema.code.getUnionDecl(zir_index);
+ for (zir_union.field_names) |zir_field_name| {
+ const name_slice = sema.code.nullTerminatedString(zir_field_name);
+ const name = try ip.getOrPutString(gpa, io, pt.tid, name_slice, .no_embedded_nulls);
+ assert(ip.addFieldName(enum_obj.field_names, enum_obj.field_name_map, name) == null); // AstGen validated this for us
+ }
+ }
+ } else {
+ if (enum_obj.is_reified) {
+ // The field names are populated, but we haven't checked for duplicates (nor populated the map) yet.
+ for (0..enum_obj.field_names.len) |field_index| {
+ const name = enum_obj.field_names.get(ip)[field_index];
+ if (ip.addFieldName(enum_obj.field_names, enum_obj.field_name_map, name)) |prev_field_index| {
+ return sema.failWithOwnedErrorMsg(&block, msg: {
+ const src = block.builtinCallArgSrc(.zero, 2);
+ const msg = try sema.errMsg(src, "duplicate enum field '{f}' at index '{d}'", .{ name.fmt(ip), field_index });
+ errdefer msg.destroy(gpa);
+ try sema.errNote(src, msg, "previous field at index '{d}'", .{prev_field_index});
+ break :msg msg;
+ });
+ }
+ }
+ } else {
+ // Declared enums do not yet have field names populated. It is our job to populate them now.
+ try sema.declareDependency(.{ .src_hash = enum_obj.zir_index.unwrap().? });
+ const zir_enum = sema.code.getEnumDecl(zir_index);
+ for (zir_enum.field_names) |zir_field_name| {
+ const name_slice = sema.code.nullTerminatedString(zir_field_name);
+ const name = try ip.getOrPutString(gpa, io, pt.tid, name_slice, .no_embedded_nulls);
+ assert(ip.addFieldName(enum_obj.field_names, enum_obj.field_name_map, name) == null); // AstGen validated this for us
+ }
+ }
+ }
+
+ // Field names populated; now deal with the backing integer type. If explicitly provided,
+ // validate it; otherwise, infer it.
+
+ const explicit_int_tag_ty: ?Type = if (enum_obj.is_reified) ty: {
+ break :ty switch (enum_obj.int_tag_mode) {
+ .explicit => .fromInterned(enum_obj.int_tag_type),
+ .auto => null,
+ };
+ } else if (maybe_parent_union_obj) |*union_obj| ty: {
+ if (union_obj.is_reified) {
+ // Reification has no equivalent of 'union(enum(T))'.
+ break :ty null;
+ }
+ const zir_union = sema.code.getUnionDecl(zir_index);
+ if (zir_union.kind != .tagged_enum_explicit) {
+ break :ty null; // int tag type will be inferred
+ }
+ // Explicitly specified, so evaluate the int tag type expression.
+ const tag_type_body = zir_union.arg_type_body.?;
+ const tag_type_src = block.src(.container_arg);
+ block.comptime_reason = .{ .reason = .{
+ .src = tag_type_src,
+ .r = .{ .simple = .enum_int_tag_type },
+ } };
+ const type_ref = try sema.resolveInlineBody(&block, tag_type_body, zir_index);
+ break :ty try sema.analyzeAsType(&block, tag_type_src, .enum_int_tag_type, type_ref);
+ } else ty: {
+ const zir_enum = sema.code.getEnumDecl(zir_index);
+ const tag_type_body = zir_enum.tag_type_body orelse {
+ break :ty null; // int tag type will be inferred
+ };
+ // Explicitly specified, so evaluate the int tag type expression.
+ const tag_type_src = block.src(.container_arg);
+ block.comptime_reason = .{ .reason = .{
+ .src = tag_type_src,
+ .r = .{ .simple = .enum_int_tag_type },
+ } };
+ const type_ref = try sema.resolveInlineBody(&block, tag_type_body, zir_index);
+ break :ty try sema.analyzeAsType(&block, tag_type_src, .enum_int_tag_type, type_ref);
+ };
+ const int_tag_ty: Type = if (explicit_int_tag_ty) |int_tag_ty| ty: {
+ if (int_tag_ty.zigTypeTag(zcu) != .int) return sema.fail(
+ &block,
+ block.src(.container_arg),
+ "expected integer tag type, found '{f}'",
+ .{int_tag_ty.fmt(pt)},
+ );
+ break :ty int_tag_ty;
+ } else ty: {
+ // Infer the int tag type from the field count
+ const bits = Type.smallestUnsignedBits(enum_obj.field_names.len -| 1);
+ break :ty try pt.intType(.unsigned, bits);
+ };
+
+ ip.resolveEnumLayout(io, enum_ty.toIntern(), int_tag_ty.toIntern());
+
+ // Finally, deal with field values. For declared types we need to analyze the expressions, while
+ // reified types already have them populated; but either way, we need to populate the hash map
+ // (and validate the values along the way).
+
+ // We'll populate this map.
+ const field_value_map = enum_obj.field_value_map.unwrap() orelse {
+ // The enum is auto-numbered with an inferred tag type. We know that the tag type generated
+ // earlier is sufficient for the number of fields, so we have nothing more to do.
+ assert(enum_obj.int_tag_mode == .auto);
+ return;
+ };
+
+ // There may be old field values in here from a previous update.
+ field_value_map.get(ip).clearRetainingCapacity();
+
+ // Map the enum (or union) decl instruction to provide the tag type as the result type
+ try sema.inst_map.ensureSpaceForInstructions(gpa, &.{zir_index});
+ sema.inst_map.putAssumeCapacity(zir_index, .fromIntern(int_tag_ty.toIntern()));
+ defer assert(sema.inst_map.remove(zir_index));
+
+ // First, populate any explicitly provided values. This is the part that actually depends on
+ // the ZIR, and hence depends on whether this is a declared or generated enum. If any explicit
+ // value is straight-up invalid, we'll emit an error here.
+ if (maybe_parent_union_obj) |union_obj| {
+ if (union_obj.is_reified) {
+ // Generated tag type for reified union; values already populated.
+ } else {
+ // Generated tag type for declared union; evaluate the expressions given in the union declaration.
+ const zir_union = sema.code.getUnionDecl(zir_index);
+ var field_it = zir_union.iterateFields();
+ while (field_it.next()) |zir_field| {
+ const field_val_src = block.src(.{ .container_field_value = zir_field.idx });
+ block.comptime_reason = .{ .reason = .{
+ .src = field_val_src,
+ .r = .{ .simple = .enum_field_values },
+ } };
+ const value_body = zir_field.value_body orelse {
+ enum_obj.field_values.get(ip)[zir_field.idx] = .none;
+ continue;
+ };
+ const uncoerced = try sema.resolveInlineBody(&block, value_body, zir_index);
+ const coerced = try sema.coerce(&block, int_tag_ty, uncoerced, field_val_src);
+ const val = try sema.resolveConstValue(&block, field_val_src, coerced, null);
+ enum_obj.field_values.get(ip)[zir_field.idx] = val.toIntern();
+ }
+ }
+ } else if (enum_obj.is_reified) {
+ // Reified enum; values already populated.
+ } else {
+ // Declared enum; evaluate the expressions given in the enum declaration.
+ const zir_enum = sema.code.getEnumDecl(zir_index);
+ var field_it = zir_enum.iterateFields();
+ while (field_it.next()) |zir_field| {
+ const field_val_src = block.src(.{ .container_field_value = zir_field.idx });
+ block.comptime_reason = .{ .reason = .{
+ .src = field_val_src,
+ .r = .{ .simple = .enum_field_values },
+ } };
+ const value_body = zir_field.value_body orelse {
+ enum_obj.field_values.get(ip)[zir_field.idx] = .none;
+ continue;
+ };
+ const uncoerced = try sema.resolveInlineBody(&block, value_body, zir_index);
+ const coerced = try sema.coerce(&block, int_tag_ty, uncoerced, field_val_src);
+ const val = try sema.resolveConstDefinedValue(&block, field_val_src, coerced, null);
+ enum_obj.field_values.get(ip)[zir_field.idx] = val.toIntern();
+ }
+ }
+
+ // Explicit values are set. Now we'll go through the whole array and figure out the final
+ // field values. This is also where we'll detect duplicates.
+
+ for (0..enum_obj.field_names.len) |field_idx| {
+ const field_val_src = block.src(.{ .container_field_value = @intCast(field_idx) });
+ // If the field value was not specified, compute the implicit value.
+ const field_val = val: {
+ const explicit_val = enum_obj.field_values.get(ip)[field_idx];
+ if (explicit_val != .none) {
+ assert(ip.typeOf(explicit_val) == int_tag_ty.toIntern());
+ break :val explicit_val;
+ }
+ if (field_idx == 0) {
+ // Implicit value is 0, which is valid for every integer type.
+ const val = (try pt.intValue(int_tag_ty, 0)).toIntern();
+ enum_obj.field_values.get(ip)[field_idx] = val;
+ break :val val;
+ }
+ // Implicit non-initial value: take the previous field value and add one.
+ const prev_field_val: Value = .fromInterned(enum_obj.field_values.get(ip)[field_idx - 1]);
+ const result = try arith.incrementDefinedInt(sema, int_tag_ty, prev_field_val);
+ if (result.overflow) return sema.fail(
+ &block,
+ field_val_src,
+ "enum tag value '{f}' too large for type '{f}'",
+ .{ result.val.fmtValueSema(pt, sema), int_tag_ty.fmt(pt) },
+ );
+ const val = result.val.toIntern();
+ enum_obj.field_values.get(ip)[field_idx] = val;
+ break :val val;
+ };
+ if (ip.addFieldTagValue(enum_obj.field_values, field_value_map, field_val)) |prev_field_index| {
+ return sema.failWithOwnedErrorMsg(&block, msg: {
+ const prev_field_val_src = block.src(.{ .container_field_value = prev_field_index });
+ const msg = try sema.errMsg(field_val_src, "enum tag value '{f}' for field '{f}' already taken", .{
+ Value.fromInterned(field_val).fmtValueSema(pt, sema),
+ enum_obj.field_names.get(ip)[field_idx].fmt(ip),
+ });
+ errdefer msg.destroy(gpa);
+ try sema.errNote(prev_field_val_src, msg, "previous occurrence in field '{f}'", .{
+ enum_obj.field_names.get(ip)[prev_field_index].fmt(ip),
+ });
+ break :msg msg;
+ });
+ }
+ }
+
+ if (enum_obj.nonexhaustive) {
+ const fields_len = enum_obj.field_names.len;
+ if (fields_len >= 1 and std.math.log2_int(u64, fields_len) == int_tag_ty.bitSize(zcu)) {
+ return sema.fail(&block, block.nodeOffset(.zero), "non-exhaustive enum specifies every value", .{});
+ }
+ }
+}
diff --git a/src/Type.zig b/src/Type.zig
index 57d8a0a5ede75204e3382f4740f28c9b83799681..841ca38b0e536b79ca44817eb55941b864ac3f56 100644
--- a/src/Type.zig
+++ b/src/Type.zig
@@ -12,12 +12,10 @@ const Target = std.Target;
const Zcu = @import("Zcu.zig");
const log = std.log.scoped(.Type);
const target_util = @import("target.zig");
-const Sema = @import("Sema.zig");
const InternPool = @import("InternPool.zig");
const Alignment = InternPool.Alignment;
const Zir = std.zig.Zir;
const Type = @This();
-const SemaError = Zcu.SemaError;
ip_index: InternPool.Index,
@@ -25,15 +23,289 @@ pub fn zigTypeTag(ty: Type, zcu: *const Zcu) std.builtin.TypeId {
return zcu.intern_pool.zigTypeTag(ty.toIntern());
}
-pub fn baseZigTypeTag(self: Type, mod: *Zcu) std.builtin.TypeId {
- return switch (self.zigTypeTag(mod)) {
- .error_union => self.errorUnionPayload(mod).baseZigTypeTag(mod),
- .optional => {
- return self.optionalChild(mod).baseZigTypeTag(mod);
+/// Every type is a member of exactly one "class" which determines:
+/// * whether values of the type can exist at all
+/// * whether values of the type can be runtime-knwon
+/// * whether the type is considered comptime-only
+/// * whether the type has runtime bits (nonzero ABI size)
+pub const Class = enum(u3) {
+ /// Values of this type cannot exist because the type semantically has no values. Attempting to
+ /// create a value of this type (such as by coercing `undefined`) always emits a compile error.
+ ///
+ /// Not comptime-only. No runtime bits, i.e. ABI size is 0.
+ ///
+ /// Exhaustive list of no-possible-value ("NPV") types:
+ /// * `noreturn`
+ /// * `anyopaque`, and any `opaque` type
+ /// * `[n]T` where `n` is non-zero and `T` is NPV
+ /// * Any tuple where at least one non-`comptime` field has an NPV type
+ /// * Any enum whose backing type is `noreturn`
+ /// * Any struct where at least one non-`comptime` field has an NPV type
+ /// * Any union where every field has an NPV type (including unions with no fields)
+ /// * If the union would typically have a runtime tag, even if that tag would have runtime
+ /// bits, the union type is still NPV; the runtime tag is effectively omitted.
+ no_possible_value,
+
+ /// Values of this type are always comptime-known because there is only one value inhabiting the
+ /// type. This matches the colloquial understanding of a "zero-bit type".
+ ///
+ /// Not comptime-only (although always comptime-known). No runtime bits, i.e. ABI size is 0.
+ ///
+ /// Exhaustive list of one-possible-value ("OPV") types:
+ /// * `void`
+ /// * `u0`, `i0`
+ /// * `[0]T` for any `T`
+ /// * `[n]T` where `T` is OPV
+ /// * `[n:s]T` where `T` is OPV
+ /// * `@Vector(0, T)` for any `T`
+ /// * `@Vector(n, T)` where `T` is OPV
+ /// * Any tuple where every non-`comptime` field has an OPV type (including tuples with no fields)
+ /// * Any enum whose backing type is OPV
+ /// * Any struct where every non-`comptime` field has an OPV type (including structs with no fields)
+ /// * Any union with no runtime tag where all fields have OPV
+ /// * Any union where one field has an OPV type, and either:
+ /// * All other fields have NPV types (in this case, if there would be a runtime tag, it is omitted)
+ /// * All other fields have NPV or OPV types, and the union has no runtime tag
+ one_possible_value,
+
+ /// The type holds state (so it is neither NPV nor OPV), but contains no comptime-only state, so
+ /// values may be runtime-known.
+ ///
+ /// Not comptime-only. Has runtime bits, i.e. ABI size is non-zero.
+ ///
+ /// Most types which are typically used in Zig inhabit this class. For instance, all pointer
+ /// types, all integer types other than `u0` and `i0`, and most user-defined aggregates fall
+ /// into this category.
+ runtime,
+
+ /// The type holds state (so it is neither NPV nor OPV). Some, but not all, of the contained
+ /// state is comptime-only.
+ ///
+ /// Comptime-only. Has runtime bits, i.e. ABI size is non-zero.
+ ///
+ /// Partially-comptime types arise from aggregates (`struct`s, `union`s, or tuples) which have
+ /// some fields with fully-comptime types (such as `comptime_int`) and some fields with runtime
+ /// types (such as `u8`). Because the user may acquire pointers to these fields, pointers to the
+ /// embedded runtime state must be valid, so backends are required to lower the runtime state
+ /// within the type.
+ ///
+ /// Note that logically-runtime state which cannot be directly referenced by the user (such as
+ /// the enum tag of a tagged union type, or the "populated" bit of an optional type) does not
+ /// cause a type to be partially-comptime.
+ partially_comptime,
+
+ /// The type contains exclusively comptime-only state.
+ ///
+ /// Comptime-only. No runtime bits, i.e. ABI size is 0.
+ ///
+ /// Fully-comptime types arise from a handful of primitive fully-comptime types:
+ /// * `type`
+ /// * `comptime_int`
+ /// * `comptime_float`
+ /// * `@EnumLiteral()`
+ /// * `@TypeOf(null)`
+ /// * `@TypeOf(undefined)`
+ ///
+ /// Then, aggregates containing fully-comptime types may themselves be either fully-comptime or
+ /// partially-comptime; see the doc comment on `.partially_comptime` for details.
+ fully_comptime,
+};
+
+/// Returns the `Class` for the type `ty`. Asserts that the layout of `ty` is resolved.
+pub fn classify(start_ty: Type, zcu: *const Zcu) Class {
+ const ip = &zcu.intern_pool;
+
+ // We avoid recursion in most cases to make us more optimizer-friendly because this can be a
+ // very hot code path. The only case where recursion is necessary is tuples, so that case is
+ // outlined into a separate function; see `classifyTuple`.
+
+ var extra_states: enum { none, one, many } = .none;
+
+ var cur_ty = start_ty;
+ const base: Class = while (true) break switch (ip.indexToKey(cur_ty.toIntern())) {
+ .simple_type => |t| switch (t) {
+ .f16,
+ .f32,
+ .f64,
+ .f80,
+ .f128,
+ .usize,
+ .isize,
+ .c_char,
+ .c_short,
+ .c_ushort,
+ .c_int,
+ .c_uint,
+ .c_long,
+ .c_ulong,
+ .c_longlong,
+ .c_ulonglong,
+ .c_longdouble,
+ .bool,
+ .anyerror,
+ .adhoc_inferred_error_set,
+ => .runtime,
+
+ .anyopaque => .no_possible_value,
+
+ .type,
+ .comptime_int,
+ .comptime_float,
+ .enum_literal,
+ .null,
+ .undefined,
+ => .fully_comptime,
+
+ .void => .one_possible_value,
+ .noreturn => .no_possible_value,
+
+ .generic_poison => unreachable,
+ },
+
+ .error_set_type,
+ .inferred_error_set_type,
+ .ptr_type,
+ .anyframe_type,
+ => .runtime,
+
+ .func_type => .fully_comptime,
+
+ .opaque_type => .no_possible_value,
+
+ .error_union_type => |eu| {
+ extra_states = .many;
+ cur_ty = .fromInterned(eu.payload_type);
+ continue;
+ },
+
+ .int_type => |int| switch (int.bits) {
+ 0 => .one_possible_value,
+ else => .runtime,
+ },
+ .array_type => |arr| {
+ if (arr.len == 0 and arr.sentinel == .none) break .one_possible_value;
+ cur_ty = .fromInterned(arr.child);
+ continue;
+ },
+ .vector_type => |vec| {
+ if (vec.len == 0) break .one_possible_value;
+ cur_ty = .fromInterned(vec.child);
+ continue;
+ },
+ .opt_type => |child_ty_ip| {
+ extra_states = switch (extra_states) {
+ .none => .one,
+ .one, .many => .many,
+ };
+ cur_ty = .fromInterned(child_ty_ip);
+ continue;
+ },
+ .tuple_type => |tuple| {
+ @branchHint(.unlikely);
+ break classifyTuple(tuple.types.get(ip), tuple.values.get(ip), zcu);
+ },
+ .struct_type => {
+ const struct_obj = ip.loadStructType(cur_ty.toIntern());
+ switch (struct_obj.layout) {
+ .auto, .@"extern" => {
+ zcu.assertUpToDate(.wrap(.{ .type_layout = cur_ty.toIntern() }));
+ break struct_obj.class;
+ },
+ .@"packed" => {
+ cur_ty = .fromInterned(struct_obj.packed_backing_int_type);
+ continue;
+ },
+ }
+ },
+ .union_type => {
+ const union_obj = ip.loadUnionType(cur_ty.toIntern());
+ switch (union_obj.layout) {
+ .auto, .@"extern" => {
+ zcu.assertUpToDate(.wrap(.{ .type_layout = cur_ty.toIntern() }));
+ break union_obj.class;
+ },
+ .@"packed" => {
+ cur_ty = .fromInterned(union_obj.packed_backing_int_type);
+ continue;
+ },
+ }
+ },
+ .enum_type => {
+ zcu.assertUpToDate(.wrap(.{ .type_layout = cur_ty.toIntern() }));
+ cur_ty = .fromInterned(ip.loadEnumType(cur_ty.toIntern()).int_tag_type);
+ continue;
+ },
+
+ // values, not types
+ .undef,
+ .simple_value,
+ .variable,
+ .@"extern",
+ .func,
+ .int,
+ .err,
+ .error_union,
+ .enum_literal,
+ .enum_tag,
+ .float,
+ .ptr,
+ .slice,
+ .opt,
+ .aggregate,
+ .un,
+ .bitpack,
+ // memoization, not types
+ .memoized_call,
+ => unreachable,
+ };
+
+ return switch (base) {
+ .runtime => .runtime, // extra states are irrelevant, we already have many!
+ .partially_comptime => .partially_comptime, // likewise
+ .fully_comptime => {
+ // We do not need to change to `.partially_comptime` here because the extra states do
+ // not necessarily require runtime bits. This is because Zig does not provide a way to
+ // take the address of the "is null" bit of an optional or the error set "inside" of an
+ // error union.
+ return .fully_comptime;
+ },
+
+ .no_possible_value => switch (extra_states) {
+ .none => .no_possible_value,
+ .one => .one_possible_value,
+ .many => .runtime,
+ },
+
+ .one_possible_value => switch (extra_states) {
+ .none => .one_possible_value,
+ .one, .many => .runtime,
},
- else => |t| t,
};
}
+/// This is a separate function to `classify` to avoid recursion in the main `classify` function,
+/// which can encourage the optimizer to e.g. inline `classify` where it would be beneficial.
+fn classifyTuple(types: []const InternPool.Index, values: []const InternPool.Index, zcu: *const Zcu) Class {
+ var has_runtime_state = false;
+ var has_comptime_state = false;
+ for (types, values) |field_ty, field_comptime_val| {
+ if (field_comptime_val != .none) continue;
+ switch (Type.fromInterned(field_ty).classify(zcu)) {
+ .no_possible_value => return .no_possible_value,
+ .one_possible_value => {},
+ .runtime => has_runtime_state = true,
+ .fully_comptime => has_comptime_state = true,
+ .partially_comptime => {
+ has_runtime_state = true;
+ has_comptime_state = true;
+ },
+ }
+ }
+ if (has_comptime_state) {
+ return if (has_runtime_state) .partially_comptime else .fully_comptime;
+ } else {
+ return if (has_runtime_state) .runtime else .one_possible_value;
+ }
+}
/// Asserts the type is resolved.
pub fn isSelfComparable(ty: Type, zcu: *const Zcu, is_equality_cmp: bool) bool {
@@ -44,7 +316,7 @@ pub fn isSelfComparable(ty: Type, zcu: *const Zcu, is_equality_cmp: bool) bool {
.comptime_int,
=> true,
- .vector => ty.elemType2(zcu).isSelfComparable(zcu, is_equality_cmp),
+ .vector => ty.childType(zcu).isSelfComparable(zcu, is_equality_cmp),
.bool,
.type,
@@ -121,11 +393,7 @@ pub fn eql(a: Type, b: Type, zcu: *const Zcu) bool {
return a.toIntern() == b.toIntern();
}
-pub fn format(ty: Type, writer: *std.Io.Writer) !void {
- _ = ty;
- _ = writer;
- @compileError("do not format types directly; use either ty.fmtDebug() or ty.fmt()");
-}
+pub const format = @compileError("do not format types directly; use either ty.fmtDebug() or ty.fmt()");
pub const Formatter = std.fmt.Alt(Format, Format.default);
@@ -416,13 +684,13 @@ pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread, ctx: ?*Compari
.error_union,
.enum_literal,
.enum_tag,
- .empty_enum_value,
.float,
.ptr,
.slice,
.opt,
.aggregate,
.un,
+ .bitpack,
// memoization, not types
.memoized_call,
=> unreachable,
@@ -440,247 +708,41 @@ pub fn toIntern(ty: Type) InternPool.Index {
}
pub fn toValue(self: Type) Value {
- return Value.fromInterned(self.toIntern());
+ return .fromInterned(self.toIntern());
}
-const RuntimeBitsError = SemaError || error{NeedLazy};
-
+/// Returns `true` if and only if the type takes up space in memory at runtime. This is also exactly
+/// whether or not the backend/linker needs to be sent values of this type to emit to the binary.
+///
+/// Types without runtime bits have an ABI size of 0; all other types have a non-zero ABI size. All
+/// types, regardless of whether they have runtime bits, have a non-zero ABI alignment.
+///
+/// Comptime-only types may still have runtime bits. For instance, `struct { a: u32, b: type }` is a
+/// comptime-only type, but it nonetheless has runtime bits and a runtime memory layout (where the
+/// field `b: type` is omitted). This is because a user may take a pointer to the field `a`, which
+/// must then be valid to use at runtime.
+///
+/// This function is a trivial wrapper around `classify`:
+///
+/// * Types with one possible value, such as `void`, or no possible value, such as `noreturn`, do
+/// not have runtime bits and have an ABI size of 0 because they simply contain no state.
+///
+/// * Types which are fully comptime, such as `type` and `comptime_int`, do not have runtime bits
+/// because they contain only comptime state. (This compiler implementation also currently makes
+/// types like `struct { x: comptime_int }` fully comptime, but that could change in the future if
+/// we start inserting hidden safety fields into them.)
+///
+/// * All other types contain some runtime state, so have runtime bits and a non-zero ABI size.
pub fn hasRuntimeBits(ty: Type, zcu: *const Zcu) bool {
- return hasRuntimeBitsInner(ty, false, .eager, zcu, {}) catch unreachable;
-}
-
-pub fn hasRuntimeBitsSema(ty: Type, pt: Zcu.PerThread) SemaError!bool {
- return hasRuntimeBitsInner(ty, false, .sema, pt.zcu, pt.tid) catch |err| switch (err) {
- error.NeedLazy => unreachable, // this would require a resolve strat of lazy
- else => |e| return e,
- };
-}
-
-pub fn hasRuntimeBitsIgnoreComptime(ty: Type, zcu: *const Zcu) bool {
- return hasRuntimeBitsInner(ty, true, .eager, zcu, {}) catch unreachable;
-}
-
-pub fn hasRuntimeBitsIgnoreComptimeSema(ty: Type, pt: Zcu.PerThread) SemaError!bool {
- return hasRuntimeBitsInner(ty, true, .sema, pt.zcu, pt.tid) catch |err| switch (err) {
- error.NeedLazy => unreachable, // this would require a resolve strat of lazy
- else => |e| return e,
- };
-}
-
-/// true if and only if the type takes up space in memory at runtime.
-/// There are two reasons a type will return false:
-/// * the type is a comptime-only type. For example, the type `type` itself.
-/// - note, however, that a struct can have mixed fields and only the non-comptime-only
-/// fields will count towards the ABI size. For example, `struct {T: type, x: i32}`
-/// hasRuntimeBits()=true and abiSize()=4
-/// * the type has only one possible value, making its ABI size 0.
-/// - an enum with an explicit tag type has the ABI size of the integer tag type,
-/// making it one-possible-value only if the integer tag type has 0 bits.
-/// When `ignore_comptime_only` is true, then types that are comptime-only
-/// may return false positives.
-pub fn hasRuntimeBitsInner(
- ty: Type,
- ignore_comptime_only: bool,
- comptime strat: ResolveStratLazy,
- zcu: strat.ZcuPtr(),
- tid: strat.Tid(),
-) RuntimeBitsError!bool {
- const ip = &zcu.intern_pool;
- const io = zcu.comp.io;
- return switch (ty.toIntern()) {
- .empty_tuple_type => false,
- else => switch (ip.indexToKey(ty.toIntern())) {
- .int_type => |int_type| int_type.bits != 0,
- .ptr_type => {
- // Pointers to zero-bit types still have a runtime address; however, pointers
- // to comptime-only types do not, with the exception of function pointers.
- if (ignore_comptime_only) return true;
- return switch (strat) {
- .sema => {
- const pt = strat.pt(zcu, tid);
- return !try ty.comptimeOnlySema(pt);
- },
- .eager => !ty.comptimeOnly(zcu),
- .lazy => error.NeedLazy,
- };
- },
- .anyframe_type => true,
- .array_type => |array_type| return array_type.lenIncludingSentinel() > 0 and
- try Type.fromInterned(array_type.child).hasRuntimeBitsInner(ignore_comptime_only, strat, zcu, tid),
- .vector_type => |vector_type| return vector_type.len > 0 and
- try Type.fromInterned(vector_type.child).hasRuntimeBitsInner(ignore_comptime_only, strat, zcu, tid),
- .opt_type => |child| {
- const child_ty = Type.fromInterned(child);
- if (child_ty.isNoReturn(zcu)) {
- // Then the optional is comptime-known to be null.
- return false;
- }
- if (ignore_comptime_only) return true;
- return switch (strat) {
- .sema => !try child_ty.comptimeOnlyInner(.sema, zcu, tid),
- .eager => !child_ty.comptimeOnly(zcu),
- .lazy => error.NeedLazy,
- };
- },
- .error_union_type,
- .error_set_type,
- .inferred_error_set_type,
- => true,
-
- // These are function *bodies*, not pointers.
- // They return false here because they are comptime-only types.
- // Special exceptions have to be made when emitting functions due to
- // this returning false.
- .func_type => false,
-
- .simple_type => |t| switch (t) {
- .f16,
- .f32,
- .f64,
- .f80,
- .f128,
- .usize,
- .isize,
- .c_char,
- .c_short,
- .c_ushort,
- .c_int,
- .c_uint,
- .c_long,
- .c_ulong,
- .c_longlong,
- .c_ulonglong,
- .c_longdouble,
- .bool,
- .anyerror,
- .adhoc_inferred_error_set,
- .anyopaque,
- => true,
-
- // These are false because they are comptime-only types.
- .void,
- .type,
- .comptime_int,
- .comptime_float,
- .noreturn,
- .null,
- .undefined,
- .enum_literal,
- => false,
-
- .generic_poison => unreachable,
- },
- .struct_type => {
- const struct_type = ip.loadStructType(ty.toIntern());
- if (strat != .eager and struct_type.assumeRuntimeBitsIfFieldTypesWip(ip, io)) {
- // In this case, we guess that hasRuntimeBits() for this type is true,
- // and then later if our guess was incorrect, we emit a compile error.
- return true;
- }
- switch (strat) {
- .sema => try ty.resolveFields(strat.pt(zcu, tid)),
- .eager => assert(struct_type.haveFieldTypes(ip)),
- .lazy => if (!struct_type.haveFieldTypes(ip)) return error.NeedLazy,
- }
- for (0..struct_type.field_types.len) |i| {
- if (struct_type.comptime_bits.getBit(ip, i)) continue;
- const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);
- if (try field_ty.hasRuntimeBitsInner(ignore_comptime_only, strat, zcu, tid))
- return true;
- } else {
- return false;
- }
- },
- .tuple_type => |tuple| {
- for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
- if (val != .none) continue; // comptime field
- if (try Type.fromInterned(field_ty).hasRuntimeBitsInner(
- ignore_comptime_only,
- strat,
- zcu,
- tid,
- )) return true;
- }
- return false;
- },
-
- .union_type => {
- const union_type = ip.loadUnionType(ty.toIntern());
- const union_flags = union_type.flagsUnordered(ip);
- switch (union_flags.runtime_tag) {
- .none => if (strat != .eager) {
- // In this case, we guess that hasRuntimeBits() for this type is true,
- // and then later if our guess was incorrect, we emit a compile error.
- if (union_type.assumeRuntimeBitsIfFieldTypesWip(ip, io)) return true;
- },
- .safety, .tagged => {},
- }
- switch (strat) {
- .sema => try ty.resolveFields(strat.pt(zcu, tid)),
- .eager => assert(union_flags.status.haveFieldTypes()),
- .lazy => if (!union_flags.status.haveFieldTypes())
- return error.NeedLazy,
- }
- switch (union_flags.runtime_tag) {
- .none => {},
- .safety, .tagged => {
- const tag_ty = union_type.tagTypeUnordered(ip);
- assert(tag_ty != .none); // tag_ty should have been resolved above
- if (try Type.fromInterned(tag_ty).hasRuntimeBitsInner(
- ignore_comptime_only,
- strat,
- zcu,
- tid,
- )) {
- return true;
- }
- },
- }
- for (0..union_type.field_types.len) |field_index| {
- const field_ty = Type.fromInterned(union_type.field_types.get(ip)[field_index]);
- if (try field_ty.hasRuntimeBitsInner(ignore_comptime_only, strat, zcu, tid))
- return true;
- } else {
- return false;
- }
- },
-
- .opaque_type => true,
- .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).hasRuntimeBitsInner(
- ignore_comptime_only,
- strat,
- zcu,
- tid,
- ),
-
- // values, not types
- .undef,
- .simple_value,
- .variable,
- .@"extern",
- .func,
- .int,
- .err,
- .error_union,
- .enum_literal,
- .enum_tag,
- .empty_enum_value,
- .float,
- .ptr,
- .slice,
- .opt,
- .aggregate,
- .un,
- // memoization, not types
- .memoized_call,
- => unreachable,
- },
+ return switch (ty.classify(zcu)) {
+ .no_possible_value, .one_possible_value, .fully_comptime => false,
+ .runtime, .partially_comptime => true,
};
}
-/// true if and only if the type has a well-defined memory layout
-/// readFrom/writeToMemory are supported only for types with a well-
-/// defined memory layout
+/// Returns `true` iff the memory layout of `ty` is defined by the Zig language specification.
+///
+/// Does not require `ty` to be resolved.
pub fn hasWellDefinedLayout(ty: Type, zcu: *const Zcu) bool {
const ip = &zcu.intern_pool;
return switch (ip.indexToKey(ty.toIntern())) {
@@ -737,17 +799,17 @@ pub fn hasWellDefinedLayout(ty: Type, zcu: *const Zcu) bool {
.generic_poison,
=> false,
},
- .struct_type => ip.loadStructType(ty.toIntern()).layout != .auto,
- .union_type => {
- const union_type = ip.loadUnionType(ty.toIntern());
- return switch (union_type.flagsUnordered(ip).runtime_tag) {
- .none, .safety => union_type.flagsUnordered(ip).layout != .auto,
- .tagged => false,
- };
+ .struct_type => switch (ip.loadStructType(ty.toIntern()).layout) {
+ .auto => false,
+ .@"extern", .@"packed" => true,
+ },
+ .union_type => switch (ip.loadUnionType(ty.toIntern()).layout) {
+ .auto => false,
+ .@"extern", .@"packed" => true,
},
- .enum_type => switch (ip.loadEnumType(ty.toIntern()).tag_mode) {
+ .enum_type => switch (ip.loadEnumType(ty.toIntern()).int_tag_mode) {
+ .explicit => true,
.auto => false,
- .explicit, .nonexhaustive => true,
},
// values, not types
@@ -761,86 +823,88 @@ pub fn hasWellDefinedLayout(ty: Type, zcu: *const Zcu) bool {
.error_union,
.enum_literal,
.enum_tag,
- .empty_enum_value,
.float,
.ptr,
.slice,
.opt,
.aggregate,
.un,
+ .bitpack,
// memoization, not types
.memoized_call,
=> unreachable,
};
}
-pub fn fnHasRuntimeBits(ty: Type, zcu: *Zcu) bool {
- return ty.fnHasRuntimeBitsInner(.normal, zcu, {}) catch unreachable;
-}
-
-pub fn fnHasRuntimeBitsSema(ty: Type, pt: Zcu.PerThread) SemaError!bool {
- return try ty.fnHasRuntimeBitsInner(.sema, pt.zcu, pt.tid);
-}
-
/// Determines whether a function type has runtime bits, i.e. whether a
/// function with this type can exist at runtime.
/// Asserts that `ty` is a function type.
-pub fn fnHasRuntimeBitsInner(
- ty: Type,
- comptime strat: ResolveStrat,
- zcu: strat.ZcuPtr(),
- tid: strat.Tid(),
-) SemaError!bool {
- const fn_info = zcu.typeToFunc(ty).?;
- if (fn_info.is_generic) return false;
- if (fn_info.is_var_args) return true;
+pub fn fnHasRuntimeBits(fn_ty: Type, zcu: *const Zcu) bool {
+ assertHasLayout(fn_ty, zcu);
+ const fn_info = zcu.typeToFunc(fn_ty).?;
+ if (fn_info.comptime_bits != 0) return false;
+ for (fn_info.param_types.get(&zcu.intern_pool)) |param_ty| {
+ if (param_ty == .generic_poison_type) return false;
+ switch (Type.fromInterned(param_ty).classify(zcu)) {
+ .fully_comptime,
+ .partially_comptime,
+ .no_possible_value,
+ => return false,
+
+ .one_possible_value,
+ .runtime,
+ => {},
+ }
+ }
+ const ret_ty: Type = .fromInterned(fn_info.return_type);
+ if (ret_ty.toIntern() == .generic_poison_type) {
+ return false;
+ }
+ if (ret_ty.zigTypeTag(zcu) == .error_union and
+ ret_ty.errorUnionPayload(zcu).toIntern() == .generic_poison_type)
+ {
+ return false;
+ }
+ switch (ret_ty.classify(zcu)) {
+ .fully_comptime,
+ .partially_comptime,
+ => return false,
+
+ .no_possible_value,
+ .one_possible_value,
+ .runtime,
+ => {},
+ }
if (fn_info.cc == .@"inline") return false;
- return !try Type.fromInterned(fn_info.return_type).comptimeOnlyInner(strat, zcu, tid);
+ return true;
}
-pub fn isFnOrHasRuntimeBits(ty: Type, zcu: *Zcu) bool {
+/// Like `hasRuntimeBits`, but also returns `true` for runtime functions.
+pub fn isRuntimeFnOrHasRuntimeBits(ty: Type, zcu: *const Zcu) bool {
switch (ty.zigTypeTag(zcu)) {
.@"fn" => return ty.fnHasRuntimeBits(zcu),
else => return ty.hasRuntimeBits(zcu),
}
}
-/// Same as `isFnOrHasRuntimeBits` but comptime-only types may return a false positive.
-pub fn isFnOrHasRuntimeBitsIgnoreComptime(ty: Type, zcu: *Zcu) bool {
- return switch (ty.zigTypeTag(zcu)) {
- .@"fn" => true,
- else => return ty.hasRuntimeBitsIgnoreComptime(zcu),
- };
-}
-
+/// Returns whether `ty` is NPV, meaning it is "like `noreturn`" in a sense. See doc comments on
+/// `Class` for more details.
+///
+/// Exactly equivalent to `ty.classify(zcu) == .no_possible_value`.
pub fn isNoReturn(ty: Type, zcu: *const Zcu) bool {
- return zcu.intern_pool.isNoReturn(ty.toIntern());
+ return ty.classify(zcu) == .no_possible_value;
}
/// Never returns `none`. Asserts that all necessary type resolution is already done.
-pub fn ptrAlignment(ty: Type, zcu: *Zcu) Alignment {
- return ptrAlignmentInner(ty, .normal, zcu, {}) catch unreachable;
-}
-
-pub fn ptrAlignmentSema(ty: Type, pt: Zcu.PerThread) SemaError!Alignment {
- return try ty.ptrAlignmentInner(.sema, pt.zcu, pt.tid);
-}
-
-pub fn ptrAlignmentInner(
- ty: Type,
- comptime strat: ResolveStrat,
- zcu: strat.ZcuPtr(),
- tid: strat.Tid(),
-) !Alignment {
- return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
- .ptr_type => |ptr_type| {
- if (ptr_type.flags.alignment != .none) return ptr_type.flags.alignment;
- const res = try Type.fromInterned(ptr_type.child).abiAlignmentInner(strat.toLazy(), zcu, tid);
- return res.scalar;
- },
- .opt_type => |child| Type.fromInterned(child).ptrAlignmentInner(strat, zcu, tid),
+pub fn ptrAlignment(ptr_ty: Type, zcu: *Zcu) Alignment {
+ const ip = &zcu.intern_pool;
+ const ptr_key: InternPool.Key.PtrType = switch (ip.indexToKey(ptr_ty.toIntern())) {
+ .ptr_type => |key| key,
+ .opt_type => |child| ip.indexToKey(child).ptr_type,
else => unreachable,
};
+ if (ptr_key.flags.alignment != .none) return ptr_key.flags.alignment;
+ return Type.fromInterned(ptr_key.child).abiAlignment(zcu);
}
pub fn ptrAddressSpace(ty: Type, zcu: *const Zcu) std.builtin.AddressSpace {
@@ -851,861 +915,364 @@ pub fn ptrAddressSpace(ty: Type, zcu: *const Zcu) std.builtin.AddressSpace {
};
}
-/// May capture a reference to `ty`.
-/// Returned value has type `comptime_int`.
-pub fn lazyAbiAlignment(ty: Type, pt: Zcu.PerThread) !Value {
- switch (try ty.abiAlignmentInner(.lazy, pt.zcu, pt.tid)) {
- .val => |val| return val,
- .scalar => |x| return pt.intValue(Type.comptime_int, x.toByteUnits() orelse 0),
- }
-}
-
-pub const AbiAlignmentInner = union(enum) {
- scalar: Alignment,
- val: Value,
-};
-
-pub const ResolveStratLazy = enum {
- /// Return a `lazy_size` or `lazy_align` value if necessary.
- /// This value can be resolved later using `Value.resolveLazy`.
- lazy,
- /// Return a scalar result, expecting all necessary type resolution to be completed.
- /// Backends should typically use this, since they must not perform type resolution.
- eager,
- /// Return a scalar result, performing type resolution as necessary.
- /// This should typically be used from semantic analysis.
- sema,
-
- pub fn Tid(strat: ResolveStratLazy) type {
- return switch (strat) {
- .lazy, .sema => Zcu.PerThread.Id,
- .eager => void,
- };
- }
-
- pub fn ZcuPtr(strat: ResolveStratLazy) type {
- return switch (strat) {
- .eager => *const Zcu,
- .sema, .lazy => *Zcu,
- };
- }
-
- pub fn pt(
- comptime strat: ResolveStratLazy,
- zcu: strat.ZcuPtr(),
- tid: strat.Tid(),
- ) switch (strat) {
- .lazy, .sema => Zcu.PerThread,
- .eager => void,
- } {
- return switch (strat) {
- .lazy, .sema => .{ .tid = tid, .zcu = zcu },
- else => {},
- };
- }
-};
-
-/// The chosen strategy can be easily optimized away in release builds.
-/// However, in debug builds, it helps to avoid accidentally resolving types in backends.
-pub const ResolveStrat = enum {
- /// Assert that all necessary resolution is completed.
- /// Backends should typically use this, since they must not perform type resolution.
- normal,
- /// Perform type resolution as necessary using `Zcu`.
- /// This should typically be used from semantic analysis.
- sema,
-
- pub fn Tid(strat: ResolveStrat) type {
- return switch (strat) {
- .sema => Zcu.PerThread.Id,
- .normal => void,
- };
- }
-
- pub fn ZcuPtr(strat: ResolveStrat) type {
- return switch (strat) {
- .normal => *const Zcu,
- .sema => *Zcu,
- };
- }
-
- pub fn pt(comptime strat: ResolveStrat, zcu: strat.ZcuPtr(), tid: strat.Tid()) switch (strat) {
- .sema => Zcu.PerThread,
- .normal => void,
- } {
- return switch (strat) {
- .sema => .{ .tid = tid, .zcu = zcu },
- .normal => {},
- };
- }
-
- pub inline fn toLazy(strat: ResolveStrat) ResolveStratLazy {
- return switch (strat) {
- .normal => .eager,
- .sema => .sema,
- };
- }
-};
-
-/// Never returns `none`. Asserts that all necessary type resolution is already done.
+/// Never returns `.none`. Asserts that the layout of `ty` is resolved.
+///
+/// Unlike ABI size, a type's ABI alignment is not affected by its `Class`. In other words, any
+/// alignment is possible regardless of the result of `ty.classify(zcu)`.
pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment {
- return (ty.abiAlignmentInner(.eager, zcu, {}) catch unreachable).scalar;
-}
-
-pub fn abiAlignmentSema(ty: Type, pt: Zcu.PerThread) SemaError!Alignment {
- return (try ty.abiAlignmentInner(.sema, pt.zcu, pt.tid)).scalar;
-}
-
-/// If you pass `eager` you will get back `scalar` and assert the type is resolved.
-/// In this case there will be no error, guaranteed.
-/// If you pass `lazy` you may get back `scalar` or `val`.
-/// If `val` is returned, a reference to `ty` has been captured.
-/// If you pass `sema` you will get back `scalar` and resolve the type if
-/// necessary, possibly returning a CompileError.
-pub fn abiAlignmentInner(
- ty: Type,
- comptime strat: ResolveStratLazy,
- zcu: strat.ZcuPtr(),
- tid: strat.Tid(),
-) SemaError!AbiAlignmentInner {
- const pt = strat.pt(zcu, tid);
- const target = zcu.getTarget();
const ip = &zcu.intern_pool;
-
- switch (ty.toIntern()) {
- .empty_tuple_type => return .{ .scalar = .@"1" },
- else => switch (ip.indexToKey(ty.toIntern())) {
- .int_type => |int_type| {
- if (int_type.bits == 0) return .{ .scalar = .@"1" };
- return .{ .scalar = .fromByteUnits(std.zig.target.intAlignment(target, int_type.bits)) };
- },
- .ptr_type, .anyframe_type => {
- return .{ .scalar = ptrAbiAlignment(target) };
- },
- .array_type => |array_type| {
- return Type.fromInterned(array_type.child).abiAlignmentInner(strat, zcu, tid);
- },
- .vector_type => |vector_type| {
- if (vector_type.len == 0) return .{ .scalar = .@"1" };
- switch (zcu.comp.getZigBackend()) {
- else => {
- // This is fine because the child type of a vector always has a bit-size known
- // without needing any type resolution.
- const elem_bits: u32 = @intCast(Type.fromInterned(vector_type.child).bitSize(zcu));
- if (elem_bits == 0) return .{ .scalar = .@"1" };
- const bytes = ((elem_bits * vector_type.len) + 7) / 8;
- const alignment = std.math.ceilPowerOfTwoAssert(u32, bytes);
- return .{ .scalar = Alignment.fromByteUnits(alignment) };
- },
- .stage2_c => {
- return Type.fromInterned(vector_type.child).abiAlignmentInner(strat, zcu, tid);
- },
- .stage2_x86_64 => {
- if (vector_type.child == .bool_type) {
- if (vector_type.len > 256 and target.cpu.has(.x86, .avx512f)) return .{ .scalar = .@"64" };
- if (vector_type.len > 128 and target.cpu.has(.x86, .avx)) return .{ .scalar = .@"32" };
- if (vector_type.len > 64) return .{ .scalar = .@"16" };
- const bytes = std.math.divCeil(u32, vector_type.len, 8) catch unreachable;
- const alignment = std.math.ceilPowerOfTwoAssert(u32, bytes);
- return .{ .scalar = Alignment.fromByteUnits(alignment) };
- }
- const elem_bytes: u32 = @intCast((try Type.fromInterned(vector_type.child).abiSizeInner(strat, zcu, tid)).scalar);
- if (elem_bytes == 0) return .{ .scalar = .@"1" };
- const bytes = elem_bytes * vector_type.len;
- if (bytes > 32 and target.cpu.has(.x86, .avx512f)) return .{ .scalar = .@"64" };
- if (bytes > 16 and target.cpu.has(.x86, .avx)) return .{ .scalar = .@"32" };
- return .{ .scalar = .@"16" };
- },
- }
- },
-
- .opt_type => return ty.abiAlignmentInnerOptional(strat, zcu, tid),
- .error_union_type => |info| return ty.abiAlignmentInnerErrorUnion(
- strat,
- zcu,
- tid,
- Type.fromInterned(info.payload_type),
- ),
-
- .error_set_type, .inferred_error_set_type => {
- const bits = zcu.errorSetBits();
- if (bits == 0) return .{ .scalar = .@"1" };
- return .{ .scalar = .fromByteUnits(std.zig.target.intAlignment(target, bits)) };
- },
-
- // represents machine code; not a pointer
- .func_type => return .{ .scalar = target_util.minFunctionAlignment(target) },
-
- .simple_type => |t| switch (t) {
- .bool,
- .anyopaque,
- => return .{ .scalar = .@"1" },
-
- .usize,
- .isize,
- => return .{ .scalar = .fromByteUnits(std.zig.target.intAlignment(target, target.ptrBitWidth())) },
-
- .c_char => return .{ .scalar = cTypeAlign(target, .char) },
- .c_short => return .{ .scalar = cTypeAlign(target, .short) },
- .c_ushort => return .{ .scalar = cTypeAlign(target, .ushort) },
- .c_int => return .{ .scalar = cTypeAlign(target, .int) },
- .c_uint => return .{ .scalar = cTypeAlign(target, .uint) },
- .c_long => return .{ .scalar = cTypeAlign(target, .long) },
- .c_ulong => return .{ .scalar = cTypeAlign(target, .ulong) },
- .c_longlong => return .{ .scalar = cTypeAlign(target, .longlong) },
- .c_ulonglong => return .{ .scalar = cTypeAlign(target, .ulonglong) },
- .c_longdouble => return .{ .scalar = cTypeAlign(target, .longdouble) },
-
- .f16 => return .{ .scalar = .@"2" },
- .f32 => return .{ .scalar = cTypeAlign(target, .float) },
- .f64 => switch (target.cTypeBitSize(.double)) {
- 64 => return .{ .scalar = cTypeAlign(target, .double) },
- else => return .{ .scalar = .@"8" },
- },
- .f80 => switch (target.cTypeBitSize(.longdouble)) {
- 80 => return .{ .scalar = cTypeAlign(target, .longdouble) },
- else => return .{ .scalar = Type.u80.abiAlignment(zcu) },
+ const target = zcu.getTarget();
+ assertHasLayout(ty, zcu);
+ return switch (ip.indexToKey(ty.toIntern())) {
+ .int_type => |int_type| {
+ if (int_type.bits == 0) return .@"1";
+ return .fromByteUnits(std.zig.target.intAlignment(target, int_type.bits));
+ },
+ .ptr_type, .anyframe_type => ptrAbiAlignment(target),
+ .array_type => |array_type| Type.fromInterned(array_type.child).abiAlignment(zcu),
+ .vector_type => |vector_type| {
+ if (vector_type.len == 0) return .@"1";
+ switch (zcu.comp.getZigBackend()) {
+ else => {
+ const elem_bits: u32 = @intCast(Type.fromInterned(vector_type.child).bitSize(zcu));
+ if (elem_bits == 0) return .@"1";
+ const bytes = ((elem_bits * vector_type.len) + 7) / 8;
+ return .fromByteUnits(std.math.ceilPowerOfTwoAssert(u32, bytes));
},
- .f128 => switch (target.cTypeBitSize(.longdouble)) {
- 128 => return .{ .scalar = cTypeAlign(target, .longdouble) },
- else => return .{ .scalar = .@"16" },
- },
-
- .anyerror, .adhoc_inferred_error_set => {
- const bits = zcu.errorSetBits();
- if (bits == 0) return .{ .scalar = .@"1" };
- return .{ .scalar = .fromByteUnits(std.zig.target.intAlignment(target, bits)) };
- },
-
- .void,
- .type,
- .comptime_int,
- .comptime_float,
- .null,
- .undefined,
- .enum_literal,
- => return .{ .scalar = .@"1" },
-
- .noreturn => unreachable,
- .generic_poison => unreachable,
- },
- .struct_type => {
- const struct_type = ip.loadStructType(ty.toIntern());
- if (struct_type.layout == .@"packed") {
- switch (strat) {
- .sema => try ty.resolveLayout(pt),
- .lazy => if (struct_type.backingIntTypeUnordered(ip) == .none) return .{
- .val = Value.fromInterned(try pt.intern(.{ .int = .{
- .ty = .comptime_int_type,
- .storage = .{ .lazy_align = ty.toIntern() },
- } })),
- },
- .eager => {},
- }
- return .{ .scalar = Type.fromInterned(struct_type.backingIntTypeUnordered(ip)).abiAlignment(zcu) };
- }
-
- if (struct_type.flagsUnordered(ip).alignment == .none) switch (strat) {
- .eager => unreachable, // struct alignment not resolved
- .sema => try ty.resolveStructAlignment(pt),
- .lazy => return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{
- .ty = .comptime_int_type,
- .storage = .{ .lazy_align = ty.toIntern() },
- } })) },
- };
-
- return .{ .scalar = struct_type.flagsUnordered(ip).alignment };
- },
- .tuple_type => |tuple| {
- var big_align: Alignment = .@"1";
- for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
- if (val != .none) continue; // comptime field
- switch (try Type.fromInterned(field_ty).abiAlignmentInner(strat, zcu, tid)) {
- .scalar => |field_align| big_align = big_align.max(field_align),
- .val => switch (strat) {
- .eager => unreachable, // field type alignment not resolved
- .sema => unreachable, // passed to abiAlignmentInner above
- .lazy => return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{
- .ty = .comptime_int_type,
- .storage = .{ .lazy_align = ty.toIntern() },
- } })) },
- },
+ .stage2_c => return Type.fromInterned(vector_type.child).abiAlignment(zcu),
+ .stage2_x86_64 => {
+ if (vector_type.child == .bool_type) {
+ if (vector_type.len > 256 and target.cpu.has(.x86, .avx512f)) return .@"64";
+ if (vector_type.len > 128 and target.cpu.has(.x86, .avx)) return .@"32";
+ if (vector_type.len > 64) return .@"16";
+ const bytes = std.math.divCeil(u32, vector_type.len, 8) catch unreachable;
+ return .fromByteUnits(std.math.ceilPowerOfTwoAssert(u32, bytes));
}
- }
- return .{ .scalar = big_align };
- },
- .union_type => {
- const union_type = ip.loadUnionType(ty.toIntern());
-
- if (union_type.flagsUnordered(ip).alignment == .none) switch (strat) {
- .eager => unreachable, // union layout not resolved
- .sema => try ty.resolveUnionAlignment(pt),
- .lazy => return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{
- .ty = .comptime_int_type,
- .storage = .{ .lazy_align = ty.toIntern() },
- } })) },
- };
-
- return .{ .scalar = union_type.flagsUnordered(ip).alignment };
- },
- .opaque_type => return .{ .scalar = .@"1" },
- .enum_type => return .{
- .scalar = Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).abiAlignment(zcu),
- },
-
- // values, not types
- .undef,
- .simple_value,
- .variable,
- .@"extern",
- .func,
- .int,
- .err,
- .error_union,
+ const elem_bytes: u32 = @intCast(Type.fromInterned(vector_type.child).abiSize(zcu));
+ if (elem_bytes == 0) return .@"1";
+ const bytes = elem_bytes * vector_type.len;
+ if (bytes > 32 and target.cpu.has(.x86, .avx512f)) return .@"64";
+ if (bytes > 16 and target.cpu.has(.x86, .avx)) return .@"32";
+ return .@"16";
+ },
+ }
+ },
+
+ .opt_type => |child| Type.fromInterned(child).abiAlignment(zcu),
+ .error_union_type => |eu| Alignment.maxStrict(
+ Type.fromInterned(eu.payload_type).abiAlignment(zcu),
+ errorAbiAlignment(zcu),
+ ),
+
+ .error_set_type, .inferred_error_set_type => errorAbiAlignment(zcu),
+
+ .func_type => target_util.minFunctionAlignment(target),
+
+ .simple_type => |t| switch (t) {
+ .bool,
+ .void,
+ .noreturn,
+ .anyopaque,
+ .type,
+ .comptime_int,
+ .comptime_float,
+ .null,
+ .undefined,
.enum_literal,
- .enum_tag,
- .empty_enum_value,
- .float,
- .ptr,
- .slice,
- .opt,
- .aggregate,
- .un,
- // memoization, not types
- .memoized_call,
- => unreachable,
- },
- }
-}
+ => .@"1",
-fn abiAlignmentInnerErrorUnion(
- ty: Type,
- comptime strat: ResolveStratLazy,
- zcu: strat.ZcuPtr(),
- tid: strat.Tid(),
- payload_ty: Type,
-) SemaError!AbiAlignmentInner {
- // This code needs to be kept in sync with the equivalent switch prong
- // in abiSizeInner.
- const code_align = Type.anyerror.abiAlignment(zcu);
- switch (strat) {
- .eager, .sema => {
- if (!(payload_ty.hasRuntimeBitsInner(false, strat, zcu, tid) catch |err| switch (err) {
- error.NeedLazy => if (strat == .lazy) {
- const pt = strat.pt(zcu, tid);
- return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{
- .ty = .comptime_int_type,
- .storage = .{ .lazy_align = ty.toIntern() },
- } })) };
- } else unreachable,
- else => |e| return e,
- })) {
- return .{ .scalar = code_align };
- }
- return .{ .scalar = code_align.max(
- (try payload_ty.abiAlignmentInner(strat, zcu, tid)).scalar,
- ) };
- },
- .lazy => {
- const pt = strat.pt(zcu, tid);
- switch (try payload_ty.abiAlignmentInner(strat, zcu, tid)) {
- .scalar => |payload_align| return .{ .scalar = code_align.max(payload_align) },
- .val => {},
- }
- return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{
- .ty = .comptime_int_type,
- .storage = .{ .lazy_align = ty.toIntern() },
- } })) };
- },
- }
-}
+ .anyerror, .adhoc_inferred_error_set => errorAbiAlignment(zcu),
+ .usize, .isize => .fromByteUnits(std.zig.target.intAlignment(target, target.ptrBitWidth())),
-fn abiAlignmentInnerOptional(
- ty: Type,
- comptime strat: ResolveStratLazy,
- zcu: strat.ZcuPtr(),
- tid: strat.Tid(),
-) SemaError!AbiAlignmentInner {
- const pt = strat.pt(zcu, tid);
- const target = zcu.getTarget();
- const child_type = ty.optionalChild(zcu);
+ .c_char => cTypeAlign(target, .char),
+ .c_short => cTypeAlign(target, .short),
+ .c_ushort => cTypeAlign(target, .ushort),
+ .c_int => cTypeAlign(target, .int),
+ .c_uint => cTypeAlign(target, .uint),
+ .c_long => cTypeAlign(target, .long),
+ .c_ulong => cTypeAlign(target, .ulong),
+ .c_longlong => cTypeAlign(target, .longlong),
+ .c_ulonglong => cTypeAlign(target, .ulonglong),
+ .c_longdouble => cTypeAlign(target, .longdouble),
- switch (child_type.zigTypeTag(zcu)) {
- .pointer => return .{ .scalar = ptrAbiAlignment(target) },
- .error_set => return Type.anyerror.abiAlignmentInner(strat, zcu, tid),
- .noreturn => return .{ .scalar = .@"1" },
- else => {},
- }
+ .f16 => .@"2",
+ .f32 => cTypeAlign(target, .float),
+ .f64 => switch (target.cTypeBitSize(.double)) {
+ 64 => cTypeAlign(target, .double),
+ else => .@"8",
+ },
+ .f80 => switch (target.cTypeBitSize(.longdouble)) {
+ 80 => cTypeAlign(target, .longdouble),
+ else => Type.u80.abiAlignment(zcu),
+ },
+ .f128 => switch (target.cTypeBitSize(.longdouble)) {
+ 128 => cTypeAlign(target, .longdouble),
+ else => .@"16",
+ },
- switch (strat) {
- .eager, .sema => {
- if (!(child_type.hasRuntimeBitsInner(false, strat, zcu, tid) catch |err| switch (err) {
- error.NeedLazy => if (strat == .lazy) {
- return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{
- .ty = .comptime_int_type,
- .storage = .{ .lazy_align = ty.toIntern() },
- } })) };
- } else unreachable,
- else => |e| return e,
- })) {
- return .{ .scalar = .@"1" };
+ .generic_poison => unreachable,
+ },
+ .tuple_type => |tuple| {
+ var big_align: Alignment = .@"1";
+ for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
+ if (val != .none) continue; // comptime field
+ const field_align = Type.fromInterned(field_ty).abiAlignment(zcu);
+ big_align = big_align.maxStrict(field_align);
}
- return child_type.abiAlignmentInner(strat, zcu, tid);
+ return big_align;
},
- .lazy => switch (try child_type.abiAlignmentInner(strat, zcu, tid)) {
- .scalar => |x| return .{ .scalar = x.max(.@"1") },
- .val => return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{
- .ty = .comptime_int_type,
- .storage = .{ .lazy_align = ty.toIntern() },
- } })) },
+ .struct_type => {
+ const struct_obj = ip.loadStructType(ty.toIntern());
+ switch (struct_obj.layout) {
+ .@"packed" => return Type.fromInterned(struct_obj.packed_backing_int_type).abiAlignment(zcu),
+ .auto, .@"extern" => {
+ assert(struct_obj.alignment != .none);
+ return struct_obj.alignment;
+ },
+ }
},
- }
-}
+ .union_type => {
+ const union_obj = ip.loadUnionType(ty.toIntern());
+ switch (union_obj.layout) {
+ .@"packed" => return Type.fromInterned(union_obj.packed_backing_int_type).abiAlignment(zcu),
+ .auto, .@"extern" => {
+ assert(union_obj.alignment != .none);
+ return union_obj.alignment;
+ },
+ }
+ },
+ .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).abiAlignment(zcu),
+ .opaque_type => .@"1",
-const AbiSizeInner = union(enum) {
- scalar: u64,
- val: Value,
-};
+ // values, not types
+ .undef,
+ .simple_value,
+ .variable,
+ .@"extern",
+ .func,
+ .int,
+ .err,
+ .error_union,
+ .enum_literal,
+ .enum_tag,
+ .float,
+ .ptr,
+ .slice,
+ .opt,
+ .aggregate,
+ .un,
+ .bitpack,
+ // memoization, not types
+ .memoized_call,
+ => unreachable,
+ };
+}
-/// Asserts the type has the ABI size already resolved.
-/// Types that return false for hasRuntimeBits() return 0.
+/// Asserts that `ty` is not an opaque type, and that the layout of `ty` is resolved.
+///
+/// If the type is NPV, OPV, or fully-comptime (see `Class`), the return value of this function is
+/// guaranteed to be zero. Otherwise (if the type is runtime or partially-comptime) the return value
+/// is guaranteed to be non-zero.
pub fn abiSize(ty: Type, zcu: *const Zcu) u64 {
- return (abiSizeInner(ty, .eager, zcu, {}) catch unreachable).scalar;
-}
-
-/// May capture a reference to `ty`.
-pub fn abiSizeLazy(ty: Type, pt: Zcu.PerThread) !Value {
- switch (try ty.abiSizeInner(.lazy, pt.zcu, pt.tid)) {
- .val => |val| return val,
- .scalar => |x| return pt.intValue(Type.comptime_int, x),
- }
-}
-
-pub fn abiSizeSema(ty: Type, pt: Zcu.PerThread) SemaError!u64 {
- return (try abiSizeInner(ty, .sema, pt.zcu, pt.tid)).scalar;
-}
-
-/// If you pass `eager` you will get back `scalar` and assert the type is resolved.
-/// In this case there will be no error, guaranteed.
-/// If you pass `lazy` you may get back `scalar` or `val`.
-/// If `val` is returned, a reference to `ty` has been captured.
-/// If you pass `sema` you will get back `scalar` and resolve the type if
-/// necessary, possibly returning a CompileError.
-pub fn abiSizeInner(
- ty: Type,
- comptime strat: ResolveStratLazy,
- zcu: strat.ZcuPtr(),
- tid: strat.Tid(),
-) SemaError!AbiSizeInner {
- const target = zcu.getTarget();
const ip = &zcu.intern_pool;
-
- switch (ty.toIntern()) {
- .empty_tuple_type => return .{ .scalar = 0 },
-
- else => switch (ip.indexToKey(ty.toIntern())) {
- .int_type => |int_type| {
- if (int_type.bits == 0) return .{ .scalar = 0 };
- return .{ .scalar = std.zig.target.intByteSize(target, int_type.bits) };
- },
- .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
- .slice => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) * 2 },
- else => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) },
- },
- .anyframe_type => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) },
-
- .array_type => |array_type| {
- const len = array_type.lenIncludingSentinel();
- if (len == 0) return .{ .scalar = 0 };
- switch (try Type.fromInterned(array_type.child).abiSizeInner(strat, zcu, tid)) {
- .scalar => |elem_size| return .{ .scalar = len * elem_size },
- .val => switch (strat) {
- .sema, .eager => unreachable,
- .lazy => {
- const pt = strat.pt(zcu, tid);
- return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{
- .ty = .comptime_int_type,
- .storage = .{ .lazy_size = ty.toIntern() },
- } })) };
- },
- },
- }
- },
- .vector_type => |vector_type| {
- const sub_strat: ResolveStrat = switch (strat) {
- .sema => .sema,
- .eager => .normal,
- .lazy => {
- const pt = strat.pt(zcu, tid);
- return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{
- .ty = .comptime_int_type,
- .storage = .{ .lazy_size = ty.toIntern() },
- } })) };
- },
- };
- const alignment = (try ty.abiAlignmentInner(strat, zcu, tid)).scalar;
- const total_bytes = switch (zcu.comp.getZigBackend()) {
- else => total_bytes: {
- const elem_bits = try Type.fromInterned(vector_type.child).bitSizeInner(sub_strat, zcu, tid);
- const total_bits = elem_bits * vector_type.len;
- break :total_bytes (total_bits + 7) / 8;
- },
- .stage2_c => total_bytes: {
- const elem_bytes: u32 = @intCast((try Type.fromInterned(vector_type.child).abiSizeInner(strat, zcu, tid)).scalar);
- break :total_bytes elem_bytes * vector_type.len;
- },
- .stage2_x86_64 => total_bytes: {
- if (vector_type.child == .bool_type) break :total_bytes std.math.divCeil(u32, vector_type.len, 8) catch unreachable;
- const elem_bytes: u32 = @intCast((try Type.fromInterned(vector_type.child).abiSizeInner(strat, zcu, tid)).scalar);
- break :total_bytes elem_bytes * vector_type.len;
- },
- };
- return .{ .scalar = alignment.forward(total_bytes) };
- },
-
- .opt_type => return ty.abiSizeInnerOptional(strat, zcu, tid),
-
- .error_set_type, .inferred_error_set_type => {
- const bits = zcu.errorSetBits();
- if (bits == 0) return .{ .scalar = 0 };
- return .{ .scalar = std.zig.target.intByteSize(target, bits) };
- },
-
- .error_union_type => |error_union_type| {
- const payload_ty = Type.fromInterned(error_union_type.payload_type);
- // This code needs to be kept in sync with the equivalent switch prong
- // in abiAlignmentInner.
- const code_size = Type.anyerror.abiSize(zcu);
- if (!(payload_ty.hasRuntimeBitsInner(false, strat, zcu, tid) catch |err| switch (err) {
- error.NeedLazy => if (strat == .lazy) {
- const pt = strat.pt(zcu, tid);
- return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{
- .ty = .comptime_int_type,
- .storage = .{ .lazy_size = ty.toIntern() },
- } })) };
- } else unreachable,
- else => |e| return e,
- })) {
- // Same as anyerror.
- return .{ .scalar = code_size };
- }
- const code_align = Type.anyerror.abiAlignment(zcu);
- const payload_align = (try payload_ty.abiAlignmentInner(strat, zcu, tid)).scalar;
- const payload_size = switch (try payload_ty.abiSizeInner(strat, zcu, tid)) {
- .scalar => |elem_size| elem_size,
- .val => switch (strat) {
- .sema => unreachable,
- .eager => unreachable,
- .lazy => {
- const pt = strat.pt(zcu, tid);
- return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{
- .ty = .comptime_int_type,
- .storage = .{ .lazy_size = ty.toIntern() },
- } })) };
- },
- },
- };
-
- var size: u64 = 0;
- if (code_align.compare(.gt, payload_align)) {
- size += code_size;
- size = payload_align.forward(size);
- size += payload_size;
- size = code_align.forward(size);
- } else {
- size += payload_size;
- size = code_align.forward(size);
- size += code_size;
- size = payload_align.forward(size);
- }
- return .{ .scalar = size };
- },
- .func_type => unreachable, // represents machine code; not a pointer
- .simple_type => |t| switch (t) {
- .bool => return .{ .scalar = 1 },
-
- .f16 => return .{ .scalar = 2 },
- .f32 => return .{ .scalar = 4 },
- .f64 => return .{ .scalar = 8 },
- .f128 => return .{ .scalar = 16 },
- .f80 => switch (target.cTypeBitSize(.longdouble)) {
- 80 => return .{ .scalar = target.cTypeByteSize(.longdouble) },
- else => return .{ .scalar = Type.u80.abiSize(zcu) },
+ const target = zcu.getTarget();
+ assertHasLayout(ty, zcu);
+ return switch (ip.indexToKey(ty.toIntern())) {
+ .int_type => |int_type| std.zig.target.intByteSize(target, int_type.bits),
+ .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
+ .slice => ptrAbiSize(target) * 2,
+ .one, .many, .c => ptrAbiSize(target),
+ },
+ .anyframe_type => ptrAbiSize(target),
+ .array_type => |arr| arr.lenIncludingSentinel() * Type.fromInterned(arr.child).abiSize(zcu),
+ .vector_type => |vec| {
+ const elem_ty: Type = .fromInterned(vec.child);
+ const bytes = switch (zcu.comp.getZigBackend()) {
+ else => std.math.divCeil(u64, vec.len * elem_ty.bitSize(zcu), 8) catch unreachable,
+ .stage2_c => vec.len * elem_ty.abiSize(zcu),
+ .stage2_x86_64 => switch (elem_ty.toIntern()) {
+ .bool_type => std.math.divCeil(u64, vec.len, 8) catch unreachable,
+ else => vec.len * elem_ty.abiSize(zcu),
},
-
- .usize,
- .isize,
- => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) },
-
- .c_char => return .{ .scalar = target.cTypeByteSize(.char) },
- .c_short => return .{ .scalar = target.cTypeByteSize(.short) },
- .c_ushort => return .{ .scalar = target.cTypeByteSize(.ushort) },
- .c_int => return .{ .scalar = target.cTypeByteSize(.int) },
- .c_uint => return .{ .scalar = target.cTypeByteSize(.uint) },
- .c_long => return .{ .scalar = target.cTypeByteSize(.long) },
- .c_ulong => return .{ .scalar = target.cTypeByteSize(.ulong) },
- .c_longlong => return .{ .scalar = target.cTypeByteSize(.longlong) },
- .c_ulonglong => return .{ .scalar = target.cTypeByteSize(.ulonglong) },
- .c_longdouble => return .{ .scalar = target.cTypeByteSize(.longdouble) },
-
- .anyopaque,
- .void,
- .type,
- .comptime_int,
- .comptime_float,
- .null,
- .undefined,
- .enum_literal,
- => return .{ .scalar = 0 },
-
- .anyerror, .adhoc_inferred_error_set => {
- const bits = zcu.errorSetBits();
- if (bits == 0) return .{ .scalar = 0 };
- return .{ .scalar = std.zig.target.intByteSize(target, bits) };
- },
-
- .noreturn => unreachable,
- .generic_poison => unreachable,
- },
- .struct_type => {
- const struct_type = ip.loadStructType(ty.toIntern());
- switch (strat) {
- .sema => try ty.resolveLayout(strat.pt(zcu, tid)),
- .lazy => {
- const pt = strat.pt(zcu, tid);
- switch (struct_type.layout) {
- .@"packed" => {
- if (struct_type.backingIntTypeUnordered(ip) == .none) return .{
- .val = Value.fromInterned(try pt.intern(.{ .int = .{
- .ty = .comptime_int_type,
- .storage = .{ .lazy_size = ty.toIntern() },
- } })),
- };
- },
- .auto, .@"extern" => {
- if (!struct_type.haveLayout(ip)) return .{
- .val = Value.fromInterned(try pt.intern(.{ .int = .{
- .ty = .comptime_int_type,
- .storage = .{ .lazy_size = ty.toIntern() },
- } })),
- };
- },
- }
- },
- .eager => {},
- }
- switch (struct_type.layout) {
- .@"packed" => return .{
- .scalar = Type.fromInterned(struct_type.backingIntTypeUnordered(ip)).abiSize(zcu),
- },
- .auto, .@"extern" => {
- assert(struct_type.haveLayout(ip));
- return .{ .scalar = struct_type.sizeUnordered(ip) };
- },
- }
- },
- .tuple_type => |tuple| {
- switch (strat) {
- .sema => try ty.resolveLayout(strat.pt(zcu, tid)),
- .lazy, .eager => {},
- }
- const field_count = tuple.types.len;
- if (field_count == 0) {
- return .{ .scalar = 0 };
- }
- return .{ .scalar = ty.structFieldOffset(field_count, zcu) };
- },
-
- .union_type => {
- const union_type = ip.loadUnionType(ty.toIntern());
- switch (strat) {
- .sema => try ty.resolveLayout(strat.pt(zcu, tid)),
- .lazy => {
- const pt = strat.pt(zcu, tid);
- if (!union_type.flagsUnordered(ip).status.haveLayout()) return .{
- .val = Value.fromInterned(try pt.intern(.{ .int = .{
- .ty = .comptime_int_type,
- .storage = .{ .lazy_size = ty.toIntern() },
- } })),
- };
- },
- .eager => {},
- }
-
- assert(union_type.haveLayout(ip));
- return .{ .scalar = union_type.sizeUnordered(ip) };
- },
- .opaque_type => unreachable, // no size available
- .enum_type => return .{ .scalar = Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).abiSize(zcu) },
-
- // values, not types
- .undef,
- .simple_value,
- .variable,
- .@"extern",
- .func,
- .int,
- .err,
- .error_union,
+ };
+ return ty.abiAlignment(zcu).forward(bytes);
+ },
+ .opt_type => |child_ty_ip| {
+ const child_ty: Type = .fromInterned(child_ty_ip);
+ if (child_ty.classify(zcu) == .no_possible_value) return 0;
+ if (ty.optionalReprIsPayload(zcu)) return child_ty.abiSize(zcu);
+ // Optional types are represented as a struct with the child type as the first
+ // field and a boolean as the second. Since the child type's abi alignment is
+ // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal
+ // to the child type's ABI alignment.
+ return child_ty.abiSize(zcu) + child_ty.abiAlignment(zcu).toByteUnits().?;
+ },
+ .error_set_type, .inferred_error_set_type => errorAbiSize(zcu),
+ .error_union_type => |error_union| {
+ const payload_ty: Type = .fromInterned(error_union.payload_type);
+ switch (payload_ty.classify(zcu)) {
+ // Zig has no way to take the address of the error set "in" an error union (giving
+ // implementations more freedom in terms of data layout), so if the payload type is
+ // fully comptime, we don't need to dedicate runtime bits to the error set.
+ .fully_comptime => return 0,
+ else => {},
+ }
+ // The layout will either be (code, payload, padding) or (payload, code, padding)
+ // depending on which has larger alignment. So the overall size is just the code
+ // and payload sizes added and padded to the larger alignment.
+ const big_align: Alignment = .maxStrict(errorAbiAlignment(zcu), payload_ty.abiAlignment(zcu));
+ return big_align.forward(errorAbiSize(zcu) + payload_ty.abiSize(zcu));
+ },
+ .func_type => 0,
+ .simple_type => |t| switch (t) {
+ .void,
+ .noreturn,
+ .type,
+ .comptime_int,
+ .comptime_float,
+ .null,
+ .undefined,
.enum_literal,
- .enum_tag,
- .empty_enum_value,
- .float,
- .ptr,
- .slice,
- .opt,
- .aggregate,
- .un,
- // memoization, not types
- .memoized_call,
- => unreachable,
- },
- }
-}
-
-fn abiSizeInnerOptional(
- ty: Type,
- comptime strat: ResolveStratLazy,
- zcu: strat.ZcuPtr(),
- tid: strat.Tid(),
-) SemaError!AbiSizeInner {
- const child_ty = ty.optionalChild(zcu);
+ => 0,
- if (child_ty.isNoReturn(zcu)) {
- return .{ .scalar = 0 };
- }
+ .bool => 1,
+ .anyerror, .adhoc_inferred_error_set => errorAbiSize(zcu),
+ .usize, .isize => ptrAbiSize(target),
- if (!(child_ty.hasRuntimeBitsInner(false, strat, zcu, tid) catch |err| switch (err) {
- error.NeedLazy => if (strat == .lazy) {
- const pt = strat.pt(zcu, tid);
- return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{
- .ty = .comptime_int_type,
- .storage = .{ .lazy_size = ty.toIntern() },
- } })) };
- } else unreachable,
- else => |e| return e,
- })) return .{ .scalar = 1 };
+ .c_char => target.cTypeByteSize(.char),
+ .c_short => target.cTypeByteSize(.short),
+ .c_ushort => target.cTypeByteSize(.ushort),
+ .c_int => target.cTypeByteSize(.int),
+ .c_uint => target.cTypeByteSize(.uint),
+ .c_long => target.cTypeByteSize(.long),
+ .c_ulong => target.cTypeByteSize(.ulong),
+ .c_longlong => target.cTypeByteSize(.longlong),
+ .c_ulonglong => target.cTypeByteSize(.ulonglong),
+ .c_longdouble => target.cTypeByteSize(.longdouble),
- if (ty.optionalReprIsPayload(zcu)) {
- return child_ty.abiSizeInner(strat, zcu, tid);
- }
+ .f16 => 2,
+ .f32 => 4,
+ .f64 => 8,
+ .f80 => switch (target.cTypeBitSize(.longdouble)) {
+ 80 => target.cTypeByteSize(.longdouble),
+ else => Type.u80.abiSize(zcu),
+ },
+ .f128 => 16,
- const payload_size = switch (try child_ty.abiSizeInner(strat, zcu, tid)) {
- .scalar => |elem_size| elem_size,
- .val => switch (strat) {
- .sema => unreachable,
- .eager => unreachable,
- .lazy => return .{ .val = Value.fromInterned(try strat.pt(zcu, tid).intern(.{ .int = .{
- .ty = .comptime_int_type,
- .storage = .{ .lazy_size = ty.toIntern() },
- } })) },
+ .anyopaque => unreachable,
+ .generic_poison => unreachable,
+ },
+ .tuple_type => |tuple| switch (ty.classify(zcu)) {
+ // `structFieldOffset` is bogus on NPV tuples, because there may be some fields with
+ // non-zero size.
+ .no_possible_value => 0,
+ else => ty.structFieldOffset(tuple.types.len, zcu),
+ },
+ .struct_type => {
+ const struct_obj = ip.loadStructType(ty.toIntern());
+ switch (struct_obj.layout) {
+ .@"packed" => return Type.fromInterned(struct_obj.packed_backing_int_type).abiSize(zcu),
+ .auto, .@"extern" => return struct_obj.size,
+ }
+ },
+ .union_type => {
+ const union_obj = ip.loadUnionType(ty.toIntern());
+ switch (union_obj.layout) {
+ .@"packed" => return Type.fromInterned(union_obj.packed_backing_int_type).abiSize(zcu),
+ .auto, .@"extern" => return union_obj.size,
+ }
},
- };
+ .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).abiSize(zcu),
+ .opaque_type => unreachable,
- // Optional types are represented as a struct with the child type as the first
- // field and a boolean as the second. Since the child type's abi alignment is
- // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal
- // to the child type's ABI alignment.
- return .{
- .scalar = (child_ty.abiAlignment(zcu).toByteUnits() orelse 0) + payload_size,
+ // values, not types
+ .undef,
+ .simple_value,
+ .variable,
+ .@"extern",
+ .func,
+ .int,
+ .err,
+ .error_union,
+ .enum_literal,
+ .enum_tag,
+ .float,
+ .ptr,
+ .slice,
+ .opt,
+ .aggregate,
+ .un,
+ .bitpack,
+ // memoization, not types
+ .memoized_call,
+ => unreachable,
};
}
pub fn ptrAbiAlignment(target: *const Target) Alignment {
- return Alignment.fromNonzeroByteUnits(@divExact(target.ptrBitWidth(), 8));
+ return .fromNonzeroByteUnits(@divExact(target.ptrBitWidth(), 8));
+}
+pub fn ptrAbiSize(target: *const Target) u64 {
+ return @divExact(target.ptrBitWidth(), 8);
+}
+pub fn errorAbiAlignment(zcu: *const Zcu) Alignment {
+ return .fromNonzeroByteUnits(std.zig.target.intAlignment(zcu.getTarget(), zcu.errorSetBits()));
+}
+pub fn errorAbiSize(zcu: *const Zcu) u64 {
+ return std.zig.target.intByteSize(zcu.getTarget(), zcu.errorSetBits());
}
+/// Asserts that `ty` is not an opaque or comptime-only type.
+/// Once #19755 is implemented, this query will only work on types with a defined bit-level representation.
pub fn bitSize(ty: Type, zcu: *const Zcu) u64 {
- return bitSizeInner(ty, .normal, zcu, {}) catch unreachable;
-}
-
-pub fn bitSizeSema(ty: Type, pt: Zcu.PerThread) SemaError!u64 {
- return bitSizeInner(ty, .sema, pt.zcu, pt.tid);
-}
-
-pub fn bitSizeInner(
- ty: Type,
- comptime strat: ResolveStrat,
- zcu: strat.ZcuPtr(),
- tid: strat.Tid(),
-) SemaError!u64 {
const target = zcu.getTarget();
const ip = &zcu.intern_pool;
-
- const strat_lazy: ResolveStratLazy = strat.toLazy();
-
- switch (ip.indexToKey(ty.toIntern())) {
- .int_type => |int_type| return int_type.bits,
+ assertHasLayout(ty, zcu);
+ return switch (ip.indexToKey(ty.toIntern())) {
+ .int_type => |int_type| int_type.bits,
.ptr_type => |ptr_type| switch (ptr_type.flags.size) {
- .slice => return target.ptrBitWidth() * 2,
- else => return target.ptrBitWidth(),
+ .slice => target.ptrBitWidth() * 2,
+ else => target.ptrBitWidth(),
},
- .anyframe_type => return target.ptrBitWidth(),
-
+ .anyframe_type => target.ptrBitWidth(),
.array_type => |array_type| {
- const len = array_type.lenIncludingSentinel();
- if (len == 0) return 0;
const elem_ty: Type = .fromInterned(array_type.child);
- switch (zcu.comp.getZigBackend()) {
- else => {
- const elem_size = (try elem_ty.abiSizeInner(strat_lazy, zcu, tid)).scalar;
- if (elem_size == 0) return 0;
- const elem_bit_size = try elem_ty.bitSizeInner(strat, zcu, tid);
- return (len - 1) * 8 * elem_size + elem_bit_size;
+ const len = array_type.lenIncludingSentinel();
+ return switch (zcu.comp.getZigBackend()) {
+ .stage2_x86_64 => len * elem_ty.bitSize(zcu),
+ // this case will be removed under #19755
+ else => switch (len) {
+ 0 => 0,
+ else => (len - 1) * 8 * elem_ty.abiSize(zcu) + elem_ty.bitSize(zcu),
},
- .stage2_x86_64 => {
- const elem_bit_size = try elem_ty.bitSizeInner(strat, zcu, tid);
- return elem_bit_size * len;
- },
- }
- },
- .vector_type => |vector_type| {
- const child_ty: Type = .fromInterned(vector_type.child);
- const elem_bit_size = try child_ty.bitSizeInner(strat, zcu, tid);
- return elem_bit_size * vector_type.len;
- },
- .opt_type => {
- // Optionals and error unions are not packed so their bitsize
- // includes padding bits.
- return (try ty.abiSizeInner(strat_lazy, zcu, tid)).scalar * 8;
+ };
},
+ .vector_type => |vec| vec.len * Type.fromInterned(vec.child).bitSize(zcu),
+ .error_set_type, .inferred_error_set_type => zcu.errorSetBits(),
+ .func_type => unreachable,
- .error_set_type, .inferred_error_set_type => return zcu.errorSetBits(),
-
- .error_union_type => {
- // Optionals and error unions are not packed so their bitsize
- // includes padding bits.
- return (try ty.abiSizeInner(strat_lazy, zcu, tid)).scalar * 8;
- },
- .func_type => unreachable, // represents machine code; not a pointer
.simple_type => |t| switch (t) {
- .f16 => return 16,
- .f32 => return 32,
- .f64 => return 64,
- .f80 => return 80,
- .f128 => return 128,
+ .void => 0,
+ .bool => 1,
+ .anyerror, .adhoc_inferred_error_set => zcu.errorSetBits(),
+ .usize, .isize => target.ptrBitWidth(),
- .usize,
- .isize,
- => return target.ptrBitWidth(),
+ .c_char => target.cTypeBitSize(.char),
+ .c_short => target.cTypeBitSize(.short),
+ .c_ushort => target.cTypeBitSize(.ushort),
+ .c_int => target.cTypeBitSize(.int),
+ .c_uint => target.cTypeBitSize(.uint),
+ .c_long => target.cTypeBitSize(.long),
+ .c_ulong => target.cTypeBitSize(.ulong),
+ .c_longlong => target.cTypeBitSize(.longlong),
+ .c_ulonglong => target.cTypeBitSize(.ulonglong),
+ .c_longdouble => target.cTypeBitSize(.longdouble),
- .c_char => return target.cTypeBitSize(.char),
- .c_short => return target.cTypeBitSize(.short),
- .c_ushort => return target.cTypeBitSize(.ushort),
- .c_int => return target.cTypeBitSize(.int),
- .c_uint => return target.cTypeBitSize(.uint),
- .c_long => return target.cTypeBitSize(.long),
- .c_ulong => return target.cTypeBitSize(.ulong),
- .c_longlong => return target.cTypeBitSize(.longlong),
- .c_ulonglong => return target.cTypeBitSize(.ulonglong),
- .c_longdouble => return target.cTypeBitSize(.longdouble),
-
- .bool => return 1,
- .void => return 0,
-
- .anyerror,
- .adhoc_inferred_error_set,
- => return zcu.errorSetBits(),
+ .f16 => 16,
+ .f32 => 32,
+ .f64 => 64,
+ .f80 => 80,
+ .f128 => 128,
.anyopaque => unreachable,
.type => unreachable,
@@ -1717,49 +1284,30 @@ pub fn bitSizeInner(
.enum_literal => unreachable,
.generic_poison => unreachable,
},
+
.struct_type => {
- const struct_type = ip.loadStructType(ty.toIntern());
- const is_packed = struct_type.layout == .@"packed";
- if (strat == .sema) {
- const pt = strat.pt(zcu, tid);
- try ty.resolveFields(pt);
- if (is_packed) try ty.resolveLayout(pt);
+ const struct_obj = ip.loadStructType(ty.toIntern());
+ switch (struct_obj.layout) {
+ .@"packed" => return Type.fromInterned(struct_obj.packed_backing_int_type).bitSize(zcu),
+ .auto, .@"extern" => return struct_obj.size * 8, // will be `unreachable` under #19755
}
- if (is_packed) {
- return try Type.fromInterned(struct_type.backingIntTypeUnordered(ip))
- .bitSizeInner(strat, zcu, tid);
- }
- return (try ty.abiSizeInner(strat_lazy, zcu, tid)).scalar * 8;
- },
-
- .tuple_type => {
- return (try ty.abiSizeInner(strat_lazy, zcu, tid)).scalar * 8;
},
-
.union_type => {
- const union_type = ip.loadUnionType(ty.toIntern());
- const is_packed = ty.containerLayout(zcu) == .@"packed";
- if (strat == .sema) {
- const pt = strat.pt(zcu, tid);
- try ty.resolveFields(pt);
- if (is_packed) try ty.resolveLayout(pt);
+ const union_obj = ip.loadUnionType(ty.toIntern());
+ switch (union_obj.layout) {
+ .@"packed" => return Type.fromInterned(union_obj.packed_backing_int_type).bitSize(zcu),
+ .auto, .@"extern" => return union_obj.size * 8, // will be `unreachable` under #19755
}
- if (!is_packed) {
- return (try ty.abiSizeInner(strat_lazy, zcu, tid)).scalar * 8;
- }
- assert(union_type.flagsUnordered(ip).status.haveFieldTypes());
-
- var size: u64 = 0;
- for (0..union_type.field_types.len) |field_index| {
- const field_ty = union_type.field_types.get(ip)[field_index];
- size = @max(size, try Type.fromInterned(field_ty).bitSizeInner(strat, zcu, tid));
- }
-
- return size;
},
+ .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).bitSize(zcu),
+
+ // will be `unreachable` under #19755
+ .opt_type,
+ .error_union_type,
+ .tuple_type,
+ => ty.abiSize(zcu) * 8,
+
.opaque_type => unreachable,
- .enum_type => return Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty)
- .bitSizeInner(strat, zcu, tid),
// values, not types
.undef,
@@ -1772,33 +1320,16 @@ pub fn bitSizeInner(
.error_union,
.enum_literal,
.enum_tag,
- .empty_enum_value,
.float,
.ptr,
.slice,
.opt,
.aggregate,
.un,
+ .bitpack,
// memoization, not types
.memoized_call,
=> unreachable,
- }
-}
-
-/// Returns true if the type's layout is already resolved and it is safe
-/// to use `abiSize`, `abiAlignment` and `bitSize` on it.
-pub fn layoutIsResolved(ty: Type, zcu: *const Zcu) bool {
- const ip = &zcu.intern_pool;
- return switch (ip.indexToKey(ty.toIntern())) {
- .struct_type => ip.loadStructType(ty.toIntern()).haveLayout(ip),
- .union_type => ip.loadUnionType(ty.toIntern()).haveLayout(ip),
- .array_type => |array_type| {
- if (array_type.lenIncludingSentinel() == 0) return true;
- return Type.fromInterned(array_type.child).layoutIsResolved(zcu);
- },
- .opt_type => |child| Type.fromInterned(child).layoutIsResolved(zcu),
- .error_union_type => |k| Type.fromInterned(k.payload_type).layoutIsResolved(zcu),
- else => true,
};
}
@@ -1841,7 +1372,7 @@ pub fn isSliceAtRuntime(ty: Type, zcu: *const Zcu) bool {
}
pub fn slicePtrFieldType(ty: Type, zcu: *const Zcu) Type {
- return Type.fromInterned(zcu.intern_pool.slicePtrType(ty.toIntern()));
+ return .fromInterned(zcu.intern_pool.slicePtrType(ty.toIntern()));
}
pub fn isConstPtr(ty: Type, zcu: *const Zcu) bool {
@@ -1897,10 +1428,7 @@ pub fn isPtrAtRuntime(ty: Type, zcu: *const Zcu) bool {
/// For pointer-like optionals, returns true, otherwise returns the allowzero property
/// of pointers.
pub fn ptrAllowsZero(ty: Type, zcu: *const Zcu) bool {
- if (ty.isPtrLikeOptional(zcu)) {
- return true;
- }
- return ty.ptrInfo(zcu).flags.is_allowzero;
+ return ty.isPtrLikeOptional(zcu) or ty.ptrInfo(zcu).flags.is_allowzero;
}
/// See also `isPtrLikeOptional`.
@@ -1918,7 +1446,6 @@ pub fn optionalReprIsPayload(ty: Type, zcu: *const Zcu) bool {
/// Returns true if the type is optional and would be lowered to a single pointer
/// address value, using 0 for null. Note that this returns true for C pointers.
-/// This function must be kept in sync with `Sema.typePtrOrOptionalPtrTy`.
pub fn isPtrLikeOptional(ty: Type, zcu: *const Zcu) bool {
return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
.ptr_type => |ptr_type| ptr_type.flags.size == .c,
@@ -1947,52 +1474,54 @@ pub fn childTypeIp(ty: Type, ip: *const InternPool) Type {
return Type.fromInterned(ip.childType(ty.toIntern()));
}
-/// For `*[N]T`, returns `T`.
-/// For `?*T`, returns `T`.
-/// For `?*[N]T`, returns `T`.
-/// For `?[*]T`, returns `T`.
-/// For `*T`, returns `T`.
-/// For `[*]T`, returns `T`.
-/// For `[N]T`, returns `T`.
-/// For `[]T`, returns `T`.
-/// For `anyframe->T`, returns `T`.
-pub fn elemType2(ty: Type, zcu: *const Zcu) Type {
- return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
- .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
- .one => Type.fromInterned(ptr_type.child).shallowElemType(zcu),
- .many, .c, .slice => Type.fromInterned(ptr_type.child),
+/// Similar to `childType`, but for pointer-like (or slice-like) optionals, gets the child type
+/// of the *pointer* type. Asserts that `ty` is either a pointer or a pointer-like optional.
+///
+/// Essentially, unwraps any one of the following into `T`:
+/// ```
+/// *T ?*T *allowzero T
+/// [*]T ?[*]T [*]allowzero T
+/// []T ?[]T []allowzero T
+/// [*c]T
+/// ```
+/// This is primarily useful in Sema to implement operations which can act on optional pointers.
+pub fn nullablePtrElem(ty: Type, zcu: *const Zcu) Type {
+ switch (ty.zigTypeTag(zcu)) {
+ .pointer => return ty.childType(zcu),
+ .optional => {
+ const ptr_ty = ty.childType(zcu);
+ const ptr_info = zcu.intern_pool.indexToKey(ptr_ty.toIntern()).ptr_type;
+ assert(ptr_info.flags.size != .c);
+ assert(!ptr_info.flags.is_allowzero);
+ return .fromInterned(ptr_info.child);
},
- .anyframe_type => |child| {
- assert(child != .none);
- return Type.fromInterned(child);
- },
- .vector_type => |vector_type| Type.fromInterned(vector_type.child),
- .array_type => |array_type| Type.fromInterned(array_type.child),
- .opt_type => |child| Type.fromInterned(zcu.intern_pool.childType(child)),
else => unreachable,
- };
-}
-
-/// Given that `ty` is an indexable pointer, returns its element type. Specifically:
-/// * for `*[n]T`, returns `T`
-/// * for `[]T`, returns `T`
-/// * for `[*]T`, returns `T`
-/// * for `[*c]T`, returns `T`
-pub fn indexablePtrElem(ty: Type, zcu: *const Zcu) Type {
- const ip = &zcu.intern_pool;
- const ptr_type = ip.indexToKey(ty.toIntern()).ptr_type;
- switch (ptr_type.flags.size) {
- .many, .slice, .c => return .fromInterned(ptr_type.child),
- .one => {},
}
- const array_type = ip.indexToKey(ptr_type.child).array_type;
- return .fromInterned(array_type.child);
}
-fn shallowElemType(child_ty: Type, zcu: *const Zcu) Type {
- return switch (child_ty.zigTypeTag(zcu)) {
- .array, .vector => child_ty.childType(zcu),
- else => child_ty,
+/// Asserts that `ty` is an indexable type, and returns its element type. Tuples (and pointers to
+/// tuples) are not supported because they do not have a single element type.
+///
+/// Returns `T` for each of the following types:
+/// * `[n]T`
+/// * `@Vector(n, T)`
+/// * `*[n]T`
+/// * `*@Vector(n, T)`
+/// * `[]T`
+/// * `[*]T`
+/// * `[*c]T`
+pub fn indexableElem(ty: Type, zcu: *const Zcu) Type {
+ const ip = &zcu.intern_pool;
+ return switch (ip.indexToKey(ty.toIntern())) {
+ inline .array_type, .vector_type => |arr| .fromInterned(arr.child),
+ .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
+ .many, .slice, .c => .fromInterned(ptr_type.child),
+ .one => switch (ip.indexToKey(ptr_type.child)) {
+ inline .array_type, .vector_type => |arr| .fromInterned(arr.child),
+ else => unreachable,
+ },
+ },
+ else => unreachable,
};
}
@@ -2004,61 +1533,54 @@ pub fn scalarType(ty: Type, zcu: *const Zcu) Type {
};
}
-/// Asserts that the type is an optional.
-/// Note that for C pointers this returns the type unmodified.
+/// Asserts that the type is an optional, or a C pointer.
+/// For C pointers this returns the type unmodified.
pub fn optionalChild(ty: Type, zcu: *const Zcu) Type {
- return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
- .opt_type => |child| Type.fromInterned(child),
- .ptr_type => |ptr_type| b: {
+ switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
+ .opt_type => |child| return .fromInterned(child),
+ .ptr_type => |ptr_type| {
assert(ptr_type.flags.size == .c);
- break :b ty;
+ return ty;
},
else => unreachable,
- };
+ }
}
-/// Returns the tag type of a union, if the type is a union and it has a tag type.
-/// Otherwise, returns `null`.
+/// If `ty` is a tagged union, returns its tag type. Otherwise, returns `null`.
pub fn unionTagType(ty: Type, zcu: *const Zcu) ?Type {
+ assertHasLayout(ty, zcu);
const ip = &zcu.intern_pool;
switch (ip.indexToKey(ty.toIntern())) {
.union_type => {},
else => return null,
}
- const union_type = ip.loadUnionType(ty.toIntern());
- const union_flags = union_type.flagsUnordered(ip);
- switch (union_flags.runtime_tag) {
- .tagged => {
- assert(union_flags.status.haveFieldTypes());
- return Type.fromInterned(union_type.enum_tag_ty);
- },
- else => return null,
- }
-}
-
-/// Same as `unionTagType` but includes safety tag.
-/// Codegen should use this version.
-pub fn unionTagTypeSafety(ty: Type, zcu: *const Zcu) ?Type {
- const ip = &zcu.intern_pool;
- return switch (ip.indexToKey(ty.toIntern())) {
- .union_type => {
- const union_type = ip.loadUnionType(ty.toIntern());
- if (!union_type.hasTag(ip)) return null;
- assert(union_type.haveFieldTypes(ip));
- return Type.fromInterned(union_type.enum_tag_ty);
- },
- else => null,
+ const union_obj = ip.loadUnionType(ty.toIntern());
+ return switch (union_obj.tag_usage) {
+ .tagged => .fromInterned(union_obj.enum_tag_type),
+ .none, .safety => null,
};
}
-/// Asserts the type is a union; returns the tag type, even if the tag will
-/// not be stored at runtime.
+/// If the given union type contains a tag (including a safety tag) in its runtime layout, returns
+/// its enum tag type. Otherwise, returns null. Asserts that `ty` is a union type.
+///
+/// In general, codegen logic should call this function instead of `unionTagType`.
+pub fn unionTagTypeRuntime(ty: Type, zcu: *const Zcu) ?Type {
+ assertHasLayout(ty, zcu);
+ const union_type = zcu.intern_pool.loadUnionType(ty.toIntern());
+ if (!union_type.has_runtime_tag) return null;
+ return .fromInterned(union_type.enum_tag_type);
+}
+
+/// Asserts that `ty` is a union type, and returns its tag type, even if the tag will not be stored at runtime.
pub fn unionTagTypeHypothetical(ty: Type, zcu: *const Zcu) Type {
- const union_obj = zcu.typeToUnion(ty).?;
- return Type.fromInterned(union_obj.enum_tag_ty);
+ assertHasLayout(ty, zcu);
+ const union_obj = zcu.intern_pool.loadUnionType(ty.toIntern());
+ return .fromInterned(union_obj.enum_tag_type);
}
pub fn unionFieldType(ty: Type, enum_tag: Value, zcu: *const Zcu) ?Type {
+ assertHasLayout(ty, zcu);
const ip = &zcu.intern_pool;
const union_obj = zcu.typeToUnion(ty).?;
const union_fields = union_obj.field_types.get(ip);
@@ -2067,17 +1589,20 @@ pub fn unionFieldType(ty: Type, enum_tag: Value, zcu: *const Zcu) ?Type {
}
pub fn unionFieldTypeByIndex(ty: Type, index: usize, zcu: *const Zcu) Type {
+ assertHasLayout(ty, zcu);
const ip = &zcu.intern_pool;
const union_obj = zcu.typeToUnion(ty).?;
return Type.fromInterned(union_obj.field_types.get(ip)[index]);
}
pub fn unionTagFieldIndex(ty: Type, enum_tag: Value, zcu: *const Zcu) ?u32 {
+ assertHasLayout(ty, zcu);
const union_obj = zcu.typeToUnion(ty).?;
return zcu.unionTagFieldIndex(union_obj, enum_tag);
}
pub fn unionHasAllZeroBitFieldTypes(ty: Type, zcu: *Zcu) bool {
+ assertHasLayout(ty, zcu);
const ip = &zcu.intern_pool;
const union_obj = zcu.typeToUnion(ty).?;
for (union_obj.field_types.get(ip)) |field_ty| {
@@ -2087,17 +1612,21 @@ pub fn unionHasAllZeroBitFieldTypes(ty: Type, zcu: *Zcu) bool {
}
/// Returns the type used for backing storage of this union during comptime operations.
-/// Asserts the type is either an extern or packed union.
-pub fn unionBackingType(ty: Type, pt: Zcu.PerThread) !Type {
+/// Asserts the type is an extern union.
+pub fn externUnionBackingType(ty: Type, pt: Zcu.PerThread) !Type {
const zcu = pt.zcu;
- return switch (ty.containerLayout(zcu)) {
- .@"extern" => try pt.arrayType(.{ .len = ty.abiSize(zcu), .child = .u8_type }),
- .@"packed" => try pt.intType(.unsigned, @intCast(ty.bitSize(zcu))),
+ assertHasLayout(ty, zcu);
+ const loaded_union = zcu.intern_pool.loadUnionType(ty.toIntern());
+ switch (loaded_union.layout) {
+ .@"extern" => return pt.arrayType(.{ .len = ty.abiSize(zcu), .child = .u8_type }),
+ .@"packed" => unreachable,
.auto => unreachable,
- };
+ }
}
+/// Asserts that `ty` is a non-packed union type.
pub fn unionGetLayout(ty: Type, zcu: *const Zcu) Zcu.UnionLayout {
+ assertHasLayout(ty, zcu);
const union_obj = zcu.intern_pool.loadUnionType(ty.toIntern());
return Type.getUnionLayout(union_obj, zcu);
}
@@ -2105,9 +1634,18 @@ pub fn unionGetLayout(ty: Type, zcu: *const Zcu) Zcu.UnionLayout {
pub fn containerLayout(ty: Type, zcu: *const Zcu) std.builtin.Type.ContainerLayout {
const ip = &zcu.intern_pool;
return switch (ip.indexToKey(ty.toIntern())) {
- .struct_type => ip.loadStructType(ty.toIntern()).layout,
.tuple_type => .auto,
- .union_type => ip.loadUnionType(ty.toIntern()).flagsUnordered(ip).layout,
+ .struct_type => ip.loadStructType(ty.toIntern()).layout,
+ .union_type => ip.loadUnionType(ty.toIntern()).layout,
+ else => unreachable,
+ };
+}
+
+pub fn bitpackBackingInt(ty: Type, zcu: *const Zcu) Type {
+ const ip = &zcu.intern_pool;
+ return switch (ip.indexToKey(ty.toIntern())) {
+ .struct_type => .fromInterned(ip.loadStructType(ty.toIntern()).packed_backing_int_type),
+ .union_type => .fromInterned(ip.loadUnionType(ty.toIntern()).packed_backing_int_type),
else => unreachable,
};
}
@@ -2123,6 +1661,11 @@ pub fn errorUnionSet(ty: Type, zcu: *const Zcu) Type {
}
/// Returns false for unresolved inferred error sets.
+///
+/// TODO: this function will behave incorrectly under incremental compilation, because in that case
+/// it may see an outdated resolved error set. This function must be either deleted, or its contract
+/// changed to require the caller to resolve the error set beforehand. If you must introduce new
+/// call sites, please make sure the error set in question is definitely resolved first!
pub fn errorSetIsEmpty(ty: Type, zcu: *const Zcu) bool {
const ip = &zcu.intern_pool;
return switch (ty.toIntern()) {
@@ -2141,6 +1684,11 @@ pub fn errorSetIsEmpty(ty: Type, zcu: *const Zcu) bool {
/// Returns true if it is an error set that includes anyerror, false otherwise.
/// Note that the result may be a false negative if the type did not get error set
/// resolution prior to this call.
+///
+/// TODO: this function will behave incorrectly under incremental compilation, because in that case
+/// it may see an outdated resolved error set. This function must be either deleted, or its contract
+/// changed to require the caller to resolve the error set beforehand. If you must introduce new
+/// call sites, please make sure the error set in question is definitely resolved first!
pub fn isAnyError(ty: Type, zcu: *const Zcu) bool {
const ip = &zcu.intern_pool;
return switch (ty.toIntern()) {
@@ -2163,14 +1711,20 @@ pub fn isError(ty: Type, zcu: *const Zcu) bool {
/// Returns whether ty, which must be an error set, includes an error `name`.
/// Might return a false negative if `ty` is an inferred error set and not fully
/// resolved yet.
-pub fn errorSetHasFieldIp(
- ip: *const InternPool,
- ty: InternPool.Index,
+///
+/// TODO: this function will behave incorrectly under incremental compilation, because in that case
+/// it may see an outdated resolved error set. This function must be either deleted, or its contract
+/// changed to require the caller to resolve the error set beforehand. If you must introduce new
+/// call sites, please make sure the error set in question is definitely resolved first!
+pub fn errorSetHasField(
+ ty: Type,
name: InternPool.NullTerminatedString,
+ zcu: *const Zcu,
) bool {
- return switch (ty) {
+ const ip = &zcu.intern_pool;
+ return switch (ty.toIntern()) {
.anyerror_type => true,
- else => switch (ip.indexToKey(ty)) {
+ else => switch (ip.indexToKey(ty.toIntern())) {
.error_set_type => |error_set_type| error_set_type.nameIndex(ip, name) != null,
.inferred_error_set_type => |i| switch (ip.funcIesResolvedUnordered(i)) {
.anyerror_type => true,
@@ -2182,33 +1736,6 @@ pub fn errorSetHasFieldIp(
};
}
-/// Returns whether ty, which must be an error set, includes an error `name`.
-/// Might return a false negative if `ty` is an inferred error set and not fully
-/// resolved yet.
-pub fn errorSetHasField(ty: Type, name: []const u8, zcu: *const Zcu) bool {
- const ip = &zcu.intern_pool;
- return switch (ty.toIntern()) {
- .anyerror_type => true,
- else => switch (ip.indexToKey(ty.toIntern())) {
- .error_set_type => |error_set_type| {
- // If the string is not interned, then the field certainly is not present.
- const field_name_interned = ip.getString(name).unwrap() orelse return false;
- return error_set_type.nameIndex(ip, field_name_interned) != null;
- },
- .inferred_error_set_type => |i| switch (ip.funcIesResolvedUnordered(i)) {
- .anyerror_type => true,
- .none => false,
- else => |t| {
- // If the string is not interned, then the field certainly is not present.
- const field_name_interned = ip.getString(name).unwrap() orelse return false;
- return ip.indexToKey(t).error_set_type.nameIndex(ip, field_name_interned) != null;
- },
- },
- else => unreachable,
- },
- };
-}
-
/// Asserts the type is an array or vector or struct.
pub fn arrayLen(ty: Type, zcu: *const Zcu) u64 {
return ty.arrayLenIp(&zcu.intern_pool);
@@ -2275,12 +1802,12 @@ pub fn isUnsignedInt(ty: Type, zcu: *const Zcu) bool {
};
}
-/// Returns true for integers, enums, error sets, and packed structs.
+/// Returns true for integers, enums, error sets, and packed structs/unions.
/// If this function returns true, then intInfo() can be called on the type.
pub fn isAbiInt(ty: Type, zcu: *const Zcu) bool {
return switch (ty.zigTypeTag(zcu)) {
.int, .@"enum", .error_set => true,
- .@"struct" => ty.containerLayout(zcu) == .@"packed",
+ .@"struct", .@"union" => ty.containerLayout(zcu) == .@"packed",
else => false,
};
}
@@ -2308,8 +1835,17 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType {
.c_ulonglong_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.ulonglong) },
else => switch (ip.indexToKey(ty.toIntern())) {
.int_type => |int_type| return int_type,
- .struct_type => ty = Type.fromInterned(ip.loadStructType(ty.toIntern()).backingIntTypeUnordered(ip)),
- .enum_type => ty = Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty),
+ .struct_type => {
+ const struct_obj = ip.loadStructType(ty.toIntern());
+ assert(struct_obj.layout == .@"packed");
+ ty = .fromInterned(struct_obj.packed_backing_int_type);
+ },
+ .union_type => {
+ const union_obj = ip.loadUnionType(ty.toIntern());
+ assert(union_obj.layout == .@"packed");
+ ty = .fromInterned(union_obj.packed_backing_int_type);
+ },
+ .enum_type => ty = .fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type),
.vector_type => |vector_type| ty = Type.fromInterned(vector_type.child),
.error_set_type, .inferred_error_set_type => {
@@ -2327,7 +1863,6 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType {
.func_type => unreachable,
.simple_type => unreachable, // handled via Index enum tag above
- .union_type => unreachable,
.opaque_type => unreachable,
// values, not types
@@ -2341,13 +1876,13 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType {
.error_union,
.enum_literal,
.enum_tag,
- .empty_enum_value,
.float,
.ptr,
.slice,
.opt,
.aggregate,
.un,
+ .bitpack,
// memoization, not types
.memoized_call,
=> unreachable,
@@ -2355,25 +1890,6 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType {
};
}
-pub fn isNamedInt(ty: Type) bool {
- return switch (ty.toIntern()) {
- .usize_type,
- .isize_type,
- .c_char_type,
- .c_short_type,
- .c_ushort_type,
- .c_int_type,
- .c_uint_type,
- .c_long_type,
- .c_ulong_type,
- .c_longlong_type,
- .c_ulonglong_type,
- => true,
-
- else => false,
- };
-}
-
/// Returns `false` for `comptime_float`.
pub fn isRuntimeFloat(ty: Type) bool {
return switch (ty.toIntern()) {
@@ -2488,429 +2004,181 @@ pub fn isNumeric(ty: Type, zcu: *const Zcu) bool {
};
}
-/// During semantic analysis, instead call `Sema.typeHasOnePossibleValue` which
-/// resolves field types rather than asserting they are already resolved.
-pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value {
+/// If the type's classification is `Class.one_possible_value` (see `classify`), returns the only
+/// possible value for the type. Otherwise, returns `null`.
+pub fn onePossibleValue(ty: Type, pt: Zcu.PerThread) !?Value {
const zcu = pt.zcu;
const comp = zcu.comp;
const gpa = comp.gpa;
- const io = comp.io;
const ip = &zcu.intern_pool;
- var ty = starting_type;
- while (true) switch (ty.toIntern()) {
- .empty_tuple_type => return Value.empty_tuple,
-
- else => switch (ip.indexToKey(ty.toIntern())) {
- .int_type => |int_type| {
- if (int_type.bits == 0) {
- return try pt.intValue(ty, 0);
- } else {
- return null;
- }
- },
-
- .ptr_type,
- .error_union_type,
- .func_type,
- .anyframe_type,
- .error_set_type,
- .inferred_error_set_type,
- => return null,
-
- inline .array_type, .vector_type => |seq_type, seq_tag| {
- const has_sentinel = seq_tag == .array_type and seq_type.sentinel != .none;
- if (seq_type.len + @intFromBool(has_sentinel) == 0) {
- return try pt.aggregateValue(ty, &.{});
- }
- if (try Type.fromInterned(seq_type.child).onePossibleValue(pt)) |opv| {
- return try pt.aggregateSplatValue(ty, opv);
- }
- return null;
- },
- .opt_type => |child| {
- if (child == .noreturn_type) {
- return try pt.nullValue(ty);
- } else {
- return null;
- }
- },
-
- .simple_type => |t| switch (t) {
- .f16,
- .f32,
- .f64,
- .f80,
- .f128,
- .usize,
- .isize,
- .c_char,
- .c_short,
- .c_ushort,
- .c_int,
- .c_uint,
- .c_long,
- .c_ulong,
- .c_longlong,
- .c_ulonglong,
- .c_longdouble,
- .anyopaque,
- .bool,
- .type,
- .anyerror,
- .comptime_int,
- .comptime_float,
- .enum_literal,
- .adhoc_inferred_error_set,
- => return null,
-
- .void => return Value.void,
- .noreturn => return Value.@"unreachable",
- .null => return Value.null,
- .undefined => return Value.undef,
-
- .generic_poison => unreachable,
- },
- .struct_type => {
- const struct_type = ip.loadStructType(ty.toIntern());
- assert(struct_type.haveFieldTypes(ip));
- if (struct_type.knownNonOpv(ip))
- return null;
- const field_vals = try zcu.gpa.alloc(InternPool.Index, struct_type.field_types.len);
- defer zcu.gpa.free(field_vals);
- for (field_vals, 0..) |*field_val, i_usize| {
- const i: u32 = @intCast(i_usize);
- if (struct_type.fieldIsComptime(ip, i)) {
- assert(struct_type.haveFieldInits(ip));
- field_val.* = struct_type.field_inits.get(ip)[i];
- continue;
- }
- const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);
- if (try field_ty.onePossibleValue(pt)) |field_opv| {
- field_val.* = field_opv.toIntern();
- } else return null;
- }
-
- // In this case the struct has no runtime-known fields and
- // therefore has one possible value.
- return try pt.aggregateValue(ty, field_vals);
- },
-
- .tuple_type => |tuple| {
- if (tuple.types.len == 0) {
- return try pt.aggregateValue(ty, &.{});
- }
-
- const field_vals = try zcu.gpa.alloc(
- InternPool.Index,
- tuple.types.len,
- );
- defer zcu.gpa.free(field_vals);
- for (
- field_vals,
- tuple.types.get(ip),
- tuple.values.get(ip),
- ) |*field_val, field_ty, field_comptime_val| {
- if (field_comptime_val != .none) {
- field_val.* = field_comptime_val;
- continue;
- }
- if (try Type.fromInterned(field_ty).onePossibleValue(pt)) |opv| {
- field_val.* = opv.toIntern();
- } else return null;
- }
-
- return try pt.aggregateValue(ty, field_vals);
- },
-
- .union_type => {
- const union_obj = ip.loadUnionType(ty.toIntern());
- const tag_val = (try Type.fromInterned(union_obj.enum_tag_ty).onePossibleValue(pt)) orelse
- return null;
- if (union_obj.field_types.len == 0) {
- const only = try pt.intern(.{ .empty_enum_value = ty.toIntern() });
- return Value.fromInterned(only);
- }
- const only_field_ty = union_obj.field_types.get(ip)[0];
- const val_val = (try Type.fromInterned(only_field_ty).onePossibleValue(pt)) orelse
- return null;
- const only = try pt.internUnion(.{
- .ty = ty.toIntern(),
- .tag = tag_val.toIntern(),
- .val = val_val.toIntern(),
- });
- return Value.fromInterned(only);
- },
- .opaque_type => return null,
- .enum_type => {
- const enum_type = ip.loadEnumType(ty.toIntern());
- switch (enum_type.tag_mode) {
- .nonexhaustive => {
- if (enum_type.tag_ty == .comptime_int_type) return null;
-
- if (try Type.fromInterned(enum_type.tag_ty).onePossibleValue(pt)) |int_opv| {
- const only = try pt.intern(.{ .enum_tag = .{
- .ty = ty.toIntern(),
- .int = int_opv.toIntern(),
- } });
- return Value.fromInterned(only);
- }
-
- return null;
- },
- .auto, .explicit => {
- if (Type.fromInterned(enum_type.tag_ty).hasRuntimeBits(zcu)) return null;
-
- return Value.fromInterned(switch (enum_type.names.len) {
- 0 => try pt.intern(.{ .empty_enum_value = ty.toIntern() }),
- 1 => try pt.intern(.{ .enum_tag = .{
- .ty = ty.toIntern(),
- .int = if (enum_type.values.len == 0)
- (try pt.intValue(.fromInterned(enum_type.tag_ty), 0)).toIntern()
- else
- try ip.getCoercedInts(
- gpa,
- io,
- pt.tid,
- ip.indexToKey(enum_type.values.get(ip)[0]).int,
- enum_type.tag_ty,
- ),
- } }),
- else => return null,
- });
- },
- }
- },
-
- // values, not types
- .undef,
- .simple_value,
- .variable,
- .@"extern",
- .func,
- .int,
- .err,
- .error_union,
+ assertHasLayout(ty, zcu);
+ return switch (ip.indexToKey(ty.toIntern())) {
+ .ptr_type,
+ .error_union_type,
+ .func_type,
+ .anyframe_type,
+ .error_set_type,
+ .inferred_error_set_type,
+ .opaque_type,
+ => null,
+
+ .simple_type => |t| switch (t) {
+ .f16,
+ .f32,
+ .f64,
+ .f80,
+ .f128,
+ .usize,
+ .isize,
+ .c_char,
+ .c_short,
+ .c_ushort,
+ .c_int,
+ .c_uint,
+ .c_long,
+ .c_ulong,
+ .c_longlong,
+ .c_ulonglong,
+ .c_longdouble,
+ .anyopaque,
+ .bool,
+ .type,
+ .anyerror,
+ .comptime_int,
+ .comptime_float,
.enum_literal,
- .enum_tag,
- .empty_enum_value,
- .float,
- .ptr,
- .slice,
- .opt,
- .aggregate,
- .un,
- // memoization, not types
- .memoized_call,
- => unreachable,
+ .adhoc_inferred_error_set,
+ .null,
+ .undefined,
+ .noreturn,
+ => null,
+
+ .void => .void,
+
+ .generic_poison => unreachable,
},
+
+ .int_type => |int_type| switch (int_type.bits) {
+ 0 => try pt.intValue(ty, 0),
+ else => null,
+ },
+
+ inline .array_type, .vector_type => |seq_type, seq_tag| {
+ const has_sentinel = seq_tag == .array_type and seq_type.sentinel != .none;
+ if (seq_type.len + @intFromBool(has_sentinel) == 0) {
+ return try pt.aggregateValue(ty, &.{});
+ }
+ if (try Type.fromInterned(seq_type.child).onePossibleValue(pt)) |opv| {
+ return try pt.aggregateSplatValue(ty, opv);
+ }
+ return null;
+ },
+ .opt_type => |child| switch (Type.fromInterned(child).classify(zcu)) {
+ .no_possible_value => try pt.nullValue(ty),
+ else => null,
+ },
+ .tuple_type => |tuple| {
+ // Check *whether* the OPV exists first, because constructing it is a little more expensive.
+ if (ty.classify(zcu) != .one_possible_value) return null;
+ const field_vals = try zcu.gpa.dupe(InternPool.Index, tuple.values.get(ip));
+ defer zcu.gpa.free(field_vals);
+ for (field_vals, tuple.types.get(ip)) |*field_val, field_ty_ip| {
+ if (field_val.* != .none) continue; // comptime field value
+ const field_ty: Type = .fromInterned(field_ty_ip);
+ field_val.* = (try field_ty.onePossibleValue(pt)).?.toIntern();
+ }
+ return try pt.aggregateValue(ty, field_vals);
+ },
+ .struct_type => {
+ const struct_obj = ip.loadStructType(ty.toIntern());
+ switch (struct_obj.layout) {
+ .auto, .@"extern" => {},
+ .@"packed" => {
+ const backing_ty: Type = .fromInterned(struct_obj.packed_backing_int_type);
+ const backing_val = try backing_ty.onePossibleValue(pt) orelse return null;
+ return try pt.bitpackValue(ty, backing_val);
+ },
+ }
+ // Type resolution already figured out whether there is an OPV, but if there is, it's
+ // our job to compute it.
+ if (struct_obj.class != .one_possible_value) return null;
+ const field_vals = try gpa.alloc(InternPool.Index, struct_obj.field_types.len);
+ defer gpa.free(field_vals);
+ for (field_vals, 0..) |*field_val, i_usize| {
+ const i: u32 = @intCast(i_usize);
+ if (struct_obj.field_is_comptime_bits.get(ip, i)) {
+ field_val.* = struct_obj.field_defaults.get(ip)[i];
+ assert(field_val.* != .none);
+ continue;
+ }
+ const field_ty: Type = .fromInterned(struct_obj.field_types.get(ip)[i]);
+ field_val.* = (try field_ty.onePossibleValue(pt)).?.toIntern();
+ }
+ return try pt.aggregateValue(ty, field_vals);
+ },
+ .union_type => {
+ const union_obj = ip.loadUnionType(ty.toIntern());
+ if (union_obj.layout == .@"packed") {
+ const backing_ty: Type = .fromInterned(union_obj.packed_backing_int_type);
+ const backing_val = try backing_ty.onePossibleValue(pt) orelse return null;
+ return try pt.bitpackValue(ty, backing_val);
+ }
+ // Type resolution already figured out whether there is an OPV, but if there is, it's
+ // our job to compute it.
+ if (union_obj.class != .one_possible_value) return null;
+ // The OPV comes from exactly one field whose type is OPV, while all others are NPV.
+ for (union_obj.field_types.get(ip), 0..) |field_ty_ip, field_index| {
+ const field_ty: Type = .fromInterned(field_ty_ip);
+ switch (field_ty.classify(zcu)) {
+ .no_possible_value => continue,
+ .one_possible_value => {},
+ else => unreachable,
+ }
+ // This field is the one!
+ const enum_tag_ty: Type = .fromInterned(union_obj.enum_tag_type);
+ const tag_val = try pt.enumValueFieldIndex(enum_tag_ty, @intCast(field_index));
+ const payload_val = (try field_ty.onePossibleValue(pt)).?;
+ return try pt.unionValue(ty, tag_val, payload_val);
+ } else unreachable;
+ },
+ .enum_type => if (try ty.intTagType(zcu).onePossibleValue(pt)) |int_tag_opv| {
+ return .fromInterned(try pt.intern(.{ .enum_tag = .{
+ .ty = ty.toIntern(),
+ .int = int_tag_opv.toIntern(),
+ } }));
+ } else null,
+
+ // values, not types
+ .undef,
+ .simple_value,
+ .variable,
+ .@"extern",
+ .func,
+ .int,
+ .err,
+ .error_union,
+ .enum_literal,
+ .enum_tag,
+ .float,
+ .ptr,
+ .slice,
+ .opt,
+ .aggregate,
+ .un,
+ .bitpack,
+ // memoization, not types
+ .memoized_call,
+ => unreachable,
};
}
-/// During semantic analysis, instead call `ty.comptimeOnlySema` which
-/// resolves field types rather than asserting they are already resolved.
+/// Asserts that `ty` has its layout resolved. `generic_poison` will return `false`.
pub fn comptimeOnly(ty: Type, zcu: *const Zcu) bool {
- return ty.comptimeOnlyInner(.normal, zcu, {}) catch unreachable;
-}
-
-pub fn comptimeOnlySema(ty: Type, pt: Zcu.PerThread) SemaError!bool {
- return try ty.comptimeOnlyInner(.sema, pt.zcu, pt.tid);
-}
-
-/// `generic_poison` will return false.
-/// May return false negatives when structs and unions are having their field types resolved.
-pub fn comptimeOnlyInner(
- ty: Type,
- comptime strat: ResolveStrat,
- zcu: strat.ZcuPtr(),
- tid: strat.Tid(),
-) SemaError!bool {
- const ip = &zcu.intern_pool;
- const io = zcu.comp.io;
- return switch (ty.toIntern()) {
- .empty_tuple_type => false,
-
- else => switch (ip.indexToKey(ty.toIntern())) {
- .int_type => false,
- .ptr_type => |ptr_type| {
- const child_ty = Type.fromInterned(ptr_type.child);
- switch (child_ty.zigTypeTag(zcu)) {
- .@"fn" => return !try child_ty.fnHasRuntimeBitsInner(strat, zcu, tid),
- .@"opaque" => return false,
- else => return child_ty.comptimeOnlyInner(strat, zcu, tid),
- }
- },
- .anyframe_type => |child| {
- if (child == .none) return false;
- return Type.fromInterned(child).comptimeOnlyInner(strat, zcu, tid);
- },
- .array_type => |array_type| return Type.fromInterned(array_type.child).comptimeOnlyInner(strat, zcu, tid),
- .vector_type => |vector_type| return Type.fromInterned(vector_type.child).comptimeOnlyInner(strat, zcu, tid),
- .opt_type => |child| return Type.fromInterned(child).comptimeOnlyInner(strat, zcu, tid),
- .error_union_type => |error_union_type| return Type.fromInterned(error_union_type.payload_type).comptimeOnlyInner(strat, zcu, tid),
-
- .error_set_type,
- .inferred_error_set_type,
- => false,
-
- // These are function bodies, not function pointers.
- .func_type => true,
-
- .simple_type => |t| switch (t) {
- .f16,
- .f32,
- .f64,
- .f80,
- .f128,
- .usize,
- .isize,
- .c_char,
- .c_short,
- .c_ushort,
- .c_int,
- .c_uint,
- .c_long,
- .c_ulong,
- .c_longlong,
- .c_ulonglong,
- .c_longdouble,
- .anyopaque,
- .bool,
- .void,
- .anyerror,
- .adhoc_inferred_error_set,
- .noreturn,
- .generic_poison,
- => false,
-
- .type,
- .comptime_int,
- .comptime_float,
- .null,
- .undefined,
- .enum_literal,
- => true,
- },
- .struct_type => {
- const struct_type = ip.loadStructType(ty.toIntern());
- // packed structs cannot be comptime-only because they have a well-defined
- // memory layout and every field has a well-defined bit pattern.
- if (struct_type.layout == .@"packed")
- return false;
-
- return switch (strat) {
- .normal => switch (struct_type.requiresComptime(ip)) {
- .wip => unreachable,
- .no => false,
- .yes => true,
- .unknown => unreachable,
- },
- .sema => switch (struct_type.setRequiresComptimeWip(ip, io)) {
- .no, .wip => false,
- .yes => true,
- .unknown => {
- if (struct_type.flagsUnordered(ip).field_types_wip) {
- struct_type.setRequiresComptime(ip, io, .unknown);
- return false;
- }
-
- errdefer struct_type.setRequiresComptime(ip, io, .unknown);
-
- const pt = strat.pt(zcu, tid);
- try ty.resolveFields(pt);
-
- for (0..struct_type.field_types.len) |i_usize| {
- const i: u32 = @intCast(i_usize);
- if (struct_type.fieldIsComptime(ip, i)) continue;
- const field_ty = struct_type.field_types.get(ip)[i];
- if (try Type.fromInterned(field_ty).comptimeOnlyInner(strat, zcu, tid)) {
- // Note that this does not cause the layout to
- // be considered resolved. Comptime-only types
- // still maintain a layout of their
- // runtime-known fields.
- struct_type.setRequiresComptime(ip, io, .yes);
- return true;
- }
- }
-
- struct_type.setRequiresComptime(ip, io, .no);
- return false;
- },
- },
- };
- },
-
- .tuple_type => |tuple| {
- for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
- const have_comptime_val = val != .none;
- if (!have_comptime_val and try Type.fromInterned(field_ty).comptimeOnlyInner(strat, zcu, tid)) return true;
- }
- return false;
- },
-
- .union_type => {
- const union_type = ip.loadUnionType(ty.toIntern());
- return switch (strat) {
- .normal => switch (union_type.requiresComptime(ip)) {
- .wip => unreachable,
- .no => false,
- .yes => true,
- .unknown => unreachable,
- },
- .sema => switch (union_type.setRequiresComptimeWip(ip, io)) {
- .no, .wip => return false,
- .yes => return true,
- .unknown => {
- if (union_type.flagsUnordered(ip).status == .field_types_wip) {
- union_type.setRequiresComptime(ip, io, .unknown);
- return false;
- }
-
- errdefer union_type.setRequiresComptime(ip, io, .unknown);
-
- const pt = strat.pt(zcu, tid);
- try ty.resolveFields(pt);
-
- for (0..union_type.field_types.len) |field_idx| {
- const field_ty = union_type.field_types.get(ip)[field_idx];
- if (try Type.fromInterned(field_ty).comptimeOnlyInner(strat, zcu, tid)) {
- union_type.setRequiresComptime(ip, io, .yes);
- return true;
- }
- }
-
- union_type.setRequiresComptime(ip, io, .no);
- return false;
- },
- },
- };
- },
-
- .opaque_type => false,
-
- .enum_type => return Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).comptimeOnlyInner(strat, zcu, tid),
-
- // values, not types
- .undef,
- .simple_value,
- .variable,
- .@"extern",
- .func,
- .int,
- .err,
- .error_union,
- .enum_literal,
- .enum_tag,
- .empty_enum_value,
- .float,
- .ptr,
- .slice,
- .opt,
- .aggregate,
- .un,
- // memoization, not types
- .memoized_call,
- => unreachable,
- },
+ if (ty.toIntern() == .generic_poison_type) return false;
+ if (ty.zigTypeTag(zcu) == .error_union and ty.errorUnionPayload(zcu).toIntern() == .generic_poison_type) return false;
+ return switch (ty.classify(zcu)) {
+ .no_possible_value, .one_possible_value, .runtime => false,
+ .partially_comptime, .fully_comptime => true,
};
}
@@ -3056,20 +2324,18 @@ pub fn maxIntScalar(ty: Type, pt: Zcu.PerThread, dest_ty: Type) !Value {
/// Asserts the type is an enum or a union.
pub fn intTagType(ty: Type, zcu: *const Zcu) Type {
const ip = &zcu.intern_pool;
- return switch (ip.indexToKey(ty.toIntern())) {
- .union_type => Type.fromInterned(ip.loadUnionType(ty.toIntern()).enum_tag_ty).intTagType(zcu),
- .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty),
+ const enum_ty: Type = switch (ip.indexToKey(ty.toIntern())) {
+ .union_type => .fromInterned(ip.loadUnionType(ty.toIntern()).enum_tag_type),
+ .enum_type => ty,
else => unreachable,
};
+ return .fromInterned(ip.loadEnumType(enum_ty.toIntern()).int_tag_type);
}
pub fn isNonexhaustiveEnum(ty: Type, zcu: *const Zcu) bool {
const ip = &zcu.intern_pool;
return switch (ip.indexToKey(ty.toIntern())) {
- .enum_type => switch (ip.loadEnumType(ty.toIntern()).tag_mode) {
- .nonexhaustive => true,
- .auto, .explicit => false,
- },
+ .enum_type => ip.loadEnumType(ty.toIntern()).nonexhaustive,
else => false,
};
}
@@ -3090,28 +2356,33 @@ pub fn errorSetNames(ty: Type, zcu: *const Zcu) InternPool.NullTerminatedString.
}
pub fn enumFields(ty: Type, zcu: *const Zcu) InternPool.NullTerminatedString.Slice {
- return zcu.intern_pool.loadEnumType(ty.toIntern()).names;
+ assertHasLayout(ty, zcu);
+ return zcu.intern_pool.loadEnumType(ty.toIntern()).field_names;
}
pub fn enumFieldCount(ty: Type, zcu: *const Zcu) usize {
- return zcu.intern_pool.loadEnumType(ty.toIntern()).names.len;
+ assertHasLayout(ty, zcu);
+ return zcu.intern_pool.loadEnumType(ty.toIntern()).field_names.len;
}
pub fn enumFieldName(ty: Type, field_index: usize, zcu: *const Zcu) InternPool.NullTerminatedString {
+ assertHasLayout(ty, zcu);
const ip = &zcu.intern_pool;
- return ip.loadEnumType(ty.toIntern()).names.get(ip)[field_index];
+ return ip.loadEnumType(ty.toIntern()).field_names.get(ip)[field_index];
}
pub fn enumFieldIndex(ty: Type, field_name: InternPool.NullTerminatedString, zcu: *const Zcu) ?u32 {
+ assertHasLayout(ty, zcu);
const ip = &zcu.intern_pool;
const enum_type = ip.loadEnumType(ty.toIntern());
return enum_type.nameIndex(ip, field_name);
}
-/// Asserts `ty` is an enum. `enum_tag` can either be `enum_field_index` or
-/// an integer which represents the enum value. Returns the field index in
+/// Asserts `ty` is an enum. `enum_tag` can either be the actual enum tag value
+/// or an integer which represents the enum value. Returns the field index in
/// declaration order, or `null` if `enum_tag` does not match any field.
pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, zcu: *const Zcu) ?u32 {
+ assertHasLayout(ty, zcu);
const ip = &zcu.intern_pool;
const enum_type = ip.loadEnumType(ty.toIntern());
const int_tag = switch (ip.indexToKey(enum_tag.toIntern())) {
@@ -3119,200 +2390,116 @@ pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, zcu: *const Zcu) ?u32 {
.enum_tag => |info| info.int,
else => unreachable,
};
- assert(ip.typeOf(int_tag) == enum_type.tag_ty);
+ assert(ip.typeOf(int_tag) == enum_type.int_tag_type);
return enum_type.tagValueIndex(ip, int_tag);
}
/// Returns none in the case of a tuple which uses the integer index as the field name.
pub fn structFieldName(ty: Type, index: usize, zcu: *const Zcu) InternPool.OptionalNullTerminatedString {
const ip = &zcu.intern_pool;
- return switch (ip.indexToKey(ty.toIntern())) {
- .struct_type => ip.loadStructType(ty.toIntern()).fieldName(ip, index).toOptional(),
- .tuple_type => .none,
+ switch (ip.indexToKey(ty.toIntern())) {
+ .struct_type => {
+ assertHasLayout(ty, zcu);
+ return ip.loadStructType(ty.toIntern()).field_names.get(ip)[index].toOptional();
+ },
+ .tuple_type => return .none,
else => unreachable,
- };
+ }
}
pub fn structFieldCount(ty: Type, zcu: *const Zcu) u32 {
const ip = &zcu.intern_pool;
- return switch (ip.indexToKey(ty.toIntern())) {
- .struct_type => ip.loadStructType(ty.toIntern()).field_types.len,
- .tuple_type => |tuple| tuple.types.len,
+ switch (ip.indexToKey(ty.toIntern())) {
+ .struct_type => {
+ assertHasLayout(ty, zcu);
+ return ip.loadStructType(ty.toIntern()).field_types.len;
+ },
+ .tuple_type => |tuple| return tuple.types.len,
else => unreachable,
- };
+ }
}
-/// Returns the field type. Supports structs and unions.
+/// Returns the field type. Supports tuples, structs, and unions.
pub fn fieldType(ty: Type, index: usize, zcu: *const Zcu) Type {
const ip = &zcu.intern_pool;
- return switch (ip.indexToKey(ty.toIntern())) {
- .struct_type => Type.fromInterned(ip.loadStructType(ty.toIntern()).field_types.get(ip)[index]),
- .union_type => {
- const union_obj = ip.loadUnionType(ty.toIntern());
- return Type.fromInterned(union_obj.field_types.get(ip)[index]);
+ const types = switch (ip.indexToKey(ty.toIntern())) {
+ .struct_type => types: {
+ assertHasLayout(ty, zcu);
+ break :types ip.loadStructType(ty.toIntern()).field_types;
},
- .tuple_type => |tuple| Type.fromInterned(tuple.types.get(ip)[index]),
+ .union_type => types: {
+ assertHasLayout(ty, zcu);
+ break :types ip.loadUnionType(ty.toIntern()).field_types;
+ },
+ .tuple_type => |tuple| tuple.types,
else => unreachable,
};
+ return .fromInterned(types.get(ip)[index]);
}
-pub fn fieldAlignment(ty: Type, index: usize, zcu: *Zcu) Alignment {
- return ty.fieldAlignmentInner(index, .normal, zcu, {}) catch unreachable;
-}
-
-pub fn fieldAlignmentSema(ty: Type, index: usize, pt: Zcu.PerThread) SemaError!Alignment {
- return try ty.fieldAlignmentInner(index, .sema, pt.zcu, pt.tid);
-}
-
-/// Returns the field alignment. Supports structs and unions.
-/// If `strat` is `.sema`, may perform type resolution.
-/// Asserts the layout is not packed.
+/// If an alignment was explicitly specified for the given field of the struct or union type `ty`,
+/// returns that. Otherwise, returns `.none`. This function also supports tuples, for which it
+/// always returns `.none`.
///
-/// Provide the struct field as the `ty`.
-pub fn fieldAlignmentInner(
- ty: Type,
- index: usize,
- comptime strat: ResolveStrat,
- zcu: strat.ZcuPtr(),
- tid: strat.Tid(),
-) SemaError!Alignment {
+/// Asserts that the layout of `ty` is resolved, unless `ty` is a tuple.
+pub fn explicitFieldAlignment(ty: Type, index: usize, zcu: *const Zcu) Alignment {
const ip = &zcu.intern_pool;
- switch (ip.indexToKey(ty.toIntern())) {
+ return switch (ip.indexToKey(ty.toIntern())) {
+ .tuple_type => .none,
.struct_type => {
- const struct_type = ip.loadStructType(ty.toIntern());
- assert(struct_type.layout != .@"packed");
- const explicit_align = struct_type.fieldAlign(ip, index);
- const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[index]);
- return field_ty.structFieldAlignmentInner(explicit_align, struct_type.layout, strat, zcu, tid);
- },
- .tuple_type => |tuple| {
- return (try Type.fromInterned(tuple.types.get(ip)[index]).abiAlignmentInner(
- strat.toLazy(),
- zcu,
- tid,
- )).scalar;
+ assertHasLayout(ty, zcu);
+ const struct_obj = ip.loadStructType(ty.toIntern());
+ assert(struct_obj.layout != .@"packed");
+ if (struct_obj.field_aligns.len == 0) return .none;
+ return struct_obj.field_aligns.get(ip)[index];
},
.union_type => {
+ assertHasLayout(ty, zcu);
const union_obj = ip.loadUnionType(ty.toIntern());
- const layout = union_obj.flagsUnordered(ip).layout;
- assert(layout != .@"packed");
- const explicit_align = union_obj.fieldAlign(ip, index);
- const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[index]);
- return field_ty.unionFieldAlignmentInner(explicit_align, layout, strat, zcu, tid);
+ assert(union_obj.layout != .@"packed");
+ if (union_obj.field_aligns.len == 0) return .none;
+ return union_obj.field_aligns.get(ip)[index];
},
else => unreachable,
- }
+ };
}
-/// Returns the alignment of a non-packed struct field. Assert the layout is not packed.
+/// Returns the alignment a struct field of type `field_ty` will be given if no alignment is
+/// explicitly specified. However, in an `extern struct`, a higher alignment may be available due
+/// to the struct's full layout (i.e. a field might coincidentally be more aligned).
///
-/// Asserts that all resolution needed was done.
-pub fn structFieldAlignment(
+/// Asserts that the layout of `field_ty` is resolved. Asserts that `layout` is not `.@"packed"`.
+pub fn defaultStructFieldAlignment(
field_ty: Type,
- explicit_alignment: InternPool.Alignment,
layout: std.builtin.Type.ContainerLayout,
- zcu: *Zcu,
+ zcu: *const Zcu,
) Alignment {
- return field_ty.structFieldAlignmentInner(
- explicit_alignment,
- layout,
- .normal,
- zcu,
- {},
- ) catch unreachable;
-}
-
-/// Returns the alignment of a non-packed struct field. Assert the layout is not packed.
-/// May do type resolution when needed.
-/// Asserts that all resolution needed was done.
-pub fn structFieldAlignmentSema(
- field_ty: Type,
- explicit_alignment: InternPool.Alignment,
- layout: std.builtin.Type.ContainerLayout,
- pt: Zcu.PerThread,
-) SemaError!Alignment {
- return try field_ty.structFieldAlignmentInner(
- explicit_alignment,
- layout,
- .sema,
- pt.zcu,
- pt.tid,
- );
-}
-
-/// Returns the alignment of a non-packed struct field. Asserts the layout is not packed.
-/// If `strat` is `.sema`, may perform type resolution.
-pub fn structFieldAlignmentInner(
- field_ty: Type,
- explicit_alignment: Alignment,
- layout: std.builtin.Type.ContainerLayout,
- comptime strat: Type.ResolveStrat,
- zcu: strat.ZcuPtr(),
- tid: strat.Tid(),
-) SemaError!Alignment {
- assert(layout != .@"packed");
- if (explicit_alignment != .none) return explicit_alignment;
- const ty_abi_align = (try field_ty.abiAlignmentInner(
- strat.toLazy(),
- zcu,
- tid,
- )).scalar;
- switch (layout) {
+ const overalign_big_int = switch (layout) {
.@"packed" => unreachable,
- .auto => if (zcu.getTarget().ofmt != .c) return ty_abi_align,
- .@"extern" => {},
+ .auto => zcu.getTarget().ofmt == .c,
+ .@"extern" => true,
+ };
+ const abi_align = field_ty.abiAlignment(zcu);
+ assert(abi_align != .none);
+ if (overalign_big_int and field_ty.isAbiInt(zcu) and field_ty.intInfo(zcu).bits >= 128) {
+ return abi_align.maxStrict(.@"16");
}
- // extern
- if (field_ty.isAbiInt(zcu) and field_ty.intInfo(zcu).bits >= 128) {
- return ty_abi_align.maxStrict(.@"16");
- }
- return ty_abi_align;
-}
-
-pub fn unionFieldAlignmentSema(
- field_ty: Type,
- explicit_alignment: Alignment,
- layout: std.builtin.Type.ContainerLayout,
- pt: Zcu.PerThread,
-) SemaError!Alignment {
- return field_ty.unionFieldAlignmentInner(
- explicit_alignment,
- layout,
- .sema,
- pt.zcu,
- pt.tid,
- );
-}
-
-pub fn unionFieldAlignmentInner(
- field_ty: Type,
- explicit_alignment: Alignment,
- layout: std.builtin.Type.ContainerLayout,
- comptime strat: Type.ResolveStrat,
- zcu: strat.ZcuPtr(),
- tid: strat.Tid(),
-) SemaError!Alignment {
- assert(layout != .@"packed");
- if (explicit_alignment != .none) return explicit_alignment;
- if (field_ty.isNoReturn(zcu)) return .none;
- return (try field_ty.abiAlignmentInner(strat.toLazy(), zcu, tid)).scalar;
+ return abi_align;
}
-pub fn structFieldDefaultValue(ty: Type, index: usize, zcu: *const Zcu) Value {
+pub fn structFieldDefaultValue(ty: Type, index: usize, zcu: *const Zcu) ?Value {
const ip = &zcu.intern_pool;
switch (ip.indexToKey(ty.toIntern())) {
.struct_type => {
- const struct_type = ip.loadStructType(ty.toIntern());
- const val = struct_type.fieldInit(ip, index);
- // TODO: avoid using `unreachable` to indicate this.
- if (val == .none) return Value.@"unreachable";
- return Value.fromInterned(val);
+ const field_defaults = ip.loadStructType(ty.toIntern()).field_defaults.get(ip);
+ if (field_defaults.len == 0) return null;
+ if (field_defaults[index] == .none) return null;
+ return .fromInterned(field_defaults[index]);
},
.tuple_type => |tuple| {
const val = tuple.values.get(ip)[index];
- // TODO: avoid using `unreachable` to indicate this.
- if (val == .none) return Value.@"unreachable";
- return Value.fromInterned(val);
+ if (val == .none) return null;
+ return .fromInterned(val);
},
else => unreachable,
}
@@ -3324,9 +2511,8 @@ pub fn structFieldValueComptime(ty: Type, pt: Zcu.PerThread, index: usize) !?Val
switch (ip.indexToKey(ty.toIntern())) {
.struct_type => {
const struct_type = ip.loadStructType(ty.toIntern());
- if (struct_type.fieldIsComptime(ip, index)) {
- assert(struct_type.haveFieldInits(ip));
- return Value.fromInterned(struct_type.field_inits.get(ip)[index]);
+ if (struct_type.field_is_comptime_bits.get(ip, index)) {
+ return .fromInterned(struct_type.field_defaults.get(ip)[index]);
} else {
return Type.fromInterned(struct_type.field_types.get(ip)[index]).onePossibleValue(pt);
}
@@ -3336,7 +2522,7 @@ pub fn structFieldValueComptime(ty: Type, pt: Zcu.PerThread, index: usize) !?Val
if (val == .none) {
return Type.fromInterned(tuple.types.get(ip)[index]).onePossibleValue(pt);
} else {
- return Value.fromInterned(val);
+ return .fromInterned(val);
}
},
else => unreachable,
@@ -3345,11 +2531,14 @@ pub fn structFieldValueComptime(ty: Type, pt: Zcu.PerThread, index: usize) !?Val
pub fn structFieldIsComptime(ty: Type, index: usize, zcu: *const Zcu) bool {
const ip = &zcu.intern_pool;
- return switch (ip.indexToKey(ty.toIntern())) {
- .struct_type => ip.loadStructType(ty.toIntern()).fieldIsComptime(ip, index),
- .tuple_type => |tuple| tuple.values.get(ip)[index] != .none,
+ switch (ip.indexToKey(ty.toIntern())) {
+ .struct_type => {
+ assertHasLayout(ty, zcu);
+ return ip.loadStructType(ty.toIntern()).field_is_comptime_bits.get(ip, index);
+ },
+ .tuple_type => |tuple| return tuple.values.get(ip)[index] != .none,
else => unreachable,
- };
+ }
}
pub const FieldOffset = struct {
@@ -3357,15 +2546,15 @@ pub const FieldOffset = struct {
offset: u64,
};
-/// Supports structs and unions.
+/// Supports structs, tuples, and unions.
pub fn structFieldOffset(ty: Type, index: usize, zcu: *const Zcu) u64 {
+ assertHasLayout(ty, zcu);
const ip = &zcu.intern_pool;
switch (ip.indexToKey(ty.toIntern())) {
.struct_type => {
const struct_type = ip.loadStructType(ty.toIntern());
- assert(struct_type.haveLayout(ip));
assert(struct_type.layout != .@"packed");
- return struct_type.offsets.get(ip)[index];
+ return struct_type.field_offsets.get(ip)[index];
},
.tuple_type => |tuple| {
@@ -3375,7 +2564,7 @@ pub fn structFieldOffset(ty: Type, index: usize, zcu: *const Zcu) u64 {
for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty, field_val, i| {
if (field_val != .none or !Type.fromInterned(field_ty).hasRuntimeBits(zcu)) {
// comptime field
- if (i == index) return offset;
+ if (i == index) return 0;
continue;
}
@@ -3391,8 +2580,7 @@ pub fn structFieldOffset(ty: Type, index: usize, zcu: *const Zcu) u64 {
.union_type => {
const union_type = ip.loadUnionType(ty.toIntern());
- if (!union_type.hasTag(ip))
- return 0;
+ if (!union_type.has_runtime_tag) return 0;
const layout = Type.getUnionLayout(union_type, zcu);
if (layout.tag_align.compare(.gte, layout.payload_align)) {
// {Tag, Payload}
@@ -3414,7 +2602,7 @@ pub fn srcLocOrNull(ty: Type, zcu: *Zcu) ?Zcu.LazySrcLoc {
.struct_type, .union_type, .opaque_type, .enum_type => |info| switch (info) {
.declared => |d| d.zir_index,
.reified => |r| r.zir_index,
- .generated_tag => |gt| ip.loadUnionType(gt.union_type).zir_index,
+ .generated_union_tag => |union_ty| ip.loadUnionType(union_ty).zir_index,
},
else => return null,
},
@@ -3438,8 +2626,8 @@ pub fn isTuple(ty: Type, zcu: *const Zcu) bool {
};
}
-/// Traverses optional child types and error union payloads until the type
-/// is not a pointer. For `E!?u32`, returns `u32`; for `*u8`, returns `*u8`.
+/// Traverses optional child types and error union payloads until the type is neither of those.
+/// For `E!?u32`, returns `u32`; for `*u8`, returns `*u8`.
pub fn optEuBaseType(ty: Type, zcu: *const Zcu) Type {
var cur = ty;
while (true) switch (cur.zigTypeTag(zcu)) {
@@ -3488,7 +2676,7 @@ pub fn typeDeclInstAllowGeneratedTag(ty: Type, zcu: *const Zcu) ?InternPool.Trac
.union_type => ip.loadUnionType(ty.toIntern()).zir_index,
.enum_type => |e| switch (e) {
.declared, .reified => ip.loadEnumType(ty.toIntern()).zir_index.unwrap().?,
- .generated_tag => |gt| ip.loadUnionType(gt.union_type).zir_index,
+ .generated_union_tag => |union_ty| ip.loadUnionType(union_ty).zir_index,
},
.opaque_type => ip.loadOpaqueType(ty.toIntern()).zir_index,
else => null,
@@ -3505,7 +2693,7 @@ pub fn typeDeclSrcLine(ty: Type, zcu: *Zcu) ?u32 {
.struct_type, .union_type, .opaque_type, .enum_type => |info| switch (info) {
.declared => |d| d.zir_index,
.reified => |r| r.zir_index,
- .generated_tag => |gt| ip.loadUnionType(gt.union_type).zir_index,
+ .generated_union_tag => |union_ty| ip.loadUnionType(union_ty).zir_index,
},
else => return null,
};
@@ -3520,10 +2708,10 @@ pub fn typeDeclSrcLine(ty: Type, zcu: *Zcu) ?u32 {
.struct_init, .struct_init_ref => zir.extraData(Zir.Inst.StructInit, inst.data.pl_node.payload_index).data.abs_line,
.struct_init_anon => zir.extraData(Zir.Inst.StructInitAnon, inst.data.pl_node.payload_index).data.abs_line,
.extended => switch (inst.data.extended.opcode) {
- .struct_decl => zir.extraData(Zir.Inst.StructDecl, inst.data.extended.operand).data.src_line,
- .union_decl => zir.extraData(Zir.Inst.UnionDecl, inst.data.extended.operand).data.src_line,
- .enum_decl => zir.extraData(Zir.Inst.EnumDecl, inst.data.extended.operand).data.src_line,
- .opaque_decl => zir.extraData(Zir.Inst.OpaqueDecl, inst.data.extended.operand).data.src_line,
+ .struct_decl => zir.getStructDecl(info.inst).src_line,
+ .union_decl => zir.getUnionDecl(info.inst).src_line,
+ .enum_decl => zir.getEnumDecl(info.inst).src_line,
+ .opaque_decl => zir.getOpaqueDecl(info.inst).src_line,
.reify_enum => zir.extraData(Zir.Inst.ReifyEnum, inst.data.extended.operand).data.src_line,
.reify_struct => zir.extraData(Zir.Inst.ReifyStruct, inst.data.extended.operand).data.src_line,
.reify_union => zir.extraData(Zir.Inst.ReifyUnion, inst.data.extended.operand).data.src_line,
@@ -3555,369 +2743,11 @@ pub fn arrayBase(ty: Type, zcu: *const Zcu) struct { Type, u64 } {
return .{ cur_ty, cur_len };
}
-/// Returns a bit-pointer with the same value and a new packed offset.
-pub fn packedStructFieldPtrInfo(
- struct_ty: Type,
- parent_ptr_ty: Type,
- field_idx: u32,
- pt: Zcu.PerThread,
-) InternPool.Key.PtrType.PackedOffset {
- comptime assert(Type.packed_struct_layout_version == 2);
-
- const zcu = pt.zcu;
- const parent_ptr_info = parent_ptr_ty.ptrInfo(zcu);
-
- var bit_offset: u16 = 0;
- var running_bits: u16 = 0;
- for (0..struct_ty.structFieldCount(zcu)) |i| {
- const f_ty = struct_ty.fieldType(i, zcu);
- if (i == field_idx) {
- bit_offset = running_bits;
- }
- running_bits += @intCast(f_ty.bitSize(zcu));
- }
-
- const res_host_size: u16, const res_bit_offset: u16 = if (parent_ptr_info.packed_offset.host_size != 0) .{
- parent_ptr_info.packed_offset.host_size,
- parent_ptr_info.packed_offset.bit_offset + bit_offset,
- } else .{
- switch (zcu.comp.getZigBackend()) {
- else => (running_bits + 7) / 8,
- .stage2_x86_64, .stage2_c => @intCast(struct_ty.abiSize(zcu)),
- },
- bit_offset,
- };
-
- return .{
- .host_size = res_host_size,
- .bit_offset = res_bit_offset,
- };
-}
-
-pub fn resolveLayout(ty: Type, pt: Zcu.PerThread) SemaError!void {
- const zcu = pt.zcu;
- const ip = &zcu.intern_pool;
- switch (ty.zigTypeTag(zcu)) {
- .@"struct" => switch (ip.indexToKey(ty.toIntern())) {
- .tuple_type => |tuple_type| for (0..tuple_type.types.len) |i| {
- const field_ty = Type.fromInterned(tuple_type.types.get(ip)[i]);
- try field_ty.resolveLayout(pt);
- },
- .struct_type => return ty.resolveStructInner(pt, .layout),
- else => unreachable,
- },
- .@"union" => return ty.resolveUnionInner(pt, .layout),
- .array => {
- if (ty.arrayLenIncludingSentinel(zcu) == 0) return;
- const elem_ty = ty.childType(zcu);
- return elem_ty.resolveLayout(pt);
- },
- .optional => {
- const payload_ty = ty.optionalChild(zcu);
- return payload_ty.resolveLayout(pt);
- },
- .error_union => {
- const payload_ty = ty.errorUnionPayload(zcu);
- return payload_ty.resolveLayout(pt);
- },
- .@"fn" => {
- const info = zcu.typeToFunc(ty).?;
- if (info.is_generic) {
- // Resolving of generic function types is deferred to when
- // the function is instantiated.
- return;
- }
- for (0..info.param_types.len) |i| {
- const param_ty = info.param_types.get(ip)[i];
- try Type.fromInterned(param_ty).resolveLayout(pt);
- }
- try Type.fromInterned(info.return_type).resolveLayout(pt);
- },
- else => {},
- }
-}
-
-pub fn resolveFields(ty: Type, pt: Zcu.PerThread) SemaError!void {
- const ip = &pt.zcu.intern_pool;
- const ty_ip = ty.toIntern();
-
- switch (ty_ip) {
- .none => unreachable,
-
- .u0_type,
- .i0_type,
- .u1_type,
- .u8_type,
- .i8_type,
- .u16_type,
- .i16_type,
- .u29_type,
- .u32_type,
- .i32_type,
- .u64_type,
- .i64_type,
- .u80_type,
- .u128_type,
- .i128_type,
- .usize_type,
- .isize_type,
- .c_char_type,
- .c_short_type,
- .c_ushort_type,
- .c_int_type,
- .c_uint_type,
- .c_long_type,
- .c_ulong_type,
- .c_longlong_type,
- .c_ulonglong_type,
- .c_longdouble_type,
- .f16_type,
- .f32_type,
- .f64_type,
- .f80_type,
- .f128_type,
- .anyopaque_type,
- .bool_type,
- .void_type,
- .type_type,
- .anyerror_type,
- .adhoc_inferred_error_set_type,
- .comptime_int_type,
- .comptime_float_type,
- .noreturn_type,
- .anyframe_type,
- .null_type,
- .undefined_type,
- .enum_literal_type,
- .ptr_usize_type,
- .ptr_const_comptime_int_type,
- .manyptr_u8_type,
- .manyptr_const_u8_type,
- .manyptr_const_u8_sentinel_0_type,
- .slice_const_u8_type,
- .slice_const_u8_sentinel_0_type,
- .optional_noreturn_type,
- .anyerror_void_error_union_type,
- .generic_poison_type,
- .empty_tuple_type,
- => {},
-
- .undef => unreachable,
- .zero => unreachable,
- .zero_usize => unreachable,
- .zero_u1 => unreachable,
- .zero_u8 => unreachable,
- .one => unreachable,
- .one_usize => unreachable,
- .one_u1 => unreachable,
- .one_u8 => unreachable,
- .four_u8 => unreachable,
- .negative_one => unreachable,
- .void_value => unreachable,
- .unreachable_value => unreachable,
- .null_value => unreachable,
- .bool_true => unreachable,
- .bool_false => unreachable,
- .empty_tuple => unreachable,
-
- else => switch (ty_ip.unwrap(ip).getTag(ip)) {
- .type_struct,
- .type_struct_packed,
- .type_struct_packed_inits,
- => return ty.resolveStructInner(pt, .fields),
-
- .type_union => return ty.resolveUnionInner(pt, .fields),
-
- else => {},
- },
- }
-}
-
-pub fn resolveFully(ty: Type, pt: Zcu.PerThread) SemaError!void {
- const zcu = pt.zcu;
- const ip = &zcu.intern_pool;
-
- switch (ty.zigTypeTag(zcu)) {
- .type,
- .void,
- .bool,
- .noreturn,
- .int,
- .float,
- .comptime_float,
- .comptime_int,
- .undefined,
- .null,
- .error_set,
- .@"enum",
- .@"opaque",
- .frame,
- .@"anyframe",
- .vector,
- .enum_literal,
- => {},
-
- .pointer => return ty.childType(zcu).resolveFully(pt),
- .array => return ty.childType(zcu).resolveFully(pt),
- .optional => return ty.optionalChild(zcu).resolveFully(pt),
- .error_union => return ty.errorUnionPayload(zcu).resolveFully(pt),
- .@"fn" => {
- const info = zcu.typeToFunc(ty).?;
- if (info.is_generic) return;
- for (0..info.param_types.len) |i| {
- const param_ty = info.param_types.get(ip)[i];
- try Type.fromInterned(param_ty).resolveFully(pt);
- }
- try Type.fromInterned(info.return_type).resolveFully(pt);
- },
-
- .@"struct" => switch (ip.indexToKey(ty.toIntern())) {
- .tuple_type => |tuple_type| for (0..tuple_type.types.len) |i| {
- const field_ty = Type.fromInterned(tuple_type.types.get(ip)[i]);
- try field_ty.resolveFully(pt);
- },
- .struct_type => return ty.resolveStructInner(pt, .full),
- else => unreachable,
- },
- .@"union" => return ty.resolveUnionInner(pt, .full),
- }
-}
-
-pub fn resolveStructFieldInits(ty: Type, pt: Zcu.PerThread) SemaError!void {
- // TODO: stop calling this for tuples!
- _ = pt.zcu.typeToStruct(ty) orelse return;
- return ty.resolveStructInner(pt, .inits);
-}
-
-pub fn resolveStructAlignment(ty: Type, pt: Zcu.PerThread) SemaError!void {
- return ty.resolveStructInner(pt, .alignment);
-}
-
-pub fn resolveUnionAlignment(ty: Type, pt: Zcu.PerThread) SemaError!void {
- return ty.resolveUnionInner(pt, .alignment);
-}
-
-/// `ty` must be a struct.
-fn resolveStructInner(
- ty: Type,
- pt: Zcu.PerThread,
- resolution: enum { fields, inits, alignment, layout, full },
-) SemaError!void {
- const zcu = pt.zcu;
- const gpa = zcu.gpa;
-
- const struct_obj = zcu.typeToStruct(ty).?;
- const owner: InternPool.AnalUnit = .wrap(.{ .type = ty.toIntern() });
-
- if (zcu.failed_analysis.contains(owner) or zcu.transitive_failed_analysis.contains(owner)) {
- return error.AnalysisFail;
- }
-
- if (zcu.comp.debugIncremental()) {
- const info = try zcu.incremental_debug_state.getUnitInfo(gpa, owner);
- info.last_update_gen = zcu.generation;
- }
-
- var analysis_arena = std.heap.ArenaAllocator.init(gpa);
- defer analysis_arena.deinit();
-
- var comptime_err_ret_trace = std.array_list.Managed(Zcu.LazySrcLoc).init(gpa);
- defer comptime_err_ret_trace.deinit();
-
- const zir = zcu.namespacePtr(struct_obj.namespace).fileScope(zcu).zir.?;
- var sema: Sema = .{
- .pt = pt,
- .gpa = gpa,
- .arena = analysis_arena.allocator(),
- .code = zir,
- .owner = owner,
- .func_index = .none,
- .func_is_naked = false,
- .fn_ret_ty = Type.void,
- .fn_ret_ty_ies = null,
- .comptime_err_ret_trace = &comptime_err_ret_trace,
- };
- defer sema.deinit();
-
- (switch (resolution) {
- .fields => sema.resolveStructFieldTypes(ty.toIntern(), struct_obj),
- .inits => sema.resolveStructFieldInits(ty),
- .alignment => sema.resolveStructAlignment(ty.toIntern(), struct_obj),
- .layout => sema.resolveStructLayout(ty),
- .full => sema.resolveStructFully(ty),
- }) catch |err| switch (err) {
- error.AnalysisFail => {
- if (!zcu.failed_analysis.contains(owner)) {
- try zcu.transitive_failed_analysis.put(gpa, owner, {});
- }
- return error.AnalysisFail;
- },
- error.OutOfMemory, error.Canceled => |e| return e,
- };
-}
-
-/// `ty` must be a union.
-fn resolveUnionInner(
- ty: Type,
- pt: Zcu.PerThread,
- resolution: enum { fields, alignment, layout, full },
-) SemaError!void {
- const zcu = pt.zcu;
- const gpa = zcu.gpa;
-
- const union_obj = zcu.typeToUnion(ty).?;
- const owner: InternPool.AnalUnit = .wrap(.{ .type = ty.toIntern() });
-
- if (zcu.failed_analysis.contains(owner) or zcu.transitive_failed_analysis.contains(owner)) {
- return error.AnalysisFail;
- }
-
- if (zcu.comp.debugIncremental()) {
- const info = try zcu.incremental_debug_state.getUnitInfo(gpa, owner);
- info.last_update_gen = zcu.generation;
- }
-
- var analysis_arena = std.heap.ArenaAllocator.init(gpa);
- defer analysis_arena.deinit();
-
- var comptime_err_ret_trace = std.array_list.Managed(Zcu.LazySrcLoc).init(gpa);
- defer comptime_err_ret_trace.deinit();
-
- const zir = zcu.namespacePtr(union_obj.namespace).fileScope(zcu).zir.?;
- var sema: Sema = .{
- .pt = pt,
- .gpa = gpa,
- .arena = analysis_arena.allocator(),
- .code = zir,
- .owner = owner,
- .func_index = .none,
- .func_is_naked = false,
- .fn_ret_ty = Type.void,
- .fn_ret_ty_ies = null,
- .comptime_err_ret_trace = &comptime_err_ret_trace,
- };
- defer sema.deinit();
-
- (switch (resolution) {
- .fields => sema.resolveUnionFieldTypes(ty, union_obj),
- .alignment => sema.resolveUnionAlignment(ty, union_obj),
- .layout => sema.resolveUnionLayout(ty),
- .full => sema.resolveUnionFully(ty),
- }) catch |err| switch (err) {
- error.AnalysisFail => {
- if (!zcu.failed_analysis.contains(owner)) {
- try zcu.transitive_failed_analysis.put(gpa, owner, {});
- }
- return error.AnalysisFail;
- },
- error.OutOfMemory => |e| return e,
- error.Canceled => |e| return e,
- };
-}
-
+/// Asserts that `loaded_union.layout` is not `.@"packed"`.
pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu) Zcu.UnionLayout {
+ assert(loaded_union.layout != .@"packed");
+
const ip = &zcu.intern_pool;
- assert(loaded_union.haveLayout(ip));
var most_aligned_field: u32 = 0;
var most_aligned_field_align: InternPool.Alignment = .@"1";
var most_aligned_field_size: u64 = 0;
@@ -3928,11 +2758,14 @@ pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu)
const field_ty: Type = .fromInterned(field_ty_ip_index);
if (field_ty.isNoReturn(zcu)) continue;
- const explicit_align = loaded_union.fieldAlign(ip, field_index);
- const field_align = if (explicit_align != .none)
- explicit_align
- else
- field_ty.abiAlignment(zcu);
+ const field_align: InternPool.Alignment = a: {
+ const explicit_aligns = loaded_union.field_aligns.get(ip);
+ if (explicit_aligns.len > 0) {
+ const a = explicit_aligns[field_index];
+ if (a != .none) break :a a;
+ }
+ break :a field_ty.abiAlignment(zcu);
+ };
if (field_ty.hasRuntimeBits(zcu)) {
const field_size = field_ty.abiSize(zcu);
if (field_size > payload_size) {
@@ -3947,8 +2780,9 @@ pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu)
}
payload_align = payload_align.max(field_align);
}
- const have_tag = loaded_union.flagsUnordered(ip).runtime_tag.hasTag();
- if (!have_tag or !Type.fromInterned(loaded_union.enum_tag_ty).hasRuntimeBits(zcu)) {
+ if (!loaded_union.has_runtime_tag or
+ !Type.fromInterned(loaded_union.enum_tag_type).hasRuntimeBits(zcu))
+ {
return .{
.abi_size = payload_align.forward(payload_size),
.abi_align = payload_align,
@@ -3963,10 +2797,10 @@ pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu)
};
}
- const tag_size = Type.fromInterned(loaded_union.enum_tag_ty).abiSize(zcu);
- const tag_align = Type.fromInterned(loaded_union.enum_tag_ty).abiAlignment(zcu).max(.@"1");
+ const tag_size = Type.fromInterned(loaded_union.enum_tag_type).abiSize(zcu);
+ const tag_align = Type.fromInterned(loaded_union.enum_tag_type).abiAlignment(zcu).max(.@"1");
return .{
- .abi_size = loaded_union.sizeUnordered(ip),
+ .abi_size = loaded_union.size,
.abi_align = tag_align.max(payload_align),
.most_aligned_field = most_aligned_field,
.most_aligned_field_size = most_aligned_field_size,
@@ -3975,85 +2809,229 @@ pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu)
.payload_align = payload_align,
.tag_align = tag_align,
.tag_size = tag_size,
- .padding = loaded_union.paddingUnordered(ip),
+ .padding = loaded_union.padding,
};
}
-/// Returns the type of a pointer to an element.
-/// Asserts that the type is a pointer, and that the element type is indexable.
-/// If the element index is comptime-known, it must be passed in `offset`.
-/// For *@Vector(n, T), return *align(a:b:h:v) T
-/// For *[N]T, return *T
-/// For [*]T, returns *T
-/// For []T, returns *T
-/// Handles const-ness and address spaces in particular.
-/// This code is duplicated in `Sema.analyzePtrArithmetic`.
-/// May perform type resolution and return a transitive `error.AnalysisFail`.
-pub fn elemPtrType(ptr_ty: Type, offset: ?usize, pt: Zcu.PerThread) !Type {
+/// Asserts that `ptr_ty` is either a many-item pointer, a slice, a C pointer, or a single pointer
+/// to array (in other words, a pointer which is indexed by pointer arithmetic), and returns the
+/// type of the element pointer at the given index.
+///
+/// Asserts that the layout of the pointer element type is resolved.
+///
+/// If `index` is `null`, the index is an arbitrary runtime-known value.
+pub fn elemPtrType(ptr_ty: Type, index: ?u64, pt: Zcu.PerThread) Allocator.Error!Type {
const zcu = pt.zcu;
- const ptr_info = ptr_ty.ptrInfo(zcu);
- const elem_ty = ptr_ty.elemType2(zcu);
- const is_allowzero = ptr_info.flags.is_allowzero and (offset orelse 0) == 0;
- const parent_ty = ptr_ty.childType(zcu);
-
- const VI = InternPool.Key.PtrType.VectorIndex;
-
- const vector_info: struct {
- host_size: u16 = 0,
- alignment: Alignment = .none,
- vector_index: VI = .none,
- } = if (parent_ty.isVector(zcu) and ptr_info.flags.size == .one) blk: {
- const elem_bits = elem_ty.bitSize(zcu);
- if (elem_bits == 0) break :blk .{};
- const is_packed = elem_bits < 8 or !std.math.isPowerOfTwo(elem_bits);
- if (!is_packed) break :blk .{};
-
- break :blk .{
- .host_size = @intCast(parent_ty.arrayLen(zcu)),
- .alignment = parent_ty.abiAlignment(zcu),
- .vector_index = @enumFromInt(offset.?),
- };
- } else .{};
+ const ip = &zcu.intern_pool;
+ const ptr_info = ip.indexToKey(ptr_ty.toIntern()).ptr_type;
+ const elem_ty: Type = switch (ptr_info.flags.size) {
+ .slice, .many, .c => .fromInterned(ptr_info.child),
+ .one => switch (ip.indexToKey(ptr_info.child)) {
+ .array_type => |array_type| .fromInterned(array_type.child),
+ else => unreachable,
+ },
+ };
+ elem_ty.assertHasLayout(zcu);
+ const elem_align: Alignment = switch (elem_ty.classify(zcu)) {
+ .no_possible_value,
+ .one_possible_value,
+ => ptr_info.flags.alignment,
- const alignment: Alignment = a: {
- // Calculate the new pointer alignment.
- if (ptr_info.flags.alignment == .none) {
- // In case of an ABI-aligned pointer, any pointer arithmetic
- // maintains the same ABI-alignedness.
- break :a vector_info.alignment;
- }
- // If the addend is not a comptime-known value we can still count on
- // it being a multiple of the type size.
- const elem_size = (try elem_ty.abiSizeInner(.sema, zcu, pt.tid)).scalar;
- const addend = if (offset) |off| elem_size * off else elem_size;
+ .partially_comptime,
+ .fully_comptime,
+ => switch (ptr_info.flags.alignment) {
+ .none => .none,
+ else => |array_align| .minStrict(array_align, elem_ty.abiAlignment(zcu)),
+ },
- // The resulting pointer is aligned to the lcd between the offset (an
- // arbitrary number) and the alignment factor (always a power of two,
- // non zero).
- const new_align: Alignment = @enumFromInt(@min(
- @ctz(addend),
- ptr_info.flags.alignment.toLog2Units(),
- ));
- assert(new_align != .none);
- break :a new_align;
+ .runtime => switch (ptr_info.flags.alignment) {
+ .none => .none,
+ else => |array_align| elem_align: {
+ // If the index is runtime-known, use 1 as it gives the minimum possible alignment.
+ const effective_index = index orelse 1;
+ if (effective_index == 0) break :elem_align array_align;
+ const byte_offset = effective_index * elem_ty.abiSize(zcu);
+ break :elem_align .minStrict(array_align, .fromLog2Units(@ctz(byte_offset)));
+ },
+ },
};
- return pt.ptrTypeSema(.{
+ return pt.ptrType(.{
.child = elem_ty.toIntern(),
.flags = .{
- .alignment = alignment,
+ .size = .one,
.is_const = ptr_info.flags.is_const,
.is_volatile = ptr_info.flags.is_volatile,
- .is_allowzero = is_allowzero,
+ .is_allowzero = ptr_info.flags.is_allowzero and (index == null or index == 0),
.address_space = ptr_info.flags.address_space,
- .vector_index = vector_info.vector_index,
- },
- .packed_offset = .{
- .host_size = vector_info.host_size,
- .bit_offset = 0,
+ .alignment = elem_align,
},
});
}
+/// Asserts that `ptr_ty` is a pointer (single-item or C) to a struct, union, tuple, or slice, and
+/// returns the type of a pointer to the field at `field_index`.
+///
+/// Asserts that the layout of the pointer child type is resolved.
+///
+/// For slices, `Value.slice_ptr_index` and `Value.slice_len_index` are used for the field index.
+pub fn fieldPtrType(ptr_ty: Type, field_index: u32, pt: Zcu.PerThread) Allocator.Error!Type {
+ const zcu = pt.zcu;
+ const ip = &zcu.intern_pool;
+ const ptr_info = ip.indexToKey(ptr_ty.toIntern()).ptr_type;
+ assert(ptr_info.flags.size == .one or ptr_info.flags.size == .c);
+ const aggregate_ty: Type = .fromInterned(ptr_info.child);
+ aggregate_ty.assertHasLayout(zcu);
+ // We only exit this `switch` for default-layout aggregates, where the field pointer alignment
+ // is a simple minimum of the aggregate pointer alignment and the field alignment.
+ // `field_align` is `.none` if there is no explicit alignment annotation.
+ const field_ty: Type, const field_align: Alignment = switch (aggregate_ty.zigTypeTag(zcu)) {
+ .@"struct" => switch (aggregate_ty.containerLayout(zcu)) {
+ .auto => field: {
+ if (aggregate_ty.isTuple(zcu)) {
+ break :field .{ aggregate_ty.fieldType(field_index, zcu), .none };
+ }
+ const struct_obj = ip.loadStructType(aggregate_ty.toIntern());
+ break :field .{
+ .fromInterned(struct_obj.field_types.get(ip)[field_index]),
+ struct_obj.field_aligns.getOrNone(ip, field_index),
+ };
+ },
+ .@"extern" => {
+ // Field alignment is determined based on the actual field offset. For instance, in
+ // `extern struct { x: u32, y: u16 }`, the `y` field is 4-byte aligned.
+ const field_ty = aggregate_ty.fieldType(field_index, zcu);
+ const field_offset = aggregate_ty.structFieldOffset(field_index, zcu);
+ const parent_align = switch (ptr_info.flags.alignment) {
+ .none => aggregate_ty.abiAlignment(zcu),
+ else => |a| a,
+ };
+ const actual_field_align = switch (field_offset) {
+ 0 => parent_align,
+ else => parent_align.minStrict(.fromLog2Units(@ctz(field_offset))),
+ };
+ const field_ptr_align: Alignment = a: {
+ if (ptr_info.flags.alignment == .none and
+ aggregate_ty.explicitFieldAlignment(field_index, zcu) == .none and
+ actual_field_align == field_ty.abiAlignment(zcu))
+ {
+ // There's no user-specified 'align' in sight, and the alignment from the
+ // field offset matches the field type's natural alignment, so just use a
+ // default-aligned pointer.
+ break :a .none;
+ }
+ break :a actual_field_align;
+ };
+ var field_ptr_info = ptr_info;
+ field_ptr_info.child = field_ty.toIntern();
+ field_ptr_info.flags.alignment = field_ptr_align;
+ return pt.ptrType(field_ptr_info);
+ },
+ .@"packed" => {
+ var field_ptr_info = ptr_info;
+ if (field_ptr_info.flags.alignment == .none) {
+ field_ptr_info.flags.alignment = aggregate_ty.abiAlignment(zcu);
+ }
+ field_ptr_info.packed_offset = packed_offset: {
+ comptime assert(Type.packed_struct_layout_version == 2);
+ const bit_offset = zcu.structPackedFieldBitOffset(
+ ip.loadStructType(aggregate_ty.toIntern()),
+ field_index,
+ );
+ break :packed_offset if (ptr_info.packed_offset.host_size != 0) .{
+ .host_size = ptr_info.packed_offset.host_size,
+ .bit_offset = ptr_info.packed_offset.bit_offset + bit_offset,
+ } else .{
+ .host_size = switch (zcu.comp.getZigBackend()) {
+ else => @intCast((aggregate_ty.bitSize(zcu) + 7) / 8),
+ .stage2_x86_64, .stage2_c => @intCast(aggregate_ty.abiSize(zcu)),
+ },
+ .bit_offset = ptr_info.packed_offset.bit_offset + bit_offset,
+ };
+ };
+ field_ptr_info.child = aggregate_ty.fieldType(field_index, zcu).toIntern();
+ return pt.ptrType(field_ptr_info);
+ },
+ },
+ .@"union" => switch (aggregate_ty.containerLayout(zcu)) {
+ .auto => field: {
+ const union_obj = ip.loadUnionType(aggregate_ty.toIntern());
+ break :field .{
+ .fromInterned(union_obj.field_types.get(ip)[field_index]),
+ union_obj.field_aligns.getOrNone(ip, field_index),
+ };
+ },
+ .@"extern" => {
+ // The alignment always matches that of the union pointer. If the union pointer is
+ // default aligned (`.none`), we may need to explicitly align the result pointer.
+ const field_ty = aggregate_ty.fieldType(field_index, zcu);
+ var field_ptr_info = ptr_info;
+ field_ptr_info.child = field_ty.toIntern();
+ if (field_ptr_info.flags.alignment == .none and
+ Alignment.compareStrict(field_ty.abiAlignment(zcu), .neq, aggregate_ty.abiAlignment(zcu)))
+ {
+ field_ptr_info.flags.alignment = aggregate_ty.abiAlignment(zcu);
+ }
+ return pt.ptrType(field_ptr_info);
+ },
+ .@"packed" => {
+ const field_ty = aggregate_ty.fieldType(field_index, zcu);
+ var field_ptr_info = ptr_info;
+ if (field_ptr_info.flags.alignment == .none) {
+ const resolved_align = aggregate_ty.abiAlignment(zcu);
+ if (field_ty.abiAlignment(zcu) != resolved_align) {
+ field_ptr_info.flags.alignment = resolved_align;
+ }
+ }
+ field_ptr_info.child = aggregate_ty.fieldType(field_index, zcu).toIntern();
+ return pt.ptrType(field_ptr_info);
+ },
+ },
+ .pointer => field: {
+ assert(aggregate_ty.isSlice(zcu));
+ break :field switch (field_index) {
+ Value.slice_ptr_index => .{ aggregate_ty.slicePtrFieldType(zcu), .none },
+ Value.slice_len_index => .{ .usize, .none },
+ else => unreachable,
+ };
+ },
+ else => unreachable,
+ };
+ const field_ptr_align: Alignment = a: {
+ if (aggregate_ty.zigTypeTag(zcu) == .@"struct" and aggregate_ty.structFieldIsComptime(field_index, zcu)) {
+ // For `comptime` fields, just use exactly what was specified, or ABI alignment if nothing was specified.
+ break :a field_align;
+ }
+ const actual_field_align = switch (field_align) {
+ .none => switch (ip.indexToKey(aggregate_ty.toIntern())) {
+ .tuple_type, .union_type => field_ty.abiAlignment(zcu),
+ .struct_type => field_ty.defaultStructFieldAlignment(.auto, zcu),
+ .ptr_type => Type.usize.abiAlignment(zcu),
+ else => unreachable,
+ },
+ else => |a| a,
+ };
+ const actual_aggregate_align = switch (ptr_info.flags.alignment) {
+ .none => aggregate_ty.abiAlignment(zcu),
+ else => |a| a,
+ };
+ if (actual_aggregate_align.compareStrict(.lt, actual_field_align)) {
+ // Underaligned aggregate; use that alignment.
+ assert(ptr_info.flags.alignment != .none);
+ break :a actual_aggregate_align;
+ }
+ if (field_align == .none and actual_field_align == field_ty.abiAlignment(zcu)) {
+ // No explicit annotation on the field (nor an unusual default), and the aggregate
+ // alignment is irrelevant to us, so return an un-annotated pointer.
+ break :a .none;
+ }
+ break :a actual_field_align;
+ };
+ var field_ptr_info = ptr_info;
+ field_ptr_info.flags.alignment = field_ptr_align;
+ field_ptr_info.child = field_ty.toIntern();
+ return pt.ptrType(field_ptr_info);
+}
+
pub fn containerTypeName(ty: Type, ip: *const InternPool) InternPool.NullTerminatedString {
return switch (ip.indexToKey(ty.toIntern())) {
.struct_type => ip.loadStructType(ty.toIntern()).name,
@@ -4064,14 +3042,257 @@ pub fn containerTypeName(ty: Type, ip: *const InternPool) InternPool.NullTermina
};
}
-/// Returns `true` if a value of this type is always `null`.
-/// Returns `false` if a value of this type is neve `null`.
-/// Returns `null` otherwise.
-pub fn isNullFromType(ty: Type, zcu: *const Zcu) ?bool {
- if (ty.zigTypeTag(zcu) != .optional and !ty.isCPtr(zcu)) return false;
- const child = ty.optionalChild(zcu);
- if (child.zigTypeTag(zcu) == .noreturn) return true; // `?noreturn` is always null
- return null;
+pub fn destructurable(ty: Type, zcu: *const Zcu) bool {
+ return switch (ty.zigTypeTag(zcu)) {
+ .array, .vector => true,
+ .@"struct" => ty.isTuple(zcu),
+ else => false,
+ };
+}
+
+pub const UnpackableReason = union(enum) {
+ comptime_only,
+ pointer,
+ enum_inferred_int_tag: Type,
+ non_packed_struct: Type,
+ non_packed_union: Type,
+ slice,
+ other,
+};
+
+/// Returns `null` iff `ty` is allowed in packed types.
+pub fn unpackable(ty: Type, zcu: *const Zcu) ?UnpackableReason {
+ return switch (ty.zigTypeTag(zcu)) {
+ .void,
+ .bool,
+ .float,
+ .int,
+ => null,
+
+ .type,
+ .comptime_float,
+ .comptime_int,
+ .enum_literal,
+ .undefined,
+ .null,
+ => .comptime_only,
+
+ .noreturn,
+ .@"opaque",
+ .error_union,
+ .error_set,
+ .frame,
+ .@"anyframe",
+ .@"fn",
+ .array,
+ .vector,
+ => .other,
+
+ .optional => if (ty.isPtrLikeOptional(zcu))
+ .pointer
+ else
+ .other,
+
+ .pointer => switch (ty.ptrSize(zcu)) {
+ .slice => .slice,
+ .one, .many, .c => .pointer,
+ },
+
+ .@"enum" => switch (zcu.intern_pool.loadEnumType(ty.toIntern()).int_tag_mode) {
+ .explicit => null,
+ .auto => .{ .enum_inferred_int_tag = ty },
+ },
+
+ .@"struct" => switch (ty.containerLayout(zcu)) {
+ .@"packed" => null,
+ .auto, .@"extern" => .{ .non_packed_struct = ty },
+ },
+ .@"union" => switch (ty.containerLayout(zcu)) {
+ .@"packed" => null,
+ .auto, .@"extern" => .{ .non_packed_union = ty },
+ },
+ };
+}
+
+pub const ExternPosition = enum {
+ ret_ty,
+ param_ty,
+ union_field,
+ struct_field,
+ element,
+ other,
+};
+
+/// Returns true if `ty` is allowed in extern types.
+/// Asserts that `ty` is fully resolved.
+/// Keep in sync with `Sema.explainWhyTypeIsNotExtern`.
+pub fn validateExtern(ty: Type, position: ExternPosition, zcu: *const Zcu) bool {
+ ty.assertHasLayout(zcu);
+ return switch (ty.zigTypeTag(zcu)) {
+ .type,
+ .comptime_float,
+ .comptime_int,
+ .enum_literal,
+ .undefined,
+ .null,
+ .error_union,
+ .error_set,
+ .frame,
+ => false,
+
+ .void => switch (position) {
+ .ret_ty,
+ .union_field,
+ .struct_field,
+ .element,
+ => true,
+ .param_ty,
+ .other,
+ => false,
+ },
+
+ .noreturn => position == .ret_ty,
+
+ .@"opaque",
+ .bool,
+ .float,
+ .@"anyframe",
+ => true,
+
+ .pointer => {
+ if (ty.isSlice(zcu)) return false;
+ const child_ty = ty.childType(zcu);
+ if (child_ty.zigTypeTag(zcu) == .@"fn") {
+ return ty.isConstPtr(zcu) and validateExternCallconv(child_ty.fnCallingConvention(zcu));
+ }
+ return true;
+ },
+ .int => switch (ty.intInfo(zcu).bits) {
+ 0, 8, 16, 32, 64, 128 => true,
+ else => false,
+ },
+ .@"fn" => {
+ if (position != .other) return false;
+ return validateExternCallconv(ty.fnCallingConvention(zcu));
+ },
+ .@"enum" => {
+ const enum_obj = zcu.intern_pool.loadEnumType(ty.toIntern());
+ return switch (enum_obj.int_tag_mode) {
+ .auto => false,
+ .explicit => Type.fromInterned(enum_obj.int_tag_type).validateExtern(position, zcu),
+ };
+ },
+ .@"struct" => {
+ const struct_obj = zcu.intern_pool.loadStructType(ty.toIntern());
+ return switch (struct_obj.layout) {
+ .auto => false,
+ .@"extern" => true,
+ .@"packed" => switch (struct_obj.packed_backing_mode) {
+ .auto => false,
+ .explicit => Type.fromInterned(struct_obj.packed_backing_int_type).validateExtern(position, zcu),
+ },
+ };
+ },
+ .@"union" => {
+ const union_obj = zcu.intern_pool.loadUnionType(ty.toIntern());
+ return switch (union_obj.layout) {
+ .auto => false,
+ .@"extern" => true,
+ .@"packed" => switch (union_obj.packed_backing_mode) {
+ .auto => false,
+ .explicit => Type.fromInterned(union_obj.packed_backing_int_type).validateExtern(position, zcu),
+ },
+ };
+ },
+ .array => switch (position) {
+ .ret_ty,
+ .param_ty,
+ => false,
+
+ .union_field,
+ .struct_field,
+ .element,
+ .other,
+ => ty.childType(zcu).validateExtern(.element, zcu),
+ },
+ .vector => ty.childType(zcu).validateExtern(.element, zcu),
+ .optional => ty.isPtrLikeOptional(zcu),
+ };
+}
+fn validateExternCallconv(cc: std.builtin.CallingConvention) bool {
+ return switch (cc) {
+ // For now we want to authorize PTX kernel to use zig objects, even if we end up exposing the ABI.
+ // The goal is to experiment with more integrated CPU/GPU code.
+ .nvptx_kernel => true,
+ else => !target_util.fnCallConvAllowsZigTypes(cc),
+ };
+}
+
+/// Asserts that `ty` has resolved layout.
+pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void {
+ if (!std.debug.runtime_safety) {
+ // This early exit isn't necessary (`Zcu.assertUpToDate` checks `std.debug.runtime_safety`
+ // itself), but LLVM has been observed to fail at optimizing away this safety check, which
+ // has a major performance impact on ReleaseFast compiler builds.
+ return;
+ }
+ switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
+ .int_type,
+ .ptr_type,
+ .anyframe_type,
+ .simple_type,
+ .opaque_type,
+ .error_set_type,
+ .inferred_error_set_type,
+ => {},
+ .func_type => |func_type| {
+ for (func_type.param_types.get(&zcu.intern_pool)) |param_ty| {
+ assertHasLayout(.fromInterned(param_ty), zcu);
+ }
+ assertHasLayout(.fromInterned(func_type.return_type), zcu);
+ },
+ .array_type => |arr| assertHasLayout(.fromInterned(arr.child), zcu),
+ .vector_type => |vec| assertHasLayout(.fromInterned(vec.child), zcu),
+ .opt_type => |child| assertHasLayout(.fromInterned(child), zcu),
+ .error_union_type => |eu| assertHasLayout(.fromInterned(eu.payload_type), zcu),
+ .tuple_type => |tuple| for (tuple.types.get(&zcu.intern_pool)) |field_ty| {
+ assertHasLayout(.fromInterned(field_ty), zcu);
+ },
+ .struct_type => {
+ assert(zcu.intern_pool.loadStructType(ty.toIntern()).want_layout);
+ zcu.assertUpToDate(.wrap(.{ .type_layout = ty.toIntern() }));
+ },
+ .union_type => {
+ assert(zcu.intern_pool.loadUnionType(ty.toIntern()).want_layout);
+ zcu.assertUpToDate(.wrap(.{ .type_layout = ty.toIntern() }));
+ },
+ .enum_type => {
+ assert(zcu.intern_pool.loadEnumType(ty.toIntern()).want_layout);
+ zcu.assertUpToDate(.wrap(.{ .type_layout = ty.toIntern() }));
+ },
+
+ // values, not types
+ .simple_value,
+ .variable,
+ .@"extern",
+ .func,
+ .int,
+ .err,
+ .error_union,
+ .enum_literal,
+ .enum_tag,
+ .float,
+ .ptr,
+ .slice,
+ .opt,
+ .aggregate,
+ .un,
+ .bitpack,
+ .undef,
+ // memoization, not types
+ .memoized_call,
+ => unreachable,
+ }
}
/// Recursively walks the type and marks for each subtype how many times it has been seen
@@ -4138,13 +3359,13 @@ fn collectSubtypes(ty: Type, pt: Zcu.PerThread, visited: *std.AutoArrayHashMapUn
.error_union,
.enum_literal,
.enum_tag,
- .empty_enum_value,
.float,
.ptr,
.slice,
.opt,
.aggregate,
.un,
+ .bitpack,
// memoization, not types
.memoized_call,
=> unreachable,
@@ -4243,6 +3464,7 @@ pub const Comparison = struct {
};
};
+pub const @"u0": Type = .{ .ip_index = .u0_type };
pub const @"u1": Type = .{ .ip_index = .u1_type };
pub const @"u8": Type = .{ .ip_index = .u8_type };
pub const @"u16": Type = .{ .ip_index = .u16_type };
diff --git a/src/Value.zig b/src/Value.zig
index 103140d3c9a3df0878f1ceb254ba2bb483ea2865..3176520d3628f07050a6821e9040b8a7c12449db 100644
--- a/src/Value.zig
+++ b/src/Value.zig
@@ -146,80 +146,23 @@ pub fn toType(self: Value) Type {
return Type.fromInterned(self.toIntern());
}
-pub fn intFromEnum(val: Value, ty: Type, pt: Zcu.PerThread) Allocator.Error!Value {
- const ip = &pt.zcu.intern_pool;
- const enum_ty = ip.typeOf(val.toIntern());
- return switch (ip.indexToKey(enum_ty)) {
- // Assume it is already an integer and return it directly.
- .simple_type, .int_type => val,
- .enum_literal => |enum_literal| {
- const field_index = ty.enumFieldIndex(enum_literal, pt.zcu).?;
- switch (ip.indexToKey(ty.toIntern())) {
- // Assume it is already an integer and return it directly.
- .simple_type, .int_type => return val,
- .enum_type => {
- const enum_type = ip.loadEnumType(ty.toIntern());
- if (enum_type.values.len != 0) {
- return Value.fromInterned(enum_type.values.get(ip)[field_index]);
- } else {
- // Field index and integer values are the same.
- return pt.intValue(Type.fromInterned(enum_type.tag_ty), field_index);
- }
- },
- else => unreachable,
- }
- },
- .enum_type => try pt.getCoerced(val, Type.fromInterned(ip.loadEnumType(enum_ty).tag_ty)),
- else => unreachable,
- };
+pub fn intFromEnum(val: Value, zcu: *const Zcu) Value {
+ return .fromInterned(zcu.intern_pool.indexToKey(val.toIntern()).enum_tag.int);
}
-pub const ResolveStrat = Type.ResolveStrat;
-
-/// Asserts the value is an integer.
-pub fn toBigInt(val: Value, space: *BigIntSpace, zcu: *Zcu) BigIntConst {
- return val.toBigIntAdvanced(space, .normal, zcu, {}) catch unreachable;
-}
-
-pub fn toBigIntSema(val: Value, space: *BigIntSpace, pt: Zcu.PerThread) !BigIntConst {
- return try val.toBigIntAdvanced(space, .sema, pt.zcu, pt.tid);
-}
-
-/// Asserts the value is an integer.
-pub fn toBigIntAdvanced(
- val: Value,
- space: *BigIntSpace,
- comptime strat: ResolveStrat,
- zcu: *Zcu,
- tid: strat.Tid(),
-) Zcu.SemaError!BigIntConst {
+/// Asserts that `val` is an integer.
+pub fn toBigInt(val: Value, space: *BigIntSpace, zcu: *const Zcu) BigIntConst {
+ if (val.getUnsignedInt(zcu)) |x| {
+ return BigIntMutable.init(&space.limbs, x).toConst();
+ }
const ip = &zcu.intern_pool;
- return switch (val.toIntern()) {
- .bool_false => BigIntMutable.init(&space.limbs, 0).toConst(),
- .bool_true => BigIntMutable.init(&space.limbs, 1).toConst(),
- .null_value => BigIntMutable.init(&space.limbs, 0).toConst(),
- else => switch (ip.indexToKey(val.toIntern())) {
- .int => |int| switch (int.storage) {
- .u64, .i64, .big_int => int.storage.toBigInt(space),
- .lazy_align, .lazy_size => |ty| {
- if (strat == .sema) try Type.fromInterned(ty).resolveLayout(strat.pt(zcu, tid));
- const x = switch (int.storage) {
- else => unreachable,
- .lazy_align => Type.fromInterned(ty).abiAlignment(zcu).toByteUnits() orelse 0,
- .lazy_size => Type.fromInterned(ty).abiSize(zcu),
- };
- return BigIntMutable.init(&space.limbs, x).toConst();
- },
- },
- .enum_tag => |enum_tag| Value.fromInterned(enum_tag.int).toBigIntAdvanced(space, strat, zcu, tid),
- .opt, .ptr => BigIntMutable.init(
- &space.limbs,
- (try val.getUnsignedIntInner(strat, zcu, tid)).?,
- ).toConst(),
- .err => |err| BigIntMutable.init(&space.limbs, ip.getErrorValueIfExists(err.name).?).toConst(),
- else => unreachable,
- },
+ const int_key = switch (ip.indexToKey(val.toIntern())) {
+ .enum_tag => |enum_tag| ip.indexToKey(enum_tag.int).int,
+ .bitpack => |bitpack| ip.indexToKey(bitpack.backing_int_val).int,
+ .int => |int| int,
+ else => unreachable,
};
+ return int_key.storage.toBigInt(space);
}
pub fn isFuncBody(val: Value, zcu: *Zcu) bool {
@@ -240,31 +183,17 @@ pub fn getVariable(val: Value, mod: *Zcu) ?InternPool.Key.Variable {
};
}
-/// If the value fits in a u64, return it, otherwise null.
-/// Asserts not undefined.
-pub fn getUnsignedInt(val: Value, zcu: *const Zcu) ?u64 {
- return getUnsignedIntInner(val, .normal, zcu, {}) catch unreachable;
-}
-
-/// Asserts the value is an integer and it fits in a u64
+/// Asserts the value is a (defined) integer and it fits in a u64.
pub fn toUnsignedInt(val: Value, zcu: *const Zcu) u64 {
return getUnsignedInt(val, zcu).?;
}
-pub fn getUnsignedIntSema(val: Value, pt: Zcu.PerThread) !?u64 {
- return try val.getUnsignedIntInner(.sema, pt.zcu, pt.tid);
-}
-
/// If the value fits in a u64, return it, otherwise null.
/// Asserts not undefined.
-pub fn getUnsignedIntInner(
- val: Value,
- comptime strat: ResolveStrat,
- zcu: strat.ZcuPtr(),
- tid: strat.Tid(),
-) !?u64 {
+pub fn getUnsignedInt(val: Value, zcu: *const Zcu) ?u64 {
return switch (val.toIntern()) {
.undef => unreachable,
+ .null_value => 0,
.bool_false => 0,
.bool_true => 1,
else => switch (zcu.intern_pool.indexToKey(val.toIntern())) {
@@ -273,37 +202,28 @@ pub fn getUnsignedIntInner(
.big_int => |big_int| big_int.toInt(u64) catch null,
.u64 => |x| x,
.i64 => |x| std.math.cast(u64, x),
- .lazy_align => |ty| (try Type.fromInterned(ty).abiAlignmentInner(strat.toLazy(), zcu, tid)).scalar.toByteUnits() orelse 0,
- .lazy_size => |ty| (try Type.fromInterned(ty).abiSizeInner(strat.toLazy(), zcu, tid)).scalar,
},
.ptr => |ptr| switch (ptr.base_addr) {
.int => ptr.byte_offset,
.field => |field| {
- const base_addr = (try Value.fromInterned(field.base).getUnsignedIntInner(strat, zcu, tid)) orelse return null;
+ const base_addr = Value.fromInterned(field.base).getUnsignedInt(zcu) orelse return null;
const struct_ty = Value.fromInterned(field.base).typeOf(zcu).childType(zcu);
- if (strat == .sema) {
- const pt = strat.pt(zcu, tid);
- try struct_ty.resolveLayout(pt);
- }
return base_addr + struct_ty.structFieldOffset(@intCast(field.index), zcu) + ptr.byte_offset;
},
else => null,
},
.opt => |opt| switch (opt.val) {
.none => 0,
- else => |payload| Value.fromInterned(payload).getUnsignedIntInner(strat, zcu, tid),
+ else => |payload| Value.fromInterned(payload).getUnsignedInt(zcu),
},
- .enum_tag => |enum_tag| return Value.fromInterned(enum_tag.int).getUnsignedIntInner(strat, zcu, tid),
+ .enum_tag => |enum_tag| Value.fromInterned(enum_tag.int).getUnsignedInt(zcu),
+ .bitpack => |bitpack| Value.fromInterned(bitpack.backing_int_val).getUnsignedInt(zcu),
+ .err => |err| zcu.intern_pool.getErrorValueIfExists(err.name).?,
else => null,
},
};
}
-/// Asserts the value is an integer and it fits in a u64
-pub fn toUnsignedIntSema(val: Value, pt: Zcu.PerThread) !u64 {
- return (try getUnsignedIntInner(val, .sema, pt.zcu, pt.tid)).?;
-}
-
/// Asserts the value is an integer and it fits in a i64
pub fn toSignedInt(val: Value, zcu: *const Zcu) i64 {
return switch (val.toIntern()) {
@@ -314,8 +234,6 @@ pub fn toSignedInt(val: Value, zcu: *const Zcu) i64 {
.big_int => |big_int| big_int.toInt(i64) catch unreachable,
.i64 => |x| x,
.u64 => |x| @intCast(x),
- .lazy_align => |ty| @intCast(Type.fromInterned(ty).abiAlignment(zcu).toByteUnits() orelse 0),
- .lazy_size => |ty| @intCast(Type.fromInterned(ty).abiSize(zcu)),
},
else => unreachable,
},
@@ -393,7 +311,7 @@ pub fn writeToMemory(val: Value, pt: Zcu.PerThread, buffer: []u8) error{
// We use byte_count instead of abi_size here, so that any padding bytes
// follow the data bytes, on both big- and little-endian systems.
const byte_count = (@as(usize, @intCast(ty.bitSize(zcu))) + 7) / 8;
- return writeToPackedMemory(val, ty, pt, buffer[0..byte_count], 0);
+ return writeToPackedMemory(val, pt, buffer[0..byte_count], 0);
},
.@"struct" => {
const struct_type = zcu.typeToStruct(ty) orelse return error.IllDefinedMemoryLayout;
@@ -412,8 +330,8 @@ pub fn writeToMemory(val: Value, pt: Zcu.PerThread, buffer: []u8) error{
try writeToMemory(field_val, pt, buffer[off..]);
},
.@"packed" => {
- const byte_count = (@as(usize, @intCast(ty.bitSize(zcu))) + 7) / 8;
- return writeToPackedMemory(val, ty, pt, buffer[0..byte_count], 0);
+ const int_index = ip.indexToKey(val.toIntern()).bitpack.backing_int_val;
+ return Value.fromInterned(int_index).writeToMemory(pt, buffer);
},
}
},
@@ -428,15 +346,14 @@ pub fn writeToMemory(val: Value, pt: Zcu.PerThread, buffer: []u8) error{
const byte_count: usize = @intCast(field_type.abiSize(zcu));
return writeToMemory(field_val, pt, buffer[0..byte_count]);
} else {
- const backing_ty = try ty.unionBackingType(pt);
+ const backing_ty = try ty.externUnionBackingType(pt);
const byte_count: usize = @intCast(backing_ty.abiSize(zcu));
- return writeToMemory(val.unionValue(zcu), pt, buffer[0..byte_count]);
+ return writeToMemory(val.unionPayload(zcu), pt, buffer[0..byte_count]);
}
},
.@"packed" => {
- const backing_ty = try ty.unionBackingType(pt);
- const byte_count: usize = @intCast(backing_ty.abiSize(zcu));
- return writeToPackedMemory(val, ty, pt, buffer[0..byte_count], 0);
+ const int_val: Value = .fromInterned(ip.indexToKey(val.toIntern()).bitpack.backing_int_val);
+ return writeToMemory(int_val, pt, buffer);
},
},
.optional => {
@@ -458,7 +375,6 @@ pub fn writeToMemory(val: Value, pt: Zcu.PerThread, buffer: []u8) error{
/// big-endian packed memory layouts start at the end of the buffer.
pub fn writeToPackedMemory(
val: Value,
- ty: Type,
pt: Zcu.PerThread,
buffer: []u8,
bit_offset: usize,
@@ -467,6 +383,7 @@ pub fn writeToPackedMemory(
const ip = &zcu.intern_pool;
const target = zcu.getTarget();
const endian = target.cpu.arch.endian();
+ const ty = val.typeOf(zcu);
if (val.isUndef(zcu)) {
const bit_size: usize = @intCast(ty.bitSize(zcu));
if (bit_size != 0) {
@@ -487,22 +404,22 @@ pub fn writeToPackedMemory(
buffer[byte_index] &= ~(@as(u8, 1) << @as(u3, @intCast(bit_offset % 8)));
}
},
- .int, .@"enum" => {
- if (buffer.len == 0) return;
+ .@"enum" => {
+ const int_val = val.intFromEnum(zcu);
+ return int_val.writeToPackedMemory(pt, buffer, bit_offset);
+ },
+ .pointer => {
+ assert(!ty.isSlice(zcu)); // No well defined layout.
+ if (ip.getBackingAddrTag(val.toIntern()).? != .int) return error.ReinterpretDeclRef;
+ const addr = val.toUnsignedInt(zcu);
+ std.mem.writeVarPackedInt(buffer, bit_offset, zcu.getTarget().ptrBitWidth(), addr, endian);
+ },
+ .int => {
const bits = ty.intInfo(zcu).bits;
- if (bits == 0) return;
-
- switch (ip.indexToKey((try val.intFromEnum(ty, pt)).toIntern()).int.storage) {
+ if (bits == 0 or buffer.len == 0) return;
+ switch (ip.indexToKey(val.toIntern()).int.storage) {
inline .u64, .i64 => |int| std.mem.writeVarPackedInt(buffer, bit_offset, bits, int, endian),
.big_int => |bigint| bigint.writePackedTwosComplement(buffer, bit_offset, bits, endian),
- .lazy_align => |lazy_align| {
- const num = Type.fromInterned(lazy_align).abiAlignment(zcu).toByteUnits() orelse 0;
- std.mem.writeVarPackedInt(buffer, bit_offset, bits, num, endian);
- },
- .lazy_size => |lazy_size| {
- const num = Type.fromInterned(lazy_size).abiSize(zcu);
- std.mem.writeVarPackedInt(buffer, bit_offset, bits, num, endian);
- },
}
},
.float => switch (ty.floatBits(target)) {
@@ -524,58 +441,21 @@ pub fn writeToPackedMemory(
// On big-endian systems, LLVM reverses the element order of vectors by default
const tgt_elem_i = if (endian == .big) len - elem_i - 1 else elem_i;
const elem_val = try val.elemValue(pt, tgt_elem_i);
- try elem_val.writeToPackedMemory(elem_ty, pt, buffer, bit_offset + bits);
+ try elem_val.writeToPackedMemory(pt, buffer, bit_offset + bits);
bits += elem_bit_size;
}
},
- .@"struct" => {
- const struct_type = ip.loadStructType(ty.toIntern());
- // Sema is supposed to have emitted a compile error already in the case of Auto,
- // and Extern is handled in non-packed writeToMemory.
- assert(struct_type.layout == .@"packed");
- var bits: u16 = 0;
- for (0..struct_type.field_types.len) |i| {
- const field_val = Value.fromInterned(switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
- .bytes => unreachable,
- .elems => |elems| elems[i],
- .repeated_elem => |elem| elem,
- });
- const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);
- const field_bits: u16 = @intCast(field_ty.bitSize(zcu));
- try field_val.writeToPackedMemory(field_ty, pt, buffer, bit_offset + bits);
- bits += field_bits;
- }
- },
- .@"union" => {
- const union_obj = zcu.typeToUnion(ty).?;
- switch (union_obj.flagsUnordered(ip).layout) {
- .auto, .@"extern" => unreachable, // Handled in non-packed writeToMemory
- .@"packed" => {
- if (val.unionTag(zcu)) |union_tag| {
- const field_index = zcu.unionTagFieldIndex(union_obj, union_tag).?;
- const field_type = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
- const field_val = try val.fieldValue(pt, field_index);
- return field_val.writeToPackedMemory(field_type, pt, buffer, bit_offset);
- } else {
- const backing_ty = try ty.unionBackingType(pt);
- return val.unionValue(zcu).writeToPackedMemory(backing_ty, pt, buffer, bit_offset);
- }
- },
- }
- },
- .pointer => {
- assert(!ty.isSlice(zcu)); // No well defined layout.
- if (ip.getBackingAddrTag(val.toIntern()).? != .int) return error.ReinterpretDeclRef;
- return val.writeToPackedMemory(Type.usize, pt, buffer, bit_offset);
+ .@"struct", .@"union" => {
+ assert(ty.containerLayout(zcu) == .@"packed");
+ const int_val: Value = .fromInterned(ip.indexToKey(val.toIntern()).bitpack.backing_int_val);
+ return int_val.writeToPackedMemory(pt, buffer, bit_offset);
},
.optional => {
assert(ty.isPtrLikeOptional(zcu));
- const child = ty.optionalChild(zcu);
- const opt_val = val.optionalValue(zcu);
- if (opt_val) |some| {
- return some.writeToPackedMemory(child, pt, buffer, bit_offset);
+ if (val.optionalValue(zcu)) |ptr_val| {
+ return ptr_val.writeToPackedMemory(pt, buffer, bit_offset);
} else {
- return writeToPackedMemory(try pt.intValue(Type.usize, 0), Type.usize, pt, buffer, bit_offset);
+ return Value.zero_usize.writeToPackedMemory(pt, buffer, bit_offset);
}
},
else => @panic("TODO implement writeToPackedMemory for more types"),
@@ -625,13 +505,12 @@ pub fn readFromPackedMemory(
pt: Zcu.PerThread,
buffer: []const u8,
bit_offset: usize,
- arena: Allocator,
+ gpa: Allocator,
) error{
IllDefinedMemoryLayout,
OutOfMemory,
}!Value {
const zcu = pt.zcu;
- const ip = &zcu.intern_pool;
const target = zcu.getTarget();
const endian = target.cpu.arch.endian();
switch (ty.zigTypeTag(zcu)) {
@@ -665,7 +544,8 @@ pub fn readFromPackedMemory(
const abi_size: usize = @intCast(ty.abiSize(zcu));
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);
+ const limbs_buffer = try gpa.alloc(Limb, limb_count);
+ defer gpa.free(limbs_buffer);
var bigint = BigIntMutable.init(limbs_buffer, 0);
bigint.readPackedTwosComplement(buffer, bit_offset, bits, endian, int_info.signedness);
@@ -673,7 +553,7 @@ pub fn readFromPackedMemory(
},
.@"enum" => {
const int_ty = ty.intTagType(zcu);
- const int_val = try Value.readFromPackedMemory(int_ty, pt, buffer, bit_offset, arena);
+ const int_val = try Value.readFromPackedMemory(int_ty, pt, buffer, bit_offset, gpa);
return pt.getCoerced(int_val, ty);
},
.float => return Value.fromInterned(try pt.intern(.{ .float = .{
@@ -689,64 +569,35 @@ pub fn readFromPackedMemory(
} })),
.vector => {
const elem_ty = ty.childType(zcu);
- const elems = try arena.alloc(InternPool.Index, @intCast(ty.arrayLen(zcu)));
+ const elems = try gpa.alloc(InternPool.Index, @intCast(ty.arrayLen(zcu)));
+ defer gpa.free(elems);
var bits: u16 = 0;
const elem_bit_size: u16 = @intCast(elem_ty.bitSize(zcu));
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;
- elems[tgt_elem_i] = (try readFromPackedMemory(elem_ty, pt, buffer, bit_offset + bits, arena)).toIntern();
+ elems[tgt_elem_i] = (try readFromPackedMemory(elem_ty, pt, buffer, bit_offset + bits, gpa)).toIntern();
bits += elem_bit_size;
}
return pt.aggregateValue(ty, elems);
},
- .@"struct" => {
- // Sema is supposed to have emitted a compile error already for Auto layout structs,
- // and Extern is handled by non-packed readFromMemory.
- const struct_type = zcu.typeToPackedStruct(ty).?;
- var bits: u16 = 0;
- const field_vals = try arena.alloc(InternPool.Index, struct_type.field_types.len);
- for (field_vals, 0..) |*field_val, i| {
- const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);
- const field_bits: u16 = @intCast(field_ty.bitSize(zcu));
- field_val.* = (try readFromPackedMemory(field_ty, pt, buffer, bit_offset + bits, arena)).toIntern();
- bits += field_bits;
- }
- return pt.aggregateValue(ty, field_vals);
- },
- .@"union" => switch (ty.containerLayout(zcu)) {
- .auto, .@"extern" => unreachable, // Handled by non-packed readFromMemory
- .@"packed" => {
- const backing_ty = try ty.unionBackingType(pt);
- const val = (try readFromPackedMemory(backing_ty, pt, buffer, bit_offset, arena)).toIntern();
- return Value.fromInterned(try pt.internUnion(.{
- .ty = ty.toIntern(),
- .tag = .none,
- .val = val,
- }));
- },
+ .@"struct", .@"union" => {
+ assert(ty.containerLayout(zcu) == .@"packed");
+ const int_val: Value = try .readFromPackedMemory(ty.bitpackBackingInt(zcu), pt, buffer, bit_offset, gpa);
+ return pt.bitpackValue(ty, int_val);
},
.pointer => {
assert(!ty.isSlice(zcu)); // No well defined layout.
- const int_val = try readFromPackedMemory(Type.usize, pt, buffer, bit_offset, arena);
- return Value.fromInterned(try pt.intern(.{ .ptr = .{
- .ty = ty.toIntern(),
- .base_addr = .int,
- .byte_offset = int_val.toUnsignedInt(zcu),
- } }));
+ const addr = (try readFromPackedMemory(Type.usize, pt, buffer, bit_offset, gpa)).toUnsignedInt(zcu);
+ return pt.ptrIntValue(ty, addr);
},
.optional => {
assert(ty.isPtrLikeOptional(zcu));
- const child_ty = ty.optionalChild(zcu);
- const child_val = try readFromPackedMemory(child_ty, pt, buffer, bit_offset, arena);
- return Value.fromInterned(try pt.intern(.{ .opt = .{
+ const addr = (try readFromPackedMemory(Type.usize, pt, buffer, bit_offset, gpa)).toUnsignedInt(zcu);
+ return .fromInterned(try pt.intern(.{ .opt = .{
.ty = ty.toIntern(),
- .val = switch (child_val.orderAgainstZero(zcu)) {
- .lt => unreachable,
- .eq => .none,
- .gt => child_val.toIntern(),
- },
+ .val = if (addr == 0) .none else (try pt.ptrIntValue(ty.childType(zcu), addr)).toIntern(),
} }));
},
else => @panic("TODO implement readFromPackedMemory for more types"),
@@ -764,8 +615,6 @@ pub fn toFloat(val: Value, comptime T: type, zcu: *const Zcu) T {
}
return @floatFromInt(x);
},
- .lazy_align => |ty| @floatFromInt(Type.fromInterned(ty).abiAlignment(zcu).toByteUnits() orelse 0),
- .lazy_size => |ty| @floatFromInt(Type.fromInterned(ty).abiSize(zcu)),
},
.float => |float| switch (float.storage) {
inline else => |x| @floatCast(x),
@@ -819,110 +668,8 @@ pub fn floatCast(val: Value, dest_ty: Type, pt: Zcu.PerThread) !Value {
} }));
}
-pub fn orderAgainstZero(lhs: Value, zcu: *Zcu) std.math.Order {
- return orderAgainstZeroInner(lhs, .normal, zcu, {}) catch unreachable;
-}
-
-pub fn orderAgainstZeroSema(lhs: Value, pt: Zcu.PerThread) !std.math.Order {
- return try orderAgainstZeroInner(lhs, .sema, pt.zcu, pt.tid);
-}
-
-pub fn orderAgainstZeroInner(
- lhs: Value,
- comptime strat: ResolveStrat,
- zcu: *Zcu,
- tid: strat.Tid(),
-) Zcu.SemaError!std.math.Order {
- return switch (lhs.toIntern()) {
- .bool_false => .eq,
- .bool_true => .gt,
- else => switch (zcu.intern_pool.indexToKey(lhs.toIntern())) {
- .ptr => |ptr| if (ptr.byte_offset > 0) .gt else switch (ptr.base_addr) {
- .nav, .comptime_alloc, .comptime_field => .gt,
- .int => .eq,
- else => unreachable,
- },
- .int => |int| switch (int.storage) {
- .big_int => |big_int| big_int.orderAgainstScalar(0),
- inline .u64, .i64 => |x| std.math.order(x, 0),
- .lazy_align => .gt, // alignment is never 0
- .lazy_size => |ty| return if (Type.fromInterned(ty).hasRuntimeBitsInner(
- false,
- strat.toLazy(),
- zcu,
- tid,
- ) catch |err| switch (err) {
- error.NeedLazy => unreachable,
- else => |e| return e,
- }) .gt else .eq,
- },
- .enum_tag => |enum_tag| Value.fromInterned(enum_tag.int).orderAgainstZeroInner(strat, zcu, tid),
- .float => |float| switch (float.storage) {
- inline else => |x| std.math.order(x, 0),
- },
- .err => .gt, // error values cannot be 0
- else => unreachable,
- },
- };
-}
-
-/// Asserts the value is comparable.
-pub fn order(lhs: Value, rhs: Value, zcu: *Zcu) std.math.Order {
- return orderAdvanced(lhs, rhs, .normal, zcu, {}) catch unreachable;
-}
-
-/// Asserts the value is comparable.
-pub fn orderAdvanced(
- lhs: Value,
- rhs: Value,
- comptime strat: ResolveStrat,
- zcu: *Zcu,
- tid: strat.Tid(),
-) !std.math.Order {
- const lhs_against_zero = try lhs.orderAgainstZeroInner(strat, zcu, tid);
- const rhs_against_zero = try rhs.orderAgainstZeroInner(strat, zcu, tid);
- switch (lhs_against_zero) {
- .lt => if (rhs_against_zero != .lt) return .lt,
- .eq => return rhs_against_zero.invert(),
- .gt => {},
- }
- switch (rhs_against_zero) {
- .lt => if (lhs_against_zero != .lt) return .gt,
- .eq => return lhs_against_zero,
- .gt => {},
- }
-
- if (lhs.isFloat(zcu) or rhs.isFloat(zcu)) {
- const lhs_f128 = lhs.toFloat(f128, zcu);
- const rhs_f128 = rhs.toFloat(f128, zcu);
- return std.math.order(lhs_f128, rhs_f128);
- }
-
- var lhs_bigint_space: BigIntSpace = undefined;
- var rhs_bigint_space: BigIntSpace = undefined;
- const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_bigint_space, strat, zcu, tid);
- const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_bigint_space, strat, zcu, tid);
- return lhs_bigint.order(rhs_bigint);
-}
-
-/// Asserts the value is comparable. Does not take a type parameter because it supports
-/// comparisons between heterogeneous types.
-pub fn compareHetero(lhs: Value, op: std.math.CompareOperator, rhs: Value, zcu: *Zcu) bool {
- return compareHeteroAdvanced(lhs, op, rhs, .normal, zcu, {}) catch unreachable;
-}
-
-pub fn compareHeteroSema(lhs: Value, op: std.math.CompareOperator, rhs: Value, pt: Zcu.PerThread) !bool {
- return try compareHeteroAdvanced(lhs, op, rhs, .sema, pt.zcu, pt.tid);
-}
-
-pub fn compareHeteroAdvanced(
- lhs: Value,
- op: std.math.CompareOperator,
- rhs: Value,
- comptime strat: ResolveStrat,
- zcu: *Zcu,
- tid: strat.Tid(),
-) !bool {
+/// Asserts the value is comparable. Supports comparisons between heterogeneous types.
+pub fn compareHetero(lhs: Value, op: std.math.CompareOperator, rhs: Value, zcu: *const Zcu) bool {
if (lhs.pointerNav(zcu)) |lhs_nav| {
if (rhs.pointerNav(zcu)) |rhs_nav| {
switch (op) {
@@ -944,9 +691,21 @@ pub fn compareHeteroAdvanced(
else => {},
}
}
-
if (lhs.isNan(zcu) or rhs.isNan(zcu)) return op == .neq;
- return (try orderAdvanced(lhs, rhs, strat, zcu, tid)).compare(op);
+ return order(lhs, rhs, zcu).compare(op);
+}
+
+pub fn order(lhs: Value, rhs: Value, zcu: *const Zcu) std.math.Order {
+ if (lhs.isFloat(zcu) or rhs.isFloat(zcu)) {
+ const lhs_f128 = lhs.toFloat(f128, zcu);
+ const rhs_f128 = rhs.toFloat(f128, zcu);
+ return std.math.order(lhs_f128, rhs_f128);
+ }
+ var lhs_bigint_space: BigIntSpace = undefined;
+ var rhs_bigint_space: BigIntSpace = undefined;
+ const lhs_bigint = lhs.toBigInt(&lhs_bigint_space, zcu);
+ const rhs_bigint = rhs.toBigInt(&rhs_bigint_space, zcu);
+ return lhs_bigint.order(rhs_bigint);
}
/// Asserts the values are comparable. Both operands have type `ty`.
@@ -988,55 +747,30 @@ pub fn compareScalar(
///
/// Note that `!compareAllWithZero(.eq, ...) != compareAllWithZero(.neq, ...)`
pub fn compareAllWithZero(lhs: Value, op: std.math.CompareOperator, zcu: *Zcu) bool {
- return compareAllWithZeroAdvancedExtra(lhs, op, .normal, zcu, {}) catch unreachable;
-}
-
-pub fn compareAllWithZeroSema(
- lhs: Value,
- op: std.math.CompareOperator,
- pt: Zcu.PerThread,
-) Zcu.CompileError!bool {
- return compareAllWithZeroAdvancedExtra(lhs, op, .sema, pt.zcu, pt.tid);
-}
-
-pub fn compareAllWithZeroAdvancedExtra(
- lhs: Value,
- op: std.math.CompareOperator,
- comptime strat: ResolveStrat,
- zcu: *Zcu,
- tid: strat.Tid(),
-) Zcu.CompileError!bool {
- if (lhs.isInf(zcu)) {
- switch (op) {
- .neq => return true,
- .eq => return false,
- .gt, .gte => return !lhs.isNegativeInf(zcu),
- .lt, .lte => return lhs.isNegativeInf(zcu),
- }
- }
-
- switch (zcu.intern_pool.indexToKey(lhs.toIntern())) {
+ return switch (zcu.intern_pool.indexToKey(lhs.toIntern())) {
.float => |float| switch (float.storage) {
- inline else => |x| if (std.math.isNan(x)) return op == .neq,
+ inline else => |x| std.math.compare(x, op, 0),
},
- .aggregate => |aggregate| return switch (aggregate.storage) {
- .bytes => |bytes| for (bytes.toSlice(lhs.typeOf(zcu).arrayLenIncludingSentinel(zcu), &zcu.intern_pool)) |byte| {
- if (!std.math.order(byte, 0).compare(op)) break false;
+ .aggregate => |aggregate| switch (aggregate.storage) {
+ .bytes => |bytes| for (bytes.toSlice(
+ lhs.typeOf(zcu).arrayLenIncludingSentinel(zcu),
+ &zcu.intern_pool,
+ )) |byte| {
+ if (!std.math.compare(byte, op, 0)) break false;
} else true,
.elems => |elems| for (elems) |elem| {
- if (!try Value.fromInterned(elem).compareAllWithZeroAdvancedExtra(op, strat, zcu, tid)) break false;
+ if (!Value.fromInterned(elem).compareAllWithZero(op, zcu)) break false;
} else true,
- .repeated_elem => |elem| Value.fromInterned(elem).compareAllWithZeroAdvancedExtra(op, strat, zcu, tid),
+ .repeated_elem => |elem| Value.fromInterned(elem).compareAllWithZero(op, zcu),
},
- .undef => return false,
- else => {},
- }
- return (try orderAgainstZeroInner(lhs, strat, zcu, tid)).compare(op);
+ .undef => false,
+ else => order(lhs, .zero_comptime_int, zcu).compare(op),
+ };
}
pub fn eql(a: Value, b: Value, ty: Type, zcu: *Zcu) bool {
- assert(zcu.intern_pool.typeOf(a.toIntern()) == ty.toIntern());
- assert(zcu.intern_pool.typeOf(b.toIntern()) == ty.toIntern());
+ assert(a.typeOf(zcu).toIntern() == ty.toIntern());
+ assert(b.typeOf(zcu).toIntern() == ty.toIntern());
return a.toIntern() == b.toIntern();
}
@@ -1071,7 +805,7 @@ pub fn canMutateComptimeVarState(val: Value, zcu: *Zcu) bool {
/// Gets the `Nav` referenced by this pointer. If the pointer does not point
/// to a `Nav`, or if it points to some part of one (like a field or element),
/// returns null.
-pub fn pointerNav(val: Value, zcu: *Zcu) ?InternPool.Nav.Index {
+pub fn pointerNav(val: Value, zcu: *const Zcu) ?InternPool.Nav.Index {
return switch (zcu.intern_pool.indexToKey(val.toIntern())) {
// TODO: these 3 cases are weird; these aren't pointer values!
.variable => |v| v.owner_nav,
@@ -1088,16 +822,13 @@ pub fn pointerNav(val: Value, zcu: *Zcu) ?InternPool.Nav.Index {
pub const slice_ptr_index = 0;
pub const slice_len_index = 1;
+pub fn sliceLen(val: Value, zcu: *Zcu) u64 {
+ return Value.fromInterned(zcu.intern_pool.sliceLen(val.toIntern())).toUnsignedInt(zcu);
+}
pub fn slicePtr(val: Value, zcu: *Zcu) Value {
return Value.fromInterned(zcu.intern_pool.slicePtr(val.toIntern()));
}
-/// Gets the `len` field of a slice value as a `u64`.
-/// Resolves the length using `Sema` if necessary.
-pub fn sliceLen(val: Value, pt: Zcu.PerThread) !u64 {
- return Value.fromInterned(pt.zcu.intern_pool.sliceLen(val.toIntern())).toUnsignedIntSema(pt);
-}
-
/// Asserts the value is an aggregate, and returns the element value at the given index.
pub fn elemValue(val: Value, pt: Zcu.PerThread, index: usize) Allocator.Error!Value {
const zcu = pt.zcu;
@@ -1123,62 +854,6 @@ pub fn elemValue(val: Value, pt: Zcu.PerThread, index: usize) Allocator.Error!Va
}
}
-pub fn isLazyAlign(val: Value, zcu: *Zcu) bool {
- return switch (zcu.intern_pool.indexToKey(val.toIntern())) {
- .int => |int| int.storage == .lazy_align,
- else => false,
- };
-}
-
-pub fn isLazySize(val: Value, zcu: *Zcu) bool {
- return switch (zcu.intern_pool.indexToKey(val.toIntern())) {
- .int => |int| int.storage == .lazy_size,
- else => false,
- };
-}
-
-// Asserts that the provided start/end are in-bounds.
-pub fn sliceArray(
- val: Value,
- sema: *Sema,
- start: usize,
- end: usize,
-) error{OutOfMemory}!Value {
- const pt = sema.pt;
- const ip = &pt.zcu.intern_pool;
- const io = pt.zcu.comp.io;
- return Value.fromInterned(try pt.intern(.{
- .aggregate = .{
- .ty = switch (pt.zcu.intern_pool.indexToKey(pt.zcu.intern_pool.typeOf(val.toIntern()))) {
- .array_type => |array_type| try pt.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 pt.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,
- io,
- 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, pt: Zcu.PerThread, index: usize) !Value {
const zcu = pt.zcu;
return switch (zcu.intern_pool.indexToKey(val.toIntern())) {
@@ -1193,8 +868,44 @@ pub fn fieldValue(val: Value, pt: Zcu.PerThread, index: usize) !Value {
.elems => |elems| elems[index],
.repeated_elem => |elem| elem,
}),
- // TODO assert the tag is correct
- .un => |un| Value.fromInterned(un.val),
+ .un => |un| {
+ switch (Type.fromInterned(un.ty).containerLayout(zcu)) {
+ .auto, .@"extern" => {}, // TODO assert the tag is correct
+ .@"packed" => unreachable,
+ }
+ return .fromInterned(un.val);
+ },
+ .bitpack => |bitpack| {
+ const ty: Type = .fromInterned(bitpack.ty);
+ assert(ty.containerLayout(zcu) == .@"packed");
+ const int_val: Value = .fromInterned(bitpack.backing_int_val);
+ assert(!int_val.isUndef(zcu));
+ const field_ty = ty.fieldType(index, zcu);
+ const field_bit_offset: u16 = switch (ty.zigTypeTag(zcu)) {
+ .@"union" => 0,
+ .@"struct" => off: {
+ var off: u16 = 0;
+ for (0..index) |preceding_field_index| {
+ off += @intCast(ty.fieldType(preceding_field_index, zcu).bitSize(zcu));
+ }
+ break :off off;
+ },
+ else => unreachable,
+ };
+ // Avoid hitting gpa for accesses to small packed structs
+ var sfba_state = std.heap.stackFallback(128, zcu.comp.gpa);
+ const sfba = sfba_state.get();
+ const buf = try sfba.alloc(u8, @intCast((ty.bitSize(zcu) + 7) / 8));
+ defer sfba.free(buf);
+ int_val.writeToPackedMemory(pt, buf, 0) catch |err| switch (err) {
+ error.ReinterpretDeclRef => unreachable, // it's an integer
+ error.OutOfMemory => |e| return e,
+ };
+ return Value.readFromPackedMemory(field_ty, pt, buf, field_bit_offset, sfba) catch |err| switch (err) {
+ error.IllDefinedMemoryLayout => unreachable, // it's a bitpack
+ error.OutOfMemory => |e| return e,
+ };
+ },
else => unreachable,
};
}
@@ -1207,7 +918,7 @@ pub fn unionTag(val: Value, zcu: *Zcu) ?Value {
};
}
-pub fn unionValue(val: Value, zcu: *Zcu) Value {
+pub fn unionPayload(val: Value, zcu: *Zcu) Value {
return switch (zcu.intern_pool.indexToKey(val.toIntern())) {
.un => |un| Value.fromInterned(un.val),
else => unreachable,
@@ -1334,63 +1045,6 @@ pub fn isFloat(self: Value, zcu: *const Zcu) bool {
};
}
-pub fn floatFromInt(val: Value, arena: Allocator, int_ty: Type, float_ty: Type, zcu: *Zcu) !Value {
- return floatFromIntAdvanced(val, arena, int_ty, float_ty, zcu, .normal) catch |err| switch (err) {
- error.OutOfMemory => return error.OutOfMemory,
- else => unreachable,
- };
-}
-
-pub fn floatFromIntAdvanced(
- val: Value,
- arena: Allocator,
- int_ty: Type,
- float_ty: Type,
- pt: Zcu.PerThread,
- comptime strat: ResolveStrat,
-) !Value {
- const zcu = pt.zcu;
- if (int_ty.zigTypeTag(zcu) == .vector) {
- const result_data = try arena.alloc(InternPool.Index, int_ty.vectorLen(zcu));
- const scalar_ty = float_ty.scalarType(zcu);
- for (result_data, 0..) |*scalar, i| {
- const elem_val = try val.elemValue(pt, i);
- scalar.* = (try floatFromIntScalar(elem_val, scalar_ty, pt, strat)).toIntern();
- }
- return pt.aggregateValue(float_ty, result_data);
- }
- return floatFromIntScalar(val, float_ty, pt, strat);
-}
-
-pub fn floatFromIntScalar(val: Value, float_ty: Type, pt: Zcu.PerThread, comptime strat: ResolveStrat) !Value {
- return switch (pt.zcu.intern_pool.indexToKey(val.toIntern())) {
- .undef => try pt.undefValue(float_ty),
- .int => |int| switch (int.storage) {
- .big_int => |big_int| pt.floatValue(float_ty, big_int.toFloat(f128, .nearest_even)[0]),
- inline .u64, .i64 => |x| floatFromIntInner(x, float_ty, pt),
- .lazy_align => |ty| floatFromIntInner((try Type.fromInterned(ty).abiAlignmentInner(strat.toLazy(), pt.zcu, pt.tid)).scalar.toByteUnits() orelse 0, float_ty, pt),
- .lazy_size => |ty| floatFromIntInner((try Type.fromInterned(ty).abiSizeInner(strat.toLazy(), pt.zcu, pt.tid)).scalar, float_ty, pt),
- },
- else => unreachable,
- };
-}
-
-fn floatFromIntInner(x: anytype, dest_ty: Type, pt: Zcu.PerThread) !Value {
- const target = pt.zcu.getTarget();
- const storage: InternPool.Key.Float.Storage = switch (dest_ty.floatBits(target)) {
- 16 => .{ .f16 = @floatFromInt(x) },
- 32 => .{ .f32 = @floatFromInt(x) },
- 64 => .{ .f64 = @floatFromInt(x) },
- 80 => .{ .f80 = @floatFromInt(x) },
- 128 => .{ .f128 = @floatFromInt(x) },
- else => unreachable,
- };
- return Value.fromInterned(try pt.intern(.{ .float = .{
- .ty = dest_ty.toIntern(),
- .storage = storage,
- } }));
-}
-
fn calcLimbLenFloat(scalar: anytype) usize {
if (scalar == 0) {
return 1;
@@ -1410,11 +1064,11 @@ pub fn numberMax(lhs: Value, rhs: Value, zcu: *Zcu) Value {
if (lhs.isUndef(zcu) or rhs.isUndef(zcu)) return undef;
if (lhs.isNan(zcu)) return rhs;
if (rhs.isNan(zcu)) return lhs;
-
- return switch (order(lhs, rhs, zcu)) {
- .lt => rhs,
- .gt, .eq => lhs,
- };
+ if (compareHetero(lhs, .gt, rhs, zcu)) {
+ return lhs;
+ } else {
+ return rhs;
+ }
}
/// Supports both floats and ints; handles undefined.
@@ -1422,11 +1076,11 @@ pub fn numberMin(lhs: Value, rhs: Value, zcu: *Zcu) Value {
if (lhs.isUndef(zcu) or rhs.isUndef(zcu)) return undef;
if (lhs.isNan(zcu)) return rhs;
if (rhs.isNan(zcu)) return lhs;
-
- return switch (order(lhs, rhs, zcu)) {
- .lt => lhs,
- .gt, .eq => rhs,
- };
+ if (compareHetero(lhs, .lt, rhs, zcu)) {
+ return lhs;
+ } else {
+ return rhs;
+ }
}
/// Returns true if the value is a floating point type and is NaN. Returns false otherwise.
@@ -2033,8 +1687,6 @@ pub fn makeBool(x: bool) Value {
/// `parent_ptr` must be a single-pointer or C pointer to some optional.
///
/// Returns a pointer to the payload of the optional.
-///
-/// May perform type resolution.
pub fn ptrOptPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {
const zcu = pt.zcu;
const parent_ptr_ty = parent_ptr.typeOf(zcu);
@@ -2044,7 +1696,7 @@ pub fn ptrOptPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {
assert(ptr_size == .one or ptr_size == .c);
assert(opt_ty.zigTypeTag(zcu) == .optional);
- const result_ty = try pt.ptrTypeSema(info: {
+ const result_ty = try pt.ptrType(info: {
var new = parent_ptr_ty.ptrInfo(zcu);
// We can correctly preserve alignment `.none`, since an optional has the same
// natural alignment as its child type.
@@ -2060,7 +1712,7 @@ pub fn ptrOptPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {
}
const base_ptr = try parent_ptr.canonicalizeBasePtr(.one, opt_ty, pt);
- return Value.fromInterned(try pt.intern(.{ .ptr = .{
+ return .fromInterned(try pt.intern(.{ .ptr = .{
.ty = result_ty.toIntern(),
.base_addr = .{ .opt_payload = base_ptr.toIntern() },
.byte_offset = 0,
@@ -2069,7 +1721,6 @@ pub fn ptrOptPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {
/// `parent_ptr` must be a single-pointer to some error union.
/// Returns a pointer to the payload of the error union.
-/// May perform type resolution.
pub fn ptrEuPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {
const zcu = pt.zcu;
const parent_ptr_ty = parent_ptr.typeOf(zcu);
@@ -2078,7 +1729,7 @@ pub fn ptrEuPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {
assert(parent_ptr_ty.ptrSize(zcu) == .one);
assert(eu_ty.zigTypeTag(zcu) == .error_union);
- const result_ty = try pt.ptrTypeSema(info: {
+ const result_ty = try pt.ptrType(info: {
var new = parent_ptr_ty.ptrInfo(zcu);
// We can correctly preserve alignment `.none`, since an error union has a
// natural alignment greater than or equal to that of its payload type.
@@ -2089,147 +1740,57 @@ pub fn ptrEuPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {
if (parent_ptr.isUndef(zcu)) return pt.undefValue(result_ty);
const base_ptr = try parent_ptr.canonicalizeBasePtr(.one, eu_ty, pt);
- return Value.fromInterned(try pt.intern(.{ .ptr = .{
+ return .fromInterned(try pt.intern(.{ .ptr = .{
.ty = result_ty.toIntern(),
.base_addr = .{ .eu_payload = base_ptr.toIntern() },
.byte_offset = 0,
} }));
}
-/// `parent_ptr` must be a single-pointer or c pointer to a struct, union, or slice.
+/// `parent_ptr` must be a single-item pointer or C pointer to a struct, union, or slice.
///
/// Returns a pointer to the aggregate field at the specified index.
///
/// For slices, uses `slice_ptr_index` and `slice_len_index`.
///
-/// May perform type resolution.
+/// Asserts that the layout of the aggregate type is resolved.
pub fn ptrField(parent_ptr: Value, field_idx: u32, pt: Zcu.PerThread) !Value {
const zcu = pt.zcu;
const parent_ptr_ty = parent_ptr.typeOf(zcu);
const aggregate_ty = parent_ptr_ty.childType(zcu);
+ aggregate_ty.assertHasLayout(zcu);
const parent_ptr_info = parent_ptr_ty.ptrInfo(zcu);
assert(parent_ptr_info.flags.size == .one or parent_ptr_info.flags.size == .c);
- // Exiting this `switch` indicates that the `field` pointer representation should be used.
- // `field_align` may be `.none` to represent the natural alignment of `field_ty`, but is not necessarily.
- const field_ty: Type, const field_align: InternPool.Alignment = switch (aggregate_ty.zigTypeTag(zcu)) {
- .@"struct" => field: {
- const field_ty = aggregate_ty.fieldType(field_idx, zcu);
- switch (aggregate_ty.containerLayout(zcu)) {
- .auto => break :field .{ field_ty, try aggregate_ty.fieldAlignmentSema(field_idx, pt) },
- .@"extern" => {
- // Well-defined layout, so just offset the pointer appropriately.
- try aggregate_ty.resolveLayout(pt);
- const byte_off = aggregate_ty.structFieldOffset(field_idx, zcu);
- const field_align = a: {
- const parent_align = if (parent_ptr_info.flags.alignment == .none) pa: {
- break :pa try aggregate_ty.abiAlignmentSema(pt);
- } else parent_ptr_info.flags.alignment;
- break :a InternPool.Alignment.fromLog2Units(@min(parent_align.toLog2Units(), @ctz(byte_off)));
- };
- const result_ty = try pt.ptrTypeSema(info: {
- var new = parent_ptr_info;
- new.child = field_ty.toIntern();
- new.flags.alignment = field_align;
- break :info new;
- });
- return parent_ptr.getOffsetPtr(byte_off, result_ty, pt);
- },
- .@"packed" => {
- const packed_offset = aggregate_ty.packedStructFieldPtrInfo(parent_ptr_ty, field_idx, pt);
- const result_ty = try pt.ptrType(info: {
- var new = parent_ptr_info;
- new.packed_offset = packed_offset;
- new.child = field_ty.toIntern();
- if (new.flags.alignment == .none) {
- new.flags.alignment = try aggregate_ty.abiAlignmentSema(pt);
- }
- break :info new;
- });
- return pt.getCoerced(parent_ptr, result_ty);
- },
- }
+ const field_ptr_ty = try parent_ptr_ty.fieldPtrType(field_idx, pt);
+
+ switch (aggregate_ty.zigTypeTag(zcu)) {
+ .pointer => assert(aggregate_ty.isSlice(zcu)),
+ .@"struct" => switch (aggregate_ty.containerLayout(zcu)) {
+ .auto => {},
+ .@"extern" => return parent_ptr.getOffsetPtr(
+ aggregate_ty.structFieldOffset(field_idx, zcu),
+ field_ptr_ty,
+ pt,
+ ),
+ .@"packed" => return pt.getCoerced(parent_ptr, field_ptr_ty),
},
- .@"union" => field: {
- const union_obj = zcu.typeToUnion(aggregate_ty).?;
- const field_ty = Type.fromInterned(union_obj.field_types.get(&zcu.intern_pool)[field_idx]);
- switch (aggregate_ty.containerLayout(zcu)) {
- .auto => break :field .{ field_ty, try aggregate_ty.fieldAlignmentSema(field_idx, pt) },
- .@"extern" => {
- // Point to the same address.
- const result_ty = try pt.ptrTypeSema(info: {
- var new = parent_ptr_info;
- new.child = field_ty.toIntern();
- break :info new;
- });
- return pt.getCoerced(parent_ptr, result_ty);
- },
- .@"packed" => {
- // If the field has an ABI size matching its bit size, then we can continue to use a
- // non-bit pointer if the parent pointer is also a non-bit pointer.
- if (parent_ptr_info.packed_offset.host_size == 0 and (try field_ty.abiSizeInner(.sema, zcu, pt.tid)).scalar * 8 == try field_ty.bitSizeSema(pt)) {
- // We must offset the pointer on big-endian targets, since the bits of packed memory don't align nicely.
- const byte_offset = switch (zcu.getTarget().cpu.arch.endian()) {
- .little => 0,
- .big => (try aggregate_ty.abiSizeInner(.sema, zcu, pt.tid)).scalar - (try field_ty.abiSizeInner(.sema, zcu, pt.tid)).scalar,
- };
- const result_ty = try pt.ptrTypeSema(info: {
- var new = parent_ptr_info;
- new.child = field_ty.toIntern();
- new.flags.alignment = InternPool.Alignment.fromLog2Units(
- @ctz(byte_offset | (try parent_ptr_ty.ptrAlignmentSema(pt)).toByteUnits().?),
- );
- break :info new;
- });
- return parent_ptr.getOffsetPtr(byte_offset, result_ty, pt);
- } else {
- // The result must be a bit-pointer if it is not already.
- const result_ty = try pt.ptrTypeSema(info: {
- var new = parent_ptr_info;
- new.child = field_ty.toIntern();
- if (new.packed_offset.host_size == 0) {
- new.packed_offset.host_size = @intCast(((try aggregate_ty.bitSizeSema(pt)) + 7) / 8);
- assert(new.packed_offset.bit_offset == 0);
- }
- break :info new;
- });
- return pt.getCoerced(parent_ptr, result_ty);
- }
- },
- }
- },
- .pointer => field_ty: {
- assert(aggregate_ty.isSlice(zcu));
- break :field_ty switch (field_idx) {
- Value.slice_ptr_index => .{ aggregate_ty.slicePtrFieldType(zcu), Type.usize.abiAlignment(zcu) },
- Value.slice_len_index => .{ Type.usize, Type.usize.abiAlignment(zcu) },
- else => unreachable,
- };
+ .@"union" => switch (aggregate_ty.containerLayout(zcu)) {
+ .auto => {},
+ .@"packed", .@"extern" => return pt.getCoerced(parent_ptr, field_ptr_ty),
},
else => unreachable,
- };
+ }
- const new_align: InternPool.Alignment = if (parent_ptr_info.flags.alignment != .none) a: {
- const ty_align = (try field_ty.abiAlignmentInner(.sema, zcu, pt.tid)).scalar;
- const true_field_align = if (field_align == .none) ty_align else field_align;
- const new_align = true_field_align.min(parent_ptr_info.flags.alignment);
- if (new_align == ty_align) break :a .none;
- break :a new_align;
- } else field_align;
+ // If we get here, we need to use the `.field` comptime pointer representation, because the
+ // aggregate does not have a well-defined layout.
- const result_ty = try pt.ptrTypeSema(info: {
- var new = parent_ptr_info;
- new.child = field_ty.toIntern();
- new.flags.alignment = new_align;
- break :info new;
- });
-
- if (parent_ptr.isUndef(zcu)) return pt.undefValue(result_ty);
+ if (parent_ptr.isUndef(zcu)) return pt.undefValue(field_ptr_ty);
const base_ptr = try parent_ptr.canonicalizeBasePtr(.one, aggregate_ty, pt);
- return Value.fromInterned(try pt.intern(.{ .ptr = .{
- .ty = result_ty.toIntern(),
+ return .fromInterned(try pt.intern(.{ .ptr = .{
+ .ty = field_ptr_ty.toIntern(),
.base_addr = .{ .field = .{
.base = base_ptr.toIntern(),
.index = field_idx,
@@ -2238,9 +1799,9 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, pt: Zcu.PerThread) !Value {
} }));
}
-/// `orig_parent_ptr` must be either a single-pointer to an array or vector, or a many-pointer or C-pointer or slice.
+/// `orig_parent_ptr` must be either a single-pointer to an array, a slice, a many-item pointer, or a C pointer.
/// Returns a pointer to the element at the specified index.
-/// May perform type resolution.
+/// Asserts that the layout of the pointer element type is resolved.
pub fn ptrElem(orig_parent_ptr: Value, field_idx: u64, pt: Zcu.PerThread) !Value {
const zcu = pt.zcu;
const parent_ptr = switch (orig_parent_ptr.typeOf(zcu).ptrSize(zcu)) {
@@ -2249,79 +1810,50 @@ pub fn ptrElem(orig_parent_ptr: Value, field_idx: u64, pt: Zcu.PerThread) !Value
};
const parent_ptr_ty = parent_ptr.typeOf(zcu);
- const elem_ty = parent_ptr_ty.childType(zcu);
- const result_ty = try parent_ptr_ty.elemPtrType(@intCast(field_idx), pt);
+ const result_ty = try parent_ptr_ty.elemPtrType(field_idx, pt);
+ const elem_ty = result_ty.childType(zcu);
+ elem_ty.assertHasLayout(zcu);
if (parent_ptr.isUndef(zcu)) return pt.undefValue(result_ty);
- if (result_ty.ptrInfo(zcu).packed_offset.host_size != 0) {
- // Since we have a bit-pointer, the pointer address should be unchanged.
- assert(elem_ty.zigTypeTag(zcu) == .vector);
+ if (!elem_ty.comptimeOnly(zcu)) {
+ const byte_offset = field_idx * elem_ty.abiSize(zcu);
+ return parent_ptr.getOffsetPtr(byte_offset, result_ty, pt);
+ }
+
+ // Comptime-only element type.
+
+ if (field_idx == 0) {
return pt.getCoerced(parent_ptr, result_ty);
}
- const PtrStrat = union(enum) {
- offset: u64,
- elem_ptr: Type, // many-ptr elem ty
- };
-
- const strat: PtrStrat = switch (parent_ptr_ty.ptrSize(zcu)) {
- .one => switch (elem_ty.zigTypeTag(zcu)) {
- .vector => .{ .offset = field_idx * @divExact(try elem_ty.childType(zcu).bitSizeSema(pt), 8) },
- .array => strat: {
- const arr_elem_ty = elem_ty.childType(zcu);
- if (try arr_elem_ty.comptimeOnlySema(pt)) {
- break :strat .{ .elem_ptr = arr_elem_ty };
- }
- break :strat .{ .offset = field_idx * (try arr_elem_ty.abiSizeInner(.sema, zcu, pt.tid)).scalar };
- },
- else => unreachable,
- },
-
- .many, .c => if (try elem_ty.comptimeOnlySema(pt))
- .{ .elem_ptr = elem_ty }
- else
- .{ .offset = field_idx * (try elem_ty.abiSizeInner(.sema, zcu, pt.tid)).scalar },
-
- .slice => unreachable,
- };
-
- switch (strat) {
- .offset => |byte_offset| {
- return parent_ptr.getOffsetPtr(byte_offset, result_ty, pt);
- },
- .elem_ptr => |manyptr_elem_ty| if (field_idx == 0) {
- return pt.getCoerced(parent_ptr, result_ty);
- } else {
- const arr_base_ty, const arr_base_len = manyptr_elem_ty.arrayBase(zcu);
- const base_idx = arr_base_len * field_idx;
- const parent_info = zcu.intern_pool.indexToKey(parent_ptr.toIntern()).ptr;
- switch (parent_info.base_addr) {
- .arr_elem => |arr_elem| {
- if (Value.fromInterned(arr_elem.base).typeOf(zcu).childType(zcu).toIntern() == arr_base_ty.toIntern()) {
- // We already have a pointer to an element of an array of this type.
- // Just modify the index.
- return Value.fromInterned(try pt.intern(.{ .ptr = ptr: {
- var new = parent_info;
- new.base_addr.arr_elem.index += base_idx;
- new.ty = result_ty.toIntern();
- break :ptr new;
- } }));
- }
- },
- else => {},
+ const arr_base_ty, const arr_base_len = elem_ty.arrayBase(zcu);
+ const base_idx = arr_base_len * field_idx;
+ const parent_info = zcu.intern_pool.indexToKey(parent_ptr.toIntern()).ptr;
+ switch (parent_info.base_addr) {
+ .arr_elem => |arr_elem| {
+ if (Value.fromInterned(arr_elem.base).typeOf(zcu).childType(zcu).toIntern() == arr_base_ty.toIntern()) {
+ // We already have a pointer to an element of an array of this type.
+ // Just modify the index.
+ return .fromInterned(try pt.intern(.{ .ptr = ptr: {
+ var new = parent_info;
+ new.base_addr.arr_elem.index += base_idx;
+ new.ty = result_ty.toIntern();
+ break :ptr new;
+ } }));
}
- const base_ptr = try parent_ptr.canonicalizeBasePtr(.many, arr_base_ty, pt);
- return Value.fromInterned(try pt.intern(.{ .ptr = .{
- .ty = result_ty.toIntern(),
- .base_addr = .{ .arr_elem = .{
- .base = base_ptr.toIntern(),
- .index = base_idx,
- } },
- .byte_offset = 0,
- } }));
},
+ else => {},
}
+ const base_ptr = try parent_ptr.canonicalizeBasePtr(.many, arr_base_ty, pt);
+ return .fromInterned(try pt.intern(.{ .ptr = .{
+ .ty = result_ty.toIntern(),
+ .base_addr = .{ .arr_elem = .{
+ .base = base_ptr.toIntern(),
+ .index = base_idx,
+ } },
+ .byte_offset = 0,
+ } }));
}
fn canonicalizeBasePtr(base_ptr: Value, want_size: std.builtin.Type.Pointer.Size, want_child: Type, pt: Zcu.PerThread) !Value {
@@ -2417,19 +1949,11 @@ pub const PointerDeriveStep = union(enum) {
}
};
-pub fn pointerDerivation(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread) Allocator.Error!PointerDeriveStep {
- return ptr_val.pointerDerivationAdvanced(arena, pt, false, null) catch |err| switch (err) {
- error.OutOfMemory => |e| return e,
- error.Canceled => @panic("TODO"), // pls remove from error set mlugg
- error.AnalysisFail => unreachable,
- };
-}
-
/// Given a pointer value, get the sequence of steps to derive it, ideally by taking
/// only field and element pointers with no casts. This can be used by codegen backends
/// which prefer field/elem accesses when lowering constant pointer values.
/// It is also used by the Value printing logic for pointers.
-pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread, comptime resolve_types: bool, opt_sema: ?*Sema) !PointerDeriveStep {
+pub fn pointerDerivation(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread, opt_sema: ?*Sema) Allocator.Error!PointerDeriveStep {
const zcu = pt.zcu;
const ptr = zcu.intern_pool.indexToKey(ptr_val.toIntern()).ptr;
const base_derive: PointerDeriveStep = switch (ptr.base_addr) {
@@ -2454,7 +1978,7 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
.comptime_alloc => |idx| base: {
const sema = opt_sema.?;
const alloc = sema.getComptimeAlloc(idx);
- const val = try alloc.val.intern(pt, sema.arena);
+ const val = try alloc.val.intern(pt, arena);
const ty = val.typeOf(zcu);
break :base .{ .comptime_alloc_ptr = .{
.idx = idx,
@@ -2472,7 +1996,7 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
const base_ptr = Value.fromInterned(eu_ptr);
const base_ptr_ty = base_ptr.typeOf(zcu);
const parent_step = try arena.create(PointerDeriveStep);
- parent_step.* = try pointerDerivationAdvanced(Value.fromInterned(eu_ptr), arena, pt, resolve_types, opt_sema);
+ parent_step.* = try pointerDerivation(.fromInterned(eu_ptr), arena, pt, opt_sema);
break :base .{ .eu_payload_ptr = .{
.parent = parent_step,
.result_ptr_ty = try pt.adjustPtrTypeChild(base_ptr_ty, base_ptr_ty.childType(zcu).errorUnionPayload(zcu)),
@@ -2482,7 +2006,7 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
const base_ptr = Value.fromInterned(opt_ptr);
const base_ptr_ty = base_ptr.typeOf(zcu);
const parent_step = try arena.create(PointerDeriveStep);
- parent_step.* = try pointerDerivationAdvanced(Value.fromInterned(opt_ptr), arena, pt, resolve_types, opt_sema);
+ parent_step.* = try pointerDerivation(.fromInterned(opt_ptr), arena, pt, opt_sema);
break :base .{ .opt_payload_ptr = .{
.parent = parent_step,
.result_ptr_ty = try pt.adjustPtrTypeChild(base_ptr_ty, base_ptr_ty.childType(zcu).optionalChild(zcu)),
@@ -2490,59 +2014,32 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
},
.field => |field| base: {
const base_ptr = Value.fromInterned(field.base);
- const base_ptr_ty = base_ptr.typeOf(zcu);
- const agg_ty = base_ptr_ty.childType(zcu);
- const field_ty, const field_align = switch (agg_ty.zigTypeTag(zcu)) {
- .@"struct" => .{ agg_ty.fieldType(@intCast(field.index), zcu), try agg_ty.fieldAlignmentInner(
- @intCast(field.index),
- if (resolve_types) .sema else .normal,
- pt.zcu,
- if (resolve_types) pt.tid else {},
- ) },
- .@"union" => .{ agg_ty.unionFieldTypeByIndex(@intCast(field.index), zcu), try agg_ty.fieldAlignmentInner(
- @intCast(field.index),
- if (resolve_types) .sema else .normal,
- pt.zcu,
- if (resolve_types) pt.tid else {},
- ) },
- .pointer => .{ switch (field.index) {
- Value.slice_ptr_index => agg_ty.slicePtrFieldType(zcu),
- Value.slice_len_index => Type.usize,
- else => unreachable,
- }, Type.usize.abiAlignment(zcu) },
- else => unreachable,
- };
- const base_align = base_ptr_ty.ptrAlignment(zcu);
- const result_align = field_align.minStrict(base_align);
- const result_ty = try pt.ptrType(.{
- .child = field_ty.toIntern(),
- .flags = flags: {
- var flags = base_ptr_ty.ptrInfo(zcu).flags;
- if (result_align == field_ty.abiAlignment(zcu)) {
- flags.alignment = .none;
- } else {
- flags.alignment = result_align;
- }
- break :flags flags;
- },
+ const base_ptr_ty = try pt.ptrType(info: {
+ var info = base_ptr.typeOf(zcu).ptrInfo(zcu);
+ info.flags.size = .one;
+ break :info info;
});
const parent_step = try arena.create(PointerDeriveStep);
- parent_step.* = try pointerDerivationAdvanced(base_ptr, arena, pt, resolve_types, opt_sema);
+ parent_step.* = try pointerDerivation(base_ptr, arena, pt, opt_sema);
break :base .{ .field_ptr = .{
.parent = parent_step,
.field_idx = @intCast(field.index),
- .result_ptr_ty = result_ty,
+ .result_ptr_ty = try base_ptr_ty.fieldPtrType(@intCast(field.index), pt),
} };
},
.arr_elem => |arr_elem| base: {
const parent_step = try arena.create(PointerDeriveStep);
- parent_step.* = try pointerDerivationAdvanced(Value.fromInterned(arr_elem.base), arena, pt, resolve_types, opt_sema);
+ parent_step.* = try pointerDerivation(.fromInterned(arr_elem.base), arena, pt, opt_sema);
const parent_ptr_info = (try parent_step.ptrType(pt)).ptrInfo(zcu);
const result_ptr_ty = try pt.ptrType(.{
.child = parent_ptr_info.child,
.flags = flags: {
var flags = parent_ptr_info.flags;
flags.size = .one;
+ if (flags.alignment != .none) flags.alignment = .minStrict(
+ flags.alignment,
+ Type.fromInterned(parent_ptr_info.child).abiAlignment(zcu),
+ );
break :flags flags;
},
});
@@ -2560,7 +2057,7 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
const ptr_ty_info = Type.fromInterned(ptr.ty).ptrInfo(zcu);
const need_child: Type = .fromInterned(ptr_ty_info.child);
- if (need_child.comptimeOnly(zcu)) {
+ if (need_child.comptimeOnly(zcu) or need_child.zigTypeTag(zcu) == .@"opaque") {
// No refinement can happen - this pointer is presumably invalid.
// Just offset it.
const parent = try arena.create(PointerDeriveStep);
@@ -2662,27 +2159,17 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
const start_off = cur_ty.structFieldOffset(field_idx, zcu);
const end_off = start_off + field_ty.abiSize(zcu);
if (cur_offset >= start_off and cur_offset + need_bytes <= end_off) {
- const old_ptr_ty = try cur_derive.ptrType(pt);
- const parent_align = old_ptr_ty.ptrAlignment(zcu);
- const field_align = InternPool.Alignment.fromLog2Units(@min(parent_align.toLog2Units(), @ctz(start_off)));
+ const base_ptr_ty = try pt.ptrType(info: {
+ var info = (try cur_derive.ptrType(pt)).ptrInfo(zcu);
+ info.flags.size = .one;
+ break :info info;
+ });
const parent = try arena.create(PointerDeriveStep);
parent.* = cur_derive;
- const new_ptr_ty = try pt.ptrType(.{
- .child = field_ty.toIntern(),
- .flags = flags: {
- var flags = old_ptr_ty.ptrInfo(zcu).flags;
- if (field_align == field_ty.abiAlignment(zcu)) {
- flags.alignment = .none;
- } else {
- flags.alignment = field_align;
- }
- break :flags flags;
- },
- });
cur_derive = .{ .field_ptr = .{
.parent = parent,
.field_idx = @intCast(field_idx),
- .result_ptr_ty = new_ptr_ty,
+ .result_ptr_ty = try base_ptr_ty.fieldPtrType(@intCast(field_idx), pt),
} };
cur_offset -= start_off;
break;
@@ -2720,148 +2207,6 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
} };
}
-pub fn resolveLazy(
- val: Value,
- arena: Allocator,
- pt: Zcu.PerThread,
-) Zcu.SemaError!Value {
- switch (pt.zcu.intern_pool.indexToKey(val.toIntern())) {
- .int => |int| switch (int.storage) {
- .u64, .i64, .big_int => return val,
- .lazy_align, .lazy_size => return pt.intValue(
- Type.fromInterned(int.ty),
- try val.toUnsignedIntSema(pt),
- ),
- },
- .slice => |slice| {
- const ptr = try Value.fromInterned(slice.ptr).resolveLazy(arena, pt);
- const len = try Value.fromInterned(slice.len).resolveLazy(arena, pt);
- if (ptr.toIntern() == slice.ptr and len.toIntern() == slice.len) return val;
- return Value.fromInterned(try pt.intern(.{ .slice = .{
- .ty = slice.ty,
- .ptr = ptr.toIntern(),
- .len = len.toIntern(),
- } }));
- },
- .ptr => |ptr| {
- switch (ptr.base_addr) {
- .nav, .comptime_alloc, .uav, .int => return val,
- .comptime_field => |field_val| {
- const resolved_field_val = (try Value.fromInterned(field_val).resolveLazy(arena, pt)).toIntern();
- return if (resolved_field_val == field_val)
- val
- else
- Value.fromInterned(try pt.intern(.{ .ptr = .{
- .ty = ptr.ty,
- .base_addr = .{ .comptime_field = resolved_field_val },
- .byte_offset = ptr.byte_offset,
- } }));
- },
- .eu_payload, .opt_payload => |base| {
- const resolved_base = (try Value.fromInterned(base).resolveLazy(arena, pt)).toIntern();
- return if (resolved_base == base)
- val
- else
- Value.fromInterned(try pt.intern(.{ .ptr = .{
- .ty = ptr.ty,
- .base_addr = switch (ptr.base_addr) {
- .eu_payload => .{ .eu_payload = resolved_base },
- .opt_payload => .{ .opt_payload = resolved_base },
- else => unreachable,
- },
- .byte_offset = ptr.byte_offset,
- } }));
- },
- .arr_elem, .field => |base_index| {
- const resolved_base = (try Value.fromInterned(base_index.base).resolveLazy(arena, pt)).toIntern();
- return if (resolved_base == base_index.base)
- val
- else
- Value.fromInterned(try pt.intern(.{ .ptr = .{
- .ty = ptr.ty,
- .base_addr = switch (ptr.base_addr) {
- .arr_elem => .{ .arr_elem = .{
- .base = resolved_base,
- .index = base_index.index,
- } },
- .field => .{ .field = .{
- .base = resolved_base,
- .index = base_index.index,
- } },
- else => unreachable,
- },
- .byte_offset = ptr.byte_offset,
- } }));
- },
- }
- },
- .aggregate => |aggregate| switch (aggregate.storage) {
- .bytes => return val,
- .elems => |elems| {
- var resolved_elems: []InternPool.Index = &.{};
- for (elems, 0..) |elem, i| {
- const resolved_elem = (try Value.fromInterned(elem).resolveLazy(arena, pt)).toIntern();
- if (resolved_elems.len == 0 and resolved_elem != elem) {
- resolved_elems = try arena.alloc(InternPool.Index, elems.len);
- @memcpy(resolved_elems[0..i], elems[0..i]);
- }
- if (resolved_elems.len > 0) resolved_elems[i] = resolved_elem;
- }
- return if (resolved_elems.len == 0)
- val
- else
- pt.aggregateValue(.fromInterned(aggregate.ty), resolved_elems);
- },
- .repeated_elem => |elem| {
- const resolved_elem = try Value.fromInterned(elem).resolveLazy(arena, pt);
- return if (resolved_elem.toIntern() == elem)
- val
- else
- pt.aggregateSplatValue(.fromInterned(aggregate.ty), resolved_elem);
- },
- },
- .un => |un| {
- const resolved_tag = if (un.tag == .none)
- .none
- else
- (try Value.fromInterned(un.tag).resolveLazy(arena, pt)).toIntern();
- const resolved_val = (try Value.fromInterned(un.val).resolveLazy(arena, pt)).toIntern();
- return if (resolved_tag == un.tag and resolved_val == un.val)
- val
- else
- Value.fromInterned(try pt.internUnion(.{
- .ty = un.ty,
- .tag = resolved_tag,
- .val = resolved_val,
- }));
- },
- .error_union => |eu| switch (eu.val) {
- .err_name => return val,
- .payload => |payload| {
- const resolved_payload = try Value.fromInterned(payload).resolveLazy(arena, pt);
- if (resolved_payload.toIntern() == payload) return val;
- return .fromInterned(try pt.intern(.{ .error_union = .{
- .ty = eu.ty,
- .val = .{ .payload = resolved_payload.toIntern() },
- } }));
- },
- },
- .opt => |opt| switch (opt.val) {
- .none => return val,
- else => |payload| {
- const resolved_payload = try Value.fromInterned(payload).resolveLazy(arena, pt);
- if (resolved_payload.toIntern() == payload) return val;
- return .fromInterned(try pt.intern(.{ .opt = .{
- .ty = opt.ty,
- .val = resolved_payload.toIntern(),
- } }));
- },
- },
-
- else => return val,
- }
-}
-
const InterpretMode = enum {
/// In this mode, types are assumed to match what the compiler was built with in terms of field
/// order, field types, etc. This improves compiler performance. However, it means that certain
@@ -2878,7 +2223,6 @@ const interpret_mode: InterpretMode = @field(InterpretMode, @tagName(build_optio
/// Given a `Value` representing a comptime-known value of type `T`, unwrap it into an actual `T` known to the compiler.
/// This is useful for accessing `std.builtin` structures received from comptime logic.
-/// `val` must be fully resolved.
pub fn interpret(val: Value, comptime T: type, pt: Zcu.PerThread) error{ OutOfMemory, UndefinedValue, TypeMismatch }!T {
const zcu = pt.zcu;
const io = zcu.comp.io;
@@ -2917,7 +2261,6 @@ pub fn interpret(val: Value, comptime T: type, pt: Zcu.PerThread) error{ OutOfMe
},
.int => switch (ip.indexToKey(val.toIntern()).int.storage) {
- .lazy_align, .lazy_size => unreachable, // `val` is fully resolved
inline .u64, .i64 => |x| std.math.cast(T, x) orelse return error.TypeMismatch,
.big_int => |big| big.toInt(T) catch return error.TypeMismatch,
},
@@ -2949,7 +2292,7 @@ pub fn interpret(val: Value, comptime T: type, pt: Zcu.PerThread) error{ OutOfMe
inline else => |tag_comptime| @unionInit(
T,
@tagName(tag_comptime),
- try val.unionValue(zcu).interpret(@FieldType(T, @tagName(tag_comptime)), pt),
+ try val.unionPayload(zcu).interpret(@FieldType(T, @tagName(tag_comptime)), pt),
),
};
},
@@ -3076,7 +2419,7 @@ pub fn uninterpret(val: anytype, ty: Type, pt: Zcu.PerThread) error{ OutOfMemory
}
for (field_vals, 0..) |*field_val, field_idx| {
if (field_val.* == .none) {
- const default_init = struct_obj.field_inits.get(ip)[field_idx];
+ const default_init = struct_obj.field_defaults.get(ip)[field_idx];
if (default_init == .none) return error.TypeMismatch;
field_val.* = default_init;
}
@@ -3092,8 +2435,8 @@ pub fn uninterpret(val: anytype, ty: Type, pt: Zcu.PerThread) error{ OutOfMemory
pub fn doPointersOverlap(ptr_val_a: Value, ptr_val_b: Value, elem_count: u64, zcu: *const Zcu) bool {
const ip = &zcu.intern_pool;
- const a_elem_ty = ptr_val_a.typeOf(zcu).indexablePtrElem(zcu);
- const b_elem_ty = ptr_val_b.typeOf(zcu).indexablePtrElem(zcu);
+ const a_elem_ty = ptr_val_a.typeOf(zcu).indexableElem(zcu);
+ const b_elem_ty = ptr_val_b.typeOf(zcu).indexableElem(zcu);
const a_ptr = ip.indexToKey(ptr_val_a.toIntern()).ptr;
const b_ptr = ip.indexToKey(ptr_val_b.toIntern()).ptr;
@@ -3179,3 +2522,58 @@ pub fn eqlScalarNum(lhs: Value, rhs: Value, zcu: *Zcu) bool {
const rhs_bigint = rhs.toBigInt(&rhs_bigint_space, zcu);
return lhs_bigint.eql(rhs_bigint);
}
+
+/// Asserts the value is an integer, and the destination type is ComptimeInt or Int.
+/// Vectors are also accepted. Vector results are reduced with AND.
+///
+/// If provided, `vector_index` reports the first element that failed the range check.
+pub fn intFitsInType(
+ val: Value,
+ ty: Type,
+ vector_index: ?*usize,
+ zcu: *const Zcu,
+) bool {
+ if (ty.toIntern() == .comptime_int_type) return true;
+ const info = ty.intInfo(zcu);
+ switch (val.toIntern()) {
+ .zero_usize, .zero_u8 => return true,
+ else => switch (zcu.intern_pool.indexToKey(val.toIntern())) {
+ .undef => return true,
+ .variable, .@"extern", .func, .ptr => {
+ const target = zcu.getTarget();
+ const ptr_bits = target.ptrBitWidth();
+ return switch (info.signedness) {
+ .signed => info.bits > ptr_bits,
+ .unsigned => info.bits >= ptr_bits,
+ };
+ },
+ .int => |int| {
+ var buffer: InternPool.Key.Int.Storage.BigIntSpace = undefined;
+ const big_int = int.storage.toBigInt(&buffer);
+ return big_int.fitsInTwosComp(info.signedness, info.bits);
+ },
+ .aggregate => |aggregate| {
+ assert(ty.zigTypeTag(zcu) == .vector);
+ return switch (aggregate.storage) {
+ .bytes => |bytes| for (bytes.toSlice(ty.vectorLen(zcu), &zcu.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;
+ if (vector_index) |vi| vi.* = i;
+ break false;
+ } else true,
+ .elems, .repeated_elem => for (switch (aggregate.storage) {
+ .bytes => unreachable,
+ .elems => |elems| elems,
+ .repeated_elem => |elem| @as(*const [1]InternPool.Index, &elem),
+ }, 0..) |elem, i| {
+ if (Value.fromInterned(elem).intFitsInType(ty.scalarType(zcu), null, zcu)) continue;
+ if (vector_index) |vi| vi.* = i;
+ break false;
+ } else true,
+ };
+ },
+ else => unreachable,
+ },
+ }
+}
diff --git a/src/Zcu.zig b/src/Zcu.zig
index f2d6dbf497a1f47faef87d208c082c364867bb9e..0ab053b696e8a63de410bb15310ada4e80cd5e38 100644
--- a/src/Zcu.zig
+++ b/src/Zcu.zig
@@ -14,6 +14,8 @@ const mem = std.mem;
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const log = std.log.scoped(.zcu);
+const deps_log = std.log.scoped(.zcu_deps);
+const refs_log = std.log.scoped(.zcu_refs);
const BigIntConst = std.math.big.int.Const;
const BigIntMutable = std.math.big.int.Mutable;
const Target = std.Target;
@@ -117,7 +119,7 @@ module_roots: std.AutoArrayHashMapUnmanaged(*Package.Module, File.Index.Optional
///
/// Always accessed through `ImportTableAdapter`, where keys are fully resolved
/// file paths in order to ensure files are properly deduplicated. This table owns
-/// the keys and values.
+/// the keysand values.
///
/// Protected by Compilation's mutex.
///
@@ -175,7 +177,9 @@ embed_table: std.ArrayHashMapUnmanaged(
/// is not yet implemented.
intern_pool: InternPool = .empty,
-analysis_in_progress: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .empty,
+/// Value explains why this `AnalUnit` is being analyzed. It is `null` for the topmost analysis
+/// (index 0), and non-`null` for all others.
+analysis_in_progress: std.AutoArrayHashMapUnmanaged(AnalUnit, ?*const DependencyReason) = .empty,
/// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator.
failed_analysis: std.AutoArrayHashMapUnmanaged(AnalUnit, *ErrorMsg) = .empty,
/// This `AnalUnit` failed semantic analysis because it required analysis of another `AnalUnit` which itself failed.
@@ -187,6 +191,19 @@ transitive_failed_analysis: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .emp
/// codegen and linking run on a separate thread.
failed_codegen: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, *ErrorMsg) = .empty,
failed_types: std.AutoArrayHashMapUnmanaged(InternPool.Index, *ErrorMsg) = .empty,
+
+/// Key is an `AnalUnit` which is in `dependency_loop_nodes`. For each dependency loop, exactly one
+/// unit in the loop is in this map, though the choice is arbitrary and not necessarily reproducible
+/// between compilations. So, instead of (for instance) defining where the dependency loop "starts",
+/// this map simply exists to allow easily iterating all dependency loops exactly once.
+dependency_loops: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .empty,
+/// Key is an `AnalUnit`, value is the `AnalUnit` which the key references and why it does so.
+/// All units in here form loops. To iterate loops, see `dependency_loops`.
+dependency_loop_nodes: std.AutoArrayHashMapUnmanaged(AnalUnit, struct {
+ unit: AnalUnit,
+ reason: DependencyReason,
+}) = .empty,
+
/// Keep track of `@compileLog`s per `AnalUnit`.
/// We track the source location of the first `@compileLog` call, and all logged lines as a linked list.
/// The list is singly linked, but we do track its tail for fast appends (optimizing many logs in one unit).
@@ -247,6 +264,10 @@ cimport_errors: std.AutoArrayHashMapUnmanaged(AnalUnit, std.zig.ErrorBundle) = .
/// Maximum amount of distinct error values, set by --error-limit
error_limit: ErrorInt,
+/// In safe builds, `Type.assertHasLayout` may be called cross-thread, so this lock
+/// guards accesses to `outdated` and `potentially_outdated`. In unsafe builds, the
+/// lock is not needed and is compiled out.
+outdated_lock: if (std.debug.runtime_safety) std.Io.RwLock else void = if (std.debug.runtime_safety) .init,
/// Value is the number of PO dependencies of this AnalUnit.
/// This value will decrease as we perform semantic analysis to learn what is outdated.
/// If any of these PO deps is outdated, this value will be moved to `outdated`.
@@ -254,19 +275,22 @@ potentially_outdated: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .empty,
/// Value is the number of PO dependencies of this AnalUnit.
/// Once this value drops to 0, the AnalUnit is a candidate for re-analysis.
outdated: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .empty,
-/// This contains all `AnalUnit`s in `outdated` whose PO dependency count is 0.
+/// This is the set of all `AnalUnit`s in `outdated` whose PO dependency count is 0.
/// Such `AnalUnit`s are ready for immediate re-analysis.
/// See `findOutdatedToAnalyze` for details.
-outdated_ready: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .empty,
+outdated_ready: struct {
+ /// These are separate from other units because it allows `findOutdatedToAnalyze` to prioritize
+ /// functions, which is useful because it means they will be sent to codegen more quickly.
+ funcs: std.AutoArrayHashMapUnmanaged(InternPool.Index, void),
+ /// Does not contain `.func` units.
+ other: std.AutoArrayHashMapUnmanaged(AnalUnit, void),
+} = .{ .funcs = .empty, .other = .empty },
/// This contains a list of AnalUnit whose analysis or codegen failed, but the
/// failure was something like running out of disk space, and trying again may
/// succeed. On the next update, we will flush this list, marking all members of
/// it as outdated.
retryable_failures: std.ArrayList(AnalUnit) = .empty,
-func_body_analysis_queued: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .empty,
-nav_val_analysis_queued: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void) = .empty,
-
/// These are the modules which we initially queue for analysis in `Compilation.update`.
/// `resolveReferences` will use these as the root of its reachability traversal.
analysis_roots_buffer: [5]*Package.Module,
@@ -322,6 +346,12 @@ codegen_task_pool: CodegenTaskPool,
generation: u32 = 0,
+pub const DependencyReason = struct {
+ src: LazySrcLoc,
+ /// Only populated if this is for a `.type_layout` unit.
+ type_layout_reason: Sema.type_resolution.LayoutResolveReason,
+};
+
pub const IncrementalDebugState = struct {
/// All container types in the ZCU, even dead ones.
/// Value is the generation the type was created on.
@@ -1220,6 +1250,15 @@ pub const ErrorMsg = struct {
notes: []ErrorMsg = &.{},
reference_trace_root: AnalUnit.Optional = .none,
+ pub fn order(lhs: *const ErrorMsg, rhs: *const ErrorMsg, zcu: *Zcu) std.math.Order {
+ return lhs.src_loc.order(rhs.src_loc, zcu).differ() orelse
+ std.mem.order(u8, lhs.msg, rhs.msg).differ() orelse
+ std.math.order(lhs.notes.len, rhs.notes.len).differ() orelse
+ for (lhs.notes, rhs.notes) |*lhs_note, *rhs_note| {
+ if (order(lhs_note, rhs_note, zcu).differ()) |o| break o;
+ } else .eq;
+ }
+
pub fn create(
gpa: Allocator,
src_loc: LazySrcLoc,
@@ -1910,40 +1949,6 @@ pub const SrcLoc = struct {
const full = tree.fullPtrType(parent_node).?;
return tree.nodeToSpan(full.ast.bit_range_end.unwrap().?);
},
- .node_offset_container_tag => |node_off| {
- const tree = try src_loc.file_scope.getTree(zcu);
- const parent_node = node_off.toAbsolute(src_loc.base_node);
-
- switch (tree.nodeTag(parent_node)) {
- .container_decl_arg, .container_decl_arg_trailing => {
- const full = tree.containerDeclArg(parent_node);
- const arg_node = full.ast.arg.unwrap().?;
- return tree.nodeToSpan(arg_node);
- },
- .tagged_union_enum_tag, .tagged_union_enum_tag_trailing => {
- const full = tree.taggedUnionEnumTag(parent_node);
- const arg_node = full.ast.arg.unwrap().?;
-
- return tree.tokensToSpan(
- tree.firstToken(arg_node) - 2,
- tree.lastToken(arg_node) + 1,
- tree.nodeMainToken(arg_node),
- );
- },
- else => unreachable,
- }
- },
- .node_offset_field_default => |node_off| {
- const tree = try src_loc.file_scope.getTree(zcu);
- const parent_node = node_off.toAbsolute(src_loc.base_node);
-
- const full: Ast.full.ContainerField = switch (tree.nodeTag(parent_node)) {
- .container_field => tree.containerField(parent_node),
- .container_field_init => tree.containerFieldInit(parent_node),
- else => unreachable,
- };
- return tree.nodeToSpan(full.ast.value_expr.unwrap().?);
- },
.node_offset_init_ty => |node_off| {
const tree = try src_loc.file_scope.getTree(zcu);
const parent_node = node_off.toAbsolute(src_loc.base_node);
@@ -2019,6 +2024,20 @@ pub const SrcLoc = struct {
}
return tree.nodeToSpan(node);
},
+ .container_arg => {
+ const tree = try src_loc.file_scope.getTree(zcu);
+ const node = src_loc.base_node;
+ var buf: [2]Ast.Node.Index = undefined;
+ if (tree.fullContainerDecl(&buf, node)) |container_decl| {
+ const arg_node = container_decl.ast.arg.unwrap() orelse return tree.nodeToSpan(node);
+ return tree.nodeToSpan(arg_node);
+ } else if (tree.builtinCallParams(&buf, node)) |args| {
+ // Builtin calls (`@Enum` etc) should use the first argument.
+ return tree.nodeToSpan(if (args.len > 0) args[0] else node);
+ } else {
+ return tree.nodeToSpan(node);
+ }
+ },
.container_field_name,
.container_field_value,
.container_field_type,
@@ -2027,8 +2046,38 @@ pub const SrcLoc = struct {
const tree = try src_loc.file_scope.getTree(zcu);
const node = src_loc.base_node;
var buf: [2]Ast.Node.Index = undefined;
- const container_decl = tree.fullContainerDecl(&buf, node) orelse
+ const container_decl = tree.fullContainerDecl(&buf, node) orelse {
+ // This could be a reification builtin. These are the args we care about:
+ // * `@Enum(_, _, names, values)`
+ // * `@Struct(_, _, names, types, values_and_aligns)`
+ // * `@Union(_, _, names, types, aligns)`
+ if (tree.builtinCallParams(&buf, node)) |args| {
+ const builtin_name = tree.tokenSlice(tree.firstToken(node));
+ const arg_index: ?u3 = if (std.mem.eql(u8, builtin_name, "@Enum")) switch (src_loc.lazy) {
+ .container_field_name => 2,
+ .container_field_value => 3,
+ .container_field_type => null,
+ .container_field_align => null,
+ else => unreachable,
+ } else if (std.mem.eql(u8, builtin_name, "@Struct")) switch (src_loc.lazy) {
+ .container_field_name => 2,
+ .container_field_value => 4,
+ .container_field_type => 3,
+ .container_field_align => 4,
+ else => unreachable,
+ } else if (std.mem.eql(u8, builtin_name, "@Union")) switch (src_loc.lazy) {
+ .container_field_name => 2,
+ .container_field_value => 4,
+ .container_field_type => 3,
+ .container_field_align => null,
+ else => unreachable,
+ } else null;
+ if (arg_index) |i| {
+ if (args.len >= i) return tree.nodeToSpan(args[i]);
+ }
+ }
return tree.nodeToSpan(node);
+ };
var cur_field_idx: usize = 0;
for (container_decl.ast.members) |member_node| {
@@ -2260,7 +2309,11 @@ pub const SrcLoc = struct {
var param_it = full.iterate(tree);
for (0..param_idx) |_| assert(param_it.next() != null);
const param = param_it.next().?;
- return tree.nodeToSpan(param.type_expr.?);
+ if (param.anytype_ellipsis3) |tok| {
+ return tree.tokenToSpan(tok);
+ } else {
+ return tree.nodeToSpan(param.type_expr.?);
+ }
},
}
}
@@ -2482,10 +2535,6 @@ pub const LazySrcLoc = struct {
node_offset_ptr_bitoffset: Ast.Node.Offset,
/// The source location points to the host size of a pointer.
node_offset_ptr_hostsize: Ast.Node.Offset,
- /// The source location points to the tag type of an union or an enum.
- node_offset_container_tag: Ast.Node.Offset,
- /// The source location points to the default value of a field.
- node_offset_field_default: Ast.Node.Offset,
/// The source location points to the type of an array or struct initializer.
node_offset_init_ty: Ast.Node.Offset,
/// The source location points to the LHS of an assignment (or assign-op, e.g. `+=`).
@@ -2530,6 +2579,11 @@ pub const LazySrcLoc = struct {
fn_proto_param_type: FnProtoParam,
array_cat_lhs: ArrayCat,
array_cat_rhs: ArrayCat,
+ /// The source location points to the backing or tag type expression of
+ /// the container type declaration at the base node.
+ ///
+ /// For 'union(enum(T))', this points to 'T', not 'enum(T)'.
+ container_arg,
/// The source location points to the name of the field at the given index
/// of the container type declaration at the base node.
container_field_name: u32,
@@ -2685,10 +2739,10 @@ pub const LazySrcLoc = struct {
.struct_init, .struct_init_ref => zir.extraData(Zir.Inst.StructInit, inst.data.pl_node.payload_index).data.abs_node,
.struct_init_anon => zir.extraData(Zir.Inst.StructInitAnon, inst.data.pl_node.payload_index).data.abs_node,
.extended => switch (inst.data.extended.opcode) {
- .struct_decl => zir.extraData(Zir.Inst.StructDecl, inst.data.extended.operand).data.src_node,
- .union_decl => zir.extraData(Zir.Inst.UnionDecl, inst.data.extended.operand).data.src_node,
- .enum_decl => zir.extraData(Zir.Inst.EnumDecl, inst.data.extended.operand).data.src_node,
- .opaque_decl => zir.extraData(Zir.Inst.OpaqueDecl, inst.data.extended.operand).data.src_node,
+ .struct_decl => zir.getStructDecl(zir_inst).src_node,
+ .union_decl => zir.getUnionDecl(zir_inst).src_node,
+ .enum_decl => zir.getEnumDecl(zir_inst).src_node,
+ .opaque_decl => zir.getOpaqueDecl(zir_inst).src_node,
.reify_enum => zir.extraData(Zir.Inst.ReifyEnum, inst.data.extended.operand).data.node,
.reify_struct => zir.extraData(Zir.Inst.ReifyStruct, inst.data.extended.operand).data.node,
.reify_union => zir.extraData(Zir.Inst.ReifyUnion, inst.data.extended.operand).data.node,
@@ -2715,36 +2769,34 @@ pub const LazySrcLoc = struct {
};
}
- /// Used to sort error messages, so that they're printed in a consistent order.
- /// If an error is returned, a file could not be read in order to resolve a source location.
- /// In that case, `bad_file_out` is populated, and sorting is impossible.
- pub fn lessThan(lhs_lazy: LazySrcLoc, rhs_lazy: LazySrcLoc, zcu: *Zcu, bad_file_out: **Zcu.File) File.GetSourceError!bool {
- const lhs_src = lhs_lazy.upgradeOrLost(zcu) orelse {
+ pub fn order(lhs: LazySrcLoc, rhs: LazySrcLoc, zcu: *Zcu) std.math.Order {
+ const lhs_resolved = lhs.upgradeOrLost(zcu) orelse {
// LHS source location lost, so should never be referenced. Just sort it to the end.
- return false;
+ return .gt;
};
- const rhs_src = rhs_lazy.upgradeOrLost(zcu) orelse {
+ const rhs_resolved = rhs.upgradeOrLost(zcu) orelse {
// RHS source location lost, so should never be referenced. Just sort it to the end.
- return true;
+ return .lt;
};
- if (lhs_src.file_scope != rhs_src.file_scope) {
- const lhs_path = lhs_src.file_scope.path;
- const rhs_path = rhs_src.file_scope.path;
- if (lhs_path.root != rhs_path.root) {
- return @intFromEnum(lhs_path.root) < @intFromEnum(rhs_path.root);
- }
- return std.mem.order(u8, lhs_path.sub_path, rhs_path.sub_path).compare(.lt);
+ if (lhs_resolved.file_scope != rhs_resolved.file_scope) {
+ const lhs_path = lhs_resolved.file_scope.path;
+ const rhs_path = rhs_resolved.file_scope.path;
+ return std.math.order(@intFromEnum(lhs_path.root), @intFromEnum(rhs_path.root)).differ() orelse
+ std.mem.order(u8, lhs_path.sub_path, rhs_path.sub_path).differ().?;
}
-
- const lhs_span = lhs_src.span(zcu) catch |err| {
- bad_file_out.* = lhs_src.file_scope;
- return err;
+ const prev_prot = zcu.comp.io.swapCancelProtection(.blocked);
+ defer _ = zcu.comp.io.swapCancelProtection(prev_prot);
+ const lhs_span = lhs_resolved.span(zcu) catch |err| {
+ assert(err != error.Canceled); // we're protected
+ // Failed to read LHS, so we'll get a transient error. Just sort it to the end.
+ return .gt;
};
- const rhs_span = rhs_src.span(zcu) catch |err| {
- bad_file_out.* = rhs_src.file_scope;
- return err;
+ const rhs_span = rhs_resolved.span(zcu) catch |err| {
+ assert(err != error.Canceled); // we're protected
+ // Failed to read RHS, so we'll get a transient error. Just sort it to the end.
+ return .lt;
};
- return lhs_span.main < rhs_span.main;
+ return std.math.order(lhs_span.main, rhs_span.main);
}
};
@@ -2800,6 +2852,8 @@ pub fn deinit(zcu: *Zcu) void {
zcu.analysis_in_progress.deinit(gpa);
zcu.failed_analysis.deinit(gpa);
zcu.transitive_failed_analysis.deinit(gpa);
+ zcu.dependency_loops.deinit(gpa);
+ zcu.dependency_loop_nodes.deinit(gpa);
zcu.failed_codegen.deinit(gpa);
zcu.failed_types.deinit(gpa);
@@ -2830,12 +2884,10 @@ pub fn deinit(zcu: *Zcu) void {
zcu.potentially_outdated.deinit(gpa);
zcu.outdated.deinit(gpa);
- zcu.outdated_ready.deinit(gpa);
+ zcu.outdated_ready.funcs.deinit(gpa);
+ zcu.outdated_ready.other.deinit(gpa);
zcu.retryable_failures.deinit(gpa);
- zcu.func_body_analysis_queued.deinit(gpa);
- zcu.nav_val_analysis_queued.deinit(gpa);
-
zcu.test_functions.deinit(gpa);
for (zcu.global_assembly.values()) |s| {
@@ -3063,18 +3115,24 @@ pub fn markDependeeOutdated(
marked_po: enum { not_marked_po, marked_po },
dependee: InternPool.Dependee,
) !void {
- log.debug("outdated dependee: {f}", .{zcu.fmtDependee(dependee)});
+ const gpa = zcu.comp.gpa;
+ deps_log.debug("outdated dependee: {f}", .{zcu.fmtDependee(dependee)});
var it = zcu.intern_pool.dependencyIterator(dependee);
+ if (std.debug.runtime_safety) zcu.outdated_lock.lockUncancelable(zcu.comp.io);
+ defer if (std.debug.runtime_safety) zcu.outdated_lock.unlock(zcu.comp.io);
while (it.next()) |depender| {
if (zcu.outdated.getPtr(depender)) |po_dep_count| {
switch (marked_po) {
.not_marked_po => {},
.marked_po => {
po_dep_count.* -= 1;
- log.debug("outdated {f} => already outdated {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), po_dep_count.* });
+ deps_log.debug("outdated {f} => already outdated {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), po_dep_count.* });
if (po_dep_count.* == 0) {
- log.debug("outdated ready: {f}", .{zcu.fmtAnalUnit(depender)});
- try zcu.outdated_ready.put(zcu.gpa, depender, {});
+ deps_log.debug("outdated ready: {f}", .{zcu.fmtAnalUnit(depender)});
+ switch (depender.unwrap()) {
+ .func => |func| try zcu.outdated_ready.funcs.put(gpa, func, {}),
+ else => try zcu.outdated_ready.other.put(gpa, depender, {}),
+ }
}
},
}
@@ -3090,14 +3148,17 @@ pub fn markDependeeOutdated(
},
};
try zcu.outdated.putNoClobber(
- zcu.gpa,
+ gpa,
depender,
new_po_dep_count,
);
- log.debug("outdated {f} => new outdated {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), new_po_dep_count });
+ deps_log.debug("outdated {f} => new outdated {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), new_po_dep_count });
if (new_po_dep_count == 0) {
- log.debug("outdated ready: {f}", .{zcu.fmtAnalUnit(depender)});
- try zcu.outdated_ready.put(zcu.gpa, depender, {});
+ deps_log.debug("outdated ready: {f}", .{zcu.fmtAnalUnit(depender)});
+ switch (depender.unwrap()) {
+ .func => |func| try zcu.outdated_ready.funcs.put(gpa, func, {}),
+ else => try zcu.outdated_ready.other.put(gpa, depender, {}),
+ }
}
// If this is a Decl and was not previously PO, we must recursively
// mark dependencies on its tyval as PO.
@@ -3109,17 +3170,27 @@ pub fn markDependeeOutdated(
}
pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
- log.debug("up-to-date dependee: {f}", .{zcu.fmtDependee(dependee)});
+ if (std.debug.runtime_safety) zcu.outdated_lock.lockUncancelable(zcu.comp.io);
+ defer if (std.debug.runtime_safety) zcu.outdated_lock.unlock(zcu.comp.io);
+ return markPoDependeeUpToDateInner(zcu, dependee);
+}
+/// Assumes that `zcu.outdated_lock` is already held exclusively.
+fn markPoDependeeUpToDateInner(zcu: *Zcu, dependee: InternPool.Dependee) !void {
+ const gpa = zcu.comp.gpa;
+ deps_log.debug("up-to-date dependee: {f}", .{zcu.fmtDependee(dependee)});
var it = zcu.intern_pool.dependencyIterator(dependee);
while (it.next()) |depender| {
if (zcu.outdated.getPtr(depender)) |po_dep_count| {
// This depender is already outdated, but it now has one
// less PO dependency!
po_dep_count.* -= 1;
- log.debug("up-to-date {f} => {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), po_dep_count.* });
+ deps_log.debug("up-to-date {f} => {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), po_dep_count.* });
if (po_dep_count.* == 0) {
- log.debug("outdated ready: {f}", .{zcu.fmtAnalUnit(depender)});
- try zcu.outdated_ready.put(zcu.gpa, depender, {});
+ deps_log.debug("outdated ready: {f}", .{zcu.fmtAnalUnit(depender)});
+ switch (depender.unwrap()) {
+ .func => |func| try zcu.outdated_ready.funcs.put(gpa, func, {}),
+ else => try zcu.outdated_ready.other.put(gpa, depender, {}),
+ }
}
continue;
}
@@ -3132,11 +3203,11 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
};
if (ptr.* > 1) {
ptr.* -= 1;
- log.debug("up-to-date {f} => {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), ptr.* });
+ deps_log.debug("up-to-date {f} => {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), ptr.* });
continue;
}
- log.debug("up-to-date {f} => {f} po_deps=0 (up-to-date)", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender) });
+ deps_log.debug("up-to-date {f} => {f} po_deps=0 (up-to-date)", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender) });
// This dependency is no longer PO, i.e. is known to be up-to-date.
assert(zcu.potentially_outdated.swapRemove(depender));
@@ -3144,139 +3215,120 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
// as no longer PO.
switch (depender.unwrap()) {
.@"comptime" => {},
- .nav_val => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_val = nav }),
- .nav_ty => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_ty = nav }),
- .type => |ty| try zcu.markPoDependeeUpToDate(.{ .interned = ty }),
- .func => |func| try zcu.markPoDependeeUpToDate(.{ .interned = func }),
- .memoized_state => |stage| try zcu.markPoDependeeUpToDate(.{ .memoized_state = stage }),
+ .nav_val => |nav| try zcu.markPoDependeeUpToDateInner(.{ .nav_val = nav }),
+ .nav_ty => |nav| try zcu.markPoDependeeUpToDateInner(.{ .nav_ty = nav }),
+ .type_layout => |ty| try zcu.markPoDependeeUpToDateInner(.{ .type_layout = ty }),
+ .struct_defaults => |ty| try zcu.markPoDependeeUpToDateInner(.{ .struct_defaults = ty }),
+ .func => |func| try zcu.markPoDependeeUpToDateInner(.{ .func_ies = func }),
+ .memoized_state => |stage| try zcu.markPoDependeeUpToDateInner(.{ .memoized_state = stage }),
}
}
}
/// Given a AnalUnit which is newly outdated or PO, mark all AnalUnits which may
/// in turn be PO, due to a dependency on the original AnalUnit's tyval or IES.
-fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUnit) !void {
+///
+/// Assumes that `zcu.outdated_lock` is already held exclusively.
+fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUnit) Allocator.Error!void {
+ const gpa = zcu.comp.gpa;
const ip = &zcu.intern_pool;
const dependee: InternPool.Dependee = switch (maybe_outdated.unwrap()) {
.@"comptime" => return, // analysis of a comptime decl can't outdate any dependencies
.nav_val => |nav| .{ .nav_val = nav },
.nav_ty => |nav| .{ .nav_ty = nav },
- .type => |ty| .{ .interned = ty },
- .func => |func_index| .{ .interned = func_index }, // IES
+ .type_layout => |ty| .{ .type_layout = ty },
+ .struct_defaults => |ty| .{ .struct_defaults = ty },
+ .func => |func_index| .{ .func_ies = func_index },
.memoized_state => |stage| .{ .memoized_state = stage },
};
- log.debug("potentially outdated dependee: {f}", .{zcu.fmtDependee(dependee)});
+ deps_log.debug("potentially outdated dependee: {f}", .{zcu.fmtDependee(dependee)});
var it = ip.dependencyIterator(dependee);
while (it.next()) |po| {
if (zcu.outdated.getPtr(po)) |po_dep_count| {
- // This dependency is already outdated, but it now has one more PO
- // dependency.
+ // This dependency is already outdated, but it now has one more PO dependency.
if (po_dep_count.* == 0) {
- _ = zcu.outdated_ready.swapRemove(po);
+ switch (po.unwrap()) {
+ .func => |func| _ = zcu.outdated_ready.funcs.swapRemove(func),
+ else => _ = zcu.outdated_ready.other.swapRemove(po),
+ }
}
po_dep_count.* += 1;
- log.debug("po {f} => {f} [outdated] po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po), po_dep_count.* });
+ deps_log.debug("po {f} => {f} [outdated] po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po), po_dep_count.* });
continue;
}
if (zcu.potentially_outdated.getPtr(po)) |n| {
// There is now one more PO dependency.
n.* += 1;
- log.debug("po {f} => {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po), n.* });
+ deps_log.debug("po {f} => {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po), n.* });
continue;
}
- try zcu.potentially_outdated.putNoClobber(zcu.gpa, po, 1);
- log.debug("po {f} => {f} po_deps=1", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po) });
+ try zcu.potentially_outdated.putNoClobber(gpa, po, 1);
+ deps_log.debug("po {f} => {f} po_deps=1", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po) });
// This AnalUnit was not already PO, so we must recursively mark its dependers as also PO.
try zcu.markTransitiveDependersPotentiallyOutdated(po);
}
}
+/// Selects an outdated `AnalUnit` to analyze next. Called from the main semantic analysis loop when
+/// there is no work immediately queued. The unit is chosen such that it is unlikely to require any
+/// recursive analysis (all of its previously-marked dependencies are already up-to-date), because
+/// recursive analysis can cause over-analysis on incremental updates.
pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {
- if (!zcu.comp.config.incremental) return null;
+ // We prioritize functions, because the sooner they get analyzed, the sooner they can be send to
+ // the codegen backend and linker, which are usually running in parallel (so this can increase
+ // parallelism).
+ // TODO: perhaps we should also experiment with *avoiding* functions if the codegen/link queue
+ // is backed up (for instance due to a very large function). That could help minimize blocking
+ // on the main thread in `CodegenTaskPool.start` waiting for the linker to catch up.
+ if (zcu.outdated_ready.funcs.count() > 0) {
+ const unit: AnalUnit = .wrap(.{ .func = zcu.outdated_ready.funcs.keys()[0] });
+ log.debug("findOutdatedToAnalyze: {f}", .{zcu.fmtAnalUnit(unit)});
+ return unit;
+ }
+
+ if (zcu.outdated_ready.other.count() > 0) {
+ const unit = zcu.outdated_ready.other.keys()[0];
+ log.debug("findOutdatedToAnalyze: {f}", .{zcu.fmtAnalUnit(unit)});
+ return unit;
+ }
+
+ // Usually, getting here means that everything is up-to-date, so there is no more work to do. We
+ // will see that `zcu.outdated` and `zcu.potentially_outdated` are both empty.
+ //
+ // However, if a previous update had a dependency loop compile error, there is a cycle in the
+ // dependency graph (which is usually acyclic), which can cause a scenario where no unit appears
+ // to be ready, because they're all waiting for the next in the loop to be up-to-date. In that
+ // case, we usually have to just bite the bullet and analyze one of them. An exception is if
+ // `zcu.outdated` is empty but `zcu.potentially_outdated` is non-empty: in that case, the only
+ // possible situation is a cycle where everything is actually up-to-date, so we can clear out
+ // `zcu.potentially_outdated` and we are done.
+
+ if (std.debug.runtime_safety) zcu.outdated_lock.lockUncancelable(zcu.comp.io);
+ defer if (std.debug.runtime_safety) zcu.outdated_lock.unlock(zcu.comp.io);
if (zcu.outdated.count() == 0) {
- // Any units in `potentially_outdated` must just be stuck in loops with one another: none of those
- // units have had any outdated dependencies so far, and all of their remaining PO deps are triggered
- // by other units in `potentially_outdated`. So, we can safety assume those units up-to-date.
+ // Everything is up-to-date. There could be lingering entries in `zcu.potentially_outdated`
+ // from a dependency loop on a previous update.
zcu.potentially_outdated.clearRetainingCapacity();
- log.debug("findOutdatedToAnalyze: no outdated depender", .{});
+ log.debug("findOutdatedToAnalyze: all up-to-date", .{});
return null;
}
- // Our goal is to find an outdated AnalUnit which itself has no outdated or
- // PO dependencies. Most of the time, such an AnalUnit will exist - we track
- // them in the `outdated_ready` set for efficiency. However, this is not
- // necessarily the case, since the Decl dependency graph may contain loops
- // via mutually recursive definitions:
- // pub const A = struct { b: *B };
- // pub const B = struct { b: *A };
- // In this case, we must defer to more complex logic below.
-
- if (zcu.outdated_ready.count() > 0) {
- const unit = zcu.outdated_ready.keys()[0];
- log.debug("findOutdatedToAnalyze: trivial {f}", .{zcu.fmtAnalUnit(unit)});
- return unit;
- }
-
- // There is no single AnalUnit which is ready for re-analysis. Instead, we must assume that some
- // AnalUnit with PO dependencies is outdated -- e.g. in the above example we arbitrarily pick one of
- // A or B. We should definitely not select a function, since a function can't be responsible for the
- // loop (IES dependencies can't have loops). We should also, of course, not select a `comptime`
- // declaration, since you can't depend on those!
-
- // The choice of this unit could have a big impact on how much total analysis we perform, since
- // if analysis concludes any dependencies on its result are up-to-date, then other PO AnalUnit
- // may be resolved as up-to-date. To hopefully avoid doing too much work, let's find a unit
- // which the most things depend on - the idea is that this will resolve a lot of loops (but this
- // is only a heuristic).
-
- log.debug("findOutdatedToAnalyze: no trivial ready, using heuristic; {d} outdated, {d} PO", .{
+ const unit = zcu.outdated.keys()[0];
+ log.debug("findOutdatedToAnalyze: dependency loop affecting {d} units, selected {f}", .{
zcu.outdated.count(),
- zcu.potentially_outdated.count(),
+ zcu.fmtAnalUnit(unit),
});
-
- const ip = &zcu.intern_pool;
-
- var chosen_unit: ?AnalUnit = null;
- var chosen_unit_dependers: u32 = undefined;
-
- inline for (.{ zcu.outdated.keys(), zcu.potentially_outdated.keys() }) |outdated_units| {
- for (outdated_units) |unit| {
- var n: u32 = 0;
- var it = ip.dependencyIterator(switch (unit.unwrap()) {
- .func => continue, // a `func` definitely can't be causing the loop so it is a bad choice
- .@"comptime" => continue, // a `comptime` block can't even be depended on so it is a terrible choice
- .type => |ty| .{ .interned = ty },
- .nav_val => |nav| .{ .nav_val = nav },
- .nav_ty => |nav| .{ .nav_ty = nav },
- .memoized_state => {
- // If we've hit a loop and some `.memoized_state` is outdated, we should make that choice eagerly.
- // In general, it's good to resolve this early on, since -- for instance -- almost every function
- // references the panic handler.
- return unit;
- },
- });
- while (it.next()) |_| n += 1;
-
- if (chosen_unit == null or n > chosen_unit_dependers) {
- chosen_unit = unit;
- chosen_unit_dependers = n;
- }
- }
- }
-
- log.debug("findOutdatedToAnalyze: heuristic returned '{f}' ({d} dependers)", .{
- zcu.fmtAnalUnit(chosen_unit.?),
- chosen_unit_dependers,
- });
-
- return chosen_unit.?;
+ return unit;
}
/// During an incremental update, before semantic analysis, call this to flush all values from
/// `retryable_failures` and mark them as outdated so they get re-analyzed.
pub fn flushRetryableFailures(zcu: *Zcu) !void {
- const gpa = zcu.gpa;
+ const comp = zcu.comp;
+ const gpa = comp.gpa;
+ if (std.debug.runtime_safety) zcu.outdated_lock.lockUncancelable(comp.io);
+ defer if (std.debug.runtime_safety) zcu.outdated_lock.unlock(comp.io);
for (zcu.retryable_failures.items) |depender| {
if (zcu.outdated.contains(depender)) continue;
if (zcu.potentially_outdated.fetchSwapRemove(depender)) |kv| {
@@ -3350,12 +3402,59 @@ pub fn mapOldZirToNew(
}
while (match_stack.pop()) |match_item| {
- // First, a check: if the number of captures of this type has changed, we can't map it, because
- // we wouldn't know how to correlate type information with the last update.
- // Synchronizes with logic in `Zcu.PerThread.recreateStructType` etc.
- if (old_zir.typeCapturesLen(match_item.old_inst) != new_zir.typeCapturesLen(match_item.new_inst)) {
- // Don't map this type or anything within it.
- continue;
+ // There are some properties of type declarations which cannot change across incremental
+ // updates. If they have, we need to ignore this mapping. These properties are essentially
+ // everything passed into `InternPool.getDeclaredStructType` (likewise for unions, enums,
+ // and opaques).
+ const old_tag = old_zir.instructions.items(.data)[@intFromEnum(match_item.old_inst)].extended.opcode;
+ const new_tag = new_zir.instructions.items(.data)[@intFromEnum(match_item.new_inst)].extended.opcode;
+ if (old_tag != new_tag) continue;
+ switch (old_tag) {
+ .struct_decl => {
+ const old = old_zir.getStructDecl(match_item.old_inst);
+ const new = new_zir.getStructDecl(match_item.new_inst);
+ if (old.captures.len != new.captures.len) continue;
+ if (old.field_names.len != new.field_names.len) continue;
+ if (old.layout != new.layout) continue;
+ const old_any_field_aligns = old.field_align_body_lens != null;
+ const old_any_field_defaults = old.field_default_body_lens != null;
+ const old_any_comptime_fields = old.field_comptime_bits != null;
+ const old_explicit_backing_int = old.backing_int_type_body != null;
+ const new_any_field_aligns = new.field_align_body_lens != null;
+ const new_any_field_defaults = new.field_default_body_lens != null;
+ const new_any_comptime_fields = new.field_comptime_bits != null;
+ const new_explicit_backing_int = new.backing_int_type_body != null;
+ if (old_any_field_aligns != new_any_field_aligns) continue;
+ if (old_any_field_defaults != new_any_field_defaults) continue;
+ if (old_any_comptime_fields != new_any_comptime_fields) continue;
+ if (old_explicit_backing_int != new_explicit_backing_int) continue;
+ },
+ .union_decl => {
+ const old = old_zir.getUnionDecl(match_item.old_inst);
+ const new = new_zir.getUnionDecl(match_item.new_inst);
+ if (old.captures.len != new.captures.len) continue;
+ if (old.field_names.len != new.field_names.len) continue;
+ if (old.kind != new.kind) continue;
+ const old_any_field_aligns = old.field_align_body_lens != null;
+ const new_any_field_aligns = new.field_align_body_lens != null;
+ if (old_any_field_aligns != new_any_field_aligns) continue;
+ },
+ .enum_decl => {
+ const old = old_zir.getEnumDecl(match_item.old_inst);
+ const new = new_zir.getEnumDecl(match_item.new_inst);
+ if (old.captures.len != new.captures.len) continue;
+ if (old.field_names.len != new.field_names.len) continue;
+ if (old.nonexhaustive != new.nonexhaustive) continue;
+ const old_explicit_tag_type = old.tag_type_body != null;
+ const new_explicit_tag_type = new.tag_type_body != null;
+ if (old_explicit_tag_type != new_explicit_tag_type) continue;
+ },
+ .opaque_decl => {
+ const old = old_zir.getOpaqueDecl(match_item.old_inst);
+ const new = new_zir.getOpaqueDecl(match_item.new_inst);
+ if (old.captures.len != new.captures.len) continue;
+ },
+ else => unreachable,
}
// Match the namespace declaration itself
@@ -3377,25 +3476,21 @@ pub fn mapOldZirToNew(
var comptime_decls: std.ArrayList(Zir.Inst.Index) = .empty;
defer comptime_decls.deinit(gpa);
- {
- var old_decl_it = old_zir.declIterator(match_item.old_inst);
- while (old_decl_it.next()) |old_decl_inst| {
- const old_decl = old_zir.getDeclaration(old_decl_inst);
- switch (old_decl.kind) {
- .@"comptime" => try comptime_decls.append(gpa, old_decl_inst),
- .unnamed_test => try unnamed_tests.append(gpa, old_decl_inst),
- .@"test" => try named_tests.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst),
- .decltest => try named_decltests.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst),
- .@"const", .@"var" => try named_decls.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst),
- }
+ for (old_zir.typeDecls(match_item.old_inst)) |old_decl_inst| {
+ const old_decl = old_zir.getDeclaration(old_decl_inst);
+ switch (old_decl.kind) {
+ .@"comptime" => try comptime_decls.append(gpa, old_decl_inst),
+ .unnamed_test => try unnamed_tests.append(gpa, old_decl_inst),
+ .@"test" => try named_tests.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst),
+ .decltest => try named_decltests.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst),
+ .@"const", .@"var" => try named_decls.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst),
}
}
var unnamed_test_idx: u32 = 0;
var comptime_decl_idx: u32 = 0;
- var new_decl_it = new_zir.declIterator(match_item.new_inst);
- while (new_decl_it.next()) |new_decl_inst| {
+ for (new_zir.typeDecls(match_item.new_inst)) |new_decl_inst| {
const new_decl = new_zir.getDeclaration(new_decl_inst);
// Attempt to match this to a declaration in the old ZIR:
// * For named declarations (`const`/`var`/`fn`), we match based on name.
@@ -3474,47 +3569,93 @@ pub fn mapOldZirToNew(
/// The caller is responsible for ensuring the function decl itself is already
/// analyzed, and for ensuring it can exist at runtime (see
/// `Type.fnHasRuntimeBitsSema`). This function does *not* guarantee that the body
-/// will be analyzed when it returns: for that, see `ensureFuncBodyAnalyzed`.
-pub fn ensureFuncBodyAnalysisQueued(zcu: *Zcu, func_index: InternPool.Index) !void {
+/// will be analyzed when it returns: for that, see `PerThread.ensureFuncBodyUpToDate`.
+pub fn ensureFuncBodyAnalysisQueued(zcu: *Zcu, func: InternPool.Index) !void {
+ const comp = zcu.comp;
+ const gpa = comp.gpa;
+ const io = comp.io;
const ip = &zcu.intern_pool;
+ assert(func == ip.unwrapCoercedFunc(func)); // analyze the body of the original function, not a coerced one
+ if (ip.setWantRuntimeFnAnalysis(io, func)) {
+ // This is the first reference to this function, so we must ensure it will be analyzed.
+ if (std.debug.runtime_safety) zcu.outdated_lock.lockUncancelable(zcu.comp.io);
+ defer if (std.debug.runtime_safety) zcu.outdated_lock.unlock(zcu.comp.io);
+ try zcu.outdated.ensureUnusedCapacity(gpa, 1);
+ try zcu.outdated_ready.funcs.ensureUnusedCapacity(gpa, 1);
+ zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .func = func }), 0);
+ zcu.outdated_ready.funcs.putAssumeCapacityNoClobber(func, {});
+ }
+}
- const func = zcu.funcInfo(func_index);
-
- assert(func.ty == func.uncoerced_ty); // analyze the body of the original function, not a coerced one
+pub fn ensureNavValAnalysisQueued(zcu: *Zcu, nav: InternPool.Nav.Index) !void {
+ const comp = zcu.comp;
+ const gpa = comp.gpa;
+ const io = comp.io;
+ const ip = &zcu.intern_pool;
+ if (ip.setWantNavAnalysis(io, nav)) {
+ // This is the first reference to this function, so we must ensure it will be analyzed.
+ if (std.debug.runtime_safety) zcu.outdated_lock.lockUncancelable(zcu.comp.io);
+ defer if (std.debug.runtime_safety) zcu.outdated_lock.unlock(zcu.comp.io);
+ try zcu.outdated.ensureUnusedCapacity(gpa, 2);
+ try zcu.outdated_ready.other.ensureUnusedCapacity(gpa, 2);
+ zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .nav_val = nav }), 0);
+ zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .nav_ty = nav }), 0);
+ zcu.outdated_ready.other.putAssumeCapacityNoClobber(.wrap(.{ .nav_val = nav }), {});
+ zcu.outdated_ready.other.putAssumeCapacityNoClobber(.wrap(.{ .nav_ty = nav }), {});
+ }
+}
- if (zcu.func_body_analysis_queued.contains(func_index)) return;
+/// Called when an `InternPool.ComptimeUnit` is first created to mark it as outdated so that it will
+/// be semantically analyzed.
+pub fn queueComptimeUnitAnalysis(zcu: *Zcu, cu: InternPool.ComptimeUnit.Id) Allocator.Error!void {
+ const comp = zcu.comp;
+ const gpa = comp.gpa;
+ const io = comp.io;
+ const unit: AnalUnit = .wrap(.{ .@"comptime" = cu });
+ if (std.debug.runtime_safety) zcu.outdated_lock.lockUncancelable(io);
+ defer if (std.debug.runtime_safety) zcu.outdated_lock.unlock(io);
+ try zcu.outdated.ensureUnusedCapacity(gpa, 1);
+ try zcu.outdated_ready.other.ensureUnusedCapacity(gpa, 1);
+ zcu.outdated.putAssumeCapacityNoClobber(unit, 0);
+ zcu.outdated_ready.other.putAssumeCapacityNoClobber(unit, {});
+}
- if (func.analysisUnordered(ip).is_analyzed) {
- if (!zcu.outdated.contains(.wrap(.{ .func = func_index })) and
- !zcu.potentially_outdated.contains(.wrap(.{ .func = func_index })))
- {
- // This function has been analyzed before and is definitely up-to-date.
- return;
+/// If `unit` was marked as outdated or porentially outdated, clears that status and returns `true`.
+/// Otherwise, returns `false`.
+pub fn clearOutdatedState(zcu: *Zcu, unit: AnalUnit) bool {
+ const io = zcu.comp.io;
+ if (std.debug.runtime_safety) zcu.outdated_lock.lockUncancelable(io);
+ defer if (std.debug.runtime_safety) zcu.outdated_lock.unlock(io);
+ if (zcu.outdated.fetchSwapRemove(unit)) |kv| {
+ const was_ready = switch (unit.unwrap()) {
+ .func => |func| zcu.outdated_ready.funcs.swapRemove(func),
+ else => zcu.outdated_ready.other.swapRemove(unit),
+ };
+ if (kv.value == 0) {
+ assert(was_ready);
+ } else {
+ assert(!was_ready);
}
+ return true;
+ } else if (zcu.potentially_outdated.swapRemove(unit)) {
+ return true;
+ } else {
+ return false;
}
-
- try zcu.func_body_analysis_queued.ensureUnusedCapacity(zcu.gpa, 1);
- try zcu.comp.queueJob(.{ .analyze_func = func_index });
- zcu.func_body_analysis_queued.putAssumeCapacityNoClobber(func_index, {});
}
-pub fn ensureNavValAnalysisQueued(zcu: *Zcu, nav_id: InternPool.Nav.Index) !void {
- const ip = &zcu.intern_pool;
+/// This function takes a `*const Zcu` and `@constCast`s it so that it can be called from functions
+/// in `Type` which otherwise do not modify the `Zcu`.
+pub fn assertUpToDate(zcu: *const Zcu, unit: AnalUnit) void {
+ if (!std.debug.runtime_safety) return;
- if (zcu.nav_val_analysis_queued.contains(nav_id)) return;
+ const io = zcu.comp.io;
- if (ip.getNav(nav_id).status == .fully_resolved) {
- if (!zcu.outdated.contains(.wrap(.{ .nav_val = nav_id })) and
- !zcu.potentially_outdated.contains(.wrap(.{ .nav_val = nav_id })))
- {
- // This `Nav` has been analyzed before and is definitely up-to-date.
- return;
- }
- }
+ @constCast(zcu).outdated_lock.lockSharedUncancelable(io);
+ defer @constCast(zcu).outdated_lock.unlockShared(io);
- try zcu.nav_val_analysis_queued.ensureUnusedCapacity(zcu.gpa, 1);
- try zcu.comp.queueJob(.{ .analyze_comptime_unit = .wrap(.{ .nav_val = nav_id }) });
- zcu.nav_val_analysis_queued.putAssumeCapacityNoClobber(nav_id, {});
+ assert(!zcu.outdated.contains(unit));
+ assert(!zcu.potentially_outdated.contains(unit));
}
pub const ImportResult = struct {
@@ -3533,56 +3674,83 @@ pub const ImportResult = struct {
module: ?*Package.Module,
};
-/// Delete all the Export objects that are caused by this `AnalUnit`. Re-analysis of
-/// this `AnalUnit` will cause them to be re-created (or not).
-pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void {
- const gpa = zcu.gpa;
+/// Prepares `unit` for re-analysis by clearing all of the following state:
+/// * Compile errors associated with `unit`
+/// * Compile logs associated with `unit`
+/// * Exports performed by `unit`
+/// * Dependencies from `unit` on other things
+/// * References from `unit` to other units
+/// Delete all references in `reference_table` which are caused by `unit`, and all dependencies it
+/// has. Called in preparation for re-analysis, which will recreate references and dependencies.
+/// Re-analysis of the `AnalUnit` will cause appropriate references to be recreated.
+pub fn resetUnit(zcu: *Zcu, unit: AnalUnit) void {
+ const gpa = zcu.comp.gpa;
- const exports_base, const exports_len = if (zcu.single_exports.fetchSwapRemove(anal_unit)) |kv|
- .{ @intFromEnum(kv.value), 1 }
- else if (zcu.multi_exports.fetchSwapRemove(anal_unit)) |info|
- .{ info.value.index, info.value.len }
- else
+ if (!dev.env.supports(.incremental)) {
+ // This is the first time `unit` is being analyzed, so there is no stale data to clear.
return;
+ }
- const exports = zcu.all_exports.items[exports_base..][0..exports_len];
+ // Compile errors
+ if (zcu.failed_analysis.fetchSwapRemove(unit)) |kv| {
+ kv.value.destroy(gpa);
+ } else if (zcu.dependency_loop_nodes.swapRemove(unit)) {
+ _ = zcu.dependency_loops.swapRemove(unit);
+ _ = zcu.transitive_failed_analysis.swapRemove(unit);
+ } else {
+ _ = zcu.transitive_failed_analysis.swapRemove(unit);
+ }
- // In an only-c build, we're guaranteed to never use incremental compilation, so there are
- // guaranteed not to be any exports in the output file that need deleting (since we only call
- // `updateExports` on flush).
- // This case is needed because in some rare edge cases, `Sema` wants to add and delete exports
- // within a single update.
- if (dev.env.supports(.incremental)) {
- for (exports, exports_base..) |exp, export_index_usize| {
- const export_idx: Export.Index = @enumFromInt(export_index_usize);
+ // Compile logs
+ if (zcu.compile_logs.fetchSwapRemove(unit)) |kv| {
+ var opt_line_idx = kv.value.first_line.toOptional();
+ while (opt_line_idx.unwrap()) |line_idx| {
+ zcu.free_compile_log_lines.append(gpa, line_idx) catch {
+ // This space will be reused eventually, so we need not propagate this error.
+ // Just leak it for now, and let GC reclaim it later on.
+ break;
+ };
+ opt_line_idx = line_idx.get(zcu).next;
+ }
+ }
+
+ // Exports
+ exports: {
+ const base: u32, const len: u32 = index: {
+ if (zcu.single_exports.fetchSwapRemove(unit)) |kv| {
+ break :index .{ @intFromEnum(kv.value), 1 };
+ }
+ if (zcu.multi_exports.fetchSwapRemove(unit)) |kv| {
+ break :index .{ kv.value.index, kv.value.len };
+ }
+ break :exports;
+ };
+ for (zcu.all_exports.items[base..][0..len], base..) |exp, exp_index_usize| {
+ const exp_index: Export.Index = @enumFromInt(exp_index_usize);
if (zcu.comp.bin_file) |lf| {
lf.deleteExport(exp.exported, exp.opts.name);
}
- if (zcu.failed_exports.fetchSwapRemove(export_idx)) |failed_kv| {
+ if (zcu.failed_exports.fetchSwapRemove(exp_index)) |failed_kv| {
failed_kv.value.destroy(gpa);
}
}
+ zcu.free_exports.ensureUnusedCapacity(gpa, len) catch {
+ // This space will be reused eventually, so we need not propagate this error.
+ // Just leak it for now, and let GC reclaim it later on.
+ break :exports;
+ };
+ for (base..base + len) |exp_index| {
+ zcu.free_exports.appendAssumeCapacity(@enumFromInt(exp_index));
+ }
}
- zcu.free_exports.ensureUnusedCapacity(gpa, exports_len) catch {
- // This space will be reused eventually, so we need not propagate this error.
- // Just leak it for now, and let GC reclaim it later on.
- return;
- };
- for (exports_base..exports_base + exports_len) |export_idx| {
- zcu.free_exports.appendAssumeCapacity(@enumFromInt(export_idx));
- }
-}
-
-/// Delete all references in `reference_table` which are caused by this `AnalUnit`.
-/// Re-analysis of the `AnalUnit` will cause appropriate references to be recreated.
-pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {
- const gpa = zcu.gpa;
+ // Dependencies
+ zcu.intern_pool.removeDependenciesForDepender(gpa, unit);
+ // References
zcu.clearCachedResolvedReferences();
-
unit_refs: {
- const kv = zcu.reference_table.fetchSwapRemove(anal_unit) orelse break :unit_refs;
+ const kv = zcu.reference_table.fetchSwapRemove(unit) orelse break :unit_refs;
var idx = kv.value;
while (idx != std.math.maxInt(u32)) {
@@ -3610,9 +3778,8 @@ pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {
}
}
}
-
type_refs: {
- const kv = zcu.type_reference_table.fetchSwapRemove(anal_unit) orelse break :type_refs;
+ const kv = zcu.type_reference_table.fetchSwapRemove(unit) orelse break :type_refs;
var idx = kv.value;
while (idx != std.math.maxInt(u32)) {
@@ -3626,22 +3793,6 @@ pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {
}
}
-/// Delete all compile logs performed by this `AnalUnit`.
-/// Re-analysis of the `AnalUnit` will cause logs to be rediscovered.
-pub fn deleteUnitCompileLogs(zcu: *Zcu, anal_unit: AnalUnit) void {
- const kv = zcu.compile_logs.fetchSwapRemove(anal_unit) orelse return;
- const gpa = zcu.gpa;
- var opt_line_idx = kv.value.first_line.toOptional();
- while (opt_line_idx.unwrap()) |line_idx| {
- zcu.free_compile_log_lines.append(gpa, line_idx) catch {
- // This space will be reused eventually, so we need not propagate this error.
- // Just leak it for now, and let GC reclaim it later on.
- return;
- };
- opt_line_idx = line_idx.get(zcu).next;
- }
-}
-
pub fn addInlineReferenceFrame(zcu: *Zcu, frame: InlineReferenceFrame) Allocator.Error!Zcu.InlineReferenceFrame.Index {
const frame_idx: InlineReferenceFrame.Index = zcu.free_inline_reference_frames.pop() orelse idx: {
_ = try zcu.inline_reference_frames.addOne(zcu.gpa);
@@ -3851,9 +4002,9 @@ pub const AtomicPtrAlignmentDiagnostics = struct {
max_bits: u16 = undefined,
};
-/// If ABI alignment of `ty` is OK for atomic operations, returns 0.
-/// Otherwise returns the alignment required on a pointer for the target
-/// to perform atomic operations.
+/// Returns the alignment required for the target to perform atomic operations on type `ty` (that
+/// is, the required align attribute on the pointer). If the ABI alignment of `ty` is sufficient,
+/// returns `.none`.
// TODO this function does not take into account CPU features, which can affect
// this value. Audit this!
pub fn atomicPtrAlignment(
@@ -3908,8 +4059,7 @@ pub fn atomicPtrAlignment(
return error.BadType;
}
-/// Returns null in the following cases:
-/// * Not a struct.
+/// Returns null if `ty` is not a struct.
pub fn typeToStruct(zcu: *const Zcu, ty: Type) ?InternPool.LoadedStructType {
if (ty.ip_index == .none) return null;
const ip = &zcu.intern_pool;
@@ -3936,7 +4086,6 @@ pub fn structPackedFieldBitOffset(
) u16 {
const ip = &zcu.intern_pool;
assert(struct_type.layout == .@"packed");
- assert(struct_type.haveLayout(ip));
var bit_sum: u64 = 0;
for (0..struct_type.field_types.len) |i| {
if (i == field_index) {
@@ -3995,8 +4144,10 @@ pub const UnionLayout = struct {
pub fn unionTagFieldIndex(zcu: *const Zcu, loaded_union: InternPool.LoadedUnionType, enum_tag: Value) ?u32 {
const ip = &zcu.intern_pool;
if (enum_tag.toIntern() == .none) return null;
- assert(ip.typeOf(enum_tag.toIntern()) == loaded_union.enum_tag_ty);
- return loaded_union.loadTagType(ip).tagValueIndex(ip, enum_tag.toIntern());
+ const enum_tag_key = ip.indexToKey(enum_tag.toIntern()).enum_tag;
+ assert(enum_tag_key.ty == loaded_union.enum_tag_type);
+ const loaded_enum = ip.loadEnumType(loaded_union.enum_tag_type);
+ return loaded_enum.tagValueIndex(ip, enum_tag_key.int);
}
pub const ResolvedReference = struct {
@@ -4012,13 +4163,13 @@ pub const ResolvedReference = struct {
/// If an `AnalUnit` is not in the returned map, it is unreferenced.
/// The returned hashmap is owned by the `Zcu`, so should not be freed by the caller.
/// This hashmap is cached, so repeated calls to this function are cheap.
-pub fn resolveReferences(zcu: *Zcu) !*const std.AutoArrayHashMapUnmanaged(AnalUnit, ?ResolvedReference) {
+pub fn resolveReferences(zcu: *Zcu) Allocator.Error!*const std.AutoArrayHashMapUnmanaged(AnalUnit, ?ResolvedReference) {
if (zcu.resolved_references == null) {
zcu.resolved_references = try zcu.resolveReferencesInner();
}
return &zcu.resolved_references.?;
}
-fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?ResolvedReference) {
+fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.AutoArrayHashMapUnmanaged(AnalUnit, ?ResolvedReference) {
const gpa = zcu.gpa;
const comp = zcu.comp;
const ip = &zcu.intern_pool;
@@ -4049,32 +4200,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R
const referencer = types.values()[type_idx];
type_idx += 1;
- log.debug("handle type '{f}'", .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)});
-
- // If this type undergoes type resolution, the corresponding `AnalUnit` is automatically referenced.
- const has_resolution: bool = switch (ip.indexToKey(ty)) {
- .struct_type, .union_type => true,
- .enum_type => |k| k != .generated_tag,
- .opaque_type => false,
- else => unreachable,
- };
- if (has_resolution) {
- // this should only be referenced by the type
- const unit: AnalUnit = .wrap(.{ .type = ty });
- try units.putNoClobber(gpa, unit, referencer);
- }
-
- // If this is a union with a generated tag, its tag type is automatically referenced.
- // We don't add this reference for non-generated tags, as those will already be referenced via the union's type resolution, with a better source location.
- if (zcu.typeToUnion(Type.fromInterned(ty))) |union_obj| {
- const tag_ty = union_obj.enum_tag_ty;
- if (tag_ty != .none) {
- if (ip.indexToKey(tag_ty).enum_type == .generated_tag) {
- const gop = try types.getOrPut(gpa, tag_ty);
- if (!gop.found_existing) gop.value_ptr.* = referencer;
- }
- }
- }
+ refs_log.debug("handle type '{f}'", .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)});
// Queue any decls within this type which would be automatically analyzed.
// Keep in sync with analysis queueing logic in `Zcu.PerThread.ScanDeclIter.scanDecl`.
@@ -4084,7 +4210,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R
const unit: AnalUnit = .wrap(.{ .@"comptime" = cu });
const gop = try units.getOrPut(gpa, unit);
if (!gop.found_existing) {
- log.debug("type '{f}': ref comptime %{}", .{
+ refs_log.debug("type '{f}': ref comptime %{}", .{
Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
@intFromEnum(ip.getComptimeUnit(cu).zir_index.resolve(ip) orelse continue),
});
@@ -4118,7 +4244,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R
{
const gop = try units.getOrPut(gpa, .wrap(.{ .nav_val = nav_id }));
if (!gop.found_existing) {
- log.debug("type '{f}': ref test %{}", .{
+ refs_log.debug("type '{f}': ref test %{}", .{
Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
@intFromEnum(inst_info.inst),
});
@@ -4141,7 +4267,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R
const unit: AnalUnit = .wrap(.{ .nav_val = nav });
const gop = try units.getOrPut(gpa, unit);
if (!gop.found_existing) {
- log.debug("type '{f}': ref named %{}", .{
+ refs_log.debug("type '{f}': ref named %{}", .{
Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
@intFromEnum(inst_info.inst),
});
@@ -4158,7 +4284,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R
const unit: AnalUnit = .wrap(.{ .nav_val = nav });
const gop = try units.getOrPut(gpa, unit);
if (!gop.found_existing) {
- log.debug("type '{f}': ref named %{}", .{
+ refs_log.debug("type '{f}': ref named %{}", .{
Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
@intFromEnum(inst_info.inst),
});
@@ -4173,18 +4299,25 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R
unit_idx += 1;
// `nav_val` and `nav_ty` reference each other *implicitly* to save memory.
+ // Likewise for `type_layout` and `struct_defaults` of a struct type.
queue_paired: {
const other: AnalUnit = .wrap(switch (unit.unwrap()) {
.nav_val => |n| .{ .nav_ty = n },
.nav_ty => |n| .{ .nav_val = n },
- .@"comptime", .type, .func, .memoized_state => break :queue_paired,
+ .struct_defaults => |ty| .{ .type_layout = ty },
+ .type_layout => |ty| switch (ip.indexToKey(ty)) {
+ .struct_type => .{ .struct_defaults = ty },
+ .union_type, .enum_type, .opaque_type => break :queue_paired,
+ else => unreachable,
+ },
+ .@"comptime", .func, .memoized_state => break :queue_paired,
});
const gop = try units.getOrPut(gpa, other);
if (gop.found_existing) break :queue_paired;
- gop.value_ptr.* = units.values()[unit_idx]; // same reference location
+ gop.value_ptr.* = units.values()[unit_idx - 1]; // same reference location
}
- log.debug("handle unit '{f}'", .{zcu.fmtAnalUnit(unit)});
+ refs_log.debug("handle unit '{f}'", .{zcu.fmtAnalUnit(unit)});
if (zcu.reference_table.get(unit)) |first_ref_idx| {
assert(first_ref_idx != std.math.maxInt(u32));
@@ -4193,7 +4326,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R
const ref = zcu.all_references.items[ref_idx];
const gop = try units.getOrPut(gpa, ref.referenced);
if (!gop.found_existing) {
- log.debug("unit '{f}': ref unit '{f}'", .{
+ refs_log.debug("unit '{f}': ref unit '{f}'", .{
zcu.fmtAnalUnit(unit),
zcu.fmtAnalUnit(ref.referenced),
});
@@ -4213,7 +4346,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R
const ref = zcu.all_type_references.items[ref_idx];
const gop = try types.getOrPut(gpa, ref.referenced);
if (!gop.found_existing) {
- log.debug("unit '{f}': ref type '{f}'", .{
+ refs_log.debug("unit '{f}': ref type '{f}'", .{
zcu.fmtAnalUnit(unit),
Type.fromInterned(ref.referenced).containerTypeName(ip).fmt(ip),
});
@@ -4298,6 +4431,16 @@ pub fn navFileScope(zcu: *Zcu, nav: InternPool.Nav.Index) *File {
return zcu.fileByIndex(zcu.navFileScopeIndex(nav));
}
+pub fn navAlignment(zcu: *Zcu, nav_index: InternPool.Nav.Index) InternPool.Alignment {
+ const ty: Type, const alignment = switch (zcu.intern_pool.getNav(nav_index).status) {
+ .unresolved => unreachable,
+ .type_resolved => |r| .{ .fromInterned(r.type), r.alignment },
+ .fully_resolved => |r| .{ Value.fromInterned(r.val).typeOf(zcu), r.alignment },
+ };
+ if (alignment != .none) return alignment;
+ return ty.abiAlignment(zcu);
+}
+
pub fn fmtAnalUnit(zcu: *Zcu, unit: AnalUnit) std.fmt.Alt(FormatAnalUnit, formatAnalUnit) {
return .{ .data = .{ .unit = unit, .zcu = zcu } };
}
@@ -4305,11 +4448,7 @@ pub fn fmtDependee(zcu: *Zcu, d: InternPool.Dependee) std.fmt.Alt(FormatDependee
return .{ .data = .{ .dependee = d, .zcu = zcu } };
}
-const FormatAnalUnit = struct {
- unit: AnalUnit,
- zcu: *Zcu,
-};
-
+const FormatAnalUnit = struct { unit: AnalUnit, zcu: *const Zcu };
fn formatAnalUnit(data: FormatAnalUnit, writer: *Io.Writer) Io.Writer.Error!void {
const zcu = data.zcu;
const ip = &zcu.intern_pool;
@@ -4323,9 +4462,8 @@ fn formatAnalUnit(data: FormatAnalUnit, writer: *Io.Writer) Io.Writer.Error!void
return writer.print("comptime(inst= [{}])", .{@intFromEnum(cu_id)});
}
},
- .nav_val => |nav| return writer.print("nav_val('{f}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) }),
- .nav_ty => |nav| return writer.print("nav_ty('{f}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) }),
- .type => |ty| return writer.print("ty('{f}' [{}])", .{ Type.fromInterned(ty).containerTypeName(ip).fmt(ip), @intFromEnum(ty) }),
+ .nav_val, .nav_ty => |nav, tag| return writer.print("{t}('{f}' [{}])", .{ tag, ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) }),
+ .type_layout, .struct_defaults => |ty, tag| return writer.print("{t}('{f}' [{}])", .{ tag, Type.fromInterned(ty).containerTypeName(ip).fmt(ip), @intFromEnum(ty) }),
.func => |func| {
const nav = zcu.funcInfo(func).owner_nav;
return writer.print("func('{f}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(func) });
@@ -4334,8 +4472,7 @@ fn formatAnalUnit(data: FormatAnalUnit, writer: *Io.Writer) Io.Writer.Error!void
}
}
-const FormatDependee = struct { dependee: InternPool.Dependee, zcu: *Zcu };
-
+const FormatDependee = struct { dependee: InternPool.Dependee, zcu: *const Zcu };
fn formatDependee(data: FormatDependee, writer: *Io.Writer) Io.Writer.Error!void {
const zcu = data.zcu;
const ip = &zcu.intern_pool;
@@ -4347,18 +4484,17 @@ fn formatDependee(data: FormatDependee, writer: *Io.Writer) Io.Writer.Error!void
const file_path = zcu.fileByIndex(info.file).path;
return writer.print("inst('{f}', %{d})", .{ file_path.fmt(zcu.comp), @intFromEnum(info.inst) });
},
- .nav_val => |nav| {
+ .nav_val, .nav_ty => |nav, tag| {
const fqn = ip.getNav(nav).fqn;
- return writer.print("nav_val('{f}')", .{fqn.fmt(ip)});
+ return writer.print("{t}('{f}')", .{ tag, fqn.fmt(ip) });
},
- .nav_ty => |nav| {
- const fqn = ip.getNav(nav).fqn;
- return writer.print("nav_ty('{f}')", .{fqn.fmt(ip)});
+ .type_layout, .struct_defaults => |ip_index, tag| {
+ const name = Type.fromInterned(ip_index).containerTypeName(ip);
+ return writer.print("{t}('{f}')", .{ tag, name.fmt(ip) });
},
- .interned => |ip_index| switch (ip.indexToKey(ip_index)) {
- .struct_type, .union_type, .enum_type => return writer.print("type('{f}')", .{Type.fromInterned(ip_index).containerTypeName(ip).fmt(ip)}),
- .func => |f| return writer.print("ies('{f}')", .{ip.getNav(f.owner_nav).fqn.fmt(ip)}),
- else => unreachable,
+ .func_ies => |ip_index| {
+ const fqn = ip.getNav(ip.indexToKey(ip_index).func.owner_nav).fqn;
+ return writer.print("func_ies('{f}')", .{fqn.fmt(ip)});
},
.zon_file => |file| {
const file_path = zcu.fileByIndex(file).path;
@@ -4386,32 +4522,6 @@ fn formatDependee(data: FormatDependee, writer: *Io.Writer) Io.Writer.Error!void
}
}
-/// Given the `InternPool.Index` of a function, set its resolved IES to `.none` if it
-/// may be outdated. `Sema` should do this before ever loading a resolved IES.
-pub fn maybeUnresolveIes(zcu: *Zcu, func_index: InternPool.Index) !void {
- const unit = AnalUnit.wrap(.{ .func = func_index });
- if (zcu.outdated.contains(unit) or zcu.potentially_outdated.contains(unit)) {
- // We're consulting the resolved IES now, but the function is outdated, so its
- // IES may have changed. We have to assume the IES is outdated and set the resolved
- // set back to `.none`.
- //
- // This will cause `PerThread.analyzeFnBody` to mark the IES as outdated when it's
- // eventually hit.
- //
- // Since the IES needs to be resolved, the function body will now definitely need
- // re-analysis (even if the IES turns out to be the same!), so mark it as
- // definitely-outdated if it's only PO.
- if (zcu.potentially_outdated.fetchSwapRemove(unit)) |kv| {
- const gpa = zcu.gpa;
- try zcu.outdated.putNoClobber(gpa, unit, kv.value);
- if (kv.value == 0) {
- try zcu.outdated_ready.put(gpa, unit, {});
- }
- }
- zcu.intern_pool.funcSetIesResolved(zcu.comp.io, func_index, .none);
- }
-}
-
pub fn callconvSupported(zcu: *Zcu, cc: std.builtin.CallingConvention) union(enum) {
ok,
bad_arch: []const std.Target.Cpu.Arch, // value is allowed archs for cc
@@ -4747,6 +4857,304 @@ fn explainWhyFileIsInModule(
}
}
+pub fn addDependencyLoopErrors(zcu: *Zcu, eb: *std.zig.ErrorBundle.Wip) Allocator.Error!void {
+ const gpa = zcu.comp.gpa;
+
+ const all_references = try zcu.resolveReferences();
+
+ var units: std.ArrayList(AnalUnit) = .empty;
+ defer units.deinit(gpa);
+
+ // TODO: sort the dependency loops somehow to make the error bundle reproducible
+ for (zcu.dependency_loops.keys()) |arbitrary_unit| {
+ units.clearRetainingCapacity();
+
+ var cur = arbitrary_unit;
+ while (true) {
+ try units.append(gpa, cur);
+ cur = zcu.dependency_loop_nodes.get(cur).?.unit;
+ if (cur == arbitrary_unit) break;
+ }
+
+ // `units` now contains all units in the loop. We need to pick a starting point somewhere
+ // along that loop to begin. We will pick whichever node has the shortest reference trace,
+ // because the other units may well just be referenced *by* that one! This is also likely
+ // to match the user's intuition for where the loop "starts".
+ var start_index: usize = 0;
+ var start_depth: u32 = depth: {
+ var depth: u32 = 0;
+ var opt_ref = all_references.get(units.items[0]) orelse {
+ // This dependency loop is actually unreferenced, so we don't need to emit a compile
+ // error at all! Move onto the next dependency loop.
+ continue;
+ };
+ while (opt_ref) |ref| : (opt_ref = all_references.get(ref.referencer).?) depth += 1;
+ break :depth depth;
+ };
+ for (units.items[1..], 1..) |unit, index| {
+ var depth: u32 = 0;
+ var opt_ref = all_references.get(unit).?;
+ while (opt_ref) |ref| : (opt_ref = all_references.get(ref.referencer).?) depth += 1;
+ if (depth < start_depth) {
+ start_index = index;
+ start_depth = depth;
+ }
+ }
+
+ // Collect a reference trace for the start of the loop.
+ var ref_trace: std.ArrayList(std.zig.ErrorBundle.ReferenceTrace) = .empty;
+ defer ref_trace.deinit(gpa);
+ const frame_limit = zcu.comp.reference_trace orelse 0;
+ try zcu.populateReferenceTrace(units.items[start_index], frame_limit, eb, &ref_trace);
+
+ if (units.items.len == 1) {
+ // Don't do a complicated message with multiple notes, just do a single error message.
+ assert(start_index == 0);
+ const root_msg = addDependencyLoopErrorLine(zcu, eb, units.items[start_index], ref_trace.items) catch |err| switch (err) {
+ error.AlreadyReported => return, // give up on the dep loop error
+ error.OutOfMemory => |e| return e,
+ };
+ try eb.root_list.append(eb.gpa, root_msg);
+ continue;
+ }
+
+ // Collect all notes first so we don't leave an incomplete root error message on `error.AlreadyReported`.
+ const note_buf = try gpa.alloc(std.zig.ErrorBundle.MessageIndex, units.items.len + 1);
+ defer gpa.free(note_buf);
+ note_buf[0] = addDependencyLoopErrorLine(zcu, eb, units.items[start_index], ref_trace.items) catch |err| switch (err) {
+ error.AlreadyReported => return, // give up on the dep loop error
+ error.OutOfMemory => |e| return e,
+ };
+ for (units.items[start_index + 1 ..], note_buf[1 .. units.items.len - start_index]) |unit, *note| {
+ note.* = addDependencyLoopErrorLine(zcu, eb, unit, &.{}) catch |err| switch (err) {
+ error.AlreadyReported => return, // give up on the dep loop error
+ error.OutOfMemory => |e| return e,
+ };
+ }
+ for (units.items[0..start_index], note_buf[units.items.len - start_index .. units.items.len]) |unit, *note| {
+ note.* = addDependencyLoopErrorLine(zcu, eb, unit, &.{}) catch |err| switch (err) {
+ error.AlreadyReported => return, // give up on the dep loop error
+ error.OutOfMemory => |e| return e,
+ };
+ }
+ note_buf[units.items.len] = try eb.addErrorMessage(.{
+ .msg = try eb.addString("eliminate any one of these dependencies to break the loop"),
+ .src_loc = .none,
+ });
+
+ try eb.addRootErrorMessage(.{
+ .msg = try eb.printString("dependency loop with length {d}", .{units.items.len}),
+ .src_loc = .none,
+ .notes_len = @intCast(units.items.len + 1),
+ });
+ const notes_start = try eb.reserveNotes(@intCast(units.items.len + 1));
+ const notes: []std.zig.ErrorBundle.MessageIndex = @ptrCast(eb.extra.items[notes_start..]);
+ @memcpy(notes, note_buf);
+ }
+}
+fn addDependencyLoopErrorLine(
+ zcu: *Zcu,
+ eb: *std.zig.ErrorBundle.Wip,
+ source_unit: AnalUnit,
+ ref_trace: []const std.zig.ErrorBundle.ReferenceTrace,
+) (Allocator.Error || error{AlreadyReported})!std.zig.ErrorBundle.MessageIndex {
+ const ip = &zcu.intern_pool;
+ const comp = zcu.comp;
+
+ const fmt_source: std.fmt.Alt(FormatAnalUnit, formatDependencyLoopSourceUnit) = .{ .data = .{
+ .unit = source_unit,
+ .zcu = zcu,
+ } };
+
+ const dep_node = zcu.dependency_loop_nodes.get(source_unit).?;
+
+ const msg: std.zig.ErrorBundle.String = if (dep_node.unit == source_unit) switch (source_unit.unwrap()) {
+ .@"comptime" => unreachable, // cannot be involved in a dependency loop
+ .nav_ty, .nav_val => try eb.printString("{f} depends on itself here", .{fmt_source}),
+ .memoized_state => unreachable, // memoized_state definitely does not *directly* depend on itself
+ .func => try eb.printString("{f} uses its own inferred error set here", .{fmt_source}),
+ .type_layout => try eb.printString("{f} depends on itself {s}", .{
+ fmt_source,
+ dep_node.reason.type_layout_reason.msg(),
+ }),
+ .struct_defaults => |ty| try eb.printString(
+ "default field values of '{f}' depend on themselves for initialization here",
+ .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)},
+ ),
+ } else switch (dep_node.unit.unwrap()) {
+ .@"comptime" => unreachable, // cannot be involved in a dependency loop
+ .nav_val => |nav| try eb.printString("{f} uses value of declaration '{f}' here", .{
+ fmt_source, ip.getNav(nav).fqn.fmt(ip),
+ }),
+ .nav_ty => |nav| try eb.printString("{f} uses type of declaration '{f}' here", .{
+ fmt_source, ip.getNav(nav).fqn.fmt(ip),
+ }),
+ .memoized_state => |stage| switch (stage) {
+ .panic => try eb.printString("{f} requires panic handler for call here", .{fmt_source}),
+ else => try eb.printString("{f} requires 'std.builtin' declarations here", .{fmt_source}),
+ },
+ .func => |func| try eb.printString("{f} uses inferred error set of function '{f}' here", .{
+ fmt_source, ip.getNav(zcu.funcInfo(func).owner_nav).fqn.fmt(ip),
+ }),
+ .type_layout => |ty| try eb.printString("{f} depends on type '{f}' {s}", .{
+ fmt_source,
+ Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
+ dep_node.reason.type_layout_reason.msg(),
+ }),
+ .struct_defaults => |ty| try eb.printString(
+ "{f} uses default field values of '{f}' here",
+ .{ fmt_source, Type.fromInterned(ty).containerTypeName(ip).fmt(ip) },
+ ),
+ };
+
+ const src_loc = dep_node.reason.src.upgrade(zcu);
+ const source = src_loc.file_scope.getSource(zcu) catch |err| {
+ try Compilation.unableToLoadZcuFile(zcu, eb, src_loc.file_scope, err);
+ return error.AlreadyReported;
+ };
+ const span = src_loc.span(zcu) catch |err| {
+ try Compilation.unableToLoadZcuFile(zcu, eb, src_loc.file_scope, err);
+ return error.AlreadyReported;
+ };
+ const loc = std.zig.findLineColumn(source, span.main);
+ const eb_src = try eb.addSourceLocation(.{
+ .src_path = try eb.printString("{f}", .{src_loc.file_scope.path.fmt(comp)}),
+ .span_start = span.start,
+ .span_main = span.main,
+ .span_end = span.end,
+ .line = @intCast(loc.line),
+ .column = @intCast(loc.column),
+ .source_line = try eb.addString(loc.source_line),
+ .reference_trace_len = @intCast(ref_trace.len),
+ });
+ for (ref_trace) |rt| try eb.addReferenceTrace(rt);
+ return eb.addErrorMessage(.{
+ .msg = msg,
+ .src_loc = eb_src,
+ });
+}
+fn formatDependencyLoopSourceUnit(data: FormatAnalUnit, w: *Io.Writer) Io.Writer.Error!void {
+ const zcu = data.zcu;
+ const ip = &zcu.intern_pool;
+ switch (data.unit.unwrap()) {
+ .@"comptime" => unreachable, // cannot be involved in a dependency loop
+ .nav_val => |nav| try w.print("value of declaration '{f}'", .{ip.getNav(nav).fqn.fmt(ip)}),
+ .nav_ty => |nav| try w.print("type of declaration '{f}'", .{ip.getNav(nav).fqn.fmt(ip)}),
+ .memoized_state => |stage| switch (stage) {
+ .panic => try w.writeAll("panic handler"),
+ else => try w.writeAll("'std.builtin' declarations"),
+ },
+ .type_layout => |ty| try w.print("type '{f}'", .{
+ Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
+ }),
+ .struct_defaults => |ty| try w.print("default field value of '{f}'", .{
+ Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
+ }),
+ .func => |func| try w.print("function '{f}'", .{
+ ip.getNav(zcu.funcInfo(func).owner_nav).fqn.fmt(ip),
+ }),
+ }
+}
+
+pub fn populateReferenceTrace(
+ zcu: *Zcu,
+ root: AnalUnit,
+ frame_limit: u32,
+ eb: *std.zig.ErrorBundle.Wip,
+ ref_trace: *std.ArrayList(std.zig.ErrorBundle.ReferenceTrace),
+) Allocator.Error!void {
+ const ip = &zcu.intern_pool;
+ const gpa = zcu.comp.gpa;
+
+ if (frame_limit == 0) return;
+
+ const all_references = try zcu.resolveReferences();
+
+ var seen: std.AutoHashMapUnmanaged(InternPool.AnalUnit, void) = .empty;
+ defer seen.deinit(gpa);
+
+ var referenced_by = root;
+ while (all_references.get(referenced_by)) |maybe_ref| {
+ const ref = maybe_ref orelse break;
+ const gop = try seen.getOrPut(gpa, ref.referencer);
+ if (gop.found_existing) break;
+ if (ref_trace.items.len < frame_limit) {
+ var last_call_src = ref.src;
+ var opt_inline_frame = ref.inline_frame;
+ while (opt_inline_frame.unwrap()) |inline_frame| {
+ const f = inline_frame.ptr(zcu).*;
+ const func_nav = ip.indexToKey(f.callee).func.owner_nav;
+ const func_name = ip.getNav(func_nav).name.toSlice(ip);
+ addReferenceTraceFrame(zcu, eb, ref_trace, func_name, last_call_src, true) catch |err| switch (err) {
+ error.OutOfMemory => |e| return e,
+ error.AlreadyReported => {
+ // An incomplete reference trace isn't the end of the world; just cut it off.
+ return;
+ },
+ };
+ last_call_src = f.call_src;
+ opt_inline_frame = f.parent;
+ }
+ const root_name: ?[]const u8 = switch (ref.referencer.unwrap()) {
+ .@"comptime" => "comptime",
+ .nav_val, .nav_ty => |nav| ip.getNav(nav).name.toSlice(ip),
+ .type_layout, .struct_defaults => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),
+ .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip),
+ .memoized_state => null,
+ };
+ if (root_name) |n| {
+ addReferenceTraceFrame(zcu, eb, ref_trace, n, last_call_src, false) catch |err| switch (err) {
+ error.OutOfMemory => |e| return e,
+ error.AlreadyReported => {
+ // An incomplete reference trace isn't the end of the world; just cut it off.
+ return;
+ },
+ };
+ }
+ }
+ referenced_by = ref.referencer;
+ }
+
+ if (seen.count() > ref_trace.items.len) {
+ try ref_trace.append(gpa, .{
+ .decl_name = @intCast(seen.count() - ref_trace.items.len),
+ .src_loc = .none,
+ });
+ }
+}
+fn addReferenceTraceFrame(
+ zcu: *Zcu,
+ eb: *std.zig.ErrorBundle.Wip,
+ ref_trace: *std.ArrayList(std.zig.ErrorBundle.ReferenceTrace),
+ name: []const u8,
+ lazy_src: Zcu.LazySrcLoc,
+ inlined: bool,
+) error{ OutOfMemory, AlreadyReported }!void {
+ const gpa = zcu.gpa;
+ const src = lazy_src.upgrade(zcu);
+ const source = src.file_scope.getSource(zcu) catch |err| {
+ try Compilation.unableToLoadZcuFile(zcu, eb, src.file_scope, err);
+ return error.AlreadyReported;
+ };
+ const span = src.span(zcu) catch |err| {
+ try Compilation.unableToLoadZcuFile(zcu, eb, src.file_scope, err);
+ return error.AlreadyReported;
+ };
+ const loc = std.zig.findLineColumn(source, span.main);
+ try ref_trace.append(gpa, .{
+ .decl_name = try eb.printString("{s}{s}", .{ name, if (inlined) " [inlined]" else "" }),
+ .src_loc = try eb.addSourceLocation(.{
+ .src_path = try eb.printString("{f}", .{src.file_scope.path.fmt(zcu.comp)}),
+ .span_start = span.start,
+ .span_main = span.main,
+ .span_end = span.end,
+ .line = @intCast(loc.line),
+ .column = @intCast(loc.column),
+ .source_line = 0,
+ }),
+ });
+}
+
const TrackedUnitSema = struct {
/// `null` means we created the node, so should end it.
old_name: ?[std.Progress.Node.max_name_len]u8,
diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig
index 5472afc5f02682b3f9083b4d710e1c5616c74d57..4abfb5157ce8538a27dd8cbeec9d3a0ac6852901 100644
--- a/src/Zcu/PerThread.zig
+++ b/src/Zcu/PerThread.zig
@@ -27,7 +27,9 @@ const introspect = @import("../introspect.zig");
const Module = @import("../Package.zig").Module;
const Sema = @import("../Sema.zig");
const target_util = @import("../target.zig");
-const trace = @import("../tracy.zig").trace;
+const tracy = @import("../tracy.zig");
+const trace = tracy.trace;
+const traceNamed = tracy.traceNamed;
const Type = @import("../Type.zig");
const Value = @import("../Value.zig");
const Zcu = @import("../Zcu.zig");
@@ -125,6 +127,329 @@ pub fn deactivate(pt: Zcu.PerThread) void {
pt.zcu.intern_pool.deactivate();
}
+/// Called from `Compilation.performAllTheWork`. Performs one incremental update of the ZCU: detects
+/// changes to files, runs AstGen, and then enters the main semantic analysis loop, where we build
+/// up a graph of declarations, functions, etc, while also sending declarations and functions to
+/// codegen as they are analyzed.
+pub fn update(
+ pt: Zcu.PerThread,
+ main_progress_node: std.Progress.Node,
+ decl_work_timer: *?Compilation.Timer,
+) (Allocator.Error || Io.Cancelable)!void {
+ const zcu = pt.zcu;
+ const comp = zcu.comp;
+ const gpa = comp.gpa;
+ const io = comp.io;
+
+ {
+ const tracy_trace = traceNamed(@src(), "astgen");
+ defer tracy_trace.end();
+
+ const zir_prog_node = main_progress_node.start("AST Lowering", 0);
+ defer zir_prog_node.end();
+
+ var timer = comp.startTimer();
+ defer if (timer.finish(io)) |ns| {
+ comp.mutex.lockUncancelable(io);
+ defer comp.mutex.unlock(io);
+ comp.time_report.?.stats.real_ns_files = ns;
+ };
+
+ var astgen_group: Io.Group = .init;
+ defer astgen_group.cancel(io);
+
+ // We cannot reference `zcu.import_table` after we spawn any `workerUpdateFile` jobs,
+ // because on single-threaded targets the worker will be run eagerly, meaning the
+ // `import_table` could be mutated, and not even holding `comp.mutex` will save us. So,
+ // build up a list of the files to update *before* we spawn any jobs.
+ var astgen_work_items: std.MultiArrayList(struct {
+ file_index: Zcu.File.Index,
+ file: *Zcu.File,
+ }) = .empty;
+ defer astgen_work_items.deinit(gpa);
+ // Not every item in `import_table` will need updating, because some are builtin.zig
+ // files. However, most will, so let's just reserve sufficient capacity upfront.
+ try astgen_work_items.ensureTotalCapacity(gpa, zcu.import_table.count());
+ for (zcu.import_table.keys()) |file_index| {
+ const file = zcu.fileByIndex(file_index);
+ if (file.is_builtin) {
+ // This is a `builtin.zig`, so updating is redundant. However, we want to make
+ // sure the file contents are still correct on disk, since it can improve the
+ // debugging experience better. That job only needs `file`, so we can kick it
+ // off right now.
+ astgen_group.async(io, workerUpdateBuiltinFile, .{ comp, file });
+ continue;
+ }
+ astgen_work_items.appendAssumeCapacity(.{
+ .file_index = file_index,
+ .file = file,
+ });
+ }
+
+ // Now that we're not going to touch `zcu.import_table` again, we can spawn `workerUpdateFile` jobs.
+ for (astgen_work_items.items(.file_index), astgen_work_items.items(.file)) |file_index, file| {
+ astgen_group.async(io, workerUpdateFile, .{
+ comp, file, file_index, zir_prog_node, &astgen_group,
+ });
+ }
+
+ // On the other hand, it's fine to directly iterate `zcu.embed_table.keys()` here
+ // because `workerUpdateEmbedFile` can't invalidate it. The different here is that one
+ // `@embedFile` can't trigger analysis of a new `@embedFile`!
+ for (0.., zcu.embed_table.keys()) |ef_index_usize, ef| {
+ const ef_index: Zcu.EmbedFile.Index = @enumFromInt(ef_index_usize);
+ astgen_group.async(io, workerUpdateEmbedFile, .{
+ comp, ef_index, ef,
+ });
+ }
+
+ try astgen_group.await(io);
+ }
+
+ // On an incremental update, a source file might become "dead", in that all imports of
+ // the file were removed. This could even change what module the file belongs to! As such,
+ // we do a traversal over the files, to figure out which ones are alive and the modules
+ // they belong to.
+ const any_fatal_files = try pt.computeAliveFiles();
+
+ // If the cache mode is `whole`, add every alive source file to the manifest.
+ switch (comp.cache_use) {
+ .whole => |whole| if (whole.cache_manifest) |man| {
+ for (zcu.alive_files.keys()) |file_index| {
+ const file = zcu.fileByIndex(file_index);
+
+ switch (file.status) {
+ .never_loaded => unreachable, // AstGen tried to load it
+ .retryable_failure => continue, // the file cannot be read; this is a guaranteed error
+ .astgen_failure, .success => {}, // the file was read successfully
+ }
+
+ const path = try file.path.toAbsolute(comp.dirs, gpa);
+ defer gpa.free(path);
+
+ const result = res: {
+ try whole.cache_manifest_mutex.lock(io);
+ defer whole.cache_manifest_mutex.unlock(io);
+ if (file.source) |source| {
+ break :res man.addFilePostContents(path, source, file.stat);
+ } else {
+ break :res man.addFilePost(path);
+ }
+ };
+ result catch |err| switch (err) {
+ error.OutOfMemory => |e| return e,
+ else => {
+ try pt.reportRetryableFileError(file_index, "unable to update cache: {s}", .{@errorName(err)});
+ continue;
+ },
+ };
+ }
+ },
+ .none, .incremental => {},
+ }
+
+ if (comp.time_report) |*tr| {
+ tr.stats.n_reachable_files = @intCast(zcu.alive_files.count());
+ }
+
+ if (any_fatal_files or
+ zcu.multi_module_err != null or
+ zcu.failed_imports.items.len > 0 or
+ comp.alloc_failure_occurred)
+ {
+ // We give up right now! No updating of ZIR refs, no nothing. The idea is that this prevents
+ // us from invalidating lots of incremental dependencies due to files with e.g. parse errors.
+ // However, this means our analysis data is invalid, so we want to omit all analysis errors.
+ zcu.skip_analysis_this_update = true;
+ return;
+ }
+
+ if (comp.config.incremental) {
+ const update_zir_refs_node = main_progress_node.start("Update ZIR References", 0);
+ defer update_zir_refs_node.end();
+ try pt.updateZirRefs();
+ }
+
+ try zcu.flushRetryableFailures();
+
+ if (!zcu.backendSupportsFeature(.separate_thread)) {
+ // Close the ZCU task queue. Prelink may still be running, but the closed
+ // queue will cause the linker task to exit once prelink finishes. The
+ // closed queue also communicates to `enqueueZcu` that it should wait for
+ // the linker task to finish and then run ZCU tasks serially.
+ comp.link_queue.finishZcuQueue(comp);
+ }
+
+ zcu.sema_prog_node = main_progress_node.start("Semantic Analysis", 0);
+ if (comp.bin_file != null) {
+ zcu.codegen_prog_node = main_progress_node.start("Code Generation", 0);
+ }
+ // We increment `pending_codegen_jobs` so that it doesn't reach 0 until after analysis finishes.
+ // That prevents the "Code Generation" node from constantly disappearing and reappearing when
+ // we're probably going to analyze more functions at some point.
+ assert(zcu.pending_codegen_jobs.swap(1, .monotonic) == 0); // don't let this become 0 until analysis finishes
+
+ defer {
+ zcu.sema_prog_node.end();
+ zcu.sema_prog_node = .none;
+ if (zcu.pending_codegen_jobs.fetchSub(1, .monotonic) == 1) {
+ // Decremented to 0, so all done.
+ zcu.codegen_prog_node.end();
+ zcu.codegen_prog_node = .none;
+ }
+ }
+
+ // Start the timer for the "decls" part of the pipeline (Sema, CodeGen, link).
+ decl_work_timer.* = comp.startTimer();
+
+ // To kick off semantic analysis, populate the root source file of any module we have marked
+ // as an analysis root. Declarations in these files which want eager analysis---those being
+ // `comptime` declarations, any declarations marked `export`, and `test` declarations in the
+ // main module if this is a test compilation---become referenced, and so will be picked up
+ // up by the main semantic analysis loop below.
+ for (zcu.analysisRoots()) |analysis_root_mod| {
+ const analysis_root_file = zcu.module_roots.get(analysis_root_mod).?.unwrap().?;
+ try pt.ensureFilePopulated(analysis_root_file);
+ }
+
+ // This is the main semantic analysis loop, which is essentially the main loop of the whole
+ // Zig compilation pipeline. It selects some `AnalUnit` which we know needs to be analyzed,
+ // and analyzes it, which may in turn discover more `AnalUnit`s which we need to analyze.
+ while (try zcu.findOutdatedToAnalyze()) |unit| {
+ const tracy_trace = traceNamed(@src(), "analyze_outdated");
+ defer tracy_trace.end();
+
+ const maybe_err: Zcu.SemaError!void = switch (unit.unwrap()) {
+ .@"comptime" => |cu| pt.ensureComptimeUnitUpToDate(cu),
+ .nav_ty => |nav| pt.ensureNavTypeUpToDate(nav, null),
+ .nav_val => |nav| pt.ensureNavValUpToDate(nav, null),
+ .type_layout => |ty| pt.ensureTypeLayoutUpToDate(.fromInterned(ty), null),
+ .struct_defaults => |ty| res: {
+ // Unlike the other functions, this one requires that the type layout is resolved first.
+ pt.ensureTypeLayoutUpToDate(.fromInterned(ty), null) catch |err| switch (err) {
+ error.OutOfMemory,
+ error.Canceled,
+ => |e| return e,
+
+ error.AnalysisFail => {}, // already reported
+ };
+ break :res pt.ensureStructDefaultsUpToDate(.fromInterned(ty), null);
+ },
+ .memoized_state => |stage| pt.ensureMemoizedStateUpToDate(stage, null),
+ .func => |func| pt.ensureFuncBodyUpToDate(func, null),
+ };
+ maybe_err catch |err| switch (err) {
+ error.OutOfMemory,
+ error.Canceled,
+ => |e| return e,
+
+ error.AnalysisFail => {}, // already reported
+ };
+ }
+}
+fn workerUpdateBuiltinFile(comp: *Compilation, file: *Zcu.File) void {
+ Builtin.updateFileOnDisk(file, comp) catch |err| comp.lockAndSetMiscFailure(
+ .write_builtin_zig,
+ "unable to write '{f}': {s}",
+ .{ file.path.fmt(comp), @errorName(err) },
+ );
+}
+fn workerUpdateFile(
+ comp: *Compilation,
+ file: *Zcu.File,
+ file_index: Zcu.File.Index,
+ prog_node: std.Progress.Node,
+ group: *Io.Group,
+) void {
+ const io = comp.io;
+ const tid: Zcu.PerThread.Id = .acquire(io);
+ defer tid.release(io);
+
+ const child_prog_node = prog_node.start(std.fs.path.basename(file.path.sub_path), 0);
+ defer child_prog_node.end();
+
+ const pt: Zcu.PerThread = .activate(comp.zcu.?, tid);
+ defer pt.deactivate();
+ pt.updateFile(file_index, file) catch |err| {
+ pt.reportRetryableFileError(file_index, "unable to load '{s}': {s}", .{ std.fs.path.basename(file.path.sub_path), @errorName(err) }) catch |oom| switch (oom) {
+ error.OutOfMemory => {
+ comp.mutex.lockUncancelable(io);
+ defer comp.mutex.unlock(io);
+ comp.setAllocFailure();
+ },
+ };
+ return;
+ };
+
+ switch (file.getMode()) {
+ .zig => {}, // continue to logic below
+ .zon => return, // ZON can't import anything so we're done
+ }
+
+ // Discover all imports in the file. Imports of modules we ignore for now since we don't
+ // know which module we're in, but imports of file paths might need us to queue up other
+ // AstGen jobs.
+ const imports_index = file.zir.?.extra[@intFromEnum(Zir.ExtraIndex.imports)];
+ if (imports_index != 0) {
+ const extra = file.zir.?.extraData(Zir.Inst.Imports, imports_index);
+ var import_i: u32 = 0;
+ var extra_index = extra.end;
+
+ while (import_i < extra.data.imports_len) : (import_i += 1) {
+ const item = file.zir.?.extraData(Zir.Inst.Imports.Item, extra_index);
+ extra_index = item.end;
+
+ const import_path = file.zir.?.nullTerminatedString(item.data.name);
+
+ if (pt.discoverImport(file.path, import_path)) |res| switch (res) {
+ .module, .existing_file => {},
+ .new_file => |new| {
+ group.async(io, workerUpdateFile, .{
+ comp, new.file, new.index, prog_node, group,
+ });
+ },
+ } else |err| switch (err) {
+ error.OutOfMemory => {
+ comp.mutex.lockUncancelable(io);
+ defer comp.mutex.unlock(io);
+ comp.setAllocFailure();
+ },
+ }
+ }
+ }
+}
+fn workerUpdateEmbedFile(comp: *Compilation, ef_index: Zcu.EmbedFile.Index, ef: *Zcu.EmbedFile) void {
+ const io = comp.io;
+ const tid: Zcu.PerThread.Id = .acquire(io);
+ defer tid.release(io);
+ detectEmbedFileUpdate(comp, tid, ef_index, ef) catch |err| switch (err) {
+ error.OutOfMemory => {
+ comp.mutex.lockUncancelable(io);
+ defer comp.mutex.unlock(io);
+ comp.setAllocFailure();
+ },
+ };
+}
+fn detectEmbedFileUpdate(comp: *Compilation, tid: Zcu.PerThread.Id, ef_index: Zcu.EmbedFile.Index, ef: *Zcu.EmbedFile) !void {
+ const io = comp.io;
+ const zcu = comp.zcu.?;
+ const pt: Zcu.PerThread = .activate(zcu, tid);
+ defer pt.deactivate();
+
+ const old_val = ef.val;
+ const old_err = ef.err;
+
+ try pt.updateEmbedFile(ef, null);
+
+ if (ef.val != .none and ef.val == old_val) return; // success, value unchanged
+ if (ef.val == .none and old_val == .none and ef.err == old_err) return; // failure, error unchanged
+
+ comp.mutex.lockUncancelable(io);
+ defer comp.mutex.unlock(io);
+
+ try zcu.markDependeeOutdated(.not_marked_po, .{ .embed_file = ef_index });
+}
+
fn deinitFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) void {
const zcu = pt.zcu;
const gpa = zcu.gpa;
@@ -156,8 +481,8 @@ pub fn updateFile(
) !void {
dev.check(.ast_gen);
- const tracy = trace(@src());
- defer tracy.end();
+ const tracy_trace = trace(@src());
+ defer tracy_trace.end();
const zcu = pt.zcu;
const comp = zcu.comp;
@@ -484,7 +809,7 @@ fn cleanupUpdatedFiles(gpa: Allocator, updated_files: *std.AutoArrayHashMapUnman
updated_files.deinit(gpa);
}
-pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
+fn updateZirRefs(pt: Zcu.PerThread) (Io.Cancelable || Allocator.Error)!void {
assert(pt.tid == .main);
const zcu = pt.zcu;
const comp = zcu.comp;
@@ -566,7 +891,7 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
const old_line = old_zir.getDeclaration(old_inst).src_line;
const new_line = new_zir.getDeclaration(new_inst).src_line;
if (old_line != new_line) {
- try comp.queueJob(.{ .update_line_number = tracked_inst_index });
+ try comp.link_queue.enqueueZcu(comp, pt.tid, .{ .debug_update_line_number = tracked_inst_index });
}
},
else => {},
@@ -598,44 +923,38 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
// Value is whether the declaration is `pub`.
var old_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, bool) = .empty;
defer old_names.deinit(zcu.gpa);
- {
- var it = old_zir.declIterator(old_inst);
- while (it.next()) |decl_inst| {
- const old_decl = old_zir.getDeclaration(decl_inst);
- if (old_decl.name == .empty) continue;
- const name_ip = try zcu.intern_pool.getOrPutString(
- zcu.gpa,
- io,
- pt.tid,
- old_zir.nullTerminatedString(old_decl.name),
- .no_embedded_nulls,
- );
- try old_names.put(zcu.gpa, name_ip, old_decl.is_pub);
- }
+ for (old_zir.typeDecls(old_inst)) |decl_inst| {
+ const old_decl = old_zir.getDeclaration(decl_inst);
+ if (old_decl.name == .empty) continue;
+ const name_ip = try zcu.intern_pool.getOrPutString(
+ zcu.gpa,
+ io,
+ pt.tid,
+ old_zir.nullTerminatedString(old_decl.name),
+ .no_embedded_nulls,
+ );
+ try old_names.put(zcu.gpa, name_ip, old_decl.is_pub);
}
var any_change = false;
- {
- var it = new_zir.declIterator(new_inst);
- while (it.next()) |decl_inst| {
- const new_decl = new_zir.getDeclaration(decl_inst);
- if (new_decl.name == .empty) continue;
- const name_ip = try zcu.intern_pool.getOrPutString(
- zcu.gpa,
- io,
- pt.tid,
- new_zir.nullTerminatedString(new_decl.name),
- .no_embedded_nulls,
- );
- if (old_names.fetchSwapRemove(name_ip)) |kv| {
- if (kv.value == new_decl.is_pub) continue;
- }
- // Name added, or changed whether it's pub
- any_change = true;
- try zcu.markDependeeOutdated(.not_marked_po, .{ .namespace_name = .{
- .namespace = tracked_inst_index,
- .name = name_ip,
- } });
+ for (new_zir.typeDecls(new_inst)) |decl_inst| {
+ const new_decl = new_zir.getDeclaration(decl_inst);
+ if (new_decl.name == .empty) continue;
+ const name_ip = try zcu.intern_pool.getOrPutString(
+ zcu.gpa,
+ io,
+ pt.tid,
+ new_zir.nullTerminatedString(new_decl.name),
+ .no_embedded_nulls,
+ );
+ if (old_names.fetchSwapRemove(name_ip)) |kv| {
+ if (kv.value == new_decl.is_pub) continue;
}
+ // Name added, or changed whether it's pub
+ any_change = true;
+ try zcu.markDependeeOutdated(.not_marked_po, .{ .namespace_name = .{
+ .namespace = tracked_inst_index,
+ .name = name_ip,
+ } });
}
// The only elements remaining in `old_names` now are any names which were removed.
for (old_names.keys()) |name_ip| {
@@ -674,32 +993,74 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
}
}
-/// Ensures that `zcu.fileRootType` on this `file_index` gives an up-to-date answer.
-/// Returns `error.AnalysisFail` if the file has an error.
-pub fn ensureFileAnalyzed(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {
- const file_root_type = pt.zcu.fileRootType(file_index);
- if (file_root_type != .none) {
- if (pt.ensureTypeUpToDate(file_root_type)) |_| {
- return;
- } else |err| switch (err) {
- error.AnalysisFail => {
- // The file's root `struct_decl` has, at some point, been lost, because the file failed AstGen.
- // Clear `file_root_type`, and try the `semaFile` call below, in case the instruction has since
- // been discovered under a new `TrackedInst.Index`.
- pt.zcu.setFileRootType(file_index, .none);
- },
- else => |e| return e,
- }
- }
- return pt.semaFile(file_index);
+/// Ensures that `zcu.fileRootType` on this `file_index` is populated (not `.none`). This implies
+/// that the file's namespace is scanned, discovering declarations.
+///
+/// Typical Zig compilations begin by claling this function on the root source file of the standard
+/// library, `lib/std/std.zig`. The resulting namespace scan discovers a `comptime` declaration in
+/// that file, which is queued for analysis, and everything goes from there.
+pub fn ensureFilePopulated(pt: Zcu.PerThread, file_index: Zcu.File.Index) (Allocator.Error || Io.Cancelable)!void {
+ dev.check(.sema);
+
+ const tracy_trace = trace(@src());
+ defer tracy_trace.end();
+
+ const zcu = pt.zcu;
+ const comp = zcu.comp;
+ const io = comp.io;
+ const gpa = comp.gpa;
+ const ip = &zcu.intern_pool;
+
+ if (zcu.fileRootType(file_index) != .none) return; // already good
+
+ if (zcu.comp.time_report) |*tr| tr.stats.n_imported_files += 1;
+
+ const file = zcu.fileByIndex(file_index);
+ assert(file.getMode() == .zig);
+ const struct_decl = file.zir.?.getStructDecl(.main_struct_inst);
+ const tracked_inst = try ip.trackZir(gpa, io, pt.tid, .{
+ .file = file_index,
+ .inst = .main_struct_inst,
+ });
+ const wip: InternPool.WipContainerType = switch (try ip.getDeclaredStructType(gpa, io, pt.tid, .{
+ .zir_index = tracked_inst,
+ .captures = &.{},
+ .fields_len = @intCast(struct_decl.field_names.len),
+ .layout = struct_decl.layout,
+ .any_comptime_fields = struct_decl.field_comptime_bits != null,
+ .any_field_defaults = struct_decl.field_default_body_lens != null,
+ .any_field_aligns = struct_decl.field_align_body_lens != null,
+ .packed_backing_mode = if (struct_decl.backing_int_type_body != null) .explicit else .auto,
+ })) {
+ .existing => unreachable, // it would have been set as `zcu.fileRootType` already
+ .wip => |wip| wip,
+ };
+ errdefer wip.cancel(ip, pt.tid);
+
+ wip.setName(ip, try file.internFullyQualifiedName(pt), .none);
+ const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
+ .parent = .none,
+ .owner_type = wip.index,
+ .file_scope = file_index,
+ .generation = zcu.generation,
+ });
+ errdefer pt.destroyNamespace(new_namespace_index);
+ try pt.scanNamespace(new_namespace_index, struct_decl.decls);
+ if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
+ zcu.setFileRootType(file_index, wip.finish(ip, new_namespace_index));
}
/// Ensures that all memoized state on `Zcu` is up-to-date, performing re-analysis if necessary.
/// Returns `error.AnalysisFail` if an analysis error is encountered; the caller is free to ignore
/// this, since the error is already registered, but it must not use the value of memoized fields.
-pub fn ensureMemoizedStateUpToDate(pt: Zcu.PerThread, stage: InternPool.MemoizedStateStage) Zcu.SemaError!void {
- const tracy = trace(@src());
- defer tracy.end();
+pub fn ensureMemoizedStateUpToDate(
+ pt: Zcu.PerThread,
+ stage: InternPool.MemoizedStateStage,
+ /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`.
+ reason: ?*const Zcu.DependencyReason,
+) Zcu.SemaError!void {
+ const tracy_trace = trace(@src());
+ defer tracy_trace.end();
const zcu = pt.zcu;
const gpa = zcu.gpa;
@@ -710,19 +1071,11 @@ pub fn ensureMemoizedStateUpToDate(pt: Zcu.PerThread, stage: InternPool.Memoized
assert(!zcu.analysis_in_progress.contains(unit));
- const was_outdated = zcu.outdated.swapRemove(unit) or zcu.potentially_outdated.swapRemove(unit);
+ const was_outdated = zcu.clearOutdatedState(unit);
const prev_failed = zcu.failed_analysis.contains(unit) or zcu.transitive_failed_analysis.contains(unit);
if (was_outdated) {
- dev.check(.incremental);
- _ = zcu.outdated_ready.swapRemove(unit);
- // No need for `deleteUnitExports` because we never export anything.
- zcu.deleteUnitReferences(unit);
- zcu.deleteUnitCompileLogs(unit);
- if (zcu.failed_analysis.fetchSwapRemove(unit)) |kv| {
- kv.value.destroy(gpa);
- }
- _ = zcu.transitive_failed_analysis.swapRemove(unit);
+ zcu.resetUnit(unit);
} else {
if (prev_failed) return error.AnalysisFail;
// We use an arbitrary element to check if the state has been resolved yet.
@@ -741,7 +1094,7 @@ pub fn ensureMemoizedStateUpToDate(pt: Zcu.PerThread, stage: InternPool.Memoized
info.deps.clearRetainingCapacity();
}
- const any_changed: bool, const new_failed: bool = if (pt.analyzeMemoizedState(stage)) |any_changed|
+ const any_changed: bool, const new_failed: bool = if (pt.analyzeMemoizedState(stage, reason)) |any_changed|
.{ any_changed or prev_failed, false }
else |err| switch (err) {
error.AnalysisFail => res: {
@@ -774,39 +1127,20 @@ pub fn ensureMemoizedStateUpToDate(pt: Zcu.PerThread, stage: InternPool.Memoized
if (new_failed) return error.AnalysisFail;
}
-fn analyzeMemoizedState(pt: Zcu.PerThread, stage: InternPool.MemoizedStateStage) Zcu.CompileError!bool {
+fn analyzeMemoizedState(
+ pt: Zcu.PerThread,
+ stage: InternPool.MemoizedStateStage,
+ reason: ?*const Zcu.DependencyReason,
+) Zcu.CompileError!bool {
const zcu = pt.zcu;
- const ip = &zcu.intern_pool;
const comp = zcu.comp;
const gpa = comp.gpa;
- const io = comp.io;
const unit: AnalUnit = .wrap(.{ .memoized_state = stage });
- try zcu.analysis_in_progress.putNoClobber(gpa, unit, {});
+ try zcu.analysis_in_progress.putNoClobber(gpa, unit, reason);
defer assert(zcu.analysis_in_progress.swapRemove(unit));
- // Before we begin, collect:
- // * The type `std`, and its namespace
- // * The type `std.builtin`, and its namespace
- // * A semi-reasonable source location
- const std_file_index = zcu.module_roots.get(zcu.std_mod).?.unwrap().?;
- try pt.ensureFileAnalyzed(std_file_index);
- const std_type: Type = .fromInterned(zcu.fileRootType(std_file_index));
- const std_namespace = std_type.getNamespaceIndex(zcu);
- try pt.ensureNamespaceUpToDate(std_namespace);
- const builtin_str = try ip.getOrPutString(gpa, io, pt.tid, "builtin", .no_embedded_nulls);
- const builtin_nav = zcu.namespacePtr(std_namespace).pub_decls.getKeyAdapted(builtin_str, Zcu.Namespace.NameAdapter{ .zcu = zcu }) orelse
- @panic("lib/std.zig is corrupt and missing 'builtin'");
- try pt.ensureNavValUpToDate(builtin_nav);
- const builtin_type: Type = .fromInterned(ip.getNav(builtin_nav).status.fully_resolved.val);
- const builtin_namespace = builtin_type.getNamespaceIndex(zcu);
- try pt.ensureNamespaceUpToDate(builtin_namespace);
- const src: Zcu.LazySrcLoc = .{
- .base_node_inst = builtin_type.typeDeclInst(zcu).?,
- .offset = .{ .byte_abs = 0 },
- };
-
var analysis_arena: std.heap.ArenaAllocator = .init(gpa);
defer analysis_arena.deinit();
@@ -827,30 +1161,15 @@ fn analyzeMemoizedState(pt: Zcu.PerThread, stage: InternPool.MemoizedStateStage)
};
defer sema.deinit();
- var block: Sema.Block = .{
- .parent = null,
- .sema = &sema,
- .namespace = std_namespace,
- .instructions = .{},
- .inlining = null,
- .comptime_reason = .{ .reason = .{
- .src = src,
- .r = .{ .simple = .type },
- } },
- .src_base_inst = src.base_node_inst,
- .type_name_ctx = .empty,
- };
- defer block.instructions.deinit(gpa);
-
- return sema.analyzeMemoizedState(&block, src, builtin_namespace, stage);
+ return sema.analyzeMemoizedState(stage);
}
/// Ensures that the state of the given `ComptimeUnit` is fully up-to-date, performing re-analysis
/// if necessary. Returns `error.AnalysisFail` if an analysis error is encountered; the caller is
/// free to ignore this, since the error is already registered.
pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu.SemaError!void {
- const tracy = trace(@src());
- defer tracy.end();
+ const tracy_trace = trace(@src());
+ defer tracy_trace.end();
const zcu = pt.zcu;
const gpa = zcu.gpa;
@@ -870,22 +1189,10 @@ pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeU
// result in over-analysis if analysis occurs in a poor order; we do our best to avoid this by
// carefully choosing which units to re-analyze. See `Zcu.findOutdatedToAnalyze`.
- const was_outdated = zcu.outdated.swapRemove(anal_unit) or
- zcu.potentially_outdated.swapRemove(anal_unit);
+ const was_outdated = zcu.clearOutdatedState(anal_unit);
if (was_outdated) {
- _ = zcu.outdated_ready.swapRemove(anal_unit);
- // `was_outdated` can be true in the initial update for comptime units, so this isn't a `dev.check`.
- if (dev.env.supports(.incremental)) {
- zcu.deleteUnitExports(anal_unit);
- zcu.deleteUnitReferences(anal_unit);
- zcu.deleteUnitCompileLogs(anal_unit);
- if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| {
- kv.value.destroy(gpa);
- }
- _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
- zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit);
- }
+ zcu.resetUnit(anal_unit);
} else {
// We can trust the current information about this unit.
if (zcu.failed_analysis.contains(anal_unit)) return error.AnalysisFail;
@@ -950,7 +1257,7 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu
const file = zcu.fileByIndex(inst_resolved.file);
const zir = file.zir.?;
- try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, {});
+ try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, null);
defer assert(zcu.analysis_in_progress.swapRemove(anal_unit));
var analysis_arena: std.heap.ArenaAllocator = .init(gpa);
@@ -980,7 +1287,7 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu
.parent = null,
.sema = &sema,
.namespace = comptime_unit.namespace,
- .instructions = .{},
+ .instructions = .empty,
.inlining = null,
.comptime_reason = .{ .reason = .{
.src = .{
@@ -1012,33 +1319,262 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu
try sema.flushExports();
}
+/// Ensures that the layout of the given `struct`, `union`, or `enum` type is fully up-to-date,
+/// performing re-analysis if necessary. Asserts that `ty` is a struct (not a tuple!), union, or
+/// enum type. Returns `error.AnalysisFail` if an analysis error is encountered during type
+/// resolution; the caller is free to ignore this, since the error is already registered.
+pub fn ensureTypeLayoutUpToDate(
+ pt: Zcu.PerThread,
+ ty: Type,
+ /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`.
+ reason: ?*const Zcu.DependencyReason,
+) Zcu.SemaError!void {
+ const tracy_trace = trace(@src());
+ defer tracy_trace.end();
+
+ const zcu = pt.zcu;
+ const ip = &zcu.intern_pool;
+ const comp = zcu.comp;
+ const gpa = comp.gpa;
+
+ const anal_unit: AnalUnit = .wrap(.{ .type_layout = ty.toIntern() });
+
+ log.debug("ensureTypeLayoutUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)});
+
+ assert(!zcu.analysis_in_progress.contains(anal_unit));
+
+ const was_outdated: bool = outdated: {
+ if (zcu.clearOutdatedState(anal_unit)) break :outdated true;
+ if (ip.setWantTypeLayout(comp.io, ty.toIntern())) {
+ // We'll analyze the layout for the first time, but if this is a struct type then its
+ // default field values also need to be analyzed.
+ if (ip.indexToKey(ty.toIntern()) == .struct_type) {
+ if (std.debug.runtime_safety) zcu.outdated_lock.lockUncancelable(zcu.comp.io);
+ defer if (std.debug.runtime_safety) zcu.outdated_lock.unlock(zcu.comp.io);
+ try zcu.outdated.ensureUnusedCapacity(gpa, 1);
+ try zcu.outdated_ready.other.ensureUnusedCapacity(gpa, 1);
+ zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .struct_defaults = ty.toIntern() }), 0);
+ zcu.outdated_ready.other.putAssumeCapacityNoClobber(.wrap(.{ .struct_defaults = ty.toIntern() }), {});
+ }
+ break :outdated true;
+ }
+ break :outdated false;
+ };
+
+ if (was_outdated) {
+ zcu.resetUnit(anal_unit);
+ // For types, we already know that we have to invalidate all dependees.
+ // TODO: we actually *could* detect whether everything was the same. should we bother?
+ try zcu.markDependeeOutdated(.marked_po, .{ .type_layout = ty.toIntern() });
+ } else {
+ // We can trust the current information about this unit.
+ if (zcu.failed_analysis.contains(anal_unit)) return error.AnalysisFail;
+ if (zcu.transitive_failed_analysis.contains(anal_unit)) return error.AnalysisFail;
+ return;
+ }
+
+ if (comp.debugIncremental()) {
+ const info = try zcu.incremental_debug_state.getUnitInfo(gpa, anal_unit);
+ info.last_update_gen = zcu.generation;
+ info.deps.clearRetainingCapacity();
+ }
+
+ const unit_tracking = zcu.trackUnitSema(ty.containerTypeName(ip).toSlice(ip), null);
+ defer unit_tracking.end(zcu);
+
+ try zcu.analysis_in_progress.put(gpa, anal_unit, reason);
+ defer assert(zcu.analysis_in_progress.swapRemove(anal_unit));
+
+ var analysis_arena: std.heap.ArenaAllocator = .init(gpa);
+ defer analysis_arena.deinit();
+
+ var comptime_err_ret_trace: std.array_list.Managed(Zcu.LazySrcLoc) = .init(gpa);
+ defer comptime_err_ret_trace.deinit();
+
+ const file = zcu.namespacePtr(ty.getNamespaceIndex(zcu)).fileScope(zcu);
+
+ var sema: Sema = .{
+ .pt = pt,
+ .gpa = gpa,
+ .arena = analysis_arena.allocator(),
+ .code = file.zir.?,
+ .owner = anal_unit,
+ .func_index = .none,
+ .func_is_naked = false,
+ .fn_ret_ty = .void,
+ .fn_ret_ty_ies = null,
+ .comptime_err_ret_trace = &comptime_err_ret_trace,
+ };
+ defer sema.deinit();
+
+ const result = switch (ty.zigTypeTag(zcu)) {
+ .@"enum" => Sema.type_resolution.resolveEnumLayout(&sema, ty),
+ .@"struct" => Sema.type_resolution.resolveStructLayout(&sema, ty),
+ .@"union" => Sema.type_resolution.resolveUnionLayout(&sema, ty),
+ else => unreachable,
+ };
+ const new_failed: bool = if (result) failed: {
+ break :failed false;
+ } else |err| switch (err) {
+ error.AnalysisFail => failed: {
+ if (!zcu.failed_analysis.contains(anal_unit)) {
+ // If this unit caused the error, it would have an entry in `failed_analysis`.
+ // Since it does not, this must be a transitive failure.
+ try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});
+ log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(anal_unit)});
+ }
+ break :failed true;
+ },
+ error.OutOfMemory,
+ error.Canceled,
+ => |e| return e,
+ error.ComptimeReturn => unreachable,
+ error.ComptimeBreak => unreachable,
+ };
+
+ sema.flushExports() catch |err| switch (err) {
+ error.OutOfMemory => |e| return e,
+ };
+
+ // We don't need to `markDependeeOutdated`/`markPoDependeeUpToDate` here, because we already
+ // marked the layout as outdated at the top of this function. However, we do need to tell the
+ // debug info logic in the backend about this type.
+ comp.link_prog_node.increaseEstimatedTotalItems(1);
+ try comp.link_queue.enqueueZcu(comp, pt.tid, .{ .debug_update_container_type = .{
+ .ty = ty.toIntern(),
+ .success = !new_failed,
+ } });
+
+ if (new_failed) return error.AnalysisFail;
+}
+
+/// Ensures that the default field values of the given `struct` type are fully up-to-date,
+/// performing re-analysis if necessary. Asserts that `ty` is a struct (not a tuple!) type. Unlike
+/// the other "ensure X up to date" functions, this particular function also asserts that the
+/// *layout* of `ty` is *already* up-to-date (though it is okay for that resolution to have failed).
+/// Returns `error.AnalysisFail` if an analysis error is encountered while resolving the default
+/// field values; the caller is free to ignore this, since the error is already registered.
+pub fn ensureStructDefaultsUpToDate(
+ pt: Zcu.PerThread,
+ ty: Type,
+ /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`.
+ reason: ?*const Zcu.DependencyReason,
+) Zcu.SemaError!void {
+ const tracy_trace = trace(@src());
+ defer tracy_trace.end();
+
+ const zcu = pt.zcu;
+ const ip = &zcu.intern_pool;
+ const comp = zcu.comp;
+ const gpa = comp.gpa;
+
+ assert(ip.indexToKey(ty.toIntern()) == .struct_type);
+
+ const anal_unit: AnalUnit = .wrap(.{ .struct_defaults = ty.toIntern() });
+
+ log.debug("ensureStructDefaultsUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)});
+
+ assert(!zcu.analysis_in_progress.contains(anal_unit));
+
+ const was_outdated: bool = outdated: {
+ if (zcu.clearOutdatedState(anal_unit)) break :outdated true;
+ // The type layout should already be marked as "wanted" by this point, because a struct's
+ // layout must always be analyzed before its default values are.
+ assert(!ip.setWantTypeLayout(comp.io, ty.toIntern()));
+ break :outdated false;
+ };
+
+ if (was_outdated) {
+ zcu.resetUnit(anal_unit);
+ // For types, we already know that we have to invalidate all dependees.
+ // TODO: we actually *could* detect whether everything was the same. should we bother?
+ try zcu.markDependeeOutdated(.marked_po, .{ .struct_defaults = ty.toIntern() });
+ } else {
+ // We can trust the current information about this unit.
+ if (zcu.failed_analysis.contains(anal_unit)) return error.AnalysisFail;
+ if (zcu.transitive_failed_analysis.contains(anal_unit)) return error.AnalysisFail;
+ return;
+ }
+
+ if (zcu.comp.debugIncremental()) {
+ const info = try zcu.incremental_debug_state.getUnitInfo(gpa, anal_unit);
+ info.last_update_gen = zcu.generation;
+ info.deps.clearRetainingCapacity();
+ }
+
+ const unit_tracking = zcu.trackUnitSema(ty.containerTypeName(ip).toSlice(ip), null);
+ defer unit_tracking.end(zcu);
+
+ try zcu.analysis_in_progress.put(gpa, anal_unit, reason);
+ defer assert(zcu.analysis_in_progress.swapRemove(anal_unit));
+
+ var analysis_arena: std.heap.ArenaAllocator = .init(gpa);
+ defer analysis_arena.deinit();
+
+ var comptime_err_ret_trace: std.array_list.Managed(Zcu.LazySrcLoc) = .init(gpa);
+ defer comptime_err_ret_trace.deinit();
+
+ const file = zcu.namespacePtr(ty.getNamespaceIndex(zcu)).fileScope(zcu);
+
+ var sema: Sema = .{
+ .pt = pt,
+ .gpa = gpa,
+ .arena = analysis_arena.allocator(),
+ .code = file.zir.?,
+ .owner = anal_unit,
+ .func_index = .none,
+ .func_is_naked = false,
+ .fn_ret_ty = .void,
+ .fn_ret_ty_ies = null,
+ .comptime_err_ret_trace = &comptime_err_ret_trace,
+ };
+ defer sema.deinit();
+
+ const new_failed: bool = if (Sema.type_resolution.resolveStructDefaults(&sema, ty)) failed: {
+ break :failed false;
+ } else |err| switch (err) {
+ error.AnalysisFail => failed: {
+ if (!zcu.failed_analysis.contains(anal_unit)) {
+ // If this unit caused the error, it would have an entry in `failed_analysis`.
+ // Since it does not, this must be a transitive failure.
+ try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});
+ log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(anal_unit)});
+ }
+ break :failed true;
+ },
+ error.OutOfMemory,
+ error.Canceled,
+ => |e| return e,
+ error.ComptimeReturn => unreachable,
+ error.ComptimeBreak => unreachable,
+ };
+
+ sema.flushExports() catch |err| switch (err) {
+ error.OutOfMemory => |e| return e,
+ };
+
+ // We don't need to `markDependeeOutdated`/`markPoDependeeUpToDate` here, because we already
+ // marked the struct defaults as outdated at the top of this function.
+
+ if (new_failed) return error.AnalysisFail;
+}
+
/// Ensures that the resolved value of the given `Nav` is fully up-to-date, performing re-analysis
/// if necessary. Returns `error.AnalysisFail` if an analysis error is encountered; the caller is
/// free to ignore this, since the error is already registered.
-pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.SemaError!void {
- const tracy = trace(@src());
- defer tracy.end();
-
- // TODO: document this elsewhere mlugg!
- // For my own benefit, here's how a namespace update for a normal (non-file-root) type works:
- // `const S = struct { ... };`
- // We are adding or removing a declaration within this `struct`.
- // * `S` registers a dependency on `.{ .src_hash = (declaration of S) }`
- // * Any change to the `struct` body -- including changing a declaration -- invalidates this
- // * `S` is re-analyzed, but notes:
- // * there is an existing struct instance (at this `TrackedInst` with these captures)
- // * the struct's resolution is up-to-date (because nothing about the fields changed)
- // * so, it uses the same `struct`
- // * but this doesn't stop it from updating the namespace!
- // * we basically do `scanDecls`, updating the namespace as needed
- // * so everyone lived happily ever after
+pub fn ensureNavValUpToDate(
+ pt: Zcu.PerThread,
+ nav_id: InternPool.Nav.Index,
+ /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`.
+ reason: ?*const Zcu.DependencyReason,
+) Zcu.SemaError!void {
+ const tracy_trace = trace(@src());
+ defer tracy_trace.end();
const zcu = pt.zcu;
const gpa = zcu.gpa;
const ip = &zcu.intern_pool;
- _ = zcu.nav_val_analysis_queued.swapRemove(nav_id);
-
const anal_unit: AnalUnit = .wrap(.{ .nav_val = nav_id });
const nav = ip.getNav(nav_id);
@@ -1046,6 +1582,8 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu
assert(!zcu.analysis_in_progress.contains(anal_unit));
+ try zcu.ensureNavValAnalysisQueued(nav_id);
+
// Determine whether or not this `Nav`'s value is outdated. This also includes checking if the
// status is `.unresolved`, which indicates that the value is outdated because it has *never*
// been analyzed so far.
@@ -1055,30 +1593,18 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu
// result in over-analysis if analysis occurs in a poor order; we do our best to avoid this by
// carefully choosing which units to re-analyze. See `Zcu.findOutdatedToAnalyze`.
- const was_outdated = zcu.outdated.swapRemove(anal_unit) or
- zcu.potentially_outdated.swapRemove(anal_unit);
+ const was_outdated = zcu.clearOutdatedState(anal_unit);
const prev_failed = zcu.failed_analysis.contains(anal_unit) or
zcu.transitive_failed_analysis.contains(anal_unit);
if (was_outdated) {
- dev.check(.incremental);
- _ = zcu.outdated_ready.swapRemove(anal_unit);
- zcu.deleteUnitExports(anal_unit);
- zcu.deleteUnitReferences(anal_unit);
- zcu.deleteUnitCompileLogs(anal_unit);
- if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| {
- kv.value.destroy(gpa);
- }
- _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
- ip.removeDependenciesForDepender(gpa, anal_unit);
+ zcu.resetUnit(anal_unit);
} else {
// We can trust the current information about this unit.
if (prev_failed) return error.AnalysisFail;
- switch (nav.status) {
- .unresolved, .type_resolved => {},
- .fully_resolved => return,
- }
+ assert(nav.status == .fully_resolved);
+ return;
}
if (zcu.comp.debugIncremental()) {
@@ -1090,7 +1616,7 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu
const unit_tracking = zcu.trackUnitSema(nav.fqn.toSlice(ip), nav.srcInst(ip));
defer unit_tracking.end(zcu);
- const invalidate_value: bool, const new_failed: bool = if (pt.analyzeNavVal(nav_id)) |result| res: {
+ const invalidate_value: bool, const new_failed: bool = if (pt.analyzeNavVal(nav_id, reason)) |result| res: {
break :res .{
// If the unit has gone from failed to success, we still need to invalidate the dependencies.
result.val_changed or prev_failed,
@@ -1134,39 +1660,14 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu
}
}
- // If there isn't a type annotation, then we have also just resolved the type. That means the
- // the type is up-to-date, so it won't have the chance to mark its own dependency on the value;
- // we must do that ourselves.
- type_deps_on_val: {
- const inst_resolved = nav.analysis.?.zir_index.resolveFull(ip) orelse break :type_deps_on_val;
- const file = zcu.fileByIndex(inst_resolved.file);
- const zir_decl = file.zir.?.getDeclaration(inst_resolved.inst);
- if (zir_decl.type_body != null) break :type_deps_on_val;
- // The type does indeed depend on the value. We are responsible for populating all state of
- // the `nav_ty`, including exports, references, errors, and dependencies.
- const ty_unit: AnalUnit = .wrap(.{ .nav_ty = nav_id });
- const ty_was_outdated = zcu.outdated.swapRemove(ty_unit) or
- zcu.potentially_outdated.swapRemove(ty_unit);
- if (ty_was_outdated) {
- _ = zcu.outdated_ready.swapRemove(ty_unit);
- zcu.deleteUnitExports(ty_unit);
- zcu.deleteUnitReferences(ty_unit);
- zcu.deleteUnitCompileLogs(ty_unit);
- if (zcu.failed_analysis.fetchSwapRemove(ty_unit)) |kv| {
- kv.value.destroy(gpa);
- }
- _ = zcu.transitive_failed_analysis.swapRemove(ty_unit);
- ip.removeDependenciesForDepender(gpa, ty_unit);
- }
- try pt.addDependency(ty_unit, .{ .nav_val = nav_id });
- if (new_failed) try zcu.transitive_failed_analysis.put(gpa, ty_unit, {});
- if (ty_was_outdated) try zcu.markDependeeOutdated(.marked_po, .{ .nav_ty = nav_id });
- }
-
if (new_failed) return error.AnalysisFail;
}
-fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileError!struct { val_changed: bool } {
+fn analyzeNavVal(
+ pt: Zcu.PerThread,
+ nav_id: InternPool.Nav.Index,
+ reason: ?*const Zcu.DependencyReason,
+) Zcu.CompileError!struct { val_changed: bool } {
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const comp = zcu.comp;
@@ -1183,16 +1684,8 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
const zir = file.zir.?;
const zir_decl = zir.getDeclaration(inst_resolved.inst);
- try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, {});
- errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit);
-
- // If there's no type body, we are also resolving the type here.
- if (zir_decl.type_body == null) {
- try zcu.analysis_in_progress.putNoClobber(gpa, .wrap(.{ .nav_ty = nav_id }), {});
- }
- errdefer if (zir_decl.type_body == null) {
- _ = zcu.analysis_in_progress.swapRemove(.wrap(.{ .nav_ty = nav_id }));
- };
+ try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, reason);
+ defer assert(zcu.analysis_in_progress.swapRemove(anal_unit));
var analysis_arena: std.heap.ArenaAllocator = .init(gpa);
defer analysis_arena.deinit();
@@ -1225,7 +1718,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
.parent = null,
.sema = &sema,
.namespace = old_nav.analysis.?.namespace,
- .instructions = .{},
+ .instructions = .empty,
.inlining = null,
.comptime_reason = undefined, // set below
.src_base_inst = old_nav.analysis.?.zir_index,
@@ -1246,9 +1739,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
const maybe_ty: ?Type = if (zir_decl.type_body != null) ty: {
// Since we have a type body, the type is resolved separately!
- // Of course, we need to make sure we depend on it properly.
- try sema.declareDependency(.{ .nav_ty = nav_id });
- try pt.ensureNavTypeUpToDate(nav_id);
+ try sema.ensureNavResolved(&block, init_src, nav_id, .type);
break :ty .fromInterned(ip.getNav(nav_id).typeOf(ip));
} else null;
@@ -1271,9 +1762,6 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
const nav_ty: Type = maybe_ty orelse final_val.?.typeOf(zcu);
- // First, we must resolve the declaration's type. To do this, we analyze the type body if available,
- // or otherwise, we analyze the value body, populating `early_val` in the process.
-
const is_const = is_const: switch (zir_decl.kind) {
.@"comptime" => unreachable, // this is not a Nav
.unnamed_test, .@"test", .decltest => {
@@ -1360,7 +1848,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
// This resolves the type of the resolved value, not that value itself. If `nav_val` is a struct type,
// this resolves the type `type` (which needs no resolution), not the struct itself.
- try nav_ty.resolveLayout(pt);
+ try sema.ensureLayoutResolved(nav_ty, block.nodeOffset(.zero), if (zir_decl.kind == .@"var") .variable else .constant);
const queue_linker_work, const is_owned_fn = switch (ip.indexToKey(nav_val.toIntern())) {
.func => |f| .{ true, f.owner_nav == nav_id }, // note that this lets function aliases reach codegen
@@ -1377,23 +1865,47 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
if (zir_decl.align_body != null and !target_util.supportsFunctionAlignment(zcu.getTarget())) {
return sema.fail(&block, align_src, "target does not support function alignment", .{});
}
- } else if (try nav_ty.comptimeOnlySema(pt)) {
+ } else if (nav_ty.comptimeOnly(zcu)) {
// alignment, linksection, addrspace annotations are not allowed for comptime-only types.
- const reason: []const u8 = switch (ip.indexToKey(nav_val.toIntern())) {
+ const cannot_align_reason: []const u8 = switch (ip.indexToKey(nav_val.toIntern())) {
.func => "function alias", // slightly clearer message, since you *can* specify these on function *declarations*
else => "comptime-only type",
};
if (zir_decl.align_body != null) {
- return sema.fail(&block, align_src, "cannot specify alignment of {s}", .{reason});
+ return sema.fail(&block, align_src, "cannot specify alignment of {s}", .{cannot_align_reason});
}
if (zir_decl.linksection_body != null) {
- return sema.fail(&block, section_src, "cannot specify linksection of {s}", .{reason});
+ return sema.fail(&block, section_src, "cannot specify linksection of {s}", .{cannot_align_reason});
}
if (zir_decl.addrspace_body != null) {
- return sema.fail(&block, addrspace_src, "cannot specify addrspace of {s}", .{reason});
+ return sema.fail(&block, addrspace_src, "cannot specify addrspace of {s}", .{cannot_align_reason});
}
}
+ // We're about to resolve the value of the Nav. This causes the information about what the value
+ // was last update to be lost; therefore, if the `nav_ty` is currently out of date, it would
+ // incorrectly think it was unchanged when eventually analyzed. To avoid this, we need to detect
+ // that case and invalidate the dependee right now.
+ if (zcu.clearOutdatedState(.wrap(.{ .nav_ty = nav_id }))) {
+ assert(zir_decl.type_body == null); // otherwise we already resolved it with `Sema.ensureNavResolved`
+ zcu.resetUnit(.wrap(.{ .nav_ty = nav_id }));
+ try pt.addDependency(.wrap(.{ .nav_ty = nav_id }), .{ .nav_val = nav_id }); // inferred type depends on the value (that's us!)
+ if (comp.debugIncremental()) {
+ const info = try zcu.incremental_debug_state.getUnitInfo(gpa, .wrap(.{ .nav_ty = nav_id }));
+ info.last_update_gen = zcu.generation;
+ info.deps.clearRetainingCapacity();
+ }
+ const type_changed: bool = switch (old_nav.status) {
+ .unresolved => true,
+ .type_resolved => |old| old.type != nav_ty.toIntern(),
+ .fully_resolved => |old| ip.typeOf(old.val) != nav_ty.toIntern(),
+ };
+ if (type_changed) {
+ try zcu.markDependeeOutdated(.marked_po, .{ .nav_ty = nav_id });
+ } else {
+ try zcu.markPoDependeeUpToDate(.{ .nav_ty = nav_id });
+ }
+ }
ip.resolveNavValue(io, nav_id, .{
.val = nav_val.toIntern(),
.is_const = is_const,
@@ -1402,17 +1914,11 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
.@"addrspace" = modifiers.@"addrspace",
});
- // Mark the unit as completed before evaluating the export!
- assert(zcu.analysis_in_progress.swapRemove(anal_unit));
- if (zir_decl.type_body == null) {
- assert(zcu.analysis_in_progress.swapRemove(.wrap(.{ .nav_ty = nav_id })));
- }
-
if (zir_decl.linkage == .@"export") {
const export_src = block.src(.{ .token_offset = @enumFromInt(@intFromBool(zir_decl.is_pub)) });
const name_slice = zir.nullTerminatedString(zir_decl.name);
const name_ip = try ip.getOrPutString(gpa, io, pt.tid, name_slice, .no_embedded_nulls);
- try sema.analyzeExport(&block, export_src, .{ .name = name_ip }, nav_id);
+ try sema.analyzeExportSelfNav(&block, export_src, name_ip);
}
try sema.flushExports();
@@ -1420,25 +1926,37 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
queue_codegen: {
if (!queue_linker_work) break :queue_codegen;
- if (!try nav_ty.hasRuntimeBitsSema(pt)) {
- if (zcu.comp.config.use_llvm) break :queue_codegen;
+ if (!nav_ty.hasRuntimeBits(zcu)) {
+ if (comp.config.use_llvm) break :queue_codegen;
if (file.mod.?.strip) break :queue_codegen;
}
- // This job depends on any resolve_type_fully jobs queued up before it.
- zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
- try zcu.comp.queueJob(.{ .link_nav = nav_id });
+ comp.link_prog_node.increaseEstimatedTotalItems(1);
+ try comp.link_queue.enqueueZcu(comp, pt.tid, .{ .link_nav = nav_id });
}
- switch (old_nav.status) {
- .unresolved, .type_resolved => return .{ .val_changed = true },
- .fully_resolved => |old| return .{ .val_changed = old.val != nav_val.toIntern() },
+ if (comp.config.is_test and zcu.test_functions.contains(nav_id)) {
+ // We just analyzed a test function's "value" (essentially its signature); now we need to
+ // implicitly reference the function *body*. `Zcu.resolveReferences` knows about this rule,
+ // so we don't need to mark an explicit reference, but we do need to make sure that the test
+ // body will actually get analyzed!
+ try zcu.ensureFuncBodyAnalysisQueued(nav_val.toIntern());
}
+
+ return switch (old_nav.status) {
+ .unresolved, .type_resolved => .{ .val_changed = true },
+ .fully_resolved => |old| .{ .val_changed = old.val != nav_val.toIntern() },
+ };
}
-pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.SemaError!void {
- const tracy = trace(@src());
- defer tracy.end();
+pub fn ensureNavTypeUpToDate(
+ pt: Zcu.PerThread,
+ nav_id: InternPool.Nav.Index,
+ /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`.
+ reason: ?*const Zcu.DependencyReason,
+) Zcu.SemaError!void {
+ const tracy_trace = trace(@src());
+ defer tracy_trace.end();
const zcu = pt.zcu;
const gpa = zcu.gpa;
@@ -1451,17 +1969,7 @@ pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zc
assert(!zcu.analysis_in_progress.contains(anal_unit));
- const type_resolved_by_value: bool = from_val: {
- const analysis = nav.analysis orelse break :from_val false;
- const inst_resolved = analysis.zir_index.resolveFull(ip) orelse break :from_val false;
- const file = zcu.fileByIndex(inst_resolved.file);
- const zir_decl = file.zir.?.getDeclaration(inst_resolved.inst);
- break :from_val zir_decl.type_body == null;
- };
- if (type_resolved_by_value) {
- // Logic at the end of `ensureNavValUpToDate` is directly responsible for populating our state.
- return pt.ensureNavValUpToDate(nav_id);
- }
+ try zcu.ensureNavValAnalysisQueued(nav_id);
// Determine whether or not this `Nav`'s type is outdated. This also includes checking if the
// status is `.unresolved`, which indicates that the value is outdated because it has *never*
@@ -1472,30 +1980,18 @@ pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zc
// result in over-analysis if analysis occurs in a poor order; we do our best to avoid this by
// carefully choosing which units to re-analyze. See `Zcu.findOutdatedToAnalyze`.
- const was_outdated = zcu.outdated.swapRemove(anal_unit) or
- zcu.potentially_outdated.swapRemove(anal_unit);
+ const was_outdated = zcu.clearOutdatedState(anal_unit);
const prev_failed = zcu.failed_analysis.contains(anal_unit) or
zcu.transitive_failed_analysis.contains(anal_unit);
if (was_outdated) {
- dev.check(.incremental);
- _ = zcu.outdated_ready.swapRemove(anal_unit);
- zcu.deleteUnitExports(anal_unit);
- zcu.deleteUnitReferences(anal_unit);
- zcu.deleteUnitCompileLogs(anal_unit);
- if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| {
- kv.value.destroy(gpa);
- }
- _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
- ip.removeDependenciesForDepender(gpa, anal_unit);
+ zcu.resetUnit(anal_unit);
} else {
// We can trust the current information about this unit.
if (prev_failed) return error.AnalysisFail;
- switch (nav.status) {
- .unresolved => {},
- .type_resolved, .fully_resolved => return,
- }
+ assert(nav.status != .unresolved);
+ return;
}
if (zcu.comp.debugIncremental()) {
@@ -1507,7 +2003,7 @@ pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zc
const unit_tracking = zcu.trackUnitSema(nav.fqn.toSlice(ip), nav.srcInst(ip));
defer unit_tracking.end(zcu);
- const invalidate_type: bool, const new_failed: bool = if (pt.analyzeNavType(nav_id)) |result| res: {
+ const invalidate_type: bool, const new_failed: bool = if (pt.analyzeNavType(nav_id, reason)) |result| res: {
break :res .{
// If the unit has gone from failed to success, we still need to invalidate the dependencies.
result.type_changed or prev_failed,
@@ -1554,7 +2050,11 @@ pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zc
if (new_failed) return error.AnalysisFail;
}
-fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileError!struct { type_changed: bool } {
+fn analyzeNavType(
+ pt: Zcu.PerThread,
+ nav_id: InternPool.Nav.Index,
+ reason: ?*const Zcu.DependencyReason,
+) Zcu.CompileError!struct { type_changed: bool } {
const zcu = pt.zcu;
const comp = zcu.comp;
const gpa = comp.gpa;
@@ -1570,11 +2070,10 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
const file = zcu.fileByIndex(inst_resolved.file);
const zir = file.zir.?;
- try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, {});
+ try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, reason);
defer assert(zcu.analysis_in_progress.swapRemove(anal_unit));
const zir_decl = zir.getDeclaration(inst_resolved.inst);
- const type_body = zir_decl.type_body.?;
var analysis_arena: std.heap.ArenaAllocator = .init(gpa);
defer analysis_arena.deinit();
@@ -1607,7 +2106,7 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
.parent = null,
.sema = &sema,
.namespace = old_nav.analysis.?.namespace,
- .instructions = .{},
+ .instructions = .empty,
.inlining = null,
.comptime_reason = undefined, // set below
.src_base_inst = old_nav.analysis.?.zir_index,
@@ -1616,6 +2115,34 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
defer block.instructions.deinit(gpa);
const ty_src = block.src(.{ .node_offset_var_decl_ty = .zero });
+ const init_src = block.src(.{ .node_offset_var_decl_init = .zero });
+
+ const type_body = zir_decl.type_body orelse {
+ // There is no type annotation, so we just need to use the declaration's value.
+ // If the value had already been re-analyzed, it would have resolved the `nav_ty` unit as
+ // either outdated or up-to-date. So we know that `old_nav` does contain information from
+ // the previous update. As such, after this call, we will be able to determine whether the
+ // type changed.
+ try sema.ensureNavResolved(&block, init_src, nav_id, .fully);
+ const new = ip.getNav(nav_id).status.fully_resolved;
+ const new_is_extern_decl = ip.indexToKey(new.val) == .@"extern";
+ const changed = switch (old_nav.status) {
+ .unresolved => true,
+ .type_resolved => |r| r.type != ip.typeOf(new.val) or
+ r.alignment != new.alignment or
+ r.@"linksection" != new.@"linksection" or
+ r.@"addrspace" != new.@"addrspace" or
+ r.is_const != new.is_const or
+ r.is_extern_decl != new_is_extern_decl,
+ .fully_resolved => |r| ip.typeOf(r.val) != ip.typeOf(new.val) or
+ r.alignment != new.alignment or
+ r.@"linksection" != new.@"linksection" or
+ r.@"addrspace" != new.@"addrspace" or
+ r.is_const != new.is_const or
+ (old_nav.getExtern(ip) != null) != new_is_extern_decl,
+ };
+ return .{ .type_changed = changed };
+ };
block.comptime_reason = .{ .reason = .{
.src = ty_src,
@@ -1628,7 +2155,7 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
break :ty .fromInterned(type_ref.toInterned().?);
};
- try resolved_ty.resolveLayout(pt);
+ try sema.ensureLayoutResolved(resolved_ty, block.nodeOffset(.zero), if (zir_decl.kind == .@"var") .variable else .constant);
// In the case where the type is specified, this function is also responsible for resolving
// the pointer modifiers, i.e. alignment, linksection, addrspace.
@@ -1678,18 +2205,24 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
return .{ .type_changed = true };
}
-pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!void {
+/// If `func_index` is not a runtime function (e.g. it has a comptime-only parameter type) then it
+/// is still valid to call this function and use its `func_body` unit in general---analysis of the
+/// runtime function body will simply fail.
+pub fn ensureFuncBodyUpToDate(
+ pt: Zcu.PerThread,
+ func_index: InternPool.Index,
+ /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`.
+ reason: ?*const Zcu.DependencyReason,
+) Zcu.SemaError!void {
dev.check(.sema);
- const tracy = trace(@src());
- defer tracy.end();
+ const tracy_trace = trace(@src());
+ defer tracy_trace.end();
const zcu = pt.zcu;
const gpa = zcu.gpa;
const ip = &zcu.intern_pool;
- _ = zcu.func_body_analysis_queued.swapRemove(func_index);
-
const anal_unit: AnalUnit = .wrap(.{ .func = func_index });
log.debug("ensureFuncBodyUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)});
@@ -1700,27 +2233,17 @@ pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, func_index: InternPool.Index) Z
assert(func.ty == func.uncoerced_ty); // analyze the body of the original function, not a coerced one
- const was_outdated = zcu.outdated.swapRemove(anal_unit) or
- zcu.potentially_outdated.swapRemove(anal_unit);
+ const was_outdated = zcu.clearOutdatedState(anal_unit) or
+ ip.setWantRuntimeFnAnalysis(zcu.comp.io, func_index);
const prev_failed = zcu.failed_analysis.contains(anal_unit) or zcu.transitive_failed_analysis.contains(anal_unit);
if (was_outdated) {
- dev.check(.incremental);
- _ = zcu.outdated_ready.swapRemove(anal_unit);
- zcu.deleteUnitExports(anal_unit);
- zcu.deleteUnitReferences(anal_unit);
- zcu.deleteUnitCompileLogs(anal_unit);
- if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| {
- kv.value.destroy(gpa);
- }
- _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
+ zcu.resetUnit(anal_unit);
} else {
// We can trust the current information about this function.
- if (prev_failed) {
- return error.AnalysisFail;
- }
- if (func.analysisUnordered(ip).is_analyzed) return;
+ if (prev_failed) return error.AnalysisFail;
+ return;
}
if (zcu.comp.debugIncremental()) {
@@ -1736,7 +2259,7 @@ pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, func_index: InternPool.Index) Z
);
defer unit_tracking.end(zcu);
- const ies_outdated, const new_failed = if (pt.analyzeFuncBody(func_index)) |result|
+ const ies_outdated, const new_failed = if (pt.analyzeFuncBody(func_index, reason)) |result|
.{ prev_failed or result.ies_outdated, false }
else |err| switch (err) {
error.AnalysisFail => res: {
@@ -1765,9 +2288,9 @@ pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, func_index: InternPool.Index) Z
if (was_outdated) {
if (ies_outdated) {
- try zcu.markDependeeOutdated(.marked_po, .{ .interned = func_index });
+ try zcu.markDependeeOutdated(.marked_po, .{ .func_ies = func_index });
} else {
- try zcu.markPoDependeeUpToDate(.{ .interned = func_index });
+ try zcu.markPoDependeeUpToDate(.{ .func_ies = func_index });
}
}
@@ -1777,6 +2300,7 @@ pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, func_index: InternPool.Index) Z
fn analyzeFuncBody(
pt: Zcu.PerThread,
func_index: InternPool.Index,
+ reason: ?*const Zcu.DependencyReason,
) Zcu.SemaError!struct { ies_outdated: bool } {
const zcu = pt.zcu;
const gpa = zcu.gpa;
@@ -1785,29 +2309,6 @@ fn analyzeFuncBody(
const func = zcu.funcInfo(func_index);
const anal_unit = AnalUnit.wrap(.{ .func = func_index });
- // Make sure that this function is still owned by the same `Nav`. Otherwise, analyzing
- // it would be a waste of time in the best case, and could cause codegen to give bogus
- // results in the worst case.
-
- if (func.generic_owner == .none) {
- // Among another things, this ensures that the function's `zir_body_inst` is correct.
- try pt.ensureNavValUpToDate(func.owner_nav);
- if (ip.getNav(func.owner_nav).status.fully_resolved.val != func_index) {
- // This function is no longer referenced! There's no point in re-analyzing it.
- // Just mark a transitive failure and move on.
- return error.AnalysisFail;
- }
- } else {
- const go_nav = zcu.funcInfo(func.generic_owner).owner_nav;
- // Among another things, this ensures that the function's `zir_body_inst` is correct.
- try pt.ensureNavValUpToDate(go_nav);
- if (ip.getNav(go_nav).status.fully_resolved.val != func.generic_owner) {
- // The generic owner is no longer referenced, so this function is also unreferenced.
- // There's no point in re-analyzing it. Just mark a transitive failure and move on.
- return error.AnalysisFail;
- }
- }
-
// We'll want to remember what the IES used to be before the update for
// dependency invalidation purposes.
const old_resolved_ies = if (func.analysisUnordered(ip).inferred_error_set)
@@ -1817,8 +2318,9 @@ fn analyzeFuncBody(
log.debug("analyze and generate fn body {f}", .{zcu.fmtAnalUnit(anal_unit)});
- var air = try pt.analyzeFnBodyInner(func_index);
- errdefer air.deinit(gpa);
+ var air = try pt.analyzeFuncBodyInner(func_index, reason);
+ var air_owned = true;
+ defer if (air_owned) air.deinit(gpa);
const ies_outdated = !func.analysisUnordered(ip).inferred_error_set or
func.resolvedErrorSetUnordered(ip) != old_resolved_ies;
@@ -1828,105 +2330,26 @@ fn analyzeFuncBody(
const dump_air = build_options.enable_debug_extensions and comp.verbose_air;
const dump_llvm_ir = build_options.enable_debug_extensions and (comp.verbose_llvm_ir != null or comp.verbose_llvm_bc != null);
- if (comp.bin_file == null and zcu.llvm_object == null and !dump_air and !dump_llvm_ir) {
- air.deinit(gpa);
- return .{ .ies_outdated = ies_outdated };
+ if (comp.bin_file != null or zcu.llvm_object != null or dump_air or dump_llvm_ir) {
+ zcu.codegen_prog_node.increaseEstimatedTotalItems(1);
+ comp.link_prog_node.increaseEstimatedTotalItems(1);
+
+ // Some linkers need to refer to the AIR. In that case, the linker is not running
+ // concurrently, so we'll just keep ownership of the AIR for ourselves instead of
+ // letting the codegen job destroy it.
+ const disown_air = zcu.backendSupportsFeature(.separate_thread);
+
+ // Begin the codegen task. If the codegen/link queue is backed up, this might
+ // block until the linker is able to process some tasks.
+ const codegen_task = try zcu.codegen_task_pool.start(zcu, func_index, &air, disown_air);
+ if (disown_air) air_owned = false;
+
+ try comp.link_queue.enqueueZcu(comp, pt.tid, .{ .link_func = codegen_task });
}
- // This job depends on any resolve_type_fully jobs queued up before it.
- zcu.codegen_prog_node.increaseEstimatedTotalItems(1);
- comp.link_prog_node.increaseEstimatedTotalItems(1);
- try comp.queueJob(.{ .codegen_func = .{
- .func = func_index,
- .air = air,
- } });
-
return .{ .ies_outdated = ies_outdated };
}
-pub fn semaMod(pt: Zcu.PerThread, mod: *Module) !void {
- dev.check(.sema);
- const file_index = pt.zcu.module_roots.get(mod).?.unwrap().?;
- const root_type = pt.zcu.fileRootType(file_index);
- if (root_type == .none) {
- return pt.semaFile(file_index);
- }
-}
-
-fn createFileRootStruct(
- pt: Zcu.PerThread,
- file_index: Zcu.File.Index,
- namespace_index: Zcu.Namespace.Index,
- replace_existing: bool,
-) Allocator.Error!InternPool.Index {
- const zcu = pt.zcu;
- const gpa = zcu.gpa;
- const io = zcu.comp.io;
- const ip = &zcu.intern_pool;
- const file = zcu.fileByIndex(file_index);
- const extended = file.zir.?.instructions.items(.data)[@intFromEnum(Zir.Inst.Index.main_struct_inst)].extended;
- assert(extended.opcode == .struct_decl);
- const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
- assert(!small.has_captures_len);
- assert(!small.has_backing_int);
- assert(small.layout == .auto);
- var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).@"struct".fields.len;
- const fields_len = if (small.has_fields_len) blk: {
- const fields_len = file.zir.?.extra[extra_index];
- extra_index += 1;
- break :blk fields_len;
- } else 0;
- const decls_len = if (small.has_decls_len) blk: {
- const decls_len = file.zir.?.extra[extra_index];
- extra_index += 1;
- break :blk decls_len;
- } else 0;
- const decls = file.zir.?.bodySlice(extra_index, decls_len);
- extra_index += decls_len;
-
- const tracked_inst = try ip.trackZir(gpa, io, pt.tid, .{
- .file = file_index,
- .inst = .main_struct_inst,
- });
- const wip_ty = switch (try ip.getStructType(gpa, io, pt.tid, .{
- .layout = .auto,
- .fields_len = fields_len,
- .known_non_opv = small.known_non_opv,
- .requires_comptime = if (small.known_comptime_only) .yes else .unknown,
- .any_comptime_fields = small.any_comptime_fields,
- .any_default_inits = small.any_default_inits,
- .inits_resolved = false,
- .any_aligned_fields = small.any_aligned_fields,
- .key = .{ .declared = .{
- .zir_index = tracked_inst,
- .captures = &.{},
- } },
- }, replace_existing)) {
- .existing => unreachable, // we wouldn't be analysing the file root if this type existed
- .wip => |wip| wip,
- };
- errdefer wip_ty.cancel(ip, pt.tid);
-
- wip_ty.setName(ip, try file.internFullyQualifiedName(pt), .none);
- ip.namespacePtr(namespace_index).owner_type = wip_ty.index;
-
- if (zcu.comp.config.incremental) {
- try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = tracked_inst });
- }
-
- try pt.scanNamespace(namespace_index, decls);
- try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
- codegen_type: {
- if (file.mod.?.strip) break :codegen_type;
- // This job depends on any resolve_type_fully jobs queued up before it.
- zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
- try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
- }
- zcu.setFileRootType(file_index, wip_ty.index);
- if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
- return wip_ty.finish(ip, namespace_index);
-}
-
/// Re-scan the namespace of a file's root struct type on an incremental update.
/// The file must have successfully populated ZIR.
/// If the file's root struct type is not populated (the file is unreferenced), nothing is done.
@@ -1945,48 +2368,11 @@ fn updateFileNamespace(pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator.
});
const namespace_index = Type.fromInterned(file_root_type).getNamespaceIndex(zcu);
- const decls = decls: {
- const extended = file.zir.?.instructions.items(.data)[@intFromEnum(Zir.Inst.Index.main_struct_inst)].extended;
- const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
-
- var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).@"struct".fields.len;
- extra_index += @intFromBool(small.has_fields_len);
- const decls_len = if (small.has_decls_len) blk: {
- const decls_len = file.zir.?.extra[extra_index];
- extra_index += 1;
- break :blk decls_len;
- } else 0;
- break :decls file.zir.?.bodySlice(extra_index, decls_len);
- };
+ const decls = file.zir.?.getStructDecl(.main_struct_inst).decls;
try pt.scanNamespace(namespace_index, decls);
zcu.namespacePtr(namespace_index).generation = zcu.generation;
}
-fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {
- const tracy = trace(@src());
- defer tracy.end();
-
- const zcu = pt.zcu;
- const file = zcu.fileByIndex(file_index);
- assert(file.getMode() == .zig);
- assert(zcu.fileRootType(file_index) == .none);
-
- assert(file.zir != null);
-
- const new_namespace_index = try pt.createNamespace(.{
- .parent = .none,
- .owner_type = undefined, // set in `createFileRootStruct`
- .file_scope = file_index,
- .generation = zcu.generation,
- });
- const struct_ty = try pt.createFileRootStruct(file_index, new_namespace_index, false);
- errdefer zcu.intern_pool.remove(pt.tid, struct_ty);
-
- if (zcu.comp.time_report) |*tr| {
- tr.stats.n_imported_files += 1;
- }
-}
-
/// Called by AstGen worker threads when an import is seen. If `new_file` is returned, the caller is
/// then responsible for queueing a new AstGen job for the new file.
/// Assumes that `comp.mutex` is NOT locked. It will be locked by this function where necessary.
@@ -2214,7 +2600,7 @@ pub fn populateModuleRootTable(pt: Zcu.PerThread) error{
/// modify `pt.zcu.skip_analysis_this_update`.
///
/// If an error is returned, `pt.zcu.alive_files` might contain undefined values.
-pub fn computeAliveFiles(pt: Zcu.PerThread) Allocator.Error!bool {
+fn computeAliveFiles(pt: Zcu.PerThread) Allocator.Error!bool {
const zcu = pt.zcu;
const comp = zcu.comp;
const gpa = zcu.gpa;
@@ -2655,8 +3041,8 @@ pub fn scanNamespace(
namespace_index: Zcu.Namespace.Index,
decls: []const Zir.Inst.Index,
) Allocator.Error!void {
- const tracy = trace(@src());
- defer tracy.end();
+ const tracy_trace = trace(@src());
+ defer tracy_trace.end();
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
@@ -2752,8 +3138,8 @@ const ScanDeclIter = struct {
}
fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void {
- const tracy = trace(@src());
- defer tracy.end();
+ const tracy_trace = trace(@src());
+ defer tracy_trace.end();
const pt = iter.pt;
const zcu = pt.zcu;
@@ -2806,89 +3192,76 @@ const ScanDeclIter = struct {
const existing_unit = iter.existing_by_inst.get(tracked_inst);
- const unit, const want_analysis = switch (decl.kind) {
- .@"comptime" => unit: {
- const cu = if (existing_unit) |eu|
- eu.unwrap().@"comptime"
- else
- try ip.createComptimeUnit(gpa, io, pt.tid, tracked_inst, namespace_index);
-
- const unit: AnalUnit = .wrap(.{ .@"comptime" = cu });
-
+ const name = maybe_name.unwrap() orelse {
+ // Only `comptime` declarations are unnamed.
+ assert(decl.kind == .@"comptime");
+ if (existing_unit) |unit| {
+ try namespace.comptime_decls.append(gpa, unit.unwrap().@"comptime");
+ } else {
+ const cu = try ip.createComptimeUnit(gpa, io, pt.tid, tracked_inst, namespace_index);
+ try zcu.queueComptimeUnitAnalysis(cu);
try namespace.comptime_decls.append(gpa, cu);
+ }
+ return;
+ };
- if (existing_unit == null) {
- // For a `comptime` declaration, whether to analyze is based solely on whether the unit
- // is outdated. So, add this fresh one to `outdated` and `outdated_ready`.
- try zcu.outdated.ensureUnusedCapacity(gpa, 1);
- try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1);
- zcu.outdated.putAssumeCapacityNoClobber(unit, 0);
- zcu.outdated_ready.putAssumeCapacityNoClobber(unit, {});
- }
-
- break :unit .{ unit, true };
- },
- else => unit: {
- const name = maybe_name.unwrap().?;
- const fqn = try namespace.internFullyQualifiedName(ip, gpa, io, pt.tid, name);
- const nav = if (existing_unit) |eu| eu.unwrap().nav_val else nav: {
- const nav = try ip.createDeclNav(gpa, io, pt.tid, name, fqn, tracked_inst, namespace_index);
- if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newNav(zcu, nav);
- break :nav nav;
- };
-
- const unit: AnalUnit = .wrap(.{ .nav_val = nav });
+ const fqn = try namespace.internFullyQualifiedName(ip, gpa, io, pt.tid, name);
- assert(ip.getNav(nav).name == name);
- assert(ip.getNav(nav).fqn == fqn);
+ const nav = if (existing_unit) |unit| nav: {
+ const nav = unit.unwrap().nav_val;
+ assert(ip.getNav(nav).name == name);
+ assert(ip.getNav(nav).fqn == fqn);
+ break :nav nav;
+ } else nav: {
+ const nav = try ip.createDeclNav(gpa, io, pt.tid, name, fqn, tracked_inst, namespace_index);
+ if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newNav(zcu, nav);
+ break :nav nav;
+ };
- const want_analysis = switch (decl.kind) {
- .@"comptime" => unreachable,
- .unnamed_test, .@"test", .decltest => a: {
- const is_named = decl.kind != .unnamed_test;
- try namespace.test_decls.append(gpa, nav);
- // TODO: incremental compilation!
- // * remove from `test_functions` if no longer matching filter
- // * add to `test_functions` if newly passing filter
- // This logic is unaware of incremental: we'll end up with duplicates.
- // Perhaps we should add all test indiscriminately and filter at the end of the update.
- if (!comp.config.is_test) break :a false;
- if (file.mod != zcu.main_mod) break :a false;
- if (is_named and comp.test_filters.len > 0) {
- const fqn_slice = fqn.toSlice(ip);
- for (comp.test_filters) |test_filter| {
- if (std.mem.indexOf(u8, fqn_slice, test_filter) != null) break;
- } else break :a false;
- }
- try zcu.test_functions.put(gpa, nav, {});
- break :a true;
- },
- .@"const", .@"var" => a: {
- if (decl.is_pub) {
- try namespace.pub_decls.putContext(gpa, nav, {}, .{ .zcu = zcu });
- } else {
- try namespace.priv_decls.putContext(gpa, nav, {}, .{ .zcu = zcu });
- }
- break :a false;
- },
- };
- break :unit .{ unit, want_analysis };
+ const want_analysis: bool = switch (decl.kind) {
+ .@"comptime" => unreachable,
+ .unnamed_test, .@"test", .decltest => a: {
+ const is_named = decl.kind != .unnamed_test;
+ try namespace.test_decls.append(gpa, nav);
+ // TODO: incremental compilation!
+ // * remove from `test_functions` if no longer matching filter
+ // * add to `test_functions` if newly passing filter
+ // This logic is unaware of incremental: we'll end up with duplicates.
+ // Perhaps we should add all test indiscriminately and filter at the end of the update.
+ if (!comp.config.is_test) break :a false;
+ if (file.mod != zcu.main_mod) break :a false;
+ if (is_named and comp.test_filters.len > 0) {
+ const fqn_slice = fqn.toSlice(ip);
+ for (comp.test_filters) |test_filter| {
+ if (std.mem.indexOf(u8, fqn_slice, test_filter) != null) break;
+ } else break :a false;
+ }
+ try zcu.test_functions.put(gpa, nav, {});
+ break :a true;
+ },
+ .@"const", .@"var" => a: {
+ if (decl.is_pub) {
+ try namespace.pub_decls.putContext(gpa, nav, {}, .{ .zcu = zcu });
+ } else {
+ try namespace.priv_decls.putContext(gpa, nav, {}, .{ .zcu = zcu });
+ }
+ break :a false;
},
};
- if (existing_unit == null and (want_analysis or decl.linkage == .@"export")) {
- log.debug(
- "scanDecl queue analyze_comptime_unit file='{s}' unit={f}",
- .{ namespace.fileScope(zcu).sub_file_path, zcu.fmtAnalUnit(unit) },
- );
- try comp.queueJob(.{ .analyze_comptime_unit = unit });
+ if (want_analysis or decl.linkage == .@"export") {
+ try zcu.ensureNavValAnalysisQueued(nav);
}
}
};
-fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!Air {
- const tracy = trace(@src());
- defer tracy.end();
+fn analyzeFuncBodyInner(
+ pt: Zcu.PerThread,
+ func_index: InternPool.Index,
+ reason: ?*const Zcu.DependencyReason,
+) Zcu.SemaError!Air {
+ const tracy_trace = trace(@src());
+ defer tracy_trace.end();
const zcu = pt.zcu;
const comp = zcu.comp;
@@ -2898,17 +3271,18 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE
const anal_unit = AnalUnit.wrap(.{ .func = func_index });
const func = zcu.funcInfo(func_index);
- const inst_info = func.zir_body_inst.resolveFull(ip) orelse return error.AnalysisFail;
- const file = zcu.fileByIndex(inst_info.file);
+
+ // This is the `Nav` corresponding to the `declaration` instruction which the function or its generic owner originates from.
+ const decl_analysis = if (func.generic_owner == .none)
+ ip.getNav(func.owner_nav).analysis.?
+ else
+ ip.getNav(zcu.funcInfo(func.generic_owner).owner_nav).analysis.?;
+
+ const file = zcu.fileByIndex(decl_analysis.zir_index.resolveFile(ip));
const zir = file.zir.?;
- try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, {});
- errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit);
-
- func.setAnalyzed(ip, io);
- if (func.analysisUnordered(ip).inferred_error_set) {
- func.setResolvedErrorSet(ip, io, .none);
- }
+ try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, reason);
+ defer assert(zcu.analysis_in_progress.swapRemove(anal_unit));
if (zcu.comp.time_report) |*tr| {
if (func.generic_owner != .none) {
@@ -2916,16 +3290,8 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE
}
}
- // This is the `Nau` corresponding to the `declaration` instruction which the function or its generic owner originates from.
- const decl_nav = ip.getNav(if (func.generic_owner == .none)
- func.owner_nav
- else
- zcu.funcInfo(func.generic_owner).owner_nav);
-
const func_nav = ip.getNav(func.owner_nav);
- zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit);
-
var analysis_arena = std.heap.ArenaAllocator.init(gpa);
defer analysis_arena.deinit();
@@ -2957,9 +3323,30 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE
// Every runtime function has a dependency on the source of the Decl it originates from.
// It also depends on the value of its owner Decl.
- try sema.declareDependency(.{ .src_hash = decl_nav.analysis.?.zir_index });
+ try sema.declareDependency(.{ .src_hash = decl_analysis.zir_index });
try sema.declareDependency(.{ .nav_val = func.owner_nav });
+ // Make sure that the declaration `Nav` still refers to this function (or its generic owner).
+ // This will not be the case if the incremental update has changed a function type or turned a
+ // `fn` decl into some other declaration. In that case, we must not run analysis: this function
+ // will not be referenced this update, and trying to generate it could be problematic since we
+ // assume the owner NAV actually, um, owns us.
+ //
+ // If we *are* still owned by the right NAV, this analysis updates `zir_body_inst` if necessary.
+
+ if (func.generic_owner == .none) {
+ try pt.ensureNavValUpToDate(func.owner_nav, reason);
+ if (ip.getNav(func.owner_nav).status.fully_resolved.val != func_index) {
+ return error.AnalysisFail;
+ }
+ } else {
+ const go_nav = zcu.funcInfo(func.generic_owner).owner_nav;
+ try pt.ensureNavValUpToDate(go_nav, reason);
+ if (ip.getNav(go_nav).status.fully_resolved.val != func.generic_owner) {
+ return error.AnalysisFail;
+ }
+ }
+
if (func.analysisUnordered(ip).inferred_error_set) {
const ies = try analysis_arena.allocator().create(Sema.InferredErrorSet);
ies.* = .{ .func = func_index };
@@ -2977,11 +3364,11 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE
var inner_block: Sema.Block = .{
.parent = null,
.sema = &sema,
- .namespace = decl_nav.analysis.?.namespace,
- .instructions = .{},
+ .namespace = decl_analysis.namespace,
+ .instructions = .empty,
.inlining = null,
.comptime_reason = null,
- .src_base_inst = decl_nav.analysis.?.zir_index,
+ .src_base_inst = decl_analysis.zir_index,
.type_name_ctx = func_nav.fqn,
};
defer inner_block.instructions.deinit(gpa);
@@ -3020,16 +3407,21 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE
const gop = sema.inst_map.getOrPutAssumeCapacity(inst);
if (gop.found_existing) continue; // provided above by comptime arg
- const param_ty = fn_ty_info.param_types.get(ip)[runtime_param_index];
+ const param_ty: Type = .fromInterned(fn_ty_info.param_types.get(ip)[runtime_param_index]);
runtime_param_index += 1;
- const opt_opv = sema.typeHasOnePossibleValue(Type.fromInterned(param_ty)) catch |err| switch (err) {
- error.ComptimeReturn => unreachable,
- error.ComptimeBreak => unreachable,
- else => |e| return e,
- };
- if (opt_opv) |opv| {
- gop.value_ptr.* = Air.internedToRef(opv.toIntern());
+ if (param_ty.isGenericPoison()) {
+ // We're guaranteed to get a compile error on the `fnHasRuntimeBits` check after this
+ // loop (the generic poison means this is a generic function). But `continue` here to
+ // avoid an illegal call to `onePossibleValue` below.
+ continue;
+ }
+
+ const param_ty_src = inner_block.src(.{ .func_decl_param_ty = @intCast(zir_param_index) });
+
+ try sema.ensureLayoutResolved(param_ty, param_ty_src, .parameter);
+ if (try param_ty.onePossibleValue(pt)) |opv| {
+ gop.value_ptr.* = .fromValue(opv);
continue;
}
const arg_index: Air.Inst.Index = @enumFromInt(sema.air_instructions.len);
@@ -3038,12 +3430,31 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE
sema.air_instructions.appendAssumeCapacity(.{
.tag = .arg,
.data = .{ .arg = .{
- .ty = Air.internedToRef(param_ty),
+ .ty = .fromIntern(param_ty.toIntern()),
.zir_param_index = @intCast(zir_param_index),
} },
});
}
+ try sema.ensureLayoutResolved(sema.fn_ret_ty, inner_block.src(.{ .node_offset_fn_type_ret_ty = .zero }), .return_type);
+
+ // The function type is now resolved, so we're ready to check whether it even makes sense to ask
+ // for it to be analyzed at runtime.
+ if (!fn_ty.fnHasRuntimeBits(zcu)) {
+ const description: []const u8 = switch (fn_ty_info.cc) {
+ .@"inline" => "inline",
+ else => "generic",
+ };
+ // This error makes sense because the only reason this analysis would ever be requested is
+ // for IES resolution.
+ return sema.fail(
+ &inner_block,
+ inner_block.nodeOffset(.zero),
+ "cannot resolve inferred error set of {s} function type '{f}'",
+ .{ description, fn_ty.fmt(pt) },
+ );
+ }
+
const last_arg_index = inner_block.instructions.items.len;
// Save the error trace as our first action in the function.
@@ -3103,21 +3514,6 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE
func.setResolvedErrorSet(ip, io, ies.resolved);
}
- assert(zcu.analysis_in_progress.swapRemove(anal_unit));
-
- // Finally we must resolve the return type and parameter types so that backends
- // have full access to type information.
- // Crucially, this happens *after* we set the function state to success above,
- // so that dependencies on the function body will now be satisfied rather than
- // result in circular dependency errors.
- // TODO: this can go away once we fix backends having to resolve `StackTrace`.
- // The codegen timing guarantees that the parameter types will be populated.
- sema.resolveFnTypes(fn_ty, inner_block.nodeOffset(.zero)) catch |err| switch (err) {
- error.ComptimeReturn => unreachable,
- error.ComptimeBreak => unreachable,
- else => |e| return e,
- };
-
try sema.flushExports();
defer {
@@ -3244,7 +3640,7 @@ pub fn processExports(pt: Zcu.PerThread) !void {
break :gop .{ gop.value_ptr, gop.found_existing };
},
};
- if (!found_existing) value_ptr.* = .{};
+ if (!found_existing) value_ptr.* = .empty;
try value_ptr.append(gpa, export_idx);
}
@@ -3273,7 +3669,7 @@ pub fn processExports(pt: Zcu.PerThread) !void {
break :gop .{ gop.value_ptr, gop.found_existing };
},
};
- if (!found_existing) value_ptr.* = .{};
+ if (!found_existing) value_ptr.* = .empty;
try value_ptr.append(gpa, @enumFromInt(export_idx));
}
}
@@ -3545,36 +3941,45 @@ pub fn intern(pt: Zcu.PerThread, key: InternPool.Key) Allocator.Error!InternPool
/// Essentially a shortcut for calling `intern_pool.getCoerced`.
/// However, this function also allows coercing `extern`s. The `InternPool` function can't do
-/// this because it requires potentially pushing to the job queue.
+/// this because it requires potentially queueing a link task.
pub fn getCoerced(pt: Zcu.PerThread, val: Value, new_ty: Type) Allocator.Error!Value {
const ip = &pt.zcu.intern_pool;
const comp = pt.zcu.comp;
const gpa = comp.gpa;
const io = comp.io;
switch (ip.indexToKey(val.toIntern())) {
- .@"extern" => |e| {
- const coerced = try pt.getExtern(.{
- .name = e.name,
+ .@"extern" => |@"extern"| {
+ // TODO: it's awkward to make this function cancelable. The problem is really that
+ // `getCoerced` is a bad API: it should be replaced with smaller, more specialized
+ // functions, so that this cancel point is only possible in the rare case that you
+ // may actually need to coerce an extern!
+ const old_prot = io.swapCancelProtection(.blocked);
+ defer _ = io.swapCancelProtection(old_prot);
+ const coerced = pt.getExtern(.{
+ .name = @"extern".name,
.ty = new_ty.toIntern(),
- .lib_name = e.lib_name,
- .is_const = e.is_const,
- .is_threadlocal = e.is_threadlocal,
- .linkage = e.linkage,
- .visibility = e.visibility,
- .is_dll_import = e.is_dll_import,
- .relocation = e.relocation,
- .decoration = e.decoration,
- .alignment = e.alignment,
- .@"addrspace" = e.@"addrspace",
- .zir_index = e.zir_index,
+ .lib_name = @"extern".lib_name,
+ .is_const = @"extern".is_const,
+ .is_threadlocal = @"extern".is_threadlocal,
+ .linkage = @"extern".linkage,
+ .visibility = @"extern".visibility,
+ .is_dll_import = @"extern".is_dll_import,
+ .relocation = @"extern".relocation,
+ .decoration = @"extern".decoration,
+ .alignment = @"extern".alignment,
+ .@"addrspace" = @"extern".@"addrspace",
+ .zir_index = @"extern".zir_index,
.owner_nav = undefined, // ignored by `getExtern`.
- .source = e.source,
- });
- return Value.fromInterned(coerced);
+ .source = @"extern".source,
+ }) catch |err| switch (err) {
+ error.Canceled => unreachable, // blocked above
+ error.OutOfMemory => |e| return e,
+ };
+ return .fromInterned(coerced);
},
else => {},
}
- return Value.fromInterned(try ip.getCoerced(gpa, io, pt.tid, val.toIntern(), new_ty.toIntern()));
+ return .fromInterned(try ip.getCoerced(gpa, io, pt.tid, val.toIntern(), new_ty.toIntern()));
}
pub fn intType(pt: Zcu.PerThread, signedness: std.builtin.Signedness, bits: u16) Allocator.Error!Type {
@@ -3605,16 +4010,6 @@ pub fn ptrType(pt: Zcu.PerThread, info: InternPool.Key.PtrType) Allocator.Error!
if (info.flags.size == .c) canon_info.flags.is_allowzero = true;
- // Canonicalize non-zero alignment. If it matches the ABI alignment of the pointee
- // type, we change it to 0 here. If this causes an assertion trip because the
- // pointee type needs to be resolved more, that needs to be done before calling
- // this ptr() function.
- if (info.flags.alignment != .none and
- info.flags.alignment == Type.fromInterned(info.child).abiAlignment(pt.zcu))
- {
- canon_info.flags.alignment = .none;
- }
-
switch (info.flags.vector_index) {
// Canonicalize host_size. If it matches the bit size of the pointee type,
// we change it to 0 here. If this causes an assertion trip, the pointee type
@@ -3632,16 +4027,6 @@ pub fn ptrType(pt: Zcu.PerThread, info: InternPool.Key.PtrType) Allocator.Error!
return Type.fromInterned(try pt.intern(.{ .ptr_type = canon_info }));
}
-/// Like `ptrType`, but if `info` specifies an `alignment`, first ensures the pointer
-/// child type's alignment is resolved so that an invalid alignment is not used.
-/// In general, prefer this function during semantic analysis.
-pub fn ptrTypeSema(pt: Zcu.PerThread, info: InternPool.Key.PtrType) Zcu.SemaError!Type {
- if (info.flags.alignment != .none) {
- _ = try Type.fromInterned(info.child).abiAlignmentSema(pt);
- }
- return pt.ptrType(info);
-}
-
pub fn singleMutPtrType(pt: Zcu.PerThread, child_type: Type) Allocator.Error!Type {
return pt.ptrType(.{ .child = child_type.toIntern() });
}
@@ -3741,29 +4126,54 @@ pub fn enumValueFieldIndex(pt: Zcu.PerThread, ty: Type, field_index: u32) Alloca
const ip = &pt.zcu.intern_pool;
const enum_type = ip.loadEnumType(ty.toIntern());
- if (enum_type.values.len == 0) {
+ assert(field_index < enum_type.field_names.len);
+
+ if (enum_type.field_values.len == 0) {
// Auto-numbered fields.
return Value.fromInterned(try pt.intern(.{ .enum_tag = .{
.ty = ty.toIntern(),
.int = try pt.intern(.{ .int = .{
- .ty = enum_type.tag_ty,
+ .ty = enum_type.int_tag_type,
.storage = .{ .u64 = field_index },
} }),
} }));
}
- return Value.fromInterned(try pt.intern(.{ .enum_tag = .{
+ return .fromInterned(try pt.intern(.{ .enum_tag = .{
.ty = ty.toIntern(),
- .int = enum_type.values.get(ip)[field_index],
+ .int = enum_type.field_values.get(ip)[field_index],
} }));
}
pub fn undefValue(pt: Zcu.PerThread, ty: Type) Allocator.Error!Value {
- return Value.fromInterned(try pt.intern(.{ .undef = ty.toIntern() }));
+ if (std.debug.runtime_safety) {
+ // TODO: values of type `struct { comptime x: u8 = undefined }` are currently represented as
+ // undef. This is wrong: they should really be represented as empty aggregates instead,
+ // because `comptime` fields shouldn't factor into that decision! This is implemented
+ // through logic in `aggregateValue` and requires this weird workaround in what ought to be
+ // a straightforward assertion:
+ //assert(ty.classify(pt.zcu) != .one_possible_value);
+ if (ty.classify(pt.zcu) == .one_possible_value) {
+ const ip = &pt.zcu.intern_pool;
+ switch (ip.indexToKey(ty.toIntern())) {
+ else => unreachable, // assertion failure
+ .struct_type => {
+ const comptime_bits = ip.loadStructType(ty.toIntern()).field_is_comptime_bits.getAll(ip);
+ for (comptime_bits) |bag| {
+ if (@popCount(bag) > 0) break;
+ } else unreachable; // assertion failure
+ },
+ .tuple_type => |tuple| for (tuple.values.get(ip)) |val| {
+ if (val != .none) break;
+ } else unreachable, // assertion failure
+ }
+ }
+ }
+ return .fromInterned(try pt.intern(.{ .undef = ty.toIntern() }));
}
pub fn undefRef(pt: Zcu.PerThread, ty: Type) Allocator.Error!Air.Inst.Ref {
- return Air.internedToRef((try pt.undefValue(ty)).toIntern());
+ return .fromValue(try pt.undefValue(ty));
}
pub fn intValue(pt: Zcu.PerThread, ty: Type, x: anytype) Allocator.Error!Value {
@@ -3839,7 +4249,7 @@ pub fn aggregateValue(pt: Zcu.PerThread, ty: Type, elems: []const InternPool.Ind
for (elems) |elem| {
if (!Value.fromInterned(elem).isUndef(pt.zcu)) break;
} else if (elems.len > 0) {
- return pt.undefValue(ty); // all-undef
+ return pt.undefValue(ty);
}
return .fromInterned(try pt.intern(.{ .aggregate = .{
.ty = ty.toIntern(),
@@ -3877,6 +4287,15 @@ pub fn floatValue(pt: Zcu.PerThread, ty: Type, x: anytype) Allocator.Error!Value
} }));
}
+/// Create a value whose type is a `packed struct` or `packed union`, from the backing integer value.
+pub fn bitpackValue(pt: Zcu.PerThread, ty: Type, backing_int_val: Value) Allocator.Error!Value {
+ assert(backing_int_val.typeOf(pt.zcu).toIntern() == ty.bitpackBackingInt(pt.zcu).toIntern());
+ return .fromInterned(try pt.intern(.{ .bitpack = .{
+ .ty = ty.toIntern(),
+ .backing_int_val = backing_int_val.toIntern(),
+ } }));
+}
+
pub fn nullValue(pt: Zcu.PerThread, opt_ty: Type) Allocator.Error!Value {
assert(pt.zcu.intern_pool.isOptionalType(opt_ty.toIntern()));
return Value.fromInterned(try pt.intern(.{ .opt = .{
@@ -3916,7 +4335,7 @@ pub fn intFittingRange(pt: Zcu.PerThread, min: Value, max: Value) !Type {
assert(Value.order(min, max, zcu).compare(.lte));
}
- const sign = min.orderAgainstZero(zcu) == .lt;
+ const sign = min.compareHetero(.lt, .zero_comptime_int, zcu);
const min_val_bits = pt.intBitsForValue(min, sign);
const max_val_bits = pt.intBitsForValue(max, sign);
@@ -3955,12 +4374,6 @@ pub fn intBitsForValue(pt: Zcu.PerThread, val: Value, sign: bool) u16 {
return @as(u16, @intCast(big.bitCountTwosComp()));
},
- .lazy_align => |lazy_ty| {
- return Type.smallestUnsignedBits(Type.fromInterned(lazy_ty).abiAlignment(pt.zcu).toByteUnits() orelse 0) + @intFromBool(sign);
- },
- .lazy_size => |lazy_ty| {
- return Type.smallestUnsignedBits(Type.fromInterned(lazy_ty).abiSize(pt.zcu)) + @intFromBool(sign);
- },
}
}
@@ -3975,10 +4388,7 @@ pub fn navPtrType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Allocator.Err
return pt.ptrType(.{
.child = ty,
.flags = .{
- .alignment = if (alignment == Type.fromInterned(ty).abiAlignment(zcu))
- .none
- else
- alignment,
+ .alignment = alignment,
.address_space = @"addrspace",
.is_const = is_const,
},
@@ -3988,392 +4398,19 @@ pub fn navPtrType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Allocator.Err
/// Intern an `.@"extern"`, creating a corresponding owner `Nav` if necessary.
/// If necessary, the new `Nav` is queued for codegen.
/// `key.owner_nav` is ignored and may be `undefined`.
-pub fn getExtern(pt: Zcu.PerThread, key: InternPool.Key.Extern) Allocator.Error!InternPool.Index {
+pub fn getExtern(pt: Zcu.PerThread, key: InternPool.Key.Extern) (Io.Cancelable || Allocator.Error)!InternPool.Index {
const zcu = pt.zcu;
const comp = zcu.comp;
+ Type.fromInterned(key.ty).assertHasLayout(zcu);
const result = try zcu.intern_pool.getExtern(comp.gpa, comp.io, pt.tid, key);
if (result.new_nav.unwrap()) |nav| {
- // This job depends on any resolve_type_fully jobs queued up before it.
- comp.link_prog_node.increaseEstimatedTotalItems(1);
- try comp.queueJob(.{ .link_nav = nav });
if (comp.debugIncremental()) try zcu.incremental_debug_state.newNav(zcu, nav);
+ comp.link_prog_node.increaseEstimatedTotalItems(1);
+ try comp.link_queue.enqueueZcu(comp, pt.tid, .{ .link_nav = nav });
}
return result.index;
}
-// TODO: this shouldn't need a `PerThread`! Fix the signature of `Type.abiAlignment`.
-pub fn navAlignment(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) InternPool.Alignment {
- const zcu = pt.zcu;
- const ty: Type, const alignment = switch (zcu.intern_pool.getNav(nav_index).status) {
- .unresolved => unreachable,
- .type_resolved => |r| .{ .fromInterned(r.type), r.alignment },
- .fully_resolved => |r| .{ Value.fromInterned(r.val).typeOf(zcu), r.alignment },
- };
- if (alignment != .none) return alignment;
- return ty.abiAlignment(zcu);
-}
-
-/// `ty` is a container type requiring resolution (struct, union, or enum).
-/// If `ty` is outdated, it is recreated at a new `InternPool.Index`, which is returned.
-/// If the type cannot be recreated because it has been lost, `error.AnalysisFail` is returned.
-/// If `ty` is not outdated, that same `InternPool.Index` is returned.
-/// If `ty` has already been replaced by this function, the new index will not be returned again.
-/// Also, if `ty` is an enum, this function will resolve the new type if needed, and the call site
-/// is responsible for checking `[transitive_]failed_analysis` to detect resolution failures.
-pub fn ensureTypeUpToDate(pt: Zcu.PerThread, ty: InternPool.Index) Zcu.SemaError!InternPool.Index {
- const zcu = pt.zcu;
- const gpa = zcu.gpa;
- const ip = &zcu.intern_pool;
-
- const anal_unit: AnalUnit = .wrap(.{ .type = ty });
- const outdated = zcu.outdated.swapRemove(anal_unit) or
- zcu.potentially_outdated.swapRemove(anal_unit);
-
- if (outdated) {
- _ = zcu.outdated_ready.swapRemove(anal_unit);
- try zcu.markDependeeOutdated(.marked_po, .{ .interned = ty });
- }
-
- const ty_key = switch (ip.indexToKey(ty)) {
- .struct_type, .union_type, .enum_type => |key| key,
- else => unreachable,
- };
- const declared_ty_key = switch (ty_key) {
- .reified => unreachable, // never outdated
- .generated_tag => unreachable, // never outdated
- .declared => |d| d,
- };
-
- if (declared_ty_key.zir_index.resolve(ip) == null) {
- // The instruction has been lost -- this type is dead.
- return error.AnalysisFail;
- }
-
- if (!outdated) return ty;
-
- // We will recreate the type at a new `InternPool.Index`.
-
- // Delete old state which is no longer in use. Technically, this is not necessary: these exports,
- // references, etc, will be ignored because the type itself is unreferenced. However, it allows
- // reusing the memory which is currently being used to track this state.
- zcu.deleteUnitExports(anal_unit);
- zcu.deleteUnitReferences(anal_unit);
- zcu.deleteUnitCompileLogs(anal_unit);
- if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| {
- kv.value.destroy(gpa);
- }
- _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
- zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit);
-
- if (zcu.comp.debugIncremental()) {
- const info = try zcu.incremental_debug_state.getUnitInfo(gpa, anal_unit);
- info.last_update_gen = zcu.generation;
- info.deps.clearRetainingCapacity();
- }
-
- switch (ip.indexToKey(ty)) {
- .struct_type => return pt.recreateStructType(ty, declared_ty_key),
- .union_type => return pt.recreateUnionType(ty, declared_ty_key),
- .enum_type => return pt.recreateEnumType(ty, declared_ty_key),
- else => unreachable,
- }
-}
-
-fn recreateStructType(
- pt: Zcu.PerThread,
- old_ty: InternPool.Index,
- key: InternPool.Key.NamespaceType.Declared,
-) Allocator.Error!InternPool.Index {
- const zcu = pt.zcu;
- const comp = zcu.comp;
- const gpa = comp.gpa;
- const io = comp.io;
- const ip = &zcu.intern_pool;
-
- const inst_info = key.zir_index.resolveFull(ip).?;
- const file = zcu.fileByIndex(inst_info.file);
- const zir = file.zir.?;
-
- assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended);
- const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended;
- assert(extended.opcode == .struct_decl);
- const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
- const extra = zir.extraData(Zir.Inst.StructDecl, extended.operand);
- var extra_index = extra.end;
-
- const captures_len = if (small.has_captures_len) blk: {
- const captures_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk captures_len;
- } else 0;
- const fields_len = if (small.has_fields_len) blk: {
- const fields_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk fields_len;
- } else 0;
-
- assert(captures_len == key.captures.owned.len); // synchronises with logic in `Zcu.mapOldZirToNew`
-
- const struct_obj = ip.loadStructType(old_ty);
-
- const wip_ty = switch (try ip.getStructType(gpa, io, pt.tid, .{
- .layout = small.layout,
- .fields_len = fields_len,
- .known_non_opv = small.known_non_opv,
- .requires_comptime = if (small.known_comptime_only) .yes else .unknown,
- .any_comptime_fields = small.any_comptime_fields,
- .any_default_inits = small.any_default_inits,
- .inits_resolved = false,
- .any_aligned_fields = small.any_aligned_fields,
- .key = .{ .declared_owned_captures = .{
- .zir_index = key.zir_index,
- .captures = key.captures.owned,
- } },
- }, true)) {
- .wip => |wip| wip,
- .existing => unreachable, // we passed `replace_existing`
- };
- errdefer wip_ty.cancel(ip, pt.tid);
-
- wip_ty.setName(ip, struct_obj.name, struct_obj.name_nav);
- try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = key.zir_index });
- zcu.namespacePtr(struct_obj.namespace).owner_type = wip_ty.index;
- // No need to re-scan the namespace -- `zirStructDecl` will ultimately do that if the type is still alive.
- try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
-
- codegen_type: {
- if (file.mod.?.strip) break :codegen_type;
- // This job depends on any resolve_type_fully jobs queued up before it.
- zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
- try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
- }
-
- if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
- const new_ty = wip_ty.finish(ip, struct_obj.namespace);
- if (inst_info.inst == .main_struct_inst) {
- // This is the root type of a file! Update the reference.
- zcu.setFileRootType(inst_info.file, new_ty);
- }
- return new_ty;
-}
-
-fn recreateUnionType(
- pt: Zcu.PerThread,
- old_ty: InternPool.Index,
- key: InternPool.Key.NamespaceType.Declared,
-) Allocator.Error!InternPool.Index {
- const zcu = pt.zcu;
- const comp = zcu.comp;
- const gpa = comp.gpa;
- const io = comp.io;
- const ip = &zcu.intern_pool;
-
- const inst_info = key.zir_index.resolveFull(ip).?;
- const file = zcu.fileByIndex(inst_info.file);
- const zir = file.zir.?;
-
- assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended);
- const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended;
- assert(extended.opcode == .union_decl);
- const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
- const extra = zir.extraData(Zir.Inst.UnionDecl, extended.operand);
- var extra_index = extra.end;
-
- extra_index += @intFromBool(small.has_tag_type);
- const captures_len = if (small.has_captures_len) blk: {
- const captures_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk captures_len;
- } else 0;
- extra_index += @intFromBool(small.has_body_len);
- const fields_len = if (small.has_fields_len) blk: {
- const fields_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk fields_len;
- } else 0;
-
- assert(captures_len == key.captures.owned.len); // synchronises with logic in `Zcu.mapOldZirToNew`
-
- const union_obj = ip.loadUnionType(old_ty);
-
- const namespace_index = union_obj.namespace;
-
- const wip_ty = switch (try ip.getUnionType(gpa, io, pt.tid, .{
- .flags = .{
- .layout = small.layout,
- .status = .none,
- .runtime_tag = if (small.has_tag_type or small.auto_enum_tag)
- .tagged
- else if (small.layout != .auto)
- .none
- else switch (true) { // TODO
- true => .safety,
- false => .none,
- },
- .any_aligned_fields = small.any_aligned_fields,
- .requires_comptime = .unknown,
- .assumed_runtime_bits = false,
- .assumed_pointer_aligned = false,
- .alignment = .none,
- },
- .fields_len = fields_len,
- .enum_tag_ty = .none, // set later
- .field_types = &.{}, // set later
- .field_aligns = &.{}, // set later
- .key = .{ .declared_owned_captures = .{
- .zir_index = key.zir_index,
- .captures = key.captures.owned,
- } },
- }, true)) {
- .wip => |wip| wip,
- .existing => unreachable, // we passed `replace_existing`
- };
- errdefer wip_ty.cancel(ip, pt.tid);
-
- wip_ty.setName(ip, union_obj.name, union_obj.name_nav);
- try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = key.zir_index });
- zcu.namespacePtr(namespace_index).owner_type = wip_ty.index;
- // No need to re-scan the namespace -- `zirUnionDecl` will ultimately do that if the type is still alive.
- try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
-
- codegen_type: {
- if (file.mod.?.strip) break :codegen_type;
- // This job depends on any resolve_type_fully jobs queued up before it.
- zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
- try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
- }
-
- if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
- return wip_ty.finish(ip, namespace_index);
-}
-
-/// This *does* call `Sema.resolveDeclaredEnum`, but errors from it are not propagated.
-/// Call sites are resposible for checking `[transitive_]failed_analysis` after `ensureTypeUpToDate`
-/// returns in order to detect resolution failures.
-fn recreateEnumType(
- pt: Zcu.PerThread,
- old_ty: InternPool.Index,
- key: InternPool.Key.NamespaceType.Declared,
-) (Allocator.Error || Io.Cancelable)!InternPool.Index {
- const zcu = pt.zcu;
- const comp = zcu.comp;
- const gpa = comp.gpa;
- const io = comp.io;
- const ip = &zcu.intern_pool;
-
- const inst_info = key.zir_index.resolveFull(ip).?;
- const file = zcu.fileByIndex(inst_info.file);
- const zir = file.zir.?;
-
- assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended);
- const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended;
- assert(extended.opcode == .enum_decl);
- const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small);
- const extra = zir.extraData(Zir.Inst.EnumDecl, extended.operand);
- var extra_index = extra.end;
-
- const tag_type_ref = if (small.has_tag_type) blk: {
- const tag_type_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]);
- extra_index += 1;
- break :blk tag_type_ref;
- } else .none;
-
- const captures_len = if (small.has_captures_len) blk: {
- const captures_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk captures_len;
- } else 0;
-
- const body_len = if (small.has_body_len) blk: {
- const body_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk body_len;
- } else 0;
-
- const fields_len = if (small.has_fields_len) blk: {
- const fields_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk fields_len;
- } else 0;
-
- const decls_len = if (small.has_decls_len) blk: {
- const decls_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk decls_len;
- } else 0;
-
- assert(captures_len == key.captures.owned.len); // synchronises with logic in `Zcu.mapOldZirToNew`
-
- extra_index += captures_len * 2;
- extra_index += decls_len;
-
- const body = zir.bodySlice(extra_index, body_len);
- extra_index += body.len;
-
- const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
- const body_end = extra_index;
- extra_index += bit_bags_count;
-
- const any_values = for (zir.extra[body_end..][0..bit_bags_count]) |bag| {
- if (bag != 0) break true;
- } else false;
-
- const enum_obj = ip.loadEnumType(old_ty);
-
- const namespace_index = enum_obj.namespace;
-
- const wip_ty = switch (try ip.getEnumType(gpa, io, pt.tid, .{
- .has_values = any_values,
- .tag_mode = if (small.nonexhaustive)
- .nonexhaustive
- else if (tag_type_ref == .none)
- .auto
- else
- .explicit,
- .fields_len = fields_len,
- .key = .{ .declared_owned_captures = .{
- .zir_index = key.zir_index,
- .captures = key.captures.owned,
- } },
- }, true)) {
- .wip => |wip| wip,
- .existing => unreachable, // we passed `replace_existing`
- };
- var done = true;
- errdefer if (!done) wip_ty.cancel(ip, pt.tid);
-
- wip_ty.setName(ip, enum_obj.name, enum_obj.name_nav);
-
- zcu.namespacePtr(namespace_index).owner_type = wip_ty.index;
- // No need to re-scan the namespace -- `zirEnumDecl` will ultimately do that if the type is still alive.
-
- if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
- wip_ty.prepare(ip, namespace_index);
- done = true;
-
- Sema.resolveDeclaredEnum(
- pt,
- wip_ty,
- inst_info.inst,
- key.zir_index,
- namespace_index,
- enum_obj.name,
- small,
- body,
- tag_type_ref,
- any_values,
- fields_len,
- zir,
- body_end,
- ) catch |err| switch (err) {
- error.OutOfMemory => |e| return e,
- error.Canceled => |e| return e,
- error.AnalysisFail => {}, // call sites are responsible for checking `[transitive_]failed_analysis` to detect this
- };
-
- return wip_ty.index;
-}
-
/// Given a namespace, re-scan its declarations from the type definition if they have not
/// yet been re-scanned on this update.
/// If the type declaration instruction has been lost, returns `error.AnalysisFail`.
@@ -4396,7 +4433,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace
};
const key = switch (full_key) {
- .reified, .generated_tag => {
+ .reified, .generated_union_tag => {
// Namespace always empty, so up-to-date.
namespace.generation = zcu.generation;
return;
@@ -4408,123 +4445,37 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace
const inst_info = key.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
const file = zcu.fileByIndex(inst_info.file);
- const zir = file.zir.?;
-
- assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended);
- const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended;
+ const zir = &file.zir.?;
const decls = switch (container) {
- .@"struct" => decls: {
- assert(extended.opcode == .struct_decl);
- const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
- const extra = zir.extraData(Zir.Inst.StructDecl, extended.operand);
- var extra_index = extra.end;
- const captures_len = if (small.has_captures_len) blk: {
- const captures_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk captures_len;
- } else 0;
- extra_index += @intFromBool(small.has_fields_len);
- const decls_len = if (small.has_decls_len) blk: {
- const decls_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk decls_len;
- } else 0;
- extra_index += captures_len * 2;
- if (small.has_backing_int) {
- const backing_int_body_len = zir.extra[extra_index];
- extra_index += 1; // backing_int_body_len
- if (backing_int_body_len == 0) {
- extra_index += 1; // backing_int_ref
- } else {
- extra_index += backing_int_body_len; // backing_int_body_inst
- }
- }
- break :decls zir.bodySlice(extra_index, decls_len);
- },
- .@"union" => decls: {
- assert(extended.opcode == .union_decl);
- const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
- const extra = zir.extraData(Zir.Inst.UnionDecl, extended.operand);
- var extra_index = extra.end;
- extra_index += @intFromBool(small.has_tag_type);
- const captures_len = if (small.has_captures_len) blk: {
- const captures_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk captures_len;
- } else 0;
- extra_index += @intFromBool(small.has_body_len);
- extra_index += @intFromBool(small.has_fields_len);
- const decls_len = if (small.has_decls_len) blk: {
- const decls_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk decls_len;
- } else 0;
- extra_index += captures_len * 2;
- break :decls zir.bodySlice(extra_index, decls_len);
- },
- .@"enum" => decls: {
- assert(extended.opcode == .enum_decl);
- const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small);
- const extra = zir.extraData(Zir.Inst.EnumDecl, extended.operand);
- var extra_index = extra.end;
- extra_index += @intFromBool(small.has_tag_type);
- const captures_len = if (small.has_captures_len) blk: {
- const captures_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk captures_len;
- } else 0;
- extra_index += @intFromBool(small.has_body_len);
- extra_index += @intFromBool(small.has_fields_len);
- const decls_len = if (small.has_decls_len) blk: {
- const decls_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk decls_len;
- } else 0;
- extra_index += captures_len * 2;
- break :decls zir.bodySlice(extra_index, decls_len);
- },
- .@"opaque" => decls: {
- assert(extended.opcode == .opaque_decl);
- const small: Zir.Inst.OpaqueDecl.Small = @bitCast(extended.small);
- const extra = zir.extraData(Zir.Inst.OpaqueDecl, extended.operand);
- var extra_index = extra.end;
- const captures_len = if (small.has_captures_len) blk: {
- const captures_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk captures_len;
- } else 0;
- const decls_len = if (small.has_decls_len) blk: {
- const decls_len = zir.extra[extra_index];
- extra_index += 1;
- break :blk decls_len;
- } else 0;
- extra_index += captures_len * 2;
- break :decls zir.bodySlice(extra_index, decls_len);
- },
+ .@"struct" => zir.getStructDecl(inst_info.inst).decls,
+ .@"union" => zir.getUnionDecl(inst_info.inst).decls,
+ .@"enum" => zir.getEnumDecl(inst_info.inst).decls,
+ .@"opaque" => zir.getOpaqueDecl(inst_info.inst).decls,
};
try pt.scanNamespace(namespace_index, decls);
namespace.generation = zcu.generation;
}
-pub fn refValue(pt: Zcu.PerThread, val: InternPool.Index) Zcu.SemaError!InternPool.Index {
- const ptr_ty = (try pt.ptrTypeSema(.{
- .child = pt.zcu.intern_pool.typeOf(val),
+pub fn uavValue(pt: Zcu.PerThread, val: Value) Zcu.SemaError!Value {
+ const zcu = pt.zcu;
+ const ptr_ty = try pt.ptrType(.{
+ .child = val.typeOf(zcu).toIntern(),
.flags = .{
.alignment = .none,
.is_const = true,
.address_space = .generic,
},
- })).toIntern();
- return pt.intern(.{ .ptr = .{
- .ty = ptr_ty,
+ });
+ return .fromInterned(try pt.intern(.{ .ptr = .{
+ .ty = ptr_ty.toIntern(),
.base_addr = .{ .uav = .{
- .val = val,
- .orig_ty = ptr_ty,
+ .val = val.toIntern(),
+ .orig_ty = ptr_ty.toIntern(),
} },
.byte_offset = 0,
- } });
+ } }));
}
pub fn addDependency(pt: Zcu.PerThread, unit: AnalUnit, dependee: InternPool.Dependee) Allocator.Error!void {
diff --git a/src/codegen.zig b/src/codegen.zig
index 6bdfa32f45f277ecd40d18e990f5f7219b81f5e4..9608095dc61dfc3ce1c4b68a2c297bcd5439a2ac 100644
--- a/src/codegen.zig
+++ b/src/codegen.zig
@@ -343,11 +343,9 @@ pub fn generateSymbol(
.undef => unreachable, // handled above
.simple_value => |simple_value| switch (simple_value) {
- .undefined => unreachable, // non-runtime value
.void => unreachable, // non-runtime value
.null => unreachable, // non-runtime value
.@"unreachable" => unreachable, // non-runtime value
- .empty_tuple => return,
.false, .true => try w.writeByte(switch (simple_value) {
.false => 0,
.true => 1,
@@ -358,7 +356,6 @@ pub fn generateSymbol(
.@"extern",
.func,
.enum_literal,
- .empty_enum_value,
=> unreachable, // non-runtime values
.int => {
const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow;
@@ -377,7 +374,7 @@ pub fn generateSymbol(
.payload => 0,
};
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!payload_ty.hasRuntimeBits(zcu)) {
try w.writeInt(u16, err_val, endian);
return;
}
@@ -571,46 +568,11 @@ pub fn generateSymbol(
.struct_type => {
const struct_type = ip.loadStructType(ty.toIntern());
switch (struct_type.layout) {
- .@"packed" => {
- const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow;
- const start = w.end;
- const buffer = try w.writableSlice(abi_size);
- @memset(buffer, 0);
- var bits: u16 = 0;
-
- for (struct_type.field_types.get(ip), 0..) |field_ty, index| {
- const field_val = switch (aggregate.storage) {
- .bytes => |bytes| try pt.intern(.{ .int = .{
- .ty = field_ty,
- .storage = .{ .u64 = bytes.at(index, ip) },
- } }),
- .elems => |elems| elems[index],
- .repeated_elem => |elem| elem,
- };
-
- // pointer may point to a decl which must be marked used
- // but can also result in a relocation. Therefore we handle those separately.
- if (Type.fromInterned(field_ty).zigTypeTag(zcu) == .pointer) {
- const field_offset = std.math.divExact(u16, bits, 8) catch |err| switch (err) {
- error.DivisionByZero => unreachable,
- error.UnexpectedRemainder => return error.RelocationNotByteAligned,
- };
- w.end = start + field_offset;
- defer {
- assert(w.end == start + field_offset + @divExact(target.ptrBitWidth(), 8));
- w.end = start + abi_size;
- }
- try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), w, reloc_parent);
- } else {
- Value.fromInterned(field_val).writeToPackedMemory(.fromInterned(field_ty), pt, buffer, bits) catch unreachable;
- }
- bits += @intCast(Type.fromInterned(field_ty).bitSize(zcu));
- }
- },
+ .@"packed" => unreachable,
.auto, .@"extern" => {
const struct_begin = w.end;
const field_types = struct_type.field_types.get(ip);
- const offsets = struct_type.offsets.get(ip);
+ const offsets = struct_type.field_offsets.get(ip);
var it = struct_type.iterateRuntimeOrder(ip);
while (it.next()) |field_index| {
@@ -635,13 +597,11 @@ pub fn generateSymbol(
try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), w, reloc_parent);
}
- const size = struct_type.sizeUnordered(ip);
- const alignment = struct_type.flagsUnordered(ip).alignment.toByteUnits().?;
+ assert(struct_type.alignment.check(struct_type.size));
- const padding = math.cast(
- usize,
- std.mem.alignForward(u64, size, @max(alignment, 1)) - (w.end - struct_begin),
- ) orelse return error.Overflow;
+ const padding = math.cast(usize, struct_type.size - (w.end - struct_begin)) orelse {
+ return error.Overflow;
+ };
if (padding > 0) try w.splatByteAll(0, padding);
},
}
@@ -686,6 +646,7 @@ pub fn generateSymbol(
}
}
},
+ .bitpack => |bitpack| try generateSymbol(bin_file, pt, src_loc, .fromInterned(bitpack.backing_int_val), w, reloc_parent),
.memoized_call => unreachable,
}
}
@@ -739,7 +700,14 @@ fn lowerPtr(
};
return lowerPtr(bin_file, pt, src_loc, field.base, w, reloc_parent, offset + field_off);
},
- .arr_elem, .comptime_field, .comptime_alloc => unreachable,
+ .arr_elem => |arr_elem| {
+ const base_ptr_ty = Value.fromInterned(arr_elem.base).typeOf(zcu);
+ assert(base_ptr_ty.ptrSize(zcu) == .many);
+ const elem_size = base_ptr_ty.childType(zcu).abiSize(zcu);
+ return lowerPtr(bin_file, pt, src_loc, arr_elem.base, w, reloc_parent, offset + elem_size * arr_elem.index);
+ },
+ .comptime_alloc => unreachable,
+ .comptime_field => unreachable,
};
}
@@ -820,9 +788,8 @@ fn lowerNavRef(
const ptr_width_bytes = @divExact(target.ptrBitWidth(), 8);
const is_obj = lf.comp.config.output_mode == .Obj;
const nav_ty = Type.fromInterned(ip.getNav(nav_index).typeOf(ip));
- const is_fn_body = nav_ty.zigTypeTag(zcu) == .@"fn";
- if (!is_fn_body and !nav_ty.hasRuntimeBits(zcu)) {
+ if (!nav_ty.isRuntimeFnOrHasRuntimeBits(zcu) and ip.getNav(nav_index).getExtern(ip) == null) {
try w.splatByteAll(0xaa, ptr_width_bytes);
return;
}
@@ -834,7 +801,7 @@ fn lowerNavRef(
dev.check(link.File.Tag.wasm.devFeature());
const wasm = lf.cast(.wasm).?;
assert(reloc_parent == .none);
- if (is_fn_body) {
+ if (nav_ty.zigTypeTag(zcu) == .@"fn") {
const gop = try wasm.zcu_indirect_function_set.getOrPut(gpa, nav_index);
if (!gop.found_existing) gop.value_ptr.* = {};
if (is_obj) {
@@ -1060,51 +1027,41 @@ pub fn lowerValue(pt: Zcu.PerThread, val: Value, target: *const std.Target) Allo
switch (ty.zigTypeTag(zcu)) {
.void => return .none,
+ .bool => return .{ .immediate = @intFromBool(val.toBool()) },
.pointer => switch (ty.ptrSize(zcu)) {
.slice => {},
- else => switch (val.toIntern()) {
- .null_value => {
- return .{ .immediate = 0 };
- },
- else => switch (ip.indexToKey(val.toIntern())) {
- .int => {
- return .{ .immediate = val.toUnsignedInt(zcu) };
- },
- .ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) {
- .nav => |nav| {
- if (!ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {
- const imm: u64 = switch (@divExact(target.ptrBitWidth(), 8)) {
- 1 => 0xaa,
- 2 => 0xaaaa,
- 4 => 0xaaaaaaaa,
- 8 => 0xaaaaaaaaaaaaaaaa,
- else => unreachable,
- };
- return .{ .immediate = imm };
- }
+ .one, .many, .c => {
+ const ptr = ip.indexToKey(val.toIntern()).ptr;
+ if (ptr.base_addr == .int) return .{ .immediate = ptr.byte_offset };
+ if (ptr.byte_offset == 0) switch (ptr.base_addr) {
+ .int => unreachable, // handled above
- if (ty.castPtrToFn(zcu)) |fn_ty| {
- if (zcu.typeToFunc(fn_ty).?.is_generic) {
- return .{ .immediate = fn_ty.abiAlignment(zcu).toByteUnits().? };
- }
- } else if (ty.zigTypeTag(zcu) == .pointer) {
- const elem_ty = ty.elemType2(zcu);
- if (!elem_ty.hasRuntimeBits(zcu)) {
- return .{ .immediate = elem_ty.abiAlignment(zcu).toByteUnits().? };
- }
- }
+ .nav => |nav_index| {
+ const nav = ip.getNav(nav_index);
+ const nav_ty: Type = .fromInterned(nav.typeOf(ip));
+ if (nav_ty.isRuntimeFnOrHasRuntimeBits(zcu) or nav.getExtern(ip) != null) {
+ return .{ .lea_nav = nav_index };
+ } else {
+ // Create the 0xaa bit pattern...
+ const undef_ptr_bits: u64 = @intCast((@as(u66, 1) << @intCast(target.ptrBitWidth() + 1)) / 3);
+ // ...but align the pointer
+ const alignment = zcu.navAlignment(nav_index);
+ return .{ .immediate = alignment.forward(undef_ptr_bits) };
+ }
+ },
- return .{ .lea_nav = nav };
- },
- .uav => |uav| if (Value.fromInterned(uav.val).typeOf(zcu).hasRuntimeBits(zcu))
- return .{ .lea_uav = uav }
- else
- return .{ .immediate = Type.fromInterned(uav.orig_ty).ptrAlignment(zcu)
- .forward(@intCast((@as(u66, 1) << @intCast(target.ptrBitWidth() | 1)) / 3)) },
- else => {},
+ .uav => |uav| if (Value.fromInterned(uav.val).typeOf(zcu).isRuntimeFnOrHasRuntimeBits(zcu)) {
+ return .{ .lea_uav = uav };
+ } else {
+ // Create the 0xaa bit pattern...
+ const undef_ptr_bits: u64 = @intCast((@as(u66, 1) << @intCast(target.ptrBitWidth() + 1)) / 3);
+ // ...but align the pointer
+ const alignment = Type.fromInterned(uav.orig_ty).ptrAlignment(zcu);
+ return .{ .immediate = alignment.forward(undef_ptr_bits) };
},
+
else => {},
- },
+ };
},
},
.int => {
@@ -1117,9 +1074,6 @@ pub fn lowerValue(pt: Zcu.PerThread, val: Value, target: *const std.Target) Allo
return .{ .immediate = unsigned };
}
},
- .bool => {
- return .{ .immediate = @intFromBool(val.toBool()) };
- },
.optional => {
if (ty.isPtrLikeOptional(zcu)) {
return lowerValue(
@@ -1139,6 +1093,10 @@ pub fn lowerValue(pt: Zcu.PerThread, val: Value, target: *const std.Target) Allo
target,
);
},
+ .@"struct", .@"union" => if (ty.containerLayout(zcu) == .@"packed") {
+ const bitpack = ip.indexToKey(val.toIntern()).bitpack;
+ return lowerValue(pt, .fromInterned(bitpack.backing_int_val), target);
+ },
.error_set => {
const err_name = ip.indexToKey(val.toIntern()).err.name;
const error_index = ip.getErrorValueIfExists(err_name).?;
@@ -1147,7 +1105,7 @@ pub fn lowerValue(pt: Zcu.PerThread, val: Value, target: *const std.Target) Allo
.error_union => {
const err_type = ty.errorUnionSet(zcu);
const payload_type = ty.errorUnionPayload(zcu);
- if (!payload_type.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!payload_type.hasRuntimeBits(zcu)) {
// We use the error type directly as the type.
const err_int_ty = try pt.errorIntType();
switch (ip.indexToKey(val.toIntern()).error_union.val) {
@@ -1187,10 +1145,10 @@ pub fn lowerValue(pt: Zcu.PerThread, val: Value, target: *const std.Target) Allo
}
pub fn errUnionPayloadOffset(payload_ty: Type, zcu: *Zcu) u64 {
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) return 0;
+ if (!payload_ty.hasRuntimeBits(zcu)) return 0;
const payload_align = payload_ty.abiAlignment(zcu);
const error_align = Type.anyerror.abiAlignment(zcu);
- if (payload_align.compare(.gte, error_align) or !payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (payload_align.compare(.gte, error_align) or !payload_ty.hasRuntimeBits(zcu)) {
return 0;
} else {
return payload_align.forward(Type.anyerror.abiSize(zcu));
@@ -1198,10 +1156,10 @@ pub fn errUnionPayloadOffset(payload_ty: Type, zcu: *Zcu) u64 {
}
pub fn errUnionErrorOffset(payload_ty: Type, zcu: *Zcu) u64 {
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) return 0;
+ if (!payload_ty.hasRuntimeBits(zcu)) return 0;
const payload_align = payload_ty.abiAlignment(zcu);
const error_align = Type.anyerror.abiAlignment(zcu);
- if (payload_align.compare(.gte, error_align) and payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (payload_align.compare(.gte, error_align) and payload_ty.hasRuntimeBits(zcu)) {
return error_align.forward(payload_ty.abiSize(zcu));
} else {
return 0;
diff --git a/src/codegen/aarch64/Select.zig b/src/codegen/aarch64/Select.zig
index 55f0d7fcc0e37b35198f01c2ff88c96cfd72aca4..ba136872b13f406329d0f35e961a50946076e6ef 100644
--- a/src/codegen/aarch64/Select.zig
+++ b/src/codegen/aarch64/Select.zig
@@ -2464,7 +2464,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
const ty_pl = air.data(air.inst_index).ty_pl;
const bin_op = isel.air.extraData(Air.Bin, ty_pl.payload).data;
- const elem_size = ty_pl.ty.toType().elemType2(zcu).abiSize(zcu);
+ const elem_size = ty_pl.ty.toType().childType(zcu).abiSize(zcu);
const base_vi = try isel.use(bin_op.lhs);
var base_part_it = base_vi.field(ty_pl.ty.toType(), 0, 8);
@@ -2791,17 +2791,17 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
} else return isel.fail("invalid constraint: '{s}'", .{constraint});
}
- const clobbers = ip.indexToKey(unwrapped_asm.clobbers).aggregate;
- const clobbers_ty: ZigType = .fromInterned(clobbers.ty);
+ const clobbers_val: Constant = .fromInterned(unwrapped_asm.clobbers);
+ const clobbers_ty = clobbers_val.typeOf(zcu);
+ var clobbers_bigint_buf: Constant.BigIntSpace = undefined;
+ const clobbers_bigint = clobbers_val.toBigInt(&clobbers_bigint_buf, zcu);
for (0..clobbers_ty.structFieldCount(zcu)) |field_index| {
- switch (switch (clobbers.storage) {
- .bytes => unreachable,
- .elems => |elems| elems[field_index],
- .repeated_elem => |repeated_elem| repeated_elem,
- }) {
- else => unreachable,
- .bool_false => continue,
- .bool_true => {},
+ assert(clobbers_ty.fieldType(field_index, zcu).toIntern() == .bool_type);
+ const limb_bits = @bitSizeOf(std.math.big.Limb);
+ if (field_index / limb_bits >= clobbers_bigint.limbs.len) continue; // field is false
+ switch (@as(u1, @truncate(clobbers_bigint.limbs[field_index / limb_bits] >> @intCast(field_index % limb_bits)))) {
+ 0 => continue, // field is false
+ 1 => {}, // field is true
}
const clobber_name = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?;
if (std.mem.eql(u8, clobber_name, "memory")) continue;
@@ -2816,14 +2816,11 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
}
}
for (0..clobbers_ty.structFieldCount(zcu)) |field_index| {
- switch (switch (clobbers.storage) {
- .bytes => unreachable,
- .elems => |elems| elems[field_index],
- .repeated_elem => |repeated_elem| repeated_elem,
- }) {
- else => unreachable,
- .bool_false => continue,
- .bool_true => {},
+ const limb_bits = @bitSizeOf(std.math.big.Limb);
+ if (field_index / limb_bits >= clobbers_bigint.limbs.len) continue; // field is false
+ switch (@as(u1, @truncate(clobbers_bigint.limbs[field_index / limb_bits] >> @intCast(field_index % limb_bits)))) {
+ 0 => continue, // field is false
+ 1 => {}, // field is true
}
const clobber_name = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?;
if (std.mem.eql(u8, clobber_name, "memory")) continue;
@@ -2872,14 +2869,11 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
}
for (0..clobbers_ty.structFieldCount(zcu)) |field_index| {
- switch (switch (clobbers.storage) {
- .bytes => unreachable,
- .elems => |elems| elems[field_index],
- .repeated_elem => |repeated_elem| repeated_elem,
- }) {
- else => unreachable,
- .bool_false => continue,
- .bool_true => {},
+ const limb_bits = @bitSizeOf(std.math.big.Limb);
+ if (field_index / limb_bits >= clobbers_bigint.limbs.len) continue; // field is false
+ switch (@as(u1, @truncate(clobbers_bigint.limbs[field_index / limb_bits] >> @intCast(field_index % limb_bits)))) {
+ 0 => continue, // field is false
+ 1 => {}, // field is true
}
const clobber_name = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?;
if (std.mem.eql(u8, clobber_name, "memory")) continue;
@@ -3289,8 +3283,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
} else if (dst_ty.isSliceAtRuntime(zcu) and src_ty.isSliceAtRuntime(zcu)) {
try dst_vi.value.move(isel, ty_op.operand);
} else if (dst_tag == .error_union and src_tag == .error_union) {
- assert(dst_ty.errorUnionSet(zcu).hasRuntimeBitsIgnoreComptime(zcu) ==
- src_ty.errorUnionSet(zcu).hasRuntimeBitsIgnoreComptime(zcu));
+ assert(dst_ty.errorUnionSet(zcu).hasRuntimeBits(zcu) ==
+ src_ty.errorUnionSet(zcu).hasRuntimeBits(zcu));
if (dst_ty.errorUnionPayload(zcu).toIntern() == src_ty.errorUnionPayload(zcu).toIntern()) {
try dst_vi.value.move(isel, ty_op.operand);
} else return isel.fail("bad {t} {f} {f}", .{ air_tag, isel.fmtType(dst_ty), isel.fmtType(src_ty) });
@@ -4568,7 +4562,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
}
if (case.ranges.len == 0 and case.items.len == 1 and Constant.fromInterned(
case.items[0].toInterned().?,
- ).orderAgainstZero(zcu).compare(.eq)) {
+ ).compareHetero(.eq, .zero_comptime_int, zcu)) {
try isel.emit(.cbnz(
cond_reg,
@intCast((isel.instructions.items.len + 1 - next_label) << 2),
@@ -6145,7 +6139,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
} else {
const elem_ptr_ra = try isel.allocIntReg();
defer isel.freeReg(elem_ptr_ra);
- if (!try elem_vi.value.load(isel, slice_ty.elemType2(zcu), elem_ptr_ra, .{
+ if (!try elem_vi.value.load(isel, slice_ty.childType(zcu), elem_ptr_ra, .{
.@"volatile" = ptr_info.flags.is_volatile,
})) break :unused;
const slice_vi = try isel.use(bin_op.lhs);
@@ -6253,7 +6247,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
} else {
const elem_ptr_ra = try isel.allocIntReg();
defer isel.freeReg(elem_ptr_ra);
- if (!try elem_vi.value.load(isel, ptr_ty.elemType2(zcu), elem_ptr_ra, .{
+ if (!try elem_vi.value.load(isel, ptr_ty.childType(zcu), elem_ptr_ra, .{
.@"volatile" = ptr_info.flags.is_volatile,
})) break :unused;
const base_vi = try isel.use(bin_op.lhs);
@@ -6594,7 +6588,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
if (try isel.hasRepeatedByteRepr(.fromInterned(fill_val))) |fill_byte|
break :fill_byte .{ .constant = fill_byte };
}
- switch (dst_ty.elemType2(zcu).abiSize(zcu)) {
+ switch (dst_ty.indexableElem(zcu).abiSize(zcu)) {
0 => unreachable,
1 => break :fill_byte .{ .value = bin_op.rhs },
2, 4, 8 => |size| {
@@ -6899,11 +6893,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
var field_it = loaded_struct.iterateRuntimeOrder(ip);
while (field_it.next()) |field_index| {
const field_ty: ZigType = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
- field_offset = field_ty.structFieldAlignment(
- loaded_struct.fieldAlign(ip, field_index),
- loaded_struct.layout,
- zcu,
- ).forward(field_offset);
+ field_offset = loaded_struct.field_offsets.get(ip)[field_index];
const field_size = field_ty.abiSize(zcu);
if (field_size == 0) continue;
var agg_part_it = agg_vi.value.field(agg_ty, field_offset, field_size);
@@ -6911,7 +6901,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
try agg_part_vi.?.move(isel, elems[field_index]);
field_offset += field_size;
}
- assert(loaded_struct.flagsUnordered(ip).alignment.forward(field_offset) == agg_vi.value.size(isel));
+ assert(loaded_struct.alignment.forward(field_offset) == agg_vi.value.size(isel));
},
.tuple_type => |tuple_type| {
const elems: []const Air.Inst.Ref =
@@ -6953,23 +6943,23 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
const union_layout = ZigType.getUnionLayout(loaded_union, zcu);
if (union_layout.tag_size > 0) unused_tag: {
- const loaded_tag = loaded_union.loadTagType(ip);
+ const loaded_tag = ip.loadEnumType(loaded_union.enum_tag_type);
var tag_it = union_vi.value.field(union_ty, union_layout.tagOffset(), union_layout.tag_size);
const tag_vi = try tag_it.only(isel);
const tag_ra = try tag_vi.?.defReg(isel) orelse break :unused_tag;
switch (union_layout.tag_size) {
0 => unreachable,
- 1...4 => try isel.movImmediate(tag_ra.w(), @as(u32, switch (loaded_tag.values.len) {
+ 1...4 => try isel.movImmediate(tag_ra.w(), @as(u32, switch (loaded_tag.field_values.len) {
0 => extra.field_index,
- else => switch (ip.indexToKey(loaded_tag.values.get(ip)[extra.field_index]).int.storage) {
+ else => switch (ip.indexToKey(loaded_tag.field_values.get(ip)[extra.field_index]).int.storage) {
.u64 => |imm| @intCast(imm),
.i64 => |imm| @bitCast(@as(i32, @intCast(imm))),
else => unreachable,
},
})),
- 5...8 => try isel.movImmediate(tag_ra.x(), switch (loaded_tag.values.len) {
+ 5...8 => try isel.movImmediate(tag_ra.x(), switch (loaded_tag.field_values.len) {
0 => extra.field_index,
- else => switch (ip.indexToKey(loaded_tag.values.get(ip)[extra.field_index]).int.storage) {
+ else => switch (ip.indexToKey(loaded_tag.field_values.get(ip)[extra.field_index]).int.storage) {
.u64 => |imm| imm,
.i64 => |imm| @bitCast(imm),
else => unreachable,
@@ -7217,7 +7207,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
const ptr_ra = try ptr_vi.value.defReg(isel) orelse break :unused;
const ty_nav = air.data(air.inst_index).ty_nav;
- if (ZigType.fromInterned(ip.getNav(ty_nav.nav).typeOf(ip)).isFnOrHasRuntimeBits(zcu)) switch (true) {
+ if (ZigType.fromInterned(ip.getNav(ty_nav.nav).typeOf(ip)).isRuntimeFnOrHasRuntimeBits(zcu)) switch (true) {
false => {
try isel.nav_relocs.append(gpa, .{
.nav = ty_nav.nav,
@@ -7240,7 +7230,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
});
try isel.emit(.adrp(ptr_ra.x(), 0));
},
- } else try isel.movImmediate(ptr_ra.x(), isel.pt.navAlignment(ty_nav.nav).forward(0xaaaaaaaaaaaaaaaa));
+ } else try isel.movImmediate(ptr_ra.x(), zcu.navAlignment(ty_nav.nav).forward(0xaaaaaaaaaaaaaaaa));
}
if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
},
@@ -10397,7 +10387,7 @@ pub const Value = struct {
switch (loaded_struct.layout) {
.auto, .@"extern" => {},
.@"packed" => continue :type_key .{
- .int_type = ip.indexToKey(loaded_struct.backingIntTypeUnordered(ip)).int_type,
+ .int_type = ip.indexToKey(loaded_struct.packed_backing_int_type).int_type,
},
}
const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0;
@@ -10412,7 +10402,7 @@ pub const Value = struct {
var field_it = loaded_struct.iterateRuntimeOrder(ip);
while (field_it.next()) |field_index| {
const field_ty: ZigType = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
- const field_begin = switch (loaded_struct.fieldAlign(ip, field_index)) {
+ const field_begin = switch (loaded_struct.field_aligns.getOrNone(ip, field_index)) {
.none => field_ty.abiAlignment(zcu),
else => |field_align| field_align,
}.forward(field_end);
@@ -10510,7 +10500,7 @@ pub const Value = struct {
},
.union_type => {
const loaded_union = ip.loadUnionType(ty.toIntern());
- switch (loaded_union.flagsUnordered(ip).layout) {
+ switch (loaded_union.layout) {
.auto, .@"extern" => {},
.@"packed" => continue :type_key .{ .int_type = .{
.signedness = .unsigned,
@@ -10545,12 +10535,13 @@ pub const Value = struct {
const field_signedness = field_signedness: switch (field) {
.tag => {
if (offset >= field_begin and offset + size <= field_begin + field_size) {
- ty = .fromInterned(loaded_union.enum_tag_ty);
+ ty = .fromInterned(loaded_union.enum_tag_type);
ty_size = field_size;
offset -= field_begin;
- continue :type_key ip.indexToKey(loaded_union.enum_tag_ty);
+ continue :type_key ip.indexToKey(loaded_union.enum_tag_type);
}
- break :field_signedness ip.indexToKey(loaded_union.loadTagType(ip).tag_ty).int_type.signedness;
+ const loaded_enum = ip.loadEnumType(loaded_union.enum_tag_type);
+ break :field_signedness ip.indexToKey(loaded_enum.int_tag_type).int_type.signedness;
},
.payload => null,
};
@@ -10580,7 +10571,7 @@ pub const Value = struct {
}
},
.opaque_type, .func_type => continue :type_key .{ .simple_type = .anyopaque },
- .enum_type => continue :type_key ip.indexToKey(ip.loadEnumType(ty.toIntern()).tag_ty),
+ .enum_type => continue :type_key ip.indexToKey(ip.loadEnumType(ty.toIntern()).int_tag_type),
.error_set_type,
.inferred_error_set_type,
=> continue :type_key .{ .simple_type = .anyerror },
@@ -10594,7 +10585,6 @@ pub const Value = struct {
.error_union,
.enum_literal,
.enum_tag,
- .empty_enum_value,
.float,
.ptr,
.slice,
@@ -10717,7 +10707,6 @@ pub const Value = struct {
.inferred_error_set_type,
.enum_literal,
- .empty_enum_value,
.memoized_call,
=> unreachable, // not a runtime value
.undef => break :free try isel.emit(if (mat.ra.isVector()) .movi(switch (size) {
@@ -10738,7 +10727,7 @@ pub const Value = struct {
} }),
}),
.simple_value => |simple_value| switch (simple_value) {
- .undefined, .void, .null, .empty_tuple, .@"unreachable" => unreachable,
+ .void, .null, .@"unreachable" => unreachable,
.true => continue :constant_key .{ .int = .{
.ty = .bool_type,
.storage = .{ .u64 = 1 },
@@ -10748,7 +10737,7 @@ pub const Value = struct {
.storage = .{ .u64 = 0 },
} },
},
- .int => |int| break :free storage: switch (int.storage) {
+ .int => |int| break :free switch (int.storage) {
.u64 => |imm| try isel.movImmediate(switch (size) {
else => unreachable,
1...4 => mat.ra.w(),
@@ -10780,12 +10769,6 @@ pub const Value = struct {
}
try isel.movImmediate(mat.ra.x(), imm);
},
- .lazy_align => |ty| continue :storage .{
- .u64 = ZigType.fromInterned(ty).abiAlignment(zcu).toByteUnits().?,
- },
- .lazy_size => |ty| continue :storage .{
- .u64 = ZigType.fromInterned(ty).abiSize(zcu),
- },
},
.err => |err| continue :constant_key .{ .int = .{
.ty = err.ty,
@@ -10931,7 +10914,7 @@ pub const Value = struct {
.ptr => |ptr| {
assert(offset == 0 and size == 8);
break :free switch (ptr.base_addr) {
- .nav => |nav| if (ZigType.fromInterned(ip.getNav(nav).typeOf(ip)).isFnOrHasRuntimeBits(zcu)) switch (true) {
+ .nav => |nav| if (ZigType.fromInterned(ip.getNav(nav).typeOf(ip)).isRuntimeFnOrHasRuntimeBits(zcu)) switch (true) {
false => {
try isel.nav_relocs.append(zcu.gpa, .{
.nav = nav,
@@ -10965,9 +10948,9 @@ pub const Value = struct {
},
} else continue :constant_key .{ .int = .{
.ty = .usize_type,
- .storage = .{ .u64 = isel.pt.navAlignment(nav).forward(0xaaaaaaaaaaaaaaaa) },
+ .storage = .{ .u64 = zcu.navAlignment(nav).forward(0xaaaaaaaaaaaaaaaa) },
} },
- .uav => |uav| if (ZigType.fromInterned(ip.typeOf(uav.val)).isFnOrHasRuntimeBits(zcu)) switch (true) {
+ .uav => |uav| if (ZigType.fromInterned(ip.typeOf(uav.val)).isRuntimeFnOrHasRuntimeBits(zcu)) switch (true) {
false => {
try isel.uav_relocs.append(zcu.gpa, .{
.uav = uav,
@@ -11092,13 +11075,9 @@ pub const Value = struct {
var field_offset: u64 = 0;
var field_it = loaded_struct.iterateRuntimeOrder(ip);
while (field_it.next()) |field_index| {
- if (loaded_struct.fieldIsComptime(ip, field_index)) continue;
+ if (loaded_struct.field_is_comptime_bits.get(ip, field_index)) continue;
const field_ty: ZigType = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
- field_offset = field_ty.structFieldAlignment(
- loaded_struct.fieldAlign(ip, field_index),
- loaded_struct.layout,
- zcu,
- ).forward(field_offset);
+ field_offset = loaded_struct.field_offsets.get(ip)[field_index];
const field_size = field_ty.abiSize(zcu);
if (offset >= field_offset and offset + size <= field_offset + field_size) {
offset -= field_offset;
@@ -11140,7 +11119,7 @@ pub const Value = struct {
.un => |un| {
const loaded_union = ip.loadUnionType(un.ty);
const union_layout = ZigType.getUnionLayout(loaded_union, zcu);
- if (loaded_union.hasTag(ip)) {
+ if (loaded_union.has_runtime_tag) {
const tag_offset = union_layout.tagOffset();
if (offset >= tag_offset and offset + size <= tag_offset + union_layout.tag_size) {
offset -= tag_offset;
@@ -11414,7 +11393,6 @@ fn writeKeyToMemory(isel: *Select, constant_key: InternPool.Key, buffer: []u8) e
.inferred_error_set_type,
.enum_literal,
- .empty_enum_value,
.memoized_call,
=> unreachable, // not a runtime value
.err => |err| {
@@ -11486,13 +11464,9 @@ fn writeKeyToMemory(isel: *Select, constant_key: InternPool.Key, buffer: []u8) e
var field_offset: u64 = 0;
var field_it = loaded_struct.iterateRuntimeOrder(ip);
while (field_it.next()) |field_index| {
- if (loaded_struct.fieldIsComptime(ip, field_index)) continue;
+ if (loaded_struct.field_is_comptime_bits.get(ip, field_index)) continue;
const field_ty: ZigType = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
- field_offset = field_ty.structFieldAlignment(
- loaded_struct.fieldAlign(ip, field_index),
- loaded_struct.layout,
- zcu,
- ).forward(field_offset);
+ field_offset = loaded_struct.field_offsets.get(ip)[field_index];
const field_size = field_ty.abiSize(zcu);
if (!try isel.writeToMemory(.fromInterned(switch (aggregate.storage) {
.bytes => unreachable,
@@ -12091,7 +12065,7 @@ pub const CallAbiIterator = struct {
const zcu = isel.pt.zcu;
const ip = &zcu.intern_pool;
- if (ty.isNoReturn(zcu) or !ty.hasRuntimeBitsIgnoreComptime(zcu)) return null;
+ if (!ty.hasRuntimeBits(zcu)) return null;
try isel.values.ensureUnusedCapacity(zcu.gpa, Value.max_parts);
const wip_vi = isel.initValue(ty);
type_key: switch (ip.indexToKey(ty.toIntern())) {
@@ -12195,7 +12169,7 @@ pub const CallAbiIterator = struct {
switch (loaded_struct.layout) {
.auto, .@"extern" => {},
.@"packed" => continue :type_key .{
- .int_type = ip.indexToKey(loaded_struct.backingIntTypeUnordered(ip)).int_type,
+ .int_type = ip.indexToKey(loaded_struct.packed_backing_int_type).int_type,
},
}
const size = wip_vi.size(isel);
@@ -12219,7 +12193,7 @@ pub const CallAbiIterator = struct {
const field_end = next_field_end;
const next_field_begin = if (field_it.next()) |field_index| next_field_begin: {
const field_ty: ZigType = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
- const next_field_begin = switch (loaded_struct.fieldAlign(ip, field_index)) {
+ const next_field_begin = switch (loaded_struct.field_aligns.getOrNone(ip, field_index)) {
.none => field_ty.abiAlignment(zcu),
else => |field_align| field_align,
}.forward(field_end);
@@ -12285,7 +12259,7 @@ pub const CallAbiIterator = struct {
},
.union_type => {
const loaded_union = ip.loadUnionType(ty.toIntern());
- switch (loaded_union.flagsUnordered(ip).layout) {
+ switch (loaded_union.layout) {
.auto, .@"extern" => {},
.@"packed" => continue :type_key .{ .int_type = .{
.signedness = .unsigned,
@@ -12318,7 +12292,9 @@ pub const CallAbiIterator = struct {
}
},
.opaque_type, .func_type => continue :type_key .{ .simple_type = .anyopaque },
- .enum_type => continue :type_key ip.indexToKey(ip.loadEnumType(ty.toIntern()).tag_ty),
+ .enum_type => continue :type_key .{
+ .int_type = ip.indexToKey(ip.loadEnumType(ty.toIntern()).int_tag_type).int_type,
+ },
.error_set_type,
.inferred_error_set_type,
=> continue :type_key .{ .simple_type = .anyerror },
@@ -12332,7 +12308,6 @@ pub const CallAbiIterator = struct {
.error_union,
.enum_literal,
.enum_tag,
- .empty_enum_value,
.float,
.ptr,
.slice,
@@ -12424,8 +12399,8 @@ pub const CallAbiIterator = struct {
const ip = &zcu.intern_pool;
var common_fdt: ?FundamentalDataType = null;
for (0.., loaded_struct.field_types.get(ip)) |field_index, field_ty| {
- if (loaded_struct.fieldIsComptime(ip, field_index)) continue;
- if (loaded_struct.fieldAlign(ip, field_index) != .none) return null;
+ if (loaded_struct.field_is_comptime_bits.get(ip, field_index)) continue;
+ if (loaded_struct.field_aligns.getOrNone(ip, field_index) != .none) return null;
if (!ZigType.fromInterned(field_ty).hasRuntimeBits(zcu)) continue;
const fdt = homogeneousAggregateBaseType(zcu, field_ty);
if (common_fdt == null) common_fdt = fdt else if (fdt != common_fdt) return null;
diff --git a/src/codegen/aarch64/abi.zig b/src/codegen/aarch64/abi.zig
index 9587415287d52becdb1f4d2e33d8e522134f3cd3..5b32aded166799de4851622e9235ae1f2914fa5c 100644
--- a/src/codegen/aarch64/abi.zig
+++ b/src/codegen/aarch64/abi.zig
@@ -13,7 +13,7 @@ pub const Class = union(enum) {
/// For `float_array` the second element will be the amount of floats.
pub fn classifyType(ty: Type, zcu: *Zcu) Class {
- assert(ty.hasRuntimeBitsIgnoreComptime(zcu));
+ assert(ty.hasRuntimeBits(zcu));
var maybe_float_bits: ?u16 = null;
switch (ty.zigTypeTag(zcu)) {
diff --git a/src/codegen/arm/abi.zig b/src/codegen/arm/abi.zig
index 23606d6145c45d80f1dde0d1405337fb2b1958bd..22bd34274f49e24d5538302a1a9c285414085c01 100644
--- a/src/codegen/arm/abi.zig
+++ b/src/codegen/arm/abi.zig
@@ -23,7 +23,7 @@ pub const Class = union(enum) {
pub const Context = enum { ret, arg };
pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class {
- assert(ty.hasRuntimeBitsIgnoreComptime(zcu));
+ assert(ty.hasRuntimeBits(zcu));
var maybe_float_bits: ?u16 = null;
const max_byval_size = 512;
@@ -39,22 +39,22 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class {
const float_count = countFloats(ty, zcu, &maybe_float_bits);
if (float_count <= byval_float_count) return .byval;
+ if (ty.abiAlignment(zcu).compare(.gt, .@"32")) {
+ return Class.arrSize(bit_size, 64);
+ }
+
const fields = ty.structFieldCount(zcu);
var i: u32 = 0;
while (i < fields) : (i += 1) {
const field_ty = ty.fieldType(i, zcu);
- const field_alignment = ty.fieldAlignment(i, zcu);
- const field_size = field_ty.bitSize(zcu);
- if (field_size > 32 or field_alignment.compare(.gt, .@"32")) {
- return Class.arrSize(bit_size, 64);
- }
+ if (field_ty.bitSize(zcu) > 32) return Class.arrSize(bit_size, 64);
}
return Class.arrSize(bit_size, 32);
},
.@"union" => {
const bit_size = ty.bitSize(zcu);
const union_obj = zcu.typeToUnion(ty).?;
- if (union_obj.flagsUnordered(ip).layout == .@"packed") {
+ if (union_obj.layout == .@"packed") {
if (bit_size > 64) return .memory;
return .byval;
}
@@ -62,10 +62,12 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class {
const float_count = countFloats(ty, zcu, &maybe_float_bits);
if (float_count <= byval_float_count) return .byval;
- for (union_obj.field_types.get(ip), 0..) |field_ty, field_index| {
- if (Type.fromInterned(field_ty).bitSize(zcu) > 32 or
- ty.fieldAlignment(field_index, zcu).compare(.gt, .@"32"))
- {
+ if (union_obj.alignment.compareStrict(.gt, .@"32")) {
+ return Class.arrSize(bit_size, 64);
+ }
+
+ for (union_obj.field_types.get(ip)) |field_ty| {
+ if (Type.fromInterned(field_ty).bitSize(zcu) > 32) {
return Class.arrSize(bit_size, 64);
}
}
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index 106737a8331c523f9ecddad0e0138f31a10ea06f..97e5ca22498df706b2fff70e5aebe7f1bf892ec3 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -50,32 +50,39 @@ pub fn legalizeFeatures(_: *const std.Target) ?*const Air.Legalize.Features {
/// * The types used, so declarations can be emitted in `flush`
/// * The lazy functions used, so definitions can be emitted in `flush`
pub const Mir = struct {
- /// This map contains all the UAVs we saw generating this function.
- /// `link.C` will merge them into its `uavs`/`aligned_uavs` fields.
- /// Key is the value of the UAV; value is the UAV's alignment, or
- /// `.none` for natural alignment. The specified alignment is never
- /// less than the natural alignment.
- uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment),
// These remaining fields are essentially just an owned version of `link.C.AvBlock`.
+ fwd_decl: []u8,
code_header: []u8,
code: []u8,
- fwd_decl: []u8,
- ctype_pool: CType.Pool,
- lazy_fns: LazyFnMap,
+ /// This map contains all the UAVs we saw generating this function.
+ /// `link.C` will merge them into its `uavs`/`aligned_uavs` fields.
+ /// Key is the value of the UAV; value is the UAV's alignment, or
+ /// `.none` for natural alignment. The specified alignment is never
+ /// less than the natural alignment.
+ need_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment),
+ ctype_deps: CType.Dependencies,
+ /// Key is an enum type for which we need a generated `@tagName` function.
+ need_tag_name_funcs: std.AutoArrayHashMapUnmanaged(InternPool.Index, void),
+ /// Key is a function Nav for which we need a generated `zig_never_tail` wrapper.
+ need_never_tail_funcs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void),
+ /// Key is a function Nav for which we need a generated `zig_never_inline` wrapper.
+ need_never_inline_funcs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void),
pub fn deinit(mir: *Mir, gpa: Allocator) void {
- mir.uavs.deinit(gpa);
+ gpa.free(mir.fwd_decl);
gpa.free(mir.code_header);
gpa.free(mir.code);
- gpa.free(mir.fwd_decl);
- mir.ctype_pool.deinit(gpa);
- mir.lazy_fns.deinit(gpa);
+ mir.need_uavs.deinit(gpa);
+ mir.ctype_deps.deinit(gpa);
+ mir.need_tag_name_funcs.deinit(gpa);
+ mir.need_never_tail_funcs.deinit(gpa);
+ mir.need_never_inline_funcs.deinit(gpa);
}
};
-pub const Error = Writer.Error || std.mem.Allocator.Error || error{AnalysisFail};
+pub const Error = Writer.Error || Allocator.Error || error{AnalysisFail};
-pub const CType = @import("c/Type.zig");
+pub const CType = @import("c/type.zig").CType;
pub const CValue = union(enum) {
none: void,
@@ -87,8 +94,6 @@ pub const CValue = union(enum) {
constant: Value,
/// Index into the parameters
arg: usize,
- /// The array field of a parameter
- arg_array: usize,
/// Index into a tuple's fields
field: usize,
/// By-value
@@ -100,8 +105,6 @@ pub const CValue = union(enum) {
identifier: []const u8,
/// Rendered as "payload." followed by as identifier (using fmtIdent)
payload_identifier: []const u8,
- /// Rendered with fmtCTypePoolString
- ctype_pool_string: CType.Pool.String,
fn eql(lhs: CValue, rhs: CValue) bool {
return switch (lhs) {
@@ -122,10 +125,6 @@ pub const CValue = union(enum) {
.arg => |rhs_arg_index| lhs_arg_index == rhs_arg_index,
else => false,
},
- .arg_array => |lhs_arg_index| switch (rhs) {
- .arg_array => |rhs_arg_index| lhs_arg_index == rhs_arg_index,
- else => false,
- },
.field => |lhs_field_index| switch (rhs) {
.field => |rhs_field_index| lhs_field_index == rhs_field_index,
else => false,
@@ -150,10 +149,6 @@ pub const CValue = union(enum) {
.payload_identifier => |rhs_id| std.mem.eql(u8, lhs_id, rhs_id),
else => false,
},
- .ctype_pool_string => |lhs_str| switch (rhs) {
- .ctype_pool_string => |rhs_str| lhs_str.index == rhs_str.index,
- else => false,
- },
};
}
};
@@ -163,53 +158,24 @@ const BlockData = struct {
result: CValue,
};
-pub const CValueMap = std.AutoHashMap(Air.Inst.Ref, CValue);
-
-pub const LazyFnKey = union(enum) {
- tag_name: InternPool.Index,
- never_tail: InternPool.Nav.Index,
- never_inline: InternPool.Nav.Index,
-};
-pub const LazyFnValue = struct {
- fn_name: CType.Pool.String,
-};
-pub const LazyFnMap = std.AutoArrayHashMapUnmanaged(LazyFnKey, LazyFnValue);
-
-const Local = struct {
- ctype: CType,
- flags: packed struct(u32) {
- alignas: CType.AlignAs,
- _: u20 = undefined,
- },
-
- fn getType(local: Local) LocalType {
- return .{ .ctype = local.ctype, .alignas = local.flags.alignas };
- }
+const LocalType = struct {
+ type: Type,
+ alignment: Alignment,
};
const LocalIndex = u16;
-const LocalType = struct { ctype: CType, alignas: CType.AlignAs };
const LocalsList = std.AutoArrayHashMapUnmanaged(LocalIndex, void);
const LocalsMap = std.AutoArrayHashMapUnmanaged(LocalType, LocalsList);
const ValueRenderLocation = enum {
- FunctionArgument,
- Initializer,
- StaticInitializer,
- Other,
+ initializer,
+ static_initializer,
+ other,
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,
+ .initializer, .static_initializer => true,
+ .other => false,
};
}
};
@@ -334,16 +300,31 @@ const reserved_idents = std.StaticStringMap(void).initComptime(.{
});
fn isReservedIdent(ident: []const u8) bool {
- if (ident.len >= 2 and ident[0] == '_') { // C language
+ // C language
+ if (ident.len >= 2 and ident[0] == '_') {
switch (ident[1]) {
'A'...'Z', '_' => return true,
- else => return false,
+ else => {},
}
- } else if (mem.startsWith(u8, ident, "DUMMYSTRUCTNAME") or
+ }
+
+ // windows.h
+ if (mem.startsWith(u8, ident, "DUMMYSTRUCTNAME") or
mem.startsWith(u8, ident, "DUMMYUNIONNAME"))
- { // windows.h
+ {
return true;
- } else return reserved_idents.has(ident);
+ }
+
+ // CType
+ if (mem.startsWith(u8, ident, "enum__") or
+ mem.startsWith(u8, ident, "bitpack__") or
+ mem.startsWith(u8, ident, "aligned__") or
+ mem.startsWith(u8, ident, "fn__"))
+ {
+ return true;
+ }
+
+ return reserved_idents.has(ident);
}
fn formatIdentSolo(ident: []const u8, w: *Writer) Writer.Error!void {
@@ -361,7 +342,7 @@ fn formatIdentOptions(ident: []const u8, w: *Writer, solo: bool) Writer.Error!vo
for (ident, 0..) |c, i| {
switch (c) {
'a'...'z', 'A'...'Z', '_' => try w.writeByte(c),
- '.' => try w.writeByte('_'),
+ '.', ' ' => try w.writeByte('_'),
'0'...'9' => if (i == 0) {
try w.print("_{x:2}", .{c});
} else {
@@ -380,29 +361,6 @@ pub fn fmtIdentUnsolo(ident: []const u8) std.fmt.Alt([]const u8, formatIdentUnso
return .{ .data = ident };
}
-const CTypePoolStringFormatData = struct {
- ctype_pool_string: CType.Pool.String,
- ctype_pool: *const CType.Pool,
- solo: bool,
-};
-fn formatCTypePoolString(data: CTypePoolStringFormatData, w: *Writer) Writer.Error!void {
- if (data.ctype_pool_string.toSlice(data.ctype_pool)) |slice|
- try formatIdentOptions(slice, w, data.solo)
- else
- try w.print("{f}", .{data.ctype_pool_string.fmt(data.ctype_pool)});
-}
-pub fn fmtCTypePoolString(
- ctype_pool_string: CType.Pool.String,
- ctype_pool: *const CType.Pool,
- solo: bool,
-) std.fmt.Alt(CTypePoolStringFormatData, formatCTypePoolString) {
- return .{ .data = .{
- .ctype_pool_string = ctype_pool_string,
- .ctype_pool = ctype_pool,
- .solo = solo,
- } };
-}
-
// 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 {
@@ -417,21 +375,26 @@ pub fn isMangledIdent(ident: []const u8, solo: bool) bool {
return false;
}
-/// This data is available when outputting .c code for a `InternPool.Index`
-/// that corresponds to `func`.
-/// It is not available when generating .h file.
+/// This data is available when rendering C source code for an interned function.
pub const Function = struct {
air: Air,
liveness: Air.Liveness,
- value_map: CValueMap,
+ value_map: std.AutoHashMap(Air.Inst.Ref, CValue),
blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .empty,
next_arg_index: u32 = 0,
next_block_index: u32 = 0,
- object: Object,
- lazy_fns: LazyFnMap,
+ dg: DeclGen,
+ code: Writer.Allocating,
+ indent_counter: usize,
+ /// Key is an enum type for which we need a generated `@tagName` function.
+ need_tag_name_funcs: std.AutoArrayHashMapUnmanaged(InternPool.Index, void),
+ /// Key is a function Nav for which we need a generated `zig_never_tail` wrapper.
+ need_never_tail_funcs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void),
+ /// Key is a function Nav for which we need a generated `zig_never_inline` wrapper.
+ need_never_inline_funcs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void),
func_index: InternPool.Index,
/// All the locals, to be emitted at the top of the function.
- locals: std.ArrayList(Local) = .empty,
+ locals: std.ArrayList(LocalType) = .empty,
/// Which locals are available for reuse, based on Type.
free_locals_map: LocalsMap = .{},
/// Locals which will not be freed by Liveness. This is used after a
@@ -445,37 +408,41 @@ pub const Function = struct {
/// for the switch cond. Dispatches should set this local to the new cond.
loop_switch_conds: std.AutoHashMapUnmanaged(Air.Inst.Index, LocalIndex) = .empty,
+ const indent_width = 1;
+ const indent_char = ' ';
+
+ fn newline(f: *Function) !void {
+ const w = &f.code.writer;
+ try w.writeByte('\n');
+ try w.splatByteAll(indent_char, f.indent_counter);
+ }
+ fn indent(f: *Function) void {
+ f.indent_counter += indent_width;
+ }
+ fn outdent(f: *Function) !void {
+ f.indent_counter -= indent_width;
+ const written = f.code.written();
+ switch (written[written.len - 1]) {
+ indent_char => f.code.shrinkRetainingCapacity(written.len - indent_width),
+ '\n' => try f.code.writer.splatByteAll(indent_char, f.indent_counter),
+ else => {
+ std.debug.print("\"{f}\"\n", .{std.zig.fmtString(written[written.len -| 100..])});
+ unreachable;
+ },
+ }
+ }
+
fn resolveInst(f: *Function, ref: Air.Inst.Ref) !CValue {
const gop = try f.value_map.getOrPut(ref);
- if (gop.found_existing) return gop.value_ptr.*;
-
- const pt = f.object.dg.pt;
- const zcu = pt.zcu;
- const val = (try f.air.value(ref, pt)).?;
- const ty = f.typeOf(ref);
-
- const result: CValue = if (lowersToArray(ty, zcu)) result: {
- const ch = &f.object.code_header.writer;
- const decl_c_value = try f.allocLocalValue(.{
- .ctype = try f.ctypeFromType(ty, .complete),
- .alignas = CType.AlignAs.fromAbiAlignment(ty.abiAlignment(zcu)),
- });
- const gpa = f.object.dg.gpa;
- try f.allocs.put(gpa, decl_c_value.new_local, false);
- try ch.writeAll("static ");
- try f.object.dg.renderTypeAndName(ch, ty, decl_c_value, Const, .none, .complete);
- try ch.writeAll(" = ");
- try f.object.dg.renderValue(ch, val, .StaticInitializer);
- try ch.writeAll(";\n ");
- break :result .{ .local = decl_c_value.new_local };
- } else .{ .constant = val };
-
- gop.value_ptr.* = result;
- return result;
+ if (!gop.found_existing) {
+ const val = try f.air.value(ref, f.dg.pt);
+ gop.value_ptr.* = .{ .constant = val.? };
+ }
+ return gop.value_ptr.*;
}
fn wantSafety(f: *Function) bool {
- return switch (f.object.dg.pt.zcu.optimizeMode()) {
+ return switch (f.dg.pt.zcu.optimizeMode()) {
.Debug, .ReleaseSafe => true,
.ReleaseFast, .ReleaseSmall => false,
};
@@ -485,18 +452,16 @@ pub const Function = struct {
/// those which go into `allocs`. This function does not add the resulting local into `allocs`;
/// that responsibility lies with the caller.
fn allocLocalValue(f: *Function, local_type: LocalType) !CValue {
- try f.locals.ensureUnusedCapacity(f.object.dg.gpa, 1);
- defer f.locals.appendAssumeCapacity(.{
- .ctype = local_type.ctype,
- .flags = .{ .alignas = local_type.alignas },
- });
- return .{ .new_local = @intCast(f.locals.items.len) };
+ try f.locals.ensureUnusedCapacity(f.dg.gpa, 1);
+ const index = f.locals.items.len;
+ f.locals.appendAssumeCapacity(local_type);
+ return .{ .new_local = @intCast(index) };
}
fn allocLocal(f: *Function, inst: ?Air.Inst.Index, ty: Type) !CValue {
return f.allocAlignedLocal(inst, .{
- .ctype = try f.ctypeFromType(ty, .complete),
- .alignas = CType.AlignAs.fromAbiAlignment(ty.abiAlignment(f.object.dg.pt.zcu)),
+ .type = ty,
+ .alignment = .none,
});
}
@@ -524,11 +489,10 @@ pub const Function = struct {
.none => unreachable,
.new_local, .local => |i| 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),
+ .constant => |val| try f.dg.renderValue(w, val, location),
.arg => |i| try w.print("a{d}", .{i}),
- .arg_array => |i| try f.writeCValueMember(w, .{ .arg = i }, .{ .identifier = "array" }),
- .undef => |ty| try f.object.dg.renderUndefValue(w, ty, location),
- else => try f.object.dg.writeCValue(w, c_value),
+ .undef => |ty| try f.dg.renderUndefValue(w, ty, location),
+ else => try f.dg.writeCValue(w, c_value),
}
}
@@ -537,17 +501,12 @@ pub const Function = struct {
.none => unreachable,
.new_local, .local, .constant => {
try w.writeAll("(*");
- try f.writeCValue(w, c_value, .Other);
+ try f.writeCValue(w, c_value, .other);
try w.writeByte(')');
},
.local_ref => |i| try w.print("t{d}", .{i}),
.arg => |i| try w.print("(*a{d})", .{i}),
- .arg_array => |i| {
- try w.writeAll("(*");
- try f.writeCValueMember(w, .{ .arg = i }, .{ .identifier = "array" });
- try w.writeByte(')');
- },
- else => try f.object.dg.writeCValueDeref(w, c_value),
+ else => try f.dg.writeCValueDeref(w, c_value),
}
}
@@ -558,119 +517,77 @@ pub const Function = struct {
member: CValue,
) Error!void {
switch (c_value) {
- .new_local, .local, .local_ref, .constant, .arg, .arg_array => {
- try f.writeCValue(w, c_value, .Other);
+ .new_local, .local, .local_ref, .constant, .arg => {
+ try f.writeCValue(w, c_value, .other);
try w.writeByte('.');
- try f.writeCValue(w, member, .Other);
+ try f.writeCValue(w, member, .other);
},
- else => return f.object.dg.writeCValueMember(w, c_value, member),
+ else => return f.dg.writeCValueMember(w, c_value, member),
}
}
fn writeCValueDerefMember(f: *Function, w: *Writer, c_value: CValue, member: CValue) !void {
switch (c_value) {
- .new_local, .local, .arg, .arg_array => {
- try f.writeCValue(w, c_value, .Other);
+ .new_local, .local, .arg => {
+ try f.writeCValue(w, c_value, .other);
try w.writeAll("->");
},
.constant => {
try w.writeByte('(');
- try f.writeCValue(w, c_value, .Other);
+ try f.writeCValue(w, c_value, .other);
try w.writeAll(")->");
},
.local_ref => {
try f.writeCValueDeref(w, c_value);
try w.writeByte('.');
},
- else => return f.object.dg.writeCValueDerefMember(w, c_value, member),
+ else => return f.dg.writeCValueDerefMember(w, c_value, member),
}
- try f.writeCValue(w, member, .Other);
+ try f.writeCValue(w, member, .other);
}
fn fail(f: *Function, comptime format: []const u8, args: anytype) Error {
- return f.object.dg.fail(format, args);
+ return f.dg.fail(format, args);
}
- fn ctypeFromType(f: *Function, ty: Type, kind: CType.Kind) !CType {
- return f.object.dg.ctypeFromType(ty, kind);
- }
-
- fn byteSize(f: *Function, ctype: CType) u64 {
- return f.object.dg.byteSize(ctype);
- }
-
- fn renderType(f: *Function, w: *Writer, ctype: Type) !void {
- return f.object.dg.renderType(w, ctype);
- }
-
- fn renderCType(f: *Function, w: *Writer, ctype: CType) !void {
- return f.object.dg.renderCType(w, ctype);
+ fn renderType(f: *Function, w: *Writer, ty: Type) !void {
+ return f.dg.renderType(w, ty);
}
fn renderIntCast(f: *Function, w: *Writer, dest_ty: Type, src: CValue, v: Vectorize, src_ty: Type, location: ValueRenderLocation) !void {
- return f.object.dg.renderIntCast(w, dest_ty, .{ .c_value = .{ .f = f, .value = src, .v = v } }, src_ty, location);
+ return f.dg.renderIntCast(w, dest_ty, .{ .c_value = .{ .f = f, .value = src, .v = v } }, src_ty, location);
}
fn fmtIntLiteralDec(f: *Function, val: Value) !std.fmt.Alt(FormatIntLiteralContext, formatIntLiteral) {
- return f.object.dg.fmtIntLiteralDec(val, .Other);
+ return f.dg.fmtIntLiteralDec(val, .other);
}
fn fmtIntLiteralHex(f: *Function, val: Value) !std.fmt.Alt(FormatIntLiteralContext, formatIntLiteral) {
- return f.object.dg.fmtIntLiteralHex(val, .Other);
- }
-
- fn getLazyFnName(f: *Function, key: LazyFnKey) ![]const u8 {
- const gpa = f.object.dg.gpa;
- const pt = f.object.dg.pt;
- const zcu = pt.zcu;
- const ip = &zcu.intern_pool;
- const ctype_pool = &f.object.dg.ctype_pool;
-
- const gop = try f.lazy_fns.getOrPut(gpa, key);
- if (!gop.found_existing) {
- errdefer _ = f.lazy_fns.pop();
-
- gop.value_ptr.* = .{
- .fn_name = switch (key) {
- .tag_name,
- => |enum_ty| try ctype_pool.fmt(gpa, "zig_{s}_{f}__{d}", .{
- @tagName(key),
- fmtIdentUnsolo(ip.loadEnumType(enum_ty).name.toSlice(ip)),
- @intFromEnum(enum_ty),
- }),
- .never_tail,
- .never_inline,
- => |owner_nav| try ctype_pool.fmt(gpa, "zig_{s}_{f}__{d}", .{
- @tagName(key),
- fmtIdentUnsolo(ip.getNav(owner_nav).name.toSlice(ip)),
- @intFromEnum(owner_nav),
- }),
- },
- };
- }
- return gop.value_ptr.fn_name.toSlice(ctype_pool).?;
+ return f.dg.fmtIntLiteralHex(val, .other);
}
pub fn deinit(f: *Function) void {
- const gpa = f.object.dg.gpa;
+ const gpa = f.dg.gpa;
f.allocs.deinit(gpa);
f.locals.deinit(gpa);
deinitFreeLocalsMap(gpa, &f.free_locals_map);
f.blocks.deinit(gpa);
f.value_map.deinit();
- f.lazy_fns.deinit(gpa);
+ f.need_tag_name_funcs.deinit(gpa);
+ f.need_never_tail_funcs.deinit(gpa);
+ f.need_never_inline_funcs.deinit(gpa);
f.loop_switch_conds.deinit(gpa);
}
fn typeOf(f: *Function, inst: Air.Inst.Ref) Type {
- return f.air.typeOf(inst, &f.object.dg.pt.zcu.intern_pool);
+ return f.air.typeOf(inst, &f.dg.pt.zcu.intern_pool);
}
fn typeOfIndex(f: *Function, inst: Air.Inst.Index) Type {
- return f.air.typeOfIndex(inst, &f.object.dg.pt.zcu.intern_pool);
+ return f.air.typeOfIndex(inst, &f.dg.pt.zcu.intern_pool);
}
- fn copyCValue(f: *Function, ctype: CType, dst: CValue, src: CValue) !void {
+ fn copyCValue(f: *Function, 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,
@@ -678,12 +595,12 @@ pub const Function = struct {
},
else => {},
}
- const w = &f.object.code.writer;
- const a = try Assignment.start(f, w, ctype);
- try f.writeCValue(w, dst, .Other);
- try a.assign(f, w);
- try f.writeCValue(w, src, .Other);
- try a.end(f, w);
+ const w = &f.code.writer;
+ try f.writeCValue(w, dst, .other);
+ try w.writeAll(" = ");
+ try f.writeCValue(w, src, .other);
+ try w.writeByte(';');
+ try f.newline();
}
fn moveCValue(f: *Function, inst: Air.Inst.Index, ty: Type, src: CValue) !CValue {
@@ -694,7 +611,7 @@ pub const Function = struct {
else => {
try freeCValue(f, inst, src);
const dst = try f.allocLocal(inst, ty);
- try f.copyCValue(try f.ctypeFromType(ty, .complete), dst, src);
+ try f.copyCValue(dst, src);
return dst;
},
}
@@ -708,51 +625,17 @@ pub const Function = struct {
}
};
-/// This data is available when outputting .c code for a `Zcu`.
-/// It is not available when generating .h file.
-pub const Object = struct {
- dg: DeclGen,
- code_header: Writer.Allocating,
- code: Writer.Allocating,
- indent_counter: usize,
-
- const indent_width = 1;
- const indent_char = ' ';
-
- fn newline(o: *Object) !void {
- const w = &o.code.writer;
- try w.writeByte('\n');
- try w.splatByteAll(indent_char, o.indent_counter);
- }
- fn indent(o: *Object) void {
- o.indent_counter += indent_width;
- }
- fn outdent(o: *Object) !void {
- o.indent_counter -= indent_width;
- const written = o.code.written();
- switch (written[written.len - 1]) {
- indent_char => o.code.shrinkRetainingCapacity(written.len - indent_width),
- '\n' => try o.code.writer.splatByteAll(indent_char, o.indent_counter),
- else => {
- std.debug.print("\"{f}\"\n", .{std.zig.fmtString(written[written.len -| 100..])});
- unreachable;
- },
- }
- }
-};
-
-/// This data is available both when outputting .c code and when outputting an .h file.
+/// This data is available when rendering *any* C source code (function or otherwise).
pub const DeclGen = struct {
gpa: Allocator,
+ arena: Allocator,
pt: Zcu.PerThread,
mod: *Module,
- pass: Pass,
+ owner_nav: InternPool.Nav.Index.Optional,
is_naked_fn: bool,
expected_block: ?u32,
- fwd_decl: Writer.Allocating,
error_msg: ?*Zcu.ErrorMsg,
- ctype_pool: CType.Pool,
- scratch: std.ArrayList(u32),
+ ctype_deps: CType.Dependencies,
/// This map contains all the UAVs we saw generating this function.
/// `link.C` will merge them into its `uavs`/`aligned_uavs` fields.
/// Key is the value of the UAV; value is the UAV's alignment, or
@@ -760,16 +643,10 @@ pub const DeclGen = struct {
/// less than the natural alignment.
uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment),
- pub const Pass = union(enum) {
- nav: InternPool.Nav.Index,
- uav: InternPool.Index,
- flush,
- };
-
fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) Error {
@branchHint(.cold);
const zcu = dg.pt.zcu;
- const src_loc = zcu.navSrcLoc(dg.pass.nav);
+ const src_loc = zcu.navSrcLoc(dg.owner_nav.unwrap().?);
dg.error_msg = try Zcu.ErrorMsg.create(dg.gpa, src_loc, format, args);
return error.AnalysisFail;
}
@@ -783,14 +660,13 @@ pub const DeclGen = struct {
const pt = dg.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
- const ctype_pool = &dg.ctype_pool;
const uav_val = Value.fromInterned(uav.val);
const uav_ty = uav_val.typeOf(zcu);
// Render an undefined pointer if we have a pointer to a zero-bit or comptime type.
const ptr_ty: Type = .fromInterned(uav.orig_ty);
- if (ptr_ty.isPtrAtRuntime(zcu) and !uav_ty.isFnOrHasRuntimeBits(zcu)) {
- return dg.writeCValue(w, .{ .undef = ptr_ty });
+ if (ptr_ty.isPtrAtRuntime(zcu) and !uav_ty.isRuntimeFnOrHasRuntimeBits(zcu)) {
+ return dg.renderUndefValue(w, ptr_ty, location);
}
// Chase function values in order to be able to reference the original function.
@@ -805,14 +681,12 @@ 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 ptr_ctype = try dg.ctypeFromType(ptr_ty, .complete);
- const elem_ctype = ptr_ctype.info(ctype_pool).pointer.elem_ctype;
- const uav_ctype = try dg.ctypeFromType(uav_ty, .complete);
- const need_cast = !elem_ctype.eql(uav_ctype) and
- (elem_ctype.info(ctype_pool) != .function or uav_ctype.info(ctype_pool) != .function);
+ const elem_ty = ptr_ty.childType(zcu);
+ const need_cast = elem_ty.toIntern() != uav_ty.toIntern() and
+ elem_ty.zigTypeTag(zcu) != .@"fn" or uav_ty.zigTypeTag(zcu) != .@"fn";
if (need_cast) {
try w.writeAll("((");
- try dg.renderCType(w, ptr_ctype);
+ try dg.renderType(w, ptr_ty);
try w.writeByte(')');
}
try w.writeByte('&');
@@ -842,11 +716,9 @@ pub const DeclGen = struct {
nav_index: InternPool.Nav.Index,
location: ValueRenderLocation,
) Error!void {
- _ = location;
const pt = dg.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
- const ctype_pool = &dg.ctype_pool;
// Chase function values in order to be able to reference the original function.
const owner_nav = switch (ip.getNav(nav_index).status) {
@@ -862,26 +734,24 @@ pub const DeclGen = struct {
// Render an undefined pointer if we have a pointer to a zero-bit or comptime type.
const nav_ty: Type = .fromInterned(ip.getNav(owner_nav).typeOf(ip));
const ptr_ty = try pt.navPtrType(owner_nav);
- if (!nav_ty.isFnOrHasRuntimeBits(zcu)) {
- return dg.writeCValue(w, .{ .undef = ptr_ty });
+ if (!nav_ty.isRuntimeFnOrHasRuntimeBits(zcu)) {
+ return dg.renderUndefValue(w, ptr_ty, location);
}
// We shouldn't cast C function pointers as this is UB (when you call
// 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 ctype = try dg.ctypeFromType(ptr_ty, .complete);
- const elem_ctype = ctype.info(ctype_pool).pointer.elem_ctype;
- const nav_ctype = try dg.ctypeFromType(nav_ty, .complete);
- const need_cast = !elem_ctype.eql(nav_ctype) and
- (elem_ctype.info(ctype_pool) != .function or nav_ctype.info(ctype_pool) != .function);
+ const elem_ty = ptr_ty.childType(zcu);
+ const need_cast = elem_ty.toIntern() != nav_ty.toIntern() and
+ elem_ty.zigTypeTag(zcu) != .@"fn" or nav_ty.zigTypeTag(zcu) != .@"fn";
if (need_cast) {
try w.writeAll("((");
- try dg.renderCType(w, ctype);
+ try dg.renderType(w, ptr_ty);
try w.writeByte(')');
}
try w.writeByte('&');
- try dg.renderNavName(w, owner_nav);
+ try renderNavName(w, owner_nav, ip);
if (need_cast) try w.writeByte(')');
}
@@ -896,11 +766,10 @@ pub const DeclGen = struct {
switch (derivation) {
.comptime_alloc_ptr, .comptime_field_ptr => unreachable,
.int => |int| {
- const ptr_ctype = try dg.ctypeFromType(int.ptr_ty, .complete);
const addr_val = try pt.intValue(.usize, int.addr);
try w.writeByte('(');
- try dg.renderCType(w, ptr_ctype);
- try w.print("){f}", .{try dg.fmtIntLiteralHex(addr_val, .Other)});
+ try dg.renderType(w, int.ptr_ty);
+ try w.print("){f}", .{try dg.fmtIntLiteralHex(addr_val, .other)});
},
.nav_ptr => |nav| try dg.renderNav(w, nav, location),
@@ -915,14 +784,10 @@ pub const DeclGen = struct {
.field_ptr => |field| {
const parent_ptr_ty = try field.parent.ptrType(pt);
- // Ensure complete type definition is available before accessing fields.
- _ = try dg.ctypeFromType(parent_ptr_ty.childType(zcu), .complete);
-
switch (fieldLocation(parent_ptr_ty, field.result_ptr_ty, field.field_idx, zcu)) {
.begin => {
- const ptr_ctype = try dg.ctypeFromType(field.result_ptr_ty, .complete);
try w.writeByte('(');
- try dg.renderCType(w, ptr_ctype);
+ try dg.renderType(w, field.result_ptr_ty);
try w.writeByte(')');
try dg.renderPointer(w, field.parent.*, location);
},
@@ -933,51 +798,40 @@ pub const DeclGen = struct {
try dg.writeCValue(w, name);
},
.byte_offset => |byte_offset| {
- const ptr_ctype = try dg.ctypeFromType(field.result_ptr_ty, .complete);
try w.writeByte('(');
- try dg.renderCType(w, ptr_ctype);
+ try dg.renderType(w, field.result_ptr_ty);
try w.writeByte(')');
const offset_val = try pt.intValue(.usize, byte_offset);
try w.writeAll("((char *)");
try dg.renderPointer(w, field.parent.*, location);
- try w.print(" + {f})", .{try dg.fmtIntLiteralDec(offset_val, .Other)});
+ try w.print(" + {f})", .{try dg.fmtIntLiteralDec(offset_val, .other)});
},
}
},
.elem_ptr => |elem| if (!(try elem.parent.ptrType(pt)).childType(zcu).hasRuntimeBits(zcu)) {
// Element type is zero-bit, so lowers to `void`. The index is irrelevant; just cast the pointer.
- const ptr_ctype = try dg.ctypeFromType(elem.result_ptr_ty, .complete);
try w.writeByte('(');
- try dg.renderCType(w, ptr_ctype);
+ try dg.renderType(w, elem.result_ptr_ty);
try w.writeByte(')');
try dg.renderPointer(w, elem.parent.*, location);
} else {
const index_val = try pt.intValue(.usize, elem.elem_idx);
- // We want to do pointer arithmetic on a pointer to the element type.
- // We might have a pointer-to-array. In this case, we must cast first.
- const result_ctype = try dg.ctypeFromType(elem.result_ptr_ty, .complete);
- const parent_ctype = try dg.ctypeFromType(try elem.parent.ptrType(pt), .complete);
- if (result_ctype.eql(parent_ctype)) {
- // The pointer already has an appropriate type - just do the arithmetic.
+ try w.writeByte('(');
+ // We want to do pointer arithmetic on a pointer to the element type, but the parent
+ // might be a pointer-to-array, in which case we must cast it.
+ if (elem.result_ptr_ty.toIntern() != (try elem.parent.ptrType(pt)).toIntern()) {
try w.writeByte('(');
- try dg.renderPointer(w, elem.parent.*, location);
- try w.print(" + {f})", .{try dg.fmtIntLiteralDec(index_val, .Other)});
- } else {
- // We probably have an array pointer `T (*)[n]`. Cast to an element pointer,
- // and *then* apply the index.
- try w.writeAll("((");
- try dg.renderCType(w, result_ctype);
+ try dg.renderType(w, elem.result_ptr_ty);
try w.writeByte(')');
- try dg.renderPointer(w, elem.parent.*, location);
- try w.print(" + {f})", .{try dg.fmtIntLiteralDec(index_val, .Other)});
}
+ try dg.renderPointer(w, elem.parent.*, location);
+ try w.print(" + {f})", .{try dg.fmtIntLiteralDec(index_val, .other)});
},
.offset_and_cast => |oac| {
- const ptr_ctype = try dg.ctypeFromType(oac.new_ptr_ty, .complete);
try w.writeByte('(');
- try dg.renderCType(w, ptr_ctype);
+ try dg.renderType(w, oac.new_ptr_ty);
try w.writeByte(')');
if (oac.byte_offset == 0) {
try dg.renderPointer(w, oac.parent.*, location);
@@ -985,14 +839,40 @@ pub const DeclGen = struct {
const offset_val = try pt.intValue(.usize, oac.byte_offset);
try w.writeAll("((char *)");
try dg.renderPointer(w, oac.parent.*, location);
- try w.print(" + {f})", .{try dg.fmtIntLiteralDec(offset_val, .Other)});
+ try w.print(" + {f})", .{try dg.fmtIntLiteralDec(offset_val, .other)});
}
},
}
}
- fn renderErrorName(dg: *DeclGen, w: *Writer, err_name: InternPool.NullTerminatedString) !void {
- try w.print("zig_error_{f}", .{fmtIdentUnsolo(err_name.toSlice(&dg.pt.zcu.intern_pool))});
+ fn renderValueAsLvalue(
+ dg: *DeclGen,
+ w: *Writer,
+ val: Value,
+ ) Error!void {
+ const zcu = dg.pt.zcu;
+
+ // If the type of `val` lowers to a C struct or union type, then `renderValue` will render
+ // it as a compound literal, and compound literals are already lvalues.
+ const ty = val.typeOf(zcu);
+ const is_aggregate: bool = switch (ty.zigTypeTag(zcu)) {
+ .@"struct", .@"union" => switch (ty.containerLayout(zcu)) {
+ .auto, .@"extern" => true,
+ .@"packed" => false,
+ },
+ .array,
+ .vector,
+ .error_union,
+ .optional,
+ => true,
+ else => false,
+ };
+ if (is_aggregate) return renderValue(dg, w, val, .other);
+
+ // Otherwise, use a UAV.
+ const gop = try dg.uavs.getOrPut(dg.gpa, val.toIntern());
+ if (!gop.found_existing) gop.value_ptr.* = .none;
+ try renderUavName(w, val);
}
fn renderValue(
@@ -1005,16 +885,13 @@ pub const DeclGen = struct {
const zcu = pt.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,
- else => .Initializer,
+ .static_initializer => .static_initializer,
+ else => .initializer,
};
const ty = val.typeOf(zcu);
- if (val.isUndef(zcu)) return dg.renderUndefValue(w, ty, location);
- const ctype = try dg.ctypeFromType(ty, location.toCTypeKind());
switch (ip.indexToKey(val.toIntern())) {
// types, not values
.int_type,
@@ -1037,13 +914,11 @@ pub const DeclGen = struct {
.memoized_call,
=> unreachable,
- .undef => unreachable, // handled above
+ .undef => try dg.renderUndefValue(w, ty, location),
.simple_value => |simple_value| switch (simple_value) {
// non-runtime values
- .undefined => unreachable,
.void => unreachable,
.null => unreachable,
- .empty_tuple => unreachable,
.@"unreachable" => unreachable,
.false => try w.writeAll("false"),
@@ -1053,59 +928,30 @@ pub const DeclGen = struct {
.@"extern",
.func,
.enum_literal,
- .empty_enum_value,
=> unreachable, // non-runtime values
- .int => |int| switch (int.storage) {
- .u64, .i64, .big_int => try w.print("{f}", .{try dg.fmtIntLiteralDec(val, location)}),
- .lazy_align, .lazy_size => {
- try w.writeAll("((");
- try dg.renderCType(w, ctype);
- try w.print("){f})", .{try dg.fmtIntLiteralHex(
- try pt.intValue(.usize, val.toUnsignedInt(zcu)),
- .Other,
- )});
- },
- },
- .err => |err| try dg.renderErrorName(w, err.name),
- .error_union => |error_union| switch (ctype.info(ctype_pool)) {
- .basic => switch (error_union.val) {
- .err_name => |err_name| try dg.renderErrorName(w, err_name),
+ .int => try w.print("{f}", .{try dg.fmtIntLiteralDec(val, location)}),
+ .err => |err| try renderErrorName(w, err.name.toSlice(ip)),
+ .error_union => |error_union| {
+ if (!location.isInitializer()) {
+ try w.writeByte('(');
+ try dg.renderType(w, ty);
+ try w.writeByte(')');
+ }
+ try w.writeAll("{ .error = ");
+ switch (error_union.val) {
+ .err_name => |err_name| try renderErrorName(w, err_name.toSlice(ip)),
.payload => try w.writeByte('0'),
- },
- .pointer, .aligned, .array, .vector, .fwd_decl, .function => unreachable,
- .aggregate => |aggregate| {
- if (!location.isInitializer()) {
- try w.writeByte('(');
- try dg.renderCType(w, ctype);
- try w.writeByte(')');
+ }
+ if (ty.errorUnionPayload(zcu).hasRuntimeBits(zcu)) {
+ try w.writeAll(", .payload = ");
+ switch (error_union.val) {
+ .err_name => try dg.renderUndefValue(w, ty.errorUnionPayload(zcu), initializer_type),
+ .payload => |payload| try dg.renderValue(w, .fromInterned(payload), initializer_type),
}
- try w.writeByte('{');
- for (0..aggregate.fields.len) |field_index| {
- if (field_index > 0) try w.writeByte(',');
- switch (aggregate.fields.at(field_index, ctype_pool).name.index) {
- .@"error" => switch (error_union.val) {
- .err_name => |err_name| try dg.renderErrorName(w, err_name),
- .payload => try w.writeByte('0'),
- },
- .payload => switch (error_union.val) {
- .err_name => try dg.renderUndefValue(
- w,
- ty.errorUnionPayload(zcu),
- initializer_type,
- ),
- .payload => |payload| try dg.renderValue(
- w,
- Value.fromInterned(payload),
- initializer_type,
- ),
- },
- else => unreachable,
- }
- }
- try w.writeByte('}');
- },
+ }
+ try w.writeAll(" }");
},
- .enum_tag => |enum_tag| try dg.renderValue(w, Value.fromInterned(enum_tag.int), location),
+ .enum_tag => |enum_tag| try dg.renderValue(w, .fromInterned(enum_tag.int), location),
.float => {
const bits = ty.floatBits(target);
const f128_val = val.toFloat(f128, zcu);
@@ -1156,7 +1002,7 @@ pub const DeclGen = struct {
else
unreachable;
- if (location == .StaticInitializer) {
+ if (location == .static_initializer) {
if (!std.math.isNan(f128_val) and std.math.isSignalNan(f128_val))
return dg.fail("TODO: C backend: implement nans rendering in static initializers", .{});
@@ -1167,9 +1013,11 @@ pub const DeclGen = struct {
// return dg.fail("Only quiet nans are supported in global variable initializers", .{});
}
- try w.writeAll("zig_");
- try w.writeAll(if (location == .StaticInitializer) "init" else "make");
- try w.writeAll("_special_");
+ if (location == .static_initializer) {
+ try w.writeAll("zig_init_special_");
+ } else {
+ try w.writeAll("zig_make_special_");
+ }
try dg.renderTypeForBuiltinFnName(w, ty);
try w.writeByte('(');
if (std.math.signbit(f128_val)) try w.writeByte('-');
@@ -1196,105 +1044,85 @@ pub const DeclGen = struct {
if (!empty) try w.writeByte(')');
},
.slice => |slice| {
- const aggregate = ctype.info(ctype_pool).aggregate;
if (!location.isInitializer()) {
try w.writeByte('(');
- try dg.renderCType(w, ctype);
+ try dg.renderType(w, ty);
try w.writeByte(')');
}
try w.writeByte('{');
- for (0..aggregate.fields.len) |field_index| {
- if (field_index > 0) try w.writeByte(',');
- try dg.renderValue(w, Value.fromInterned(
- switch (aggregate.fields.at(field_index, ctype_pool).name.index) {
- .ptr => slice.ptr,
- .len => slice.len,
- else => unreachable,
- },
- ), initializer_type);
- }
+ try dg.renderValue(w, .fromInterned(slice.ptr), initializer_type);
+ try w.writeByte(',');
+ try dg.renderValue(w, .fromInterned(slice.len), initializer_type);
try w.writeByte('}');
},
.ptr => {
- var arena = std.heap.ArenaAllocator.init(zcu.gpa);
- defer arena.deinit();
- const derivation = try val.pointerDerivation(arena.allocator(), pt);
+ const derivation = try val.pointerDerivation(dg.arena, pt, null);
+ try w.writeByte('(');
try dg.renderPointer(w, derivation, location);
+ try w.writeByte(')');
},
- .opt => |opt| switch (ctype.info(ctype_pool)) {
- .basic => if (ctype.isBool()) try w.writeAll(switch (opt.val) {
- .none => "true",
- else => "false",
- }) else switch (opt.val) {
+ .opt => |opt| switch (CType.classifyOptional(ty, zcu)) {
+ .npv_payload => unreachable, // opv optional
+ .opv_payload => {
+ if (!location.isInitializer()) {
+ try w.writeByte('(');
+ try dg.renderType(w, ty);
+ try w.writeByte(')');
+ }
+ try w.writeAll(switch (opt.val) {
+ .none => "{.is_null = true}",
+ else => "{.is_null = false}",
+ });
+ },
+ .error_set => switch (opt.val) {
.none => try w.writeByte('0'),
- else => |payload| switch (ip.indexToKey(payload)) {
- .undef => |err_ty| try dg.renderUndefValue(
- w,
- .fromInterned(err_ty),
- location,
- ),
- .err => |err| try dg.renderErrorName(w, err.name),
- else => unreachable,
- },
+ else => |payload_val| try dg.renderValue(w, .fromInterned(payload_val), location),
},
- .pointer => switch (opt.val) {
+ .ptr_like => switch (opt.val) {
.none => try w.writeAll("NULL"),
- else => |payload| try dg.renderValue(w, Value.fromInterned(payload), location),
+ else => |payload_val| try dg.renderValue(w, .fromInterned(payload_val), location),
},
- .aligned, .array, .vector, .fwd_decl, .function => unreachable,
- .aggregate => |aggregate| {
+ .slice_like => switch (opt.val) {
+ .none => {
+ if (!location.isInitializer()) {
+ try w.writeByte('(');
+ try dg.renderType(w, ty);
+ try w.writeByte(')');
+ }
+ try w.writeAll("{NULL,");
+ try dg.renderUndefValue(w, .usize, initializer_type);
+ try w.writeByte('}');
+ },
+ else => |payload_val| try dg.renderValue(w, .fromInterned(payload_val), location),
+ },
+ .@"struct" => {
+ if (!location.isInitializer()) {
+ try w.writeByte('(');
+ try dg.renderType(w, ty);
+ try w.writeByte(')');
+ }
switch (opt.val) {
- .none => {},
- else => |payload| switch (aggregate.fields.at(0, ctype_pool).name.index) {
- .is_null, .payload => {},
- .ptr, .len => return dg.renderValue(
- w,
- Value.fromInterned(payload),
- location,
- ),
- else => unreachable,
+ .none => {
+ try w.writeAll("{ .is_null = true, .payload = ");
+ try dg.renderUndefValue(w, ty.optionalChild(zcu), initializer_type);
+ try w.writeAll(" }");
+ },
+ else => |payload_val| {
+ try w.writeAll("{ .is_null = false, .payload = ");
+ try dg.renderValue(w, .fromInterned(payload_val), initializer_type);
+ try w.writeAll(" }");
},
}
- if (!location.isInitializer()) {
- try w.writeByte('(');
- try dg.renderCType(w, ctype);
- try w.writeByte(')');
- }
- try w.writeByte('{');
- for (0..aggregate.fields.len) |field_index| {
- if (field_index > 0) try w.writeByte(',');
- switch (aggregate.fields.at(field_index, ctype_pool).name.index) {
- .is_null => try w.writeAll(switch (opt.val) {
- .none => "true",
- else => "false",
- }),
- .payload => switch (opt.val) {
- .none => try dg.renderUndefValue(
- w,
- ty.optionalChild(zcu),
- initializer_type,
- ),
- else => |payload| try dg.renderValue(
- w,
- Value.fromInterned(payload),
- initializer_type,
- ),
- },
- .ptr => try w.writeAll("NULL"),
- .len => try dg.renderUndefValue(w, .usize, initializer_type),
- else => unreachable,
- }
- }
- try w.writeByte('}');
},
},
.aggregate => switch (ip.indexToKey(ty.toIntern())) {
.array_type, .vector_type => {
- if (location == .FunctionArgument) {
+ if (!location.isInitializer()) {
try w.writeByte('(');
- try dg.renderCType(w, ctype);
+ try dg.renderType(w, ty);
try w.writeByte(')');
}
+ try w.writeByte('{');
const ai = ty.arrayInfo(zcu);
if (ai.elem_type.eql(.u8, zcu)) {
var literal: StringLiteral = .init(w, @intCast(ty.arrayLenIncludingSentinel(zcu)));
@@ -1327,11 +1155,12 @@ pub const DeclGen = struct {
}
try w.writeByte('}');
}
+ try w.writeByte('}');
},
.tuple_type => |tuple| {
if (!location.isInitializer()) {
try w.writeByte('(');
- try dg.renderCType(w, ctype);
+ try dg.renderType(w, ty);
try w.writeByte(')');
}
@@ -1341,7 +1170,7 @@ pub const DeclGen = struct {
const comptime_val = tuple.values.get(ip)[field_index];
if (comptime_val != .none) continue;
const field_ty: Type = .fromInterned(tuple.types.get(ip)[field_index]);
- if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
+ if (!field_ty.hasRuntimeBits(zcu)) continue;
if (!empty) try w.writeByte(',');
@@ -1363,139 +1192,95 @@ pub const DeclGen = struct {
},
.struct_type => {
const loaded_struct = ip.loadStructType(ty.toIntern());
- switch (loaded_struct.layout) {
- .auto, .@"extern" => {
- if (!location.isInitializer()) {
- try w.writeByte('(');
- try dg.renderCType(w, ctype);
- try w.writeByte(')');
- }
+ assert(loaded_struct.layout != .@"packed");
- try w.writeByte('{');
- var field_it = loaded_struct.iterateRuntimeOrder(ip);
- var need_comma = false;
- while (field_it.next()) |field_index| {
- const field_ty: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
- if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
+ if (!location.isInitializer()) {
+ try w.writeByte('(');
+ try dg.renderType(w, ty);
+ try w.writeByte(')');
+ }
+
+ try w.writeByte('{');
+ var field_it = loaded_struct.iterateRuntimeOrder(ip);
+ var need_comma = false;
+ while (field_it.next()) |field_index| {
+ const field_ty: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
+ if (!field_ty.hasRuntimeBits(zcu)) continue;
- if (need_comma) try w.writeByte(',');
- need_comma = true;
- const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
- .bytes => |bytes| try pt.intern(.{ .int = .{
- .ty = field_ty.toIntern(),
- .storage = .{ .u64 = bytes.at(field_index, ip) },
- } }),
- .elems => |elems| elems[field_index],
- .repeated_elem => |elem| elem,
- };
- try dg.renderValue(w, Value.fromInterned(field_val), initializer_type);
- }
- try w.writeByte('}');
- },
- .@"packed" => {
- // https://github.com/ziglang/zig/issues/24657 will eliminate most of the
- // following logic, leaving only the recursive `renderValue` call. Once
- // that proposal is implemented, a `packed struct` will literally be
- // represented in the InternPool by its comptime-known backing integer.
- var arena: std.heap.ArenaAllocator = .init(zcu.gpa);
- defer arena.deinit();
- const backing_ty: Type = .fromInterned(loaded_struct.backingIntTypeUnordered(ip));
- const buf = try arena.allocator().alloc(u8, @intCast(ty.abiSize(zcu)));
- val.writeToMemory(pt, buf) catch |err| switch (err) {
- error.IllDefinedMemoryLayout => unreachable,
- error.OutOfMemory => |e| return e,
- error.ReinterpretDeclRef, error.Unimplemented => return dg.fail("TODO: C backend: lower packed struct value", .{}),
- };
- const backing_val: Value = try .readUintFromMemory(backing_ty, pt, buf, arena.allocator());
- return dg.renderValue(w, backing_val, location);
- },
+ if (need_comma) try w.writeByte(',');
+ need_comma = true;
+ const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
+ .bytes => |bytes| try pt.intern(.{ .int = .{
+ .ty = field_ty.toIntern(),
+ .storage = .{ .u64 = bytes.at(field_index, ip) },
+ } }),
+ .elems => |elems| elems[field_index],
+ .repeated_elem => |elem| elem,
+ };
+ try dg.renderValue(w, Value.fromInterned(field_val), initializer_type);
}
+ try w.writeByte('}');
},
else => unreachable,
},
+ .bitpack => |bitpack| return dg.renderValue(w, .fromInterned(bitpack.backing_int_val), location),
.un => |un| {
const loaded_union = ip.loadUnionType(ty.toIntern());
- if (loaded_union.flagsUnordered(ip).layout == .@"packed") {
- // https://github.com/ziglang/zig/issues/24657 will eliminate most of the
- // following logic, leaving only the recursive `renderValue` call. Once
- // that proposal is implemented, a `packed union` will literally be
- // represented in the InternPool by its comptime-known backing integer.
- var arena: std.heap.ArenaAllocator = .init(zcu.gpa);
- defer arena.deinit();
- const backing_ty = try ty.unionBackingType(pt);
- const buf = try arena.allocator().alloc(u8, @intCast(ty.abiSize(zcu)));
- val.writeToMemory(pt, buf) catch |err| switch (err) {
- error.IllDefinedMemoryLayout => unreachable,
- error.OutOfMemory => |e| return e,
- error.ReinterpretDeclRef, error.Unimplemented => return dg.fail("TODO: C backend: lower packed union value", .{}),
- };
- const backing_val: Value = try .readUintFromMemory(backing_ty, pt, buf, arena.allocator());
- return dg.renderValue(w, backing_val, location);
- }
if (un.tag == .none) {
- const backing_ty = try ty.unionBackingType(pt);
- assert(loaded_union.flagsUnordered(ip).layout == .@"extern");
- if (location == .StaticInitializer) {
+ assert(loaded_union.layout == .@"extern");
+ if (location == .static_initializer) {
return dg.fail("TODO: C backend: implement extern union backing type rendering in static initializers", .{});
}
const ptr_ty = try pt.singleConstPtrType(ty);
- try w.writeAll("*((");
+ try w.writeAll("*(");
try dg.renderType(w, ptr_ty);
- try w.writeAll(")(");
- try dg.renderType(w, backing_ty);
- try w.writeAll("){");
- try dg.renderValue(w, Value.fromInterned(un.val), location);
- try w.writeAll("})");
+ try w.writeAll(")&");
+ // We need an lvalue for '&'.
+ try dg.renderValueAsLvalue(w, .fromInterned(un.val));
} else {
if (!location.isInitializer()) {
try w.writeByte('(');
- try dg.renderCType(w, ctype);
+ try dg.renderType(w, ty);
try w.writeByte(')');
}
+ if (ty.unionHasAllZeroBitFieldTypes(zcu)) {
+ assert(loaded_union.has_runtime_tag); // otherwise it does not have runtime bits
+ try w.writeAll("{ .tag = ");
+ try dg.renderValue(w, .fromInterned(un.tag), initializer_type);
+ try w.writeAll(" }");
+ return;
+ }
+
+ if (loaded_union.layout == .auto) try w.writeByte('{');
- const field_index = zcu.unionTagFieldIndex(loaded_union, Value.fromInterned(un.tag)).?;
- const field_ty: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]);
- const field_name = loaded_union.loadTagType(ip).names.get(ip)[field_index];
+ if (loaded_union.has_runtime_tag) {
+ try w.writeAll(" .tag = ");
+ try dg.renderValue(w, .fromInterned(un.tag), initializer_type);
+ try w.writeAll(", .payload = ");
+ }
- const has_tag = loaded_union.hasTag(ip);
- if (has_tag) try w.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 w.writeByte(',');
- switch (if (has_tag)
- aggregate.fields.at(outer_field_index, ctype_pool).name.index
- else
- .payload) {
- .tag => try dg.renderValue(
- w,
- Value.fromInterned(un.tag),
- initializer_type,
- ),
- .payload => {
- try w.writeByte('{');
- if (field_ty.hasRuntimeBits(zcu)) {
- try w.print(" .{f} = ", .{fmtIdentSolo(field_name.toSlice(ip))});
- try dg.renderValue(
- w,
- Value.fromInterned(un.val),
- initializer_type,
- );
- try w.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(w, inner_field_ty, initializer_type);
- break;
- }
- try w.writeByte('}');
- },
- else => unreachable,
- }
+ const enum_tag_ty: Type = .fromInterned(loaded_union.enum_tag_type);
+ const active_field_index = enum_tag_ty.enumTagFieldIndex(.fromInterned(un.tag), zcu).?;
+ const active_field_ty: Type = .fromInterned(loaded_union.field_types.get(ip)[active_field_index]);
+ if (active_field_ty.hasRuntimeBits(zcu)) {
+ const active_field_name = enum_tag_ty.enumFieldName(active_field_index, zcu);
+ try w.print("{{ .{f} = ", .{fmtIdentSolo(active_field_name.toSlice(ip))});
+ try dg.renderValue(w, .fromInterned(un.val), initializer_type);
+ try w.writeAll(" }");
+ } else {
+ const first_field_ty: Type = for (loaded_union.field_types.get(ip)) |field_ty_ip| {
+ const field_ty: Type = .fromInterned(field_ty_ip);
+ if (!field_ty.hasRuntimeBits(pt.zcu)) continue;
+ break field_ty;
+ } else unreachable;
+ try w.writeByte('{');
+ try dg.renderUndefValue(w, first_field_ty, initializer_type);
+ try w.writeByte('}');
}
- if (has_tag) try w.writeByte('}');
+
+ if (loaded_union.has_runtime_tag) try w.writeByte(' ');
+ if (loaded_union.layout == .auto) try w.writeByte('}');
}
},
}
@@ -1511,11 +1296,10 @@ pub const DeclGen = struct {
const zcu = pt.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,
- else => .Initializer,
+ .static_initializer => .static_initializer,
+ else => .initializer,
};
const safety_on = switch (zcu.optimizeMode()) {
@@ -1523,7 +1307,6 @@ pub const DeclGen = struct {
.ReleaseFast, .ReleaseSmall => false,
};
- const ctype = try dg.ctypeFromType(ty, location.toCTypeKind());
switch (ty.toIntern()) {
.c_longdouble_type,
.f16_type,
@@ -1548,94 +1331,126 @@ pub const DeclGen = struct {
else => unreachable,
}
try w.writeAll(", ");
- try dg.renderUndefValue(w, repr_ty, .FunctionArgument);
+ try dg.renderUndefValue(w, repr_ty, .other);
return w.writeByte(')');
},
.bool_type => try w.writeAll(if (safety_on) "0xaa" else "false"),
else => switch (ip.indexToKey(ty.toIntern())) {
- .simple_type,
+ .simple_type, // anyerror, c_char (etc), usize, isize
.int_type,
.enum_type,
.error_set_type,
.inferred_error_set_type,
- => return w.print("{f}", .{
- try dg.fmtIntLiteralHex(try pt.undefValue(ty), location),
- }),
+ => switch (CType.classifyInt(ty, zcu)) {
+ .void => unreachable, // opv
+ .small => |s| {
+ const int = ty.intInfo(zcu);
+ var buf: [std.math.big.int.calcTwosCompLimbCount(128)]std.math.big.Limb = undefined;
+ var bigint: std.math.big.int.Mutable = .init(&buf, undefPattern(u128));
+ bigint.truncate(bigint.toConst(), int.signedness, int.bits);
+ const fmt_undef: FormatInt128 = .{
+ .target = zcu.getTarget(),
+ .int_cty = s,
+ .val = bigint.toConst(),
+ .is_global = location == .static_initializer,
+ .base = 16,
+ .case = .lower,
+ };
+ try w.print("{f}", .{fmt_undef});
+ },
+ .big => |big| {
+ var buf: [std.math.big.int.calcTwosCompLimbCount(128)]std.math.big.Limb = undefined;
+ var limb_bigint: std.math.big.int.Mutable = .init(&buf, undefPattern(u128));
+ limb_bigint.truncate(limb_bigint.toConst(), .unsigned, big.limb_size.bits());
+ const fmt_undef_limb: FormatInt128 = .{
+ .target = zcu.getTarget(),
+ .int_cty = big.limb_size.unsigned(),
+ .val = limb_bigint.toConst(),
+ .is_global = location == .static_initializer,
+ .base = 16,
+ .case = .lower,
+ };
+
+ if (!location.isInitializer()) {
+ try w.writeByte('(');
+ try dg.renderType(w, ty);
+ try w.writeByte(')');
+ }
+ try w.writeAll("{{");
+ try w.print("{f}", .{fmt_undef_limb});
+ for (1..big.limbs_len) |_| {
+ try w.print(",{f}", .{fmt_undef_limb});
+ }
+ try w.writeAll("}}");
+ },
+ },
.ptr_type => |ptr_type| switch (ptr_type.flags.size) {
.one, .many, .c => {
try w.writeAll("((");
- try dg.renderCType(w, ctype);
- return w.print("){f})", .{
- try dg.fmtIntLiteralHex(.undef_usize, .Other),
- });
+ try dg.renderType(w, ty);
+ try w.writeByte(')');
+ try dg.renderUndefValue(w, .usize, location);
+ try w.writeByte(')');
},
.slice => {
if (!location.isInitializer()) {
try w.writeByte('(');
- try dg.renderCType(w, ctype);
+ try dg.renderType(w, ty);
try w.writeByte(')');
}
- try w.writeAll("{(");
- const ptr_ty = ty.slicePtrFieldType(zcu);
- try dg.renderType(w, ptr_ty);
- return w.print("){f}, {0f}}}", .{
- try dg.fmtIntLiteralHex(.undef_usize, .Other),
- });
- },
- },
- .opt_type => |child_type| switch (ctype.info(ctype_pool)) {
- .basic, .pointer => try dg.renderUndefValue(
- w,
- .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(
- w,
- .fromInterned(child_type),
- location,
- ),
- else => unreachable,
- }
- if (!location.isInitializer()) {
- try w.writeByte('(');
- try dg.renderCType(w, ctype);
- try w.writeByte(')');
- }
try w.writeByte('{');
- for (0..aggregate.fields.len) |field_index| {
- if (field_index > 0) try w.writeByte(',');
- try dg.renderUndefValue(w, .fromInterned(
- switch (aggregate.fields.at(field_index, ctype_pool).name.index) {
- .is_null => .bool_type,
- .payload => child_type,
- else => unreachable,
- },
- ), initializer_type);
- }
+ try dg.renderUndefValue(w, ty.slicePtrFieldType(zcu), initializer_type);
+ try w.writeByte(',');
+ try dg.renderUndefValue(w, .usize, initializer_type);
try w.writeByte('}');
},
},
+ .opt_type => |child_type| switch (CType.classifyOptional(ty, zcu)) {
+ .npv_payload => unreachable, // opv optional
+
+ .error_set,
+ .ptr_like,
+ .slice_like,
+ => try dg.renderUndefValue(w, .fromInterned(child_type), location),
+
+ .opv_payload => {
+ if (!location.isInitializer()) {
+ try w.writeByte('(');
+ try dg.renderType(w, ty);
+ try w.writeByte(')');
+ }
+ try w.writeAll(if (safety_on) "{.is_null=0xaa}" else "{.is_null=false}");
+ },
+
+ .@"struct" => {
+ if (!location.isInitializer()) {
+ try w.writeByte('(');
+ try dg.renderType(w, ty);
+ try w.writeByte(')');
+ }
+ try w.writeAll("{ .is_null = ");
+ try dg.renderUndefValue(w, .bool, initializer_type);
+ try w.writeAll(", .payload = ");
+ try dg.renderUndefValue(w, .fromInterned(child_type), initializer_type);
+ try w.writeAll(" }");
+ },
+ },
.struct_type => {
const loaded_struct = ip.loadStructType(ty.toIntern());
switch (loaded_struct.layout) {
.auto, .@"extern" => {
if (!location.isInitializer()) {
try w.writeByte('(');
- try dg.renderCType(w, ctype);
+ try dg.renderType(w, ty);
try w.writeByte(')');
}
-
try w.writeByte('{');
var field_it = loaded_struct.iterateRuntimeOrder(ip);
var need_comma = false;
while (field_it.next()) |field_index| {
const field_ty: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
- if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
+ if (!field_ty.hasRuntimeBits(zcu)) continue;
if (need_comma) try w.writeByte(',');
need_comma = true;
@@ -1643,17 +1458,13 @@ pub const DeclGen = struct {
}
return w.writeByte('}');
},
- .@"packed" => return dg.renderUndefValue(
- w,
- .fromInterned(loaded_struct.backingIntTypeUnordered(ip)),
- location,
- ),
+ .@"packed" => return dg.renderUndefValue(w, ty.bitpackBackingInt(zcu), location),
}
},
.tuple_type => |tuple_info| {
if (!location.isInitializer()) {
try w.writeByte('(');
- try dg.renderCType(w, ctype);
+ try dg.renderType(w, ty);
try w.writeByte(')');
}
@@ -1662,7 +1473,7 @@ pub const DeclGen = struct {
for (0..tuple_info.types.len) |field_index| {
if (tuple_info.values.get(ip)[field_index] != .none) continue;
const field_ty: Type = .fromInterned(tuple_info.types.get(ip)[field_index]);
- if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
+ if (!field_ty.hasRuntimeBits(zcu)) continue;
if (need_comma) try w.writeByte(',');
need_comma = true;
@@ -1672,88 +1483,65 @@ pub const DeclGen = struct {
},
.union_type => {
const loaded_union = ip.loadUnionType(ty.toIntern());
- switch (loaded_union.flagsUnordered(ip).layout) {
+ switch (loaded_union.layout) {
.auto, .@"extern" => {
if (!location.isInitializer()) {
try w.writeByte('(');
- try dg.renderCType(w, ctype);
+ try dg.renderType(w, ty);
try w.writeByte(')');
}
- const has_tag = loaded_union.hasTag(ip);
- if (has_tag) try w.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 w.writeByte(',');
- switch (if (has_tag)
- aggregate.fields.at(outer_field_index, ctype_pool).name.index
- else
- .payload) {
- .tag => try dg.renderUndefValue(
- w,
- .fromInterned(loaded_union.enum_tag_ty),
- initializer_type,
- ),
- .payload => {
- try w.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(pt.zcu)) continue;
- try dg.renderUndefValue(
- w,
- inner_field_ty,
- initializer_type,
- );
- break;
- }
- try w.writeByte('}');
- },
- else => unreachable,
- }
+ const first_field_ty: Type = for (loaded_union.field_types.get(ip)) |field_ty_ip| {
+ const field_ty: Type = .fromInterned(field_ty_ip);
+ if (!field_ty.hasRuntimeBits(pt.zcu)) continue;
+ break field_ty;
+ } else {
+ assert(loaded_union.has_runtime_tag); // otherwise it does not have runtime bits
+ try w.writeAll("{ .tag = ");
+ try dg.renderUndefValue(w, .fromInterned(loaded_union.enum_tag_type), initializer_type);
+ try w.writeAll(" }");
+ return;
+ };
+
+ if (loaded_union.layout == .auto) try w.writeByte('{');
+
+ if (loaded_union.has_runtime_tag) {
+ try w.writeAll(" .tag = ");
+ try dg.renderUndefValue(w, .fromInterned(loaded_union.enum_tag_type), initializer_type);
+ try w.writeAll(", .payload = ");
}
- if (has_tag) try w.writeByte('}');
+
+ try w.writeByte('{');
+ try dg.renderUndefValue(w, first_field_ty, initializer_type);
+ try w.writeByte('}');
+
+ if (loaded_union.has_runtime_tag) try w.writeByte(' ');
+ if (loaded_union.layout == .auto) try w.writeByte('}');
},
- .@"packed" => return dg.renderUndefValue(
- w,
- try ty.unionBackingType(pt),
- location,
- ),
+ .@"packed" => return dg.renderUndefValue(w, ty.bitpackBackingInt(zcu), location),
}
},
- .error_union_type => |error_union_type| switch (ctype.info(ctype_pool)) {
- .basic => try dg.renderUndefValue(
- w,
- .fromInterned(error_union_type.error_set_type),
- location,
- ),
- .pointer, .aligned, .array, .vector, .fwd_decl, .function => unreachable,
- .aggregate => |aggregate| {
- if (!location.isInitializer()) {
- try w.writeByte('(');
- try dg.renderCType(w, ctype);
- try w.writeByte(')');
- }
- try w.writeByte('{');
- for (0..aggregate.fields.len) |field_index| {
- if (field_index > 0) try w.writeByte(',');
- try dg.renderUndefValue(
- w,
- .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 w.writeByte('}');
- },
+ .error_union_type => |error_union| {
+ if (!location.isInitializer()) {
+ try w.writeByte('(');
+ try dg.renderType(w, ty);
+ try w.writeByte(')');
+ }
+ try w.writeAll("{ .error = ");
+ try dg.renderUndefValue(w, .fromInterned(error_union.error_set_type), initializer_type);
+ if (Type.fromInterned(error_union.payload_type).hasRuntimeBits(zcu)) {
+ try w.writeAll(", .payload = ");
+ try dg.renderUndefValue(w, .fromInterned(error_union.payload_type), initializer_type);
+ }
+ try w.writeAll(" }");
},
.array_type, .vector_type => {
+ if (!location.isInitializer()) {
+ try w.writeByte('(');
+ try dg.renderType(w, ty);
+ try w.writeByte(')');
+ }
+ try w.writeByte('{');
const ai = ty.arrayInfo(zcu);
if (ai.elem_type.eql(.u8, zcu)) {
var literal: StringLiteral = .init(w, @intCast(ty.arrayLenIncludingSentinel(zcu)));
@@ -1764,14 +1552,8 @@ pub const DeclGen = struct {
const s_u8: u8 = @intCast(s.toUnsignedInt(zcu));
if (s_u8 != 0) try literal.writeChar(s_u8);
}
- return literal.end();
+ try literal.end();
} else {
- if (!location.isInitializer()) {
- try w.writeByte('(');
- try dg.renderCType(w, ctype);
- try w.writeByte(')');
- }
-
try w.writeByte('{');
var index: u64 = 0;
while (index < ai.len) : (index += 1) {
@@ -1782,8 +1564,9 @@ pub const DeclGen = struct {
if (index > 0) try w.writeAll(", ");
try dg.renderValue(w, s, location);
}
- return w.writeByte('}');
+ try w.writeByte('}');
}
+ try w.writeByte('}');
},
.anyframe_type,
.opaque_type,
@@ -1800,13 +1583,13 @@ pub const DeclGen = struct {
.error_union,
.enum_literal,
.enum_tag,
- .empty_enum_value,
.float,
.ptr,
.slice,
.opt,
.aggregate,
.un,
+ .bitpack,
.memoized_call,
=> unreachable, // values, not types
},
@@ -1818,10 +1601,11 @@ pub const DeclGen = struct {
w: *Writer,
fn_val: Value,
fn_align: InternPool.Alignment,
- kind: CType.Kind,
+ kind: enum { forward_decl, definition },
name: union(enum) {
nav: InternPool.Nav.Index,
- fmt_ctype_pool_string: std.fmt.Alt(CTypePoolStringFormatData, formatCTypePoolString),
+ nav_never_tail: InternPool.Nav.Index,
+ nav_never_inline: InternPool.Nav.Index,
@"export": struct {
main_name: InternPool.NullTerminatedString,
extern_name: InternPool.NullTerminatedString,
@@ -1832,14 +1616,12 @@ pub const DeclGen = struct {
const ip = &zcu.intern_pool;
const fn_ty = fn_val.typeOf(zcu);
- const fn_ctype = try dg.ctypeFromType(fn_ty, kind);
const fn_info = zcu.typeToFunc(fn_ty).?;
if (fn_info.cc == .naked) {
switch (kind) {
- .forward => try w.writeAll("zig_naked_decl "),
- .complete => try w.writeAll("zig_naked "),
- else => unreachable,
+ .forward_decl => try w.writeAll("zig_naked_decl "),
+ .definition => try w.writeAll("zig_naked "),
}
}
@@ -1849,45 +1631,63 @@ pub const DeclGen = struct {
if (func_analysis.branch_hint == .cold)
try w.writeAll("zig_cold ");
- if (kind == .complete and func_analysis.disable_intrinsics or dg.mod.no_builtin)
+ if (kind == .definition and func_analysis.disable_intrinsics or dg.mod.no_builtin)
try w.writeAll("zig_no_builtin ");
}
if (fn_info.return_type == .noreturn_type) try w.writeAll("zig_noreturn ");
- var trailing = try renderTypePrefix(dg.pass, &dg.ctype_pool, zcu, w, fn_ctype, .suffix, .{});
+ // While incomplete types are usually an acceptable substitute for "void", this is not true
+ // in function return types, where "void" is the only incomplete type permitted.
+ const actual_return_type: Type = .fromInterned(fn_info.return_type);
+ const effective_return_type: Type = switch (actual_return_type.classify(zcu)) {
+ .no_possible_value => .noreturn,
+ .one_possible_value, .fully_comptime => .void, // no runtime bits
+ .partially_comptime, .runtime => actual_return_type, // yes runtime bits
+ };
+ const ret_cty: CType = try .lower(effective_return_type, &dg.ctype_deps, dg.arena, zcu);
+ try w.print("{f}", .{ret_cty.fmtDeclaratorPrefix(zcu)});
if (toCallingConvention(fn_info.cc, zcu)) |call_conv| {
- try w.print("{f}zig_callconv({s})", .{ trailing, call_conv });
- trailing = .maybe_space;
+ try w.print("zig_callconv({s}) ", .{call_conv});
}
-
- try w.print("{f}", .{trailing});
switch (name) {
- .nav => |nav| try dg.renderNavName(w, nav),
- .fmt_ctype_pool_string => |fmt| try w.print("{f}", .{fmt}),
+ .nav => |nav| try renderNavName(w, nav, ip),
+ .nav_never_tail => |nav| try w.print("zig_never_tail_{f}__{d}", .{
+ fmtIdentUnsolo(ip.getNav(nav).name.toSlice(ip)), @intFromEnum(nav),
+ }),
+ .nav_never_inline => |nav| try w.print("zig_never_inline_{f}__{d}", .{
+ fmtIdentUnsolo(ip.getNav(nav).name.toSlice(ip)), @intFromEnum(nav),
+ }),
.@"export" => |@"export"| try w.print("{f}", .{fmtIdentSolo(@"export".extern_name.toSlice(ip))}),
}
-
- try renderTypeSuffix(
- dg.pass,
- &dg.ctype_pool,
- zcu,
- w,
- fn_ctype,
- .suffix,
- CQualifiers.init(.{ .@"const" = switch (kind) {
- .forward => false,
- .complete => true,
- else => unreachable,
- } }),
- );
+ {
+ try w.writeByte('(');
+ var c_param_index: u32 = 0;
+ for (fn_info.param_types.get(ip)) |param_ty_ip| {
+ const param_ty: Type = .fromInterned(param_ty_ip);
+ if (!param_ty.hasRuntimeBits(zcu)) continue;
+ if (c_param_index != 0) try w.writeAll(", ");
+ try dg.renderTypeAndName(w, param_ty, .{ .arg = c_param_index }, .{
+ .@"const" = kind == .definition,
+ }, .none);
+ c_param_index += 1;
+ }
+ if (fn_info.is_var_args) {
+ if (c_param_index != 0) try w.writeAll(", ");
+ try w.writeAll("...");
+ } else if (c_param_index == 0) {
+ try w.writeAll("void");
+ }
+ try w.writeByte(')');
+ }
+ try w.print("{f}", .{ret_cty.fmtDeclaratorSuffixIgnoreNonstring(zcu)});
switch (kind) {
- .forward => {
+ .forward_decl => {
if (fn_align.toByteUnits()) |a| try w.print(" zig_align_fn({})", .{a});
switch (name) {
- .nav, .fmt_ctype_pool_string => {},
+ .nav, .nav_never_tail, .nav_never_inline => {},
.@"export" => |@"export"| {
const extern_name = @"export".extern_name.toSlice(ip);
const is_mangled = isMangledIdent(extern_name, true);
@@ -1911,38 +1711,16 @@ pub const DeclGen = struct {
},
}
},
- .complete => {},
- else => unreachable,
+ .definition => {},
}
}
- fn ctypeFromType(dg: *DeclGen, ty: Type, kind: CType.Kind) !CType {
- defer std.debug.assert(dg.scratch.items.len == 0);
- return dg.ctype_pool.fromType(dg.gpa, &dg.scratch, ty, dg.pt, dg.mod, kind);
- }
-
- fn byteSize(dg: *DeclGen, ctype: CType) u64 {
- return ctype.byteSize(&dg.ctype_pool, dg.mod);
- }
-
- /// Renders a type as a single identifier, generating intermediate typedefs
- /// if necessary.
- ///
- /// This is guaranteed to be valid in both typedefs and declarations/definitions.
- ///
- /// There are three type formats in total that we support rendering:
- /// | Function | Example 1 (*u8) | Example 2 ([10]*u8) |
- /// |---------------------|-----------------|---------------------|
- /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" |
- /// | `renderType` | "uint8_t *" | "uint8_t *[10]" |
- ///
- fn renderType(dg: *DeclGen, w: *Writer, t: Type) Error!void {
- try dg.renderCType(w, try dg.ctypeFromType(t, .complete));
- }
-
- fn renderCType(dg: *DeclGen, w: *Writer, ctype: CType) Error!void {
- _ = try renderTypePrefix(dg.pass, &dg.ctype_pool, dg.pt.zcu, w, ctype, .suffix, .{});
- try renderTypeSuffix(dg.pass, &dg.ctype_pool, dg.pt.zcu, w, ctype, .suffix, .{});
+ /// Renders the C lowering of the given Zig type to `w`. This renders the type name---to render
+ /// a declarator with this type, see instead `renderTypeAndName`.
+ fn renderType(dg: *DeclGen, w: *Writer, ty: Type) (Writer.Error || Allocator.Error)!void {
+ const zcu = dg.pt.zcu;
+ const cty: CType = try .lower(ty, &dg.ctype_deps, dg.arena, zcu);
+ try w.print("{f}", .{cty.fmtTypeName(zcu)});
}
const IntCastContext = union(enum) {
@@ -2046,7 +1824,7 @@ pub const DeclGen = struct {
try w.writeAll("zig_lo_");
try dg.renderTypeForBuiltinFnName(w, src_eff_ty);
try w.writeByte('(');
- try context.writeValue(dg, w, .FunctionArgument);
+ try context.writeValue(dg, w, .other);
try w.writeByte(')');
} else if (dest_bits > 64 and src_bits <= 64) {
try w.writeAll("zig_make_");
@@ -2057,7 +1835,7 @@ pub const DeclGen = struct {
try dg.renderType(w, src_eff_ty);
try w.writeByte(')');
}
- try context.writeValue(dg, w, .FunctionArgument);
+ try context.writeValue(dg, w, .other);
try w.writeByte(')');
} else {
assert(!src_is_ptr);
@@ -2066,23 +1844,16 @@ pub const DeclGen = struct {
try w.writeAll("(zig_hi_");
try dg.renderTypeForBuiltinFnName(w, src_eff_ty);
try w.writeByte('(');
- try context.writeValue(dg, w, .FunctionArgument);
+ try context.writeValue(dg, w, .other);
try w.writeAll("), zig_lo_");
try dg.renderTypeForBuiltinFnName(w, src_eff_ty);
try w.writeByte('(');
- try context.writeValue(dg, w, .FunctionArgument);
+ try context.writeValue(dg, w, .other);
try w.writeAll("))");
}
}
- /// Renders a type and name in field declaration/definition format.
- ///
- /// There are three type formats in total that we support rendering:
- /// | Function | Example 1 (*u8) | Example 2 ([10]*u8) |
- /// |---------------------|-----------------|---------------------|
- /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" |
- /// | `renderType` | "uint8_t *" | "uint8_t *[10]" |
- ///
+ /// Renders to `w` a C declarator whose type is the C lowering of the given Zig type.
fn renderTypeAndName(
dg: *DeclGen,
w: *Writer,
@@ -2090,73 +1861,47 @@ pub const DeclGen = struct {
name: CValue,
qualifiers: CQualifiers,
alignment: Alignment,
- kind: CType.Kind,
- ) !void {
- try dg.renderCTypeAndName(
- w,
- try dg.ctypeFromType(ty, kind),
- name,
- qualifiers,
- CType.AlignAs.fromAlignment(.{
- .@"align" = alignment,
- .abi = ty.abiAlignment(dg.pt.zcu),
- }),
- );
- }
-
- fn renderCTypeAndName(
- dg: *DeclGen,
- w: *Writer,
- ctype: CType,
- name: CValue,
- qualifiers: CQualifiers,
- alignas: CType.AlignAs,
) !void {
const zcu = dg.pt.zcu;
- switch (alignas.abiOrder()) {
- .lt => try w.print("zig_under_align({}) ", .{alignas.toByteUnits()}),
+ const ip = &zcu.intern_pool;
+ const cty: CType = try .lower(ty, &dg.ctype_deps, dg.arena, zcu);
+ try w.print("{f}", .{cty.fmtDeclaratorPrefix(zcu)});
+ if (alignment != .none) switch (alignment.order(ty.abiAlignment(zcu))) {
+ .lt => try w.print("zig_under_align({d}) ", .{alignment.toByteUnits().?}),
.eq => {},
- .gt => try w.print("zig_align({}) ", .{alignas.toByteUnits()}),
- }
-
- try w.print("{f}", .{
- try renderTypePrefix(dg.pass, &dg.ctype_pool, zcu, w, ctype, .suffix, qualifiers),
- });
- try dg.writeName(w, name);
- try renderTypeSuffix(dg.pass, &dg.ctype_pool, zcu, w, ctype, .suffix, .{});
- if (ctype.isNonString(&dg.ctype_pool)) try w.writeAll(" zig_nonstring");
- }
-
- fn writeName(dg: *DeclGen, w: *Writer, c_value: CValue) !void {
- switch (c_value) {
+ .gt => try w.print("zig_align({d}) ", .{alignment.toByteUnits().?}),
+ };
+ if (qualifiers.@"const") try w.writeAll("const ");
+ if (qualifiers.@"volatile") try w.writeAll("volatile ");
+ if (qualifiers.restrict) try w.writeAll("restrict ");
+ switch (name) {
.new_local, .local => |i| try w.print("t{d}", .{i}),
+ .arg => |i| try w.print("a{d}", .{i}),
.constant => |uav| try renderUavName(w, uav),
- .nav => |nav| try dg.renderNavName(w, nav),
+ .nav => |nav| try renderNavName(w, nav, ip),
.identifier => |ident| try w.print("{f}", .{fmtIdentSolo(ident)}),
else => unreachable,
}
+ try w.print("{f}", .{cty.fmtDeclaratorSuffix(zcu)});
}
fn writeCValue(dg: *DeclGen, w: *Writer, c_value: CValue) Error!void {
switch (c_value) {
.none, .new_local, .local, .local_ref => unreachable,
.constant => |uav| try renderUavName(w, uav),
- .arg, .arg_array => unreachable,
+ .arg => unreachable,
.field => |i| try w.print("f{d}", .{i}),
- .nav => |nav| try dg.renderNavName(w, nav),
+ .nav => |nav| try renderNavName(w, nav, &dg.pt.zcu.intern_pool),
.nav_ref => |nav| {
try w.writeByte('&');
- try dg.renderNavName(w, nav);
+ try renderNavName(w, nav, &dg.pt.zcu.intern_pool);
},
- .undef => |ty| try dg.renderUndefValue(w, ty, .Other),
+ .undef => |ty| try dg.renderUndefValue(w, ty, .other),
.identifier => |ident| try w.print("{f}", .{fmtIdentSolo(ident)}),
.payload_identifier => |ident| try w.print("{f}.{f}", .{
fmtIdentSolo("payload"),
fmtIdentSolo(ident),
}),
- .ctype_pool_string => |string| try w.print("{f}", .{
- fmtCTypePoolString(string, &dg.ctype_pool, true),
- }),
}
}
@@ -2168,16 +1913,14 @@ pub const DeclGen = struct {
.local_ref,
.constant,
.arg,
- .arg_array,
- .ctype_pool_string,
=> unreachable,
.field => |i| try w.print("f{d}", .{i}),
.nav => |nav| {
try w.writeAll("(*");
- try dg.renderNavName(w, nav);
+ try renderNavName(w, nav, &dg.pt.zcu.intern_pool);
try w.writeByte(')');
},
- .nav_ref => |nav| try dg.renderNavName(w, nav),
+ .nav_ref => |nav| try renderNavName(w, nav, &dg.pt.zcu.intern_pool),
.undef => unreachable,
.identifier => |ident| try w.print("(*{f})", .{fmtIdentSolo(ident)}),
.payload_identifier => |ident| try w.print("(*{f}.{f})", .{
@@ -2213,8 +1956,6 @@ pub const DeclGen = struct {
.field,
.undef,
.arg,
- .arg_array,
- .ctype_pool_string,
=> unreachable,
.nav, .identifier, .payload_identifier => {
try dg.writeCValue(w, c_value);
@@ -2228,101 +1969,36 @@ pub const DeclGen = struct {
try dg.writeCValue(w, member);
}
- fn renderFwdDecl(
- dg: *DeclGen,
- nav_index: InternPool.Nav.Index,
- flags: packed struct {
- is_const: bool,
- is_threadlocal: bool,
- linkage: std.builtin.GlobalLinkage,
- visibility: std.builtin.SymbolVisibility,
- },
- ) !void {
- const zcu = dg.pt.zcu;
- const ip = &zcu.intern_pool;
- const nav = ip.getNav(nav_index);
- const fwd = &dg.fwd_decl.writer;
- try fwd.writeAll(switch (flags.linkage) {
- .internal => "static ",
- .strong, .weak, .link_once => "zig_extern ",
- });
- switch (flags.linkage) {
- .internal, .strong => {},
- .weak => try fwd.writeAll("zig_weak_linkage "),
- .link_once => return dg.fail("TODO: CBE: implement linkonce linkage?", .{}),
- }
- switch (flags.linkage) {
- .internal => {},
- .strong, .weak, .link_once => try fwd.print("zig_visibility({s}) ", .{@tagName(flags.visibility)}),
- }
- if (flags.is_threadlocal and !dg.mod.single_threaded) try fwd.writeAll("zig_threadlocal ");
- try dg.renderTypeAndName(
- fwd,
- .fromInterned(nav.typeOf(ip)),
- .{ .nav = nav_index },
- CQualifiers.init(.{ .@"const" = flags.is_const }),
- nav.getAlignment(),
- .complete,
- );
- try fwd.writeAll(";\n");
- }
-
- fn renderNavName(dg: *DeclGen, w: *Writer, nav_index: InternPool.Nav.Index) !void {
- const zcu = dg.pt.zcu;
- const ip = &zcu.intern_pool;
- const nav = ip.getNav(nav_index);
- if (nav.getExtern(ip)) |@"extern"| {
- try w.print("{f}", .{
- fmtIdentSolo(ip.getNav(@"extern".owner_nav).name.toSlice(ip)),
- });
- } else {
- // MSVC has a limit of 4095 character token length limit, and fmtIdent can (worst case),
- // expand to 3x the length of its input, but let's cut it off at a much shorter limit.
- const fqn_slice = ip.getNav(nav_index).fqn.toSlice(ip);
- try w.print("{f}__{d}", .{
- fmtIdentUnsolo(fqn_slice[0..@min(fqn_slice.len, 100)]),
- @intFromEnum(nav_index),
- });
- }
- }
-
- fn renderUavName(w: *Writer, uav: Value) !void {
- try w.print("__anon_{d}", .{@intFromEnum(uav.toIntern())});
- }
-
fn renderTypeForBuiltinFnName(dg: *DeclGen, w: *Writer, ty: Type) !void {
- try dg.renderCTypeForBuiltinFnName(w, try dg.ctypeFromType(ty, .complete));
- }
-
- fn renderCTypeForBuiltinFnName(dg: *DeclGen, w: *Writer, ctype: CType) !void {
- switch (ctype.info(&dg.ctype_pool)) {
- else => |ctype_info| try w.print("{c}{d}", .{
- if (ctype.isBool())
- signAbbrev(.unsigned)
- else if (ctype.isInteger())
- signAbbrev(ctype.signedness(dg.mod))
- else if (ctype.isFloat())
- @as(u8, 'f')
- else if (ctype_info == .pointer)
- @as(u8, 'p')
- else
- return dg.fail("TODO: CBE: implement renderTypeForBuiltinFnName for {s} type", .{@tagName(ctype_info)}),
- if (ctype.isFloat()) ctype.floatActiveBits(dg.mod) else dg.byteSize(ctype) * 8,
+ const zcu = dg.pt.zcu;
+ switch (ty.zigTypeTag(zcu)) {
+ .bool => return w.writeAll("u8"),
+ .float => return w.print("f{d}", .{ty.floatBits(zcu.getTarget())}),
+ else => {},
+ }
+ if (ty.isPtrAtRuntime(zcu)) {
+ return w.print("p{d}", .{zcu.getTarget().ptrBitWidth()});
+ }
+ switch (CType.classifyInt(ty, zcu)) {
+ .void => unreachable, // opv
+ .small => try w.print("{c}{d}", .{
+ signAbbrev(ty.intInfo(zcu).signedness),
+ ty.abiSize(zcu) * 8,
}),
- .array => try w.writeAll("big"),
+ .big => try w.writeAll("big"),
}
}
fn renderBuiltinInfo(dg: *DeclGen, w: *Writer, ty: Type, info: BuiltinInfo) !void {
- const ctype = try dg.ctypeFromType(ty, .complete);
- const is_big = ctype.info(&dg.ctype_pool) == .array;
+ const pt = dg.pt;
+ const zcu = pt.zcu;
+
+ const is_big = lowersToBigInt(ty, zcu);
switch (info) {
.none => if (!is_big) return,
.bits => {},
}
- const pt = dg.pt;
- const zcu = pt.zcu;
const int_info: std.builtin.Type.Int = if (ty.isAbiInt(zcu)) ty.intInfo(zcu) else .{
.signedness = .unsigned,
.bits = @intCast(ty.bitSize(zcu)),
@@ -2331,7 +2007,7 @@ pub const DeclGen = struct {
if (is_big) try w.print(", {}", .{int_info.signedness == .signed});
try w.print(", {f}", .{try dg.fmtIntLiteralDec(
try pt.intValue(if (is_big) .u16 else .u8, int_info.bits),
- .FunctionArgument,
+ .other,
)});
}
@@ -2342,15 +2018,13 @@ pub const DeclGen = struct {
base: u8,
case: std.fmt.Case,
) !std.fmt.Alt(FormatIntLiteralContext, formatIntLiteral) {
- const zcu = dg.pt.zcu;
- const kind = loc.toCTypeKind();
- const ty = val.typeOf(zcu);
+ // If there's a bigint type involved, mark a dependency on it.
+ const cty: CType = try .lower(val.typeOf(dg.pt.zcu), &dg.ctype_deps, dg.arena, dg.pt.zcu);
return .{ .data = .{
.dg = dg,
- .int_info = ty.intInfo(zcu),
- .kind = kind,
- .ctype = try dg.ctypeFromType(ty, kind),
+ .loc = loc,
.val = val,
+ .cty = cty,
.base = base,
.case = case,
} };
@@ -2373,339 +2047,11 @@ pub const DeclGen = struct {
}
};
-const CTypeFix = enum { prefix, suffix };
-const CQualifiers = std.enums.EnumSet(enum { @"const", @"volatile", restrict });
-const Const = CQualifiers.init(.{ .@"const" = true });
-const RenderCTypeTrailing = enum {
- no_space,
- maybe_space,
-
- pub fn format(self: @This(), w: *Writer) Writer.Error!void {
- switch (self) {
- .no_space => {},
- .maybe_space => try w.writeByte(' '),
- }
- }
+const CQualifiers = packed struct {
+ @"const": bool = false,
+ @"volatile": bool = false,
+ restrict: bool = false,
};
-fn renderAlignedTypeName(w: *Writer, ctype: CType) !void {
- try w.print("anon__aligned_{d}", .{@intFromEnum(ctype.index)});
-}
-fn renderFwdDeclTypeName(
- zcu: *Zcu,
- w: *Writer,
- ctype: CType,
- fwd_decl: CType.Info.FwdDecl,
- attributes: []const u8,
-) !void {
- const ip = &zcu.intern_pool;
- try w.print("{s} {s}", .{ @tagName(fwd_decl.tag), attributes });
- switch (fwd_decl.name) {
- .anon => try w.print("anon__lazy_{d}", .{@intFromEnum(ctype.index)}),
- .index => |index| try w.print("{f}__{d}", .{
- fmtIdentUnsolo(Type.fromInterned(index).containerTypeName(ip).toSlice(&zcu.intern_pool)),
- @intFromEnum(index),
- }),
- }
-}
-fn renderTypePrefix(
- pass: DeclGen.Pass,
- ctype_pool: *const CType.Pool,
- zcu: *Zcu,
- w: *Writer,
- ctype: CType,
- parent_fix: CTypeFix,
- qualifiers: CQualifiers,
-) Writer.Error!RenderCTypeTrailing {
- var trailing = RenderCTypeTrailing.maybe_space;
- switch (ctype.info(ctype_pool)) {
- .basic => |basic_info| try w.writeAll(@tagName(basic_info)),
-
- .pointer => |pointer_info| {
- try w.print("{f}*", .{try renderTypePrefix(
- pass,
- ctype_pool,
- zcu,
- w,
- pointer_info.elem_ctype,
- .prefix,
- CQualifiers.init(.{
- .@"const" = pointer_info.@"const",
- .@"volatile" = pointer_info.@"volatile",
- }),
- )});
- trailing = .no_space;
- },
-
- .aligned => switch (pass) {
- .nav => |nav| try w.print("nav__{d}_{d}", .{
- @intFromEnum(nav), @intFromEnum(ctype.index),
- }),
- .uav => |uav| try w.print("uav__{d}_{d}", .{
- @intFromEnum(uav), @intFromEnum(ctype.index),
- }),
- .flush => try renderAlignedTypeName(w, ctype),
- },
-
- .array, .vector => |sequence_info| {
- const child_trailing = try renderTypePrefix(
- pass,
- ctype_pool,
- zcu,
- w,
- sequence_info.elem_ctype,
- .suffix,
- qualifiers,
- );
- switch (parent_fix) {
- .prefix => {
- try w.print("{f}(", .{child_trailing});
- return .no_space;
- },
- .suffix => return child_trailing,
- }
- },
-
- .fwd_decl => |fwd_decl_info| switch (fwd_decl_info.name) {
- .anon => switch (pass) {
- .nav => |nav| try w.print("nav__{d}_{d}", .{
- @intFromEnum(nav), @intFromEnum(ctype.index),
- }),
- .uav => |uav| try w.print("uav__{d}_{d}", .{
- @intFromEnum(uav), @intFromEnum(ctype.index),
- }),
- .flush => try renderFwdDeclTypeName(zcu, w, ctype, fwd_decl_info, ""),
- },
- .index => try renderFwdDeclTypeName(zcu, w, ctype, fwd_decl_info, ""),
- },
-
- .aggregate => |aggregate_info| switch (aggregate_info.name) {
- .anon => {
- try w.print("{s} {s}", .{
- @tagName(aggregate_info.tag),
- if (aggregate_info.@"packed") "zig_packed(" else "",
- });
- try renderFields(zcu, w, ctype_pool, aggregate_info, 1);
- if (aggregate_info.@"packed") try w.writeByte(')');
- },
- .fwd_decl => |fwd_decl| return renderTypePrefix(
- pass,
- ctype_pool,
- zcu,
- w,
- fwd_decl,
- parent_fix,
- qualifiers,
- ),
- },
-
- .function => |function_info| {
- const child_trailing = try renderTypePrefix(
- pass,
- ctype_pool,
- zcu,
- w,
- function_info.return_ctype,
- .suffix,
- .{},
- );
- switch (parent_fix) {
- .prefix => {
- try w.print("{f}(", .{child_trailing});
- return .no_space;
- },
- .suffix => return child_trailing,
- }
- },
- }
- var qualifier_it = qualifiers.iterator();
- while (qualifier_it.next()) |qualifier| {
- try w.print("{f}{s}", .{ trailing, @tagName(qualifier) });
- trailing = .maybe_space;
- }
- return trailing;
-}
-fn renderTypeSuffix(
- pass: DeclGen.Pass,
- ctype_pool: *const CType.Pool,
- zcu: *Zcu,
- w: *Writer,
- ctype: CType,
- parent_fix: CTypeFix,
- qualifiers: CQualifiers,
-) Writer.Error!void {
- switch (ctype.info(ctype_pool)) {
- .basic, .aligned, .fwd_decl, .aggregate => {},
- .pointer => |pointer_info| try renderTypeSuffix(
- pass,
- ctype_pool,
- zcu,
- w,
- pointer_info.elem_ctype,
- .prefix,
- .{},
- ),
- .array, .vector => |sequence_info| {
- switch (parent_fix) {
- .prefix => try w.writeByte(')'),
- .suffix => {},
- }
-
- try w.print("[{}]", .{sequence_info.len});
- try renderTypeSuffix(pass, ctype_pool, zcu, w, sequence_info.elem_ctype, .suffix, .{});
- },
- .function => |function_info| {
- switch (parent_fix) {
- .prefix => try w.writeByte(')'),
- .suffix => {},
- }
-
- try w.writeByte('(');
- var need_comma = false;
- for (0..function_info.param_ctypes.len) |param_index| {
- const param_type = function_info.param_ctypes.at(param_index, ctype_pool);
- if (need_comma) try w.writeAll(", ");
- need_comma = true;
- const trailing =
- try renderTypePrefix(pass, ctype_pool, zcu, w, param_type, .suffix, qualifiers);
- if (qualifiers.contains(.@"const")) try w.print("{f}a{d}", .{ trailing, param_index });
- try renderTypeSuffix(pass, ctype_pool, zcu, w, param_type, .suffix, .{});
- }
- if (function_info.varargs) {
- if (need_comma) try w.writeAll(", ");
- need_comma = true;
- try w.writeAll("...");
- }
- if (!need_comma) try w.writeAll("void");
- try w.writeByte(')');
-
- try renderTypeSuffix(pass, ctype_pool, zcu, w, function_info.return_ctype, .suffix, .{});
- },
- }
-}
-fn renderFields(
- zcu: *Zcu,
- w: *Writer,
- ctype_pool: *const CType.Pool,
- aggregate_info: CType.Info.Aggregate,
- indent: usize,
-) !void {
- try w.writeAll("{\n");
- for (0..aggregate_info.fields.len) |field_index| {
- const field_info = aggregate_info.fields.at(field_index, ctype_pool);
- try w.splatByteAll(' ', indent + 1);
- switch (field_info.alignas.abiOrder()) {
- .lt => {
- std.debug.assert(aggregate_info.@"packed");
- if (field_info.alignas.@"align" != .@"1") try w.print("zig_under_align({}) ", .{
- field_info.alignas.toByteUnits(),
- });
- },
- .eq => if (aggregate_info.@"packed" and field_info.alignas.@"align" != .@"1")
- try w.print("zig_align({}) ", .{field_info.alignas.toByteUnits()}),
- .gt => {
- std.debug.assert(field_info.alignas.@"align" != .@"1");
- try w.print("zig_align({}) ", .{field_info.alignas.toByteUnits()});
- },
- }
- const trailing = try renderTypePrefix(
- .flush,
- ctype_pool,
- zcu,
- w,
- field_info.ctype,
- .suffix,
- .{},
- );
- try w.print("{f}{f}", .{ trailing, fmtCTypePoolString(field_info.name, ctype_pool, true) });
- try renderTypeSuffix(.flush, ctype_pool, zcu, w, field_info.ctype, .suffix, .{});
- if (field_info.ctype.isNonString(ctype_pool)) try w.writeAll(" zig_nonstring");
- try w.writeAll(";\n");
- }
- try w.splatByteAll(' ', indent);
- try w.writeByte('}');
-}
-
-pub fn genTypeDecl(
- zcu: *Zcu,
- w: *Writer,
- global_ctype_pool: *const CType.Pool,
- global_ctype: CType,
- pass: DeclGen.Pass,
- decl_ctype_pool: *const CType.Pool,
- decl_ctype: CType,
- found_existing: bool,
-) !void {
- switch (global_ctype.info(global_ctype_pool)) {
- .basic, .pointer, .array, .vector, .function => {},
- .aligned => |aligned_info| {
- if (!found_existing) {
- std.debug.assert(aligned_info.alignas.abiOrder().compare(.lt));
- try w.print("typedef zig_under_align({d}) ", .{aligned_info.alignas.toByteUnits()});
- try w.print("{f}", .{try renderTypePrefix(
- .flush,
- global_ctype_pool,
- zcu,
- w,
- aligned_info.ctype,
- .suffix,
- .{},
- )});
- try renderAlignedTypeName(w, global_ctype);
- try renderTypeSuffix(.flush, global_ctype_pool, zcu, w, aligned_info.ctype, .suffix, .{});
- try w.writeAll(";\n");
- }
- switch (pass) {
- .nav, .uav => {
- try w.writeAll("typedef ");
- _ = try renderTypePrefix(.flush, global_ctype_pool, zcu, w, global_ctype, .suffix, .{});
- try w.writeByte(' ');
- _ = try renderTypePrefix(pass, decl_ctype_pool, zcu, w, decl_ctype, .suffix, .{});
- try w.writeAll(";\n");
- },
- .flush => {},
- }
- },
- .fwd_decl => |fwd_decl_info| switch (fwd_decl_info.name) {
- .anon => switch (pass) {
- .nav, .uav => {
- try w.writeAll("typedef ");
- _ = try renderTypePrefix(.flush, global_ctype_pool, zcu, w, global_ctype, .suffix, .{});
- try w.writeByte(' ');
- _ = try renderTypePrefix(pass, decl_ctype_pool, zcu, w, decl_ctype, .suffix, .{});
- try w.writeAll(";\n");
- },
- .flush => {},
- },
- .index => |index| if (!found_existing) {
- const ip = &zcu.intern_pool;
- const ty: Type = .fromInterned(index);
- _ = try renderTypePrefix(.flush, global_ctype_pool, zcu, w, global_ctype, .suffix, .{});
- try w.writeByte(';');
- const file_scope = ty.typeDeclInstAllowGeneratedTag(zcu).?.resolveFile(ip);
- if (!zcu.fileByIndex(file_scope).mod.?.strip) try w.print(" /* {f} */", .{
- ty.containerTypeName(ip).fmt(ip),
- });
- try w.writeByte('\n');
- },
- },
- .aggregate => |aggregate_info| switch (aggregate_info.name) {
- .anon => {},
- .fwd_decl => |fwd_decl| if (!found_existing) {
- try renderFwdDeclTypeName(
- zcu,
- w,
- fwd_decl,
- fwd_decl.info(global_ctype_pool).fwd_decl,
- if (aggregate_info.@"packed") "zig_packed(" else "",
- );
- try w.writeByte(' ');
- try renderFields(zcu, w, global_ctype_pool, aggregate_info, 0);
- if (aggregate_info.@"packed") try w.writeByte(')');
- try w.writeAll(";\n");
- },
- },
- }
-}
pub fn genGlobalAsm(zcu: *Zcu, w: *Writer) !void {
for (zcu.global_assembly.values()) |asm_source| {
@@ -2713,200 +2059,128 @@ pub fn genGlobalAsm(zcu: *Zcu, w: *Writer) !void {
}
}
-pub fn genErrDecls(o: *Object) Error!void {
- const pt = o.dg.pt;
- const zcu = pt.zcu;
+pub fn genErrDecls(
+ zcu: *const Zcu,
+ w: *Writer,
+ slice_const_u8_sentinel_0_type_name: []const u8,
+) Writer.Error!void {
const ip = &zcu.intern_pool;
- const w = &o.code.writer;
- var max_name_len: usize = 0;
- // do not generate an invalid empty enum when the global error set is empty
const names = ip.global_error_set.getNamesFromMainThread();
+ // Don't generate an invalid empty enum if the global error set is empty!
if (names.len > 0) {
- try w.writeAll("enum {");
- o.indent();
- try o.newline();
+ try w.writeAll("enum {\n");
for (names, 1..) |name_nts, value| {
- const name = name_nts.toSlice(ip);
- max_name_len = @max(name.len, max_name_len);
- const err_val = try pt.intern(.{ .err = .{
- .ty = .anyerror_type,
- .name = name_nts,
- } });
- try o.dg.renderValue(w, Value.fromInterned(err_val), .Other);
- try w.print(" = {d}u,", .{value});
- try o.newline();
+ try w.writeByte(' ');
+ try renderErrorName(w, name_nts.toSlice(ip));
+ try w.print(" = {d}u,\n", .{value});
}
- try o.outdent();
- try w.writeAll("};");
- try o.newline();
+ try w.writeAll("};\n");
}
- const array_identifier = "zig_errorName";
- const name_prefix = array_identifier ++ "_";
- const name_buf = try o.dg.gpa.alloc(u8, name_prefix.len + max_name_len);
- defer o.dg.gpa.free(name_buf);
- @memcpy(name_buf[0..name_prefix.len], name_prefix);
- for (names) |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 pt.arrayType(.{
- .len = name_slice.len,
- .child = .u8_type,
- .sentinel = .zero_u8,
- });
- const name_val = try pt.intern(.{ .aggregate = .{
- .ty = name_ty.toIntern(),
- .storage = .{ .bytes = name.toString() },
- } });
-
- try w.writeAll("static ");
- try o.dg.renderTypeAndName(
- w,
- name_ty,
- .{ .identifier = identifier },
- Const,
- .none,
- .complete,
+ for (names) |name_nts| {
+ const name = name_nts.toSlice(ip);
+ try w.print(
+ "static uint8_t const zig_errorName_{f}[] = {f};\n",
+ .{ fmtIdentUnsolo(name), fmtStringLiteral(name, 0) },
);
- try w.writeAll(" = ");
- try o.dg.renderValue(w, Value.fromInterned(name_val), .StaticInitializer);
- try w.writeByte(';');
- try o.newline();
}
- const name_array_ty = try pt.arrayType(.{
- .len = 1 + names.len,
- .child = .slice_const_u8_sentinel_0_type,
- });
-
- try w.writeAll("static ");
- try o.dg.renderTypeAndName(
- w,
- name_array_ty,
- .{ .identifier = array_identifier },
- Const,
- .none,
- .complete,
+ try w.print(
+ "static {s} const zig_errorName[{d}] = {{",
+ .{ slice_const_u8_sentinel_0_type_name, names.len },
);
- try w.writeAll(" = {");
- for (names, 1..) |name_nts, val| {
+ if (names.len > 0) try w.writeByte('\n');
+ for (names) |name_nts| {
const name = name_nts.toSlice(ip);
- if (val > 1) try w.writeAll(", ");
- try w.print("{{" ++ name_prefix ++ "{f}, {f}}}", .{
- fmtIdentUnsolo(name),
- try o.dg.fmtIntLiteralDec(try pt.intValue(.usize, name.len), .StaticInitializer),
- });
+ try w.print(
+ " {{zig_errorName_{f},{d}}},\n",
+ .{ fmtIdentUnsolo(name), name.len },
+ );
}
- try w.writeAll("};");
- try o.newline();
+ try w.writeAll("};\n");
}
-pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFnMap.Entry) Error!void {
- const pt = o.dg.pt;
- const zcu = pt.zcu;
+pub fn genTagNameFn(
+ zcu: *const Zcu,
+ w: *Writer,
+ slice_const_u8_sentinel_0_type_name: []const u8,
+ enum_ty: Type,
+ enum_type_name: []const u8,
+) Writer.Error!void {
const ip = &zcu.intern_pool;
- const ctype_pool = &o.dg.ctype_pool;
- const w = &o.code.writer;
- const key = lazy_fn.key_ptr.*;
- const val = lazy_fn.value_ptr;
- switch (key) {
- .tag_name => |enum_ty_ip| {
- const enum_ty: Type = .fromInterned(enum_ty_ip);
- const name_slice_ty: Type = .slice_const_u8_sentinel_0;
+ const loaded_enum = ip.loadEnumType(enum_ty.toIntern());
+ assert(loaded_enum.field_names.len > 0);
+ if (Type.fromInterned(loaded_enum.int_tag_type).bitSize(zcu) > 64) {
+ @panic("TODO CBE: tagName for enum over 64 bits");
+ }
- try w.writeAll("static ");
- try o.dg.renderType(w, name_slice_ty);
- try w.print(" {f}(", .{val.fn_name.fmt(lazy_ctype_pool)});
- try o.dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, Const, .none, .complete);
- try w.writeAll(") {");
- o.indent();
- try o.newline();
- try w.writeAll("switch (tag) {");
- o.indent();
- try o.newline();
- const tag_names = enum_ty.enumFields(zcu);
- for (0..tag_names.len) |tag_index| {
- const tag_name = tag_names.get(ip)[tag_index];
- const tag_name_len = tag_name.length(ip);
- const tag_val = try pt.enumValueFieldIndex(enum_ty, @intCast(tag_index));
+ try w.print("static {s} zig_tagName_{f}__{d}({s} tag) {{\n", .{
+ slice_const_u8_sentinel_0_type_name,
+ fmtIdentUnsolo(loaded_enum.name.toSlice(ip)),
+ @intFromEnum(enum_ty.toIntern()),
+ enum_type_name,
+ });
+ for (loaded_enum.field_names.get(ip), 0..) |field_name, field_index| {
+ try w.print(" static uint8_t const name{d}[] = {f};\n", .{
+ field_index, fmtStringLiteral(field_name.toSlice(ip), 0),
+ });
+ }
- const name_ty = try pt.arrayType(.{
- .len = tag_name_len,
- .child = .u8_type,
- .sentinel = .zero_u8,
- });
- const name_val = try pt.intern(.{ .aggregate = .{
- .ty = name_ty.toIntern(),
- .storage = .{ .bytes = tag_name.toString() },
- } });
+ try w.writeAll(" switch (tag) {\n");
+ const field_values = loaded_enum.field_values.get(ip);
+ for (loaded_enum.field_names.get(ip), 0..) |field_name, field_index| {
+ const field_int: i65 = int: {
+ if (field_values.len == 0) break :int field_index;
+ const field_val: Value = .fromInterned(field_values[field_index]);
+ break :int field_val.getUnsignedInt(zcu) orelse field_val.toSignedInt(zcu);
+ };
+ try w.print(" case {d}: return ({s}){{name{d},{d}}};\n", .{
+ field_int,
+ slice_const_u8_sentinel_0_type_name,
+ field_index,
+ field_name.toSlice(ip).len,
+ });
+ }
+ try w.writeAll(
+ \\ }
+ \\ zig_unreachable();
+ \\}
+ \\
+ );
+}
- try w.print("case {f}: {{", .{
- try o.dg.fmtIntLiteralDec(try tag_val.intFromEnum(enum_ty, pt), .Other),
- });
- o.indent();
- try o.newline();
- try w.writeAll("static ");
- try o.dg.renderTypeAndName(w, name_ty, .{ .identifier = "name" }, Const, .none, .complete);
- try w.writeAll(" = ");
- try o.dg.renderValue(w, Value.fromInterned(name_val), .StaticInitializer);
- try w.writeByte(';');
- try o.newline();
- try w.writeAll("return (");
- try o.dg.renderType(w, name_slice_ty);
- try w.print("){{{f}, {f}}};", .{
- fmtIdentUnsolo("name"),
- try o.dg.fmtIntLiteralDec(try pt.intValue(.usize, tag_name_len), .Other),
- });
- try o.newline();
- try o.outdent();
- try w.writeByte('}');
- try o.newline();
- }
- try o.outdent();
- try w.writeByte('}');
- try o.newline();
- try airUnreach(o);
- try o.outdent();
- try w.writeByte('}');
- try o.newline();
- },
- .never_tail, .never_inline => |fn_nav_index| {
- const fn_val = zcu.navValue(fn_nav_index);
- const fn_ctype = try o.dg.ctypeFromType(fn_val.typeOf(zcu), .complete);
- const fn_info = fn_ctype.info(ctype_pool).function;
- const fn_name = fmtCTypePoolString(val.fn_name, lazy_ctype_pool, true);
+pub fn genLazyCallModifierFn(
+ dg: *DeclGen,
+ fn_nav: InternPool.Nav.Index,
+ kind: enum { never_tail, never_inline },
+ w: *Writer,
+) Error!void {
+ const zcu = dg.pt.zcu;
+ const ip = &zcu.intern_pool;
- const fwd = &o.dg.fwd_decl.writer;
- try fwd.print("static zig_{s} ", .{@tagName(key)});
- try o.dg.renderFunctionSignature(fwd, fn_val, ip.getNav(fn_nav_index).getAlignment(), .forward, .{
- .fmt_ctype_pool_string = fn_name,
- });
- try fwd.writeAll(";\n");
+ const fn_val = zcu.navValue(fn_nav);
- try w.print("zig_{s} ", .{@tagName(key)});
- try o.dg.renderFunctionSignature(w, fn_val, .none, .complete, .{
- .fmt_ctype_pool_string = fn_name,
- });
- try w.writeAll(" {");
- o.indent();
- try o.newline();
- try w.writeAll("return ");
- try o.dg.renderNavName(w, fn_nav_index);
- try w.writeByte('(');
- for (0..fn_info.param_ctypes.len) |arg| {
- if (arg > 0) try w.writeAll(", ");
- try w.print("a{d}", .{arg});
- }
- try w.writeAll(");");
- try o.newline();
- try o.outdent();
- try w.writeByte('}');
- try o.newline();
- },
+ try w.print("static zig_{t} ", .{kind});
+ try dg.renderFunctionSignature(w, fn_val, .none, .definition, switch (kind) {
+ .never_tail => .{ .nav_never_tail = fn_nav },
+ .never_inline => .{ .nav_never_inline = fn_nav },
+ });
+ try w.writeAll(" {\n return ");
+ try renderNavName(w, fn_nav, ip);
+ try w.writeByte('(');
+ {
+ const func_type = ip.indexToKey(fn_val.typeOf(zcu).toIntern()).func_type;
+ var c_param_index: u32 = 0;
+ for (func_type.param_types.get(ip)) |param_ty_ip| {
+ const param_ty: Type = .fromInterned(param_ty_ip);
+ if (!param_ty.hasRuntimeBits(zcu)) continue;
+ if (c_param_index != 0) try w.writeAll(", ");
+ try w.print("a{d}", .{c_param_index});
+ c_param_index += 1;
+ }
}
+ try w.writeAll(");\n}\n");
}
pub fn generate(
@@ -2925,110 +2199,109 @@ pub fn generate(
const func = zcu.funcInfo(func_index);
+ var arena: std.heap.ArenaAllocator = .init(gpa);
+ defer arena.deinit();
+
var function: Function = .{
.value_map = .init(gpa),
.air = air.*,
.liveness = liveness.*.?,
.func_index = func_index,
- .object = .{
- .dg = .{
- .gpa = gpa,
- .pt = pt,
- .mod = zcu.navFileScope(func.owner_nav).mod.?,
- .error_msg = null,
- .pass = .{ .nav = func.owner_nav },
- .is_naked_fn = Type.fromInterned(func.ty).fnCallingConvention(zcu) == .naked,
- .expected_block = null,
- .fwd_decl = .init(gpa),
- .ctype_pool = .empty,
- .scratch = .empty,
- .uavs = .empty,
- },
- .code_header = .init(gpa),
- .code = .init(gpa),
- .indent_counter = 0,
+ .dg = .{
+ .gpa = gpa,
+ .arena = arena.allocator(),
+ .pt = pt,
+ .mod = zcu.navFileScope(func.owner_nav).mod.?,
+ .error_msg = null,
+ .owner_nav = func.owner_nav.toOptional(),
+ .is_naked_fn = Type.fromInterned(func.ty).fnCallingConvention(zcu) == .naked,
+ .expected_block = null,
+ .ctype_deps = .empty,
+ .uavs = .empty,
},
- .lazy_fns = .empty,
+ .code = .init(gpa),
+ .indent_counter = 0,
+ .need_tag_name_funcs = .empty,
+ .need_never_tail_funcs = .empty,
+ .need_never_inline_funcs = .empty,
};
defer {
- function.object.code_header.deinit();
- function.object.code.deinit();
- function.object.dg.fwd_decl.deinit();
- function.object.dg.ctype_pool.deinit(gpa);
- function.object.dg.scratch.deinit(gpa);
- function.object.dg.uavs.deinit(gpa);
+ function.code.deinit();
+ function.dg.ctype_deps.deinit(gpa);
+ function.dg.uavs.deinit(gpa);
function.deinit();
}
- try function.object.dg.ctype_pool.init(gpa);
- genFunc(&function) catch |err| switch (err) {
- error.AnalysisFail => return zcu.codegenFailMsg(func.owner_nav, function.object.dg.error_msg.?),
- error.OutOfMemory => return error.OutOfMemory,
+ var fwd_decl: Writer.Allocating = .init(gpa);
+ defer fwd_decl.deinit();
+
+ var code_header: Writer.Allocating = .init(gpa);
+ defer code_header.deinit();
+
+ genFunc(&function, &fwd_decl.writer, &code_header.writer) catch |err| switch (err) {
+ error.AnalysisFail => return zcu.codegenFailMsg(func.owner_nav, function.dg.error_msg.?),
error.WriteFailed => return error.OutOfMemory,
+ error.OutOfMemory => |e| return e,
};
var mir: Mir = .{
- .uavs = .empty,
- .code = &.{},
- .code_header = &.{},
.fwd_decl = &.{},
- .ctype_pool = .empty,
- .lazy_fns = .empty,
+ .code_header = &.{},
+ .code = &.{},
+ .ctype_deps = function.dg.ctype_deps.move(),
+ .need_uavs = function.dg.uavs.move(),
+ .need_tag_name_funcs = function.need_tag_name_funcs.move(),
+ .need_never_tail_funcs = function.need_never_tail_funcs.move(),
+ .need_never_inline_funcs = function.need_never_inline_funcs.move(),
};
errdefer mir.deinit(gpa);
- mir.uavs = function.object.dg.uavs.move();
- mir.code_header = try function.object.code_header.toOwnedSlice();
- mir.code = try function.object.code.toOwnedSlice();
- mir.fwd_decl = try function.object.dg.fwd_decl.toOwnedSlice();
- mir.ctype_pool = function.object.dg.ctype_pool.move();
- mir.lazy_fns = function.lazy_fns.move();
+ mir.fwd_decl = try fwd_decl.toOwnedSlice();
+ mir.code_header = try code_header.toOwnedSlice();
+ mir.code = try function.code.toOwnedSlice();
return mir;
}
-pub fn genFunc(f: *Function) Error!void {
+pub fn genFunc(f: *Function, fwd_decl_writer: *Writer, header_writer: *Writer) Error!void {
const tracy = trace(@src());
defer tracy.end();
- const o = &f.object;
- const zcu = o.dg.pt.zcu;
+ const zcu = f.dg.pt.zcu;
const ip = &zcu.intern_pool;
- const gpa = o.dg.gpa;
- const nav_index = o.dg.pass.nav;
+ const gpa = f.dg.gpa;
+ const nav_index = f.dg.owner_nav.unwrap().?;
const nav_val = zcu.navValue(nav_index);
const nav = ip.getNav(nav_index);
- const fwd = &o.dg.fwd_decl.writer;
- try fwd.writeAll("static ");
- try o.dg.renderFunctionSignature(
- fwd,
+ try fwd_decl_writer.writeAll("static ");
+ try f.dg.renderFunctionSignature(
+ fwd_decl_writer,
nav_val,
nav.status.fully_resolved.alignment,
- .forward,
+ .forward_decl,
.{ .nav = nav_index },
);
- try fwd.writeAll(";\n");
+ try fwd_decl_writer.writeAll(";\n");
- const ch = &o.code_header.writer;
if (nav.status.fully_resolved.@"linksection".toSlice(ip)) |s|
- try ch.print("zig_linksection_fn({f}) ", .{fmtStringLiteral(s, null)});
- try o.dg.renderFunctionSignature(
- ch,
+ try header_writer.print("zig_linksection_fn({f}) ", .{fmtStringLiteral(s, null)});
+ try f.dg.renderFunctionSignature(
+ header_writer,
nav_val,
.none,
- .complete,
+ .definition,
.{ .nav = nav_index },
);
- try ch.writeAll(" {\n ");
+ try header_writer.writeAll(" {\n ");
f.free_locals_map.clearRetainingCapacity();
const main_body = f.air.getMainBody();
- o.indent();
+ f.indent();
try genBodyResolveState(f, undefined, &.{}, main_body, true);
- try o.outdent();
- try o.code.writer.writeByte('}');
- try o.newline();
- if (o.dg.expected_block) |_|
+ try f.outdent();
+ try f.code.writer.writeByte('}');
+ try f.newline();
+ if (f.dg.expected_block) |_|
return f.fail("runtime code not allowed in naked function", .{});
// Take advantage of the free_locals map to bucket locals per type. All
@@ -3042,155 +2315,204 @@ pub fn genFunc(f: *Function) Error!void {
if (!should_emit) continue;
const local = f.locals.items[local_index];
log.debug("inserting local {d} into free_locals", .{local_index});
- const gop = try free_locals.getOrPut(gpa, local.getType());
+ const gop = try free_locals.getOrPut(gpa, local);
if (!gop.found_existing) gop.value_ptr.* = .{};
try gop.value_ptr.putNoClobber(gpa, local_index, {});
}
const SortContext = struct {
+ zcu: *const Zcu,
keys: []const LocalType,
pub fn lessThan(ctx: @This(), lhs_index: usize, rhs_index: usize) bool {
- const lhs_ty = ctx.keys[lhs_index];
- const rhs_ty = ctx.keys[rhs_index];
- return lhs_ty.alignas.order(rhs_ty.alignas).compare(.gt);
+ const lhs = ctx.keys[lhs_index];
+ const rhs = ctx.keys[rhs_index];
+ const lhs_align = switch (lhs.alignment) {
+ .none => lhs.type.abiAlignment(ctx.zcu),
+ else => |a| a,
+ };
+ const rhs_align = switch (rhs.alignment) {
+ .none => rhs.type.abiAlignment(ctx.zcu),
+ else => |a| a,
+ };
+ return Alignment.compareStrict(lhs_align, .gt, rhs_align);
}
};
- free_locals.sort(SortContext{ .keys = free_locals.keys() });
+ free_locals.sort(SortContext{
+ .zcu = zcu,
+ .keys = free_locals.keys(),
+ });
for (free_locals.values()) |list| {
for (list.keys()) |local_index| {
const local = f.locals.items[local_index];
- try o.dg.renderCTypeAndName(ch, local.ctype, .{ .local = local_index }, .{}, local.flags.alignas);
- try ch.writeAll(";\n ");
+ try f.dg.renderTypeAndName(header_writer, local.type, .{ .local = local_index }, .{}, local.alignment);
+ try header_writer.writeAll(";\n ");
}
}
}
-pub fn genDecl(o: *Object) Error!void {
+pub fn genDecl(dg: *DeclGen, w: *Writer) Error!void {
const tracy = trace(@src());
defer tracy.end();
- const pt = o.dg.pt;
+ const pt = dg.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
- const nav = ip.getNav(o.dg.pass.nav);
+ const nav = ip.getNav(dg.owner_nav.unwrap().?);
const nav_ty: Type = .fromInterned(nav.typeOf(ip));
- if (!nav_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return;
- switch (ip.indexToKey(nav.status.fully_resolved.val)) {
- .@"extern" => |@"extern"| {
- if (!ip.isFunctionType(nav_ty.toIntern())) return o.dg.renderFwdDecl(o.dg.pass.nav, .{
- .is_const = @"extern".is_const,
- .is_threadlocal = @"extern".is_threadlocal,
- .linkage = @"extern".linkage,
- .visibility = @"extern".visibility,
- });
+ const is_const: bool, const is_threadlocal: bool, const init_val: Value = switch (ip.indexToKey(nav.status.fully_resolved.val)) {
+ else => .{ true, false, .fromInterned(nav.status.fully_resolved.val) },
+ .variable => |v| .{ false, v.is_threadlocal, .fromInterned(v.init) },
+ .@"extern" => return,
+ };
- const fwd = &o.dg.fwd_decl.writer;
- try fwd.writeAll("zig_extern ");
- try o.dg.renderFunctionSignature(
- fwd,
- Value.fromInterned(nav.status.fully_resolved.val),
- nav.status.fully_resolved.alignment,
- .forward,
- .{ .@"export" = .{
- .main_name = nav.name,
- .extern_name = nav.name,
- } },
- );
- try fwd.writeAll(";\n");
- },
- .variable => |variable| {
- try o.dg.renderFwdDecl(o.dg.pass.nav, .{
- .is_const = false,
- .is_threadlocal = variable.is_threadlocal,
- .linkage = .internal,
- .visibility = .default,
- });
- const w = &o.code.writer;
- if (variable.is_threadlocal and !o.dg.mod.single_threaded) try w.writeAll("zig_threadlocal ");
- if (nav.status.fully_resolved.@"linksection".toSlice(&zcu.intern_pool)) |s|
- try w.print("zig_linksection({f}) ", .{fmtStringLiteral(s, null)});
- try o.dg.renderTypeAndName(
- w,
- nav_ty,
- .{ .nav = o.dg.pass.nav },
- .{},
- nav.status.fully_resolved.alignment,
- .complete,
- );
- try w.writeAll(" = ");
- try o.dg.renderValue(w, Value.fromInterned(variable.init), .StaticInitializer);
- try w.writeByte(';');
- try o.newline();
- },
- else => try genDeclValue(
- o,
- Value.fromInterned(nav.status.fully_resolved.val),
- .{ .nav = o.dg.pass.nav },
- nav.status.fully_resolved.alignment,
- nav.status.fully_resolved.@"linksection",
- ),
- }
-}
-
-pub fn genDeclValue(
- o: *Object,
- val: Value,
- decl_c_value: CValue,
- alignment: Alignment,
- @"linksection": InternPool.OptionalNullTerminatedString,
-) Error!void {
- const zcu = o.dg.pt.zcu;
- const ty = val.typeOf(zcu);
-
- const fwd = &o.dg.fwd_decl.writer;
- try fwd.writeAll("static ");
- try o.dg.renderTypeAndName(fwd, ty, decl_c_value, Const, alignment, .complete);
- try fwd.writeAll(";\n");
-
- const w = &o.code.writer;
- if (@"linksection".toSlice(&zcu.intern_pool)) |s|
+ if (nav.status.fully_resolved.@"linksection".toSlice(ip)) |s| {
try w.print("zig_linksection({f}) ", .{fmtStringLiteral(s, null)});
- try o.dg.renderTypeAndName(w, ty, decl_c_value, Const, alignment, .complete);
+ }
+
+ // We don't bother underaligning---it's unnecessary and hurts compatibility.
+ const a = nav.status.fully_resolved.alignment;
+ if (a != .none and a.compareStrict(.gt, nav_ty.abiAlignment(zcu))) {
+ try w.print("zig_align({d}) ", .{a.toByteUnits().?});
+ }
+
+ try genDeclValue(dg, w, .{
+ .name = .{ .nav = dg.owner_nav.unwrap().? },
+ .@"const" = is_const,
+ .@"threadlocal" = is_threadlocal,
+ .init_val = init_val,
+ });
+}
+pub fn genDeclFwd(dg: *DeclGen, w: *Writer) Error!void {
+ const tracy = trace(@src());
+ defer tracy.end();
+
+ const pt = dg.pt;
+ const zcu = pt.zcu;
+ const ip = &zcu.intern_pool;
+ const nav = ip.getNav(dg.owner_nav.unwrap().?);
+ const nav_ty: Type = .fromInterned(nav.typeOf(ip));
+
+ const is_const: bool, const is_threadlocal: bool, const init_val: Value = switch (ip.indexToKey(nav.status.fully_resolved.val)) {
+ else => .{ true, false, .fromInterned(nav.status.fully_resolved.val) },
+ .variable => |v| .{ false, v.is_threadlocal, .fromInterned(v.init) },
+
+ .@"extern" => |@"extern"| switch (nav_ty.zigTypeTag(zcu)) {
+ .@"fn" => {
+ try w.writeAll("zig_extern ");
+ try dg.renderFunctionSignature(
+ w,
+ Value.fromInterned(nav.status.fully_resolved.val),
+ nav.status.fully_resolved.alignment,
+ .forward_decl,
+ .{ .@"export" = .{
+ .main_name = nav.name,
+ .extern_name = nav.name,
+ } },
+ );
+ try w.writeAll(";\n");
+ return;
+ },
+ else => {
+ switch (@"extern".linkage) {
+ .internal => try w.writeAll("static "),
+ .strong => try w.print("zig_extern zig_visibility({t}) ", .{@"extern".visibility}),
+ .weak => try w.print("zig_extern zig_weak_linkage zig_visibility({t}) ", .{@"extern".visibility}),
+ .link_once => return dg.fail("TODO: CBE: implement linkonce linkage?", .{}),
+ }
+ if (@"extern".is_threadlocal and !dg.mod.single_threaded) {
+ try w.writeAll("zig_threadlocal ");
+ }
+ try dg.renderTypeAndName(
+ w,
+ .fromInterned(nav.typeOf(ip)),
+ .{ .nav = dg.owner_nav.unwrap().? },
+ .{ .@"const" = @"extern".is_const },
+ nav.getAlignment(),
+ );
+ try w.writeAll(";\n");
+ return;
+ },
+ },
+ };
+
+ // We don't bother underaligning---it's unnecessary and hurts compatibility.
+ const a = nav.status.fully_resolved.alignment;
+ if (a != .none and a.compareStrict(.gt, nav_ty.abiAlignment(zcu))) {
+ try w.print("zig_align({d}) ", .{a.toByteUnits().?});
+ }
+
+ try genDeclValueFwd(dg, w, .{
+ .name = .{ .nav = dg.owner_nav.unwrap().? },
+ .@"const" = is_const,
+ .@"threadlocal" = is_threadlocal,
+ .init_val = init_val,
+ });
+}
+pub fn genDeclValue(dg: *DeclGen, w: *Writer, options: struct {
+ name: CValue,
+ @"const": bool,
+ @"threadlocal": bool,
+ init_val: Value,
+}) Error!void {
+ const zcu = dg.pt.zcu;
+ const ty = options.init_val.typeOf(zcu);
+ if (options.@"threadlocal" and !dg.mod.single_threaded) {
+ try w.writeAll("zig_threadlocal ");
+ }
+ try dg.renderTypeAndName(w, ty, options.name, .{ .@"const" = options.@"const" }, .none);
try w.writeAll(" = ");
- try o.dg.renderValue(w, val, .StaticInitializer);
- try w.writeByte(';');
- try o.newline();
+ try dg.renderValue(w, options.init_val, .static_initializer);
+ try w.writeAll(";\n");
+}
+pub fn genDeclValueFwd(dg: *DeclGen, w: *Writer, options: struct {
+ name: CValue,
+ @"const": bool,
+ @"threadlocal": bool,
+ init_val: Value,
+}) Error!void {
+ const zcu = dg.pt.zcu;
+ const ty = options.init_val.typeOf(zcu);
+ try w.writeAll("static ");
+ if (options.@"threadlocal" and !dg.mod.single_threaded) {
+ try w.writeAll("zig_threadlocal ");
+ }
+ try dg.renderTypeAndName(w, ty, options.name, .{ .@"const" = options.@"const" }, .none);
+ try w.writeAll(";\n");
}
-pub fn genExports(dg: *DeclGen, exported: Zcu.Exported, export_indices: []const Zcu.Export.Index) !void {
+pub fn genExports(dg: *DeclGen, w: *Writer, exported: Zcu.Exported, export_indices: []const Zcu.Export.Index) !void {
const zcu = dg.pt.zcu;
const ip = &zcu.intern_pool;
- const fwd = &dg.fwd_decl.writer;
const main_name = export_indices[0].ptr(zcu).opts.name;
- try fwd.writeAll("#define ");
+ try w.writeAll("#define ");
switch (exported) {
- .nav => |nav| try dg.renderNavName(fwd, nav),
- .uav => |uav| try DeclGen.renderUavName(fwd, Value.fromInterned(uav)),
+ .nav => |nav| try renderNavName(w, nav, ip),
+ .uav => |uav| try renderUavName(w, Value.fromInterned(uav)),
}
- try fwd.writeByte(' ');
- try fwd.print("{f}", .{fmtIdentSolo(main_name.toSlice(ip))});
- try fwd.writeByte('\n');
+ try w.writeByte(' ');
+ try w.print("{f}", .{fmtIdentSolo(main_name.toSlice(ip))});
+ try w.writeByte('\n');
const exported_val = exported.getValue(zcu);
if (ip.isFunctionType(exported_val.typeOf(zcu).toIntern())) return for (export_indices) |export_index| {
const @"export" = export_index.ptr(zcu);
- try fwd.writeAll("zig_extern ");
- if (@"export".opts.linkage == .weak) try fwd.writeAll("zig_weak_linkage_fn ");
+ try w.writeAll("zig_extern ");
+ if (@"export".opts.linkage == .weak) try w.writeAll("zig_weak_linkage_fn ");
try dg.renderFunctionSignature(
- fwd,
+ w,
exported.getValue(zcu),
exported.getAlign(zcu),
- .forward,
+ .forward_decl,
.{ .@"export" = .{
.main_name = main_name,
.extern_name = @"export".opts.name,
} },
);
- try fwd.writeAll(";\n");
+ try w.writeAll(";\n");
};
const is_const = switch (ip.indexToKey(exported_val.toIntern())) {
.func => unreachable,
@@ -3200,39 +2522,38 @@ pub fn genExports(dg: *DeclGen, exported: Zcu.Exported, export_indices: []const
};
for (export_indices) |export_index| {
const @"export" = export_index.ptr(zcu);
- try fwd.writeAll("zig_extern ");
- if (@"export".opts.linkage == .weak) try fwd.writeAll("zig_weak_linkage ");
- if (@"export".opts.section.toSlice(ip)) |s| try fwd.print("zig_linksection({f}) ", .{
+ try w.writeAll("zig_extern ");
+ if (@"export".opts.linkage == .weak) try w.writeAll("zig_weak_linkage ");
+ if (@"export".opts.section.toSlice(ip)) |s| try w.print("zig_linksection({f}) ", .{
fmtStringLiteral(s, null),
});
const extern_name = @"export".opts.name.toSlice(ip);
const is_mangled = isMangledIdent(extern_name, true);
const is_export = @"export".opts.name != main_name;
try dg.renderTypeAndName(
- fwd,
+ w,
exported.getValue(zcu).typeOf(zcu),
.{ .identifier = extern_name },
- CQualifiers.init(.{ .@"const" = is_const }),
+ .{ .@"const" = is_const },
exported.getAlign(zcu),
- .complete,
);
if (is_mangled and is_export) {
- try fwd.print(" zig_mangled_export({f}, {f}, {f})", .{
+ try w.print(" zig_mangled_export({f}, {f}, {f})", .{
fmtIdentSolo(extern_name),
fmtStringLiteral(extern_name, null),
fmtStringLiteral(main_name.toSlice(ip), null),
});
} else if (is_mangled) {
- try fwd.print(" zig_mangled({f}, {f})", .{
+ try w.print(" zig_mangled({f}, {f})", .{
fmtIdentSolo(extern_name), fmtStringLiteral(extern_name, null),
});
} else if (is_export) {
- try fwd.print(" zig_export({f}, {f})", .{
+ try w.print(" zig_export({f}, {f})", .{
fmtStringLiteral(main_name.toSlice(ip), null),
fmtStringLiteral(extern_name, null),
});
}
- try fwd.writeAll(";\n");
+ try w.writeAll(";\n");
}
}
@@ -3241,15 +2562,15 @@ pub fn genExports(dg: *DeclGen, exported: Zcu.Exported, export_indices: []const
/// have been added to `free_locals_map`. For a version of this function that restores this state,
/// see `genBodyResolveState`.
fn genBody(f: *Function, body: []const Air.Inst.Index) Error!void {
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
if (body.len == 0) {
try w.writeAll("{}");
} else {
try w.writeByte('{');
- f.object.indent();
- try f.object.newline();
+ f.indent();
+ try f.newline();
try genBodyInner(f, body);
- try f.object.outdent();
+ try f.outdent();
try w.writeByte('}');
}
}
@@ -3263,13 +2584,13 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) Error!void {
fn genBodyResolveState(f: *Function, inst: Air.Inst.Index, leading_deaths: []const Air.Inst.Index, body: []const Air.Inst.Index, inner: bool) Error!void {
if (body.len == 0) {
// Don't go to the expense of cloning everything!
- if (!inner) try f.object.code.writer.writeAll("{}");
+ if (!inner) try f.code.writer.writeAll("{}");
return;
}
// TODO: we can probably avoid the copies in some other common cases too.
- const gpa = f.object.dg.gpa;
+ const gpa = f.dg.gpa;
// Save the original value_map and free_locals_map so that we can restore them after the body.
var old_value_map = try f.value_map.clone();
@@ -3310,13 +2631,13 @@ fn genBodyResolveState(f: *Function, inst: Air.Inst.Index, leading_deaths: []con
}
fn genBodyInner(f: *Function, body: []const Air.Inst.Index) Error!void {
- const zcu = f.object.dg.pt.zcu;
+ const zcu = f.dg.pt.zcu;
const ip = &zcu.intern_pool;
const air_tags = f.air.instructions.items(.tag);
const air_datas = f.air.instructions.items(.data);
for (body) |inst| {
- if (f.object.dg.expected_block) |_|
+ if (f.dg.expected_block) |_|
return f.fail("runtime code not allowed in naked function", .{});
if (f.liveness.isUnused(inst) and !f.air.mustLower(inst, ip))
continue;
@@ -3585,8 +2906,8 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) Error!void {
.ret => return airRet(f, inst, false),
.ret_safe => return airRet(f, inst, false), // TODO
.ret_load => return airRet(f, inst, true),
- .trap => return airTrap(f, &f.object.code.writer),
- .unreach => return airUnreach(&f.object),
+ .trap => return airTrap(f),
+ .unreach => return airUnreach(f),
// Instructions which may be `noreturn`.
.block => res: {
@@ -3629,177 +2950,159 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: [
const operand = try f.resolveInst(ty_op.operand);
try reap(f, inst, &.{ty_op.operand});
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
- const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete));
- try f.writeCValue(w, local, .Other);
- try a.assign(f, w);
+ try f.writeCValue(w, local, .other);
+ try w.writeAll(" = ");
if (is_ptr) {
try w.writeByte('&');
try f.writeCValueDerefMember(w, operand, .{ .identifier = field_name });
} else try f.writeCValueMember(w, operand, .{ .identifier = field_name });
- try a.end(f, w);
+ try w.writeByte(';');
+ try f.newline();
return local;
}
fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
- const zcu = f.object.dg.pt.zcu;
+ const zcu = f.dg.pt.zcu;
const inst_ty = f.typeOfIndex(inst);
const bin_op = f.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
- if (!inst_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
- try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
- return .none;
- }
+ assert(inst_ty.hasRuntimeBits(zcu));
const ptr = try f.resolveInst(bin_op.lhs);
const index = try f.resolveInst(bin_op.rhs);
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
- const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete));
- try f.writeCValue(w, local, .Other);
- try a.assign(f, w);
- try f.writeCValue(w, ptr, .Other);
+ try f.writeCValue(w, local, .other);
+ try w.writeAll(" = ");
+ switch (f.typeOf(bin_op.lhs).ptrSize(zcu)) {
+ .one => try f.writeCValueDerefMember(w, ptr, .{ .identifier = "array" }),
+ .many, .c => try f.writeCValue(w, ptr, .other),
+ .slice => unreachable,
+ }
try w.writeByte('[');
- try f.writeCValue(w, index, .Other);
- try w.writeByte(']');
- try a.end(f, w);
+ try f.writeCValue(w, index, .other);
+ try w.writeAll("];");
+ try f.newline();
return local;
}
fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
const inst_ty = f.typeOfIndex(inst);
const ptr_ty = f.typeOf(bin_op.lhs);
- const elem_has_bits = ptr_ty.elemType2(zcu).hasRuntimeBitsIgnoreComptime(zcu);
+ assert(ptr_ty.indexableElem(zcu).hasRuntimeBits(zcu));
const ptr = try f.resolveInst(bin_op.lhs);
const index = try f.resolveInst(bin_op.rhs);
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
- const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete));
- try f.writeCValue(w, local, .Other);
- try a.assign(f, w);
- try w.writeByte('(');
- try f.renderType(w, inst_ty);
- try w.writeByte(')');
- if (elem_has_bits) try w.writeByte('&');
- if (elem_has_bits and ptr_ty.ptrSize(zcu) == .one) {
- // It's a pointer to an array, so we need to de-reference.
- try f.writeCValueDeref(w, ptr);
- } else try f.writeCValue(w, ptr, .Other);
- if (elem_has_bits) {
- try w.writeByte('[');
- try f.writeCValue(w, index, .Other);
- try w.writeByte(']');
+ try f.writeCValue(w, local, .other);
+ try w.writeAll(" = ");
+ try w.writeByte('&');
+ if (ptr_ty.ptrSize(zcu) == .one) {
+ // `*[n]T` was turned into a pointer to `struct { T array[n]; }`
+ try f.writeCValueDerefMember(w, ptr, .{ .identifier = "array" });
+ } else {
+ try f.writeCValue(w, ptr, .other);
}
- try a.end(f, w);
+ try w.writeByte('[');
+ try f.writeCValue(w, index, .other);
+ try w.writeAll("];");
+ try f.newline();
return local;
}
fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
- const zcu = f.object.dg.pt.zcu;
+ const zcu = f.dg.pt.zcu;
const inst_ty = f.typeOfIndex(inst);
const bin_op = f.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
- if (!inst_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
- try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
- return .none;
- }
+ assert(inst_ty.hasRuntimeBits(zcu));
const slice = try f.resolveInst(bin_op.lhs);
const index = try f.resolveInst(bin_op.rhs);
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
- const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete));
- try f.writeCValue(w, local, .Other);
- try a.assign(f, w);
+ try f.writeCValue(w, local, .other);
+ try w.writeAll(" = ");
try f.writeCValueMember(w, slice, .{ .identifier = "ptr" });
try w.writeByte('[');
- try f.writeCValue(w, index, .Other);
- try w.writeByte(']');
- try a.end(f, w);
+ try f.writeCValue(w, index, .other);
+ try w.writeAll("];");
+ try f.newline();
return local;
}
fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
const inst_ty = f.typeOfIndex(inst);
const slice_ty = f.typeOf(bin_op.lhs);
- const elem_ty = slice_ty.elemType2(zcu);
- const elem_has_bits = elem_ty.hasRuntimeBitsIgnoreComptime(zcu);
+ const elem_ty = slice_ty.childType(zcu);
+ assert(elem_ty.hasRuntimeBits(zcu));
const slice = try f.resolveInst(bin_op.lhs);
const index = try f.resolveInst(bin_op.rhs);
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
- const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete));
- try f.writeCValue(w, local, .Other);
- try a.assign(f, w);
- if (elem_has_bits) try w.writeByte('&');
+ try f.writeCValue(w, local, .other);
+ try w.writeAll(" = ");
+ try w.writeByte('&');
try f.writeCValueMember(w, slice, .{ .identifier = "ptr" });
- if (elem_has_bits) {
- try w.writeByte('[');
- try f.writeCValue(w, index, .Other);
- try w.writeByte(']');
- }
- try a.end(f, w);
+ try w.writeByte('[');
+ try f.writeCValue(w, index, .other);
+ try w.writeAll("];");
+ try f.newline();
return local;
}
fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
- const zcu = f.object.dg.pt.zcu;
+ const zcu = f.dg.pt.zcu;
const bin_op = f.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
const inst_ty = f.typeOfIndex(inst);
- if (!inst_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
- try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
- return .none;
- }
+ assert(inst_ty.hasRuntimeBits(zcu));
const array = try f.resolveInst(bin_op.lhs);
const index = try f.resolveInst(bin_op.rhs);
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
- const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete));
- try f.writeCValue(w, local, .Other);
- try a.assign(f, w);
- try f.writeCValue(w, array, .Other);
+ try f.writeCValue(w, local, .other);
+ try w.writeAll(" = ");
+ try f.writeCValueMember(w, array, .{ .identifier = "array" });
try w.writeByte('[');
- try f.writeCValue(w, index, .Other);
- try w.writeByte(']');
- try a.end(f, w);
+ try f.writeCValue(w, index, .other);
+ try w.writeAll("];");
+ try f.newline();
return local;
}
fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const inst_ty = f.typeOfIndex(inst);
const elem_ty = inst_ty.childType(zcu);
- if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return .{ .undef = inst_ty };
+ if (!elem_ty.hasRuntimeBits(zcu)) return .{ .undef = inst_ty };
const local = try f.allocLocalValue(.{
- .ctype = try f.ctypeFromType(elem_ty, .complete),
- .alignas = CType.AlignAs.fromAlignment(.{
- .@"align" = inst_ty.ptrInfo(zcu).flags.alignment,
- .abi = elem_ty.abiAlignment(zcu),
- }),
+ .type = elem_ty,
+ .alignment = inst_ty.ptrInfo(zcu).flags.alignment,
});
log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
try f.allocs.put(zcu.gpa, local.new_local, true);
@@ -3810,11 +3113,11 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
// For packed aggregates, we zero-initialize to try and work around a design flaw
// related to how `packed`, `undefined`, and RLS interact. See comment in `airStore`
// for details.
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
try w.print("memset(&t{d}, 0x00, sizeof(", .{local.new_local});
try f.renderType(w, elem_ty);
try w.writeAll("));");
- try f.object.newline();
+ try f.newline();
},
.auto, .@"extern" => {},
},
@@ -3825,18 +3128,15 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
}
fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const inst_ty = f.typeOfIndex(inst);
const elem_ty = inst_ty.childType(zcu);
- if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return .{ .undef = inst_ty };
+ if (!elem_ty.hasRuntimeBits(zcu)) return .{ .undef = inst_ty };
const local = try f.allocLocalValue(.{
- .ctype = try f.ctypeFromType(elem_ty, .complete),
- .alignas = CType.AlignAs.fromAlignment(.{
- .@"align" = inst_ty.ptrInfo(zcu).flags.alignment,
- .abi = elem_ty.abiAlignment(zcu),
- }),
+ .type = elem_ty,
+ .alignment = inst_ty.ptrInfo(zcu).flags.alignment,
});
log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
try f.allocs.put(zcu.gpa, local.new_local, true);
@@ -3847,11 +3147,11 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
// For packed aggregates, we zero-initialize to try and work around a design flaw
// related to how `packed`, `undefined`, and RLS interact. See comment in `airStore`
// for details.
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
try w.print("memset(&t{d}, 0x00, sizeof(", .{local.new_local});
try f.renderType(w, elem_ty);
try w.writeAll("));");
- try f.object.newline();
+ try f.newline();
},
.auto, .@"extern" => {},
},
@@ -3862,24 +3162,18 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
}
fn airArg(f: *Function, inst: Air.Inst.Index) !CValue {
- const inst_ty = f.typeOfIndex(inst);
- const inst_ctype = try f.ctypeFromType(inst_ty, .parameter);
-
const i = f.next_arg_index;
f.next_arg_index += 1;
- const result: CValue = if (inst_ctype.eql(try f.ctypeFromType(inst_ty, .complete)))
- .{ .arg = i }
- else
- .{ .arg_array = i };
+ const result: CValue = .{ .arg = i };
if (f.liveness.isUnused(inst)) {
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
try w.writeByte('(');
try f.renderType(w, .void);
try w.writeByte(')');
- try f.writeCValue(w, result, .Other);
+ try f.writeCValue(w, result, .other);
try w.writeByte(';');
- try f.object.newline();
+ try f.newline();
return .none;
}
@@ -3887,7 +3181,7 @@ fn airArg(f: *Function, inst: Air.Inst.Index) !CValue {
}
fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
@@ -3900,10 +3194,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
// bit-pointers we see here are vector element pointers.
assert(ptr_info.packed_offset.host_size == 0 or ptr_info.flags.vector_index != .none);
- if (!src_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
- try reap(f, inst, &.{ty_op.operand});
- return .none;
- }
+ assert(src_ty.hasRuntimeBits(zcu));
const operand = try f.resolveInst(ty_op.operand);
@@ -3913,94 +3204,69 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
ptr_info.flags.alignment.order(src_ty.abiAlignment(zcu)).compare(.gte)
else
true;
- const is_array = lowersToArray(src_ty, zcu);
- const need_memcpy = !is_aligned or is_array;
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, src_ty);
const v = try Vectorize.start(f, inst, w, ptr_ty);
- if (need_memcpy) {
- try w.writeAll("memcpy(");
- if (!is_array) try w.writeByte('&');
- try f.writeCValue(w, local, .Other);
+ if (!is_aligned) {
+ try w.writeAll("memcpy(&");
+ try f.writeCValue(w, local, .other);
try v.elem(f, w);
try w.writeAll(", (const char *)");
- try f.writeCValue(w, operand, .Other);
+ try f.writeCValue(w, operand, .other);
try v.elem(f, w);
try w.writeAll(", sizeof(");
try f.renderType(w, src_ty);
try w.writeAll("))");
} else {
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try v.elem(f, w);
try w.writeAll(" = ");
try f.writeCValueDeref(w, operand);
try v.elem(f, w);
}
try w.writeByte(';');
- try f.object.newline();
+ try f.newline();
try v.end(f, inst, w);
return local;
}
fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !void {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const un_op = f.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const op_inst = un_op.toIndex();
const op_ty = f.typeOf(un_op);
const ret_ty = if (is_ptr) op_ty.childType(zcu) else op_ty;
- const ret_ctype = try f.ctypeFromType(ret_ty, .parameter);
if (op_inst != null and f.air.instructions.items(.tag)[@intFromEnum(op_inst.?)] == .call_always_tail) {
try reap(f, inst, &.{un_op});
_ = try airCall(f, op_inst.?, .always_tail);
- } else if (ret_ctype.index != .void) {
+ } else if (ret_ty.hasRuntimeBits(zcu)) {
const operand = try f.resolveInst(un_op);
try reap(f, inst, &.{un_op});
- var deref = is_ptr;
- const is_array = lowersToArray(ret_ty, zcu);
- const ret_val = if (is_array) ret_val: {
- const array_local = try f.allocAlignedLocal(inst, .{
- .ctype = ret_ctype,
- .alignas = CType.AlignAs.fromAbiAlignment(ret_ty.abiAlignment(zcu)),
- });
- try w.writeAll("memcpy(");
- try f.writeCValueMember(w, array_local, .{ .identifier = "array" });
- try w.writeAll(", ");
- if (deref)
- try f.writeCValueDeref(w, operand)
- else
- try f.writeCValue(w, operand, .FunctionArgument);
- deref = false;
- try w.writeAll(", sizeof(");
- try f.renderType(w, ret_ty);
- try w.writeAll("));");
- try f.object.newline();
- break :ret_val array_local;
- } else operand;
try w.writeAll("return ");
- if (deref)
- try f.writeCValueDeref(w, ret_val)
- else
- try f.writeCValue(w, ret_val, .Other);
- try w.writeAll(";\n");
- if (is_array) {
- try freeLocal(f, inst, ret_val.new_local, null);
+ if (is_ptr) {
+ try f.writeCValueDeref(w, operand);
+ } else switch (operand) {
+ // Instead of 'return &local', emit 'return undefined'.
+ .local_ref => try f.dg.renderUndefValue(w, ret_ty, .other),
+ else => try f.writeCValue(w, operand, .other),
}
+ try w.writeAll(";\n");
} else {
try reap(f, inst, &.{un_op});
// Not even allowed to return void in a naked function.
- if (!f.object.dg.is_naked_fn) try w.writeAll("return;\n");
+ if (!f.dg.is_naked_fn) try w.writeAll("return;\n");
}
}
fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
@@ -4012,23 +3278,26 @@ 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);
+ // `intCastIsNoop` doesn't apply to vectors because every vector lowers to a different C struct.
+ if (inst_ty.zigTypeTag(zcu) != .vector and f.dg.intCastIsNoop(inst_scalar_ty, scalar_ty)) {
+ return f.moveCValue(inst, inst_ty, operand);
+ }
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
const v = try Vectorize.start(f, inst, w, operand_ty);
- const a = try Assignment.start(f, w, try f.ctypeFromType(scalar_ty, .complete));
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try v.elem(f, w);
- try a.assign(f, w);
- try f.renderIntCast(w, inst_scalar_ty, operand, v, scalar_ty, .Other);
- try a.end(f, w);
+ try w.writeAll(" = ");
+ try f.renderIntCast(w, inst_scalar_ty, operand, v, scalar_ty, .other);
+ try w.writeByte(';');
+ try f.newline();
try v.end(f, inst, w);
return local;
}
fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
@@ -4050,13 +3319,12 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
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 w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
const v = try Vectorize.start(f, inst, w, operand_ty);
- const a = try Assignment.start(f, w, try f.ctypeFromType(inst_scalar_ty, .complete));
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try v.elem(f, w);
- try a.assign(f, w);
+ try w.writeAll(" = ");
if (need_cast) {
try w.writeByte('(');
try f.renderType(w, inst_scalar_ty);
@@ -4064,18 +3332,18 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
}
if (need_lo) {
try w.writeAll("zig_lo_");
- try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty);
+ try f.dg.renderTypeForBuiltinFnName(w, scalar_ty);
try w.writeByte('(');
}
if (!need_mask) {
- try f.writeCValue(w, operand, .Other);
+ try f.writeCValue(w, operand, .other);
try v.elem(f, w);
} else switch (dest_int_info.signedness) {
.unsigned => {
try w.writeAll("zig_and_");
- try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty);
+ try f.dg.renderTypeForBuiltinFnName(w, scalar_ty);
try w.writeByte('(');
- try f.writeCValue(w, operand, .FunctionArgument);
+ try f.writeCValue(w, operand, .other);
try v.elem(f, w);
try w.print(", {f})", .{
try f.fmtIntLiteralHex(try inst_scalar_ty.maxIntScalar(pt, scalar_ty)),
@@ -4087,7 +3355,7 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
const shift_val = try pt.intValue(.u8, c_bits - dest_bits);
try w.writeAll("zig_shr_");
- try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty);
+ try f.dg.renderTypeForBuiltinFnName(w, scalar_ty);
if (c_bits == 128) {
try w.print("(zig_bitCast_i{d}(", .{c_bits});
} else {
@@ -4099,7 +3367,7 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
} else {
try w.print("(uint{d}_t)", .{c_bits});
}
- try f.writeCValue(w, operand, .FunctionArgument);
+ try f.writeCValue(w, operand, .other);
try v.elem(f, w);
if (c_bits == 128) try w.writeByte(')');
try w.print(", {f})", .{try f.fmtIntLiteralDec(shift_val)});
@@ -4108,13 +3376,14 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
},
}
if (need_lo) try w.writeByte(')');
- try a.end(f, w);
+ try w.writeByte(';');
+ try f.newline();
try v.end(f, inst, w);
return local;
}
fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
// *a = b;
const bin_op = f.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
@@ -4132,7 +3401,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
const val_is_undef = if (try f.air.value(bin_op.rhs, pt)) |v| v.isUndef(zcu) else false;
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
if (val_is_undef) {
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
if (safety and ptr_info.packed_offset.host_size == 0) {
@@ -4152,11 +3421,11 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
},
};
try w.writeAll("memset(");
- try f.writeCValue(w, ptr_val, .FunctionArgument);
+ try f.writeCValue(w, ptr_val, .other);
try w.print(", {s}, sizeof(", .{byte_str});
try f.renderType(w, .fromInterned(ptr_info.child));
try w.writeAll("));");
- try f.object.newline();
+ try f.newline();
}
return .none;
}
@@ -4165,46 +3434,29 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
ptr_info.flags.alignment.order(src_ty.abiAlignment(zcu)).compare(.gte)
else
true;
- const is_array = lowersToArray(.fromInterned(ptr_info.child), zcu);
- const need_memcpy = !is_aligned or is_array;
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);
- if (need_memcpy) {
+ if (!is_aligned) {
// 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).
assert(src_ty.eql(.fromInterned(ptr_info.child), zcu));
- // If the source is a constant, writeCValue will emit a brace initialization
- // so work around this by initializing into new local.
- // TODO this should be done by manually initializing elements of the dest array
- const array_src = if (src_val == .constant) blk: {
- const new_local = try f.allocLocal(inst, src_ty);
- try f.writeCValue(w, new_local, .Other);
- try w.writeAll(" = ");
- try f.writeCValue(w, src_val, .Other);
- try w.writeByte(';');
- try f.object.newline();
-
- break :blk new_local;
- } else src_val;
-
const v = try Vectorize.start(f, inst, w, ptr_ty);
try w.writeAll("memcpy((char *)");
- try f.writeCValue(w, ptr_val, .FunctionArgument);
+ try f.writeCValue(w, ptr_val, .other);
try v.elem(f, w);
- try w.writeAll(", ");
- if (!is_array) try w.writeByte('&');
- try f.writeCValue(w, array_src, .FunctionArgument);
+ try w.writeAll(", &");
+ switch (src_val) {
+ .constant => |val| try f.dg.renderValueAsLvalue(w, val),
+ else => try f.writeCValue(w, src_val, .other),
+ }
try v.elem(f, w);
try w.writeAll(", sizeof(");
try f.renderType(w, src_ty);
- try w.writeAll("))");
- try f.freeCValue(inst, array_src);
- try w.writeByte(';');
- try f.object.newline();
+ try w.writeAll("));");
+ try f.newline();
try v.end(f, inst, w);
} else {
switch (ptr_val) {
@@ -4216,20 +3468,20 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
else => {},
}
const v = try Vectorize.start(f, inst, w, ptr_ty);
- const a = try Assignment.start(f, w, src_scalar_ctype);
try f.writeCValueDeref(w, ptr_val);
try v.elem(f, w);
- try a.assign(f, w);
- try f.writeCValue(w, src_val, .Other);
+ try w.writeAll(" = ");
+ try f.writeCValue(w, src_val, .other);
try v.elem(f, w);
- try a.end(f, w);
+ try w.writeByte(';');
+ try f.newline();
try v.end(f, inst, w);
}
return .none;
}
fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: BuiltinInfo) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
@@ -4242,7 +3494,9 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info:
const operand_ty = f.typeOf(bin_op.lhs);
const scalar_ty = operand_ty.scalarType(zcu);
- const w = &f.object.code.writer;
+ const ref_arg = lowersToBigInt(scalar_ty, zcu);
+
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
const v = try Vectorize.start(f, inst, w, operand_ty);
try f.writeCValueMember(w, local, .{ .field = 1 });
@@ -4250,26 +3504,28 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info:
try w.writeAll(" = zig_");
try w.writeAll(operation);
try w.writeAll("o_");
- try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty);
+ try f.dg.renderTypeForBuiltinFnName(w, scalar_ty);
try w.writeAll("(&");
try f.writeCValueMember(w, local, .{ .field = 0 });
try v.elem(f, w);
try w.writeAll(", ");
- try f.writeCValue(w, lhs, .FunctionArgument);
+ if (ref_arg) try w.writeByte('&');
+ try f.writeCValue(w, lhs, .other);
try v.elem(f, w);
try w.writeAll(", ");
- try f.writeCValue(w, rhs, .FunctionArgument);
+ if (ref_arg) try w.writeByte('&');
+ try f.writeCValue(w, rhs, .other);
if (f.typeOf(bin_op.rhs).isVector(zcu)) try v.elem(f, w);
- try f.object.dg.renderBuiltinInfo(w, scalar_ty, info);
+ try f.dg.renderBuiltinInfo(w, scalar_ty, info);
try w.writeAll(");");
- try f.object.newline();
+ try f.newline();
try v.end(f, inst, w);
return local;
}
fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
const operand_ty = f.typeOf(ty_op.operand);
@@ -4281,17 +3537,17 @@ fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {
const inst_ty = f.typeOfIndex(inst);
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
const v = try Vectorize.start(f, inst, w, operand_ty);
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try v.elem(f, w);
try w.writeAll(" = ");
try w.writeByte('!');
- try f.writeCValue(w, op, .Other);
+ try f.writeCValue(w, op, .other);
try v.elem(f, w);
try w.writeByte(';');
- try f.object.newline();
+ try f.newline();
try v.end(f, inst, w);
return local;
@@ -4304,7 +3560,7 @@ fn airBinOp(
operation: []const u8,
info: BuiltinInfo,
) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const bin_op = f.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
const operand_ty = f.typeOf(bin_op.lhs);
@@ -4318,21 +3574,21 @@ fn airBinOp(
const inst_ty = f.typeOfIndex(inst);
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
const v = try Vectorize.start(f, inst, w, operand_ty);
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try v.elem(f, w);
try w.writeAll(" = ");
- try f.writeCValue(w, lhs, .Other);
+ try f.writeCValue(w, lhs, .other);
try v.elem(f, w);
try w.writeByte(' ');
try w.writeAll(operator);
try w.writeByte(' ');
- try f.writeCValue(w, rhs, .Other);
+ try f.writeCValue(w, rhs, .other);
try v.elem(f, w);
try w.writeByte(';');
- try f.object.newline();
+ try f.newline();
try v.end(f, inst, w);
return local;
@@ -4344,7 +3600,7 @@ fn airCmpOp(
data: anytype,
operator: std.math.CompareOperator,
) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const lhs_ty = f.typeOf(data.lhs);
const scalar_ty = lhs_ty.scalarType(zcu);
@@ -4369,26 +3625,26 @@ fn airCmpOp(
const rhs_ty = f.typeOf(data.rhs);
const need_cast = lhs_ty.isSinglePointer(zcu) or rhs_ty.isSinglePointer(zcu);
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
const v = try Vectorize.start(f, inst, w, lhs_ty);
- const a = try Assignment.start(f, w, try f.ctypeFromType(scalar_ty, .complete));
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try v.elem(f, w);
- try a.assign(f, w);
+ try w.writeAll(" = ");
if (lhs != .undef and lhs.eql(rhs)) try w.writeAll(switch (operator) {
.lt, .neq, .gt => "false",
.lte, .eq, .gte => "true",
}) else {
if (need_cast) try w.writeAll("(void*)");
- try f.writeCValue(w, lhs, .Other);
+ try f.writeCValue(w, lhs, .other);
try v.elem(f, w);
try w.writeAll(compareOperatorC(operator));
if (need_cast) try w.writeAll("(void*)");
- try f.writeCValue(w, rhs, .Other);
+ try f.writeCValue(w, rhs, .other);
try v.elem(f, w);
}
- try a.end(f, w);
+ try w.writeByte(';');
+ try f.newline();
try v.end(f, inst, w);
return local;
@@ -4399,9 +3655,8 @@ fn airEquality(
inst: Air.Inst.Index,
operator: std.math.CompareOperator,
) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.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);
@@ -4422,54 +3677,64 @@ fn airEquality(
const rhs = try f.resolveInst(bin_op.rhs);
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
- const w = &f.object.code.writer;
+ if (lhs.eql(rhs)) {
+ // Avoid emitting a tautological comparison.
+ return .{ .constant = .makeBool(switch (operator) {
+ .eq, .lte, .gte => true,
+ .neq, .lt, .gt => false,
+ }) };
+ }
+
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, .bool);
- const a = try Assignment.start(f, w, .bool);
- try f.writeCValue(w, local, .Other);
- try a.assign(f, w);
+ try f.writeCValue(w, local, .other);
+ try w.writeAll(" = ");
- const operand_ctype = try f.ctypeFromType(operand_ty, .complete);
- if (lhs != .undef and lhs.eql(rhs)) try w.writeAll(switch (operator) {
- .lt, .lte, .gte, .gt => unreachable,
- .neq => "false",
- .eq => "true",
- }) else switch (operand_ctype.info(ctype_pool)) {
- .basic, .pointer => {
- try f.writeCValue(w, lhs, .Other);
- try w.writeAll(compareOperatorC(operator));
- try f.writeCValue(w, 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(w, lhs, .{ .identifier = "is_null" });
- try w.writeAll(" || ");
- try f.writeCValueMember(w, rhs, .{ .identifier = "is_null" });
- try w.writeAll(" ? ");
- try f.writeCValueMember(w, lhs, .{ .identifier = "is_null" });
- try w.writeAll(compareOperatorC(operator));
- try f.writeCValueMember(w, rhs, .{ .identifier = "is_null" });
- try w.writeAll(" : ");
- try f.writeCValueMember(w, lhs, .{ .identifier = "payload" });
- try w.writeAll(compareOperatorC(operator));
- try f.writeCValueMember(w, rhs, .{ .identifier = "payload" });
- } else for (0..aggregate.fields.len) |field_index| {
- if (field_index > 0) try w.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(w, lhs, field_name);
- try w.writeAll(compareOperatorC(operator));
- try f.writeCValueMember(w, rhs, field_name);
+ switch (operand_ty.zigTypeTag(zcu)) {
+ .optional => switch (CType.classifyOptional(operand_ty, zcu)) {
+ .npv_payload => unreachable, // opv optional
+
+ .error_set, .ptr_like => {},
+
+ .slice_like => unreachable, // equality is not defined on slices
+
+ .opv_payload => {
+ try f.writeCValueMember(w, lhs, .{ .identifier = "is_null" });
+ try w.writeAll(compareOperatorC(operator));
+ try f.writeCValueMember(w, rhs, .{ .identifier = "is_null" });
+ try w.writeByte(';');
+ try f.newline();
+ return local;
+ },
+
+ .@"struct" => {
+ // `lhs.is_null || rhs.is_null ? lhs.is_null == rhs.is_null : lhs.payload == rhs.payload`
+ try f.writeCValueMember(w, lhs, .{ .identifier = "is_null" });
+ try w.writeAll(" || ");
+ try f.writeCValueMember(w, rhs, .{ .identifier = "is_null" });
+ try w.writeAll(" ? ");
+ try f.writeCValueMember(w, lhs, .{ .identifier = "is_null" });
+ try w.writeAll(compareOperatorC(operator));
+ try f.writeCValueMember(w, rhs, .{ .identifier = "is_null" });
+ try w.writeAll(" : ");
+ try f.writeCValueMember(w, lhs, .{ .identifier = "payload" });
+ try w.writeAll(compareOperatorC(operator));
+ try f.writeCValueMember(w, rhs, .{ .identifier = "payload" });
+ try w.writeByte(';');
+ try f.newline();
+ return local;
+ },
},
+ .bool, .int, .pointer, .@"enum", .error_set => {},
+ .@"struct", .@"union" => assert(operand_ty.containerLayout(zcu) == .@"packed"),
+ else => unreachable,
}
- try a.end(f, w);
+
+ try f.writeCValue(w, lhs, .other);
+ try w.writeAll(compareOperatorC(operator));
+ try f.writeCValue(w, rhs, .other);
+ try w.writeByte(';');
+ try f.newline();
return local;
}
@@ -4480,18 +3745,18 @@ fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue {
const operand = try f.resolveInst(un_op);
try reap(f, inst, &.{un_op});
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, .bool);
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try w.writeAll(" = ");
- try f.writeCValue(w, operand, .Other);
+ try f.writeCValue(w, operand, .other);
try w.print(" < sizeof({f}) / sizeof(*{0f});", .{fmtIdentSolo("zig_errorName")});
- try f.object.newline();
+ try f.newline();
return local;
}
fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
@@ -4502,40 +3767,36 @@ 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 elem_ty = inst_scalar_ty.indexableElem(zcu);
+ assert(elem_ty.hasRuntimeBits(zcu));
const local = try f.allocLocal(inst, inst_ty);
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const v = try Vectorize.start(f, inst, w, inst_ty);
- const a = try Assignment.start(f, w, inst_scalar_ctype);
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try v.elem(f, w);
- try a.assign(f, w);
+ try w.writeAll(" = ");
// 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 w.writeByte('(');
- try f.renderCType(w, inst_scalar_ctype);
+ try f.renderType(w, inst_scalar_ty);
try w.writeAll(")(((uintptr_t)");
- try f.writeCValue(w, lhs, .Other);
+ try f.writeCValue(w, lhs, .other);
try v.elem(f, w);
- try w.writeAll(") ");
- try w.writeByte(operator);
- try w.writeAll(" (");
- try f.writeCValue(w, rhs, .Other);
+ try w.print(") {c} (", .{operator});
+ try f.writeCValue(w, rhs, .other);
try v.elem(f, w);
try w.writeAll("*sizeof(");
try f.renderType(w, elem_ty);
- try w.writeAll(")))");
- try a.end(f, w);
+ try w.writeAll(")));");
+ try f.newline();
try v.end(f, inst, w);
return local;
}
fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []const u8) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const bin_op = f.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
@@ -4549,36 +3810,34 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons
const rhs = try f.resolveInst(bin_op.rhs);
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
const v = try Vectorize.start(f, inst, w, inst_ty);
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try v.elem(f, w);
// (lhs <> rhs) ? lhs : rhs
try w.writeAll(" = (");
- try f.writeCValue(w, lhs, .Other);
+ try f.writeCValue(w, lhs, .other);
try v.elem(f, w);
try w.writeByte(' ');
try w.writeByte(operator);
try w.writeByte(' ');
- try f.writeCValue(w, rhs, .Other);
+ try f.writeCValue(w, rhs, .other);
try v.elem(f, w);
try w.writeAll(") ? ");
- try f.writeCValue(w, lhs, .Other);
+ try f.writeCValue(w, lhs, .other);
try v.elem(f, w);
try w.writeAll(" : ");
- try f.writeCValue(w, rhs, .Other);
+ try f.writeCValue(w, rhs, .other);
try v.elem(f, w);
try w.writeByte(';');
- try f.object.newline();
+ try f.newline();
try v.end(f, inst, w);
return local;
}
fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
- const zcu = pt.zcu;
const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
@@ -4587,24 +3846,22 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
const inst_ty = f.typeOfIndex(inst);
- const ptr_ty = inst_ty.slicePtrFieldType(zcu);
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
- {
- const a = try Assignment.start(f, w, try f.ctypeFromType(ptr_ty, .complete));
- try f.writeCValueMember(w, local, .{ .identifier = "ptr" });
- try a.assign(f, w);
- try f.writeCValue(w, ptr, .Other);
- try a.end(f, w);
- }
- {
- const a = try Assignment.start(f, w, .usize);
- try f.writeCValueMember(w, local, .{ .identifier = "len" });
- try a.assign(f, w);
- try f.writeCValue(w, len, .Other);
- try a.end(f, w);
- }
+
+ try f.writeCValueMember(w, local, .{ .identifier = "ptr" });
+ try w.writeAll(" = ");
+ try f.writeCValue(w, ptr, .other);
+ try w.writeByte(';');
+ try f.newline();
+
+ try f.writeCValueMember(w, local, .{ .identifier = "len" });
+ try w.writeAll(" = ");
+ try f.writeCValue(w, len, .other);
+ try w.writeByte(';');
+ try f.newline();
+
return local;
}
@@ -4613,14 +3870,14 @@ fn airCall(
inst: Air.Inst.Index,
modifier: std.builtin.CallModifier,
) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
// Not even allowed to call panic in a naked function.
- if (f.object.dg.is_naked_fn) return .none;
+ if (f.dg.is_naked_fn) return .none;
- const gpa = f.object.dg.gpa;
- const w = &f.object.code.writer;
+ const gpa = f.dg.gpa;
+ const w = &f.code.writer;
const call = f.air.unwrapCall(inst);
const args = call.args;
@@ -4629,27 +3886,11 @@ fn airCall(
defer gpa.free(resolved_args);
for (resolved_args, args) |*resolved_arg, arg| {
const arg_ty = f.typeOf(arg);
- const arg_ctype = try f.ctypeFromType(arg_ty, .parameter);
- if (arg_ctype.index == .void) {
+ if (!arg_ty.hasRuntimeBits(zcu)) {
resolved_arg.* = .none;
continue;
}
resolved_arg.* = try f.resolveInst(arg);
- if (!arg_ctype.eql(try f.ctypeFromType(arg_ty, .complete))) {
- const array_local = try f.allocAlignedLocal(inst, .{
- .ctype = arg_ctype,
- .alignas = CType.AlignAs.fromAbiAlignment(arg_ty.abiAlignment(zcu)),
- });
- try w.writeAll("memcpy(");
- try f.writeCValueMember(w, array_local, .{ .identifier = "array" });
- try w.writeAll(", ");
- try f.writeCValue(w, resolved_arg.*, .FunctionArgument);
- try w.writeAll(", sizeof(");
- try f.renderCType(w, arg_ctype);
- try w.writeAll("));");
- try f.object.newline();
- resolved_arg.* = array_local;
- }
}
const callee = try f.resolveInst(call.callee);
@@ -4668,28 +3909,22 @@ fn airCall(
};
const fn_info = zcu.typeToFunc(if (callee_is_ptr) callee_ty.childType(zcu) else callee_ty).?;
const ret_ty: Type = .fromInterned(fn_info.return_type);
- const ret_ctype: CType = if (ret_ty.isNoReturn(zcu))
- .void
- else
- try f.ctypeFromType(ret_ty, .parameter);
const result_local = result: {
if (modifier == .always_tail) {
try w.writeAll("zig_always_tail return ");
break :result .none;
- } else if (ret_ctype.index == .void) {
+ } else if (!ret_ty.hasRuntimeBits(zcu)) {
break :result .none;
} else if (f.liveness.isUnused(inst)) {
- try w.writeByte('(');
- try f.renderCType(w, .void);
- try w.writeByte(')');
+ try w.writeAll("(void)");
break :result .none;
} else {
const local = try f.allocAlignedLocal(inst, .{
- .ctype = ret_ctype,
- .alignas = CType.AlignAs.fromAbiAlignment(ret_ty.abiAlignment(zcu)),
+ .type = ret_ty,
+ .alignment = .none,
});
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try w.writeAll(" = ");
break :result local;
}
@@ -4716,8 +3951,19 @@ fn airCall(
if (!callee_is_ptr) try w.writeByte('&');
}
switch (modifier) {
- .auto, .always_tail => try f.object.dg.renderNavName(w, fn_nav),
- inline .never_tail, .never_inline => |m| try w.writeAll(try f.getLazyFnName(@unionInit(LazyFnKey, @tagName(m), fn_nav))),
+ .auto, .always_tail => try renderNavName(w, fn_nav, ip),
+ .never_tail => {
+ try f.need_never_tail_funcs.put(gpa, fn_nav, {});
+ try w.print("zig_never_tail_{f}__{d}", .{
+ fmtIdentUnsolo(ip.getNav(fn_nav).name.toSlice(ip)), @intFromEnum(fn_nav),
+ });
+ },
+ .never_inline => {
+ try f.need_never_inline_funcs.put(gpa, fn_nav, {});
+ try w.print("zig_never_inline_{f}__{d}", .{
+ fmtIdentUnsolo(ip.getNav(fn_nav).name.toSlice(ip)), @intFromEnum(fn_nav),
+ });
+ },
else => unreachable,
}
if (need_cast) try w.writeByte(')');
@@ -4730,7 +3976,7 @@ fn airCall(
else => unreachable,
}
// Fall back to function pointer call.
- try f.writeCValue(w, callee, .Other);
+ try f.writeCValue(w, callee, .other);
}
try w.writeByte('(');
@@ -4739,38 +3985,20 @@ fn airCall(
if (resolved_arg == .none) continue;
if (need_comma) try w.writeAll(", ");
need_comma = true;
- try f.writeCValue(w, resolved_arg, .FunctionArgument);
- try f.freeCValue(inst, resolved_arg);
+ try f.writeCValue(w, resolved_arg, .other);
}
try w.writeAll(");");
switch (modifier) {
.always_tail => try w.writeByte('\n'),
- else => try f.object.newline(),
+ else => try f.newline(),
}
- const result = result: {
- if (result_local == .none or !lowersToArray(ret_ty, zcu))
- break :result result_local;
-
- const array_local = try f.allocLocal(inst, ret_ty);
- try w.writeAll("memcpy(");
- try f.writeCValue(w, array_local, .FunctionArgument);
- try w.writeAll(", ");
- try f.writeCValueMember(w, result_local, .{ .identifier = "array" });
- try w.writeAll(", sizeof(");
- try f.renderType(w, ret_ty);
- try w.writeAll("));");
- try f.object.newline();
- try freeLocal(f, inst, result_local.new_local, null);
- break :result array_local;
- };
-
- return result;
+ return result_local;
}
fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue {
const dbg_stmt = f.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
// TODO re-evaluate whether to emit these or not. If we naively emit
// these directives, the output file will report bogus line numbers because
// every newline after the #line directive adds one to the line.
@@ -4779,32 +4007,32 @@ fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue {
// newlines until the next dbg_stmt occurs.
// Perhaps an additional compilation option is in order?
//try w.print("#line {d}", .{dbg_stmt.line + 1});
- //try f.object.newline();
+ //try f.newline();
try w.print("/* file:{d}:{d} */", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 });
- try f.object.newline();
+ try f.newline();
return .none;
}
fn airDbgEmptyStmt(f: *Function, _: Air.Inst.Index) !CValue {
- try f.object.code.writer.writeAll("(void)0;");
- try f.object.newline();
+ try f.code.writer.writeAll("(void)0;");
+ try f.newline();
return .none;
}
fn airDbgInlineBlock(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const block = f.air.unwrapDbgBlock(inst);
const owner_nav = ip.getNav(zcu.funcInfo(block.func).owner_nav);
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
try w.print("/* inline:{f} */", .{owner_nav.fqn.fmt(&zcu.intern_pool)});
- try f.object.newline();
+ try f.newline();
return lowerBlock(f, inst, block.body);
}
fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const tag = f.air.instructions.items(.tag)[@intFromEnum(inst)];
const pl_op = f.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
@@ -4813,9 +4041,9 @@ fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue {
if (!operand_is_undef) _ = try f.resolveInst(pl_op.operand);
try reap(f, inst, &.{pl_op.operand});
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
try w.print("/* {s}:{s} */", .{ @tagName(tag), name.toSlice(f.air) });
- try f.object.newline();
+ try f.newline();
return .none;
}
@@ -4825,21 +4053,21 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {
}
fn lowerBlock(f: *Function, inst: Air.Inst.Index, body: []const Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const liveness_block = f.liveness.getBlock(inst);
const block_id = f.next_block_index;
f.next_block_index += 1;
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const inst_ty = f.typeOfIndex(inst);
- const result = if (inst_ty.hasRuntimeBitsIgnoreComptime(zcu) and !f.liveness.isUnused(inst))
+ const result = if (inst_ty.hasRuntimeBits(zcu) and !f.liveness.isUnused(inst))
try f.allocLocal(inst, inst_ty)
else
.none;
- try f.blocks.putNoClobber(f.object.dg.gpa, inst, .{
+ try f.blocks.putNoClobber(f.dg.gpa, inst, .{
.block_id = block_id,
.result = result,
});
@@ -4854,23 +4082,23 @@ fn lowerBlock(f: *Function, inst: Air.Inst.Index, body: []const Air.Inst.Index)
}
// noreturn blocks have no `br` instructions reaching them, so we don't want a label
- if (f.object.dg.is_naked_fn) {
- if (f.object.dg.expected_block) |expected_block| {
+ if (f.dg.is_naked_fn) {
+ if (f.dg.expected_block) |expected_block| {
if (block_id != expected_block)
return f.fail("runtime code not allowed in naked function", .{});
- f.object.dg.expected_block = null;
+ f.dg.expected_block = null;
}
} else if (!f.typeOfIndex(inst).isNoReturn(zcu)) {
// label must be followed by an expression, include an empty one.
try w.print("\nzig_block_{d}:;", .{block_id});
- try f.object.newline();
+ try f.newline();
}
return result;
}
fn airTry(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const unwrapped_try = f.air.unwrapTry(inst);
const body = unwrapped_try.else_body;
const err_union_ty = f.air.typeOf(unwrapped_try.error_union, &pt.zcu.intern_pool);
@@ -4878,7 +4106,7 @@ fn airTry(f: *Function, inst: Air.Inst.Index) !CValue {
}
fn airTryPtr(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const unwrapped_try = f.air.unwrapTryPtr(inst);
const body = unwrapped_try.else_body;
const err_union_ty = f.air.typeOf(unwrapped_try.error_union_ptr, &pt.zcu.intern_pool).childType(pt.zcu);
@@ -4893,46 +4121,38 @@ fn lowerTry(
err_union_ty: Type,
is_ptr: bool,
) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const err_union = try f.resolveInst(operand);
const inst_ty = f.typeOfIndex(inst);
const liveness_condbr = f.liveness.getCondBr(inst);
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const payload_ty = err_union_ty.errorUnionPayload(zcu);
- const payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(zcu);
- if (!err_union_ty.errorUnionSet(zcu).errorSetIsEmpty(zcu)) {
- try w.writeAll("if (");
- if (!payload_has_bits) {
- if (is_ptr)
- try f.writeCValueDeref(w, err_union)
- else
- try f.writeCValue(w, err_union, .Other);
- } else {
- // Reap the operand so that it can be reused inside genBody.
- // Remember we must avoid calling reap() twice for the same operand
- // in this function.
- try reap(f, inst, &.{operand});
- if (is_ptr)
- try f.writeCValueDerefMember(w, err_union, .{ .identifier = "error" })
- else
- try f.writeCValueMember(w, err_union, .{ .identifier = "error" });
- }
- try w.writeAll(") ");
+ try w.writeAll("if (");
- try genBodyResolveState(f, inst, liveness_condbr.else_deaths, body, false);
- try f.object.newline();
- if (f.object.dg.expected_block) |_|
- return f.fail("runtime code not allowed in naked function", .{});
- }
+ // Reap the operand so that it can be reused inside genBody.
+ // Remember we must avoid calling reap() twice for the same operand
+ // in this function.
+ try reap(f, inst, &.{operand});
+ if (is_ptr)
+ try f.writeCValueDerefMember(w, err_union, .{ .identifier = "error" })
+ else
+ try f.writeCValueMember(w, err_union, .{ .identifier = "error" });
+
+ try w.writeAll(") ");
+
+ try genBodyResolveState(f, inst, liveness_condbr.else_deaths, body, false);
+ try f.newline();
+ if (f.dg.expected_block) |_|
+ return f.fail("runtime code not allowed in naked function", .{});
// Now we have the "then branch" (in terms of the liveness data); process any deaths.
for (liveness_condbr.then_deaths) |death| {
try die(f, inst, death.toRef());
}
- if (!payload_has_bits) {
+ if (!payload_ty.hasRuntimeBits(zcu)) {
if (!is_ptr) {
return .none;
} else {
@@ -4945,14 +4165,14 @@ fn lowerTry(
if (f.liveness.isUnused(inst)) return .none;
const local = try f.allocLocal(inst, inst_ty);
- const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete));
- try f.writeCValue(w, local, .Other);
- try a.assign(f, w);
+ try f.writeCValue(w, local, .other);
+ try w.writeAll(" = ");
if (is_ptr) {
try w.writeByte('&');
try f.writeCValueDerefMember(w, err_union, .{ .identifier = "payload" });
} else try f.writeCValueMember(w, err_union, .{ .identifier = "payload" });
- try a.end(f, w);
+ try w.writeByte(';');
+ try f.newline();
return local;
}
@@ -4960,25 +4180,24 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !void {
const branch = f.air.instructions.items(.data)[@intFromEnum(inst)].br;
const block = f.blocks.get(branch.block_inst).?;
const result = block.result;
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
- if (f.object.dg.is_naked_fn) {
+ if (f.dg.is_naked_fn) {
if (result != .none) return f.fail("runtime code not allowed in naked function", .{});
- f.object.dg.expected_block = block.block_id;
+ f.dg.expected_block = block.block_id;
return;
}
// If result is .none then the value of the block is unused.
if (result != .none) {
- const operand_ty = f.typeOf(branch.operand);
const operand = try f.resolveInst(branch.operand);
try reap(f, inst, &.{branch.operand});
- const a = try Assignment.start(f, w, try f.ctypeFromType(operand_ty, .complete));
- try f.writeCValue(w, result, .Other);
- try a.assign(f, w);
- try f.writeCValue(w, operand, .Other);
- try a.end(f, w);
+ try f.writeCValue(w, result, .other);
+ try w.writeAll(" = ");
+ try f.writeCValue(w, operand, .other);
+ try w.writeByte(';');
+ try f.newline();
}
try w.print("goto zig_block_{d};\n", .{block.block_id});
@@ -4986,14 +4205,14 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !void {
fn airRepeat(f: *Function, inst: Air.Inst.Index) !void {
const repeat = f.air.instructions.items(.data)[@intFromEnum(inst)].repeat;
- try f.object.code.writer.print("goto zig_loop_{d};\n", .{@intFromEnum(repeat.loop_inst)});
+ try f.code.writer.print("goto zig_loop_{d};\n", .{@intFromEnum(repeat.loop_inst)});
}
fn airSwitchDispatch(f: *Function, inst: Air.Inst.Index) !void {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const br = f.air.instructions.items(.data)[@intFromEnum(inst)].br;
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
if (try f.air.value(br.operand, pt)) |cond_val| {
// Comptime-known dispatch. Iterate the cases to find the correct
@@ -5022,11 +4241,11 @@ fn airSwitchDispatch(f: *Function, inst: Air.Inst.Index) !void {
// Runtime-known dispatch. Set the switch condition, and branch back.
const cond = try f.resolveInst(br.operand);
const cond_local = f.loop_switch_conds.get(br.block_inst).?;
- try f.writeCValue(w, .{ .local = cond_local }, .Other);
+ try f.writeCValue(w, .{ .local = cond_local }, .other);
try w.writeAll(" = ");
- try f.writeCValue(w, cond, .Other);
+ try f.writeCValue(w, cond, .other);
try w.writeByte(';');
- try f.object.newline();
+ try f.newline();
try w.print("goto zig_switch_{d}_loop;\n", .{@intFromEnum(br.block_inst)});
}
@@ -5043,11 +4262,10 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
}
fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
- const target = &f.object.dg.mod.resolved_target.result;
- const ctype_pool = &f.object.dg.ctype_pool;
- const w = &f.object.code.writer;
+ const target = &f.dg.mod.resolved_target.result;
+ const w = &f.code.writer;
if (operand_ty.isAbiInt(zcu) and dest_ty.isAbiInt(zcu)) {
const src_info = dest_ty.intInfo(zcu);
@@ -5058,26 +4276,16 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !CVal
if (dest_ty.isPtrAtRuntime(zcu) or operand_ty.isPtrAtRuntime(zcu)) {
const local = try f.allocLocal(null, dest_ty);
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try w.writeAll(" = (");
try f.renderType(w, dest_ty);
try w.writeByte(')');
- try f.writeCValue(w, operand, .Other);
+ try f.writeCValue(w, operand, .other);
try w.writeByte(';');
- try f.object.newline();
+ try f.newline();
return local;
}
- const operand_lval = if (operand == .constant) blk: {
- const operand_local = try f.allocLocal(null, operand_ty);
- try f.writeCValue(w, operand_local, .Other);
- try w.writeAll(" = ");
- try f.writeCValue(w, operand, .Other);
- try w.writeByte(';');
- try f.object.newline();
- break :blk operand_local;
- } else operand;
-
const local = try f.allocLocal(null, dest_ty);
// On big-endian targets, copying ABI integers with padding bits is awkward, because the padding bits are at the low bytes of the value.
// We need to offset the source or destination pointer appropriately and copy the right number of bytes.
@@ -5085,141 +4293,134 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !CVal
// e.g. [10]u8 -> u80. We need to offset the destination so that we copy to the least significant bits of the integer.
const offset = dest_ty.abiSize(zcu) - operand_ty.abiSize(zcu);
try w.writeAll("memcpy((char *)&");
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try w.print(" + {d}, &", .{offset});
- try f.writeCValue(w, operand_lval, .Other);
+ switch (operand) {
+ .constant => |val| try f.dg.renderValueAsLvalue(w, val),
+ else => try f.writeCValue(w, operand, .other),
+ }
try w.print(", {d});", .{operand_ty.abiSize(zcu)});
} else if (target.cpu.arch.endian() == .big and operand_ty.isAbiInt(zcu) and !dest_ty.isAbiInt(zcu)) {
// e.g. u80 -> [10]u8. We need to offset the source so that we copy from the least significant bits of the integer.
const offset = operand_ty.abiSize(zcu) - dest_ty.abiSize(zcu);
try w.writeAll("memcpy(&");
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try w.writeAll(", (const char *)&");
- try f.writeCValue(w, operand_lval, .Other);
+ switch (operand) {
+ .constant => |val| try f.dg.renderValueAsLvalue(w, val),
+ else => try f.writeCValue(w, operand, .other),
+ }
try w.print(" + {d}, {d});", .{ offset, dest_ty.abiSize(zcu) });
} else {
try w.writeAll("memcpy(&");
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try w.writeAll(", &");
- try f.writeCValue(w, operand_lval, .Other);
+ switch (operand) {
+ .constant => |val| try f.dg.renderValueAsLvalue(w, val),
+ else => try f.writeCValue(w, operand, .other),
+ }
try w.print(", {d});", .{@min(dest_ty.abiSize(zcu), operand_ty.abiSize(zcu))});
}
- try f.object.newline();
+ try f.newline();
// Ensure padding bits have the expected value.
if (dest_ty.isAbiInt(zcu)) {
- const dest_ctype = try f.ctypeFromType(dest_ty, .complete);
- const dest_info = dest_ty.intInfo(zcu);
- var bits: u16 = dest_info.bits;
- var wrap_ctype: ?CType = null;
- var need_bitcasts = false;
-
- try f.writeCValue(w, local, .Other);
- switch (dest_ctype.info(ctype_pool)) {
- else => {},
- .array => |array_info| {
- try w.print("[{d}]", .{switch (target.cpu.arch.endian()) {
- .little => array_info.len - 1,
- .big => 0,
- }});
- wrap_ctype = array_info.elem_ctype.toSignedness(dest_info.signedness);
- need_bitcasts = wrap_ctype.?.index == .zig_i128;
- bits -= 1;
- bits %= @as(u16, @intCast(f.byteSize(array_info.elem_ctype) * 8));
- bits += 1;
+ switch (CType.classifyInt(dest_ty, zcu)) {
+ .void => unreachable, // opv
+ .small => {
+ try f.writeCValue(w, local, .other);
+ try w.writeAll(" = zig_wrap_");
+ try f.dg.renderTypeForBuiltinFnName(w, dest_ty);
+ try w.writeByte('(');
+ try f.writeCValue(w, local, .other);
+ try f.dg.renderBuiltinInfo(w, dest_ty, .bits);
+ try w.writeAll(");");
+ try f.newline();
},
- }
- try w.writeAll(" = ");
- if (need_bitcasts) {
- try w.writeAll("zig_bitCast_");
- try f.object.dg.renderCTypeForBuiltinFnName(w, wrap_ctype.?.toUnsigned());
- try w.writeByte('(');
- }
- try w.writeAll("zig_wrap_");
- const info_ty = try pt.intType(dest_info.signedness, bits);
- if (wrap_ctype) |ctype|
- try f.object.dg.renderCTypeForBuiltinFnName(w, ctype)
- else
- try f.object.dg.renderTypeForBuiltinFnName(w, info_ty);
- try w.writeByte('(');
- if (need_bitcasts) {
- try w.writeAll("zig_bitCast_");
- try f.object.dg.renderCTypeForBuiltinFnName(w, wrap_ctype.?);
- try w.writeByte('(');
- }
- try f.writeCValue(w, local, .Other);
- switch (dest_ctype.info(ctype_pool)) {
- else => {},
- .array => |array_info| try w.print("[{d}]", .{
- switch (target.cpu.arch.endian()) {
- .little => array_info.len - 1,
+ .big => |big| {
+ const dest_info = dest_ty.intInfo(zcu);
+ const padding_index: u16 = switch (target.cpu.arch.endian()) {
+ .little => big.limbs_len - 1,
.big => 0,
- },
- }),
+ };
+ const wrap_bits = ((dest_info.bits - 1) % big.limb_size.bits()) + 1;
+ if (big.limb_size != .@"128" or dest_info.signedness == .unsigned) {
+ try f.writeCValueMember(w, local, .{ .identifier = "limbs" });
+ try w.print("[{d}] = zig_wrap_{c}{d}(", .{
+ padding_index,
+ signAbbrev(dest_info.signedness),
+ big.limb_size.bits(),
+ });
+ try f.writeCValueMember(w, local, .{ .identifier = "limbs" });
+ try w.print("[{d}], {d});", .{ padding_index, wrap_bits });
+ } else {
+ try f.writeCValueMember(w, local, .{ .identifier = "limbs" });
+ try w.print("[{d}] = zig_bitCast_u128(zig_wrap_i128(zig_bitCast_i128(", .{
+ padding_index,
+ });
+ try f.writeCValueMember(w, local, .{ .identifier = "limbs" });
+ try w.print("[{d}]), {d}));", .{ padding_index, wrap_bits });
+ try f.newline();
+ }
+ },
}
- if (need_bitcasts) try w.writeByte(')');
- try f.object.dg.renderBuiltinInfo(w, info_ty, .bits);
- if (need_bitcasts) try w.writeByte(')');
- try w.writeAll(");");
- try f.object.newline();
}
- try f.freeCValue(null, operand_lval);
return local;
}
-fn airTrap(f: *Function, w: *Writer) !void {
+fn airTrap(f: *Function) !void {
// Not even allowed to call trap in a naked function.
- if (f.object.dg.is_naked_fn) return;
- try w.writeAll("zig_trap();\n");
+ if (f.dg.is_naked_fn) return;
+ try f.code.writer.writeAll("zig_trap();\n");
}
fn airBreakpoint(f: *Function) !CValue {
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
try w.writeAll("zig_breakpoint();");
- try f.object.newline();
+ try f.newline();
return .none;
}
fn airRetAddr(f: *Function, inst: Air.Inst.Index) !CValue {
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, .usize);
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try w.writeAll(" = (");
try f.renderType(w, .usize);
try w.writeAll(")zig_return_address();");
- try f.object.newline();
+ try f.newline();
return local;
}
fn airFrameAddress(f: *Function, inst: Air.Inst.Index) !CValue {
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, .usize);
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try w.writeAll(" = (");
try f.renderType(w, .usize);
try w.writeAll(")zig_frame_address();");
- try f.object.newline();
+ try f.newline();
return local;
}
-fn airUnreach(o: *Object) !void {
+fn airUnreach(f: *Function) !void {
// Not even allowed to call unreachable in a naked function.
- if (o.dg.is_naked_fn) return;
- try o.code.writer.writeAll("zig_unreachable();\n");
+ if (f.dg.is_naked_fn) return;
+ try f.code.writer.writeAll("zig_unreachable();\n");
}
fn airLoop(f: *Function, inst: Air.Inst.Index) !void {
const block = f.air.unwrapBlock(inst);
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
// `repeat` instructions matching this loop will branch to
// this label. Since we need a label for arbitrary `repeat`
// anyway, there's actually no need to use a "real" looping
// construct at all!
try w.print("zig_loop_{d}:", .{@intFromEnum(inst)});
- try f.object.newline();
+ try f.newline();
try genBodyInner(f, block.body); // no need to restore state, we're noreturn
}
@@ -5230,15 +4431,15 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !void {
const then_body = cond_br.then_body;
const else_body = cond_br.else_body;
const liveness_condbr = f.liveness.getCondBr(inst);
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
try w.writeAll("if (");
- try f.writeCValue(w, cond, .Other);
+ try f.writeCValue(w, cond, .other);
try w.writeAll(") ");
try genBodyResolveState(f, inst, liveness_condbr.then_deaths, then_body, false);
- try f.object.newline();
- if (else_body.len > 0) if (f.object.dg.expected_block) |_|
+ try f.newline();
+ if (else_body.len > 0) if (f.dg.expected_block) |_|
return f.fail("runtime code not allowed in naked function", .{});
// We don't need to use `genBodyResolveState` for the else block, because this instruction is
@@ -5256,23 +4457,23 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !void {
}
fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
- const gpa = f.object.dg.gpa;
+ const gpa = f.dg.gpa;
const switch_br = f.air.unwrapSwitch(inst);
const init_condition = try f.resolveInst(switch_br.operand);
try reap(f, inst, &.{switch_br.operand});
const condition_ty = f.typeOf(switch_br.operand);
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
// For dispatches, we will create a local alloc to contain the condition value.
// This may not result in optimal codegen for switch loops, but it minimizes the
// amount of C code we generate, which is probably more desirable here (and is simpler).
const condition = if (is_dispatch_loop) cond: {
const new_local = try f.allocLocal(inst, condition_ty);
- try f.copyCValue(try f.ctypeFromType(condition_ty, .complete), new_local, init_condition);
+ try f.copyCValue(new_local, init_condition);
try w.print("zig_switch_{d}_loop:", .{@intFromEnum(inst)});
- try f.object.newline();
+ try f.newline();
try f.loop_switch_conds.put(gpa, inst, new_local.new_local);
break :cond new_local;
} else init_condition;
@@ -5294,9 +4495,9 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void
try f.renderType(w, lowered_condition_ty);
try w.writeByte(')');
}
- try f.writeCValue(w, condition, .Other);
+ try f.writeCValue(w, condition, .other);
try w.writeAll(") {");
- f.object.indent();
+ f.indent();
const liveness = try f.liveness.getSwitchBr(gpa, inst, switch_br.cases_len + 1);
defer gpa.free(liveness.deaths);
@@ -5309,7 +4510,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void
continue;
}
for (case.items) |item| {
- try f.object.newline();
+ try f.newline();
try w.writeAll("case ");
const item_value = try f.air.value(item, pt);
// If `item_value` is a pointer with a known integer address, print the address
@@ -5326,28 +4527,28 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void
try f.renderType(w, .usize);
try w.writeByte(')');
}
- try f.object.dg.renderValue(w, (try f.air.value(item, pt)).?, .Other);
+ try f.dg.renderValue(w, (try f.air.value(item, pt)).?, .other);
}
try w.writeByte(':');
}
try w.writeAll(" {");
- f.object.indent();
- try f.object.newline();
+ f.indent();
+ try f.newline();
if (is_dispatch_loop) {
try w.print("zig_switch_{d}_dispatch_{d}:;", .{ @intFromEnum(inst), case.idx });
- try f.object.newline();
+ try f.newline();
}
try genBodyResolveState(f, inst, liveness.deaths[case.idx], case.body, true);
- try f.object.outdent();
+ try f.outdent();
try w.writeByte('}');
- if (f.object.dg.expected_block) |_|
+ if (f.dg.expected_block) |_|
return f.fail("runtime code not allowed in naked function", .{});
// The case body must be noreturn so we don't need to insert a break.
}
const else_body = it.elseBody();
- try f.object.newline();
+ try f.newline();
try w.writeAll("default: ");
if (any_range_cases) {
@@ -5360,33 +4561,33 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void
try w.writeAll("if (");
for (case.items, 0..) |item, item_i| {
if (item_i != 0) try w.writeAll(" || ");
- try f.writeCValue(w, condition, .Other);
+ try f.writeCValue(w, condition, .other);
try w.writeAll(" == ");
- try f.object.dg.renderValue(w, (try f.air.value(item, pt)).?, .Other);
+ try f.dg.renderValue(w, (try f.air.value(item, pt)).?, .other);
}
for (case.ranges, 0..) |range, range_i| {
if (case.items.len != 0 or range_i != 0) try w.writeAll(" || ");
// "(x >= lower && x <= upper)"
try w.writeByte('(');
- try f.writeCValue(w, condition, .Other);
+ try f.writeCValue(w, condition, .other);
try w.writeAll(" >= ");
- try f.object.dg.renderValue(w, (try f.air.value(range[0], pt)).?, .Other);
+ try f.dg.renderValue(w, (try f.air.value(range[0], pt)).?, .other);
try w.writeAll(" && ");
- try f.writeCValue(w, condition, .Other);
+ try f.writeCValue(w, condition, .other);
try w.writeAll(" <= ");
- try f.object.dg.renderValue(w, (try f.air.value(range[1], pt)).?, .Other);
+ try f.dg.renderValue(w, (try f.air.value(range[1], pt)).?, .other);
try w.writeByte(')');
}
try w.writeAll(") {");
- f.object.indent();
- try f.object.newline();
+ f.indent();
+ try f.newline();
if (is_dispatch_loop) {
try w.print("zig_switch_{d}_dispatch_{d}: ", .{ @intFromEnum(inst), case.idx });
}
try genBodyResolveState(f, inst, liveness.deaths[case.idx], case.body, true);
- try f.object.outdent();
+ try f.outdent();
try w.writeByte('}');
- if (f.object.dg.expected_block) |_|
+ if (f.dg.expected_block) |_|
return f.fail("runtime code not allowed in naked function", .{});
}
}
@@ -5400,16 +4601,16 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index, is_dispatch_loop: bool) !void
try die(f, inst, death.toRef());
}
try genBody(f, else_body);
- if (f.object.dg.expected_block) |_|
+ if (f.dg.expected_block) |_|
return f.fail("runtime code not allowed in naked function", .{});
- } else try airUnreach(&f.object);
- try f.object.newline();
- try f.object.outdent();
+ } else try airUnreach(f);
+ try f.newline();
+ try f.outdent();
try w.writeAll("}\n");
}
fn asmInputNeedsLocal(f: *Function, constraint: []const u8, value: CValue) bool {
- const dg = f.object.dg;
+ const dg = f.dg;
const target = &dg.mod.resolved_target.result;
return switch (constraint[0]) {
'{' => true,
@@ -5429,28 +4630,28 @@ fn asmInputNeedsLocal(f: *Function, constraint: []const u8, value: CValue) bool
}
fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const unwrapped_asm = f.air.unwrapAsm(inst);
const is_volatile = unwrapped_asm.is_volatile;
- const gpa = f.object.dg.gpa;
+ const gpa = f.dg.gpa;
const outputs = unwrapped_asm.outputs;
const inputs = unwrapped_asm.inputs;
const result = result: {
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const inst_ty = f.typeOfIndex(inst);
- const inst_local = if (inst_ty.hasRuntimeBitsIgnoreComptime(zcu)) local: {
+ const inst_local = if (inst_ty.hasRuntimeBits(zcu)) local: {
const inst_local = try f.allocLocalValue(.{
- .ctype = try f.ctypeFromType(inst_ty, .complete),
- .alignas = CType.AlignAs.fromAbiAlignment(inst_ty.abiAlignment(zcu)),
+ .type = inst_ty,
+ .alignment = .none,
});
if (f.wantSafety()) {
- try f.writeCValue(w, inst_local, .Other);
+ try f.writeCValue(w, inst_local, .other);
try w.writeAll(" = ");
- try f.writeCValue(w, .{ .undef = inst_ty }, .Other);
+ try f.writeCValue(w, .{ .undef = inst_ty }, .other);
try w.writeByte(';');
- try f.object.newline();
+ try f.newline();
}
break :local inst_local;
} else .none;
@@ -5471,20 +4672,20 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
const output_ty = if (output.operand == .none) inst_ty else f.typeOf(output.operand).childType(zcu);
try w.writeAll("register ");
const output_local = try f.allocLocalValue(.{
- .ctype = try f.ctypeFromType(output_ty, .complete),
- .alignas = CType.AlignAs.fromAbiAlignment(output_ty.abiAlignment(zcu)),
+ .type = output_ty,
+ .alignment = .none,
});
try f.allocs.put(gpa, output_local.new_local, false);
- try f.object.dg.renderTypeAndName(w, output_ty, output_local, .{}, .none, .complete);
+ try f.dg.renderTypeAndName(w, output_ty, output_local, .{}, .none);
try w.writeAll(" __asm(\"");
try w.writeAll(constraint["={".len .. constraint.len - "}".len]);
try w.writeAll("\")");
if (f.wantSafety()) {
try w.writeAll(" = ");
- try f.writeCValue(w, .{ .undef = output_ty }, .Other);
+ try f.writeCValue(w, .{ .undef = output_ty }, .other);
}
try w.writeByte(';');
- try f.object.newline();
+ try f.newline();
}
}
@@ -5504,29 +4705,29 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
const input_ty = f.typeOf(input.operand);
if (is_reg) try w.writeAll("register ");
const input_local = try f.allocLocalValue(.{
- .ctype = try f.ctypeFromType(input_ty, .complete),
- .alignas = CType.AlignAs.fromAbiAlignment(input_ty.abiAlignment(zcu)),
+ .type = input_ty,
+ .alignment = .none,
});
try f.allocs.put(gpa, input_local.new_local, false);
// Do not render the declaration as `const` qualified if we're generating an
// explicit `register` local, as GCC will ignore the constraint completely.
- try f.object.dg.renderTypeAndName(w, input_ty, input_local, if (is_reg) .{} else Const, .none, .complete);
+ try f.dg.renderTypeAndName(w, input_ty, input_local, .{ .@"const" = is_reg }, .none);
if (is_reg) {
try w.writeAll(" __asm(\"");
try w.writeAll(constraint["{".len .. constraint.len - "}".len]);
try w.writeAll("\")");
}
try w.writeAll(" = ");
- try f.writeCValue(w, input_val, .Other);
+ try f.writeCValue(w, input_val, .other);
try w.writeByte(';');
- try f.object.newline();
+ try f.newline();
}
}
{
const asm_source = unwrapped_asm.source;
- var stack = std.heap.stackFallback(256, f.object.dg.gpa);
+ var stack = std.heap.stackFallback(256, f.dg.gpa);
const allocator = stack.get();
const fixed_asm_source = try allocator.alloc(u8, asm_source.len);
defer allocator.free(fixed_asm_source);
@@ -5592,10 +4793,10 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
const is_reg = constraint[1] == '{';
try w.print("{f}(", .{fmtStringLiteral(if (is_reg) "=r" else constraint, null)});
if (is_reg) {
- try f.writeCValue(w, .{ .local = locals_index }, .Other);
+ try f.writeCValue(w, .{ .local = locals_index }, .other);
locals_index += 1;
} else if (output.operand == .none) {
- try f.writeCValue(w, inst_local, .FunctionArgument);
+ try f.writeCValue(w, inst_local, .other);
} else {
try f.writeCValueDeref(w, try f.resolveInst(output.operand));
}
@@ -5619,57 +4820,54 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
const input_local_idx = locals_index;
locals_index += 1;
break :local .{ .local = input_local_idx };
- } else input_val, .Other);
+ } else input_val, .other);
try w.writeByte(')');
}
try w.writeByte(':');
const ip = &zcu.intern_pool;
- const aggregate = ip.indexToKey(unwrapped_asm.clobbers).aggregate;
- const struct_type: Type = .fromInterned(aggregate.ty);
- switch (aggregate.storage) {
- .elems => |elems| for (elems, 0..) |elem, i| switch (elem) {
- .bool_true => {
- const field_name = struct_type.structFieldName(i, zcu).toSlice(ip).?;
- assert(field_name.len != 0);
+ const clobbers_val: Value = .fromInterned(unwrapped_asm.clobbers);
+ const clobbers_ty = clobbers_val.typeOf(zcu);
+ var clobbers_bigint_buf: Value.BigIntSpace = undefined;
+ const clobbers_bigint = clobbers_val.toBigInt(&clobbers_bigint_buf, zcu);
+ for (0..clobbers_ty.structFieldCount(zcu)) |field_index| {
+ assert(clobbers_ty.fieldType(field_index, zcu).toIntern() == .bool_type);
+ const limb_bits = @bitSizeOf(std.math.big.Limb);
+ if (field_index / limb_bits >= clobbers_bigint.limbs.len) continue; // field is false
+ switch (@as(u1, @truncate(clobbers_bigint.limbs[field_index / limb_bits] >> @intCast(field_index % limb_bits)))) {
+ 0 => continue, // field is false
+ 1 => {}, // field is true
+ }
+ const field_name = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?;
+ assert(field_name.len != 0);
- const target = &f.object.dg.mod.resolved_target.result;
- var c_name_buf: [16]u8 = undefined;
- const name =
- if ((target.cpu.arch.isMIPS() or target.cpu.arch == .alpha) and field_name[0] == 'r') name: {
- // Convert "rN" to "$N"
- const c_name = (&c_name_buf)[0..field_name.len];
- @memcpy(c_name, field_name);
- c_name_buf[0] = '$';
- break :name c_name;
- } else if ((target.cpu.arch.isMIPS() and (mem.startsWith(u8, field_name, "fcc") or field_name[0] == 'w')) or
- ((target.cpu.arch.isMIPS() or target.cpu.arch == .alpha) and field_name[0] == 'f') or
- (target.cpu.arch == .kvx and !mem.eql(u8, field_name, "memory"))) name: {
- // "$" prefix for these registers
- c_name_buf[0] = '$';
- @memcpy((&c_name_buf)[1..][0..field_name.len], field_name);
- break :name (&c_name_buf)[0 .. 1 + field_name.len];
- } else if (target.cpu.arch.isSPARC() and
- (mem.eql(u8, field_name, "ccr") or mem.eql(u8, field_name, "icc") or mem.eql(u8, field_name, "xcc"))) name: {
- // C compilers just use `icc` to encompass all of these.
- break :name "icc";
- } else field_name;
+ const target = &f.dg.mod.resolved_target.result;
+ var c_name_buf: [16]u8 = undefined;
+ const name =
+ if ((target.cpu.arch.isMIPS() or target.cpu.arch == .alpha) and field_name[0] == 'r') name: {
+ // Convert "rN" to "$N"
+ const c_name = (&c_name_buf)[0..field_name.len];
+ @memcpy(c_name, field_name);
+ c_name_buf[0] = '$';
+ break :name c_name;
+ } else if ((target.cpu.arch.isMIPS() and (mem.startsWith(u8, field_name, "fcc") or field_name[0] == 'w')) or
+ ((target.cpu.arch.isMIPS() or target.cpu.arch == .alpha) and field_name[0] == 'f') or
+ (target.cpu.arch == .kvx and !mem.eql(u8, field_name, "memory"))) name: {
+ // "$" prefix for these registers
+ c_name_buf[0] = '$';
+ @memcpy((&c_name_buf)[1..][0..field_name.len], field_name);
+ break :name (&c_name_buf)[0 .. 1 + field_name.len];
+ } else if (target.cpu.arch.isSPARC() and
+ (mem.eql(u8, field_name, "ccr") or mem.eql(u8, field_name, "icc") or mem.eql(u8, field_name, "xcc"))) name: {
+ // C compilers just use `icc` to encompass all of these.
+ break :name "icc";
+ } else field_name;
- try w.print(" {f}", .{fmtStringLiteral(name, null)});
- (try w.writableArray(1))[0] = ',';
- },
- .bool_false => continue,
- else => unreachable,
- },
- .repeated_elem => |elem| switch (elem) {
- .bool_true => @panic("TODO"),
- .bool_false => {},
- else => unreachable,
- },
- .bytes => @panic("TODO"),
+ try w.print(" {f}", .{fmtStringLiteral(name, null)});
+ (try w.writableArray(1))[0] = ',';
}
w.undo(1); // erase the last comma
try w.writeAll(");");
- try f.object.newline();
+ try f.newline();
locals_index = locals_begin;
it = unwrapped_asm.iterateOutputs();
@@ -5683,10 +4881,10 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
else
try f.resolveInst(output.operand));
try w.writeAll(" = ");
- try f.writeCValue(w, .{ .local = locals_index }, .Other);
+ try f.writeCValue(w, .{ .local = locals_index }, .other);
locals_index += 1;
try w.writeByte(';');
- try f.object.newline();
+ try f.newline();
}
}
@@ -5708,147 +4906,145 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
fn airIsNull(
f: *Function,
inst: Air.Inst.Index,
- operator: std.math.CompareOperator,
+ operator: enum { eq, neq },
is_ptr: bool,
) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
- const ctype_pool = &f.object.dg.ctype_pool;
const un_op = f.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const operand = try f.resolveInst(un_op);
try reap(f, inst, &.{un_op});
const local = try f.allocLocal(inst, .bool);
- const a = try Assignment.start(f, w, .bool);
- try f.writeCValue(w, local, .Other);
- try a.assign(f, w);
+ try f.writeCValue(w, local, .other);
+ try w.writeAll(" = ");
const operand_ty = f.typeOf(un_op);
const optional_ty = if (is_ptr) operand_ty.childType(zcu) else operand_ty;
- 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(w, operand)
- else
- try f.writeCValue(w, operand, .Other);
- break :rhs if (opt_ctype.isBool())
- "true"
- else if (opt_ctype.isInteger())
- "0"
- else
- "NULL";
+
+ const pre: []const u8, const maybe_field: ?[]const u8, const post: []const u8 = switch (operator) {
+ // zig fmt: off
+ .eq => switch (CType.classifyOptional(optional_ty, zcu)) {
+ .npv_payload => unreachable, // opv optional
+ .error_set => .{ "", null, " == 0" },
+ .ptr_like => .{ "", null, " == NULL" },
+ .slice_like => .{ "", "ptr", " == NULL" },
+ .opv_payload => .{ "", "is_null", "" },
+ .@"struct" => .{ "", "is_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(w, operand, .{ .identifier = "is_null" })
- else
- try f.writeCValueMember(w, operand, .{ .identifier = "is_null" });
- break :rhs "true";
- },
- .ptr, .len => rhs: {
- if (is_ptr)
- try f.writeCValueDerefMember(w, operand, .{ .identifier = "ptr" })
- else
- try f.writeCValueMember(w, operand, .{ .identifier = "ptr" });
- break :rhs "NULL";
- },
- else => unreachable,
+ .neq => switch (CType.classifyOptional(optional_ty, zcu)) {
+ .npv_payload => unreachable, // opv optional
+ .error_set => .{ "", null, " != 0" },
+ .ptr_like => .{ "", null, " != NULL" },
+ .slice_like => .{ "", "ptr", " != NULL" },
+ .opv_payload => .{ "!", "is_null", "" },
+ .@"struct" => .{ "!", "is_null", "" },
},
+ // zig fmt: on
};
- try w.writeAll(compareOperatorC(operator));
- try w.writeAll(rhs);
- try a.end(f, w);
+
+ try w.writeAll(pre);
+ if (maybe_field) |field| {
+ if (is_ptr) {
+ try f.writeCValueDerefMember(w, operand, .{ .identifier = field });
+ } else {
+ try f.writeCValueMember(w, operand, .{ .identifier = field });
+ }
+ } else {
+ if (is_ptr) {
+ try f.writeCValueDeref(w, operand);
+ } else {
+ try f.writeCValue(w, operand, .other);
+ }
+ }
+ try w.writeAll(post);
+
+ try w.writeByte(';');
+ try f.newline();
return local;
}
fn airOptionalPayload(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.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 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;
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 w = &f.object.code.writer;
- const local = try f.allocLocal(inst, inst_ty);
- const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete));
- try f.writeCValue(w, local, .Other);
- try a.assign(f, w);
- if (is_ptr) {
- try w.writeByte('&');
- try f.writeCValueDerefMember(w, operand, .{ .identifier = "payload" });
- } else try f.writeCValueMember(w, operand, .{ .identifier = "payload" });
- try a.end(f, w);
- return local;
- },
- .ptr, .len => return f.moveCValue(inst, inst_ty, operand),
- else => unreachable,
+
+ switch (CType.classifyOptional(opt_ty, zcu)) {
+ .npv_payload => unreachable, // opv optional
+
+ .opv_payload => return if (is_ptr) .{ .undef = inst_ty } else .none,
+
+ .error_set,
+ .ptr_like,
+ .slice_like,
+ => return f.moveCValue(inst, inst_ty, operand),
+
+ .@"struct" => {
+ const w = &f.code.writer;
+ const local = try f.allocLocal(inst, inst_ty);
+ try f.writeCValue(w, local, .other);
+ try w.writeAll(" = ");
+ if (is_ptr) {
+ try w.writeByte('&');
+ try f.writeCValueDerefMember(w, operand, .{ .identifier = "payload" });
+ } else try f.writeCValueMember(w, operand, .{ .identifier = "payload" });
+ try w.writeByte(';');
+ try f.newline();
+ return local;
},
}
}
fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const operand = try f.resolveInst(ty_op.operand);
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);
- 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, w, opt_ctype);
- try f.writeCValueDeref(w, operand);
- try a.assign(f, w);
- try f.object.dg.renderValue(w, Value.false, .Other);
- try a.end(f, w);
- return .none;
+
+ switch (CType.classifyOptional(opt_ty, zcu)) {
+ .npv_payload => unreachable, // opv optional
+
+ .opv_payload => {
+ try f.writeCValueDerefMember(w, operand, .{ .identifier = "is_null" });
+ try w.writeAll(" = ");
+ try f.dg.renderValue(w, .false, .other);
+ try w.writeByte(';');
+ try f.newline();
+ return .{ .undef = inst_ty };
},
- .pointer => {
+
+ .error_set,
+ .ptr_like,
+ .slice_like,
+ => return f.moveCValue(inst, inst_ty, operand),
+
+ .@"struct" => {
+ try f.writeCValueDerefMember(w, operand, .{ .identifier = "is_null" });
+ try w.writeAll(" = ");
+ try f.dg.renderValue(w, .false, .other);
+ try w.writeByte(';');
+ try f.newline();
if (f.liveness.isUnused(inst)) return .none;
const local = try f.allocLocal(inst, inst_ty);
- const a = try Assignment.start(f, w, opt_ctype);
- try f.writeCValue(w, local, .Other);
- try a.assign(f, w);
- try f.writeCValue(w, operand, .Other);
- try a.end(f, w);
- return local;
- },
- .aligned, .array, .vector, .fwd_decl, .function => unreachable,
- .aggregate => {
- {
- const a = try Assignment.start(f, w, opt_ctype);
- try f.writeCValueDerefMember(w, operand, .{ .identifier = "is_null" });
- try a.assign(f, w);
- try f.object.dg.renderValue(w, Value.false, .Other);
- try a.end(f, w);
- }
- if (f.liveness.isUnused(inst)) return .none;
- const local = try f.allocLocal(inst, inst_ty);
- const a = try Assignment.start(f, w, opt_ctype);
- try f.writeCValue(w, local, .Other);
- try a.assign(f, w);
- try w.writeByte('&');
+ try f.writeCValue(w, local, .other);
+ try w.writeAll(" = &");
try f.writeCValueDerefMember(w, operand, .{ .identifier = "payload" });
- try a.end(f, w);
+ try w.writeByte(';');
+ try f.newline();
return local;
},
}
@@ -5870,12 +5066,12 @@ fn fieldLocation(
.struct_type => {
const loaded_struct = ip.loadStructType(container_ty.toIntern());
return switch (loaded_struct.layout) {
- .auto, .@"extern" => if (!container_ty.hasRuntimeBitsIgnoreComptime(zcu))
+ .auto, .@"extern" => if (!container_ty.hasRuntimeBits(zcu))
.begin
- else if (!field_ptr_ty.childType(zcu).hasRuntimeBitsIgnoreComptime(zcu))
- .{ .byte_offset = loaded_struct.offsets.get(ip)[field_index] }
+ else if (!field_ptr_ty.childType(zcu).hasRuntimeBits(zcu))
+ .{ .byte_offset = loaded_struct.field_offsets.get(ip)[field_index] }
else
- .{ .field = .{ .identifier = loaded_struct.fieldName(ip, field_index).toSlice(ip) } },
+ .{ .field = .{ .identifier = loaded_struct.field_names.get(ip)[field_index].toSlice(ip) } },
.@"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) }
@@ -5883,27 +5079,29 @@ fn fieldLocation(
.begin,
};
},
- .tuple_type => return if (!container_ty.hasRuntimeBitsIgnoreComptime(zcu))
+ .tuple_type => return if (!container_ty.hasRuntimeBits(zcu))
.begin
- else if (!field_ptr_ty.childType(zcu).hasRuntimeBitsIgnoreComptime(zcu))
+ else if (!field_ptr_ty.childType(zcu).hasRuntimeBits(zcu))
.{ .byte_offset = container_ty.structFieldOffset(field_index, zcu) }
else
.{ .field = .{ .field = field_index } },
.union_type => {
const loaded_union = ip.loadUnionType(container_ty.toIntern());
- switch (loaded_union.flagsUnordered(ip).layout) {
- .auto, .@"extern" => {
+ switch (loaded_union.layout) {
+ .auto => {
const field_ty: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]);
- if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu))
- return if (loaded_union.hasTag(ip) and !container_ty.unionHasAllZeroBitFieldTypes(zcu))
- .{ .field = .{ .identifier = "payload" } }
- else
- .begin;
- const field_name = loaded_union.loadTagType(ip).names.get(ip)[field_index];
- return .{ .field = if (loaded_union.hasTag(ip))
- .{ .payload_identifier = field_name.toSlice(ip) }
- else
- .{ .identifier = field_name.toSlice(ip) } };
+ if (!field_ty.hasRuntimeBits(zcu)) {
+ if (container_ty.unionHasAllZeroBitFieldTypes(zcu)) return .begin;
+ return .{ .field = .{ .identifier = "payload" } };
+ }
+ const field_name = ip.loadEnumType(loaded_union.enum_tag_type).field_names.get(ip)[field_index];
+ return .{ .field = .{ .payload_identifier = field_name.toSlice(ip) } };
+ },
+ .@"extern" => {
+ const field_ty: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]);
+ if (!field_ty.hasRuntimeBits(zcu)) return .begin;
+ const field_name = ip.loadEnumType(loaded_union.enum_tag_type).field_names.get(ip)[field_index];
+ return .{ .field = .{ .identifier = field_name.toSlice(ip) } };
},
.@"packed" => return .begin,
}
@@ -5940,7 +5138,7 @@ fn airStructFieldPtrIndex(f: *Function, inst: Air.Inst.Index, index: u8) !CValue
}
fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = f.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
@@ -5952,26 +5150,26 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {
const field_ptr_val = try f.resolveInst(extra.field_ptr);
try reap(f, inst, &.{extra.field_ptr});
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, container_ptr_ty);
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try w.writeAll(" = (");
try f.renderType(w, container_ptr_ty);
try w.writeByte(')');
switch (fieldLocation(container_ptr_ty, field_ptr_ty, extra.field_index, zcu)) {
- .begin => try f.writeCValue(w, field_ptr_val, .Other),
+ .begin => try f.writeCValue(w, field_ptr_val, .other),
.field => |field| {
const u8_ptr_ty = try pt.adjustPtrTypeChild(field_ptr_ty, .u8);
try w.writeAll("((");
try f.renderType(w, u8_ptr_ty);
try w.writeByte(')');
- try f.writeCValue(w, field_ptr_val, .Other);
+ try f.writeCValue(w, field_ptr_val, .other);
try w.writeAll(" - offsetof(");
try f.renderType(w, container_ty);
try w.writeAll(", ");
- try f.writeCValue(w, field, .Other);
+ try f.writeCValue(w, field, .other);
try w.writeAll("))");
},
.byte_offset => |byte_offset| {
@@ -5980,7 +5178,7 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {
try w.writeAll("((");
try f.renderType(w, u8_ptr_ty);
try w.writeByte(')');
- try f.writeCValue(w, field_ptr_val, .Other);
+ try f.writeCValue(w, field_ptr_val, .other);
try w.print(" - {f})", .{
try f.fmtIntLiteralDec(try pt.intValue(.usize, byte_offset)),
});
@@ -5988,7 +5186,7 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {
}
try w.writeByte(';');
- try f.object.newline();
+ try f.newline();
return local;
}
@@ -5999,23 +5197,19 @@ fn fieldPtr(
container_ptr_val: CValue,
field_index: u32,
) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
- const container_ty = container_ptr_ty.childType(zcu);
const field_ptr_ty = f.typeOfIndex(inst);
- // Ensure complete type definition is visible before accessing fields.
- _ = try f.ctypeFromType(container_ty, .complete);
-
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, field_ptr_ty);
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try w.writeAll(" = (");
try f.renderType(w, field_ptr_ty);
try w.writeByte(')');
switch (fieldLocation(container_ptr_ty, field_ptr_ty, field_index, zcu)) {
- .begin => try f.writeCValue(w, container_ptr_val, .Other),
+ .begin => try f.writeCValue(w, container_ptr_val, .other),
.field => |field| {
try w.writeByte('&');
try f.writeCValueDerefMember(w, container_ptr_val, field);
@@ -6026,7 +5220,7 @@ fn fieldPtr(
try w.writeAll("((");
try f.renderType(w, u8_ptr_ty);
try w.writeByte(')');
- try f.writeCValue(w, container_ptr_val, .Other);
+ try f.writeCValue(w, container_ptr_val, .other);
try w.print(" + {f})", .{
try f.fmtIntLiteralDec(try pt.intValue(.usize, byte_offset)),
});
@@ -6034,61 +5228,51 @@ fn fieldPtr(
}
try w.writeByte(';');
- try f.object.newline();
+ try f.newline();
return local;
}
fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = f.air.extraData(Air.StructField, ty_pl.payload).data;
const inst_ty = f.typeOfIndex(inst);
- if (!inst_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
- try reap(f, inst, &.{extra.struct_operand});
- return .none;
- }
+ assert(inst_ty.hasRuntimeBits(zcu));
const struct_byval = try f.resolveInst(extra.struct_operand);
try reap(f, inst, &.{extra.struct_operand});
const struct_ty = f.typeOf(extra.struct_operand);
- const w = &f.object.code.writer;
-
- // Ensure complete type definition is visible before accessing fields.
- _ = try f.ctypeFromType(struct_ty, .complete);
+ const w = &f.code.writer;
assert(struct_ty.containerLayout(zcu) != .@"packed"); // `Air.Legalize.Feature.expand_packed_struct_field_val` handles this case
const field_name: CValue = switch (ip.indexToKey(struct_ty.toIntern())) {
.struct_type => .{ .identifier = struct_ty.structFieldName(extra.field_index, zcu).unwrap().?.toSlice(ip) },
.union_type => name: {
const union_type = ip.loadUnionType(struct_ty.toIntern());
- const enum_tag_ty: Type = .fromInterned(union_type.enum_tag_ty);
+ const enum_tag_ty: Type = .fromInterned(union_type.enum_tag_type);
const field_name_str = enum_tag_ty.enumFieldName(extra.field_index, zcu).toSlice(ip);
- if (union_type.hasTag(ip)) {
- break :name .{ .payload_identifier = field_name_str };
- } else {
- break :name .{ .identifier = field_name_str };
- }
+ break :name .{ .payload_identifier = field_name_str };
},
.tuple_type => .{ .field = extra.field_index },
else => unreachable,
};
const local = try f.allocLocal(inst, inst_ty);
- const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete));
- try f.writeCValue(w, local, .Other);
- try a.assign(f, w);
+ try f.writeCValue(w, local, .other);
+ try w.writeAll(" = ");
try f.writeCValueMember(w, struct_byval, field_name);
- try a.end(f, w);
+ try w.writeByte(';');
+ try f.newline();
return local;
}
/// *(E!T) -> E
/// Note that the result is never a pointer.
fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
@@ -6098,37 +5282,23 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
try reap(f, inst, &.{ty_op.operand});
const operand_is_ptr = operand_ty.zigTypeTag(zcu) == .pointer;
- const error_union_ty = if (operand_is_ptr) operand_ty.childType(zcu) else operand_ty;
- const error_ty = error_union_ty.errorUnionSet(zcu);
- const payload_ty = error_union_ty.errorUnionPayload(zcu);
const local = try f.allocLocal(inst, inst_ty);
- if (!payload_ty.hasRuntimeBits(zcu) and operand == .local and operand.local == local.new_local) {
- // The store will be 'x = x'; elide it.
- return local;
- }
-
- const w = &f.object.code.writer;
- try f.writeCValue(w, local, .Other);
+ const w = &f.code.writer;
+ try f.writeCValue(w, local, .other);
try w.writeAll(" = ");
- if (!payload_ty.hasRuntimeBits(zcu))
- try f.writeCValue(w, operand, .Other)
- else if (error_ty.errorSetIsEmpty(zcu))
- try w.print("{f}", .{
- try f.fmtIntLiteralDec(try pt.intValue(try pt.errorIntType(), 0)),
- })
- else if (operand_is_ptr)
+ if (operand_is_ptr)
try f.writeCValueDerefMember(w, operand, .{ .identifier = "error" })
else
try f.writeCValueMember(w, operand, .{ .identifier = "error" });
try w.writeByte(';');
- try f.object.newline();
+ try f.newline();
return local;
}
fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
@@ -6138,154 +5308,124 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu
const operand_ty = f.typeOf(ty_op.operand);
const error_union_ty = if (is_ptr) operand_ty.childType(zcu) else operand_ty;
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
if (!error_union_ty.errorUnionPayload(zcu).hasRuntimeBits(zcu)) {
- if (!is_ptr) return .none;
-
+ assert(is_ptr); // opv bug in sema
const local = try f.allocLocal(inst, inst_ty);
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try w.writeAll(" = (");
try f.renderType(w, inst_ty);
try w.writeByte(')');
- try f.writeCValue(w, operand, .Other);
+ try f.writeCValue(w, operand, .other);
try w.writeByte(';');
- try f.object.newline();
+ try f.newline();
return local;
}
const local = try f.allocLocal(inst, inst_ty);
- const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete));
- try f.writeCValue(w, local, .Other);
- try a.assign(f, w);
+ try f.writeCValue(w, local, .other);
+ try w.writeAll(" = ");
if (is_ptr) {
try w.writeByte('&');
try f.writeCValueDerefMember(w, operand, .{ .identifier = "payload" });
} else try f.writeCValueMember(w, operand, .{ .identifier = "payload" });
- try a.end(f, w);
+ try w.writeByte(';');
+ try f.newline();
return local;
}
fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
- const ctype_pool = &f.object.dg.ctype_pool;
+ const zcu = f.dg.pt.zcu;
const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
const inst_ty = f.typeOfIndex(inst);
- const inst_ctype = try f.ctypeFromType(inst_ty, .complete);
- if (inst_ctype.isBool()) return .{ .constant = Value.true };
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 w = &f.object.code.writer;
- const local = try f.allocLocal(inst, inst_ty);
- {
- const a = try Assignment.start(f, w, .bool);
- try f.writeCValueMember(w, local, .{ .identifier = "is_null" });
- try a.assign(f, w);
- try w.writeAll("false");
- try a.end(f, w);
- }
- {
- const a = try Assignment.start(f, w, operand_ctype);
- try f.writeCValueMember(w, local, .{ .identifier = "payload" });
- try a.assign(f, w);
- try f.writeCValue(w, operand, .Other);
- try a.end(f, w);
- }
- return local;
- },
- .ptr, .len => return f.moveCValue(inst, inst_ty, operand),
- else => unreachable,
+
+ switch (CType.classifyOptional(inst_ty, zcu)) {
+ .npv_payload => unreachable, // opv optional
+
+ .opv_payload => unreachable, // opv bug in Sema
+
+ .error_set,
+ .ptr_like,
+ .slice_like,
+ => return f.moveCValue(inst, inst_ty, operand),
+
+ .@"struct" => {
+ const w = &f.code.writer;
+ const local = try f.allocLocal(inst, inst_ty);
+
+ try f.writeCValueMember(w, local, .{ .identifier = "is_null" });
+ try w.writeAll(" = false;");
+ try f.newline();
+
+ try f.writeCValueMember(w, local, .{ .identifier = "payload" });
+ try w.writeAll(" = ");
+ try f.writeCValue(w, operand, .other);
+ try w.writeByte(';');
+ try f.newline();
+
+ return local;
},
}
}
fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
const inst_ty = f.typeOfIndex(inst);
const payload_ty = inst_ty.errorUnionPayload(zcu);
- const repr_is_err = !payload_ty.hasRuntimeBitsIgnoreComptime(zcu);
- const err_ty = inst_ty.errorUnionSet(zcu);
const err = try f.resolveInst(ty_op.operand);
try reap(f, inst, &.{ty_op.operand});
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
- if (repr_is_err and err == .local and err.local == local.new_local) {
- // The store will be 'x = x'; elide it.
- return local;
- }
-
- if (!repr_is_err) {
- const a = try Assignment.start(f, w, try f.ctypeFromType(payload_ty, .complete));
+ if (payload_ty.hasRuntimeBits(zcu)) {
try f.writeCValueMember(w, local, .{ .identifier = "payload" });
- try a.assign(f, w);
- try f.object.dg.renderUndefValue(w, payload_ty, .Other);
- try a.end(f, w);
- }
- {
- const a = try Assignment.start(f, w, try f.ctypeFromType(err_ty, .complete));
- if (repr_is_err)
- try f.writeCValue(w, local, .Other)
- else
- try f.writeCValueMember(w, local, .{ .identifier = "error" });
- try a.assign(f, w);
- try f.writeCValue(w, err, .Other);
- try a.end(f, w);
+ try w.writeAll(" = ");
+ try f.dg.renderUndefValue(w, payload_ty, .other);
+ try w.writeByte(';');
+ try f.newline();
}
+
+ try f.writeCValueMember(w, local, .{ .identifier = "error" });
+ try w.writeAll(" = ");
+ try f.writeCValue(w, err, .other);
+ try w.writeByte(';');
+ try f.newline();
+
return local;
}
fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
- const zcu = pt.zcu;
- const w = &f.object.code.writer;
+ const pt = f.dg.pt;
+ const w = &f.code.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 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 pt.errorIntType();
const no_err = try pt.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, w, try f.ctypeFromType(operand_ty, .complete));
- try f.writeCValueDeref(w, operand);
- try a.assign(f, w);
- try w.print("{f}", .{try f.fmtIntLiteralDec(no_err)});
- try a.end(f, w);
- return .none;
- }
- {
- const a = try Assignment.start(f, w, try f.ctypeFromType(err_int_ty, .complete));
- try f.writeCValueDerefMember(w, operand, .{ .identifier = "error" });
- try a.assign(f, w);
- try w.print("{f}", .{try f.fmtIntLiteralDec(no_err)});
- try a.end(f, w);
- }
+ try f.writeCValueDerefMember(w, operand, .{ .identifier = "error" });
+ try w.print(" = {f};", .{try f.fmtIntLiteralDec(no_err)});
+ try f.newline();
// Then return the payload pointer (only if it is used)
if (f.liveness.isUnused(inst)) return .none;
const local = try f.allocLocal(inst, inst_ty);
- const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete));
- try f.writeCValue(w, local, .Other);
- try a.assign(f, w);
- try w.writeByte('&');
+ try f.writeCValue(w, local, .other);
+ try w.writeAll(" = &");
try f.writeCValueDerefMember(w, operand, .{ .identifier = "payload" });
- try a.end(f, w);
+ try w.writeByte(';');
+ try f.newline();
return local;
}
@@ -6305,131 +5445,96 @@ fn airSaveErrReturnTraceIndex(f: *Function, inst: Air.Inst.Index) !CValue {
}
fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
const inst_ty = f.typeOfIndex(inst);
const payload_ty = inst_ty.errorUnionPayload(zcu);
const payload = try f.resolveInst(ty_op.operand);
- const repr_is_err = !payload_ty.hasRuntimeBitsIgnoreComptime(zcu);
- const err_ty = inst_ty.errorUnionSet(zcu);
+ assert(payload_ty.hasRuntimeBits(zcu));
try reap(f, inst, &.{ty_op.operand});
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
- if (!repr_is_err) {
- const a = try Assignment.start(f, w, try f.ctypeFromType(payload_ty, .complete));
- try f.writeCValueMember(w, local, .{ .identifier = "payload" });
- try a.assign(f, w);
- try f.writeCValue(w, payload, .Other);
- try a.end(f, w);
- }
- {
- const a = try Assignment.start(f, w, try f.ctypeFromType(err_ty, .complete));
- if (repr_is_err)
- try f.writeCValue(w, local, .Other)
- else
- try f.writeCValueMember(w, local, .{ .identifier = "error" });
- try a.assign(f, w);
- try f.object.dg.renderValue(w, try pt.intValue(try pt.errorIntType(), 0), .Other);
- try a.end(f, w);
- }
+
+ try f.writeCValueMember(w, local, .{ .identifier = "payload" });
+ try w.writeAll(" = ");
+ try f.writeCValue(w, payload, .other);
+ try w.writeByte(';');
+ try f.newline();
+
+ try f.writeCValueMember(w, local, .{ .identifier = "error" });
+ try w.writeAll(" = ");
+ try f.dg.renderValue(w, try pt.intValue(try pt.errorIntType(), 0), .other);
+ try w.writeByte(';');
+ try f.newline();
+
return local;
}
fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const u8) !CValue {
- const pt = f.object.dg.pt;
- const zcu = pt.zcu;
+ const pt = f.dg.pt;
const un_op = f.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const operand = try f.resolveInst(un_op);
try reap(f, inst, &.{un_op});
- const operand_ty = f.typeOf(un_op);
const local = try f.allocLocal(inst, .bool);
- const err_union_ty = if (is_ptr) operand_ty.childType(zcu) else operand_ty;
- const payload_ty = err_union_ty.errorUnionPayload(zcu);
- const error_ty = err_union_ty.errorUnionSet(zcu);
- const a = try Assignment.start(f, w, .bool);
- try f.writeCValue(w, local, .Other);
- try a.assign(f, w);
+ try f.writeCValue(w, local, .other);
+ try w.writeAll(" = ");
const err_int_ty = try pt.errorIntType();
- if (!error_ty.errorSetIsEmpty(zcu))
- if (payload_ty.hasRuntimeBits(zcu))
- if (is_ptr)
- try f.writeCValueDerefMember(w, operand, .{ .identifier = "error" })
- else
- try f.writeCValueMember(w, operand, .{ .identifier = "error" })
- else
- try f.writeCValue(w, operand, .Other)
+ if (is_ptr)
+ try f.writeCValueDerefMember(w, operand, .{ .identifier = "error" })
else
- try f.object.dg.renderValue(w, try pt.intValue(err_int_ty, 0), .Other);
- try w.writeByte(' ');
- try w.writeAll(operator);
- try w.writeByte(' ');
- try f.object.dg.renderValue(w, try pt.intValue(err_int_ty, 0), .Other);
- try a.end(f, w);
+ try f.writeCValueMember(w, operand, .{ .identifier = "error" });
+ try w.print(" {s} ", .{operator});
+ try f.dg.renderValue(w, try pt.intValue(err_int_ty, 0), .other);
+ try w.writeByte(';');
+ try f.newline();
return local;
}
fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
- const ctype_pool = &f.object.dg.ctype_pool;
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 inst_ty = f.typeOfIndex(inst);
- const ptr_ty = inst_ty.slicePtrFieldType(zcu);
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
const operand_ty = f.typeOf(ty_op.operand);
const array_ty = operand_ty.childType(zcu);
- {
- const a = try Assignment.start(f, w, try f.ctypeFromType(ptr_ty, .complete));
- try f.writeCValueMember(w, local, .{ .identifier = "ptr" });
- try a.assign(f, w);
- if (operand == .undef) {
- try f.writeCValue(w, .{ .undef = inst_ty.slicePtrFieldType(zcu) }, .Other);
- } else {
- const ptr_ctype = try f.ctypeFromType(ptr_ty, .complete);
- const ptr_child_ctype = ptr_ctype.info(ctype_pool).pointer.elem_ctype;
- const elem_ty = array_ty.childType(zcu);
- const elem_ctype = try f.ctypeFromType(elem_ty, .complete);
- if (!ptr_child_ctype.eql(elem_ctype)) {
- try w.writeByte('(');
- try f.renderCType(w, ptr_ctype);
- try w.writeByte(')');
- }
- const operand_ctype = try f.ctypeFromType(operand_ty, .complete);
- const operand_child_ctype = operand_ctype.info(ctype_pool).pointer.elem_ctype;
- if (operand_child_ctype.info(ctype_pool) == .array) {
- try w.writeByte('&');
- try f.writeCValueDeref(w, operand);
- try w.print("[{f}]", .{try f.fmtIntLiteralDec(.zero_usize)});
- } else try f.writeCValue(w, operand, .Other);
- }
- try a.end(f, w);
- }
- {
- const a = try Assignment.start(f, w, .usize);
- try f.writeCValueMember(w, local, .{ .identifier = "len" });
- try a.assign(f, w);
- try w.print("{f}", .{
- try f.fmtIntLiteralDec(try pt.intValue(.usize, array_ty.arrayLen(zcu))),
- });
- try a.end(f, w);
- }
+ // We have a `*[n]T`, which was turned into to a pointer to `struct { T array[n]; }`.
+ // Ideally we would want to use 'operand->array' to convert to a `T *` (we get a `T []`
+ // which decays to a pointer), but if the element type is zero-bit or the array length is
+ // zero, there will not be an `array` member (the array type lowers to `void`). We cannot
+ // check the type layout here because it may not be resolved, so in this instance, we must
+ // use a pointer cast.
+ try f.writeCValueMember(w, local, .{ .identifier = "ptr" });
+ try w.writeAll(" = (");
+ try f.dg.renderType(w, inst_ty.slicePtrFieldType(zcu));
+ try w.writeByte(')');
+ try f.writeCValue(w, operand, .other);
+ try w.writeByte(';');
+ try f.newline();
+
+ try f.writeCValueMember(w, local, .{ .identifier = "len" });
+ try w.print(" = {f}", .{
+ try f.fmtIntLiteralDec(try pt.intValue(.usize, array_ty.arrayLen(zcu))),
+ });
+ try w.writeByte(';');
+ try f.newline();
return local;
}
fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
@@ -6439,7 +5544,7 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {
try reap(f, inst, &.{ty_op.operand});
const operand_ty = f.typeOf(ty_op.operand);
const scalar_ty = operand_ty.scalarType(zcu);
- const target = &f.object.dg.mod.resolved_target.result;
+ const target = &f.dg.mod.resolved_target.result;
const operation = if (inst_scalar_ty.isRuntimeFloat() and scalar_ty.isRuntimeFloat())
if (inst_scalar_ty.floatBits(target) < scalar_ty.floatBits(target)) "trunc" else "extend"
else if (inst_scalar_ty.isInt(zcu) and scalar_ty.isRuntimeFloat())
@@ -6449,16 +5554,15 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {
else
unreachable;
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
const v = try Vectorize.start(f, inst, w, operand_ty);
- const a = try Assignment.start(f, w, try f.ctypeFromType(scalar_ty, .complete));
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try v.elem(f, w);
- try a.assign(f, w);
+ try w.writeAll(" = ");
if (inst_scalar_ty.isInt(zcu) and scalar_ty.isRuntimeFloat()) {
try w.writeAll("zig_wrap_");
- try f.object.dg.renderTypeForBuiltinFnName(w, inst_scalar_ty);
+ try f.dg.renderTypeForBuiltinFnName(w, inst_scalar_ty);
try w.writeByte('(');
}
try w.writeAll("zig_");
@@ -6466,14 +5570,15 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {
try w.writeAll(compilerRtAbbrev(scalar_ty, zcu, target));
try w.writeAll(compilerRtAbbrev(inst_scalar_ty, zcu, target));
try w.writeByte('(');
- try f.writeCValue(w, operand, .FunctionArgument);
+ try f.writeCValue(w, operand, .other);
try v.elem(f, w);
try w.writeByte(')');
if (inst_scalar_ty.isInt(zcu) and scalar_ty.isRuntimeFloat()) {
- try f.object.dg.renderBuiltinInfo(w, inst_scalar_ty, .bits);
+ try f.dg.renderBuiltinInfo(w, inst_scalar_ty, .bits);
try w.writeByte(')');
}
- try a.end(f, w);
+ try w.writeByte(';');
+ try f.newline();
try v.end(f, inst, w);
return local;
@@ -6486,7 +5591,7 @@ fn airUnBuiltinCall(
operation: []const u8,
info: BuiltinInfo,
) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const operand = try f.resolveInst(operand_ref);
@@ -6496,30 +5601,32 @@ fn airUnBuiltinCall(
const operand_ty = f.typeOf(operand_ref);
const scalar_ty = operand_ty.scalarType(zcu);
- const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete);
- const ref_ret = inst_scalar_ctype.info(&f.object.dg.ctype_pool) == .array;
+ const ref_ret = lowersToBigInt(inst_scalar_ty, zcu);
+ const ref_arg = lowersToBigInt(scalar_ty, zcu);
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
const v = try Vectorize.start(f, inst, w, operand_ty);
if (!ref_ret) {
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try v.elem(f, w);
try w.writeAll(" = ");
}
try w.print("zig_{s}_", .{operation});
- try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty);
+ try f.dg.renderTypeForBuiltinFnName(w, scalar_ty);
try w.writeByte('(');
if (ref_ret) {
- try f.writeCValue(w, local, .FunctionArgument);
+ try w.writeByte('&');
+ try f.writeCValue(w, local, .other);
try v.elem(f, w);
try w.writeAll(", ");
}
- try f.writeCValue(w, operand, .FunctionArgument);
+ if (ref_arg) try w.writeByte('&');
+ try f.writeCValue(w, operand, .other);
try v.elem(f, w);
- try f.object.dg.renderBuiltinInfo(w, scalar_ty, info);
+ try f.dg.renderBuiltinInfo(w, scalar_ty, info);
try w.writeAll(");");
- try f.object.newline();
+ try f.newline();
try v.end(f, inst, w);
return local;
@@ -6531,13 +5638,12 @@ fn airBinBuiltinCall(
operation: []const u8,
info: BuiltinInfo,
) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const bin_op = f.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
const operand_ty = f.typeOf(bin_op.lhs);
- const operand_ctype = try f.ctypeFromType(operand_ty, .complete);
- const is_big = operand_ctype.info(&f.object.dg.ctype_pool) == .array;
+ const is_big = lowersToBigInt(operand_ty, zcu);
const lhs = try f.resolveInst(bin_op.lhs);
const rhs = try f.resolveInst(bin_op.rhs);
@@ -6547,32 +5653,35 @@ fn airBinBuiltinCall(
const inst_scalar_ty = inst_ty.scalarType(zcu);
const scalar_ty = operand_ty.scalarType(zcu);
- const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete);
- const ref_ret = inst_scalar_ctype.info(&f.object.dg.ctype_pool) == .array;
+ const ref_ret = lowersToBigInt(inst_scalar_ty, zcu);
+ const ref_arg = lowersToBigInt(scalar_ty, zcu);
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
if (is_big) try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
const v = try Vectorize.start(f, inst, w, operand_ty);
if (!ref_ret) {
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try v.elem(f, w);
try w.writeAll(" = ");
}
try w.print("zig_{s}_", .{operation});
- try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty);
+ try f.dg.renderTypeForBuiltinFnName(w, scalar_ty);
try w.writeByte('(');
if (ref_ret) {
- try f.writeCValue(w, local, .FunctionArgument);
+ try w.writeByte('&');
+ try f.writeCValue(w, local, .other);
try v.elem(f, w);
try w.writeAll(", ");
}
- try f.writeCValue(w, lhs, .FunctionArgument);
+ if (ref_arg) try w.writeByte('&');
+ try f.writeCValue(w, lhs, .other);
try v.elem(f, w);
try w.writeAll(", ");
- try f.writeCValue(w, rhs, .FunctionArgument);
+ if (ref_arg) try w.writeByte('&');
+ try f.writeCValue(w, rhs, .other);
if (f.typeOf(bin_op.rhs).isVector(zcu)) try v.elem(f, w);
- try f.object.dg.renderBuiltinInfo(w, scalar_ty, info);
+ try f.dg.renderBuiltinInfo(w, scalar_ty, info);
try w.writeAll(");\n");
try v.end(f, inst, w);
@@ -6587,7 +5696,7 @@ fn airCmpBuiltinCall(
operation: enum { cmp, operator },
info: BuiltinInfo,
) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const lhs = try f.resolveInst(data.lhs);
const rhs = try f.resolveInst(data.rhs);
@@ -6598,14 +5707,14 @@ fn airCmpBuiltinCall(
const operand_ty = f.typeOf(data.lhs);
const scalar_ty = operand_ty.scalarType(zcu);
- const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete);
- const ref_ret = inst_scalar_ctype.info(&f.object.dg.ctype_pool) == .array;
+ const ref_ret = lowersToBigInt(inst_scalar_ty, zcu);
+ const ref_arg = lowersToBigInt(scalar_ty, zcu);
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
const v = try Vectorize.start(f, inst, w, operand_ty);
if (!ref_ret) {
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try v.elem(f, w);
try w.writeAll(" = ");
}
@@ -6613,33 +5722,36 @@ fn airCmpBuiltinCall(
else => @tagName(operation),
.operator => compareOperatorAbbrev(operator),
}});
- try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty);
+ try f.dg.renderTypeForBuiltinFnName(w, scalar_ty);
try w.writeByte('(');
if (ref_ret) {
- try f.writeCValue(w, local, .FunctionArgument);
+ try w.writeByte('&');
+ try f.writeCValue(w, local, .other);
try v.elem(f, w);
try w.writeAll(", ");
}
- try f.writeCValue(w, lhs, .FunctionArgument);
+ if (ref_arg) try w.writeByte('&');
+ try f.writeCValue(w, lhs, .other);
try v.elem(f, w);
try w.writeAll(", ");
- try f.writeCValue(w, rhs, .FunctionArgument);
+ if (ref_arg) try w.writeByte('&');
+ try f.writeCValue(w, rhs, .other);
try v.elem(f, w);
- try f.object.dg.renderBuiltinInfo(w, scalar_ty, info);
+ try f.dg.renderBuiltinInfo(w, scalar_ty, info);
try w.writeByte(')');
if (!ref_ret) try w.print("{s}{f}", .{
compareOperatorC(operator),
try f.fmtIntLiteralDec(try pt.intValue(.i32, 0)),
});
try w.writeByte(';');
- try f.object.newline();
+ try f.newline();
try v.end(f, inst, w);
return local;
}
fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = f.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
@@ -6649,9 +5761,8 @@ 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 w = &f.object.code.writer;
+ const w = &f.code.writer;
const new_value_mat = try Materialize.start(f, inst, ty, new_value);
try reap(f, inst, &.{ extra.ptr, extra.expected_value, extra.new_value });
@@ -6662,13 +5773,11 @@ 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, w, ctype);
- try f.writeCValue(w, local, .Other);
- try a.assign(f, w);
- try f.writeCValue(w, expected_value, .Other);
- try a.end(f, w);
- }
+ try f.writeCValue(w, local, .other);
+ try w.writeAll(" = ");
+ try f.writeCValue(w, expected_value, .other);
+ try w.writeByte(';');
+ try f.newline();
try w.writeAll("if (");
try w.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor});
@@ -6676,9 +5785,9 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
try w.writeByte(')');
if (ptr_ty.isVolatilePtr(zcu)) try w.writeAll(" volatile");
try w.writeAll(" *)");
- try f.writeCValue(w, ptr, .Other);
+ try f.writeCValue(w, ptr, .other);
try w.writeAll(", ");
- try f.writeCValue(w, local, .FunctionArgument);
+ try f.writeCValue(w, local, .other);
try w.writeAll(", ");
try new_value_mat.mat(f, w);
try w.writeAll(", ");
@@ -6686,56 +5795,49 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
try w.writeAll(", ");
try writeMemoryOrder(w, extra.failureOrder());
try w.writeAll(", ");
- try f.object.dg.renderTypeForBuiltinFnName(w, ty);
+ try f.dg.renderTypeForBuiltinFnName(w, ty);
try w.writeAll(", ");
try f.renderType(w, repr_ty);
try w.writeByte(')');
try w.writeAll(") {");
- f.object.indent();
- try f.object.newline();
- {
- const a = try Assignment.start(f, w, ctype);
- try f.writeCValue(w, local, .Other);
- try a.assign(f, w);
- try w.writeAll("NULL");
- try a.end(f, w);
- }
- try f.object.outdent();
+ f.indent();
+ try f.newline();
+
+ try f.writeCValue(w, local, .other);
+ try w.writeAll(" = NULL;");
+ try f.newline();
+
+ try f.outdent();
try w.writeByte('}');
- try f.object.newline();
+ try f.newline();
} else {
- {
- const a = try Assignment.start(f, w, ctype);
- try f.writeCValueMember(w, local, .{ .identifier = "payload" });
- try a.assign(f, w);
- try f.writeCValue(w, expected_value, .Other);
- try a.end(f, w);
- }
- {
- const a = try Assignment.start(f, w, .bool);
- try f.writeCValueMember(w, local, .{ .identifier = "is_null" });
- try a.assign(f, w);
- try w.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor});
- try f.renderType(w, ty);
- try w.writeByte(')');
- if (ptr_ty.isVolatilePtr(zcu)) try w.writeAll(" volatile");
- try w.writeAll(" *)");
- try f.writeCValue(w, ptr, .Other);
- try w.writeAll(", ");
- try f.writeCValueMember(w, local, .{ .identifier = "payload" });
- try w.writeAll(", ");
- try new_value_mat.mat(f, w);
- try w.writeAll(", ");
- try writeMemoryOrder(w, extra.successOrder());
- try w.writeAll(", ");
- try writeMemoryOrder(w, extra.failureOrder());
- try w.writeAll(", ");
- try f.object.dg.renderTypeForBuiltinFnName(w, ty);
- try w.writeAll(", ");
- try f.renderType(w, repr_ty);
- try w.writeByte(')');
- try a.end(f, w);
- }
+ try f.writeCValueMember(w, local, .{ .identifier = "payload" });
+ try w.writeAll(" = ");
+ try f.writeCValue(w, expected_value, .other);
+ try w.writeByte(';');
+ try f.newline();
+
+ try f.writeCValueMember(w, local, .{ .identifier = "is_null" });
+ try w.print(" = zig_cmpxchg_{s}((zig_atomic(", .{flavor});
+ try f.renderType(w, ty);
+ try w.writeByte(')');
+ if (ptr_ty.isVolatilePtr(zcu)) try w.writeAll(" volatile");
+ try w.writeAll(" *)");
+ try f.writeCValue(w, ptr, .other);
+ try w.writeAll(", ");
+ try f.writeCValueMember(w, local, .{ .identifier = "payload" });
+ try w.writeAll(", ");
+ try new_value_mat.mat(f, w);
+ try w.writeAll(", ");
+ try writeMemoryOrder(w, extra.successOrder());
+ try w.writeAll(", ");
+ try writeMemoryOrder(w, extra.failureOrder());
+ try w.writeAll(", ");
+ try f.dg.renderTypeForBuiltinFnName(w, ty);
+ try w.writeAll(", ");
+ try f.renderType(w, repr_ty);
+ try w.writeAll(");");
+ try f.newline();
}
try new_value_mat.end(f, inst);
@@ -6748,7 +5850,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
}
fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const pl_op = f.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
const extra = f.air.extraData(Air.AtomicRmw, pl_op.payload).data;
@@ -6758,7 +5860,7 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {
const ptr = try f.resolveInst(pl_op.operand);
const operand = try f.resolveInst(extra.operand);
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const operand_mat = try Materialize.start(f, inst, ty, operand);
try reap(f, inst, &.{ pl_op.operand, extra.operand });
@@ -6771,7 +5873,7 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {
try w.print("zig_atomicrmw_{s}", .{toAtomicRmwSuffix(extra.op())});
if (is_float) try w.writeAll("_float") else if (is_128) try w.writeAll("_int128");
try w.writeByte('(');
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try w.writeAll(", (");
const use_atomic = switch (extra.op()) {
else => true,
@@ -6783,17 +5885,17 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {
if (use_atomic) try w.writeByte(')');
if (ptr_ty.isVolatilePtr(zcu)) try w.writeAll(" volatile");
try w.writeAll(" *)");
- try f.writeCValue(w, ptr, .Other);
+ try f.writeCValue(w, ptr, .other);
try w.writeAll(", ");
try operand_mat.mat(f, w);
try w.writeAll(", ");
try writeMemoryOrder(w, extra.ordering());
try w.writeAll(", ");
- try f.object.dg.renderTypeForBuiltinFnName(w, ty);
+ try f.dg.renderTypeForBuiltinFnName(w, ty);
try w.writeAll(", ");
try f.renderType(w, repr_ty);
try w.writeAll(");");
- try f.object.newline();
+ try f.newline();
try operand_mat.end(f, inst);
if (f.liveness.isUnused(inst)) {
@@ -6805,7 +5907,7 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {
}
fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const atomic_load = f.air.instructions.items(.data)[@intFromEnum(inst)].atomic_load;
const ptr = try f.resolveInst(atomic_load.ptr);
@@ -6819,31 +5921,31 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {
ty;
const inst_ty = f.typeOfIndex(inst);
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
try w.writeAll("zig_atomic_load(");
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try w.writeAll(", (zig_atomic(");
try f.renderType(w, ty);
try w.writeByte(')');
if (ptr_ty.isVolatilePtr(zcu)) try w.writeAll(" volatile");
try w.writeAll(" *)");
- try f.writeCValue(w, ptr, .Other);
+ try f.writeCValue(w, ptr, .other);
try w.writeAll(", ");
try writeMemoryOrder(w, atomic_load.order);
try w.writeAll(", ");
- try f.object.dg.renderTypeForBuiltinFnName(w, ty);
+ try f.dg.renderTypeForBuiltinFnName(w, ty);
try w.writeAll(", ");
try f.renderType(w, repr_ty);
try w.writeAll(");");
- try f.object.newline();
+ try f.newline();
return local;
}
fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const bin_op = f.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
const ptr_ty = f.typeOf(bin_op.lhs);
@@ -6851,7 +5953,7 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa
const ptr = try f.resolveInst(bin_op.lhs);
const element = try f.resolveInst(bin_op.rhs);
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const element_mat = try Materialize.start(f, inst, ty, element);
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
@@ -6865,32 +5967,22 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa
try w.writeByte(')');
if (ptr_ty.isVolatilePtr(zcu)) try w.writeAll(" volatile");
try w.writeAll(" *)");
- try f.writeCValue(w, ptr, .Other);
+ try f.writeCValue(w, ptr, .other);
try w.writeAll(", ");
try element_mat.mat(f, w);
try w.print(", {s}, ", .{order});
- try f.object.dg.renderTypeForBuiltinFnName(w, ty);
+ try f.dg.renderTypeForBuiltinFnName(w, ty);
try w.writeAll(", ");
try f.renderType(w, repr_ty);
try w.writeAll(");");
- try f.object.newline();
+ try f.newline();
try element_mat.end(f, inst);
return .none;
}
-fn writeSliceOrPtr(f: *Function, w: *Writer, ptr: CValue, ptr_ty: Type) !void {
- const pt = f.object.dg.pt;
- const zcu = pt.zcu;
- if (ptr_ty.isSlice(zcu)) {
- try f.writeCValueMember(w, ptr, .{ .identifier = "ptr" });
- } else {
- try f.writeCValue(w, ptr, .FunctionArgument);
- }
-}
-
fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const bin_op = f.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
const dest_ty = f.typeOf(bin_op.lhs);
@@ -6899,7 +5991,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
const elem_ty = f.typeOf(bin_op.rhs);
const elem_abi_size = elem_ty.abiSize(zcu);
const val_is_undef = if (try f.air.value(bin_op.rhs, pt)) |val| val.isUndef(zcu) else false;
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
if (val_is_undef) {
if (!safety) {
@@ -6913,153 +6005,128 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
try f.writeCValueMember(w, dest_slice, .{ .identifier = "ptr" });
try w.writeAll(", 0xaa, ");
try f.writeCValueMember(w, dest_slice, .{ .identifier = "len" });
- if (elem_abi_size > 1) {
- try w.print(" * {d}", .{elem_abi_size});
- }
- try w.writeAll(");");
- try f.object.newline();
},
.one => {
- const array_ty = dest_ty.childType(zcu);
- const len = array_ty.arrayLen(zcu) * elem_abi_size;
-
- try f.writeCValue(w, dest_slice, .FunctionArgument);
- try w.print(", 0xaa, {d});", .{len});
- try f.object.newline();
+ try f.writeCValue(w, dest_slice, .other);
+ try w.print(", 0xaa, {d}", .{dest_ty.childType(zcu).arrayLen(zcu)});
},
.many, .c => unreachable,
}
+ if (elem_abi_size > 0) try w.print(" * {d}", .{elem_abi_size});
+ try w.writeAll(");");
+ try f.newline();
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
return .none;
}
- if (elem_abi_size > 1 or dest_ty.isVolatilePtr(zcu)) {
- // For the assignment in this loop, the array pointer needs to get
- // casted to a regular pointer, otherwise an error like this occurs:
- // error: array type 'uint32_t[20]' (aka 'unsigned int[20]') is not assignable
- const elem_ptr_ty = try pt.ptrType(.{
- .child = elem_ty.toIntern(),
- .flags = .{
- .size = .c,
- },
- });
-
- const index = try f.allocLocal(inst, .usize);
-
- try w.writeAll("for (");
- try f.writeCValue(w, index, .Other);
- try w.writeAll(" = ");
- try f.object.dg.renderValue(w, .zero_usize, .Other);
- try w.writeAll("; ");
- try f.writeCValue(w, index, .Other);
- try w.writeAll(" != ");
+ if (elem_abi_size == 1 and !dest_ty.isVolatilePtr(zcu)) {
+ const bitcasted = try bitcast(f, .u8, value, elem_ty);
+ try w.writeAll("memset(");
switch (dest_ty.ptrSize(zcu)) {
.slice => {
+ try f.writeCValueMember(w, dest_slice, .{ .identifier = "ptr" });
+ try w.writeAll(", ");
+ try f.writeCValue(w, bitcasted, .other);
+ try w.writeAll(", ");
try f.writeCValueMember(w, dest_slice, .{ .identifier = "len" });
},
.one => {
- const array_ty = dest_ty.childType(zcu);
- try w.print("{d}", .{array_ty.arrayLen(zcu)});
+ try f.writeCValue(w, dest_slice, .other);
+ try w.writeAll(", ");
+ try f.writeCValue(w, bitcasted, .other);
+ try w.print(", {d}", .{dest_ty.childType(zcu).arrayLen(zcu)});
},
.many, .c => unreachable,
}
- try w.writeAll("; ++");
- try f.writeCValue(w, index, .Other);
- try w.writeAll(") ");
-
- const a = try Assignment.start(f, w, try f.ctypeFromType(elem_ty, .complete));
- try w.writeAll("((");
- try f.renderType(w, elem_ptr_ty);
- try w.writeByte(')');
- try writeSliceOrPtr(f, w, dest_slice, dest_ty);
- try w.writeAll(")[");
- try f.writeCValue(w, index, .Other);
- try w.writeByte(']');
- try a.assign(f, w);
- try f.writeCValue(w, value, .Other);
- try a.end(f, w);
-
+ try w.writeAll(");");
+ try f.newline();
+ try f.freeCValue(inst, bitcasted);
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
- try freeLocal(f, inst, index.new_local, null);
-
return .none;
}
- const bitcasted = try bitcast(f, .u8, value, elem_ty);
+ // Fallback path: use a `for` loop.
- try w.writeAll("memset(");
+ const index = try f.allocLocal(inst, .usize);
+
+ try w.writeAll("for (");
+ try f.writeCValue(w, index, .other);
+ try w.writeAll(" = ");
+ try f.dg.renderValue(w, .zero_usize, .other);
+ try w.writeAll("; ");
+ try f.writeCValue(w, index, .other);
+ try w.writeAll(" != ");
switch (dest_ty.ptrSize(zcu)) {
- .slice => {
- try f.writeCValueMember(w, dest_slice, .{ .identifier = "ptr" });
- try w.writeAll(", ");
- try f.writeCValue(w, bitcasted, .FunctionArgument);
- try w.writeAll(", ");
- try f.writeCValueMember(w, dest_slice, .{ .identifier = "len" });
- try w.writeAll(");");
- try f.object.newline();
- },
- .one => {
- const array_ty = dest_ty.childType(zcu);
- const len = array_ty.arrayLen(zcu) * elem_abi_size;
+ .slice => try f.writeCValueMember(w, dest_slice, .{ .identifier = "len" }),
+ .one => try w.print("{d}", .{dest_ty.childType(zcu).arrayLen(zcu)}),
+ .many, .c => unreachable,
+ }
+ try w.writeAll("; ++");
+ try f.writeCValue(w, index, .other);
+ try w.writeAll(") ");
- try f.writeCValue(w, dest_slice, .FunctionArgument);
- try w.writeAll(", ");
- try f.writeCValue(w, bitcasted, .FunctionArgument);
- try w.print(", {d});", .{len});
- try f.object.newline();
- },
+ switch (dest_ty.ptrSize(zcu)) {
+ .slice => try f.writeCValueMember(w, dest_slice, .{ .identifier = "ptr" }),
+ .one => try f.writeCValueDerefMember(w, dest_slice, .{ .identifier = "array" }),
.many, .c => unreachable,
}
- try f.freeCValue(inst, bitcasted);
+ try w.writeByte('[');
+ try f.writeCValue(w, index, .other);
+ try w.writeAll("] = ");
+ try f.writeCValue(w, value, .other);
+ try w.writeByte(';');
+ try f.newline();
+
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
+ try freeLocal(f, inst, index.new_local, null);
+
return .none;
}
fn airMemcpy(f: *Function, inst: Air.Inst.Index, function_paren: []const u8) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const bin_op = f.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
const dest_ptr = try f.resolveInst(bin_op.lhs);
const src_ptr = try f.resolveInst(bin_op.rhs);
const dest_ty = f.typeOf(bin_op.lhs);
const src_ty = f.typeOf(bin_op.rhs);
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
if (dest_ty.ptrSize(zcu) != .one) {
try w.writeAll("if (");
- try writeArrayLen(f, dest_ptr, dest_ty);
+ try f.writeCValueMember(w, dest_ptr, .{ .identifier = "len" });
try w.writeAll(" != 0) ");
}
try w.writeAll(function_paren);
- try writeSliceOrPtr(f, w, dest_ptr, dest_ty);
+ switch (dest_ty.ptrSize(zcu)) {
+ .slice => try f.writeCValueMember(w, dest_ptr, .{ .identifier = "ptr" }),
+ .one => try f.writeCValueDerefMember(w, dest_ptr, .{ .identifier = "array" }),
+ .many, .c => unreachable,
+ }
try w.writeAll(", ");
- try writeSliceOrPtr(f, w, src_ptr, src_ty);
+ switch (src_ty.ptrSize(zcu)) {
+ .slice => try f.writeCValueMember(w, src_ptr, .{ .identifier = "ptr" }),
+ .one => try f.writeCValueDerefMember(w, src_ptr, .{ .identifier = "array" }),
+ .many, .c => try f.writeCValue(w, src_ptr, .other),
+ }
try w.writeAll(", ");
- try writeArrayLen(f, dest_ptr, dest_ty);
+ switch (dest_ty.ptrSize(zcu)) {
+ .slice => try f.writeCValueMember(w, dest_ptr, .{ .identifier = "len" }),
+ .one => try w.print("{d}", .{dest_ty.childType(zcu).arrayLen(zcu)}),
+ .many, .c => unreachable,
+ }
try w.writeAll(" * sizeof(");
- try f.renderType(w, dest_ty.elemType2(zcu));
+ try f.renderType(w, dest_ty.indexableElem(zcu));
try w.writeAll("));");
- try f.object.newline();
+ try f.newline();
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
return .none;
}
-fn writeArrayLen(f: *Function, dest_ptr: CValue, dest_ty: Type) !void {
- const pt = f.object.dg.pt;
- const zcu = pt.zcu;
- const w = &f.object.code.writer;
- switch (dest_ty.ptrSize(zcu)) {
- .one => try w.print("{f}", .{
- try f.fmtIntLiteralDec(try pt.intValue(.usize, dest_ty.childType(zcu).arrayLen(zcu))),
- }),
- .many, .c => unreachable,
- .slice => try f.writeCValueMember(w, dest_ptr, .{ .identifier = "len" }),
- }
-}
-
fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const bin_op = f.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
const union_ptr = try f.resolveInst(bin_op.lhs);
@@ -7069,19 +6136,18 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
const union_ty = f.typeOf(bin_op.lhs).childType(zcu);
const layout = union_ty.unionGetLayout(zcu);
if (layout.tag_size == 0) return .none;
- const tag_ty = union_ty.unionTagTypeSafety(zcu).?;
- const w = &f.object.code.writer;
- const a = try Assignment.start(f, w, try f.ctypeFromType(tag_ty, .complete));
+ const w = &f.code.writer;
try f.writeCValueDerefMember(w, union_ptr, .{ .identifier = "tag" });
- try a.assign(f, w);
- try f.writeCValue(w, new_tag, .Other);
- try a.end(f, w);
+ try w.writeAll(" = ");
+ try f.writeCValue(w, new_tag, .other);
+ try w.writeByte(';');
+ try f.newline();
return .none;
}
fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
@@ -7093,17 +6159,20 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
if (layout.tag_size == 0) return .none;
const inst_ty = f.typeOfIndex(inst);
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
- const a = try Assignment.start(f, w, try f.ctypeFromType(inst_ty, .complete));
- try f.writeCValue(w, local, .Other);
- try a.assign(f, w);
+ try f.writeCValue(w, local, .other);
+ try w.writeAll(" = ");
try f.writeCValueMember(w, operand, .{ .identifier = "tag" });
- try a.end(f, w);
+ try w.writeByte(';');
+ try f.newline();
return local;
}
fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
+ const zcu = f.dg.pt.zcu;
+ const ip = &zcu.intern_pool;
+ const gpa = zcu.comp.gpa;
const un_op = f.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const inst_ty = f.typeOfIndex(inst);
@@ -7111,15 +6180,17 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
const operand = try f.resolveInst(un_op);
try reap(f, inst, &.{un_op});
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
- try f.writeCValue(w, local, .Other);
- try w.print(" = {s}(", .{
- try f.getLazyFnName(.{ .tag_name = enum_ty.toIntern() }),
+ try f.writeCValue(w, local, .other);
+ try f.need_tag_name_funcs.put(gpa, enum_ty.toIntern(), {});
+ try w.print(" = zig_tagName_{f}__{d}(", .{
+ fmtIdentUnsolo(enum_ty.containerTypeName(ip).toSlice(ip)),
+ @intFromEnum(enum_ty.toIntern()),
});
- try f.writeCValue(w, operand, .Other);
+ try f.writeCValue(w, operand, .other);
try w.writeAll(");");
- try f.object.newline();
+ try f.newline();
return local;
}
@@ -7127,40 +6198,37 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue {
const un_op = f.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const inst_ty = f.typeOfIndex(inst);
const operand = try f.resolveInst(un_op);
try reap(f, inst, &.{un_op});
const local = try f.allocLocal(inst, inst_ty);
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try w.writeAll(" = zig_errorName[");
- try f.writeCValue(w, operand, .Other);
+ try f.writeCValue(w, operand, .other);
try w.writeAll(" - 1];");
- try f.object.newline();
+ try f.newline();
return local;
}
fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
- const zcu = pt.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 inst_ty = f.typeOfIndex(inst);
- const inst_scalar_ty = inst_ty.scalarType(zcu);
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
const v = try Vectorize.start(f, inst, w, inst_ty);
- const a = try Assignment.start(f, w, try f.ctypeFromType(inst_scalar_ty, .complete));
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try v.elem(f, w);
- try a.assign(f, w);
- try f.writeCValue(w, operand, .Other);
- try a.end(f, w);
+ try w.writeAll(" = ");
+ try f.writeCValue(w, operand, .other);
+ try w.writeByte(';');
+ try f.newline();
try v.end(f, inst, w);
return local;
@@ -7177,29 +6245,29 @@ fn airSelect(f: *Function, inst: Air.Inst.Index) !CValue {
const inst_ty = f.typeOfIndex(inst);
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
const v = try Vectorize.start(f, inst, w, inst_ty);
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try v.elem(f, w);
try w.writeAll(" = ");
- try f.writeCValue(w, pred, .Other);
+ try f.writeCValue(w, pred, .other);
try v.elem(f, w);
try w.writeAll(" ? ");
- try f.writeCValue(w, lhs, .Other);
+ try f.writeCValue(w, lhs, .other);
try v.elem(f, w);
try w.writeAll(" : ");
- try f.writeCValue(w, rhs, .Other);
+ try f.writeCValue(w, rhs, .other);
try v.elem(f, w);
try w.writeByte(';');
- try f.object.newline();
+ try f.newline();
try v.end(f, inst, w);
return local;
}
fn airShuffleOne(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const unwrapped = f.air.unwrapShuffleOne(zcu, inst);
@@ -7207,22 +6275,22 @@ fn airShuffleOne(f: *Function, inst: Air.Inst.Index) !CValue {
const operand = try f.resolveInst(unwrapped.operand);
const inst_ty = unwrapped.result_ty;
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
try reap(f, inst, &.{unwrapped.operand}); // local cannot alias operand
for (mask, 0..) |mask_elem, out_idx| {
- try f.writeCValue(w, local, .Other);
+ try f.writeCValueMember(w, local, .{ .identifier = "array" });
try w.writeByte('[');
- try f.object.dg.renderValue(w, try pt.intValue(.usize, out_idx), .Other);
+ try f.dg.renderValue(w, try pt.intValue(.usize, out_idx), .other);
try w.writeAll("] = ");
switch (mask_elem.unwrap()) {
.elem => |src_idx| {
- try f.writeCValue(w, operand, .Other);
+ try f.writeCValueMember(w, operand, .{ .identifier = "array" });
try w.writeByte('[');
- try f.object.dg.renderValue(w, try pt.intValue(.usize, src_idx), .Other);
+ try f.dg.renderValue(w, try pt.intValue(.usize, src_idx), .other);
try w.writeByte(']');
},
- .value => |val| try f.object.dg.renderValue(w, .fromInterned(val), .Other),
+ .value => |val| try f.dg.renderValue(w, .fromInterned(val), .other),
}
try w.writeAll(";\n");
}
@@ -7231,7 +6299,7 @@ fn airShuffleOne(f: *Function, inst: Air.Inst.Index) !CValue {
}
fn airShuffleTwo(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const unwrapped = f.air.unwrapShuffleTwo(zcu, inst);
@@ -7241,38 +6309,38 @@ fn airShuffleTwo(f: *Function, inst: Air.Inst.Index) !CValue {
const inst_ty = unwrapped.result_ty;
const elem_ty = inst_ty.childType(zcu);
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
try reap(f, inst, &.{ unwrapped.operand_a, unwrapped.operand_b }); // local cannot alias operands
for (mask, 0..) |mask_elem, out_idx| {
- try f.writeCValue(w, local, .Other);
+ try f.writeCValueMember(w, local, .{ .identifier = "array" });
try w.writeByte('[');
- try f.object.dg.renderValue(w, try pt.intValue(.usize, out_idx), .Other);
+ try f.dg.renderValue(w, try pt.intValue(.usize, out_idx), .other);
try w.writeAll("] = ");
switch (mask_elem.unwrap()) {
.a_elem => |src_idx| {
- try f.writeCValue(w, operand_a, .Other);
+ try f.writeCValueMember(w, operand_a, .{ .identifier = "array" });
try w.writeByte('[');
- try f.object.dg.renderValue(w, try pt.intValue(.usize, src_idx), .Other);
+ try f.dg.renderValue(w, try pt.intValue(.usize, src_idx), .other);
try w.writeByte(']');
},
.b_elem => |src_idx| {
- try f.writeCValue(w, operand_b, .Other);
+ try f.writeCValueMember(w, operand_b, .{ .identifier = "array" });
try w.writeByte('[');
- try f.object.dg.renderValue(w, try pt.intValue(.usize, src_idx), .Other);
+ try f.dg.renderValue(w, try pt.intValue(.usize, src_idx), .other);
try w.writeByte(']');
},
- .undef => try f.object.dg.renderUndefValue(w, elem_ty, .Other),
+ .undef => try f.dg.renderUndefValue(w, elem_ty, .other),
}
try w.writeByte(';');
- try f.object.newline();
+ try f.newline();
}
return local;
}
fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const reduce = f.air.instructions.items(.data)[@intFromEnum(inst)].reduce;
@@ -7280,7 +6348,7 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
const operand = try f.resolveInst(reduce.operand);
try reap(f, inst, &.{reduce.operand});
const operand_ty = f.typeOf(reduce.operand);
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const use_operator = scalar_ty.bitSize(zcu) <= 64;
const op: union(enum) {
@@ -7327,10 +6395,10 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
// }
const accum = try f.allocLocal(inst, scalar_ty);
- try f.writeCValue(w, accum, .Other);
+ try f.writeCValue(w, accum, .other);
try w.writeAll(" = ");
- try f.object.dg.renderValue(w, switch (reduce.operation) {
+ try f.dg.renderValue(w, switch (reduce.operation) {
.Or, .Xor => switch (scalar_ty.zigTypeTag(zcu)) {
.bool => Value.false,
.int => try pt.intValue(scalar_ty, 0),
@@ -7366,58 +6434,58 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
.float => try pt.floatValue(scalar_ty, std.math.nan(f128)),
else => unreachable,
},
- }, .Other);
+ }, .other);
try w.writeByte(';');
- try f.object.newline();
+ try f.newline();
const v = try Vectorize.start(f, inst, w, operand_ty);
- try f.writeCValue(w, accum, .Other);
+ try f.writeCValue(w, accum, .other);
switch (op) {
.builtin => |func| {
try w.print(" = zig_{s}_", .{func.operation});
- try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty);
+ try f.dg.renderTypeForBuiltinFnName(w, scalar_ty);
try w.writeByte('(');
- try f.writeCValue(w, accum, .FunctionArgument);
+ try f.writeCValue(w, accum, .other);
try w.writeAll(", ");
- try f.writeCValue(w, operand, .Other);
+ try f.writeCValue(w, operand, .other);
try v.elem(f, w);
- try f.object.dg.renderBuiltinInfo(w, scalar_ty, func.info);
+ try f.dg.renderBuiltinInfo(w, scalar_ty, func.info);
try w.writeByte(')');
},
.infix => |ass| {
try w.writeAll(ass);
- try f.writeCValue(w, operand, .Other);
+ try f.writeCValue(w, operand, .other);
try v.elem(f, w);
},
.ternary => |cmp| {
try w.writeAll(" = ");
- try f.writeCValue(w, accum, .Other);
+ try f.writeCValue(w, accum, .other);
try w.writeAll(cmp);
- try f.writeCValue(w, operand, .Other);
+ try f.writeCValue(w, operand, .other);
try v.elem(f, w);
try w.writeAll(" ? ");
- try f.writeCValue(w, accum, .Other);
+ try f.writeCValue(w, accum, .other);
try w.writeAll(" : ");
- try f.writeCValue(w, operand, .Other);
+ try f.writeCValue(w, operand, .other);
try v.elem(f, w);
},
}
try w.writeByte(';');
- try f.object.newline();
+ try f.newline();
try v.end(f, inst, w);
return accum;
}
fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const inst_ty = f.typeOfIndex(inst);
const len: usize = @intCast(inst_ty.arrayLen(zcu));
const elements: []const Air.Inst.Ref = @ptrCast(f.air.extra.items[ty_pl.payload..][0..len]);
- const gpa = f.object.dg.gpa;
+ const gpa = f.dg.gpa;
const resolved_elements = try gpa.alloc(CValue, elements.len);
defer gpa.free(resolved_elements);
for (resolved_elements, elements) |*resolved_element, element| {
@@ -7430,28 +6498,23 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
}
}
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
switch (ip.indexToKey(inst_ty.toIntern())) {
inline .array_type, .vector_type => |info, tag| {
- const a: Assignment = .{
- .ctype = try f.ctypeFromType(.fromInterned(info.child), .complete),
- };
for (resolved_elements, 0..) |element, i| {
- try a.restart(f, w);
- try f.writeCValue(w, local, .Other);
- try w.print("[{d}]", .{i});
- try a.assign(f, w);
- try f.writeCValue(w, element, .Other);
- try a.end(f, w);
+ try f.writeCValueMember(w, local, .{ .identifier = "array" });
+ try w.print("[{d}] = ", .{i});
+ try f.writeCValue(w, element, .other);
+ try w.writeByte(';');
+ try f.newline();
}
if (tag == .array_type and info.sentinel != .none) {
- try a.restart(f, w);
- try f.writeCValue(w, local, .Other);
- try w.print("[{d}]", .{info.len});
- try a.assign(f, w);
- try f.object.dg.renderValue(w, Value.fromInterned(info.sentinel), .Other);
- try a.end(f, w);
+ try f.writeCValueMember(w, local, .{ .identifier = "array" });
+ try w.print("[{d}] = ", .{info.len});
+ try f.dg.renderValue(w, Value.fromInterned(info.sentinel), .other);
+ try w.writeByte(';');
+ try f.newline();
}
},
.struct_type => {
@@ -7461,13 +6524,13 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
var field_it = loaded_struct.iterateRuntimeOrder(ip);
while (field_it.next()) |field_index| {
const field_ty: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
- if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
+ if (!field_ty.hasRuntimeBits(zcu)) continue;
- const a = try Assignment.start(f, w, try f.ctypeFromType(field_ty, .complete));
- try f.writeCValueMember(w, local, .{ .identifier = loaded_struct.fieldName(ip, field_index).toSlice(ip) });
- try a.assign(f, w);
- try f.writeCValue(w, resolved_elements[field_index], .Other);
- try a.end(f, w);
+ try f.writeCValueMember(w, local, .{ .identifier = loaded_struct.field_names.get(ip)[field_index].toSlice(ip) });
+ try w.writeAll(" = ");
+ try f.writeCValue(w, resolved_elements[field_index], .other);
+ try w.writeByte(';');
+ try f.newline();
}
},
.@"packed" => unreachable, // `Air.Legalize.Feature.expand_packed_struct_init` handles this case
@@ -7476,13 +6539,13 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
.tuple_type => |tuple_info| for (0..tuple_info.types.len) |field_index| {
if (tuple_info.values.get(ip)[field_index] != .none) continue;
const field_ty: Type = .fromInterned(tuple_info.types.get(ip)[field_index]);
- if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
+ if (!field_ty.hasRuntimeBits(zcu)) continue;
- const a = try Assignment.start(f, w, try f.ctypeFromType(field_ty, .complete));
try f.writeCValueMember(w, local, .{ .field = field_index });
- try a.assign(f, w);
- try f.writeCValue(w, resolved_elements[field_index], .Other);
- try a.end(f, w);
+ try w.writeAll(" = ");
+ try f.writeCValue(w, resolved_elements[field_index], .other);
+ try w.writeByte(';');
+ try f.newline();
},
else => unreachable,
}
@@ -7491,49 +6554,52 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
}
fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const ty_pl = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = f.air.extraData(Air.UnionInit, ty_pl.payload).data;
+ const field_index = extra.field_index;
const union_ty = f.typeOfIndex(inst);
const loaded_union = ip.loadUnionType(union_ty.toIntern());
- const field_name = loaded_union.loadTagType(ip).names.get(ip)[extra.field_index];
- const payload_ty = f.typeOf(extra.init);
+ const loaded_enum = ip.loadEnumType(loaded_union.enum_tag_type);
+
const payload = try f.resolveInst(extra.init);
try reap(f, inst, &.{extra.init});
- const w = &f.object.code.writer;
- if (loaded_union.flagsUnordered(ip).layout == .@"packed") return f.moveCValue(inst, union_ty, payload);
+ const w = &f.code.writer;
+ if (loaded_union.layout == .@"packed") return f.moveCValue(inst, union_ty, payload);
const local = try f.allocLocal(inst, union_ty);
- const field: CValue = if (union_ty.unionTagTypeSafety(zcu)) |tag_ty| field: {
- const layout = union_ty.unionGetLayout(zcu);
- if (layout.tag_size != 0) {
- const field_index = tag_ty.enumFieldIndex(field_name, zcu).?;
- const tag_val = try pt.enumValueFieldIndex(tag_ty, field_index);
-
- const a = try Assignment.start(f, w, try f.ctypeFromType(tag_ty, .complete));
- try f.writeCValueMember(w, local, .{ .identifier = "tag" });
- try a.assign(f, w);
- try w.print("{f}", .{try f.fmtIntLiteralDec(try tag_val.intFromEnum(tag_ty, pt))});
- try a.end(f, w);
+ if (loaded_union.has_runtime_tag) {
+ try f.writeCValueMember(w, local, .{ .identifier = "tag" });
+ if (loaded_enum.field_values.len == 0) {
+ // auto-numbered
+ try w.print(" = {d};", .{field_index});
+ } else {
+ const tag_int_val: Value = .fromInterned(loaded_enum.field_values.get(ip)[field_index]);
+ try w.print(" = {f};", .{try f.fmtIntLiteralDec(tag_int_val)});
}
- break :field .{ .payload_identifier = field_name.toSlice(ip) };
- } else .{ .identifier = field_name.toSlice(ip) };
+ try f.newline();
+ }
- const a = try Assignment.start(f, w, try f.ctypeFromType(payload_ty, .complete));
- try f.writeCValueMember(w, local, field);
- try a.assign(f, w);
- try f.writeCValue(w, payload, .Other);
- try a.end(f, w);
+ const field_name_slice = loaded_enum.field_names.get(ip)[field_index].toSlice(ip);
+ switch (loaded_union.layout) {
+ .auto => try f.writeCValueMember(w, local, .{ .payload_identifier = field_name_slice }),
+ .@"extern" => try f.writeCValueMember(w, local, .{ .identifier = field_name_slice }),
+ .@"packed" => unreachable,
+ }
+ try w.writeAll(" = ");
+ try f.writeCValue(w, payload, .other);
+ try w.writeByte(';');
+ try f.newline();
return local;
}
fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const prefetch = f.air.instructions.items(.data)[@intFromEnum(inst)].prefetch;
@@ -7541,16 +6607,16 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {
const ptr = try f.resolveInst(prefetch.ptr);
try reap(f, inst, &.{prefetch.ptr});
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
switch (prefetch.cache) {
.data => {
try w.writeAll("zig_prefetch(");
if (ptr_ty.isSlice(zcu))
try f.writeCValueMember(w, ptr, .{ .identifier = "ptr" })
else
- try f.writeCValue(w, ptr, .FunctionArgument);
+ try f.writeCValue(w, ptr, .other);
try w.print(", {d}, {d});", .{ @intFromEnum(prefetch.rw), prefetch.locality });
- try f.object.newline();
+ try f.newline();
},
// The available prefetch intrinsics do not accept a cache argument; only
// address, rw, and locality.
@@ -7563,14 +6629,14 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {
fn airWasmMemorySize(f: *Function, inst: Air.Inst.Index) !CValue {
const pl_op = f.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const inst_ty = f.typeOfIndex(inst);
const local = try f.allocLocal(inst, inst_ty);
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try w.writeAll(" = ");
try w.print("zig_wasm_memory_size({d});", .{pl_op.payload});
- try f.object.newline();
+ try f.newline();
return local;
}
@@ -7578,23 +6644,23 @@ fn airWasmMemorySize(f: *Function, inst: Air.Inst.Index) !CValue {
fn airWasmMemoryGrow(f: *Function, inst: Air.Inst.Index) !CValue {
const pl_op = f.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const inst_ty = f.typeOfIndex(inst);
const operand = try f.resolveInst(pl_op.operand);
try reap(f, inst, &.{pl_op.operand});
const local = try f.allocLocal(inst, inst_ty);
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try w.writeAll(" = ");
try w.print("zig_wasm_memory_grow({d}, ", .{pl_op.payload});
- try f.writeCValue(w, operand, .FunctionArgument);
+ try f.writeCValue(w, operand, .other);
try w.writeAll(");");
- try f.object.newline();
+ try f.newline();
return local;
}
fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const pl_op = f.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
const bin_op = f.air.extraData(Air.Bin, pl_op.payload).data;
@@ -7607,24 +6673,24 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
const inst_ty = f.typeOfIndex(inst);
const inst_scalar_ty = inst_ty.scalarType(zcu);
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
const v = try Vectorize.start(f, inst, w, inst_ty);
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try v.elem(f, w);
try w.writeAll(" = zig_fma_");
- try f.object.dg.renderTypeForBuiltinFnName(w, inst_scalar_ty);
+ try f.dg.renderTypeForBuiltinFnName(w, inst_scalar_ty);
try w.writeByte('(');
- try f.writeCValue(w, mulend1, .FunctionArgument);
+ try f.writeCValue(w, mulend1, .other);
try v.elem(f, w);
try w.writeAll(", ");
- try f.writeCValue(w, mulend2, .FunctionArgument);
+ try f.writeCValue(w, mulend2, .other);
try v.elem(f, w);
try w.writeAll(", ");
- try f.writeCValue(w, addend, .FunctionArgument);
+ try f.writeCValue(w, addend, .other);
try v.elem(f, w);
try w.writeAll(");");
- try f.object.newline();
+ try f.newline();
try v.end(f, inst, w);
return local;
@@ -7632,34 +6698,33 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
fn airRuntimeNavPtr(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_nav = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, .fromInterned(ty_nav.ty));
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try w.writeAll(" = ");
- try f.object.dg.renderNav(w, ty_nav.nav, .Other);
+ try f.dg.renderNav(w, ty_nav.nav, .other);
try w.writeByte(';');
- try f.object.newline();
+ try f.newline();
return local;
}
fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
const inst_ty = f.typeOfIndex(inst);
- const function_ty = zcu.navValue(f.object.dg.pass.nav).typeOf(zcu);
- const function_info = (try f.ctypeFromType(function_ty, .complete)).info(&f.object.dg.ctype_pool).function;
- assert(function_info.varargs);
- const w = &f.object.code.writer;
+ assert(Value.fromInterned(f.func_index).typeOf(zcu).fnIsVarArgs(zcu));
+
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
try w.writeAll("va_start(*(va_list *)&");
- try f.writeCValue(w, local, .Other);
- if (function_info.param_ctypes.len > 0) {
+ try f.writeCValue(w, local, .other);
+ if (f.next_arg_index > 0) {
try w.writeAll(", ");
- try f.writeCValue(w, .{ .arg = function_info.param_ctypes.len - 1 }, .FunctionArgument);
+ try f.writeCValue(w, .{ .arg = f.next_arg_index - 1 }, .other);
}
try w.writeAll(");");
- try f.object.newline();
+ try f.newline();
return local;
}
@@ -7670,15 +6735,15 @@ fn airCVaArg(f: *Function, inst: Air.Inst.Index) !CValue {
const va_list = try f.resolveInst(ty_op.operand);
try reap(f, inst, &.{ty_op.operand});
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try w.writeAll(" = va_arg(*(va_list *)");
- try f.writeCValue(w, va_list, .Other);
+ try f.writeCValue(w, va_list, .other);
try w.writeAll(", ");
try f.renderType(w, ty_op.ty.toType());
try w.writeAll(");");
- try f.object.newline();
+ try f.newline();
return local;
}
@@ -7688,11 +6753,11 @@ fn airCVaEnd(f: *Function, inst: Air.Inst.Index) !CValue {
const va_list = try f.resolveInst(un_op);
try reap(f, inst, &.{un_op});
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
try w.writeAll("va_end(*(va_list *)");
- try f.writeCValue(w, va_list, .Other);
+ try f.writeCValue(w, va_list, .other);
try w.writeAll(");");
- try f.object.newline();
+ try f.newline();
return .none;
}
@@ -7703,14 +6768,14 @@ fn airCVaCopy(f: *Function, inst: Air.Inst.Index) !CValue {
const va_list = try f.resolveInst(ty_op.operand);
try reap(f, inst, &.{ty_op.operand});
- const w = &f.object.code.writer;
+ const w = &f.code.writer;
const local = try f.allocLocal(inst, inst_ty);
try w.writeAll("va_copy(*(va_list *)&");
- try f.writeCValue(w, local, .Other);
+ try f.writeCValue(w, local, .other);
try w.writeAll(", *(va_list *)");
- try f.writeCValue(w, va_list, .Other);
+ try f.writeCValue(w, va_list, .other);
try w.writeAll(");");
- try f.object.newline();
+ try f.newline();
return local;
}
@@ -8027,103 +7092,193 @@ fn undefPattern(comptime IntType: type) IntType {
const FormatIntLiteralContext = struct {
dg: *DeclGen,
- int_info: InternPool.Key.IntType,
- kind: CType.Kind,
- ctype: CType,
+ loc: ValueRenderLocation,
val: Value,
+ cty: CType,
base: u8,
case: std.fmt.Case,
};
fn formatIntLiteral(data: FormatIntLiteralContext, w: *Writer) Writer.Error!void {
- const pt = data.dg.pt;
- const zcu = pt.zcu;
- const target = &data.dg.mod.resolved_target.result;
- const ctype_pool = &data.dg.ctype_pool;
-
- const ExpectedContents = struct {
- const base = 10;
- const bits = 128;
- const limbs_count = BigInt.calcTwosCompLimbCount(bits);
-
- undef_limbs: [limbs_count]BigIntLimb,
- wrap_limbs: [limbs_count]BigIntLimb,
- to_string_buf: [bits]u8,
- to_string_limbs: [BigInt.calcToStringLimbsBufferLen(limbs_count, base)]BigIntLimb,
- };
- var stack align(@alignOf(ExpectedContents)) =
- std.heap.stackFallback(@sizeOf(ExpectedContents), data.dg.gpa);
- const allocator = stack.get();
-
- var undef_limbs: []BigIntLimb = &.{};
- defer allocator.free(undef_limbs);
-
- var int_buf: Value.BigIntSpace = undefined;
- const int = if (data.val.isUndef(zcu)) blk: {
- undef_limbs = allocator.alloc(BigIntLimb, BigInt.calcTwosCompLimbCount(data.int_info.bits)) catch return error.WriteFailed;
- @memset(undef_limbs, undefPattern(BigIntLimb));
-
- var undef_int = BigInt.Mutable{
- .limbs = undef_limbs,
- .len = undef_limbs.len,
- .positive = true,
- };
- undef_int.truncate(undef_int.toConst(), data.int_info.signedness, data.int_info.bits);
- break :blk undef_int.toConst();
- } else data.val.toBigInt(&int_buf, zcu);
- assert(int.fitsInTwosComp(data.int_info.signedness, data.int_info.bits));
-
- const c_bits: usize = @intCast(data.ctype.byteSize(ctype_pool, data.dg.mod) * 8);
- var one_limbs: [BigInt.calcLimbLen(1)]BigIntLimb = undefined;
- const one = BigInt.Mutable.init(&one_limbs, 1).toConst();
-
- var wrap = BigInt.Mutable{
- .limbs = allocator.alloc(BigIntLimb, BigInt.calcTwosCompLimbCount(c_bits)) catch return error.WriteFailed,
- .len = undefined,
- .positive = undefined,
- };
- defer allocator.free(wrap.limbs);
-
- const c_limb_info: struct {
- ctype: CType,
- count: usize,
- endian: std.builtin.Endian,
- homogeneous: bool,
- } = switch (data.ctype.info(ctype_pool)) {
- .basic => |basic_info| switch (basic_info) {
- else => .{
- .ctype = .void,
- .count = 1,
- .endian = .little,
- .homogeneous = true,
+ const dg = data.dg;
+ const zcu = dg.pt.zcu;
+ const target = &dg.mod.resolved_target.result;
+
+ const val = data.val;
+ const ty = val.typeOf(zcu);
+
+ assert(!val.isUndef(zcu));
+
+ var space: Value.BigIntSpace = undefined;
+ const val_bigint = val.toBigInt(&space, zcu);
+
+ switch (CType.classifyInt(ty, zcu)) {
+ .void => unreachable, // opv
+ .small => |int_cty| return FormatInt128.format(.{
+ .target = zcu.getTarget(),
+ .int_cty = int_cty,
+ .val = val_bigint,
+ .is_global = data.loc == .static_initializer,
+ .base = data.base,
+ .case = data.case,
+ }, w),
+ .big => |big| {
+ if (!data.loc.isInitializer()) {
+ // Use `CType.fmtTypeName` directly to avoid the possibility of `error.OutOfMemory`.
+ try w.print("({f})", .{data.cty.fmtTypeName(zcu)});
+ }
+
+ try w.writeAll("{{");
+
+ var limb_buf: [std.math.big.int.calcTwosCompLimbCount(65535)]std.math.big.Limb = undefined;
+ for (0..big.limbs_len) |limb_index| {
+ if (limb_index != 0) try w.writeAll(", ");
+ const limb_bit_offset: u16 = switch (target.cpu.arch.endian()) {
+ .little => @intCast(limb_index * big.limb_size.bits()),
+ .big => @intCast((big.limbs_len - limb_index - 1) * big.limb_size.bits()),
+ };
+ var limb_bigint: std.math.big.int.Mutable = .{
+ .limbs = &limb_buf,
+ .len = undefined,
+ .positive = undefined,
+ };
+ limb_bigint.shiftRight(val_bigint, limb_bit_offset);
+ limb_bigint.truncate(limb_bigint.toConst(), .unsigned, big.limb_size.bits());
+ try FormatInt128.format(.{
+ .target = zcu.getTarget(),
+ .int_cty = big.limb_size.unsigned(),
+ .val = limb_bigint.toConst(),
+ .is_global = data.loc == .static_initializer,
+ .base = data.base,
+ .case = data.case,
+ }, w);
+ }
+
+ try w.writeAll("}}");
+ },
+ }
+}
+const FormatInt128 = struct {
+ target: *const std.Target,
+ int_cty: CType.Int,
+ val: std.math.big.int.Const,
+ is_global: bool,
+ base: u8,
+ case: std.fmt.Case,
+ pub fn format(data: FormatInt128, w: *Writer) Writer.Error!void {
+ const target = data.target;
+
+ const val = data.val;
+ const is_global = data.is_global;
+ const base = data.base;
+ const case = data.case;
+
+ switch (data.int_cty) {
+ .uint8_t,
+ .uint16_t,
+ .uint32_t,
+ .uint64_t,
+ .@"unsigned short",
+ .@"unsigned int",
+ .@"unsigned long",
+ .@"unsigned long long",
+ .uintptr_t,
+ => |t| try w.print("{f}", .{
+ fmtUnsignedIntLiteralSmall(target, t, val.toInt(u64) catch unreachable, is_global, base, case),
+ }),
+
+ .int8_t,
+ .int16_t,
+ .int32_t,
+ .int64_t,
+ .char,
+ .@"signed short",
+ .@"signed int",
+ .@"signed long",
+ .@"signed long long",
+ .intptr_t,
+ => |t| try w.print("{f}", .{
+ fmtSignedIntLiteralSmall(target, t, val.toInt(i64) catch unreachable, is_global, base, case),
+ }),
+
+ .zig_u128 => {
+ const raw = val.toInt(u128) catch unreachable;
+ const lo: u64 = @truncate(raw);
+ const hi: u64 = @intCast(raw >> 64);
+ const macro_name: []const u8 = if (is_global) "zig_init_u128" else "zig_make_u128";
+ try w.print("{s}({f}, {f})", .{
+ macro_name,
+ fmtUnsignedIntLiteralSmall(target, .uint64_t, hi, is_global, base, case),
+ fmtUnsignedIntLiteralSmall(target, .uint64_t, lo, is_global, base, case),
+ });
},
- .zig_u128, .zig_i128 => .{
- .ctype = .u64,
- .count = 2,
- .endian = .big,
- .homogeneous = false,
+
+ .zig_i128 => {
+ const raw = val.toInt(i128) catch unreachable;
+ const lo: u64 = @truncate(@as(u128, @bitCast(raw)));
+ const hi: i64 = @intCast(raw >> 64);
+ const macro_name: []const u8 = if (is_global) "zig_init_i128" else "zig_make_i128";
+ try w.print("{s}({f}, {f})", .{
+ macro_name,
+ fmtSignedIntLiteralSmall(target, .int64_t, hi, is_global, base, case),
+ fmtUnsignedIntLiteralSmall(target, .uint64_t, lo, is_global, base, case),
+ });
},
- },
- .array => |array_info| .{
- .ctype = array_info.elem_ctype,
- .count = @intCast(array_info.len),
- .endian = target.cpu.arch.endian(),
- .homogeneous = true,
- },
- else => unreachable,
+ }
+ }
+};
+fn fmtUnsignedIntLiteralSmall(
+ target: *const std.Target,
+ int_cty: CType.Int,
+ val: u64,
+ is_global: bool,
+ base: u8,
+ case: std.fmt.Case,
+) FormatUnsignedIntLiteralSmall {
+ return .{
+ .target = target,
+ .int_cty = int_cty,
+ .val = val,
+ .is_global = is_global,
+ .base = base,
+ .case = case,
+ };
+}
+fn fmtSignedIntLiteralSmall(
+ target: *const std.Target,
+ int_cty: CType.Int,
+ val: i64,
+ is_global: bool,
+ base: u8,
+ case: std.fmt.Case,
+) FormatSignedIntLiteralSmall {
+ return .{
+ .target = target,
+ .int_cty = int_cty,
+ .val = val,
+ .is_global = is_global,
+ .base = base,
+ .case = case,
};
- if (c_limb_info.count == 1) {
- if (wrap.addWrap(int, one, data.int_info.signedness, c_bits) or
- data.int_info.signedness == .signed and wrap.subWrap(int, one, data.int_info.signedness, c_bits))
- return w.print("{s}_{s}", .{
- data.ctype.getStandardDefineAbbrev() orelse return w.print("zig_{s}Int_{c}{d}", .{
- if (int.positive) "max" else "min", signAbbrev(data.int_info.signedness), c_bits,
- }),
- if (int.positive) "MAX" else "MIN",
- });
-
- if (!int.positive) try w.writeByte('-');
- try data.ctype.renderLiteralPrefix(w, data.kind, ctype_pool);
+}
+const FormatSignedIntLiteralSmall = struct {
+ target: *const std.Target,
+ int_cty: CType.Int,
+ val: i64,
+ is_global: bool,
+ base: u8,
+ case: std.fmt.Case,
+ pub fn format(data: FormatSignedIntLiteralSmall, w: *Writer) Writer.Error!void {
+ const bits = data.int_cty.bits(data.target);
+ const max_int: i64 = @bitCast((@as(u64, 1) << @intCast(bits - 1)) - 1);
+ const min_int: i64 = @bitCast(@as(u64, 1) << @intCast(bits - 1));
+ if (data.val == max_int) {
+ return w.print("{s}_MAX", .{minMaxMacroPrefix(data.int_cty)});
+ } else if (data.val == min_int) {
+ return w.print("{s}_MIN", .{minMaxMacroPrefix(data.int_cty)});
+ }
+ if (data.val < 0) try w.writeByte('-');
+ try w.writeAll(intLiteralPrefix(data.int_cty, data.is_global));
switch (data.base) {
2 => try w.writeAll("0b"),
8 => try w.writeByte('0'),
@@ -8131,68 +7286,131 @@ fn formatIntLiteral(data: FormatIntLiteralContext, w: *Writer) Writer.Error!void
16 => try w.writeAll("0x"),
else => unreachable,
}
- const string = int.abs().toStringAlloc(allocator, data.base, data.case) catch
- return error.WriteFailed;
- defer allocator.free(string);
- try w.writeAll(string);
- } else {
- try data.ctype.renderLiteralPrefix(w, data.kind, ctype_pool);
- wrap.truncate(int, .unsigned, c_bits);
- @memset(wrap.limbs[wrap.len..], 0);
- wrap.len = wrap.limbs.len;
- const limbs_per_c_limb = @divExact(wrap.len, c_limb_info.count);
-
- var c_limb_int_info: std.builtin.Type.Int = .{
- .signedness = undefined,
- .bits = @intCast(@divExact(c_bits, c_limb_info.count)),
- };
- var c_limb_ctype: CType = undefined;
-
- var limb_offset: usize = 0;
- const most_significant_limb_i = wrap.len - limbs_per_c_limb;
- while (limb_offset < wrap.len) : (limb_offset += limbs_per_c_limb) {
- const limb_i = switch (c_limb_info.endian) {
- .little => limb_offset,
- .big => most_significant_limb_i - limb_offset,
- };
- var c_limb_mut = BigInt.Mutable{
- .limbs = wrap.limbs[limb_i..][0..limbs_per_c_limb],
- .len = undefined,
- .positive = true,
- };
- c_limb_mut.normalize(limbs_per_c_limb);
-
- if (limb_i == most_significant_limb_i and
- !c_limb_info.homogeneous and data.int_info.signedness == .signed)
- {
- // most significant limb is actually signed
- c_limb_int_info.signedness = .signed;
- c_limb_ctype = c_limb_info.ctype.toSigned();
-
- c_limb_mut.truncate(
- c_limb_mut.toConst(),
- .signed,
- data.int_info.bits - limb_i * @bitSizeOf(BigIntLimb),
- );
- } else {
- c_limb_int_info.signedness = .unsigned;
- c_limb_ctype = c_limb_info.ctype;
- }
-
- if (limb_offset > 0) try w.writeAll(", ");
- try formatIntLiteral(.{
- .dg = data.dg,
- .int_info = c_limb_int_info,
- .kind = data.kind,
- .ctype = c_limb_ctype,
- .val = pt.intValue_big(.comptime_int, c_limb_mut.toConst()) catch
- return error.WriteFailed,
- .base = data.base,
- .case = data.case,
- }, w);
+ // This `@abs` is safe thanks to the `min_int` case above.
+ try w.printInt(@abs(data.val), data.base, data.case, .{});
+ try w.writeAll(intLiteralSuffix(data.int_cty));
+ }
+};
+const FormatUnsignedIntLiteralSmall = struct {
+ target: *const std.Target,
+ int_cty: CType.Int,
+ val: u64,
+ is_global: bool,
+ base: u8,
+ case: std.fmt.Case,
+ pub fn format(data: FormatUnsignedIntLiteralSmall, w: *Writer) Writer.Error!void {
+ const bits = data.int_cty.bits(data.target);
+ const max_int: u64 = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - bits);
+ if (data.val == max_int) {
+ return w.print("{s}_MAX", .{minMaxMacroPrefix(data.int_cty)});
}
+ try w.writeAll(intLiteralPrefix(data.int_cty, data.is_global));
+ switch (data.base) {
+ 2 => try w.writeAll("0b"),
+ 8 => try w.writeByte('0'),
+ 10 => {},
+ 16 => try w.writeAll("0x"),
+ else => unreachable,
+ }
+ try w.printInt(data.val, data.base, data.case, .{});
+ try w.writeAll(intLiteralSuffix(data.int_cty));
}
- try data.ctype.renderLiteralSuffix(w, ctype_pool);
+};
+fn minMaxMacroPrefix(int_cty: CType.Int) []const u8 {
+ return switch (int_cty) {
+ // zig fmt: off
+ .char => "CHAR",
+
+ .@"unsigned short" => "USHRT",
+ .@"unsigned int" => "UINT",
+ .@"unsigned long" => "ULONG",
+ .@"unsigned long long" => "ULLONG",
+
+ .@"signed short" => "SHRT",
+ .@"signed int" => "INT",
+ .@"signed long" => "LONG",
+ .@"signed long long" => "LLONG",
+
+ .uint8_t => "UINT8",
+ .uint16_t => "UINT16",
+ .uint32_t => "UINT32",
+ .uint64_t => "UINT64",
+ .zig_u128 => unreachable,
+
+ .int8_t => "INT8",
+ .int16_t => "INT16",
+ .int32_t => "INT32",
+ .int64_t => "INT64",
+ .zig_i128 => unreachable,
+
+ .uintptr_t => "UINTPTR",
+ .intptr_t => "INTPTR",
+ // zig fmt: on
+ };
+}
+fn intLiteralPrefix(cty: CType.Int, is_global: bool) []const u8 {
+ return switch (cty) {
+ // zig fmt: off
+ .char => if (is_global) "" else "(char)",
+
+ .@"unsigned short" => if (is_global) "" else "(unsigned short)",
+ .@"unsigned int" => "",
+ .@"unsigned long" => "",
+ .@"unsigned long long" => "",
+
+ .@"signed short" => if (is_global) "" else "(signed short)",
+ .@"signed int" => "",
+ .@"signed long" => "",
+ .@"signed long long" => "",
+
+ .uint8_t => "UINT8_C(",
+ .uint16_t => "UINT16_C(",
+ .uint32_t => "UINT32_C(",
+ .uint64_t => "UINT64_C(",
+ .zig_u128 => unreachable,
+
+ .int8_t => "INT8_C(",
+ .int16_t => "INT16_C(",
+ .int32_t => "INT32_C(",
+ .int64_t => "INT64_C(",
+ .zig_i128 => unreachable,
+
+ .uintptr_t => if (is_global) "" else "(uintptr_t)",
+ .intptr_t => if (is_global) "" else "(intptr_t)",
+ // zig fmt: on
+ };
+}
+fn intLiteralSuffix(cty: CType.Int) []const u8 {
+ return switch (cty) {
+ // zig fmt: off
+ .char => "",
+
+ .@"unsigned short" => "u",
+ .@"unsigned int" => "u",
+ .@"unsigned long" => "ul",
+ .@"unsigned long long" => "ull",
+
+ .@"signed short" => "",
+ .@"signed int" => "",
+ .@"signed long" => "l",
+ .@"signed long long" => "ll",
+
+ .uint8_t => ")",
+ .uint16_t => ")",
+ .uint32_t => ")",
+ .uint64_t => ")",
+ .zig_u128 => unreachable,
+
+ .int8_t => ")",
+ .int16_t => ")",
+ .int32_t => ")",
+ .int64_t => ")",
+ .zig_i128 => unreachable,
+
+ .uintptr_t => "ul",
+ .intptr_t => "",
+ // zig fmt: on
+ };
}
const Materialize = struct {
@@ -8207,7 +7425,7 @@ const Materialize = struct {
}
pub fn mat(self: Materialize, f: *Function, w: *Writer) !void {
- try f.writeCValue(w, self.local, .Other);
+ try f.writeCValue(w, self.local, .other);
}
pub fn end(self: Materialize, f: *Function, inst: Air.Inst.Index) !void {
@@ -8215,95 +7433,52 @@ const Materialize = struct {
}
};
-const Assignment = struct {
- ctype: CType,
-
- pub fn start(f: *Function, w: *Writer, ctype: CType) !Assignment {
- const self: Assignment = .{ .ctype = ctype };
- try self.restart(f, w);
- return self;
- }
-
- pub fn restart(self: Assignment, f: *Function, w: *Writer) !void {
- switch (self.strategy(f)) {
- .assign => {},
- .memcpy => try w.writeAll("memcpy("),
- }
- }
-
- pub fn assign(self: Assignment, f: *Function, w: *Writer) !void {
- switch (self.strategy(f)) {
- .assign => try w.writeAll(" = "),
- .memcpy => try w.writeAll(", "),
- }
- }
-
- pub fn end(self: Assignment, f: *Function, w: *Writer) !void {
- switch (self.strategy(f)) {
- .assign => {},
- .memcpy => {
- try w.writeAll(", sizeof(");
- try f.renderCType(w, self.ctype);
- try w.writeAll("))");
- },
- }
- try w.writeByte(';');
- try f.object.newline();
- }
-
- fn strategy(self: Assignment, f: *Function) enum { assign, memcpy } {
- return switch (self.ctype.info(&f.object.dg.ctype_pool)) {
- else => .assign,
- .array, .vector => .memcpy,
- };
- }
-};
-
const Vectorize = struct {
index: CValue = .none,
pub fn start(f: *Function, inst: Air.Inst.Index, w: *Writer, ty: Type) !Vectorize {
- const pt = f.object.dg.pt;
+ const pt = f.dg.pt;
const zcu = pt.zcu;
- return if (ty.zigTypeTag(zcu) == .vector) index: {
- const local = try f.allocLocal(inst, .usize);
-
- try w.writeAll("for (");
- try f.writeCValue(w, local, .Other);
- try w.print(" = {f}; ", .{try f.fmtIntLiteralDec(.zero_usize)});
- try f.writeCValue(w, local, .Other);
- try w.print(" < {f}; ", .{try f.fmtIntLiteralDec(try pt.intValue(.usize, ty.vectorLen(zcu)))});
- try f.writeCValue(w, local, .Other);
- try w.print(" += {f}) {{\n", .{try f.fmtIntLiteralDec(.one_usize)});
- f.object.indent();
- try f.object.newline();
-
- break :index .{ .index = local };
- } else .{};
+ switch (ty.zigTypeTag(zcu)) {
+ else => return .{ .index = .none },
+ .vector => {
+ const local = try f.allocLocal(inst, .usize);
+ try w.writeAll("for (");
+ try f.writeCValue(w, local, .other);
+ try w.print(" = {f}; ", .{try f.fmtIntLiteralDec(.zero_usize)});
+ try f.writeCValue(w, local, .other);
+ try w.print(" < {f}; ", .{try f.fmtIntLiteralDec(try pt.intValue(.usize, ty.vectorLen(zcu)))});
+ try f.writeCValue(w, local, .other);
+ try w.print(" += {f}) {{", .{try f.fmtIntLiteralDec(.one_usize)});
+ f.indent();
+ try f.newline();
+ return .{ .index = local };
+ },
+ }
}
pub fn elem(self: Vectorize, f: *Function, w: *Writer) !void {
if (self.index != .none) {
- try w.writeByte('[');
- try f.writeCValue(w, self.index, .Other);
+ try w.writeAll(".array[");
+ try f.writeCValue(w, self.index, .other);
try w.writeByte(']');
}
}
pub fn end(self: Vectorize, f: *Function, inst: Air.Inst.Index, w: *Writer) !void {
if (self.index != .none) {
- try f.object.outdent();
+ try f.outdent();
try w.writeByte('}');
- try f.object.newline();
+ try f.newline();
try freeLocal(f, inst, self.index.new_local, null);
}
}
};
-fn lowersToArray(ty: Type, zcu: *Zcu) bool {
+fn lowersToBigInt(ty: Type, zcu: *const Zcu) bool {
return switch (ty.zigTypeTag(zcu)) {
- .array, .vector => return true,
- else => return ty.isAbiInt(zcu) and toCIntBits(@as(u32, @intCast(ty.bitSize(zcu)))) == null,
+ .int, .@"enum", .@"struct", .@"union" => CType.classifyInt(ty, zcu) == .big,
+ else => false,
};
}
@@ -8329,8 +7504,8 @@ fn die(f: *Function, inst: Air.Inst.Index, ref: Air.Inst.Ref) !void {
}
fn freeLocal(f: *Function, inst: ?Air.Inst.Index, local_index: LocalIndex, ref_inst: ?Air.Inst.Index) !void {
- const gpa = f.object.dg.gpa;
- const local = &f.locals.items[local_index];
+ const gpa = f.dg.gpa;
+ const local = f.locals.items[local_index];
if (inst) |i| {
if (ref_inst) |operand| {
log.debug("%{d}: freeing t{d} (operand %{d})", .{ @intFromEnum(i), local_index, operand });
@@ -8344,7 +7519,7 @@ fn freeLocal(f: *Function, inst: ?Air.Inst.Index, local_index: LocalIndex, ref_i
log.debug("freeing t{d}", .{local_index});
}
}
- const gop = try f.free_locals_map.getOrPut(gpa, local.getType());
+ const gop = try f.free_locals_map.getOrPut(gpa, local);
if (!gop.found_existing) gop.value_ptr.* = .{};
if (std.debug.runtime_safety) {
// If this trips, an unfreeable allocation was attempted to be freed.
@@ -8401,3 +7576,28 @@ fn deinitFreeLocalsMap(gpa: Allocator, map: *LocalsMap) void {
}
map.deinit(gpa);
}
+
+fn renderErrorName(w: *Writer, err_name: []const u8) Writer.Error!void {
+ try w.print("zig_error_{f}", .{fmtIdentUnsolo(err_name)});
+}
+
+fn renderNavName(w: *Writer, nav_index: InternPool.Nav.Index, ip: *const InternPool) !void {
+ const nav = ip.getNav(nav_index);
+ if (nav.getExtern(ip)) |@"extern"| {
+ try w.print("{f}", .{
+ fmtIdentSolo(ip.getNav(@"extern".owner_nav).name.toSlice(ip)),
+ });
+ } else {
+ // MSVC has a limit of 4095 character token length limit, and fmtIdent can (worst case),
+ // expand to 3x the length of its input, but let's cut it off at a much shorter limit.
+ const fqn_slice = ip.getNav(nav_index).fqn.toSlice(ip);
+ try w.print("{f}__{d}", .{
+ fmtIdentUnsolo(fqn_slice[0..@min(fqn_slice.len, 100)]),
+ @intFromEnum(nav_index),
+ });
+ }
+}
+
+fn renderUavName(w: *Writer, uav: Value) !void {
+ try w.print("__anon_{d}", .{@intFromEnum(uav.toIntern())});
+}
diff --git a/src/codegen/c/Type.zig b/src/codegen/c/Type.zig
deleted file mode 100644
index 0bcdb207fc693b3acb38cd2a2c458dee9d61dbe3..0000000000000000000000000000000000000000
--- a/src/codegen/c/Type.zig
+++ /dev/null
@@ -1,3472 +0,0 @@
-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_null =
- @subWithOverflow(@intFromEnum(ctype.index), CType.Index.first_pool_index);
- return switch (is_null) {
- 0 => pool_index,
- 1 => null,
- };
-}
-
-pub fn eql(lhs: CType, rhs: CType) bool {
- return lhs.index == rhs.index;
-}
-
-pub fn isBool(ctype: CType) bool {
- return switch (ctype.index) {
- ._Bool, .bool => true,
- else => false,
- };
-}
-
-pub fn isInteger(ctype: CType) bool {
- return switch (ctype.index) {
- .char,
- .@"signed char",
- .short,
- .int,
- .long,
- .@"long long",
- .@"unsigned char",
- .@"unsigned short",
- .@"unsigned int",
- .@"unsigned long",
- .@"unsigned long long",
- .size_t,
- .ptrdiff_t,
- .uint8_t,
- .int8_t,
- .uint16_t,
- .int16_t,
- .uint32_t,
- .int32_t,
- .uint64_t,
- .int64_t,
- .uintptr_t,
- .intptr_t,
- .zig_u128,
- .zig_i128,
- => true,
- else => false,
- };
-}
-
-pub fn signedness(ctype: CType, mod: *Module) std.builtin.Signedness {
- return switch (ctype.index) {
- .char => mod.resolved_target.result.cCharSignedness(),
- .@"signed char",
- .short,
- .int,
- .long,
- .@"long long",
- .ptrdiff_t,
- .int8_t,
- .int16_t,
- .int32_t,
- .int64_t,
- .intptr_t,
- .zig_i128,
- => .signed,
- .@"unsigned char",
- .@"unsigned short",
- .@"unsigned int",
- .@"unsigned long",
- .@"unsigned long long",
- .size_t,
- .uint8_t,
- .uint16_t,
- .uint32_t,
- .uint64_t,
- .uintptr_t,
- .zig_u128,
- => .unsigned,
- else => unreachable,
- };
-}
-
-pub fn isFloat(ctype: CType) bool {
- return switch (ctype.index) {
- .float,
- .double,
- .@"long double",
- .zig_f16,
- .zig_f32,
- .zig_f64,
- .zig_f80,
- .zig_f128,
- .zig_c_longdouble,
- => true,
- else => false,
- };
-}
-
-pub fn toSigned(ctype: CType) CType {
- return switch (ctype.index) {
- .char, .@"signed char", .@"unsigned char" => .{ .index = .@"signed char" },
- .short, .@"unsigned short" => .{ .index = .short },
- .int, .@"unsigned int" => .{ .index = .int },
- .long, .@"unsigned long" => .{ .index = .long },
- .@"long long", .@"unsigned long long" => .{ .index = .@"long long" },
- .size_t, .ptrdiff_t => .{ .index = .ptrdiff_t },
- .uint8_t, .int8_t => .{ .index = .int8_t },
- .uint16_t, .int16_t => .{ .index = .int16_t },
- .uint32_t, .int32_t => .{ .index = .int32_t },
- .uint64_t, .int64_t => .{ .index = .int64_t },
- .uintptr_t, .intptr_t => .{ .index = .intptr_t },
- .zig_u128, .zig_i128 => .{ .index = .zig_i128 },
- .float,
- .double,
- .@"long double",
- .zig_f16,
- .zig_f32,
- .zig_f80,
- .zig_f128,
- .zig_c_longdouble,
- => ctype,
- else => unreachable,
- };
-}
-
-pub fn toUnsigned(ctype: CType) CType {
- return switch (ctype.index) {
- .char, .@"signed char", .@"unsigned char" => .{ .index = .@"unsigned char" },
- .short, .@"unsigned short" => .{ .index = .@"unsigned short" },
- .int, .@"unsigned int" => .{ .index = .@"unsigned int" },
- .long, .@"unsigned long" => .{ .index = .@"unsigned long" },
- .@"long long", .@"unsigned long long" => .{ .index = .@"unsigned long long" },
- .size_t, .ptrdiff_t => .{ .index = .size_t },
- .uint8_t, .int8_t => .{ .index = .uint8_t },
- .uint16_t, .int16_t => .{ .index = .uint16_t },
- .uint32_t, .int32_t => .{ .index = .uint32_t },
- .uint64_t, .int64_t => .{ .index = .uint64_t },
- .uintptr_t, .intptr_t => .{ .index = .uintptr_t },
- .zig_u128, .zig_i128 => .{ .index = .zig_u128 },
- else => unreachable,
- };
-}
-
-pub fn toSignedness(ctype: CType, s: std.builtin.Signedness) CType {
- return switch (s) {
- .unsigned => ctype.toUnsigned(),
- .signed => ctype.toSigned(),
- };
-}
-
-pub fn isAnyChar(ctype: CType) bool {
- return switch (ctype.index) {
- else => false,
- .char, .@"signed char", .@"unsigned char", .uint8_t, .int8_t => true,
- };
-}
-
-pub fn isString(ctype: CType, pool: *const Pool) bool {
- return info: switch (ctype.info(pool)) {
- .basic, .fwd_decl, .aggregate, .function => false,
- .pointer => |pointer_info| pointer_info.elem_ctype.isAnyChar(),
- .aligned => |aligned_info| continue :info aligned_info.ctype.info(pool),
- .array, .vector => |sequence_info| sequence_info.elem_type.isAnyChar(),
- };
-}
-
-pub fn isNonString(ctype: CType, pool: *const Pool) bool {
- var allow_pointer = true;
- return info: switch (ctype.info(pool)) {
- .basic, .fwd_decl, .aggregate, .function => false,
- .pointer => |pointer_info| allow_pointer and pointer_info.nonstring,
- .aligned => |aligned_info| continue :info aligned_info.ctype.info(pool),
- .array, .vector => |sequence_info| sequence_info.nonstring or {
- allow_pointer = false;
- continue :info sequence_info.elem_ctype.info(pool);
- },
- };
-}
-
-pub fn getStandardDefineAbbrev(ctype: CType) ?[]const u8 {
- return switch (ctype.index) {
- .char => "CHAR",
- .@"signed char" => "SCHAR",
- .short => "SHRT",
- .int => "INT",
- .long => "LONG",
- .@"long long" => "LLONG",
- .@"unsigned char" => "UCHAR",
- .@"unsigned short" => "USHRT",
- .@"unsigned int" => "UINT",
- .@"unsigned long" => "ULONG",
- .@"unsigned long long" => "ULLONG",
- .float => "FLT",
- .double => "DBL",
- .@"long double" => "LDBL",
- .size_t => "SIZE",
- .ptrdiff_t => "PTRDIFF",
- .uint8_t => "UINT8",
- .int8_t => "INT8",
- .uint16_t => "UINT16",
- .int16_t => "INT16",
- .uint32_t => "UINT32",
- .int32_t => "INT32",
- .uint64_t => "UINT64",
- .int64_t => "INT64",
- .uintptr_t => "UINTPTR",
- .intptr_t => "INTPTR",
- else => null,
- };
-}
-
-pub fn renderLiteralPrefix(ctype: CType, w: *Writer, kind: Kind, pool: *const Pool) Writer.Error!void {
- switch (ctype.info(pool)) {
- .basic => |basic_info| switch (basic_info) {
- .void => unreachable,
- ._Bool,
- .char,
- .@"signed char",
- .short,
- .@"unsigned short",
- .bool,
- .size_t,
- .ptrdiff_t,
- .uintptr_t,
- .intptr_t,
- => switch (kind) {
- else => try w.print("({s})", .{@tagName(basic_info)}),
- .global => {},
- },
- .int,
- .long,
- .@"long long",
- .@"unsigned char",
- .@"unsigned int",
- .@"unsigned long",
- .@"unsigned long long",
- .float,
- .double,
- .@"long double",
- => {},
- .uint8_t,
- .int8_t,
- .uint16_t,
- .int16_t,
- .uint32_t,
- .int32_t,
- .uint64_t,
- .int64_t,
- => try w.print("{s}_C(", .{ctype.getStandardDefineAbbrev().?}),
- .zig_u128,
- .zig_i128,
- .zig_f16,
- .zig_f32,
- .zig_f64,
- .zig_f80,
- .zig_f128,
- .zig_c_longdouble,
- => try w.print("zig_{s}_{s}(", .{
- switch (kind) {
- else => "make",
- .global => "init",
- },
- @tagName(basic_info)["zig_".len..],
- }),
- .va_list => unreachable,
- _ => unreachable,
- },
- .array, .vector => try w.writeByte('{'),
- else => unreachable,
- }
-}
-
-pub fn renderLiteralSuffix(ctype: CType, w: *Writer, pool: *const Pool) Writer.Error!void {
- switch (ctype.info(pool)) {
- .basic => |basic_info| switch (basic_info) {
- .void => unreachable,
- ._Bool => {},
- .char,
- .@"signed char",
- .short,
- .int,
- => {},
- .long => try w.writeByte('l'),
- .@"long long" => try w.writeAll("ll"),
- .@"unsigned char",
- .@"unsigned short",
- .@"unsigned int",
- => try w.writeByte('u'),
- .@"unsigned long",
- .size_t,
- .uintptr_t,
- => try w.writeAll("ul"),
- .@"unsigned long long" => try w.writeAll("ull"),
- .float => try w.writeByte('f'),
- .double => {},
- .@"long double" => try w.writeByte('l'),
- .bool,
- .ptrdiff_t,
- .intptr_t,
- => {},
- .uint8_t,
- .int8_t,
- .uint16_t,
- .int16_t,
- .uint32_t,
- .int32_t,
- .uint64_t,
- .int64_t,
- .zig_u128,
- .zig_i128,
- .zig_f16,
- .zig_f32,
- .zig_f64,
- .zig_f80,
- .zig_f128,
- .zig_c_longdouble,
- => try w.writeByte(')'),
- .va_list => unreachable,
- _ => unreachable,
- },
- .array, .vector => try w.writeByte('}'),
- else => unreachable,
- }
-}
-
-pub fn floatActiveBits(ctype: CType, mod: *Module) u16 {
- const target = &mod.resolved_target.result;
- return switch (ctype.index) {
- .float => target.cTypeBitSize(.float),
- .double => target.cTypeBitSize(.double),
- .@"long double", .zig_c_longdouble => target.cTypeBitSize(.longdouble),
- .zig_f16 => 16,
- .zig_f32 => 32,
- .zig_f64 => 64,
- .zig_f80 => 80,
- .zig_f128 => 128,
- else => unreachable,
- };
-}
-
-pub fn byteSize(ctype: CType, pool: *const Pool, mod: *Module) u64 {
- const target = &mod.resolved_target.result;
- return switch (ctype.info(pool)) {
- .basic => |basic_info| switch (basic_info) {
- .void => 0,
- .char, .@"signed char", ._Bool, .@"unsigned char", .bool, .uint8_t, .int8_t => 1,
- .short => target.cTypeByteSize(.short),
- .int => target.cTypeByteSize(.int),
- .long => target.cTypeByteSize(.long),
- .@"long long" => target.cTypeByteSize(.longlong),
- .@"unsigned short" => target.cTypeByteSize(.ushort),
- .@"unsigned int" => target.cTypeByteSize(.uint),
- .@"unsigned long" => target.cTypeByteSize(.ulong),
- .@"unsigned long long" => target.cTypeByteSize(.ulonglong),
- .float => target.cTypeByteSize(.float),
- .double => target.cTypeByteSize(.double),
- .@"long double" => target.cTypeByteSize(.longdouble),
- .size_t,
- .ptrdiff_t,
- .uintptr_t,
- .intptr_t,
- => @divExact(target.ptrBitWidth(), 8),
- .uint16_t, .int16_t, .zig_f16 => 2,
- .uint32_t, .int32_t, .zig_f32 => 4,
- .uint64_t, .int64_t, .zig_f64 => 8,
- .zig_u128, .zig_i128, .zig_f128 => 16,
- .zig_f80 => if (target.cTypeBitSize(.longdouble) == 80)
- target.cTypeByteSize(.longdouble)
- else
- 16,
- .zig_c_longdouble => target.cTypeByteSize(.longdouble),
- .va_list => unreachable,
- _ => unreachable,
- },
- .pointer => @divExact(target.ptrBitWidth(), 8),
- .array, .vector => |sequence_info| sequence_info.elem_ctype.byteSize(pool, mod) * sequence_info.len,
- else => unreachable,
- };
-}
-
-pub fn info(ctype: CType, pool: *const Pool) Info {
- const pool_index = ctype.toPoolIndex() orelse return .{ .basic = ctype.index };
- const item = pool.items.get(pool_index);
- switch (item.tag) {
- .basic => unreachable,
- .pointer => return .{ .pointer = .{
- .elem_ctype = .{ .index = @enumFromInt(item.data) },
- } },
- .pointer_const => return .{ .pointer = .{
- .elem_ctype = .{ .index = @enumFromInt(item.data) },
- .@"const" = true,
- } },
- .pointer_volatile => return .{ .pointer = .{
- .elem_ctype = .{ .index = @enumFromInt(item.data) },
- .@"volatile" = true,
- } },
- .pointer_const_volatile => return .{ .pointer = .{
- .elem_ctype = .{ .index = @enumFromInt(item.data) },
- .@"const" = true,
- .@"volatile" = true,
- } },
- .aligned => {
- const extra = pool.getExtra(Pool.Aligned, item.data);
- return .{ .aligned = .{
- .ctype = .{ .index = extra.ctype },
- .alignas = extra.flags.alignas,
- } };
- },
- .array_small => {
- const extra = pool.getExtra(Pool.SequenceSmall, item.data);
- return .{ .array = .{
- .elem_ctype = .{ .index = extra.elem_ctype },
- .len = extra.len,
- } };
- },
- .array_large => {
- const extra = pool.getExtra(Pool.SequenceLarge, item.data);
- return .{ .array = .{
- .elem_ctype = .{ .index = extra.elem_ctype },
- .len = extra.len(),
- } };
- },
- .vector => {
- const extra = pool.getExtra(Pool.SequenceSmall, item.data);
- return .{ .vector = .{
- .elem_ctype = .{ .index = extra.elem_ctype },
- .len = extra.len,
- } };
- },
- .nonstring => {
- var child_info = info(.{ .index = @enumFromInt(item.data) }, pool);
- switch (child_info) {
- else => unreachable,
- .pointer => |*pointer_info| pointer_info.nonstring = true,
- .array, .vector => |*sequence_info| sequence_info.nonstring = true,
- }
- return child_info;
- },
- .fwd_decl_struct_anon => {
- const extra_trail = pool.getExtraTrail(Pool.FwdDeclAnon, item.data);
- return .{ .fwd_decl = .{
- .tag = .@"struct",
- .name = .{ .anon = .{
- .extra_index = extra_trail.trail.extra_index,
- .len = extra_trail.extra.fields_len,
- } },
- } };
- },
- .fwd_decl_union_anon => {
- const extra_trail = pool.getExtraTrail(Pool.FwdDeclAnon, item.data);
- return .{ .fwd_decl = .{
- .tag = .@"union",
- .name = .{ .anon = .{
- .extra_index = extra_trail.trail.extra_index,
- .len = extra_trail.extra.fields_len,
- } },
- } };
- },
- .fwd_decl_struct => return .{ .fwd_decl = .{
- .tag = .@"struct",
- .name = .{ .index = @enumFromInt(item.data) },
- } },
- .fwd_decl_union => return .{ .fwd_decl = .{
- .tag = .@"union",
- .name = .{ .index = @enumFromInt(item.data) },
- } },
- .aggregate_struct_anon => {
- const extra_trail = pool.getExtraTrail(Pool.AggregateAnon, item.data);
- return .{ .aggregate = .{
- .tag = .@"struct",
- .name = .{ .anon = .{
- .index = extra_trail.extra.index,
- .id = extra_trail.extra.id,
- } },
- .fields = .{
- .extra_index = extra_trail.trail.extra_index,
- .len = extra_trail.extra.fields_len,
- },
- } };
- },
- .aggregate_union_anon => {
- const extra_trail = pool.getExtraTrail(Pool.AggregateAnon, item.data);
- return .{ .aggregate = .{
- .tag = .@"union",
- .name = .{ .anon = .{
- .index = extra_trail.extra.index,
- .id = extra_trail.extra.id,
- } },
- .fields = .{
- .extra_index = extra_trail.trail.extra_index,
- .len = extra_trail.extra.fields_len,
- },
- } };
- },
- .aggregate_struct_packed_anon => {
- const extra_trail = pool.getExtraTrail(Pool.AggregateAnon, item.data);
- return .{ .aggregate = .{
- .tag = .@"struct",
- .@"packed" = true,
- .name = .{ .anon = .{
- .index = extra_trail.extra.index,
- .id = extra_trail.extra.id,
- } },
- .fields = .{
- .extra_index = extra_trail.trail.extra_index,
- .len = extra_trail.extra.fields_len,
- },
- } };
- },
- .aggregate_union_packed_anon => {
- const extra_trail = pool.getExtraTrail(Pool.AggregateAnon, item.data);
- return .{ .aggregate = .{
- .tag = .@"union",
- .@"packed" = true,
- .name = .{ .anon = .{
- .index = extra_trail.extra.index,
- .id = extra_trail.extra.id,
- } },
- .fields = .{
- .extra_index = extra_trail.trail.extra_index,
- .len = extra_trail.extra.fields_len,
- },
- } };
- },
- .aggregate_struct => {
- const extra_trail = pool.getExtraTrail(Pool.Aggregate, item.data);
- return .{ .aggregate = .{
- .tag = .@"struct",
- .name = .{ .fwd_decl = .{ .index = extra_trail.extra.fwd_decl } },
- .fields = .{
- .extra_index = extra_trail.trail.extra_index,
- .len = extra_trail.extra.fields_len,
- },
- } };
- },
- .aggregate_union => {
- const extra_trail = pool.getExtraTrail(Pool.Aggregate, item.data);
- return .{ .aggregate = .{
- .tag = .@"union",
- .name = .{ .fwd_decl = .{ .index = extra_trail.extra.fwd_decl } },
- .fields = .{
- .extra_index = extra_trail.trail.extra_index,
- .len = extra_trail.extra.fields_len,
- },
- } };
- },
- .aggregate_struct_packed => {
- const extra_trail = pool.getExtraTrail(Pool.Aggregate, item.data);
- return .{ .aggregate = .{
- .tag = .@"struct",
- .@"packed" = true,
- .name = .{ .fwd_decl = .{ .index = extra_trail.extra.fwd_decl } },
- .fields = .{
- .extra_index = extra_trail.trail.extra_index,
- .len = extra_trail.extra.fields_len,
- },
- } };
- },
- .aggregate_union_packed => {
- const extra_trail = pool.getExtraTrail(Pool.Aggregate, item.data);
- return .{ .aggregate = .{
- .tag = .@"union",
- .@"packed" = true,
- .name = .{ .fwd_decl = .{ .index = extra_trail.extra.fwd_decl } },
- .fields = .{
- .extra_index = extra_trail.trail.extra_index,
- .len = extra_trail.extra.fields_len,
- },
- } };
- },
- .function => {
- const extra_trail = pool.getExtraTrail(Pool.Function, item.data);
- return .{ .function = .{
- .return_ctype = .{ .index = extra_trail.extra.return_ctype },
- .param_ctypes = .{
- .extra_index = extra_trail.trail.extra_index,
- .len = extra_trail.extra.param_ctypes_len,
- },
- .varargs = false,
- } };
- },
- .function_varargs => {
- const extra_trail = pool.getExtraTrail(Pool.Function, item.data);
- return .{ .function = .{
- .return_ctype = .{ .index = extra_trail.extra.return_ctype },
- .param_ctypes = .{
- .extra_index = extra_trail.trail.extra_index,
- .len = extra_trail.extra.param_ctypes_len,
- },
- .varargs = true,
- } };
- },
- }
-}
-
-pub fn hash(ctype: CType, pool: *const Pool) Pool.Map.Hash {
- return if (ctype.toPoolIndex()) |pool_index|
- pool.map.entries.items(.hash)[pool_index]
- else
- CType.Index.basic_hashes[@intFromEnum(ctype.index)];
-}
-
-fn toForward(ctype: CType, pool: *Pool, allocator: std.mem.Allocator) !CType {
- return switch (ctype.info(pool)) {
- .basic, .pointer, .fwd_decl => ctype,
- .aligned => |aligned_info| pool.getAligned(allocator, .{
- .ctype = try aligned_info.ctype.toForward(pool, allocator),
- .alignas = aligned_info.alignas,
- }),
- .array => |array_info| pool.getArray(allocator, .{
- .elem_ctype = try array_info.elem_ctype.toForward(pool, allocator),
- .len = array_info.len,
- .nonstring = array_info.nonstring,
- }),
- .vector => |vector_info| pool.getVector(allocator, .{
- .elem_ctype = try vector_info.elem_ctype.toForward(pool, allocator),
- .len = vector_info.len,
- .nonstring = vector_info.nonstring,
- }),
- .aggregate => |aggregate_info| switch (aggregate_info.name) {
- .anon => ctype,
- .fwd_decl => |fwd_decl| fwd_decl,
- },
- .function => unreachable,
- };
-}
-
-const Index = enum(u32) {
- void,
-
- // C basic types
- char,
-
- @"signed char",
- short,
- int,
- long,
- @"long long",
-
- _Bool,
- @"unsigned char",
- @"unsigned short",
- @"unsigned int",
- @"unsigned long",
- @"unsigned long long",
-
- float,
- double,
- @"long double",
-
- // C header types
- // - stdbool.h
- bool,
- // - stddef.h
- size_t,
- ptrdiff_t,
- // - stdint.h
- uint8_t,
- int8_t,
- uint16_t,
- int16_t,
- uint32_t,
- int32_t,
- uint64_t,
- int64_t,
- uintptr_t,
- intptr_t,
- // - stdarg.h
- va_list,
-
- // zig.h types
- zig_u128,
- zig_i128,
- zig_f16,
- zig_f32,
- zig_f64,
- zig_f80,
- zig_f128,
- zig_c_longdouble,
-
- _,
-
- const first_pool_index: u32 = @typeInfo(CType.Index).@"enum".fields.len;
- const basic_hashes = init: {
- @setEvalBranchQuota(1_600);
- var basic_hashes_init: [first_pool_index]Pool.Map.Hash = undefined;
- for (&basic_hashes_init, 0..) |*basic_hash, index| {
- const ctype_index: CType.Index = @enumFromInt(index);
- var hasher = Pool.Hasher.init;
- hasher.update(@intFromEnum(ctype_index));
- basic_hash.* = hasher.final(.basic);
- }
- break :init basic_hashes_init;
- };
-};
-
-const Slice = struct {
- extra_index: Pool.ExtraIndex,
- len: u32,
-
- pub fn at(slice: CType.Slice, index: usize, pool: *const Pool) CType {
- var extra: Pool.ExtraTrail = .{ .extra_index = slice.extra_index };
- return .{ .index = extra.next(slice.len, CType.Index, pool)[index] };
- }
-};
-
-pub const Kind = enum {
- forward,
- forward_parameter,
- complete,
- global,
- parameter,
-
- pub fn isForward(kind: Kind) bool {
- return switch (kind) {
- .forward, .forward_parameter => true,
- .complete, .global, .parameter => false,
- };
- }
-
- pub fn isParameter(kind: Kind) bool {
- return switch (kind) {
- .forward_parameter, .parameter => true,
- .forward, .complete, .global => false,
- };
- }
-
- pub fn asParameter(kind: Kind) Kind {
- return switch (kind) {
- .forward, .forward_parameter => .forward_parameter,
- .complete, .parameter, .global => .parameter,
- };
- }
-
- pub fn noParameter(kind: Kind) Kind {
- return switch (kind) {
- .forward, .forward_parameter => .forward,
- .complete, .parameter => .complete,
- .global => .global,
- };
- }
-
- pub fn asComplete(kind: Kind) Kind {
- return switch (kind) {
- .forward, .complete => .complete,
- .forward_parameter, .parameter => .parameter,
- .global => .global,
- };
- }
-};
-
-pub const Info = union(enum) {
- basic: CType.Index,
- pointer: Pointer,
- aligned: Aligned,
- array: Sequence,
- vector: Sequence,
- fwd_decl: FwdDecl,
- aggregate: Aggregate,
- function: Function,
-
- const Tag = @typeInfo(Info).@"union".tag_type.?;
-
- pub const Pointer = struct {
- elem_ctype: CType,
- @"const": bool = false,
- @"volatile": bool = false,
- nonstring: bool = false,
-
- fn tag(pointer_info: Pointer) Pool.Tag {
- return @enumFromInt(@intFromEnum(Pool.Tag.pointer) +
- @as(u2, @bitCast(packed struct(u2) {
- @"const": bool,
- @"volatile": bool,
- }{
- .@"const" = pointer_info.@"const",
- .@"volatile" = pointer_info.@"volatile",
- })));
- }
- };
-
- pub const Aligned = struct {
- ctype: CType,
- alignas: AlignAs,
- };
-
- pub const Sequence = struct {
- elem_ctype: CType,
- len: u64,
- nonstring: bool = false,
- };
-
- pub const AggregateTag = enum { @"enum", @"struct", @"union" };
-
- pub const Field = struct {
- name: Pool.String,
- ctype: CType,
- alignas: AlignAs,
-
- pub const Slice = struct {
- extra_index: Pool.ExtraIndex,
- len: u32,
-
- pub fn at(slice: Field.Slice, index: usize, pool: *const Pool) Field {
- assert(index < slice.len);
- const extra = pool.getExtra(Pool.Field, @intCast(slice.extra_index +
- index * @typeInfo(Pool.Field).@"struct".fields.len));
- return .{
- .name = .{ .index = extra.name },
- .ctype = .{ .index = extra.ctype },
- .alignas = extra.flags.alignas,
- };
- }
-
- fn eqlAdapted(
- lhs_slice: Field.Slice,
- lhs_pool: *const Pool,
- rhs_slice: Field.Slice,
- rhs_pool: *const Pool,
- pool_adapter: anytype,
- ) bool {
- if (lhs_slice.len != rhs_slice.len) return false;
- for (0..lhs_slice.len) |index| {
- if (!lhs_slice.at(index, lhs_pool).eqlAdapted(
- lhs_pool,
- rhs_slice.at(index, rhs_pool),
- rhs_pool,
- pool_adapter,
- )) return false;
- }
- return true;
- }
- };
-
- fn eqlAdapted(
- lhs_field: Field,
- lhs_pool: *const Pool,
- rhs_field: Field,
- rhs_pool: *const Pool,
- pool_adapter: anytype,
- ) bool {
- 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;
- }
- };
-
- pub const FwdDecl = struct {
- tag: AggregateTag,
- name: union(enum) {
- anon: Field.Slice,
- index: InternPool.Index,
- },
- };
-
- pub const Aggregate = struct {
- tag: AggregateTag,
- @"packed": bool = false,
- name: union(enum) {
- anon: struct {
- index: InternPool.Index,
- id: u32,
- },
- fwd_decl: CType,
- },
- fields: Field.Slice,
- };
-
- pub const Function = struct {
- return_ctype: CType,
- param_ctypes: CType.Slice,
- varargs: bool = false,
- };
-
- pub fn eqlAdapted(
- lhs_info: Info,
- lhs_pool: *const Pool,
- rhs_ctype: CType,
- rhs_pool: *const Pool,
- pool_adapter: anytype,
- ) bool {
- const rhs_info = rhs_ctype.info(rhs_pool);
- if (@as(Info.Tag, lhs_info) != @as(Info.Tag, rhs_info)) return false;
- return switch (lhs_info) {
- .basic => |lhs_basic_info| lhs_basic_info == rhs_info.basic,
- .pointer => |lhs_pointer_info| lhs_pointer_info.@"const" == rhs_info.pointer.@"const" and
- lhs_pointer_info.@"volatile" == rhs_info.pointer.@"volatile" and
- lhs_pointer_info.nonstring == rhs_info.pointer.nonstring and
- pool_adapter.eql(lhs_pointer_info.elem_ctype, rhs_info.pointer.elem_ctype),
- .aligned => |lhs_aligned_info| std.meta.eql(lhs_aligned_info.alignas, rhs_info.aligned.alignas) and
- pool_adapter.eql(lhs_aligned_info.ctype, rhs_info.aligned.ctype),
- .array => |lhs_array_info| lhs_array_info.len == rhs_info.array.len and
- lhs_array_info.nonstring == rhs_info.array.nonstring and
- pool_adapter.eql(lhs_array_info.elem_ctype, rhs_info.array.elem_ctype),
- .vector => |lhs_vector_info| lhs_vector_info.len == rhs_info.vector.len and
- lhs_vector_info.nonstring == rhs_info.vector.nonstring and
- pool_adapter.eql(lhs_vector_info.elem_ctype, rhs_info.vector.elem_ctype),
- .fwd_decl => |lhs_fwd_decl_info| lhs_fwd_decl_info.tag == rhs_info.fwd_decl.tag and
- switch (lhs_fwd_decl_info.name) {
- .anon => |lhs_anon| rhs_info.fwd_decl.name == .anon and lhs_anon.eqlAdapted(
- lhs_pool,
- rhs_info.fwd_decl.name.anon,
- rhs_pool,
- pool_adapter,
- ),
- .index => |lhs_index| rhs_info.fwd_decl.name == .index and
- lhs_index == rhs_info.fwd_decl.name.index,
- },
- .aggregate => |lhs_aggregate_info| lhs_aggregate_info.tag == rhs_info.aggregate.tag and
- lhs_aggregate_info.@"packed" == rhs_info.aggregate.@"packed" and
- switch (lhs_aggregate_info.name) {
- .anon => |lhs_anon| rhs_info.aggregate.name == .anon and
- lhs_anon.index == rhs_info.aggregate.name.anon.index and
- lhs_anon.id == rhs_info.aggregate.name.anon.id,
- .fwd_decl => |lhs_fwd_decl| rhs_info.aggregate.name == .fwd_decl and
- pool_adapter.eql(lhs_fwd_decl, rhs_info.aggregate.name.fwd_decl),
- } and lhs_aggregate_info.fields.eqlAdapted(
- lhs_pool,
- rhs_info.aggregate.fields,
- rhs_pool,
- pool_adapter,
- ),
- .function => |lhs_function_info| lhs_function_info.param_ctypes.len ==
- rhs_info.function.param_ctypes.len and
- pool_adapter.eql(lhs_function_info.return_ctype, rhs_info.function.return_ctype) and
- for (0..lhs_function_info.param_ctypes.len) |param_index| {
- if (!pool_adapter.eql(
- lhs_function_info.param_ctypes.at(param_index, lhs_pool),
- rhs_info.function.param_ctypes.at(param_index, rhs_pool),
- )) break false;
- } else true,
- };
- }
-};
-
-pub const Pool = struct {
- map: Map,
- items: std.MultiArrayList(Item),
- extra: std.ArrayList(u32),
-
- string_map: Map,
- string_indices: std.ArrayList(u32),
- string_bytes: std.ArrayList(u8),
-
- 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, writer: *Writer) Writer.Error!void {
- 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.Alt(FormatData, 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 = .{},
- .extra = .{},
-
- .string_map = .{},
- .string_indices = .{},
- .string_bytes = .{},
- };
-
- pub fn init(pool: *Pool, allocator: std.mem.Allocator) !void {
- if (pool.string_indices.items.len == 0)
- try pool.string_indices.append(allocator, 0);
- }
-
- pub fn deinit(pool: *Pool, allocator: std.mem.Allocator) void {
- pool.map.deinit(allocator);
- pool.items.deinit(allocator);
- pool.extra.deinit(allocator);
-
- pool.string_map.deinit(allocator);
- pool.string_indices.deinit(allocator);
- pool.string_bytes.deinit(allocator);
-
- pool.* = undefined;
- }
-
- pub fn move(pool: *Pool) Pool {
- defer pool.* = empty;
- return pool.*;
- }
-
- pub fn clearRetainingCapacity(pool: *Pool) void {
- pool.map.clearRetainingCapacity();
- pool.items.shrinkRetainingCapacity(0);
- pool.extra.clearRetainingCapacity();
-
- pool.string_map.clearRetainingCapacity();
- pool.string_indices.shrinkRetainingCapacity(1);
- pool.string_bytes.clearRetainingCapacity();
- }
-
- pub fn freeUnusedCapacity(pool: *Pool, allocator: std.mem.Allocator) void {
- pool.map.shrinkAndFree(allocator, pool.map.count());
- pool.items.shrinkAndFree(allocator, pool.items.len);
- pool.extra.shrinkAndFree(allocator, pool.extra.items.len);
-
- pool.string_map.shrinkAndFree(allocator, pool.string_map.count());
- pool.string_indices.shrinkAndFree(allocator, pool.string_indices.items.len);
- pool.string_bytes.shrinkAndFree(allocator, pool.string_bytes.items.len);
- }
-
- pub fn getPointer(pool: *Pool, allocator: std.mem.Allocator, pointer_info: Info.Pointer) !CType {
- var hasher = Hasher.init;
- hasher.update(pointer_info.elem_ctype.hash(pool));
- return pool.getNonString(allocator, try pool.tagData(
- allocator,
- hasher,
- pointer_info.tag(),
- @intFromEnum(pointer_info.elem_ctype.index),
- ), pointer_info.nonstring);
- }
-
- pub fn getAligned(pool: *Pool, allocator: std.mem.Allocator, aligned_info: Info.Aligned) !CType {
- return pool.tagExtra(allocator, .aligned, Aligned, .{
- .ctype = aligned_info.ctype.index,
- .flags = .{ .alignas = aligned_info.alignas },
- });
- }
-
- pub fn getArray(pool: *Pool, allocator: std.mem.Allocator, array_info: Info.Sequence) !CType {
- return pool.getNonString(allocator, if (std.math.cast(u32, array_info.len)) |small_len|
- try pool.tagExtra(allocator, .array_small, SequenceSmall, .{
- .elem_ctype = array_info.elem_ctype.index,
- .len = small_len,
- })
- else
- try pool.tagExtra(allocator, .array_large, SequenceLarge, .{
- .elem_ctype = array_info.elem_ctype.index,
- .len_lo = @truncate(array_info.len >> 0),
- .len_hi = @truncate(array_info.len >> 32),
- }), array_info.nonstring);
- }
-
- pub fn getVector(pool: *Pool, allocator: std.mem.Allocator, vector_info: Info.Sequence) !CType {
- return pool.getNonString(allocator, try pool.tagExtra(allocator, .vector, SequenceSmall, .{
- .elem_ctype = vector_info.elem_ctype.index,
- .len = @intCast(vector_info.len),
- }), vector_info.nonstring);
- }
-
- pub fn getNonString(
- pool: *Pool,
- allocator: std.mem.Allocator,
- child_ctype: CType,
- nonstring: bool,
- ) !CType {
- if (!nonstring) return child_ctype;
- var hasher = Hasher.init;
- hasher.update(child_ctype.hash(pool));
- return pool.tagData(allocator, hasher, .nonstring, @intFromEnum(child_ctype.index));
- }
-
- pub fn getFwdDecl(
- pool: *Pool,
- allocator: std.mem.Allocator,
- fwd_decl_info: struct {
- tag: Info.AggregateTag,
- name: union(enum) {
- anon: []const Info.Field,
- index: InternPool.Index,
- },
- },
- ) !CType {
- var hasher = Hasher.init;
- switch (fwd_decl_info.name) {
- .anon => |fields| {
- const ExpectedContents = [32]CType;
- var stack align(@max(
- @alignOf(std.heap.StackFallbackAllocator(0)),
- @alignOf(ExpectedContents),
- )) = std.heap.stackFallback(@sizeOf(ExpectedContents), allocator);
- const stack_allocator = stack.get();
- const field_ctypes = try stack_allocator.alloc(CType, fields.len);
- defer stack_allocator.free(field_ctypes);
- for (field_ctypes, fields) |*field_ctype, field|
- field_ctype.* = try field.ctype.toForward(pool, allocator);
- const extra: FwdDeclAnon = .{ .fields_len = @intCast(fields.len) };
- const extra_index = try pool.addExtra(
- allocator,
- FwdDeclAnon,
- extra,
- fields.len * @typeInfo(Field).@"struct".fields.len,
- );
- for (fields, field_ctypes) |field, field_ctype| pool.addHashedExtraAssumeCapacity(
- &hasher,
- Field,
- .{
- .name = field.name.index,
- .ctype = field_ctype.index,
- .flags = .{ .alignas = field.alignas },
- },
- );
- hasher.updateExtra(FwdDeclAnon, extra, pool);
- return pool.tagTrailingExtra(allocator, hasher, switch (fwd_decl_info.tag) {
- .@"struct" => .fwd_decl_struct_anon,
- .@"union" => .fwd_decl_union_anon,
- .@"enum" => unreachable,
- }, extra_index);
- },
- .index => |index| {
- hasher.update(index);
- return pool.tagData(allocator, hasher, switch (fwd_decl_info.tag) {
- .@"struct" => .fwd_decl_struct,
- .@"union" => .fwd_decl_union,
- .@"enum" => unreachable,
- }, @intFromEnum(index));
- },
- }
- }
-
- pub fn getAggregate(
- pool: *Pool,
- allocator: std.mem.Allocator,
- aggregate_info: struct {
- tag: Info.AggregateTag,
- @"packed": bool = false,
- name: union(enum) {
- anon: struct {
- index: InternPool.Index,
- id: u32,
- },
- fwd_decl: CType,
- },
- fields: []const Info.Field,
- },
- ) !CType {
- var hasher = Hasher.init;
- switch (aggregate_info.name) {
- .anon => |anon| {
- const extra: AggregateAnon = .{
- .index = anon.index,
- .id = anon.id,
- .fields_len = @intCast(aggregate_info.fields.len),
- };
- const extra_index = try pool.addExtra(
- allocator,
- AggregateAnon,
- extra,
- aggregate_info.fields.len * @typeInfo(Field).@"struct".fields.len,
- );
- for (aggregate_info.fields) |field| pool.addHashedExtraAssumeCapacity(&hasher, Field, .{
- .name = field.name.index,
- .ctype = field.ctype.index,
- .flags = .{ .alignas = field.alignas },
- });
- hasher.updateExtra(AggregateAnon, extra, pool);
- return pool.tagTrailingExtra(allocator, hasher, switch (aggregate_info.tag) {
- .@"struct" => switch (aggregate_info.@"packed") {
- false => .aggregate_struct_anon,
- true => .aggregate_struct_packed_anon,
- },
- .@"union" => switch (aggregate_info.@"packed") {
- false => .aggregate_union_anon,
- true => .aggregate_union_packed_anon,
- },
- .@"enum" => unreachable,
- }, extra_index);
- },
- .fwd_decl => |fwd_decl| {
- const extra: Aggregate = .{
- .fwd_decl = fwd_decl.index,
- .fields_len = @intCast(aggregate_info.fields.len),
- };
- const extra_index = try pool.addExtra(
- allocator,
- Aggregate,
- extra,
- aggregate_info.fields.len * @typeInfo(Field).@"struct".fields.len,
- );
- for (aggregate_info.fields) |field| pool.addHashedExtraAssumeCapacity(&hasher, Field, .{
- .name = field.name.index,
- .ctype = field.ctype.index,
- .flags = .{ .alignas = field.alignas },
- });
- hasher.updateExtra(Aggregate, extra, pool);
- return pool.tagTrailingExtra(allocator, hasher, switch (aggregate_info.tag) {
- .@"struct" => switch (aggregate_info.@"packed") {
- false => .aggregate_struct,
- true => .aggregate_struct_packed,
- },
- .@"union" => switch (aggregate_info.@"packed") {
- false => .aggregate_union,
- true => .aggregate_union_packed,
- },
- .@"enum" => unreachable,
- }, extra_index);
- },
- }
- }
-
- pub fn getFunction(
- pool: *Pool,
- allocator: std.mem.Allocator,
- function_info: struct {
- return_ctype: CType,
- param_ctypes: []const CType,
- varargs: bool = false,
- },
- ) !CType {
- var hasher = Hasher.init;
- const extra: Function = .{
- .return_ctype = function_info.return_ctype.index,
- .param_ctypes_len = @intCast(function_info.param_ctypes.len),
- };
- const extra_index = try pool.addExtra(allocator, Function, extra, function_info.param_ctypes.len);
- for (function_info.param_ctypes) |param_ctype| {
- hasher.update(param_ctype.hash(pool));
- pool.extra.appendAssumeCapacity(@intFromEnum(param_ctype.index));
- }
- hasher.updateExtra(Function, extra, pool);
- return pool.tagTrailingExtra(allocator, hasher, switch (function_info.varargs) {
- false => .function,
- true => .function_varargs,
- }, extra_index);
- }
-
- pub fn fromFields(
- pool: *Pool,
- allocator: std.mem.Allocator,
- tag: Info.AggregateTag,
- fields: []Info.Field,
- kind: Kind,
- ) !CType {
- sortFields(fields);
- const fwd_decl = try pool.getFwdDecl(allocator, .{
- .tag = tag,
- .name = .{ .anon = fields },
- });
- return if (kind.isForward()) fwd_decl else pool.getAggregate(allocator, .{
- .tag = tag,
- .name = .{ .fwd_decl = fwd_decl },
- .fields = fields,
- });
- }
-
- pub fn fromIntInfo(
- pool: *Pool,
- allocator: std.mem.Allocator,
- int_info: std.builtin.Type.Int,
- mod: *Module,
- kind: Kind,
- ) !CType {
- switch (int_info.bits) {
- 0 => return .void,
- 1...8 => switch (int_info.signedness) {
- .signed => return .i8,
- .unsigned => return .u8,
- },
- 9...16 => switch (int_info.signedness) {
- .signed => return .i16,
- .unsigned => return .u16,
- },
- 17...32 => switch (int_info.signedness) {
- .signed => return .i32,
- .unsigned => return .u32,
- },
- 33...64 => switch (int_info.signedness) {
- .signed => return .i64,
- .unsigned => return .u64,
- },
- 65...128 => switch (int_info.signedness) {
- .signed => return .i128,
- .unsigned => return .u128,
- },
- else => {
- const target = &mod.resolved_target.result;
- const abi_align_bytes = std.zig.target.intAlignment(target, int_info.bits);
- const limb_ctype = try pool.fromIntInfo(allocator, .{
- .signedness = .unsigned,
- .bits = @intCast(abi_align_bytes * 8),
- }, mod, kind.noParameter());
- const array_ctype = try pool.getArray(allocator, .{
- .len = @divExact(std.zig.target.intByteSize(target, int_info.bits), abi_align_bytes),
- .elem_ctype = limb_ctype,
- .nonstring = limb_ctype.isAnyChar(),
- });
- if (!kind.isParameter()) return array_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = array_ctype,
- .alignas = AlignAs.fromAbiAlignment(.fromByteUnits(abi_align_bytes)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- }
- }
-
- pub fn fromType(
- pool: *Pool,
- allocator: std.mem.Allocator,
- scratch: *std.ArrayList(u32),
- ty: Type,
- pt: Zcu.PerThread,
- mod: *Module,
- kind: Kind,
- ) !CType {
- const ip = &pt.zcu.intern_pool;
- const zcu = pt.zcu;
- switch (ty.toIntern()) {
- .u0_type,
- .i0_type,
- .anyopaque_type,
- .void_type,
- .empty_tuple_type,
- .type_type,
- .comptime_int_type,
- .comptime_float_type,
- .null_type,
- .undefined_type,
- .enum_literal_type,
- .optional_type_type,
- .manyptr_const_type_type,
- .slice_const_type_type,
- => return .void,
- .u1_type, .u8_type => return .u8,
- .i8_type => return .i8,
- .u16_type => return .u16,
- .i16_type => return .i16,
- .u29_type, .u32_type => return .u32,
- .i32_type => return .i32,
- .u64_type => return .u64,
- .i64_type => return .i64,
- .u80_type, .u128_type => return .u128,
- .i128_type => return .i128,
- .u256_type => return pool.fromIntInfo(allocator, .{
- .signedness = .unsigned,
- .bits = 256,
- }, mod, kind),
- .usize_type => return .usize,
- .isize_type => return .isize,
- .c_char_type => return .{ .index = .char },
- .c_short_type => return .{ .index = .short },
- .c_ushort_type => return .{ .index = .@"unsigned short" },
- .c_int_type => return .{ .index = .int },
- .c_uint_type => return .{ .index = .@"unsigned int" },
- .c_long_type => return .{ .index = .long },
- .c_ulong_type => return .{ .index = .@"unsigned long" },
- .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 .f16,
- .f32_type => return .f32,
- .f64_type => return .f64,
- .f80_type => return .f80,
- .f128_type => return .f128,
- .bool_type, .optional_noreturn_type => return .bool,
- .noreturn_type,
- .anyframe_type,
- .generic_poison_type,
- => unreachable,
- .anyerror_type,
- .anyerror_void_error_union_type,
- .adhoc_inferred_error_set_type,
- => return pool.fromIntInfo(allocator, .{
- .signedness = .unsigned,
- .bits = pt.zcu.errorSetBits(),
- }, mod, kind),
-
- .ptr_usize_type => return pool.getPointer(allocator, .{
- .elem_ctype = .usize,
- }),
- .ptr_const_comptime_int_type => return pool.getPointer(allocator, .{
- .elem_ctype = .void,
- .@"const" = true,
- }),
- .manyptr_u8_type => return pool.getPointer(allocator, .{
- .elem_ctype = .u8,
- .nonstring = true,
- }),
- .manyptr_const_u8_type => return pool.getPointer(allocator, .{
- .elem_ctype = .u8,
- .@"const" = true,
- .nonstring = true,
- }),
- .manyptr_const_u8_sentinel_0_type => return pool.getPointer(allocator, .{
- .elem_ctype = .u8,
- .@"const" = true,
- }),
- .slice_const_u8_type => {
- const target = &mod.resolved_target.result;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .ptr },
- .ctype = try pool.getPointer(allocator, .{
- .elem_ctype = .u8,
- .@"const" = true,
- .nonstring = true,
- }),
- .alignas = AlignAs.fromAbiAlignment(Type.ptrAbiAlignment(target)),
- },
- .{
- .name = .{ .index = .len },
- .ctype = .usize,
- .alignas = AlignAs.fromAbiAlignment(
- .fromByteUnits(std.zig.target.intAlignment(target, target.ptrBitWidth())),
- ),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .slice_const_u8_sentinel_0_type => {
- const target = &mod.resolved_target.result;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .ptr },
- .ctype = try pool.getPointer(allocator, .{
- .elem_ctype = .u8,
- .@"const" = true,
- }),
- .alignas = AlignAs.fromAbiAlignment(Type.ptrAbiAlignment(target)),
- },
- .{
- .name = .{ .index = .len },
- .ctype = .usize,
- .alignas = AlignAs.fromAbiAlignment(
- .fromByteUnits(std.zig.target.intAlignment(target, target.ptrBitWidth())),
- ),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
-
- .manyptr_const_slice_const_u8_type => {
- const target = &mod.resolved_target.result;
- var fields: [2]Info.Field = .{
- .{
- .name = .{ .index = .ptr },
- .ctype = try pool.getPointer(allocator, .{
- .elem_ctype = .u8,
- .@"const" = true,
- .nonstring = true,
- }),
- .alignas = AlignAs.fromAbiAlignment(Type.ptrAbiAlignment(target)),
- },
- .{
- .name = .{ .index = .len },
- .ctype = .usize,
- .alignas = AlignAs.fromAbiAlignment(
- .fromByteUnits(std.zig.target.intAlignment(target, target.ptrBitWidth())),
- ),
- },
- };
- const slice_const_u8 = try pool.fromFields(allocator, .@"struct", &fields, kind);
- return pool.getPointer(allocator, .{
- .elem_ctype = slice_const_u8,
- .@"const" = true,
- });
- },
- .slice_const_slice_const_u8_type => {
- const target = &mod.resolved_target.result;
- var fields: [2]Info.Field = .{
- .{
- .name = .{ .index = .ptr },
- .ctype = try pool.getPointer(allocator, .{
- .elem_ctype = .u8,
- .@"const" = true,
- .nonstring = true,
- }),
- .alignas = AlignAs.fromAbiAlignment(Type.ptrAbiAlignment(target)),
- },
- .{
- .name = .{ .index = .len },
- .ctype = .usize,
- .alignas = AlignAs.fromAbiAlignment(
- .fromByteUnits(std.zig.target.intAlignment(target, target.ptrBitWidth())),
- ),
- },
- };
- const slice_const_u8 = try pool.fromFields(allocator, .@"struct", &fields, .forward);
- fields = .{
- .{
- .name = .{ .index = .ptr },
- .ctype = try pool.getPointer(allocator, .{
- .elem_ctype = slice_const_u8,
- .@"const" = true,
- }),
- .alignas = AlignAs.fromAbiAlignment(Type.ptrAbiAlignment(target)),
- },
- .{
- .name = .{ .index = .len },
- .ctype = .usize,
- .alignas = AlignAs.fromAbiAlignment(
- .fromByteUnits(std.zig.target.intAlignment(target, target.ptrBitWidth())),
- ),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
-
- .vector_8_i8_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .i8,
- .len = 8,
- .nonstring = true,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.i8.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_16_i8_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .i8,
- .len = 16,
- .nonstring = true,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.i8.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_32_i8_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .i8,
- .len = 32,
- .nonstring = true,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.i8.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_64_i8_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .i8,
- .len = 64,
- .nonstring = true,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.i8.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_1_u8_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .u8,
- .len = 1,
- .nonstring = true,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.u8.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_2_u8_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .u8,
- .len = 2,
- .nonstring = true,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.u8.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_4_u8_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .u8,
- .len = 4,
- .nonstring = true,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.u8.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_8_u8_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .u8,
- .len = 8,
- .nonstring = true,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.u8.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_16_u8_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .u8,
- .len = 16,
- .nonstring = true,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.u8.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_32_u8_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .u8,
- .len = 32,
- .nonstring = true,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.u8.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_64_u8_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .u8,
- .len = 64,
- .nonstring = true,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.u8.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_2_i16_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .i16,
- .len = 2,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.i16.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_4_i16_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .i16,
- .len = 4,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.i16.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_8_i16_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .i16,
- .len = 8,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.i16.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_16_i16_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .i16,
- .len = 16,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.i16.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_32_i16_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .i16,
- .len = 32,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.i16.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_4_u16_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .u16,
- .len = 4,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.u16.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_8_u16_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .u16,
- .len = 8,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.u16.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_16_u16_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .u16,
- .len = 16,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.u16.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_32_u16_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .u16,
- .len = 32,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.u16.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_2_i32_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .i32,
- .len = 2,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.i32.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_4_i32_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .i32,
- .len = 4,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.i32.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_8_i32_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .i32,
- .len = 8,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.i32.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_16_i32_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .i32,
- .len = 16,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.i32.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_4_u32_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .u32,
- .len = 4,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.u32.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_8_u32_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .u32,
- .len = 8,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.u32.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_16_u32_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .u32,
- .len = 16,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.u32.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_2_i64_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .i64,
- .len = 2,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.i64.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_4_i64_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .i64,
- .len = 4,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.i64.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_8_i64_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .i64,
- .len = 8,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.i64.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_2_u64_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .u64,
- .len = 2,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.u64.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_4_u64_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .u64,
- .len = 4,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.u64.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_8_u64_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .u64,
- .len = 8,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.u64.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_1_u128_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .u128,
- .len = 1,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.u128.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_2_u128_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .u128,
- .len = 2,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.u128.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_1_u256_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = try pool.fromIntInfo(allocator, .{
- .signedness = .unsigned,
- .bits = 256,
- }, mod, kind),
- .len = 1,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.u256.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_4_f16_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .f16,
- .len = 4,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.f16.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_8_f16_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .f16,
- .len = 8,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.f16.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_16_f16_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .f16,
- .len = 16,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.f16.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_32_f16_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .f16,
- .len = 32,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.f16.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_2_f32_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .f32,
- .len = 2,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.f32.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_4_f32_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .f32,
- .len = 4,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.f32.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_8_f32_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .f32,
- .len = 8,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.f32.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_16_f32_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .f32,
- .len = 16,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.f32.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_2_f64_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .f64,
- .len = 2,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.f64.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_4_f64_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .f64,
- .len = 4,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.f64.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_8_f64_type => {
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = .f64,
- .len = 8,
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(Type.f64.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
-
- .undef,
- .undef_bool,
- .undef_usize,
- .undef_u1,
- .zero,
- .zero_usize,
- .zero_u1,
- .zero_u8,
- .one,
- .one_usize,
- .one_u1,
- .one_u8,
- .four_u8,
- .negative_one,
- .void_value,
- .unreachable_value,
- .null_value,
- .bool_true,
- .bool_false,
- .empty_tuple,
- .none,
- => unreachable, // values, not types
-
- _ => |ip_index| switch (ip.indexToKey(ip_index)) {
- .int_type => |int_info| return pool.fromIntInfo(allocator, int_info, mod, kind),
- .ptr_type => |ptr_info| switch (ptr_info.flags.size) {
- .one, .many, .c => {
- const elem_ctype = elem_ctype: {
- if (ptr_info.packed_offset.host_size > 0 and
- ptr_info.flags.vector_index == .none)
- break :elem_ctype try pool.fromIntInfo(allocator, .{
- .signedness = .unsigned,
- .bits = ptr_info.packed_offset.host_size * 8,
- }, mod, .forward);
- const elem: Info.Aligned = .{
- .ctype = try pool.fromType(
- allocator,
- scratch,
- Type.fromInterned(ptr_info.child),
- pt,
- mod,
- .forward,
- ),
- .alignas = AlignAs.fromAlignment(.{
- .@"align" = ptr_info.flags.alignment,
- .abi = Type.fromInterned(ptr_info.child).abiAlignment(zcu),
- }),
- };
- break :elem_ctype if (elem.alignas.abiOrder().compare(.gte))
- elem.ctype
- else
- try pool.getAligned(allocator, elem);
- };
- const elem_tag: Info.Tag = switch (elem_ctype.info(pool)) {
- .aligned => |aligned_info| aligned_info.ctype.info(pool),
- else => |elem_tag| elem_tag,
- };
- return pool.getPointer(allocator, .{
- .elem_ctype = elem_ctype,
- .@"const" = switch (elem_tag) {
- .basic,
- .pointer,
- .aligned,
- .array,
- .vector,
- .fwd_decl,
- .aggregate,
- => ptr_info.flags.is_const,
- .function => false,
- },
- .@"volatile" = ptr_info.flags.is_volatile,
- .nonstring = elem_ctype.isAnyChar() and switch (ptr_info.sentinel) {
- .none => true,
- .zero_u8 => false,
- else => |sentinel| !Value.fromInterned(sentinel).compareAllWithZero(.eq, zcu),
- },
- });
- },
- .slice => {
- const target = &mod.resolved_target.result;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .ptr },
- .ctype = try pool.fromType(
- allocator,
- scratch,
- Type.fromInterned(ip.slicePtrType(ip_index)),
- pt,
- mod,
- kind,
- ),
- .alignas = AlignAs.fromAbiAlignment(Type.ptrAbiAlignment(target)),
- },
- .{
- .name = .{ .index = .len },
- .ctype = .usize,
- .alignas = AlignAs.fromAbiAlignment(
- .fromByteUnits(std.zig.target.intAlignment(target, target.ptrBitWidth())),
- ),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- },
- .array_type => |array_info| {
- const len = array_info.lenIncludingSentinel();
- if (len == 0) return .void;
- const elem_type = Type.fromInterned(array_info.child);
- const elem_ctype = try pool.fromType(
- allocator,
- scratch,
- elem_type,
- pt,
- mod,
- kind.noParameter().asComplete(),
- );
- if (elem_ctype.index == .void) return .void;
- const array_ctype = try pool.getArray(allocator, .{
- .elem_ctype = elem_ctype,
- .len = len,
- .nonstring = elem_ctype.isAnyChar() and switch (array_info.sentinel) {
- .none => true,
- .zero_u8 => false,
- else => |sentinel| !Value.fromInterned(sentinel).compareAllWithZero(.eq, zcu),
- },
- });
- if (!kind.isParameter()) return array_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = array_ctype,
- .alignas = AlignAs.fromAbiAlignment(elem_type.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .vector_type => |vector_info| {
- if (vector_info.len == 0) return .void;
- const elem_type = Type.fromInterned(vector_info.child);
- const elem_ctype = try pool.fromType(
- allocator,
- scratch,
- elem_type,
- pt,
- mod,
- kind.noParameter().asComplete(),
- );
- if (elem_ctype.index == .void) return .void;
- const vector_ctype = try pool.getVector(allocator, .{
- .elem_ctype = elem_ctype,
- .len = vector_info.len,
- .nonstring = elem_ctype.isAnyChar(),
- });
- if (!kind.isParameter()) return vector_ctype;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .array },
- .ctype = vector_ctype,
- .alignas = AlignAs.fromAbiAlignment(elem_type.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .opt_type => |payload_type| {
- if (ip.isNoReturn(payload_type)) return .void;
- const payload_ctype = try pool.fromType(
- allocator,
- scratch,
- Type.fromInterned(payload_type),
- pt,
- mod,
- kind.noParameter(),
- );
- if (payload_ctype.index == .void) return .bool;
- switch (payload_type) {
- .anyerror_type => return payload_ctype,
- else => switch (ip.indexToKey(payload_type)) {
- .ptr_type => |payload_ptr_info| if (payload_ptr_info.flags.size != .c and
- !payload_ptr_info.flags.is_allowzero) return payload_ctype,
- .error_set_type, .inferred_error_set_type => return payload_ctype,
- else => {},
- },
- }
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .is_null },
- .ctype = .bool,
- .alignas = AlignAs.fromAbiAlignment(.@"1"),
- },
- .{
- .name = .{ .index = .payload },
- .ctype = payload_ctype,
- .alignas = AlignAs.fromAbiAlignment(
- Type.fromInterned(payload_type).abiAlignment(zcu),
- ),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .anyframe_type => unreachable,
- .error_union_type => |error_union_info| {
- const error_set_bits = pt.zcu.errorSetBits();
- const error_set_ctype = try pool.fromIntInfo(allocator, .{
- .signedness = .unsigned,
- .bits = error_set_bits,
- }, mod, kind);
- if (ip.isNoReturn(error_union_info.payload_type)) return error_set_ctype;
- const payload_type = Type.fromInterned(error_union_info.payload_type);
- const payload_ctype = try pool.fromType(
- allocator,
- scratch,
- payload_type,
- pt,
- mod,
- kind.noParameter(),
- );
- if (payload_ctype.index == .void) return error_set_ctype;
- const target = &mod.resolved_target.result;
- var fields = [_]Info.Field{
- .{
- .name = .{ .index = .@"error" },
- .ctype = error_set_ctype,
- .alignas = AlignAs.fromAbiAlignment(
- .fromByteUnits(std.zig.target.intAlignment(target, error_set_bits)),
- ),
- },
- .{
- .name = .{ .index = .payload },
- .ctype = payload_ctype,
- .alignas = AlignAs.fromAbiAlignment(payload_type.abiAlignment(zcu)),
- },
- };
- return pool.fromFields(allocator, .@"struct", &fields, kind);
- },
- .simple_type => unreachable,
- .struct_type => {
- const loaded_struct = ip.loadStructType(ip_index);
- switch (loaded_struct.layout) {
- .auto, .@"extern" => {
- const fwd_decl = try pool.getFwdDecl(allocator, .{
- .tag = .@"struct",
- .name = .{ .index = ip_index },
- });
- if (kind.isForward()) return if (ty.hasRuntimeBitsIgnoreComptime(zcu))
- fwd_decl
- else
- .void;
- const scratch_top = scratch.items.len;
- defer scratch.shrinkRetainingCapacity(scratch_top);
- try scratch.ensureUnusedCapacity(
- allocator,
- loaded_struct.field_types.len * @typeInfo(Field).@"struct".fields.len,
- );
- var hasher = Hasher.init;
- var tag: Pool.Tag = .aggregate_struct;
- var field_it = loaded_struct.iterateRuntimeOrder(ip);
- while (field_it.next()) |field_index| {
- const field_type = Type.fromInterned(
- loaded_struct.field_types.get(ip)[field_index],
- );
- const field_ctype = try pool.fromType(
- allocator,
- scratch,
- field_type,
- pt,
- mod,
- kind.noParameter(),
- );
- if (field_ctype.index == .void) continue;
- const field_name = try pool.string(allocator, loaded_struct.fieldName(ip, field_index).toSlice(ip));
- const field_alignas = AlignAs.fromAlignment(.{
- .@"align" = loaded_struct.fieldAlign(ip, field_index),
- .abi = field_type.abiAlignment(zcu),
- });
- pool.addHashedExtraAssumeCapacityTo(scratch, &hasher, Field, .{
- .name = field_name.index,
- .ctype = field_ctype.index,
- .flags = .{ .alignas = field_alignas },
- });
- if (field_alignas.abiOrder().compare(.lt))
- tag = .aggregate_struct_packed;
- }
- const fields_len: u32 = @intCast(@divExact(
- scratch.items.len - scratch_top,
- @typeInfo(Field).@"struct".fields.len,
- ));
- if (fields_len == 0) return .void;
- try pool.ensureUnusedCapacity(allocator, 1);
- const extra_index = try pool.addHashedExtra(allocator, &hasher, Aggregate, .{
- .fwd_decl = fwd_decl.index,
- .fields_len = fields_len,
- }, fields_len * @typeInfo(Field).@"struct".fields.len);
- pool.extra.appendSliceAssumeCapacity(scratch.items[scratch_top..]);
- return pool.tagTrailingExtraAssumeCapacity(hasher, tag, extra_index);
- },
- .@"packed" => return pool.fromType(
- allocator,
- scratch,
- Type.fromInterned(loaded_struct.backingIntTypeUnordered(ip)),
- pt,
- mod,
- kind,
- ),
- }
- },
- .tuple_type => |tuple_info| {
- const scratch_top = scratch.items.len;
- defer scratch.shrinkRetainingCapacity(scratch_top);
- try scratch.ensureUnusedCapacity(allocator, tuple_info.types.len *
- @typeInfo(Field).@"struct".fields.len);
- var hasher = Hasher.init;
- for (0..tuple_info.types.len) |field_index| {
- if (tuple_info.values.get(ip)[field_index] != .none) continue;
- const field_type = Type.fromInterned(
- tuple_info.types.get(ip)[field_index],
- );
- const field_ctype = try pool.fromType(
- allocator,
- scratch,
- field_type,
- pt,
- mod,
- kind.noParameter(),
- );
- if (field_ctype.index == .void) continue;
- const field_name = try pool.fmt(allocator, "f{d}", .{field_index});
- pool.addHashedExtraAssumeCapacityTo(scratch, &hasher, Field, .{
- .name = field_name.index,
- .ctype = field_ctype.index,
- .flags = .{ .alignas = AlignAs.fromAbiAlignment(
- field_type.abiAlignment(zcu),
- ) },
- });
- }
- const fields_len: u32 = @intCast(@divExact(
- scratch.items.len - scratch_top,
- @typeInfo(Field).@"struct".fields.len,
- ));
- if (fields_len == 0) return .void;
- if (kind.isForward()) {
- try pool.ensureUnusedCapacity(allocator, 1);
- const extra_index = try pool.addHashedExtra(
- allocator,
- &hasher,
- FwdDeclAnon,
- .{ .fields_len = fields_len },
- fields_len * @typeInfo(Field).@"struct".fields.len,
- );
- pool.extra.appendSliceAssumeCapacity(scratch.items[scratch_top..]);
- return pool.tagTrailingExtra(
- allocator,
- hasher,
- .fwd_decl_struct_anon,
- extra_index,
- );
- }
- const fwd_decl = try pool.fromType(allocator, scratch, ty, pt, mod, .forward);
- try pool.ensureUnusedCapacity(allocator, 1);
- const extra_index = try pool.addHashedExtra(allocator, &hasher, Aggregate, .{
- .fwd_decl = fwd_decl.index,
- .fields_len = fields_len,
- }, fields_len * @typeInfo(Field).@"struct".fields.len);
- pool.extra.appendSliceAssumeCapacity(scratch.items[scratch_top..]);
- return pool.tagTrailingExtraAssumeCapacity(hasher, .aggregate_struct, extra_index);
- },
- .union_type => {
- const loaded_union = ip.loadUnionType(ip_index);
- switch (loaded_union.flagsUnordered(ip).layout) {
- .auto, .@"extern" => {
- const has_tag = loaded_union.hasTag(ip);
- const fwd_decl = try pool.getFwdDecl(allocator, .{
- .tag = if (has_tag) .@"struct" else .@"union",
- .name = .{ .index = ip_index },
- });
- if (kind.isForward()) return if (ty.hasRuntimeBitsIgnoreComptime(zcu))
- fwd_decl
- else
- .void;
- const loaded_tag = loaded_union.loadTagType(ip);
- const scratch_top = scratch.items.len;
- defer scratch.shrinkRetainingCapacity(scratch_top);
- try scratch.ensureUnusedCapacity(
- allocator,
- loaded_union.field_types.len * @typeInfo(Field).@"struct".fields.len,
- );
- var hasher = Hasher.init;
- var tag: Pool.Tag = .aggregate_union;
- var payload_align: InternPool.Alignment = .@"1";
- for (0..loaded_union.field_types.len) |field_index| {
- const field_type = Type.fromInterned(
- loaded_union.field_types.get(ip)[field_index],
- );
- if (ip.isNoReturn(field_type.toIntern())) continue;
- const field_ctype = try pool.fromType(
- allocator,
- scratch,
- field_type,
- pt,
- mod,
- kind.noParameter(),
- );
- if (field_ctype.index == .void) continue;
- const field_name = try pool.string(
- allocator,
- loaded_tag.names.get(ip)[field_index].toSlice(ip),
- );
- const field_alignas = AlignAs.fromAlignment(.{
- .@"align" = loaded_union.fieldAlign(ip, field_index),
- .abi = field_type.abiAlignment(zcu),
- });
- pool.addHashedExtraAssumeCapacityTo(scratch, &hasher, Field, .{
- .name = field_name.index,
- .ctype = field_ctype.index,
- .flags = .{ .alignas = field_alignas },
- });
- if (field_alignas.abiOrder().compare(.lt))
- tag = .aggregate_union_packed;
- payload_align = payload_align.maxStrict(field_alignas.@"align");
- }
- const fields_len: u32 = @intCast(@divExact(
- scratch.items.len - scratch_top,
- @typeInfo(Field).@"struct".fields.len,
- ));
- if (!has_tag) {
- if (fields_len == 0) return .void;
- try pool.ensureUnusedCapacity(allocator, 1);
- const extra_index = try pool.addHashedExtra(
- allocator,
- &hasher,
- Aggregate,
- .{ .fwd_decl = fwd_decl.index, .fields_len = fields_len },
- fields_len * @typeInfo(Field).@"struct".fields.len,
- );
- pool.extra.appendSliceAssumeCapacity(scratch.items[scratch_top..]);
- return pool.tagTrailingExtraAssumeCapacity(hasher, tag, extra_index);
- }
- try pool.ensureUnusedCapacity(allocator, 2);
- var struct_fields: [2]Info.Field = undefined;
- var struct_fields_len: usize = 0;
- if (loaded_tag.tag_ty != .comptime_int_type) {
- const tag_type = Type.fromInterned(loaded_tag.tag_ty);
- const tag_ctype: CType = try pool.fromType(
- allocator,
- scratch,
- tag_type,
- pt,
- mod,
- kind.noParameter(),
- );
- if (tag_ctype.index != .void) {
- struct_fields[struct_fields_len] = .{
- .name = .{ .index = .tag },
- .ctype = tag_ctype,
- .alignas = AlignAs.fromAbiAlignment(tag_type.abiAlignment(zcu)),
- };
- struct_fields_len += 1;
- }
- }
- if (fields_len > 0) {
- const payload_ctype = payload_ctype: {
- const extra_index = try pool.addHashedExtra(
- allocator,
- &hasher,
- AggregateAnon,
- .{
- .index = ip_index,
- .id = 0,
- .fields_len = fields_len,
- },
- fields_len * @typeInfo(Field).@"struct".fields.len,
- );
- pool.extra.appendSliceAssumeCapacity(scratch.items[scratch_top..]);
- break :payload_ctype pool.tagTrailingExtraAssumeCapacity(
- hasher,
- switch (tag) {
- .aggregate_union => .aggregate_union_anon,
- .aggregate_union_packed => .aggregate_union_packed_anon,
- else => unreachable,
- },
- extra_index,
- );
- };
- if (payload_ctype.index != .void) {
- struct_fields[struct_fields_len] = .{
- .name = .{ .index = .payload },
- .ctype = payload_ctype,
- .alignas = AlignAs.fromAbiAlignment(payload_align),
- };
- struct_fields_len += 1;
- }
- }
- if (struct_fields_len == 0) return .void;
- sortFields(struct_fields[0..struct_fields_len]);
- return pool.getAggregate(allocator, .{
- .tag = .@"struct",
- .name = .{ .fwd_decl = fwd_decl },
- .fields = struct_fields[0..struct_fields_len],
- });
- },
- .@"packed" => return pool.fromIntInfo(allocator, .{
- .signedness = .unsigned,
- .bits = @intCast(ty.bitSize(zcu)),
- }, mod, kind),
- }
- },
- .opaque_type => return .void,
- .enum_type => return pool.fromType(
- allocator,
- scratch,
- Type.fromInterned(ip.loadEnumType(ip_index).tag_ty),
- pt,
- mod,
- kind,
- ),
- .func_type => |func_info| if (func_info.is_generic) return .void else {
- const scratch_top = scratch.items.len;
- defer scratch.shrinkRetainingCapacity(scratch_top);
- try scratch.ensureUnusedCapacity(allocator, func_info.param_types.len);
- var hasher = Hasher.init;
- const return_type = Type.fromInterned(func_info.return_type);
- const return_ctype: CType =
- if (!ip.isNoReturn(func_info.return_type)) try pool.fromType(
- allocator,
- scratch,
- return_type,
- pt,
- mod,
- kind.asParameter(),
- ) else .void;
- for (0..func_info.param_types.len) |param_index| {
- const param_type = Type.fromInterned(
- func_info.param_types.get(ip)[param_index],
- );
- const param_ctype = try pool.fromType(
- allocator,
- scratch,
- param_type,
- pt,
- mod,
- kind.asParameter(),
- );
- if (param_ctype.index == .void) continue;
- hasher.update(param_ctype.hash(pool));
- scratch.appendAssumeCapacity(@intFromEnum(param_ctype.index));
- }
- const param_ctypes_len: u32 = @intCast(scratch.items.len - scratch_top);
- try pool.ensureUnusedCapacity(allocator, 1);
- const extra_index = try pool.addHashedExtra(allocator, &hasher, Function, .{
- .return_ctype = return_ctype.index,
- .param_ctypes_len = param_ctypes_len,
- }, param_ctypes_len);
- pool.extra.appendSliceAssumeCapacity(scratch.items[scratch_top..]);
- return pool.tagTrailingExtraAssumeCapacity(hasher, switch (func_info.is_var_args) {
- false => .function,
- true => .function_varargs,
- }, extra_index);
- },
- .error_set_type,
- .inferred_error_set_type,
- => return pool.fromIntInfo(allocator, .{
- .signedness = .unsigned,
- .bits = pt.zcu.errorSetBits(),
- }, mod, kind),
-
- .undef,
- .simple_value,
- .variable,
- .@"extern",
- .func,
- .int,
- .err,
- .error_union,
- .enum_literal,
- .enum_tag,
- .empty_enum_value,
- .float,
- .ptr,
- .slice,
- .opt,
- .aggregate,
- .un,
- .memoized_call,
- => unreachable, // values, not types
- },
- }
- }
-
- pub fn getOrPutAdapted(
- pool: *Pool,
- allocator: std.mem.Allocator,
- source_pool: *const Pool,
- source_ctype: CType,
- pool_adapter: anytype,
- ) !struct { CType, bool } {
- const tag = source_pool.items.items(.tag)[
- source_ctype.toPoolIndex() orelse return .{ source_ctype, true }
- ];
- try pool.ensureUnusedCapacity(allocator, 1);
- const CTypeAdapter = struct {
- pool: *const Pool,
- source_pool: *const Pool,
- source_info: Info,
- pool_adapter: @TypeOf(pool_adapter),
- pub fn hash(map_adapter: @This(), key_ctype: CType) Map.Hash {
- return key_ctype.hash(map_adapter.source_pool);
- }
- pub fn eql(map_adapter: @This(), _: CType, _: void, pool_index: usize) bool {
- return map_adapter.source_info.eqlAdapted(
- map_adapter.source_pool,
- .fromPoolIndex(pool_index),
- map_adapter.pool,
- map_adapter.pool_adapter,
- );
- }
- };
- const source_info = source_ctype.info(source_pool);
- const gop = pool.map.getOrPutAssumeCapacityAdapted(source_ctype, CTypeAdapter{
- .pool = pool,
- .source_pool = source_pool,
- .source_info = source_info,
- .pool_adapter = pool_adapter,
- });
- errdefer _ = pool.map.pop();
- const ctype: CType = .fromPoolIndex(gop.index);
- if (!gop.found_existing) switch (source_info) {
- .basic => unreachable,
- .pointer => |pointer_info| pool.items.appendAssumeCapacity(switch (pointer_info.nonstring) {
- false => .{
- .tag = tag,
- .data = @intFromEnum(pool_adapter.copy(pointer_info.elem_ctype).index),
- },
- true => .{
- .tag = .nonstring,
- .data = @intFromEnum(pool_adapter.copy(.{ .index = @enumFromInt(
- source_pool.items.items(.data)[source_ctype.toPoolIndex().?],
- ) }).index),
- },
- }),
- .aligned => |aligned_info| pool.items.appendAssumeCapacity(.{
- .tag = tag,
- .data = try pool.addExtra(allocator, Aligned, .{
- .ctype = pool_adapter.copy(aligned_info.ctype).index,
- .flags = .{ .alignas = aligned_info.alignas },
- }, 0),
- }),
- .array, .vector => |sequence_info| pool.items.appendAssumeCapacity(switch (sequence_info.nonstring) {
- false => .{
- .tag = tag,
- .data = switch (tag) {
- .array_small, .vector => try pool.addExtra(allocator, SequenceSmall, .{
- .elem_ctype = pool_adapter.copy(sequence_info.elem_ctype).index,
- .len = @intCast(sequence_info.len),
- }, 0),
- .array_large => try pool.addExtra(allocator, SequenceLarge, .{
- .elem_ctype = pool_adapter.copy(sequence_info.elem_ctype).index,
- .len_lo = @truncate(sequence_info.len >> 0),
- .len_hi = @truncate(sequence_info.len >> 32),
- }, 0),
- else => unreachable,
- },
- },
- true => .{
- .tag = .nonstring,
- .data = @intFromEnum(pool_adapter.copy(.{ .index = @enumFromInt(
- source_pool.items.items(.data)[source_ctype.toPoolIndex().?],
- ) }).index),
- },
- }),
- .fwd_decl => |fwd_decl_info| switch (fwd_decl_info.name) {
- .anon => |fields| {
- pool.items.appendAssumeCapacity(.{
- .tag = tag,
- .data = try pool.addExtra(allocator, FwdDeclAnon, .{
- .fields_len = fields.len,
- }, fields.len * @typeInfo(Field).@"struct".fields.len),
- });
- for (0..fields.len) |field_index| {
- const field = fields.at(field_index, 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,
- .flags = .{ .alignas = field.alignas },
- });
- }
- },
- .index => |index| pool.items.appendAssumeCapacity(.{
- .tag = tag,
- .data = @intFromEnum(index),
- }),
- },
- .aggregate => |aggregate_info| {
- pool.items.appendAssumeCapacity(.{
- .tag = tag,
- .data = switch (aggregate_info.name) {
- .anon => |anon| try pool.addExtra(allocator, AggregateAnon, .{
- .index = anon.index,
- .id = anon.id,
- .fields_len = aggregate_info.fields.len,
- }, aggregate_info.fields.len * @typeInfo(Field).@"struct".fields.len),
- .fwd_decl => |fwd_decl| try pool.addExtra(allocator, Aggregate, .{
- .fwd_decl = pool_adapter.copy(fwd_decl).index,
- .fields_len = aggregate_info.fields.len,
- }, aggregate_info.fields.len * @typeInfo(Field).@"struct".fields.len),
- },
- });
- for (0..aggregate_info.fields.len) |field_index| {
- const field = aggregate_info.fields.at(field_index, 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,
- .flags = .{ .alignas = field.alignas },
- });
- }
- },
- .function => |function_info| {
- pool.items.appendAssumeCapacity(.{
- .tag = tag,
- .data = try pool.addExtra(allocator, Function, .{
- .return_ctype = pool_adapter.copy(function_info.return_ctype).index,
- .param_ctypes_len = function_info.param_ctypes.len,
- }, function_info.param_ctypes.len),
- });
- for (0..function_info.param_ctypes.len) |param_index| pool.extra.appendAssumeCapacity(
- @intFromEnum(pool_adapter.copy(
- function_info.param_ctypes.at(param_index, source_pool),
- ).index),
- );
- },
- };
- assert(source_info.eqlAdapted(source_pool, ctype, pool, pool_adapter));
- assert(source_ctype.hash(source_pool) == ctype.hash(pool));
- return .{ ctype, gop.found_existing };
- }
-
- pub fn string(pool: *Pool, allocator: std.mem.Allocator, slice: []const u8) !String {
- try pool.string_bytes.appendSlice(allocator, slice);
- return pool.trailingString(allocator);
- }
-
- pub fn fmt(
- pool: *Pool,
- allocator: std.mem.Allocator,
- comptime fmt_str: []const u8,
- fmt_args: anytype,
- ) !String {
- try pool.string_bytes.print(allocator, fmt_str, fmt_args);
- return pool.trailingString(allocator);
- }
-
- fn ensureUnusedCapacity(pool: *Pool, allocator: std.mem.Allocator, len: u32) !void {
- try pool.map.ensureUnusedCapacity(allocator, len);
- try pool.items.ensureUnusedCapacity(allocator, len);
- }
-
- const Hasher = struct {
- const Impl = std.hash.Wyhash;
- impl: Impl,
-
- const init: Hasher = .{ .impl = Impl.init(0) };
-
- 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);
- switch (field.type) {
- Pool.Tag, String, CType => unreachable,
- 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 {
- switch (@TypeOf(data)) {
- Pool.Tag => @compileError("pass tag to final"),
- CType, CType.Index => @compileError("hash ctype.hash(pool) instead"),
- String, String.Index => @compileError("hash string.slice(pool) instead"),
- u32, InternPool.Index, Aligned.Flags => hasher.impl.update(std.mem.asBytes(&data)),
- []const u8 => hasher.impl.update(data),
- else => @compileError("unhandled type: " ++ @typeName(@TypeOf(data))),
- }
- }
-
- fn final(hasher: Hasher, tag: Pool.Tag) Map.Hash {
- var impl = hasher.impl;
- impl.update(std.mem.asBytes(&tag));
- return @truncate(impl.final());
- }
- };
-
- fn tagData(
- pool: *Pool,
- allocator: std.mem.Allocator,
- hasher: Hasher,
- tag: Pool.Tag,
- data: u32,
- ) !CType {
- try pool.ensureUnusedCapacity(allocator, 1);
- const Key = struct { hash: Map.Hash, tag: Pool.Tag, data: u32 };
- const CTypeAdapter = struct {
- pool: *const Pool,
- pub fn hash(_: @This(), key: Key) Map.Hash {
- return key.hash;
- }
- pub fn eql(ctype_adapter: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
- const rhs_item = ctype_adapter.pool.items.get(rhs_index);
- return lhs_key.tag == rhs_item.tag and lhs_key.data == rhs_item.data;
- }
- };
- const gop = pool.map.getOrPutAssumeCapacityAdapted(
- Key{ .hash = hasher.final(tag), .tag = tag, .data = data },
- CTypeAdapter{ .pool = pool },
- );
- if (!gop.found_existing) pool.items.appendAssumeCapacity(.{ .tag = tag, .data = data });
- return .fromPoolIndex(gop.index);
- }
-
- fn tagExtra(
- pool: *Pool,
- allocator: std.mem.Allocator,
- tag: Pool.Tag,
- comptime Extra: type,
- extra: Extra,
- ) !CType {
- var hasher = Hasher.init;
- hasher.updateExtra(Extra, extra, pool);
- return pool.tagTrailingExtra(
- allocator,
- hasher,
- tag,
- try pool.addExtra(allocator, Extra, extra, 0),
- );
- }
-
- fn tagTrailingExtra(
- pool: *Pool,
- allocator: std.mem.Allocator,
- hasher: Hasher,
- tag: Pool.Tag,
- extra_index: ExtraIndex,
- ) !CType {
- try pool.ensureUnusedCapacity(allocator, 1);
- return pool.tagTrailingExtraAssumeCapacity(hasher, tag, extra_index);
- }
-
- fn tagTrailingExtraAssumeCapacity(
- pool: *Pool,
- hasher: Hasher,
- tag: Pool.Tag,
- extra_index: ExtraIndex,
- ) CType {
- const Key = struct { hash: Map.Hash, tag: Pool.Tag, extra: []const u32 };
- const CTypeAdapter = struct {
- pool: *const Pool,
- pub fn hash(_: @This(), key: Key) Map.Hash {
- return key.hash;
- }
- pub fn eql(ctype_adapter: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
- const rhs_item = ctype_adapter.pool.items.get(rhs_index);
- if (lhs_key.tag != rhs_item.tag) return false;
- const rhs_extra = ctype_adapter.pool.extra.items[rhs_item.data..];
- return std.mem.startsWith(u32, rhs_extra, lhs_key.extra);
- }
- };
- const gop = pool.map.getOrPutAssumeCapacityAdapted(
- Key{ .hash = hasher.final(tag), .tag = tag, .extra = pool.extra.items[extra_index..] },
- CTypeAdapter{ .pool = pool },
- );
- if (gop.found_existing)
- pool.extra.shrinkRetainingCapacity(extra_index)
- else
- pool.items.appendAssumeCapacity(.{ .tag = tag, .data = extra_index });
- return .fromPoolIndex(gop.index);
- }
-
- fn sortFields(fields: []Info.Field) void {
- std.mem.sort(Info.Field, fields, {}, struct {
- fn before(_: void, lhs_field: Info.Field, rhs_field: Info.Field) bool {
- return lhs_field.alignas.order(rhs_field.alignas).compare(.gt);
- }
- }.before);
- }
-
- fn trailingString(pool: *Pool, allocator: std.mem.Allocator) !String {
- 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 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 String.fromPoolIndex(gop.index);
- }
-
- const Item = struct {
- tag: Pool.Tag,
- data: u32,
- };
-
- const ExtraIndex = u32;
-
- const Tag = enum(u8) {
- basic,
- pointer,
- pointer_const,
- pointer_volatile,
- pointer_const_volatile,
- aligned,
- array_small,
- array_large,
- vector,
- nonstring,
- fwd_decl_struct_anon,
- fwd_decl_union_anon,
- fwd_decl_struct,
- fwd_decl_union,
- aggregate_struct_anon,
- aggregate_struct_packed_anon,
- aggregate_union_anon,
- aggregate_union_packed_anon,
- aggregate_struct,
- aggregate_struct_packed,
- aggregate_union,
- aggregate_union_packed,
- function,
- function_varargs,
- };
-
- const Aligned = struct {
- ctype: CType.Index,
- flags: Flags,
-
- const Flags = packed struct(u32) {
- alignas: AlignAs,
- _: u20 = 0,
- };
- };
-
- const SequenceSmall = struct {
- elem_ctype: CType.Index,
- len: u32,
- };
-
- const SequenceLarge = struct {
- elem_ctype: CType.Index,
- len_lo: u32,
- len_hi: u32,
-
- fn len(extra: SequenceLarge) u64 {
- return @as(u64, extra.len_lo) << 0 |
- @as(u64, extra.len_hi) << 32;
- }
- };
-
- const Field = struct {
- name: String.Index,
- ctype: CType.Index,
- flags: Flags,
-
- const Flags = Aligned.Flags;
- };
-
- const FwdDeclAnon = struct {
- fields_len: u32,
- };
-
- const AggregateAnon = struct {
- index: InternPool.Index,
- id: u32,
- fields_len: u32,
- };
-
- const Aggregate = struct {
- fwd_decl: CType.Index,
- fields_len: u32,
- };
-
- const Function = struct {
- return_ctype: CType.Index,
- param_ctypes_len: u32,
- };
-
- fn addExtra(
- pool: *Pool,
- allocator: std.mem.Allocator,
- comptime Extra: type,
- extra: Extra,
- trailing_len: usize,
- ) !ExtraIndex {
- try pool.extra.ensureUnusedCapacity(
- allocator,
- @typeInfo(Extra).@"struct".fields.len + trailing_len,
- );
- defer pool.addExtraAssumeCapacity(Extra, extra);
- return @intCast(pool.extra.items.len);
- }
- fn addExtraAssumeCapacity(pool: *Pool, comptime Extra: type, extra: Extra) void {
- addExtraAssumeCapacityTo(&pool.extra, Extra, extra);
- }
- fn addExtraAssumeCapacityTo(
- array: *std.ArrayList(u32),
- comptime Extra: type,
- extra: Extra,
- ) void {
- inline for (@typeInfo(Extra).@"struct".fields) |field| {
- const value = @field(extra, field.name);
- array.appendAssumeCapacity(switch (field.type) {
- u32 => value,
- CType.Index, String.Index, InternPool.Index => @intFromEnum(value),
- Aligned.Flags => @bitCast(value),
- else => @compileError("bad field type: " ++ field.name ++ ": " ++
- @typeName(field.type)),
- });
- }
- }
-
- fn addHashedExtra(
- pool: *Pool,
- allocator: std.mem.Allocator,
- hasher: *Hasher,
- comptime Extra: type,
- extra: Extra,
- trailing_len: usize,
- ) !ExtraIndex {
- hasher.updateExtra(Extra, extra, pool);
- return pool.addExtra(allocator, Extra, extra, trailing_len);
- }
- fn addHashedExtraAssumeCapacity(
- pool: *Pool,
- hasher: *Hasher,
- comptime Extra: type,
- extra: Extra,
- ) void {
- hasher.updateExtra(Extra, extra, pool);
- pool.addExtraAssumeCapacity(Extra, extra);
- }
- fn addHashedExtraAssumeCapacityTo(
- pool: *Pool,
- array: *std.ArrayList(u32),
- hasher: *Hasher,
- comptime Extra: type,
- extra: Extra,
- ) void {
- hasher.updateExtra(Extra, extra, pool);
- addExtraAssumeCapacityTo(array, Extra, extra);
- }
-
- const ExtraTrail = struct {
- extra_index: ExtraIndex,
-
- fn next(
- extra_trail: *ExtraTrail,
- len: u32,
- comptime Extra: type,
- pool: *const Pool,
- ) []const Extra {
- defer extra_trail.extra_index += @intCast(len);
- return @ptrCast(pool.extra.items[extra_trail.extra_index..][0..len]);
- }
- };
-
- fn getExtraTrail(
- pool: *const Pool,
- comptime Extra: type,
- extra_index: ExtraIndex,
- ) struct { extra: Extra, trail: ExtraTrail } {
- var extra: Extra = undefined;
- const fields = @typeInfo(Extra).@"struct".fields;
- inline for (fields, pool.extra.items[extra_index..][0..fields.len]) |field, value|
- @field(extra, field.name) = switch (field.type) {
- u32 => value,
- CType.Index, String.Index, InternPool.Index => @enumFromInt(value),
- Aligned.Flags => @bitCast(value),
- else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),
- };
- return .{
- .extra = extra,
- .trail = .{ .extra_index = extra_index + @as(ExtraIndex, @intCast(fields.len)) },
- };
- }
-
- fn getExtra(pool: *const Pool, comptime Extra: type, extra_index: ExtraIndex) Extra {
- return pool.getExtraTrail(Extra, extra_index).extra;
- }
-};
-
-pub const AlignAs = packed struct {
- @"align": InternPool.Alignment,
- abi: InternPool.Alignment,
-
- pub fn fromAlignment(alignas: AlignAs) AlignAs {
- assert(alignas.abi != .none);
- return .{
- .@"align" = if (alignas.@"align" != .none) alignas.@"align" else alignas.abi,
- .abi = alignas.abi,
- };
- }
- pub fn fromAbiAlignment(abi: InternPool.Alignment) AlignAs {
- assert(abi != .none);
- return .{ .@"align" = abi, .abi = abi };
- }
- pub fn fromByteUnits(@"align": u64, abi: u64) AlignAs {
- return fromAlignment(.{
- .@"align" = InternPool.Alignment.fromByteUnits(@"align"),
- .abi = InternPool.Alignment.fromNonzeroByteUnits(abi),
- });
- }
-
- pub fn order(lhs: AlignAs, rhs: AlignAs) std.math.Order {
- return lhs.@"align".order(rhs.@"align");
- }
- pub fn abiOrder(alignas: AlignAs) std.math.Order {
- return alignas.@"align".order(alignas.abi);
- }
- pub fn toByteUnits(alignas: AlignAs) u64 {
- return alignas.@"align".toByteUnits().?;
- }
-};
-
-const std = @import("std");
-const assert = std.debug.assert;
-const Writer = std.Io.Writer;
-
-const CType = @This();
-const InternPool = @import("../../InternPool.zig");
-const Module = @import("../../Package/Module.zig");
-const Type = @import("../../Type.zig");
-const Value = @import("../../Value.zig");
-const Zcu = @import("../../Zcu.zig");
diff --git a/src/codegen/c/type.zig b/src/codegen/c/type.zig
new file mode 100644
index 0000000000000000000000000000000000000000..7a12a343f999179845a96febeaa15557605162e1
--- /dev/null
+++ b/src/codegen/c/type.zig
@@ -0,0 +1,1023 @@
+pub const CType = union(enum) {
+ pub const render_defs = @import("type/render_defs.zig");
+
+ // The first nodes are primitive types (or standard typedefs).
+
+ void,
+ bool,
+ int: Int,
+ float: Float,
+
+ // These next nodes are all typedefs, structs, or unions.
+
+ @"fn": Type,
+ @"enum": Type,
+ bitpack: Type,
+ @"struct": Type,
+ union_auto: Type,
+ union_extern: Type,
+ slice: Type,
+ opt: Type,
+ arr: Type,
+ vec: Type,
+ errunion: struct { payload_ty: Type },
+ aligned: struct {
+ ty: Type,
+ alignment: InternPool.Alignment,
+ },
+ bigint: BigInt,
+
+ // The remaining nodes have children.
+
+ pointer: struct {
+ @"const": bool,
+ @"volatile": bool,
+ elem_ty: *const CType,
+ nonstring: bool,
+ },
+ array: struct {
+ len: u64,
+ elem_ty: *const CType,
+ nonstring: bool,
+ },
+ function: struct {
+ param_tys: []const CType,
+ ret_ty: *const CType,
+ varargs: bool,
+ },
+
+ /// Returns `true` if this node has a postfix operator, meaning an `[...]` or `(...)` appears
+ /// after the identifier in a declarator with this type. In this case, if this node is wrapped
+ /// in a pointer type, we will need to add parentheses due to operator precedence.
+ ///
+ /// For instance, when lowering a Zig declaration `foo: *const fn (c_int) void`, it would be a
+ /// bug to write the C declarator as `void *foo(int)`, because the `(int)` suffix declaring the
+ /// function type has higher precedence than the `*` prefix declaring the pointer type. Instead,
+ /// this type must be lowered as `void (*foo)(int)`.
+ fn kind(cty: *const CType) enum {
+ /// `cty` is just a C type specifier, i.e. a typedef or a named struct/union type.
+ specifier,
+ /// `cty` is a C function or array type. It will have a postfix "operator" in its suffix to
+ /// declare the type, either `(...)` (for a function type) or `[...]` (for an array type).
+ postfix_op,
+ /// `cty` is a C pointer type. Its prefix will end with "*".
+ pointer,
+ } {
+ return switch (cty.*) {
+ .void,
+ .bool,
+ .int,
+ .float,
+ .@"fn",
+ .@"enum",
+ .bitpack,
+ .@"struct",
+ .union_auto,
+ .union_extern,
+ .slice,
+ .opt,
+ .arr,
+ .vec,
+ .errunion,
+ .aligned,
+ .bigint,
+ => .specifier,
+
+ .array,
+ .function,
+ => .postfix_op,
+
+ .pointer => .pointer,
+ };
+ }
+
+ pub const Int = enum {
+ char,
+
+ @"unsigned short",
+ @"unsigned int",
+ @"unsigned long",
+ @"unsigned long long",
+
+ @"signed short",
+ @"signed int",
+ @"signed long",
+ @"signed long long",
+
+ uint8_t,
+ uint16_t,
+ uint32_t,
+ uint64_t,
+ zig_u128,
+
+ int8_t,
+ int16_t,
+ int32_t,
+ int64_t,
+ zig_i128,
+
+ uintptr_t,
+ intptr_t,
+
+ pub fn bits(int: Int, target: *const std.Target) u16 {
+ return switch (int) {
+ // zig fmt: off
+ .char => target.cTypeBitSize(.char),
+
+ .@"unsigned short" => target.cTypeBitSize(.ushort),
+ .@"unsigned int" => target.cTypeBitSize(.uint),
+ .@"unsigned long" => target.cTypeBitSize(.ulong),
+ .@"unsigned long long" => target.cTypeBitSize(.ulonglong),
+
+ .@"signed short" => target.cTypeBitSize(.short),
+ .@"signed int" => target.cTypeBitSize(.int),
+ .@"signed long" => target.cTypeBitSize(.long),
+ .@"signed long long" => target.cTypeBitSize(.longlong),
+
+ .uintptr_t, .intptr_t => target.ptrBitWidth(),
+
+ .uint8_t, .int8_t => 8,
+ .uint16_t, .int16_t => 16,
+ .uint32_t, .int32_t => 32,
+ .uint64_t, .int64_t => 64,
+ .zig_u128, .zig_i128 => 128,
+ // zig fmt: on
+ };
+ }
+ };
+
+ pub const BigInt = struct {
+ limb_size: LimbSize,
+ /// Always greater than 1.
+ limbs_len: u16,
+
+ pub const LimbSize = enum {
+ @"8",
+ @"16",
+ @"32",
+ @"64",
+ @"128",
+ pub fn bits(s: LimbSize) u8 {
+ return switch (s) {
+ .@"8" => 8,
+ .@"16" => 16,
+ .@"32" => 32,
+ .@"64" => 64,
+ .@"128" => 128,
+ };
+ }
+ pub fn unsigned(s: LimbSize) Int {
+ return switch (s) {
+ .@"8" => .uint8_t,
+ .@"16" => .uint16_t,
+ .@"32" => .uint32_t,
+ .@"64" => .uint64_t,
+ .@"128" => .zig_u128,
+ };
+ }
+ pub fn signed(s: LimbSize) Int {
+ return switch (s) {
+ .@"8" => .int8_t,
+ .@"16" => .int16_t,
+ .@"32" => .int32_t,
+ .@"64" => .int64_t,
+ .@"128" => .zig_i128,
+ };
+ }
+ };
+ };
+
+ pub const Float = enum {
+ @"long double",
+ zig_f16,
+ zig_f32,
+ zig_f64,
+ zig_f80,
+ zig_f128,
+ zig_u128,
+ zig_i128,
+ };
+
+ pub fn isStringElem(cty: CType) bool {
+ return switch (cty) {
+ .int => |int| switch (int) {
+ .char, .int8_t, .uint8_t => true,
+ else => false,
+ },
+ else => false,
+ };
+ }
+
+ pub fn lower(
+ ty: Type,
+ deps: *Dependencies,
+ arena: Allocator,
+ zcu: *const Zcu,
+ ) Allocator.Error!CType {
+ return lowerInner(ty, false, deps, arena, zcu);
+ }
+ fn lowerInner(
+ start_ty: Type,
+ allow_incomplete: bool,
+ deps: *Dependencies,
+ arena: Allocator,
+ zcu: *const Zcu,
+ ) Allocator.Error!CType {
+ const gpa = zcu.comp.gpa;
+ const ip = &zcu.intern_pool;
+ var cur_ty = start_ty;
+ while (true) {
+ switch (cur_ty.zigTypeTag(zcu)) {
+ .type,
+ .comptime_int,
+ .comptime_float,
+ .undefined,
+ .null,
+ .enum_literal,
+ .@"opaque",
+ .noreturn,
+ .void,
+ => return .void,
+
+ .bool => return .bool,
+
+ .int, .error_set => switch (classifyInt(cur_ty, zcu)) {
+ .void => return .void,
+ .small => |s| return .{ .int = s },
+ .big => |big| {
+ try deps.bigint.put(gpa, big, {});
+ return .{ .bigint = big };
+ },
+ },
+
+ .float => return .{ .float = switch (cur_ty.toIntern()) {
+ .c_longdouble_type => .@"long double",
+ .f16_type => .zig_f16,
+ .f32_type => .zig_f32,
+ .f64_type => .zig_f64,
+ .f80_type => .zig_f80,
+ .f128_type => .zig_f128,
+ else => unreachable,
+ } },
+ .vector => {
+ try deps.addType(gpa, cur_ty, allow_incomplete);
+ return .{ .vec = cur_ty };
+ },
+ .array => {
+ try deps.addType(gpa, cur_ty, allow_incomplete);
+ return .{ .arr = cur_ty };
+ },
+
+ .pointer => {
+ const ptr = cur_ty.ptrInfo(zcu);
+ switch (ptr.flags.size) {
+ .slice => {
+ try deps.addType(gpa, cur_ty, allow_incomplete);
+ return .{ .slice = cur_ty };
+ },
+ .one, .many, .c => {
+ const elem_ty: Type = .fromInterned(ptr.child);
+ const is_fn_ptr = elem_ty.zigTypeTag(zcu) == .@"fn";
+ const elem_cty: CType = elem_cty: {
+ if (ptr.packed_offset.host_size > 0 and ptr.flags.vector_index == .none) {
+ switch (classifyBitInt(.unsigned, ptr.packed_offset.host_size * 8, zcu)) {
+ .void => break :elem_cty .void,
+ .small => |s| break :elem_cty .{ .int = s },
+ .big => |big| {
+ try deps.bigint.put(gpa, big, {});
+ break :elem_cty .{ .bigint = big };
+ },
+ }
+ }
+ if (ptr.flags.alignment != .none and !is_fn_ptr) {
+ // The pointer has an explicit alignment---if it's an underalignment
+ // then we need to use an "aligned" typedef.
+ const ptr_align = ptr.flags.alignment;
+ if (!alwaysHasLayout(elem_ty, ip) or
+ ptr_align.compareStrict(.lt, elem_ty.abiAlignment(zcu)))
+ {
+ const gop = try deps.aligned_type_fwd.getOrPut(gpa, elem_ty.toIntern());
+ if (!gop.found_existing) gop.value_ptr.* = 0;
+ gop.value_ptr.* |= @as(u64, 1) << ptr_align.toLog2Units();
+ break :elem_cty .{ .aligned = .{
+ .ty = elem_ty,
+ .alignment = ptr_align,
+ } };
+ }
+ }
+ break :elem_cty try .lowerInner(elem_ty, true, deps, arena, zcu);
+ };
+ const elem_cty_buf = try arena.create(CType);
+ elem_cty_buf.* = elem_cty;
+ return .{ .pointer = .{
+ .@"const" = ptr.flags.is_const and !is_fn_ptr,
+ .@"volatile" = ptr.flags.is_volatile and !is_fn_ptr,
+ .elem_ty = elem_cty_buf,
+ .nonstring = nonstring: {
+ if (!elem_cty.isStringElem()) break :nonstring false;
+ if (ptr.sentinel == .none) break :nonstring true;
+ break :nonstring Value.compareHetero(
+ .fromInterned(ptr.sentinel),
+ .neq,
+ .zero_comptime_int,
+ zcu,
+ );
+ },
+ } };
+ },
+ }
+ },
+
+ .@"fn" => {
+ const func_type = ip.indexToKey(cur_ty.toIntern()).func_type;
+ direct: {
+ const ret_ty: Type = .fromInterned(func_type.return_type);
+ if (!alwaysHasLayout(ret_ty, ip)) break :direct;
+ var params_len: usize = 0; // only counts parameter types with runtime bits
+ for (func_type.param_types.get(ip)) |param_ty_ip| {
+ const param_ty: Type = .fromInterned(param_ty_ip);
+ if (!alwaysHasLayout(param_ty, ip)) break :direct;
+ if (param_ty.hasRuntimeBits(zcu)) params_len += 1;
+ }
+ // We can actually write this function type directly!
+ if (!cur_ty.fnHasRuntimeBits(zcu)) return .void;
+ const ret_cty_buf = try arena.create(CType);
+ if (!ret_ty.hasRuntimeBits(zcu)) {
+ // Incomplete function return types must always be `void`.
+ ret_cty_buf.* = .void;
+ } else {
+ ret_cty_buf.* = try .lowerInner(ret_ty, allow_incomplete, deps, arena, zcu);
+ }
+ const param_cty_buf = try arena.alloc(CType, params_len);
+ var param_index: usize = 0;
+ for (func_type.param_types.get(ip)) |param_ty_ip| {
+ const param_ty: Type = .fromInterned(param_ty_ip);
+ if (!param_ty.hasRuntimeBits(zcu)) continue;
+ param_cty_buf[param_index] = try .lowerInner(param_ty, allow_incomplete, deps, arena, zcu);
+ param_index += 1;
+ }
+ assert(param_index == params_len);
+ return .{ .function = .{
+ .ret_ty = ret_cty_buf,
+ .param_tys = param_cty_buf,
+ .varargs = func_type.is_var_args,
+ } };
+ }
+ try deps.addType(gpa, cur_ty, allow_incomplete);
+ return .{ .@"fn" = cur_ty };
+ },
+
+ .@"struct" => {
+ try deps.addType(gpa, cur_ty, allow_incomplete);
+ switch (cur_ty.containerLayout(zcu)) {
+ .auto, .@"extern" => return .{ .@"struct" = cur_ty },
+ .@"packed" => return .{ .bitpack = cur_ty },
+ }
+ },
+ .@"union" => {
+ try deps.addType(gpa, cur_ty, allow_incomplete);
+ switch (cur_ty.containerLayout(zcu)) {
+ .auto => return .{ .union_auto = cur_ty },
+ .@"extern" => return .{ .union_extern = cur_ty },
+ .@"packed" => return .{ .bitpack = cur_ty },
+ }
+ },
+ .@"enum" => {
+ try deps.addType(gpa, cur_ty, allow_incomplete);
+ return .{ .@"enum" = cur_ty };
+ },
+
+ .optional => {
+ // This query does not require any type resolution.
+ if (cur_ty.optionalReprIsPayload(zcu)) {
+ // Either a pointer-like optional, or an optional error set. Just lower the payload.
+ cur_ty = cur_ty.optionalChild(zcu);
+ continue;
+ }
+ if (alwaysHasLayout(cur_ty, ip)) switch (classifyOptional(cur_ty, zcu)) {
+ .error_set, .ptr_like, .slice_like => unreachable, // handled above
+ .npv_payload => return .void,
+ .opv_payload, .@"struct" => {},
+ };
+ try deps.addType(gpa, cur_ty, allow_incomplete);
+ return .{ .opt = cur_ty };
+ },
+
+ .error_union => {
+ const payload_ty = cur_ty.errorUnionPayload(zcu);
+ if (allow_incomplete) {
+ try deps.errunion_type_fwd.put(gpa, payload_ty.toIntern(), {});
+ } else {
+ try deps.errunion_type.put(gpa, payload_ty.toIntern(), {});
+ }
+ return .{ .errunion = .{
+ .payload_ty = payload_ty,
+ } };
+ },
+
+ .frame,
+ .@"anyframe",
+ => unreachable,
+ }
+ comptime unreachable;
+ }
+ }
+
+ pub fn classifyOptional(opt_ty: Type, zcu: *const Zcu) enum {
+ /// The optional is something like `?noreturn`; it lowers to `void`.
+ npv_payload,
+ /// The payload type is an error set; the representation matches that of the error set, with
+ /// the value 0 representing `null`.
+ error_set,
+ /// The payload type is a non-optional pointer; the NULL pointer is used for `null`.
+ ptr_like,
+ /// The payload type is a non-optional slice; a NULL pointer field is used for `null`.
+ slice_like,
+ /// The optional is something like `?void`; it lowers to a struct, but one containing only
+ /// one field `is_null` (the payload is omitted).
+ opv_payload,
+ /// The optional uses the "default" lowering of a struct with two fields, like this:
+ /// struct optional_1234 { payload_ty payload; bool is_null; }
+ @"struct",
+ } {
+ const payload_ty = opt_ty.optionalChild(zcu);
+ if (opt_ty.optionalReprIsPayload(zcu)) {
+ return switch (payload_ty.zigTypeTag(zcu)) {
+ .error_set => .error_set,
+ .pointer => if (payload_ty.isSlice(zcu)) .slice_like else .ptr_like,
+ else => unreachable,
+ };
+ } else {
+ return switch (payload_ty.classify(zcu)) {
+ .no_possible_value => .npv_payload,
+ .one_possible_value => .opv_payload,
+ else => .@"struct",
+ };
+ }
+ }
+
+ pub const IntClass = union(enum) {
+ /// The integer type is zero-bit, so lowers to `void`.
+ void,
+ /// The integer is under 128 bits long, so lowers to this C integer type.
+ small: Int,
+ /// The integer is over 128 bits long, so lowers to an array of limbs.
+ big: BigInt,
+ };
+
+ /// Asserts that `ty` is an integer, enum, bitpack, or error set.
+ pub fn classifyInt(ty: Type, zcu: *const Zcu) IntClass {
+ const int_ty: Type = switch (ty.zigTypeTag(zcu)) {
+ .error_set => return classifyBitInt(.unsigned, zcu.errorSetBits(), zcu),
+ .@"enum" => ty.intTagType(zcu),
+ .@"struct", .@"union" => ty.bitpackBackingInt(zcu),
+ .int => ty,
+ else => unreachable,
+ };
+ switch (int_ty.toIntern()) {
+ // zig fmt: off
+ .usize_type => return .{ .small = .uintptr_t },
+ .isize_type => return .{ .small = .intptr_t },
+
+ .c_char_type => return .{ .small = .char },
+
+ .c_short_type => return .{ .small = .@"signed short" },
+ .c_int_type => return .{ .small = .@"signed int" },
+ .c_long_type => return .{ .small = .@"signed long" },
+ .c_longlong_type => return .{ .small = .@"signed long long" },
+
+ .c_ushort_type => return .{ .small = .@"unsigned short" },
+ .c_uint_type => return .{ .small = .@"unsigned int" },
+ .c_ulong_type => return .{ .small = .@"unsigned long" },
+ .c_ulonglong_type => return .{ .small = .@"unsigned long long" },
+ // zig fmt: on
+
+ else => {
+ const int = ty.intInfo(zcu);
+ return classifyBitInt(int.signedness, int.bits, zcu);
+ },
+ }
+ }
+ fn classifyBitInt(signedness: std.builtin.Signedness, bits: u16, zcu: *const Zcu) IntClass {
+ return switch (bits) {
+ 0 => .void,
+ 1...8 => switch (signedness) {
+ .unsigned => .{ .small = .uint8_t },
+ .signed => .{ .small = .int8_t },
+ },
+ 9...16 => switch (signedness) {
+ .unsigned => .{ .small = .uint16_t },
+ .signed => .{ .small = .int16_t },
+ },
+ 17...32 => switch (signedness) {
+ .unsigned => .{ .small = .uint32_t },
+ .signed => .{ .small = .int32_t },
+ },
+ 33...64 => switch (signedness) {
+ .unsigned => .{ .small = .uint64_t },
+ .signed => .{ .small = .int64_t },
+ },
+ 65...128 => switch (signedness) {
+ .unsigned => .{ .small = .zig_u128 },
+ .signed => .{ .small = .zig_i128 },
+ },
+ else => {
+ @branchHint(.unlikely);
+ const target = zcu.getTarget();
+ const limb_bytes = std.zig.target.intAlignment(target, bits);
+ return .{ .big = .{
+ .limb_size = switch (limb_bytes) {
+ 1 => .@"8",
+ 2 => .@"16",
+ 4 => .@"32",
+ 8 => .@"64",
+ 16 => .@"128",
+ else => unreachable,
+ },
+ .limbs_len = @divExact(
+ std.zig.target.intByteSize(target, bits),
+ limb_bytes,
+ ),
+ } };
+ },
+ };
+ }
+
+ /// Describes a set of types which must be declared or completed in the C source file before
+ /// some string of rendered C code (such as a function), due to said C code using these types.
+ pub const Dependencies = struct {
+ /// Key is any Zig type which corresponds to a C `struct`, `union`, or `typedef`. That C
+ /// type must be declared and complete.
+ type: std.AutoArrayHashMapUnmanaged(InternPool.Index, void),
+
+ /// Key is a Zig type which is the *payload* of an error union. The C `struct` type
+ /// corresponding to such an error union must be declared and complete.
+ ///
+ /// These are separate from `type` to avoid redundant types for every different error set
+ /// used with the same payload type---for instance a different C type for every `E!void`.
+ errunion_type: std.AutoArrayHashMapUnmanaged(InternPool.Index, void),
+
+ /// Like `type`, but the type does not necessarily need to be completed yet: a forward
+ /// declaration is sufficient.
+ type_fwd: std.AutoArrayHashMapUnmanaged(InternPool.Index, void),
+
+ /// Like `errunion_type`, but the type does not necessarily need to be completed yet: a
+ /// forward declaration is sufficient.
+ errunion_type_fwd: std.AutoArrayHashMapUnmanaged(InternPool.Index, void),
+
+ /// Key is a Zig type; value is a bitmask of alignments. For every bit which is set, an
+ /// aligned typedef is required. For instance, if bit 3 is set, the C type 'aligned__8_foo'
+ /// must be declared through `typedef` (but not necessarily completed yet).
+ aligned_type_fwd: std.AutoArrayHashMapUnmanaged(InternPool.Index, u64),
+
+ /// Key specifies a big-int type whose C `struct` must be declared and complete.
+ bigint: std.AutoArrayHashMapUnmanaged(BigInt, void),
+
+ pub const empty: Dependencies = .{
+ .type = .empty,
+ .errunion_type = .empty,
+ .type_fwd = .empty,
+ .errunion_type_fwd = .empty,
+ .aligned_type_fwd = .empty,
+ .bigint = .empty,
+ };
+
+ pub fn deinit(deps: *Dependencies, gpa: Allocator) void {
+ deps.type.deinit(gpa);
+ deps.errunion_type.deinit(gpa);
+ deps.type_fwd.deinit(gpa);
+ deps.errunion_type_fwd.deinit(gpa);
+ deps.aligned_type_fwd.deinit(gpa);
+ deps.bigint.deinit(gpa);
+ }
+
+ pub fn clearRetainingCapacity(deps: *Dependencies) void {
+ deps.type.clearRetainingCapacity();
+ deps.errunion_type.clearRetainingCapacity();
+ deps.type_fwd.clearRetainingCapacity();
+ deps.errunion_type_fwd.clearRetainingCapacity();
+ deps.aligned_type_fwd.clearRetainingCapacity();
+ deps.bigint.clearRetainingCapacity();
+ }
+
+ pub fn move(deps: *Dependencies) Dependencies {
+ const moved = deps.*;
+ deps.* = .empty;
+ return moved;
+ }
+
+ fn addType(deps: *Dependencies, gpa: Allocator, ty: Type, allow_incomplete: bool) Allocator.Error!void {
+ if (allow_incomplete) {
+ try deps.type_fwd.put(gpa, ty.toIntern(), {});
+ } else {
+ try deps.type.put(gpa, ty.toIntern(), {});
+ }
+ }
+ };
+
+ /// Formats the bytes which appear *before* the identifier in a declarator. This includes the
+ /// type specifier and all "prefix type operators" in the declarator. e.g:
+ /// * for the declarator "int foo", writes "int "
+ /// * for the declarator "struct thing *foo", writes "struct thing *"
+ /// * for the declarator "void *(*foo)(int)", writes "void *(*"
+ pub fn fmtDeclaratorPrefix(cty: CType, zcu: *const Zcu) Formatter {
+ return .{
+ .cty = cty,
+ .zcu = zcu,
+ .kind = .declarator_prefix,
+ };
+ }
+ /// Formats the bytes which appear *before* the identifier in a declarator. This includes the
+ /// type specifier and all "prefix type operators" in the declarator. e.g:
+ /// * for the declarator "int foo", writes ""
+ /// * for the declarator "struct thing *foo", writes ""
+ /// * for the declarator "void *(*foo)(int)", writes ")(int)"
+ pub fn fmtDeclaratorSuffix(cty: CType, zcu: *const Zcu) Formatter {
+ return .{
+ .cty = cty,
+ .zcu = zcu,
+ .kind = .declarator_suffix,
+ };
+ }
+ /// Like `fmtDeclaratorSuffix`, except never emits a `zig_nonstring` annotation.
+ pub fn fmtDeclaratorSuffixIgnoreNonstring(cty: CType, zcu: *const Zcu) Formatter {
+ return .{
+ .cty = cty,
+ .zcu = zcu,
+ .kind = .declarator_suffix_ignore_nonstring,
+ };
+ }
+ /// Formats a type's full name, e.g. "int", "struct foo *", "void *(uint32_t)".
+ ///
+ /// This is almost identical to `fmtDeclaratorPrefix` followed by `fmtDeclaratorSuffix`, but
+ /// that sequence of calls may emit trailing whitespace where this one does not---for instance,
+ /// those calls would write the type "void" as "void ".
+ pub fn fmtTypeName(cty: CType, zcu: *const Zcu) Formatter {
+ return .{
+ .cty = cty,
+ .zcu = zcu,
+ .kind = .type_name,
+ };
+ }
+
+ const Formatter = struct {
+ cty: CType,
+ zcu: *const Zcu,
+ kind: enum { type_name, declarator_prefix, declarator_suffix, declarator_suffix_ignore_nonstring },
+
+ pub fn format(ctx: Formatter, w: *Writer) Writer.Error!void {
+ switch (ctx.kind) {
+ .type_name => {
+ try ctx.cty.writeTypePrefix(w, ctx.zcu);
+ try ctx.cty.writeTypeSuffix(w, ctx.zcu);
+ },
+ .declarator_prefix => {
+ try ctx.cty.writeTypePrefix(w, ctx.zcu);
+ switch (ctx.cty.kind()) {
+ .specifier => try w.writeByte(' '), // write "int " rather than "int"
+ .pointer => {}, // we already have something like "foo *"
+ .postfix_op => {}, // we already have something like "ret_ty "
+ }
+ },
+ .declarator_suffix => {
+ try ctx.cty.writeTypeSuffix(w, ctx.zcu);
+ const nonstring = switch (ctx.cty) {
+ .array => |arr| arr.nonstring,
+ .pointer => |ptr| ptr.nonstring,
+ else => false,
+ };
+ if (nonstring) try w.writeAll(" zig_nonstring");
+ },
+ .declarator_suffix_ignore_nonstring => {
+ try ctx.cty.writeTypeSuffix(w, ctx.zcu);
+ },
+ }
+ }
+ };
+
+ fn writeTypePrefix(cty: CType, w: *Writer, zcu: *const Zcu) Writer.Error!void {
+ switch (cty) {
+ .void => try w.writeAll("void"),
+ .bool => try w.writeAll("bool"),
+ .int => |int| try w.writeAll(@tagName(int)),
+ .float => |float| try w.writeAll(@tagName(float)),
+ .@"fn" => |ty| try w.print("{f}_{d}", .{ fmtZigType(ty, zcu), ty.toIntern() }),
+ .@"enum" => |ty| try w.print("enum__{f}_{d}", .{ fmtZigType(ty, zcu), ty.toIntern() }),
+ .bitpack => |ty| try w.print("bitpack__{f}_{d}", .{ fmtZigType(ty, zcu), ty.toIntern() }),
+ .@"struct" => |ty| try w.print("struct {f}_{d}", .{ fmtZigType(ty, zcu), ty.toIntern() }),
+ .union_auto => |ty| try w.print("struct {f}_{d}", .{ fmtZigType(ty, zcu), ty.toIntern() }),
+ .union_extern => |ty| try w.print("union {f}_{d}", .{ fmtZigType(ty, zcu), ty.toIntern() }),
+ .slice => |ty| try w.print("struct {f}_{d}", .{ fmtZigType(ty, zcu), ty.toIntern() }),
+ .opt => |ty| try w.print("struct {f}_{d}", .{ fmtZigType(ty, zcu), ty.toIntern() }),
+ .arr => |ty| try w.print("struct {f}_{d}", .{ fmtZigType(ty, zcu), ty.toIntern() }),
+ .vec => |ty| try w.print("struct {f}_{d}", .{ fmtZigType(ty, zcu), ty.toIntern() }),
+ .errunion => |eu| try w.print("struct errunion_{f}_{d}", .{
+ fmtZigType(eu.payload_ty, zcu),
+ eu.payload_ty.toIntern(),
+ }),
+ .aligned => |aligned| try w.print("aligned__{d}_{f}_{d}", .{
+ aligned.alignment.toByteUnits().?,
+ fmtZigType(aligned.ty, zcu),
+ aligned.ty.toIntern(),
+ }),
+ .bigint => |bigint| try w.print("struct int_{d}x{d}", .{
+ bigint.limb_size.bits(),
+ bigint.limbs_len,
+ }),
+
+ .pointer => |ptr| {
+ try ptr.elem_ty.writeTypePrefix(w, zcu);
+ switch (ptr.elem_ty.kind()) {
+ .pointer, .postfix_op => {},
+ .specifier => {
+ // We want "foo *" or "foo const *" rather than "foo*" or "fooconst *".
+ try w.writeByte(' ');
+ },
+ }
+ if (ptr.@"const") try w.writeAll("const ");
+ if (ptr.@"volatile") try w.writeAll("volatile ");
+ switch (ptr.elem_ty.kind()) {
+ .specifier, .pointer => {},
+ .postfix_op => {
+ // Prefix "*" is lower precedence than postfix "(x)" or "[x]" so use parens
+ // to disambiguate; e.g. "void (*foo)(int)" instead of "void *foo(int)".
+ try w.writeByte('(');
+ },
+ }
+ try w.writeByte('*');
+ },
+
+ .array => |array| {
+ try array.elem_ty.writeTypePrefix(w, zcu);
+ switch (array.elem_ty.kind()) {
+ .pointer, .postfix_op => {},
+ .specifier => {
+ // We want e.g. "struct foo [5]" rather than "struct foo[5]".
+ try w.writeByte(' ');
+ },
+ }
+ },
+
+ .function => |function| {
+ try function.ret_ty.writeTypePrefix(w, zcu);
+ switch (function.ret_ty.kind()) {
+ .pointer, .postfix_op => {},
+ .specifier => {
+ // We want e.g. "struct foo (void)" rather than "struct foo(void)".
+ try w.writeByte(' ');
+ },
+ }
+ },
+ }
+ }
+ fn writeTypeSuffix(cty: CType, w: *Writer, zcu: *const Zcu) Writer.Error!void {
+ switch (cty) {
+ // simple type specifiers
+ .void,
+ .bool,
+ .int,
+ .float,
+ .@"fn",
+ .@"enum",
+ .bitpack,
+ .@"struct",
+ .union_auto,
+ .union_extern,
+ .slice,
+ .opt,
+ .arr,
+ .vec,
+ .errunion,
+ .aligned,
+ .bigint,
+ => {},
+
+ .pointer => |ptr| {
+ // Match opening paren "(" write `writeTypePrefix`.
+ switch (ptr.elem_ty.kind()) {
+ .specifier, .pointer => {},
+ .postfix_op => try w.writeByte(')'),
+ }
+ try ptr.elem_ty.writeTypeSuffix(w, zcu);
+ },
+
+ .array => |array| {
+ try w.print("[{d}]", .{array.len});
+ try array.elem_ty.writeTypeSuffix(w, zcu);
+ },
+
+ .function => |function| {
+ if (function.param_tys.len == 0 and !function.varargs) {
+ try w.writeAll("(void)");
+ } else {
+ try w.writeByte('(');
+ for (function.param_tys, 0..) |param_ty, param_index| {
+ if (param_index > 0) try w.writeAll(", ");
+ try param_ty.writeTypePrefix(w, zcu);
+ try param_ty.writeTypeSuffix(w, zcu);
+ }
+ if (function.varargs) {
+ if (function.param_tys.len > 0) try w.writeAll(", ");
+ try w.writeAll("...");
+ }
+ try w.writeByte(')');
+ }
+ try function.ret_ty.writeTypeSuffix(w, zcu);
+ },
+ }
+ }
+
+ /// Renders Zig types using only bytes allowed in C identifiers in a somewhat-understandable
+ /// way. The output is *not* guaranteed to be unique.
+ fn fmtZigType(ty: Type, zcu: *const Zcu) FormatZigType {
+ return .{ .ty = ty, .zcu = zcu };
+ }
+ const FormatZigType = struct {
+ ty: Type,
+ zcu: *const Zcu,
+ pub fn format(ctx: FormatZigType, w: *Writer) Writer.Error!void {
+ const ty = ctx.ty;
+ const zcu = ctx.zcu;
+ const ip = &zcu.intern_pool;
+ switch (ty.zigTypeTag(zcu)) {
+ .frame => unreachable,
+ .@"anyframe" => unreachable,
+
+ .type => try w.writeAll("type"),
+ .void => try w.writeAll("void"),
+ .bool => try w.writeAll("bool"),
+ .noreturn => try w.writeAll("noreturn"),
+ .comptime_int => try w.writeAll("comptime_int"),
+ .comptime_float => try w.writeAll("comptime_float"),
+ .enum_literal => try w.writeAll("enum_literal"),
+ .undefined => try w.writeAll("undefined"),
+ .null => try w.writeAll("null"),
+
+ .int => switch (ty.toIntern()) {
+ .usize_type => try w.writeAll("usize"),
+ .isize_type => try w.writeAll("isize"),
+ .c_char_type => try w.writeAll("c_char"),
+ .c_short_type => try w.writeAll("c_short"),
+ .c_ushort_type => try w.writeAll("c_ushort"),
+ .c_int_type => try w.writeAll("c_int"),
+ .c_uint_type => try w.writeAll("c_uint"),
+ .c_long_type => try w.writeAll("c_long"),
+ .c_ulong_type => try w.writeAll("c_ulong"),
+ .c_longlong_type => try w.writeAll("c_longlong"),
+ .c_ulonglong_type => try w.writeAll("c_ulonglong"),
+ else => {
+ const info = ty.intInfo(zcu);
+ switch (info.signedness) {
+ .unsigned => try w.print("u{d}", .{info.bits}),
+ .signed => try w.print("i{d}", .{info.bits}),
+ }
+ },
+ },
+ .float => switch (ty.toIntern()) {
+ .c_longdouble_type => try w.writeAll("c_longdouble"),
+ .f16_type => try w.writeAll("f16"),
+ .f32_type => try w.writeAll("f32"),
+ .f64_type => try w.writeAll("f64"),
+ .f80_type => try w.writeAll("f80"),
+ .f128_type => try w.writeAll("f128"),
+ else => unreachable,
+ },
+ .error_set => switch (ty.toIntern()) {
+ .anyerror_type => try w.writeAll("anyerror"),
+ else => try w.print("error_{d}", .{@intFromEnum(ty.toIntern())}),
+ },
+ .optional => try w.print("opt_{f}", .{fmtZigType(ty.optionalChild(zcu), zcu)}),
+ .error_union => try w.print("errunion_{f}", .{fmtZigType(ty.errorUnionPayload(zcu), zcu)}),
+
+ .pointer => switch (ty.ptrSize(zcu)) {
+ .one, .many, .c => try w.print("ptr_{f}", .{fmtZigType(ty.childType(zcu), zcu)}),
+ .slice => try w.print("slice_{f}", .{fmtZigType(ty.childType(zcu), zcu)}),
+ },
+ .@"fn" => {
+ const func_type = ip.indexToKey(ty.toIntern()).func_type;
+ try w.writeAll("fn_"); // intentional double underscore to start
+ for (func_type.param_types.get(ip)) |param_ty_ip| {
+ const param_ty: Type = .fromInterned(param_ty_ip);
+ if (param_ty.isGenericPoison()) {
+ try w.writeAll("_Pgeneric");
+ } else {
+ try w.print("_P{f}", .{fmtZigType(param_ty, zcu)});
+ }
+ }
+ if (func_type.is_var_args) {
+ try w.writeAll("_VA");
+ }
+ const ret_ty: Type = .fromInterned(func_type.return_type);
+ if (ret_ty.isGenericPoison()) {
+ try w.writeAll("_Rgeneric");
+ } else if (ret_ty.zigTypeTag(zcu) == .error_union and ret_ty.errorUnionPayload(zcu).isGenericPoison()) {
+ try w.writeAll("_Rgeneric_ies");
+ } else {
+ try w.print("_R{f}", .{fmtZigType(ret_ty, zcu)});
+ }
+ },
+
+ .vector => try w.print("vec_{d}_{f}", .{
+ ty.arrayLen(zcu),
+ fmtZigType(ty.childType(zcu), zcu),
+ }),
+
+ .array => if (ty.sentinel(zcu)) |s| try w.print("arr_{d}s{d}_{f}", .{
+ ty.arrayLen(zcu),
+ @intFromEnum(s.toIntern()),
+ fmtZigType(ty.childType(zcu), zcu),
+ }) else try w.print("arr_{d}_{f}", .{
+ ty.arrayLen(zcu),
+ fmtZigType(ty.childType(zcu), zcu),
+ }),
+
+ .@"struct" => if (ty.isTuple(zcu)) {
+ const len = ty.structFieldCount(zcu);
+ try w.print("tuple_{d}", .{len});
+ for (0..len) |field_index| {
+ const field_ty = ty.fieldType(field_index, zcu);
+ try w.print("_{f}", .{fmtZigType(field_ty, zcu)});
+ }
+ } else {
+ const name = ty.containerTypeName(ip).toSlice(ip);
+ try w.print("{f}", .{@import("../c.zig").fmtIdentUnsolo(name)});
+ },
+ .@"opaque" => if (ty.toIntern() == .anyopaque_type) {
+ try w.writeAll("anyopaque");
+ } else {
+ const name = ty.containerTypeName(ip).toSlice(ip);
+ try w.print("{f}", .{@import("../c.zig").fmtIdentUnsolo(name)});
+ },
+ .@"union", .@"enum" => {
+ const name = ty.containerTypeName(ip).toSlice(ip);
+ try w.print("{f}", .{@import("../c.zig").fmtIdentUnsolo(name)});
+ },
+ }
+ }
+ };
+
+ /// Returns `true` if the layout of `ty` is known without any type resolution required. This
+ /// allows some types to be lowered directly where 'typedef' would otherwise be necessary.
+ fn alwaysHasLayout(ty: Type, ip: *const InternPool) bool {
+ return switch (ip.indexToKey(ty.toIntern())) {
+ .int_type,
+ .ptr_type,
+ .anyframe_type,
+ .simple_type,
+ .opaque_type,
+ .error_set_type,
+ .inferred_error_set_type,
+ => true,
+
+ .struct_type,
+ .union_type,
+ .enum_type,
+ => false,
+
+ .array_type => |arr| alwaysHasLayout(.fromInterned(arr.child), ip),
+ .vector_type => |vec| alwaysHasLayout(.fromInterned(vec.child), ip),
+ .opt_type => |child| alwaysHasLayout(.fromInterned(child), ip),
+ .error_union_type => |eu| alwaysHasLayout(.fromInterned(eu.payload_type), ip),
+
+ .tuple_type => |tuple| for (tuple.types.get(ip)) |field_ty| {
+ if (!alwaysHasLayout(.fromInterned(field_ty), ip)) break false;
+ } else true,
+
+ .func_type => |f| for (f.param_types.get(ip)) |param_ty| {
+ if (!alwaysHasLayout(.fromInterned(param_ty), ip)) break false;
+ } else alwaysHasLayout(.fromInterned(f.return_type), ip),
+
+ // values, not types
+ .undef,
+ .simple_value,
+ .variable,
+ .@"extern",
+ .func,
+ .int,
+ .err,
+ .error_union,
+ .enum_literal,
+ .enum_tag,
+ .float,
+ .ptr,
+ .slice,
+ .opt,
+ .aggregate,
+ .un,
+ .bitpack,
+ // memoization, not types
+ .memoized_call,
+ => unreachable,
+ };
+ }
+};
+
+const Zcu = @import("../../Zcu.zig");
+const Type = @import("../../Type.zig");
+const Value = @import("../../Value.zig");
+const InternPool = @import("../../InternPool.zig");
+
+const std = @import("std");
+const assert = std.debug.assert;
+const Allocator = std.mem.Allocator;
+const Writer = std.Io.Writer;
diff --git a/src/codegen/c/type/render_defs.zig b/src/codegen/c/type/render_defs.zig
new file mode 100644
index 0000000000000000000000000000000000000000..52bf57306426156917bcfbcda475d57edd972e06
--- /dev/null
+++ b/src/codegen/c/type/render_defs.zig
@@ -0,0 +1,710 @@
+/// Renders the `typedef` for an aligned type.
+pub fn defineAligned(
+ ty: Type,
+ alignment: Alignment,
+ complete: bool,
+ deps: *CType.Dependencies,
+ arena: Allocator,
+ w: *Writer,
+ pt: Zcu.PerThread,
+) (Allocator.Error || Writer.Error)!void {
+ const zcu = pt.zcu;
+
+ const name_cty: CType = .{ .aligned = .{
+ .ty = ty,
+ .alignment = alignment,
+ } };
+
+ const cty: CType = try .lower(ty, deps, arena, zcu);
+
+ try w.writeAll("typedef ");
+ if (complete and alignment.compareStrict(.lt, ty.abiAlignment(zcu))) {
+ try w.print("zig_under_align({d}) ", .{alignment.toByteUnits().?});
+ }
+ try w.print("{f}{f}{f}; /* align({d}) {f} */\n", .{
+ cty.fmtDeclaratorPrefix(zcu),
+ name_cty.fmtTypeName(zcu),
+ cty.fmtDeclaratorSuffix(zcu),
+ alignment.toByteUnits().?,
+ ty.fmt(pt),
+ });
+}
+/// Renders the definition of a big-int `struct`.
+pub fn defineBigInt(big: CType.BigInt, w: *Writer, zcu: *const Zcu) Writer.Error!void {
+ const name_cty: CType = .{ .bigint = .{
+ .limb_size = big.limb_size,
+ .limbs_len = big.limbs_len,
+ } };
+ const limb_cty: CType = .{ .int = big.limb_size.unsigned() };
+ const array_cty: CType = .{ .array = .{
+ .len = big.limbs_len,
+ .elem_ty = &limb_cty,
+ .nonstring = limb_cty.isStringElem(),
+ } };
+ try w.print("{f} {{ {f}limbs{f}; }}; /* {d} bits */\n", .{
+ name_cty.fmtTypeName(zcu),
+ array_cty.fmtDeclaratorPrefix(zcu),
+ array_cty.fmtDeclaratorSuffix(zcu),
+ big.limb_size.bits() * @as(u17, big.limbs_len),
+ });
+}
+
+/// Renders a forward declaration of the `struct` which represents an error union whose payload type
+/// is `payload_ty` (the error set type is unspecified).
+pub fn errunionFwdDecl(payload_ty: Type, w: *Writer, zcu: *const Zcu) Writer.Error!void {
+ const name_cty: CType = .{ .errunion = .{
+ .payload_ty = payload_ty,
+ } };
+ try w.print("{f};\n", .{name_cty.fmtTypeName(zcu)});
+}
+/// Renders the definition of the `struct` which represents an error union whose payload type is
+/// `payload_ty` (the error set type is unspecified).
+///
+/// Asserts that the layout of `payload_ty` is resolved.
+pub fn errunionDefineComplete(
+ payload_ty: Type,
+ deps: *CType.Dependencies,
+ arena: Allocator,
+ w: *Writer,
+ pt: Zcu.PerThread,
+) (Allocator.Error || Writer.Error)!void {
+ const zcu = pt.zcu;
+
+ payload_ty.assertHasLayout(zcu);
+
+ const name_cty: CType = .{ .errunion = .{
+ .payload_ty = payload_ty,
+ } };
+
+ const error_cty: CType = try .lower(.anyerror, deps, arena, zcu);
+
+ if (payload_ty.hasRuntimeBits(zcu)) {
+ const payload_cty: CType = try .lower(payload_ty, deps, arena, zcu);
+ try w.print(
+ \\{f} {{ /* anyerror!{f} */
+ \\ {f}payload{f};
+ \\ {f}error{f};
+ \\}};
+ \\
+ , .{
+ name_cty.fmtTypeName(zcu),
+ payload_ty.fmt(pt),
+ payload_cty.fmtDeclaratorPrefix(zcu),
+ payload_cty.fmtDeclaratorSuffix(zcu),
+ error_cty.fmtDeclaratorPrefix(zcu),
+ error_cty.fmtDeclaratorSuffix(zcu),
+ });
+ } else {
+ try w.print("{f} {{ {f}error{f}; }}; /* anyerror!{f} */\n", .{
+ name_cty.fmtTypeName(zcu),
+ error_cty.fmtDeclaratorPrefix(zcu),
+ error_cty.fmtDeclaratorSuffix(zcu),
+ payload_ty.fmt(pt),
+ });
+ }
+}
+
+/// If the Zig type `ty` lowers to a `struct` or `union` type, renders a forward declaration of that
+/// type. Does not write anything for error union types, because their forward declarations are
+/// instead rendered by `errunionFwdDecl`.
+pub fn fwdDecl(ty: Type, w: *Writer, zcu: *const Zcu) Writer.Error!void {
+ const name_cty: CType = switch (ty.zigTypeTag(zcu)) {
+ .@"struct" => switch (ty.containerLayout(zcu)) {
+ .auto, .@"extern" => .{ .@"struct" = ty },
+ .@"packed" => return,
+ },
+ .@"union" => switch (ty.containerLayout(zcu)) {
+ .auto => .{ .union_auto = ty },
+ .@"extern" => .{ .union_extern = ty },
+ .@"packed" => return,
+ },
+ .pointer => if (ty.isSlice(zcu)) .{ .slice = ty } else return,
+ .optional => .{ .opt = ty },
+ .array => .{ .arr = ty },
+ .vector => .{ .vec = ty },
+ else => return,
+ };
+ try w.print("{f};\n", .{name_cty.fmtTypeName(zcu)});
+}
+
+/// If the Zig type `ty` lowers to a `typedef`, renders a typedef of that type to `void`, because
+/// the type's layout is not resolved. This is only necessary for `typedef`s because a `struct` or
+/// `union` which is never defined is already an incomplete type, just like `void`.
+pub fn defineIncomplete(ty: Type, w: *Writer, pt: Zcu.PerThread) Writer.Error!void {
+ const zcu = pt.zcu;
+ const name_cty: CType = switch (ty.zigTypeTag(zcu)) {
+ .@"fn" => .{ .@"fn" = ty },
+ .@"enum" => .{ .@"enum" = ty },
+ .@"struct", .@"union" => switch (ty.containerLayout(zcu)) {
+ .auto, .@"extern" => return,
+ .@"packed" => .{ .bitpack = ty },
+ },
+ else => return,
+ };
+ try w.print("typedef void {f}; /* {f} */\n", .{
+ name_cty.fmtTypeName(zcu),
+ ty.fmt(pt),
+ });
+}
+
+/// If the Zig type `ty` lowers to a `struct` or `union` type, or to a `typedef`, renders the
+/// definition of that type. Does not write anything for error union types, because their
+/// definitions are instead rendered by `errunionDefine`.
+///
+/// Asserts that the layout of `ty` is resolved.
+pub fn defineComplete(
+ ty: Type,
+ deps: *CType.Dependencies,
+ arena: Allocator,
+ w: *Writer,
+ pt: Zcu.PerThread,
+) (Allocator.Error || Writer.Error)!void {
+ const zcu = pt.zcu;
+
+ ty.assertHasLayout(zcu);
+
+ switch (ty.zigTypeTag(zcu)) {
+ .@"fn" => if (!ty.fnHasRuntimeBits(zcu)) {
+ const name_cty: CType = .{ .@"fn" = ty };
+ try w.print("typedef void {f}; /* {f} */\n", .{
+ name_cty.fmtTypeName(zcu),
+ ty.fmt(pt),
+ });
+ } else {
+ const ip = &zcu.intern_pool;
+ const func_type = ip.indexToKey(ty.toIntern()).func_type;
+
+ // While incomplete types are usually an acceptable substitute for "void", this is not
+ // true in function return types, where "void" is the only incomplete type permitted.
+ const actual_ret_ty: Type = .fromInterned(func_type.return_type);
+ const effective_ret_ty: Type = switch (actual_ret_ty.classify(zcu)) {
+ .no_possible_value => .noreturn,
+ .one_possible_value, .fully_comptime => .void, // no runtime bits
+ .partially_comptime, .runtime => actual_ret_ty, // yes runtime bits
+ };
+
+ const name_cty: CType = .{ .@"fn" = ty };
+ const ret_cty: CType = try .lower(effective_ret_ty, deps, arena, zcu);
+
+ try w.print("typedef {f}{f}(", .{
+ ret_cty.fmtDeclaratorPrefix(zcu),
+ name_cty.fmtTypeName(zcu),
+ });
+ var any_params = false;
+ for (func_type.param_types.get(ip)) |param_ty_ip| {
+ const param_ty: Type = .fromInterned(param_ty_ip);
+ if (!param_ty.hasRuntimeBits(zcu)) continue;
+ if (any_params) try w.writeAll(", ");
+ any_params = true;
+ const param_cty: CType = try .lower(param_ty, deps, arena, zcu);
+ try w.print("{f}", .{param_cty.fmtTypeName(zcu)});
+ }
+ if (func_type.is_var_args) {
+ if (any_params) try w.writeAll(", ");
+ try w.writeAll("...");
+ } else if (!any_params) {
+ try w.writeAll("void");
+ }
+ try w.print("){f}; /* {f} */\n", .{
+ ret_cty.fmtDeclaratorSuffixIgnoreNonstring(zcu),
+ ty.fmt(pt),
+ });
+ },
+ .@"enum" => {
+ const name_cty: CType = .{ .@"enum" = ty };
+ const cty: CType = try .lower(ty.intTagType(zcu), deps, arena, zcu);
+ try w.print("typedef {f}{f}{f}; /* {f} */\n", .{
+ cty.fmtDeclaratorPrefix(zcu),
+ name_cty.fmtTypeName(zcu),
+ cty.fmtDeclaratorSuffix(zcu),
+ ty.fmt(pt),
+ });
+ },
+ .@"struct" => if (ty.isTuple(zcu)) {
+ try defineTuple(ty, deps, arena, w, pt);
+ } else switch (ty.containerLayout(zcu)) {
+ .auto, .@"extern" => try defineStruct(ty, deps, arena, w, pt),
+ .@"packed" => try defineBitpack(ty, deps, arena, w, pt),
+ },
+ .@"union" => switch (ty.containerLayout(zcu)) {
+ .auto => try defineUnionAuto(ty, deps, arena, w, pt),
+ .@"extern" => try defineUnionExtern(ty, deps, arena, w, pt),
+ .@"packed" => try defineBitpack(ty, deps, arena, w, pt),
+ },
+ .pointer => if (ty.isSlice(zcu)) {
+ const name_cty: CType = .{ .slice = ty };
+ const ptr_cty: CType = try .lower(ty.slicePtrFieldType(zcu), deps, arena, zcu);
+ try w.print(
+ \\{f} {{ /* {f} */
+ \\ {f}ptr{f};
+ \\ size_t len;
+ \\}};
+ \\
+ , .{
+ name_cty.fmtTypeName(zcu),
+ ty.fmt(pt),
+ ptr_cty.fmtDeclaratorPrefix(zcu),
+ ptr_cty.fmtDeclaratorSuffix(zcu),
+ });
+ // Don't bother with `writeStaticAssertLayout`---there's not really any way we could mess
+ // slices up, and they're all obviously the same layout.
+ },
+ .optional => switch (CType.classifyOptional(ty, zcu)) {
+ .error_set,
+ .ptr_like,
+ .slice_like,
+ .npv_payload,
+ => {},
+
+ .opv_payload => {
+ const name_cty: CType = .{ .opt = ty };
+ try w.print("{f} {{ bool is_null; }}; /* {f} */\n", .{
+ name_cty.fmtTypeName(zcu),
+ ty.fmt(pt),
+ });
+ try writeStaticAssertLayout(ty, name_cty, w, zcu);
+ },
+
+ .@"struct" => {
+ const name_cty: CType = .{ .opt = ty };
+ const payload_cty: CType = try .lower(ty.optionalChild(zcu), deps, arena, zcu);
+ try w.print(
+ \\{f} {{ /* {f} */
+ \\ {f}payload{f};
+ \\ bool is_null;
+ \\}};
+ \\
+ , .{
+ name_cty.fmtTypeName(zcu),
+ ty.fmt(pt),
+ payload_cty.fmtDeclaratorPrefix(zcu),
+ payload_cty.fmtDeclaratorSuffix(zcu),
+ });
+ try writeStaticAssertLayout(ty, name_cty, w, zcu);
+ },
+ },
+ .array => if (ty.hasRuntimeBits(zcu)) {
+ const name_cty: CType = .{ .arr = ty };
+ const elem_cty: CType = try .lower(ty.childType(zcu), deps, arena, zcu);
+ const array_cty: CType = .{ .array = .{
+ .len = ty.arrayLenIncludingSentinel(zcu),
+ .elem_ty = &elem_cty,
+ .nonstring = nonstring: {
+ if (!elem_cty.isStringElem()) break :nonstring false;
+ const s = ty.sentinel(zcu) orelse break :nonstring true;
+ break :nonstring Value.compareHetero(s, .neq, .zero_comptime_int, zcu);
+ },
+ } };
+ try w.print("{f} {{ {f}array{f}; }}; /* {f} */\n", .{
+ name_cty.fmtTypeName(zcu),
+ array_cty.fmtDeclaratorPrefix(zcu),
+ array_cty.fmtDeclaratorSuffix(zcu),
+ ty.fmt(pt),
+ });
+ try writeStaticAssertLayout(ty, name_cty, w, zcu);
+ },
+ .vector => if (ty.hasRuntimeBits(zcu)) {
+ const name_cty: CType = .{ .vec = ty };
+ const elem_cty: CType = try .lower(ty.childType(zcu), deps, arena, zcu);
+ const array_cty: CType = .{ .array = .{
+ .len = ty.arrayLenIncludingSentinel(zcu),
+ .elem_ty = &elem_cty,
+ .nonstring = elem_cty.isStringElem(),
+ } };
+ try w.print("{f} {{ {f}array{f}; }}; /* {f} */\n", .{
+ name_cty.fmtTypeName(zcu),
+ array_cty.fmtDeclaratorPrefix(zcu),
+ array_cty.fmtDeclaratorSuffix(zcu),
+ ty.fmt(pt),
+ });
+ try writeStaticAssertLayout(ty, name_cty, w, zcu);
+ },
+ else => {},
+ }
+}
+fn defineBitpack(
+ ty: Type,
+ deps: *CType.Dependencies,
+ arena: Allocator,
+ w: *Writer,
+ pt: Zcu.PerThread,
+) (Allocator.Error || Writer.Error)!void {
+ const zcu = pt.zcu;
+ const name_cty: CType = .{ .bitpack = ty };
+ const cty: CType = try .lower(ty.bitpackBackingInt(zcu), deps, arena, zcu);
+ try w.print("typedef {f}{f}{f}; /* {f} */\n", .{
+ cty.fmtDeclaratorPrefix(zcu),
+ name_cty.fmtTypeName(zcu),
+ cty.fmtDeclaratorSuffix(zcu),
+ ty.fmt(pt),
+ });
+}
+fn defineTuple(
+ ty: Type,
+ deps: *CType.Dependencies,
+ arena: Allocator,
+ w: *Writer,
+ pt: Zcu.PerThread,
+) (Allocator.Error || Writer.Error)!void {
+ const zcu = pt.zcu;
+ if (!ty.hasRuntimeBits(zcu)) return;
+ const ip = &zcu.intern_pool;
+ const tuple = ip.indexToKey(ty.toIntern()).tuple_type;
+
+ // Fields cannot be underaligned, because tuple fields cannot have specified alignments.
+ // However, overaligned fields are possible thanks to intermediate zero-bit fields.
+
+ const tuple_align = ty.abiAlignment(zcu);
+
+ // If the alignment of other fields would not give the tuple sufficient alignment, we
+ // need to align the first field (which does not affect its offset, because 0 is always
+ // well-aligned) to indirectly specify the tuple alignment.
+ const overalign: bool = for (tuple.types.get(ip)) |field_ty_ip| {
+ const field_ty: Type = .fromInterned(field_ty_ip);
+ if (!field_ty.hasRuntimeBits(zcu)) continue;
+ const natural_align = field_ty.defaultStructFieldAlignment(.auto, zcu);
+ if (natural_align.compareStrict(.gte, tuple_align)) break false;
+ } else true;
+
+ const name_cty: CType = .{ .@"struct" = ty };
+ try w.print("{f} {{ /* {f} */\n", .{
+ name_cty.fmtTypeName(zcu),
+ ty.fmt(pt),
+ });
+ var zig_offset: u64 = 0;
+ var c_offset: u64 = 0;
+ for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty_ip, field_val_ip, field_index| {
+ if (field_val_ip != .none) continue; // `comptime` field
+ const field_ty: Type = .fromInterned(field_ty_ip);
+ const field_align = field_ty.abiAlignment(zcu);
+ zig_offset = field_align.forward(zig_offset);
+ if (!field_ty.hasRuntimeBits(zcu)) continue;
+ c_offset = field_align.forward(c_offset);
+ try w.writeByte(' ');
+ if (zig_offset == 0 and overalign) {
+ // This is the first field; specify its alignment to align the tuple.
+ try writeFieldAlign(field_ty, tuple_align, w, zcu);
+ } else if (zig_offset > c_offset) {
+ // This field needs to be overaligned compared to what its offset would otherwise be.
+ const need_align: Alignment = .minStrict(
+ tuple_align, // don't make the struct more aligned than it should be
+ .fromLog2Units(@ctz(zig_offset)),
+ );
+ try writeFieldAlign(field_ty, need_align, w, zcu);
+ c_offset = need_align.forward(c_offset);
+ }
+ const field_cty: CType = try .lower(field_ty, deps, arena, zcu);
+ try w.print("{f}f{d}{f};\n", .{
+ field_cty.fmtDeclaratorPrefix(zcu),
+ field_index,
+ field_cty.fmtDeclaratorSuffix(zcu),
+ });
+ const field_size = field_ty.abiSize(zcu);
+ zig_offset += field_size;
+ c_offset += field_size;
+ }
+ try w.writeAll("};\n");
+
+ try writeStaticAssertLayout(ty, name_cty, w, zcu);
+}
+fn defineStruct(
+ ty: Type,
+ deps: *CType.Dependencies,
+ arena: Allocator,
+ w: *Writer,
+ pt: Zcu.PerThread,
+) (Allocator.Error || Writer.Error)!void {
+ const zcu = pt.zcu;
+ if (!ty.hasRuntimeBits(zcu)) return;
+ const ip = &zcu.intern_pool;
+
+ const struct_type = ip.loadStructType(ty.toIntern());
+
+ // If there are any underaligned fields, we need to byte-pack the struct.
+ const pack: bool = pack: {
+ var it = struct_type.iterateRuntimeOrder(ip);
+ var offset: u64 = 0;
+ while (it.next()) |field_index| {
+ const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);
+ if (!field_ty.hasRuntimeBits(zcu)) continue;
+ const natural_align = field_ty.defaultStructFieldAlignment(struct_type.layout, zcu);
+ const natural_offset = natural_align.forward(offset);
+ const actual_offset = struct_type.field_offsets.get(ip)[field_index];
+ if (actual_offset < natural_offset) break :pack true;
+ // Also pack if any field is more aligned than the struct should be.
+ if (natural_align.compareStrict(.gt, struct_type.alignment)) break :pack true;
+ offset = actual_offset + field_ty.abiSize(zcu);
+ }
+ break :pack false;
+ };
+
+ // If the alignment of other fields would not give the struct sufficient alignment, we
+ // need to align the first field (which does not affect its offset, because 0 is always
+ // well-aligned) to indirectly specify the struct alignment.
+ const overalign: bool = switch (pack) {
+ true => struct_type.alignment.compareStrict(.gt, .@"1"),
+ false => overalign: {
+ var it = struct_type.iterateRuntimeOrder(ip);
+ while (it.next()) |field_index| {
+ const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);
+ if (!field_ty.hasRuntimeBits(zcu)) continue;
+ const natural_align = field_ty.defaultStructFieldAlignment(struct_type.layout, zcu);
+ if (natural_align.compareStrict(.gte, struct_type.alignment)) break :overalign false;
+ }
+ break :overalign true;
+ },
+ };
+
+ if (pack) try w.writeAll("zig_packed(");
+ const name_cty: CType = .{ .@"struct" = ty };
+ try w.print("{f} {{ /* {f} */\n", .{
+ name_cty.fmtTypeName(zcu),
+ ty.fmt(pt),
+ });
+ var it = struct_type.iterateRuntimeOrder(ip);
+ var offset: u64 = 0;
+ while (it.next()) |field_index| {
+ const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);
+ if (!field_ty.hasRuntimeBits(zcu)) continue;
+ const natural_align = field_ty.defaultStructFieldAlignment(struct_type.layout, zcu);
+ const natural_offset = switch (pack) {
+ true => offset,
+ false => natural_align.forward(offset),
+ };
+ const actual_offset = struct_type.field_offsets.get(ip)[field_index];
+ try w.writeByte(' ');
+ if (actual_offset == 0 and overalign) {
+ // This is the first field; specify its alignment to align the struct.
+ try writeFieldAlign(field_ty, struct_type.alignment, w, zcu);
+ } else if (actual_offset > natural_offset) {
+ // This field needs to be underaligned or overaligned compared to what its
+ // offset would otherwise be.
+ const need_align: Alignment = .minStrict(
+ struct_type.alignment, // don't make the struct more aligned than it should be
+ .fromLog2Units(@ctz(actual_offset)),
+ );
+ try writeFieldAlign(field_ty, need_align, w, zcu);
+ }
+ const field_cty: CType = try .lower(field_ty, deps, arena, zcu);
+ const field_name = struct_type.field_names.get(ip)[field_index].toSlice(ip);
+ try w.print("{f}{f}{f};\n", .{
+ field_cty.fmtDeclaratorPrefix(zcu),
+ fmtIdentSolo(field_name),
+ field_cty.fmtDeclaratorSuffix(zcu),
+ });
+ offset = actual_offset + field_ty.abiSize(zcu);
+ }
+ assert(struct_type.alignment.forward(offset) == struct_type.size);
+ try w.writeByte('}');
+ if (pack) try w.writeByte(')');
+ try w.writeAll(";\n");
+
+ try writeStaticAssertLayout(ty, name_cty, w, zcu);
+}
+fn defineUnionAuto(
+ ty: Type,
+ deps: *CType.Dependencies,
+ arena: Allocator,
+ w: *Writer,
+ pt: Zcu.PerThread,
+) (Allocator.Error || Writer.Error)!void {
+ const zcu = pt.zcu;
+ if (!ty.hasRuntimeBits(zcu)) return;
+ const ip = &zcu.intern_pool;
+
+ const union_type = ip.loadUnionType(ty.toIntern());
+ const enum_tag_ty: Type = .fromInterned(union_type.enum_tag_type);
+
+ const layout = Type.getUnionLayout(union_type, zcu);
+
+ // If there are any underaligned fields, we need to byte-pack the union.
+ const pack: bool = for (union_type.field_types.get(ip)) |field_ty_ip| {
+ const field_ty: Type = .fromInterned(field_ty_ip);
+ if (!field_ty.hasRuntimeBits(zcu)) continue;
+ const natural_align = field_ty.abiAlignment(zcu);
+ if (natural_align.compareStrict(.gt, union_type.alignment)) break true;
+ // The tag will immediately follow the payload. This layout may put the tag in what would
+ // otherwise be padding on the payload union, because if the most-aligned union field is not
+ // the largest one, a larger field may make the payload "underaligned" overall. As such, we
+ // need to check whether this field is okay with the payload size, and if not then we must
+ // byte-pack.
+ if (!natural_align.check(layout.payload_size)) break true;
+ } else false;
+
+ // If the alignment of other fields would not give the union sufficient alignment, we
+ // need to align the first field (which does not affect its offset, because 0 is always
+ // well-aligned) to indirectly specify the union alignment.
+ const overalign: bool = switch (pack) {
+ true => union_type.alignment.compareStrict(.gt, .@"1"),
+ false => for (union_type.field_types.get(ip)) |field_ty_ip| {
+ const field_ty: Type = .fromInterned(field_ty_ip);
+ if (!field_ty.hasRuntimeBits(zcu)) continue;
+ const natural_align = field_ty.abiAlignment(zcu);
+ if (natural_align.compareStrict(.gte, union_type.alignment)) break false;
+ } else overalign: {
+ if (union_type.has_runtime_tag) {
+ const tag_align = enum_tag_ty.abiAlignment(zcu);
+ if (tag_align.compareStrict(.gte, union_type.alignment)) break :overalign false;
+ }
+ break :overalign true;
+ },
+ };
+
+ const payload_has_bits = !union_type.has_runtime_tag or union_type.size > enum_tag_ty.abiSize(zcu);
+
+ const name_cty: CType = .{ .union_auto = ty };
+ try w.print("{f} {{ /* {f} */\n", .{
+ name_cty.fmtTypeName(zcu),
+ ty.fmt(pt),
+ });
+ if (payload_has_bits) {
+ try w.writeByte(' ');
+ if (overalign) {
+ // Specify the alignment of `union { ... } payload;` to align the union's `struct`.
+ try w.print("zig_align({d}) ", .{union_type.alignment.toByteUnits().?});
+ }
+ if (pack) try w.writeAll("zig_packed(");
+ try w.writeAll("union {\n");
+ for (0..enum_tag_ty.enumFieldCount(zcu)) |field_index| {
+ const field_ty = ty.fieldType(field_index, zcu);
+ if (!field_ty.hasRuntimeBits(zcu)) continue;
+ const field_name = enum_tag_ty.enumFieldName(field_index, zcu).toSlice(ip);
+ const field_cty: CType = try .lower(field_ty, deps, arena, zcu);
+ try w.print(" {f}{f}{f};\n", .{
+ field_cty.fmtDeclaratorPrefix(zcu),
+ fmtIdentSolo(field_name),
+ field_cty.fmtDeclaratorSuffix(zcu),
+ });
+ }
+ try w.writeAll(" }");
+ if (pack) try w.writeByte(')');
+ try w.writeAll(" payload;\n");
+ }
+ if (union_type.has_runtime_tag) {
+ const tag_cty: CType = try .lower(enum_tag_ty, deps, arena, zcu);
+ try w.print(" {f}tag{f};\n", .{
+ tag_cty.fmtDeclaratorPrefix(zcu),
+ tag_cty.fmtDeclaratorSuffix(zcu),
+ });
+ }
+ try w.writeAll("};\n");
+
+ try writeStaticAssertLayout(ty, name_cty, w, zcu);
+}
+fn defineUnionExtern(
+ ty: Type,
+ deps: *CType.Dependencies,
+ arena: Allocator,
+ w: *Writer,
+ pt: Zcu.PerThread,
+) (Allocator.Error || Writer.Error)!void {
+ const zcu = pt.zcu;
+ if (!ty.hasRuntimeBits(zcu)) return;
+ const ip = &zcu.intern_pool;
+
+ const union_type = ip.loadUnionType(ty.toIntern());
+ assert(!union_type.has_runtime_tag);
+ const enum_tag_ty: Type = .fromInterned(union_type.enum_tag_type);
+
+ // If there are any underaligned fields, we need to byte-pack the union.
+ const pack: bool = for (union_type.field_types.get(ip)) |field_ty_ip| {
+ const field_ty: Type = .fromInterned(field_ty_ip);
+ if (!field_ty.hasRuntimeBits(zcu)) continue;
+ const natural_align = field_ty.abiAlignment(zcu);
+ if (natural_align.compareStrict(.gt, union_type.alignment)) break true;
+ } else false;
+
+ // If the alignment of other fields would not give the union sufficient alignment, we
+ // need to align the first field (which does not affect its offset, because 0 is always
+ // well-aligned) to indirectly specify the union alignment.
+ const overalign: bool = switch (pack) {
+ true => union_type.alignment.compareStrict(.gt, .@"1"),
+ false => for (union_type.field_types.get(ip)) |field_ty_ip| {
+ const field_ty: Type = .fromInterned(field_ty_ip);
+ if (!field_ty.hasRuntimeBits(zcu)) continue;
+ const natural_align = field_ty.abiAlignment(zcu);
+ if (natural_align.compareStrict(.gte, union_type.alignment)) break false;
+ } else overalign: {
+ if (union_type.has_runtime_tag) {
+ const tag_align = enum_tag_ty.abiAlignment(zcu);
+ if (tag_align.compareStrict(.gte, union_type.alignment)) break :overalign false;
+ }
+ break :overalign true;
+ },
+ };
+
+ if (pack) try w.writeAll("zig_packed(");
+
+ const name_cty: CType = .{ .union_extern = ty };
+ try w.print("{f} {{ /* {f} */\n", .{
+ name_cty.fmtTypeName(zcu),
+ ty.fmt(pt),
+ });
+
+ for (0..enum_tag_ty.enumFieldCount(zcu)) |field_index| {
+ const field_ty = ty.fieldType(field_index, zcu);
+ if (!field_ty.hasRuntimeBits(zcu)) continue;
+ const field_name = enum_tag_ty.enumFieldName(field_index, zcu).toSlice(ip);
+ const field_cty: CType = try .lower(field_ty, deps, arena, zcu);
+ try w.writeByte(' ');
+ if (overalign and field_index == 0) {
+ // This is the first field; specify its alignment to align the union.
+ try writeFieldAlign(field_ty, union_type.alignment, w, zcu);
+ }
+ try w.print("{f}{f}{f};\n", .{
+ field_cty.fmtDeclaratorPrefix(zcu),
+ fmtIdentSolo(field_name),
+ field_cty.fmtDeclaratorSuffix(zcu),
+ });
+ }
+ try w.writeByte('}');
+ if (pack) try w.writeByte(')');
+ try w.writeAll(";\n");
+
+ try writeStaticAssertLayout(ty, name_cty, w, zcu);
+}
+
+/// Writes an annotation which, placed before a struct/union field declaration with field type `ty`,
+/// will specify that field as having the given alignment.
+fn writeFieldAlign(
+ ty: Type,
+ alignment: Alignment,
+ w: *Writer,
+ zcu: *const Zcu,
+) Writer.Error!void {
+ if (alignment.compareStrict(.lt, ty.abiAlignment(zcu))) {
+ try w.print("zig_under_align({d}) ", .{alignment.toByteUnits().?});
+ } else {
+ try w.print("zig_align({d}) ", .{alignment.toByteUnits().?});
+ }
+}
+
+/// Emits static assertions that the size and alignment of `cty` match those of the Zig type `ty`.
+fn writeStaticAssertLayout(
+ ty: Type,
+ cty: CType,
+ w: *Writer,
+ zcu: *const Zcu,
+) Writer.Error!void {
+ try w.print(
+ \\zig_static_assert(sizeof ({f}) == {d}, "incorrect size");
+ \\zig_static_assert(_Alignof ({f}) == {d}, "incorrect alignment");
+ \\
+ , .{
+ cty.fmtTypeName(zcu), ty.abiSize(zcu),
+ cty.fmtTypeName(zcu), ty.abiAlignment(zcu).toByteUnits().?,
+ });
+}
+
+const std = @import("std");
+const assert = std.debug.assert;
+const Writer = std.Io.Writer;
+const Allocator = std.mem.Allocator;
+
+const Zcu = @import("../../../Zcu.zig");
+const Type = @import("../../../Type.zig");
+const Value = @import("../../../Value.zig");
+const CType = @import("../type.zig").CType;
+const Alignment = @import("../../../InternPool.zig").Alignment;
+
+const fmtIdentSolo = @import("../../c.zig").fmtIdentSolo;
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index 4ef72e8ab7fed1786845aa5b8e08d1ddfe6091fa..fc487d5a2618d3357f8fa422fcd79760f835d916 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -520,6 +520,21 @@ pub const Object = struct {
gpa: Allocator,
builder: Builder,
+ /// This pool contains only types (and not `@as(type, undefined)`). It has two purposes:
+ ///
+ /// * Lazily tracking ABI alignment of types, so that `@"align"` attributes can be set to a
+ /// type's ABI alignment before that type is fully resolved. Each type in the pool has a
+ /// corresponding entry in `lazy_abi_aligns`.
+ ///
+ /// * If `!Object.builder.strip`, lazily tracking debug information types, so that debug
+ /// information can handle indirect self-reference (and so that debug information works
+ /// correctly across incremental updates). Each type has a corresponding entry in
+ /// `debug_types`, provided that `Object.builder.strip` is `false`.
+ type_pool: link.ConstPool,
+
+ /// Keyed on `link.ConstPool.Index`.
+ lazy_abi_aligns: std.ArrayList(Builder.Alignment.Lazy),
+
debug_compile_unit: Builder.Metadata.Optional,
debug_enums_fwd_ref: Builder.Metadata.Optional,
@@ -529,9 +544,13 @@ pub const Object = struct {
debug_globals: std.ArrayList(Builder.Metadata),
debug_file_map: std.AutoHashMapUnmanaged(Zcu.File.Index, Builder.Metadata),
- debug_type_map: std.AutoHashMapUnmanaged(InternPool.Index, Builder.Metadata),
- debug_unresolved_namespace_scopes: std.AutoArrayHashMapUnmanaged(InternPool.NamespaceIndex, Builder.Metadata),
+ /// Keyed on `link.ConstPool.Index`.
+ debug_types: std.ArrayList(Builder.Metadata),
+ /// Initially `.none`, set if the type `anyerror` is lowered to a debug type. The type will not
+ /// actually be created until `emit`, which must resolve this reference with an appropriate enum
+ /// type from the global error set.
+ debug_anyerror_fwd_ref: Builder.Metadata.Optional,
target: *const std.Target,
/// Ideally we would use `llvm_module.getNamedFunction` to go from *Decl to LLVM function,
@@ -654,35 +673,38 @@ pub const Object = struct {
obj.* = .{
.gpa = gpa,
.builder = builder,
+ .type_pool = .empty,
+ .lazy_abi_aligns = .empty,
.debug_compile_unit = debug_compile_unit,
.debug_enums_fwd_ref = debug_enums_fwd_ref,
.debug_globals_fwd_ref = debug_globals_fwd_ref,
- .debug_enums = .{},
- .debug_globals = .{},
- .debug_file_map = .{},
- .debug_type_map = .{},
- .debug_unresolved_namespace_scopes = .{},
+ .debug_enums = .empty,
+ .debug_globals = .empty,
+ .debug_file_map = .empty,
+ .debug_types = .empty,
+ .debug_anyerror_fwd_ref = .none,
.target = target,
- .nav_map = .{},
- .uav_map = .{},
- .enum_tag_name_map = .{},
- .named_enum_map = .{},
- .type_map = .{},
+ .nav_map = .empty,
+ .uav_map = .empty,
+ .enum_tag_name_map = .empty,
+ .named_enum_map = .empty,
+ .type_map = .empty,
.error_name_table = .none,
.null_opt_usize = .no_init,
- .struct_field_map = .{},
- .used = .{},
+ .struct_field_map = .empty,
+ .used = .empty,
};
return obj;
}
pub fn deinit(self: *Object) void {
const gpa = self.gpa;
+ self.type_pool.deinit(gpa);
+ self.lazy_abi_aligns.deinit(gpa);
self.debug_enums.deinit(gpa);
self.debug_globals.deinit(gpa);
self.debug_file_map.deinit(gpa);
- self.debug_type_map.deinit(gpa);
- self.debug_unresolved_namespace_scopes.deinit(gpa);
+ self.debug_types.deinit(gpa);
self.nav_map.deinit(gpa);
self.uav_map.deinit(gpa);
self.enum_tag_name_map.deinit(gpa);
@@ -824,19 +846,13 @@ pub const Object = struct {
}
if (!o.builder.strip) {
- {
- var i: usize = 0;
- while (i < o.debug_unresolved_namespace_scopes.count()) : (i += 1) {
- const namespace_index = o.debug_unresolved_namespace_scopes.keys()[i];
- const fwd_ref = o.debug_unresolved_namespace_scopes.values()[i];
-
- const namespace = zcu.namespacePtr(namespace_index);
- const debug_type = try o.lowerDebugType(pt, Type.fromInterned(namespace.owner_type));
-
- o.builder.resolveDebugForwardReference(fwd_ref, debug_type);
- }
+ if (o.debug_anyerror_fwd_ref.unwrap()) |fwd_ref| {
+ const debug_anyerror_type = try o.lowerDebugAnyerrorType(pt);
+ o.builder.resolveDebugForwardReference(fwd_ref, debug_anyerror_type);
}
+ try o.flushTypePool(pt);
+
o.builder.resolveDebugForwardReference(
o.debug_enums_fwd_ref.unwrap().?,
try o.builder.metadataTuple(o.debug_enums.items),
@@ -1395,10 +1411,10 @@ pub const Object = struct {
if (ptr_info.flags.is_const) {
try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
}
- const elem_align = (if (ptr_info.flags.alignment != .none)
- @as(InternPool.Alignment, ptr_info.flags.alignment)
- else
- Type.fromInterned(ptr_info.child).abiAlignment(zcu).max(.@"1")).toLlvm();
+ const elem_align: Builder.Alignment.Lazy = switch (ptr_info.flags.alignment) {
+ else => |a| .wrap(a.toLlvm()),
+ .none => try o.lazyAbiAlignment(pt, .fromInterned(ptr_info.child)),
+ };
try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
const ptr_param = wip.arg(llvm_arg_i);
llvm_arg_i += 1;
@@ -1472,7 +1488,7 @@ pub const Object = struct {
const line_number = zcu.navSrcLine(func.owner_nav) + 1;
const is_internal_linkage = ip.indexToKey(nav.status.fully_resolved.val) != .@"extern";
- const debug_decl_type = try o.lowerDebugType(pt, fn_ty);
+ const debug_decl_type = try o.getDebugType(pt, fn_ty);
const subprogram = try o.builder.debugSubprogram(
file,
@@ -1522,7 +1538,7 @@ pub const Object = struct {
break :f .{
.counters_variable = counters_variable,
- .pcs = .{},
+ .pcs = .empty,
};
};
@@ -1538,10 +1554,10 @@ pub const Object = struct {
.args = args.items,
.arg_index = 0,
.arg_inline_index = 0,
- .func_inst_table = .{},
- .blocks = .{},
- .loops = .{},
- .switch_dispatch_info = .{},
+ .func_inst_table = .empty,
+ .blocks = .empty,
+ .loops = .empty,
+ .switch_dispatch_info = .empty,
.sync_scope = if (owner_mod.single_threaded) .singlethread else .system,
.file = file,
.scope = subprogram,
@@ -1599,6 +1615,7 @@ pub const Object = struct {
}
try fg.wip.finish();
+ try o.flushTypePool(pt);
}
pub fn updateNav(self: *Object, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {
@@ -1615,6 +1632,11 @@ pub const Object = struct {
},
else => |e| return e,
};
+ try self.flushTypePool(pt);
+ }
+
+ fn flushTypePool(o: *Object, pt: Zcu.PerThread) Allocator.Error!void {
+ try o.type_pool.flushPending(pt, .{ .llvm = o });
}
pub fn updateExports(
@@ -1810,6 +1832,84 @@ pub const Object = struct {
}
}
+ pub fn updateContainerType(o: *Object, pt: Zcu.PerThread, ty: InternPool.Index, success: bool) Allocator.Error!void {
+ try o.type_pool.updateContainerType(pt, .{ .llvm = o }, ty, success);
+ }
+
+ /// Should only be called by the `link.ConstPool` implementation.
+ ///
+ /// `val` is always a type because `o.type_pool` only contains types.
+ pub fn addConst(o: *Object, pt: Zcu.PerThread, index: link.ConstPool.Index, val: InternPool.Index) Allocator.Error!void {
+ const zcu = pt.zcu;
+ const gpa = zcu.comp.gpa;
+ assert(zcu.intern_pool.typeOf(val) == .type_type);
+
+ {
+ assert(@intFromEnum(index) == o.lazy_abi_aligns.items.len);
+ try o.lazy_abi_aligns.ensureUnusedCapacity(gpa, 1);
+ const fwd_ref = try o.builder.alignmentForwardReference();
+ o.lazy_abi_aligns.appendAssumeCapacity(fwd_ref);
+ }
+
+ if (!o.builder.strip) {
+ assert(@intFromEnum(index) == o.debug_types.items.len);
+ try o.debug_types.ensureUnusedCapacity(gpa, 1);
+ const fwd_ref = try o.builder.debugForwardReference();
+ o.debug_types.appendAssumeCapacity(fwd_ref);
+ if (val == .anyerror_type) {
+ assert(o.debug_anyerror_fwd_ref.is_none);
+ o.debug_anyerror_fwd_ref = fwd_ref.toOptional();
+ }
+ }
+ }
+ /// Should only be called by the `link.ConstPool` implementation.
+ ///
+ /// `val` is always a type because `o.type_pool` only contains types.
+ pub fn updateConstIncomplete(o: *Object, pt: Zcu.PerThread, index: link.ConstPool.Index, val: InternPool.Index) Allocator.Error!void {
+ const zcu = pt.zcu;
+ assert(zcu.intern_pool.typeOf(val) == .type_type);
+
+ const ty: Type = .fromInterned(val);
+
+ {
+ const fwd_ref = o.lazy_abi_aligns.items[@intFromEnum(index)];
+ o.builder.resolveAlignmentForwardReference(fwd_ref, .fromByteUnits(1));
+ }
+
+ if (!o.builder.strip) {
+ assert(val != .anyerror_type);
+ const fwd_ref = o.debug_types.items[@intFromEnum(index)];
+ const name_str = try o.builder.metadataStringFmt("{f}", .{ty.fmt(pt)});
+ const debug_incomplete_type = try o.builder.debugSignedType(name_str, 0);
+ o.builder.resolveDebugForwardReference(fwd_ref, debug_incomplete_type);
+ }
+ }
+ /// Should only be called by the `link.ConstPool` implementation.
+ ///
+ /// `val` is always a type because `o.type_pool` only contains types.
+ pub fn updateConst(o: *Object, pt: Zcu.PerThread, index: link.ConstPool.Index, val: InternPool.Index) Allocator.Error!void {
+ const zcu = pt.zcu;
+ assert(zcu.intern_pool.typeOf(val) == .type_type);
+
+ const ty: Type = .fromInterned(val);
+
+ {
+ const fwd_ref = o.lazy_abi_aligns.items[@intFromEnum(index)];
+ o.builder.resolveAlignmentForwardReference(fwd_ref, ty.abiAlignment(zcu).toLlvm());
+ }
+
+ if (!o.builder.strip) {
+ const fwd_ref = o.debug_types.items[@intFromEnum(index)];
+ if (val == .anyerror_type) {
+ // Don't lower this now; it will be populated in `emit` instead.
+ assert(o.debug_anyerror_fwd_ref == fwd_ref.toOptional());
+ } else {
+ const debug_type = try o.lowerDebugType(pt, ty, fwd_ref);
+ o.builder.resolveDebugForwardReference(fwd_ref, debug_type);
+ }
+ }
+ }
+
fn getDebugFile(o: *Object, pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator.Error!Builder.Metadata {
const gpa = o.gpa;
const gop = try o.debug_file_map.getOrPut(gpa, file_index);
@@ -1826,10 +1926,19 @@ pub const Object = struct {
return gop.value_ptr.*;
}
- pub fn lowerDebugType(
+ fn getDebugType(o: *Object, pt: Zcu.PerThread, ty: Type) Allocator.Error!Builder.Metadata {
+ assert(!o.builder.strip);
+ const index = try o.type_pool.get(pt, .{ .llvm = o }, ty.toIntern());
+ return o.debug_types.items[@intFromEnum(index)];
+ }
+
+ /// In codegen logic, instead of calling this directly, use `getDebugType` to get a forward
+ /// reference which will be populated only when all necessary type resolution is complete.
+ fn lowerDebugType(
o: *Object,
pt: Zcu.PerThread,
ty: Type,
+ ty_fwd_ref: Builder.Metadata,
) Allocator.Error!Builder.Metadata {
assert(!o.builder.strip);
@@ -1838,312 +1947,137 @@ pub const Object = struct {
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
- if (o.debug_type_map.get(ty.toIntern())) |debug_type| return debug_type;
+ const name = try o.builder.metadataStringFmt("{f}", .{ty.fmt(pt)});
+
+ // lldb cannot handle non-byte-sized types, so in the logic below, bit sizes are padded up.
+ // For instance, `bool` is considered to be 8 bits, and `u60` is considered to be 64 bits.
+
+ // I tried using variants (DW_TAG_variant_part + DW_TAG_variant) to encode error unions,
+ // tagged unions, etc; this would have told debuggers which field was active, which could
+ // improve UX significantly. GDB handles this perfectly fine, but unfortunately, LLDB has no
+ // handling for variants at all, and will never print fields in them, so I opted not to use
+ // them for now.
switch (ty.zigTypeTag(zcu)) {
.void,
.noreturn,
- => {
- const debug_void_type = try o.builder.debugSignedType(
- try o.builder.metadataString("void"),
- 0,
- );
- try o.debug_type_map.put(gpa, ty.toIntern(), debug_void_type);
- return debug_void_type;
- },
+ .comptime_int,
+ .comptime_float,
+ .type,
+ .undefined,
+ .null,
+ .enum_literal,
+ => return o.builder.debugSignedType(name, 0),
+
+ .float => return o.builder.debugFloatType(name, ty.floatBits(target)),
+
+ .bool => return o.builder.debugBoolType(name, 8),
+
.int => {
const info = ty.intInfo(zcu);
- assert(info.bits != 0);
- const name = try o.allocTypeName(pt, ty);
- defer gpa.free(name);
- const builder_name = try o.builder.metadataString(name);
- const debug_bits = ty.abiSize(zcu) * 8; // lldb cannot handle non-byte sized types
- const debug_int_type = switch (info.signedness) {
- .signed => try o.builder.debugSignedType(builder_name, debug_bits),
- .unsigned => try o.builder.debugUnsignedType(builder_name, debug_bits),
+ const bits = ty.abiSize(zcu) * 8;
+ return switch (info.signedness) {
+ .signed => try o.builder.debugSignedType(name, bits),
+ .unsigned => try o.builder.debugUnsignedType(name, bits),
};
- try o.debug_type_map.put(gpa, ty.toIntern(), debug_int_type);
- return debug_int_type;
},
- .@"enum" => {
- if (!ty.hasRuntimeBitsIgnoreComptime(zcu)) {
- const debug_enum_type = try o.makeEmptyNamespaceDebugType(pt, ty);
- try o.debug_type_map.put(gpa, ty.toIntern(), debug_enum_type);
- return debug_enum_type;
- }
- const enum_type = ip.loadEnumType(ty.toIntern());
- const enumerators = try gpa.alloc(Builder.Metadata, enum_type.names.len);
- defer gpa.free(enumerators);
-
- const int_ty = Type.fromInterned(enum_type.tag_ty);
- const int_info = ty.intInfo(zcu);
- assert(int_info.bits != 0);
-
- for (enum_type.names.get(ip), 0..) |field_name_ip, i| {
- var bigint_space: Value.BigIntSpace = undefined;
- const bigint = if (enum_type.values.len != 0)
- Value.fromInterned(enum_type.values.get(ip)[i]).toBigInt(&bigint_space, zcu)
- else
- std.math.big.int.Mutable.init(&bigint_space.limbs, i).toConst();
-
- enumerators[i] = try o.builder.debugEnumerator(
- try o.builder.metadataString(field_name_ip.toSlice(ip)),
- int_info.signedness == .unsigned,
- int_info.bits,
- bigint,
- );
- }
-
- const file = try o.getDebugFile(pt, ty.typeDeclInstAllowGeneratedTag(zcu).?.resolveFile(ip));
- const scope = if (ty.getParentNamespace(zcu).unwrap()) |parent_namespace|
- try o.namespaceToDebugScope(pt, parent_namespace)
- else
- file;
-
- const name = try o.allocTypeName(pt, ty);
- defer gpa.free(name);
-
- const debug_enum_type = try o.builder.debugEnumerationType(
- try o.builder.metadataString(name),
- file,
- scope,
- ty.typeDeclSrcLine(zcu).? + 1, // Line
- try o.lowerDebugType(pt, int_ty),
- ty.abiSize(zcu) * 8,
- (ty.abiAlignment(zcu).toByteUnits() orelse 0) * 8,
- try o.builder.metadataTuple(enumerators),
- );
-
- try o.debug_type_map.put(gpa, ty.toIntern(), debug_enum_type);
- try o.debug_enums.append(gpa, debug_enum_type);
- return debug_enum_type;
- },
- .float => {
- const bits = ty.floatBits(target);
- const name = try o.allocTypeName(pt, ty);
- defer gpa.free(name);
- const debug_float_type = try o.builder.debugFloatType(
- try o.builder.metadataString(name),
- bits,
- );
- try o.debug_type_map.put(gpa, ty.toIntern(), debug_float_type);
- return debug_float_type;
- },
- .bool => {
- const debug_bool_type = try o.builder.debugBoolType(
- try o.builder.metadataString("bool"),
- 8, // lldb cannot handle non-byte sized types
- );
- try o.debug_type_map.put(gpa, ty.toIntern(), debug_bool_type);
- return debug_bool_type;
- },
.pointer => {
- // Normalize everything that the debug info does not represent.
- const ptr_info = ty.ptrInfo(zcu);
-
- if (ptr_info.sentinel != .none or
- ptr_info.flags.address_space != .generic or
- ptr_info.packed_offset.bit_offset != 0 or
- ptr_info.packed_offset.host_size != 0 or
- ptr_info.flags.vector_index != .none or
- ptr_info.flags.is_allowzero or
- ptr_info.flags.is_const or
- ptr_info.flags.is_volatile or
- ptr_info.flags.size == .many or ptr_info.flags.size == .c or
- !Type.fromInterned(ptr_info.child).hasRuntimeBitsIgnoreComptime(zcu))
- {
- const bland_ptr_ty = try pt.ptrType(.{
- .child = if (!Type.fromInterned(ptr_info.child).hasRuntimeBitsIgnoreComptime(zcu))
- .anyopaque_type
- else
- ptr_info.child,
- .flags = .{
- .alignment = ptr_info.flags.alignment,
- .size = switch (ptr_info.flags.size) {
- .many, .c, .one => .one,
- .slice => .slice,
- },
- },
- });
- const debug_ptr_type = try o.lowerDebugType(pt, bland_ptr_ty);
- try o.debug_type_map.put(gpa, ty.toIntern(), debug_ptr_type);
- return debug_ptr_type;
- }
-
- const debug_fwd_ref = try o.builder.debugForwardReference();
-
- // Set as forward reference while the type is lowered in case it references itself
- try o.debug_type_map.put(gpa, ty.toIntern(), debug_fwd_ref);
+ const ptr_size = Type.ptrAbiSize(zcu.getTarget());
+ const ptr_align = Type.ptrAbiAlignment(zcu.getTarget());
if (ty.isSlice(zcu)) {
- const ptr_ty = ty.slicePtrFieldType(zcu);
- const len_ty = Type.usize;
-
- const name = try o.allocTypeName(pt, ty);
- defer gpa.free(name);
- const line = 0;
-
- const ptr_size = ptr_ty.abiSize(zcu);
- const ptr_align = ptr_ty.abiAlignment(zcu);
- const len_size = len_ty.abiSize(zcu);
- const len_align = len_ty.abiAlignment(zcu);
-
- const len_offset = len_align.forward(ptr_size);
-
const debug_ptr_type = try o.builder.debugMemberType(
try o.builder.metadataString("ptr"),
- null, // File
- debug_fwd_ref,
- 0, // Line
- try o.lowerDebugType(pt, ptr_ty),
+ null, // file
+ ty_fwd_ref,
+ 0, // line
+ try o.getDebugType(pt, ty.slicePtrFieldType(zcu)),
ptr_size * 8,
- (ptr_align.toByteUnits() orelse 0) * 8,
- 0, // Offset
+ ptr_align.toByteUnits().? * 8,
+ 0, // offset
);
const debug_len_type = try o.builder.debugMemberType(
try o.builder.metadataString("len"),
- null, // File
- debug_fwd_ref,
- 0, // Line
- try o.lowerDebugType(pt, len_ty),
- len_size * 8,
- (len_align.toByteUnits() orelse 0) * 8,
- len_offset * 8,
+ null, // file
+ ty_fwd_ref,
+ 0, // line
+ try o.getDebugType(pt, .usize),
+ ptr_size * 8,
+ ptr_align.toByteUnits().? * 8,
+ ptr_size * 8,
);
- const debug_slice_type = try o.builder.debugStructType(
- try o.builder.metadataString(name),
- null, // File
- o.debug_compile_unit.unwrap().?, // Scope
- line,
- null, // Underlying type
- ty.abiSize(zcu) * 8,
- (ty.abiAlignment(zcu).toByteUnits() orelse 0) * 8,
+ return o.builder.debugStructType(
+ name,
+ null, // file
+ o.debug_compile_unit.unwrap().?, // scope
+ 0, // line
+ null, // underlying type
+ ptr_size * 2 * 8,
+ ptr_align.toByteUnits().? * 8,
try o.builder.metadataTuple(&.{
debug_ptr_type,
debug_len_type,
}),
);
-
- o.builder.resolveDebugForwardReference(debug_fwd_ref, debug_slice_type);
-
- // Set to real type now that it has been lowered fully
- const map_ptr = o.debug_type_map.getPtr(ty.toIntern()) orelse unreachable;
- map_ptr.* = debug_slice_type;
-
- return debug_slice_type;
- }
-
- const debug_elem_ty = try o.lowerDebugType(pt, Type.fromInterned(ptr_info.child));
-
- const name = try o.allocTypeName(pt, ty);
- defer gpa.free(name);
-
- const debug_ptr_type = try o.builder.debugPointerType(
- try o.builder.metadataString(name),
- null, // File
- null, // Scope
- 0, // Line
- debug_elem_ty,
- target.ptrBitWidth(),
- (ty.ptrAlignment(zcu).toByteUnits() orelse 0) * 8,
- 0, // Offset
- );
-
- o.builder.resolveDebugForwardReference(debug_fwd_ref, debug_ptr_type);
-
- // Set to real type now that it has been lowered fully
- const map_ptr = o.debug_type_map.getPtr(ty.toIntern()) orelse unreachable;
- map_ptr.* = debug_ptr_type;
-
- return debug_ptr_type;
- },
- .@"opaque" => {
- if (ty.toIntern() == .anyopaque_type) {
- const debug_opaque_type = try o.builder.debugSignedType(
- try o.builder.metadataString("anyopaque"),
- 0,
- );
- try o.debug_type_map.put(gpa, ty.toIntern(), debug_opaque_type);
- return debug_opaque_type;
}
- const name = try o.allocTypeName(pt, ty);
- defer gpa.free(name);
-
- const file = try o.getDebugFile(pt, ty.typeDeclInstAllowGeneratedTag(zcu).?.resolveFile(ip));
- const scope = if (ty.getParentNamespace(zcu).unwrap()) |parent_namespace|
- try o.namespaceToDebugScope(pt, parent_namespace)
- else
- file;
-
- const debug_opaque_type = try o.builder.debugStructType(
- try o.builder.metadataString(name),
- file,
- scope,
- ty.typeDeclSrcLine(zcu).? + 1, // Line
- null, // Underlying type
- 0, // Size
- 0, // Align
- null, // Fields
- );
- try o.debug_type_map.put(gpa, ty.toIntern(), debug_opaque_type);
- return debug_opaque_type;
- },
- .array => {
- const debug_array_type = try o.builder.debugArrayType(
- null, // Name
- null, // File
- null, // Scope
- 0, // Line
- try o.lowerDebugType(pt, ty.childType(zcu)),
- ty.abiSize(zcu) * 8,
- (ty.abiAlignment(zcu).toByteUnits() orelse 0) * 8,
- try o.builder.metadataTuple(&.{
- try o.builder.debugSubrange(
- try o.builder.metadataConstant(try o.builder.intConst(.i64, 0)),
- try o.builder.metadataConstant(try o.builder.intConst(.i64, ty.arrayLen(zcu))),
- ),
- }),
+ return o.builder.debugPointerType(
+ name,
+ null, // file
+ o.debug_compile_unit.unwrap().?, // scope
+ 0, // line
+ try o.getDebugType(pt, ty.childType(zcu)),
+ ptr_size * 8,
+ ptr_align.toByteUnits().? * 8,
+ 0, // offset
);
- try o.debug_type_map.put(gpa, ty.toIntern(), debug_array_type);
- return debug_array_type;
},
+ .array => return o.builder.debugArrayType(
+ name,
+ null, // file
+ o.debug_compile_unit.unwrap().?, // scope
+ 0, // line
+ try o.getDebugType(pt, ty.childType(zcu)),
+ ty.abiSize(zcu) * 8,
+ ty.abiAlignment(zcu).toByteUnits().? * 8,
+ try o.builder.metadataTuple(&.{
+ try o.builder.debugSubrange(
+ try o.builder.metadataConstant(try o.builder.intConst(.i64, 0)),
+ try o.builder.metadataConstant(try o.builder.intConst(.i64, ty.arrayLen(zcu))),
+ ),
+ }),
+ ),
.vector => {
- const elem_ty = ty.elemType2(zcu);
+ const elem_ty = ty.childType(zcu);
// Vector elements cannot be padded since that would make
- // @bitSizOf(elem) * len > @bitSizOf(vec).
+ // @bitSizeOf(elem) * len > @bitSizOf(vec).
// Neither gdb nor lldb seem to be able to display non-byte sized
// vectors properly.
const debug_elem_type = switch (elem_ty.zigTypeTag(zcu)) {
.int => blk: {
const info = elem_ty.intInfo(zcu);
- assert(info.bits != 0);
- const name = try o.allocTypeName(pt, ty);
- defer gpa.free(name);
- const builder_name = try o.builder.metadataString(name);
break :blk switch (info.signedness) {
- .signed => try o.builder.debugSignedType(builder_name, info.bits),
- .unsigned => try o.builder.debugUnsignedType(builder_name, info.bits),
+ .signed => try o.builder.debugSignedType(name, info.bits),
+ .unsigned => try o.builder.debugUnsignedType(name, info.bits),
};
},
- .bool => try o.builder.debugBoolType(
- try o.builder.metadataString("bool"),
- 1,
- ),
- else => try o.lowerDebugType(pt, ty.childType(zcu)),
+ .bool => try o.builder.debugBoolType(try o.builder.metadataString("bool"), 1),
+ // We don't pad pointers or floats, so we can lower those normally.
+ .pointer, .optional, .float => try o.getDebugType(pt, elem_ty),
+ else => unreachable,
};
- const debug_vector_type = try o.builder.debugVectorType(
- null, // Name
- null, // File
- null, // Scope
- 0, // Line
+ return o.builder.debugVectorType(
+ name,
+ null, // file
+ o.debug_compile_unit.unwrap().?, // scope
+ 0, // line
debug_elem_type,
ty.abiSize(zcu) * 8,
- (ty.abiAlignment(zcu).toByteUnits() orelse 0) * 8,
+ ty.abiAlignment(zcu).toByteUnits().? * 8,
try o.builder.metadataTuple(&.{
try o.builder.debugSubrange(
try o.builder.metadataConstant(try o.builder.intConst(.i64, 0)),
@@ -2151,566 +2085,574 @@ pub const Object = struct {
),
}),
);
-
- try o.debug_type_map.put(gpa, ty.toIntern(), debug_vector_type);
- return debug_vector_type;
},
.optional => {
- const name = try o.allocTypeName(pt, ty);
- defer gpa.free(name);
- const child_ty = ty.optionalChild(zcu);
- if (!child_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
- const debug_bool_type = try o.builder.debugBoolType(
- try o.builder.metadataString(name),
- 8,
- );
- try o.debug_type_map.put(gpa, ty.toIntern(), debug_bool_type);
- return debug_bool_type;
- }
-
- const debug_fwd_ref = try o.builder.debugForwardReference();
-
- // Set as forward reference while the type is lowered in case it references itself
- try o.debug_type_map.put(gpa, ty.toIntern(), debug_fwd_ref);
-
+ const payload_ty = ty.optionalChild(zcu);
if (ty.optionalReprIsPayload(zcu)) {
- const debug_optional_type = try o.lowerDebugType(pt, child_ty);
-
- o.builder.resolveDebugForwardReference(debug_fwd_ref, debug_optional_type);
-
- // Set to real type now that it has been lowered fully
- const map_ptr = o.debug_type_map.getPtr(ty.toIntern()) orelse unreachable;
- map_ptr.* = debug_optional_type;
-
- return debug_optional_type;
+ return o.builder.debugTypedefType(
+ name,
+ null, // file
+ o.debug_compile_unit.unwrap().?, // scope
+ 0, // line
+ try o.getDebugType(pt, payload_ty),
+ ty.abiSize(zcu) * 8,
+ ty.abiAlignment(zcu).toByteUnits().? * 8,
+ 0, // offset
+ );
}
+ const payload_size = payload_ty.abiSize(zcu);
+
const non_null_ty = Type.u8;
- const payload_size = child_ty.abiSize(zcu);
- const payload_align = child_ty.abiAlignment(zcu);
const non_null_size = non_null_ty.abiSize(zcu);
const non_null_align = non_null_ty.abiAlignment(zcu);
const non_null_offset = non_null_align.forward(payload_size);
- const debug_data_type = try o.builder.debugMemberType(
- try o.builder.metadataString("data"),
- null, // File
- debug_fwd_ref,
- 0, // Line
- try o.lowerDebugType(pt, child_ty),
+ const debug_payload_type = try o.builder.debugMemberType(
+ try o.builder.metadataString("payload"),
+ null, // file
+ ty_fwd_ref, // scope
+ 0, // line
+ try o.getDebugType(pt, payload_ty),
payload_size * 8,
- (payload_align.toByteUnits() orelse 0) * 8,
- 0, // Offset
+ payload_ty.abiAlignment(zcu).toByteUnits().? * 8,
+ 0, // offset
);
const debug_some_type = try o.builder.debugMemberType(
try o.builder.metadataString("some"),
null,
- debug_fwd_ref,
+ ty_fwd_ref,
0,
- try o.lowerDebugType(pt, non_null_ty),
+ try o.getDebugType(pt, non_null_ty),
non_null_size * 8,
- (non_null_align.toByteUnits() orelse 0) * 8,
+ non_null_align.toByteUnits().? * 8,
non_null_offset * 8,
);
- const debug_optional_type = try o.builder.debugStructType(
- try o.builder.metadataString(name),
- null, // File
- o.debug_compile_unit.unwrap().?, // Scope
- 0, // Line
- null, // Underlying type
+ return o.builder.debugStructType(
+ name,
+ null, // file
+ o.debug_compile_unit.unwrap().?, // scope
+ 0, // line
+ null, // underlying type
ty.abiSize(zcu) * 8,
- (ty.abiAlignment(zcu).toByteUnits() orelse 0) * 8,
+ ty.abiAlignment(zcu).toByteUnits().? * 8,
try o.builder.metadataTuple(&.{
- debug_data_type,
+ debug_payload_type,
debug_some_type,
}),
);
-
- o.builder.resolveDebugForwardReference(debug_fwd_ref, debug_optional_type);
-
- // Set to real type now that it has been lowered fully
- const map_ptr = o.debug_type_map.getPtr(ty.toIntern()) orelse unreachable;
- map_ptr.* = debug_optional_type;
-
- return debug_optional_type;
},
.error_union => {
+ const error_ty = ty.errorUnionSet(zcu);
const payload_ty = ty.errorUnionPayload(zcu);
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
- // TODO: Maybe remove?
- const debug_error_union_type = try o.lowerDebugType(pt, Type.anyerror);
- try o.debug_type_map.put(gpa, ty.toIntern(), debug_error_union_type);
- return debug_error_union_type;
- }
- const name = try o.allocTypeName(pt, ty);
- defer gpa.free(name);
-
- const error_size = Type.anyerror.abiSize(zcu);
- const error_align = Type.anyerror.abiAlignment(zcu);
+ const error_size = error_ty.abiSize(zcu);
+ const error_align = error_ty.abiAlignment(zcu);
const payload_size = payload_ty.abiSize(zcu);
const payload_align = payload_ty.abiAlignment(zcu);
- var error_index: u32 = undefined;
- var payload_index: u32 = undefined;
- var error_offset: u64 = undefined;
- var payload_offset: u64 = undefined;
- if (error_align.compare(.gt, payload_align)) {
- error_index = 0;
- payload_index = 1;
- error_offset = 0;
- payload_offset = payload_align.forward(error_size);
- } else {
- payload_index = 0;
- error_index = 1;
- payload_offset = 0;
- error_offset = error_align.forward(payload_size);
- }
+ const error_offset: u64, const payload_offset: u64 = offsets: {
+ if (error_align.compare(.gt, payload_align)) {
+ break :offsets .{ 0, payload_align.forward(error_size) };
+ } else {
+ break :offsets .{ error_align.forward(payload_size), 0 };
+ }
+ };
- const debug_fwd_ref = try o.builder.debugForwardReference();
-
- var fields: [2]Builder.Metadata = undefined;
- fields[error_index] = try o.builder.debugMemberType(
- try o.builder.metadataString("tag"),
- null, // File
- debug_fwd_ref,
- 0, // Line
- try o.lowerDebugType(pt, Type.anyerror),
+ const error_field = try o.builder.debugMemberType(
+ try o.builder.metadataString("error"),
+ null, // file
+ ty_fwd_ref,
+ 0, // line
+ try o.getDebugType(pt, error_ty),
error_size * 8,
- (error_align.toByteUnits() orelse 0) * 8,
+ error_align.toByteUnits().? * 8,
error_offset * 8,
);
- fields[payload_index] = try o.builder.debugMemberType(
- try o.builder.metadataString("value"),
- null, // File
- debug_fwd_ref,
- 0, // Line
- try o.lowerDebugType(pt, payload_ty),
+ const payload_field = try o.builder.debugMemberType(
+ try o.builder.metadataString("payload"),
+ null, // file
+ ty_fwd_ref, // scope
+ 0, // line
+ try o.getDebugType(pt, payload_ty),
payload_size * 8,
- (payload_align.toByteUnits() orelse 0) * 8,
+ payload_align.toByteUnits().? * 8,
payload_offset * 8,
);
- const debug_error_union_type = try o.builder.debugStructType(
- try o.builder.metadataString(name),
+ return try o.builder.debugStructType(
+ name,
null, // File
- o.debug_compile_unit.unwrap().?, // Sope
+ o.debug_compile_unit.unwrap().?, // Scope
0, // Line
null, // Underlying type
ty.abiSize(zcu) * 8,
- (ty.abiAlignment(zcu).toByteUnits() orelse 0) * 8,
- try o.builder.metadataTuple(&fields),
+ ty.abiAlignment(zcu).toByteUnits().? * 8,
+ try o.builder.metadataTuple(&.{ error_field, payload_field }),
);
-
- o.builder.resolveDebugForwardReference(debug_fwd_ref, debug_error_union_type);
-
- try o.debug_type_map.put(gpa, ty.toIntern(), debug_error_union_type);
- return debug_error_union_type;
},
.error_set => {
- const debug_error_set = try o.builder.debugUnsignedType(
- try o.builder.metadataString("anyerror"),
- 16,
+ assert(ty.toIntern() != .anyerror_type); // handled specially in `updateConst`; will be populated by `emit` instead
+ // Error sets are just named wrappers around `anyerror`.
+ return o.builder.debugTypedefType(
+ name,
+ null, // file
+ o.debug_compile_unit.unwrap().?, // scope
+ 0, // line
+ try o.getDebugType(pt, .anyerror),
+ ty.abiSize(zcu) * 8,
+ ty.abiAlignment(zcu).toByteUnits().? * 8,
+ 0, // offset
+ );
+ },
+ .@"fn" => {
+ if (!ty.fnHasRuntimeBits(zcu)) {
+ return o.builder.debugSignedType(name, 0);
+ }
+
+ const fn_info = zcu.typeToFunc(ty).?;
+
+ var debug_param_types: std.ArrayList(Builder.Metadata) = try .initCapacity(gpa, 3 + fn_info.param_types.len);
+ defer debug_param_types.deinit(gpa);
+
+ // Return type goes first.
+ const sret = firstParamSRet(fn_info, zcu, target);
+ const ret_ty: Type = if (sret) .void else .fromInterned(fn_info.return_type);
+ debug_param_types.appendAssumeCapacity(try o.getDebugType(pt, ret_ty));
+
+ if (sret) {
+ const ptr_ty = try pt.singleMutPtrType(Type.fromInterned(fn_info.return_type));
+ debug_param_types.appendAssumeCapacity(try o.getDebugType(pt, ptr_ty));
+ }
+
+ if (fn_info.cc == .auto and zcu.comp.config.any_error_tracing) {
+ // Stack trace pointer.
+ debug_param_types.appendAssumeCapacity(try o.getDebugType(pt, .ptr_usize));
+ }
+
+ for (fn_info.param_types.get(ip)) |param_ty_ip| {
+ const param_ty: Type = .fromInterned(param_ty_ip);
+ if (!param_ty.hasRuntimeBits(zcu)) continue;
+ if (isByRef(param_ty, zcu)) {
+ const ptr_ty = try pt.singleConstPtrType(param_ty);
+ debug_param_types.appendAssumeCapacity(try o.getDebugType(pt, ptr_ty));
+ } else {
+ debug_param_types.appendAssumeCapacity(try o.getDebugType(pt, param_ty));
+ }
+ }
+
+ return o.builder.debugSubroutineType(
+ try o.builder.metadataTuple(debug_param_types.items),
);
- try o.debug_type_map.put(gpa, ty.toIntern(), debug_error_set);
- return debug_error_set;
},
.@"struct" => {
- const name = try o.allocTypeName(pt, ty);
- defer gpa.free(name);
-
- if (zcu.typeToPackedStruct(ty)) |struct_type| {
- const backing_int_ty = struct_type.backingIntTypeUnordered(ip);
- if (backing_int_ty != .none) {
- const info = Type.fromInterned(backing_int_ty).intInfo(zcu);
- const builder_name = try o.builder.metadataString(name);
- const debug_int_type = switch (info.signedness) {
- .signed => try o.builder.debugSignedType(builder_name, ty.abiSize(zcu) * 8),
- .unsigned => try o.builder.debugUnsignedType(builder_name, ty.abiSize(zcu) * 8),
- };
- try o.debug_type_map.put(gpa, ty.toIntern(), debug_int_type);
- return debug_int_type;
+ if (ty.isTuple(zcu)) {
+ const tuple = ip.indexToKey(ty.toIntern()).tuple_type;
+ var fields: std.ArrayList(Builder.Metadata) = .empty;
+ defer fields.deinit(gpa);
+
+ try fields.ensureUnusedCapacity(gpa, tuple.types.len);
+
+ comptime assert(struct_layout_version == 2);
+ var offset: u64 = 0;
+
+ for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty_ip, field_val, i| {
+ const field_ty: Type = .fromInterned(field_ty_ip);
+ if (field_val != .none or !field_ty.hasRuntimeBits(zcu)) continue;
+
+ const field_size = field_ty.abiSize(zcu);
+ const field_align = field_ty.abiAlignment(zcu);
+ const field_offset = field_align.forward(offset);
+ offset = field_offset + field_size;
+
+ fields.appendAssumeCapacity(try o.builder.debugMemberType(
+ try o.builder.metadataStringFmt("{d}", .{i}),
+ null, // file
+ ty_fwd_ref,
+ 0, // line
+ try o.getDebugType(pt, field_ty),
+ field_size * 8,
+ field_align.toByteUnits().? * 8,
+ field_offset * 8,
+ ));
}
+
+ return o.builder.debugStructType(
+ name,
+ null, // file
+ o.debug_compile_unit.unwrap().?,
+ 0, // line
+ null, // underlying type
+ ty.abiSize(zcu) * 8,
+ (ty.abiAlignment(zcu).toByteUnits() orelse 0) * 8,
+ try o.builder.metadataTuple(fields.items),
+ );
}
- switch (ip.indexToKey(ty.toIntern())) {
- .tuple_type => |tuple| {
- var fields: std.ArrayList(Builder.Metadata) = .empty;
- defer fields.deinit(gpa);
+ const struct_type = zcu.typeToStruct(ty).?;
- try fields.ensureUnusedCapacity(gpa, tuple.types.len);
+ const file = try o.getDebugFile(pt, struct_type.zir_index.resolveFile(ip));
+ const scope = if (ty.getParentNamespace(zcu).unwrap()) |parent_namespace|
+ try o.namespaceToDebugScope(pt, parent_namespace)
+ else
+ file;
+ const line = ty.typeDeclSrcLine(zcu).? + 1;
+
+ var fields: std.ArrayList(Builder.Metadata) = .empty;
+ defer fields.deinit(gpa);
+
+ switch (struct_type.layout) {
+ .@"packed" => {
+ try fields.ensureTotalCapacityPrecise(gpa, 1);
+ fields.appendAssumeCapacity(try o.builder.debugMemberType(
+ try o.builder.metadataString("bits"),
+ null, // file
+ ty_fwd_ref,
+ 0, // line
+ try o.getDebugType(pt, .fromInterned(struct_type.packed_backing_int_type)),
+ ty.abiSize(zcu) * 8,
+ ty.abiAlignment(zcu).toByteUnits().? * 8,
+ 0, // offset
+ ));
+ },
+ .auto, .@"extern" => {
comptime assert(struct_layout_version == 2);
- var offset: u64 = 0;
-
- const debug_fwd_ref = try o.builder.debugForwardReference();
-
- for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty, field_val, i| {
- if (field_val != .none or !Type.fromInterned(field_ty).hasRuntimeBits(zcu)) continue;
-
- const field_size = Type.fromInterned(field_ty).abiSize(zcu);
- const field_align = Type.fromInterned(field_ty).abiAlignment(zcu);
- const field_offset = field_align.forward(offset);
- offset = field_offset + field_size;
-
- var name_buf: [32]u8 = undefined;
- const field_name = std.fmt.bufPrint(&name_buf, "{d}", .{i}) catch unreachable;
-
+ try fields.ensureTotalCapacityPrecise(gpa, struct_type.field_types.len);
+ var it = struct_type.iterateRuntimeOrder(ip);
+ while (it.next()) |field_index| {
+ const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);
+ if (!field_ty.hasRuntimeBits(zcu)) continue;
+ const field_size = field_ty.abiSize(zcu);
+ const field_align = switch (ty.explicitFieldAlignment(field_index, zcu)) {
+ .none => field_ty.abiAlignment(zcu),
+ else => |a| a,
+ };
+ const field_offset = struct_type.field_offsets.get(ip)[field_index];
+ const field_name = struct_type.field_names.get(ip)[field_index];
fields.appendAssumeCapacity(try o.builder.debugMemberType(
- try o.builder.metadataString(field_name),
- null, // File
- debug_fwd_ref,
- 0,
- try o.lowerDebugType(pt, Type.fromInterned(field_ty)),
+ try o.builder.metadataString(field_name.toSlice(ip)),
+ null, // file
+ ty_fwd_ref,
+ 0, // line
+ try o.getDebugType(pt, field_ty),
field_size * 8,
- (field_align.toByteUnits() orelse 0) * 8,
+ field_align.toByteUnits().? * 8,
field_offset * 8,
));
}
-
- const debug_struct_type = try o.builder.debugStructType(
- try o.builder.metadataString(name),
- null, // File
- o.debug_compile_unit.unwrap().?, // Scope
- 0, // Line
- null, // Underlying type
- ty.abiSize(zcu) * 8,
- (ty.abiAlignment(zcu).toByteUnits() orelse 0) * 8,
- try o.builder.metadataTuple(fields.items),
- );
-
- o.builder.resolveDebugForwardReference(debug_fwd_ref, debug_struct_type);
-
- try o.debug_type_map.put(gpa, ty.toIntern(), debug_struct_type);
- return debug_struct_type;
- },
- .struct_type => {
- if (!ip.loadStructType(ty.toIntern()).haveFieldTypes(ip)) {
- // This can happen if a struct type makes it all the way to
- // flush() without ever being instantiated or referenced (even
- // via pointer). The only reason we are hearing about it now is
- // that it is being used as a namespace to put other debug types
- // into. Therefore we can satisfy this by making an empty namespace,
- // rather than changing the frontend to unnecessarily resolve the
- // struct field types.
- const debug_struct_type = try o.makeEmptyNamespaceDebugType(pt, ty);
- try o.debug_type_map.put(gpa, ty.toIntern(), debug_struct_type);
- return debug_struct_type;
- }
},
- else => {},
- }
-
- if (!ty.hasRuntimeBitsIgnoreComptime(zcu)) {
- const debug_struct_type = try o.makeEmptyNamespaceDebugType(pt, ty);
- try o.debug_type_map.put(gpa, ty.toIntern(), debug_struct_type);
- return debug_struct_type;
- }
-
- const struct_type = zcu.typeToStruct(ty).?;
-
- var fields: std.ArrayList(Builder.Metadata) = .empty;
- defer fields.deinit(gpa);
-
- try fields.ensureUnusedCapacity(gpa, struct_type.field_types.len);
-
- const debug_fwd_ref = try o.builder.debugForwardReference();
-
- // Set as forward reference while the type is lowered in case it references itself
- try o.debug_type_map.put(gpa, ty.toIntern(), debug_fwd_ref);
-
- comptime assert(struct_layout_version == 2);
- var it = struct_type.iterateRuntimeOrder(ip);
- while (it.next()) |field_index| {
- const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
- if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
- const field_size = field_ty.abiSize(zcu);
- const field_align = ty.fieldAlignment(field_index, zcu);
- const field_offset = ty.structFieldOffset(field_index, zcu);
- const field_name = struct_type.fieldName(ip, field_index);
- fields.appendAssumeCapacity(try o.builder.debugMemberType(
- try o.builder.metadataString(field_name.toSlice(ip)),
- null, // File
- debug_fwd_ref,
- 0, // Line
- try o.lowerDebugType(pt, field_ty),
- field_size * 8,
- (field_align.toByteUnits() orelse 0) * 8,
- field_offset * 8,
- ));
}
- const debug_struct_type = try o.builder.debugStructType(
- try o.builder.metadataString(name),
- null, // File
- o.debug_compile_unit.unwrap().?, // Scope
- 0, // Line
- null, // Underlying type
+ return o.builder.debugStructType(
+ name,
+ file,
+ scope,
+ line,
+ null, // underlying type
ty.abiSize(zcu) * 8,
- (ty.abiAlignment(zcu).toByteUnits() orelse 0) * 8,
+ ty.abiAlignment(zcu).toByteUnits().? * 8,
try o.builder.metadataTuple(fields.items),
);
-
- o.builder.resolveDebugForwardReference(debug_fwd_ref, debug_struct_type);
-
- // Set to real type now that it has been lowered fully
- const map_ptr = o.debug_type_map.getPtr(ty.toIntern()) orelse unreachable;
- map_ptr.* = debug_struct_type;
-
- return debug_struct_type;
},
.@"union" => {
- const name = try o.allocTypeName(pt, ty);
- defer gpa.free(name);
-
const union_type = ip.loadUnionType(ty.toIntern());
- if (!union_type.haveFieldTypes(ip) or
- !ty.hasRuntimeBitsIgnoreComptime(zcu) or
- !union_type.haveLayout(ip))
- {
- const debug_union_type = try o.makeEmptyNamespaceDebugType(pt, ty);
- try o.debug_type_map.put(gpa, ty.toIntern(), debug_union_type);
- return debug_union_type;
+
+ const file = try o.getDebugFile(pt, union_type.zir_index.resolveFile(ip));
+ const scope = if (ty.getParentNamespace(zcu).unwrap()) |parent_namespace|
+ try o.namespaceToDebugScope(pt, parent_namespace)
+ else
+ file;
+
+ const line = ty.typeDeclSrcLine(zcu).? + 1;
+
+ const enum_tag_ty: Type = .fromInterned(union_type.enum_tag_type);
+
+ if (union_type.layout == .@"packed") {
+ const bitpack_field = try o.builder.debugMemberType(
+ try o.builder.metadataString("bits"),
+ null, // file
+ ty_fwd_ref,
+ 0, // line
+ try o.getDebugType(pt, .fromInterned(union_type.packed_backing_int_type)),
+ ty.abiSize(zcu) * 8,
+ ty.abiAlignment(zcu).toByteUnits().? * 8,
+ 0, // offset
+ );
+ return o.builder.debugStructType(
+ name,
+ file,
+ scope,
+ line,
+ null, // underlying type
+ ty.abiSize(zcu) * 8,
+ ty.abiAlignment(zcu).toByteUnits().? * 8,
+ try o.builder.metadataTuple(&.{bitpack_field}),
+ );
}
const layout = Type.getUnionLayout(union_type, zcu);
- const debug_fwd_ref = try o.builder.debugForwardReference();
-
- // Set as forward reference while the type is lowered in case it references itself
- try o.debug_type_map.put(gpa, ty.toIntern(), debug_fwd_ref);
-
if (layout.payload_size == 0) {
- const debug_union_type = try o.builder.debugStructType(
- try o.builder.metadataString(name),
- null, // File
- o.debug_compile_unit.unwrap().?, // Scope
- 0, // Line
- null, // Underlying type
+ const fields_tuple: ?Builder.Metadata = fields: {
+ if (layout.tag_size == 0) break :fields null;
+ break :fields try o.builder.metadataTuple(&.{
+ try o.builder.debugMemberType(
+ try o.builder.metadataString("tag"),
+ null, // file
+ ty_fwd_ref,
+ 0, // line
+ try o.getDebugType(pt, enum_tag_ty),
+ layout.tag_size * 8,
+ layout.tag_align.toByteUnits().? * 8,
+ 0, // offset
+ ),
+ });
+ };
+ return o.builder.debugStructType(
+ name,
+ file,
+ scope,
+ line,
+ null, // underlying type
ty.abiSize(zcu) * 8,
- (ty.abiAlignment(zcu).toByteUnits() orelse 0) * 8,
- try o.builder.metadataTuple(
- &.{try o.lowerDebugType(pt, Type.fromInterned(union_type.enum_tag_ty))},
- ),
+ ty.abiAlignment(zcu).toByteUnits().? * 8,
+ fields_tuple,
);
-
- // Set to real type now that it has been lowered fully
- const map_ptr = o.debug_type_map.getPtr(ty.toIntern()) orelse unreachable;
- map_ptr.* = debug_union_type;
-
- return debug_union_type;
}
- var fields: std.ArrayList(Builder.Metadata) = .empty;
+ var fields: std.ArrayList(Builder.Metadata) = try .initCapacity(gpa, union_type.field_types.len);
defer fields.deinit(gpa);
- try fields.ensureUnusedCapacity(gpa, union_type.loadTagType(ip).names.len);
-
- const debug_union_fwd_ref = if (layout.tag_size == 0)
- debug_fwd_ref
+ const payload_fwd_ref = if (layout.tag_size == 0)
+ ty_fwd_ref
else
try o.builder.debugForwardReference();
- const tag_type = union_type.loadTagType(ip);
-
- for (0..tag_type.names.len) |field_index| {
+ for (0..union_type.field_types.len) |field_index| {
const field_ty = union_type.field_types.get(ip)[field_index];
- if (!Type.fromInterned(field_ty).hasRuntimeBitsIgnoreComptime(zcu)) continue;
const field_size = Type.fromInterned(field_ty).abiSize(zcu);
- const field_align: InternPool.Alignment = switch (union_type.flagsUnordered(ip).layout) {
- .@"packed" => .none,
- .auto, .@"extern" => ty.fieldAlignment(field_index, zcu),
- };
+ const field_align: InternPool.Alignment = ty.explicitFieldAlignment(field_index, zcu);
- const field_name = tag_type.names.get(ip)[field_index];
+ const field_name = enum_tag_ty.enumFieldName(field_index, zcu);
fields.appendAssumeCapacity(try o.builder.debugMemberType(
try o.builder.metadataString(field_name.toSlice(ip)),
- null, // File
- debug_union_fwd_ref,
- 0, // Line
- try o.lowerDebugType(pt, Type.fromInterned(field_ty)),
+ null, // file
+ payload_fwd_ref,
+ 0, // line
+ try o.getDebugType(pt, .fromInterned(field_ty)),
field_size * 8,
(field_align.toByteUnits() orelse 0) * 8,
- 0, // Offset
+ 0, // offset
));
}
- var union_name_buf: ?[:0]const u8 = null;
- defer if (union_name_buf) |buf| gpa.free(buf);
- const union_name = if (layout.tag_size == 0) name else name: {
- union_name_buf = try std.fmt.allocPrintSentinel(gpa, "{s}:Payload", .{name}, 0);
- break :name union_name_buf.?;
- };
-
- const debug_union_type = try o.builder.debugUnionType(
- try o.builder.metadataString(union_name),
- null, // File
- o.debug_compile_unit.unwrap().?, // Scope
- 0, // Line
- null, // Underlying type
+ const debug_payload_type = try o.builder.debugUnionType(
+ payload_name: {
+ if (layout.tag_size == 0) break :payload_name name;
+ break :payload_name try o.builder.metadataStringFmt("{f}:Payload", .{ty.fmt(pt)});
+ },
+ file,
+ scope,
+ line,
+ null, // underlying type
layout.payload_size * 8,
- (ty.abiAlignment(zcu).toByteUnits() orelse 0) * 8,
+ ty.abiAlignment(zcu).toByteUnits().? * 8,
try o.builder.metadataTuple(fields.items),
);
- o.builder.resolveDebugForwardReference(debug_union_fwd_ref, debug_union_type);
-
if (layout.tag_size == 0) {
- // Set to real type now that it has been lowered fully
- const map_ptr = o.debug_type_map.getPtr(ty.toIntern()) orelse unreachable;
- map_ptr.* = debug_union_type;
-
- return debug_union_type;
+ return debug_payload_type;
}
- var tag_offset: u64 = undefined;
- var payload_offset: u64 = undefined;
- if (layout.tag_align.compare(.gte, layout.payload_align)) {
- tag_offset = 0;
- payload_offset = layout.payload_align.forward(layout.tag_size);
- } else {
- payload_offset = 0;
- tag_offset = layout.tag_align.forward(layout.payload_size);
- }
+ o.builder.resolveDebugForwardReference(payload_fwd_ref, debug_payload_type);
+
+ const tag_offset: u64, const payload_offset: u64 = offsets: {
+ if (layout.tag_align.compare(.gte, layout.payload_align)) {
+ break :offsets .{ 0, layout.payload_align.forward(layout.tag_size) };
+ } else {
+ break :offsets .{ layout.tag_align.forward(layout.payload_size), 0 };
+ }
+ };
- const debug_tag_type = try o.builder.debugMemberType(
+ const tag_member_type = try o.builder.debugMemberType(
try o.builder.metadataString("tag"),
- null, // File
- debug_fwd_ref,
- 0, // Line
- try o.lowerDebugType(pt, Type.fromInterned(union_type.enum_tag_ty)),
+ null, // file
+ ty_fwd_ref,
+ 0, // line
+ try o.getDebugType(pt, enum_tag_ty),
layout.tag_size * 8,
- (layout.tag_align.toByteUnits() orelse 0) * 8,
+ layout.tag_align.toByteUnits().? * 8,
tag_offset * 8,
);
- const debug_payload_type = try o.builder.debugMemberType(
+ const payload_member_type = try o.builder.debugMemberType(
try o.builder.metadataString("payload"),
- null, // File
- debug_fwd_ref,
- 0, // Line
- debug_union_type,
+ null, // file
+ ty_fwd_ref,
+ 0, // line
+ debug_payload_type,
layout.payload_size * 8,
- (layout.payload_align.toByteUnits() orelse 0) * 8,
+ layout.payload_align.toByteUnits().? * 8,
payload_offset * 8,
);
const full_fields: [2]Builder.Metadata =
if (layout.tag_align.compare(.gte, layout.payload_align))
- .{ debug_tag_type, debug_payload_type }
+ .{ tag_member_type, payload_member_type }
else
- .{ debug_payload_type, debug_tag_type };
+ .{ payload_member_type, tag_member_type };
- const debug_tagged_union_type = try o.builder.debugStructType(
- try o.builder.metadataString(name),
- null, // File
- o.debug_compile_unit.unwrap().?, // Scope
- 0, // Line
- null, // Underlying type
+ return o.builder.debugStructType(
+ name,
+ file,
+ scope,
+ line,
+ null, // underlying type
ty.abiSize(zcu) * 8,
- (ty.abiAlignment(zcu).toByteUnits() orelse 0) * 8,
+ ty.abiAlignment(zcu).toByteUnits().? * 8,
try o.builder.metadataTuple(&full_fields),
);
+ },
+ .@"enum" => {
+ const file = try o.getDebugFile(pt, ty.typeDeclInstAllowGeneratedTag(zcu).?.resolveFile(ip));
+ const scope = if (ty.getParentNamespace(zcu).unwrap()) |parent_namespace|
+ try o.namespaceToDebugScope(pt, parent_namespace)
+ else
+ file;
- o.builder.resolveDebugForwardReference(debug_fwd_ref, debug_tagged_union_type);
-
- // Set to real type now that it has been lowered fully
- const map_ptr = o.debug_type_map.getPtr(ty.toIntern()) orelse unreachable;
- map_ptr.* = debug_tagged_union_type;
+ const line = ty.typeDeclSrcLine(zcu).? + 1;
- return debug_tagged_union_type;
- },
- .@"fn" => {
- const fn_info = zcu.typeToFunc(ty).?;
-
- var debug_param_types = std.array_list.Managed(Builder.Metadata).init(gpa);
- defer debug_param_types.deinit();
-
- try debug_param_types.ensureUnusedCapacity(3 + fn_info.param_types.len);
-
- // Return type goes first.
- if (Type.fromInterned(fn_info.return_type).hasRuntimeBitsIgnoreComptime(zcu)) {
- const sret = firstParamSRet(fn_info, zcu, target);
- const ret_ty = if (sret) Type.void else Type.fromInterned(fn_info.return_type);
- debug_param_types.appendAssumeCapacity(try o.lowerDebugType(pt, ret_ty));
-
- if (sret) {
- const ptr_ty = try pt.singleMutPtrType(Type.fromInterned(fn_info.return_type));
- debug_param_types.appendAssumeCapacity(try o.lowerDebugType(pt, ptr_ty));
- }
- } else {
- debug_param_types.appendAssumeCapacity(try o.lowerDebugType(pt, Type.void));
+ if (!ty.hasRuntimeBits(zcu)) {
+ return o.builder.debugStructType(
+ name,
+ file,
+ scope,
+ line,
+ null, // underlying type
+ ty.abiSize(zcu) * 8,
+ ty.abiAlignment(zcu).toByteUnits().? * 8,
+ null, // fields
+ );
}
- if (fn_info.cc == .auto and zcu.comp.config.any_error_tracing) {
- // Stack trace pointer.
- debug_param_types.appendAssumeCapacity(try o.lowerDebugType(pt, .fromInterned(.ptr_usize_type)));
- }
+ const enum_type = ip.loadEnumType(ty.toIntern());
+ const enumerators = try gpa.alloc(Builder.Metadata, enum_type.field_names.len);
+ defer gpa.free(enumerators);
- for (0..fn_info.param_types.len) |i| {
- const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[i]);
- if (!param_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
+ const int_ty: Type = .fromInterned(enum_type.int_tag_type);
+ const int_info = ty.intInfo(zcu);
+ assert(int_info.bits != 0);
- if (isByRef(param_ty, zcu)) {
- const ptr_ty = try pt.singleMutPtrType(param_ty);
- debug_param_types.appendAssumeCapacity(try o.lowerDebugType(pt, ptr_ty));
- } else {
- debug_param_types.appendAssumeCapacity(try o.lowerDebugType(pt, param_ty));
- }
+ for (enumerators, enum_type.field_names.get(ip), 0..) |*out, field_name, field_index| {
+ var space: Value.BigIntSpace = undefined;
+ const field_val: std.math.big.int.Const = switch (enum_type.field_values.len) {
+ 0 => std.math.big.int.Mutable.init(&space.limbs, field_index).toConst(),
+ else => Value.fromInterned(enum_type.field_values.get(ip)[field_index]).toBigInt(&space, zcu),
+ };
+ out.* = try o.builder.debugEnumerator(
+ try o.builder.metadataString(field_name.toSlice(ip)),
+ int_info.signedness == .unsigned,
+ int_info.bits,
+ field_val,
+ );
}
- const debug_function_type = try o.builder.debugSubroutineType(
- try o.builder.metadataTuple(debug_param_types.items),
+ const debug_enum_type = try o.builder.debugEnumerationType(
+ name,
+ file,
+ scope,
+ line,
+ try o.getDebugType(pt, int_ty),
+ ty.abiSize(zcu) * 8,
+ ty.abiAlignment(zcu).toByteUnits().? * 8,
+ try o.builder.metadataTuple(enumerators),
);
-
- try o.debug_type_map.put(gpa, ty.toIntern(), debug_function_type);
- return debug_function_type;
+ try o.debug_enums.append(gpa, debug_enum_type);
+ return debug_enum_type;
},
- .comptime_int => unreachable,
- .comptime_float => unreachable,
- .type => unreachable,
- .undefined => unreachable,
- .null => unreachable,
- .enum_literal => unreachable,
+ .@"opaque" => {
+ if (ty.toIntern() == .anyopaque_type) {
+ return o.builder.debugSignedType(name, 0);
+ }
+
+ const file = try o.getDebugFile(pt, ty.typeDeclInstAllowGeneratedTag(zcu).?.resolveFile(ip));
+ const scope = if (ty.getParentNamespace(zcu).unwrap()) |parent_namespace|
+ try o.namespaceToDebugScope(pt, parent_namespace)
+ else
+ file;
+
+ const line = ty.typeDeclSrcLine(zcu).? + 1;
+ return o.builder.debugStructType(
+ name,
+ file,
+ scope,
+ line,
+ null, // underlying type
+ 0, // size
+ ty.abiAlignment(zcu).toByteUnits().? * 8,
+ null, // fields
+ );
+ },
.frame => @panic("TODO implement lowerDebugType for Frame types"),
.@"anyframe" => @panic("TODO implement lowerDebugType for AnyFrame types"),
}
}
+ /// Called in `emit` so that the global error set is fully populated.
+ fn lowerDebugAnyerrorType(o: *Object, pt: Zcu.PerThread) Allocator.Error!Builder.Metadata {
+ const zcu = pt.zcu;
+ const ip = &zcu.intern_pool;
+ const gpa = zcu.comp.gpa;
+
+ const error_set_bits = zcu.errorSetBits();
+ const error_names = ip.global_error_set.getNamesFromMainThread();
+
+ const enumerators = try gpa.alloc(Builder.Metadata, error_names.len + 1);
+ defer gpa.free(enumerators);
+
+ // The value 0 means "no error" in optionals and error unions.
+ enumerators[0] = try o.builder.debugEnumerator(
+ try o.builder.metadataString("null"),
+ true, // unsigned,
+ error_set_bits,
+ .{ .limbs = &.{0}, .positive = true }, // zero
+ );
+
+ for (enumerators[1..], error_names, 1..) |*out, error_name, error_value| {
+ var space: Value.BigIntSpace = undefined;
+ var bigint: std.math.big.int.Mutable = .init(&space.limbs, error_value);
+ out.* = try o.builder.debugEnumerator(
+ try o.builder.metadataStringFmt("error.{f}", .{error_name.fmtId(ip)}),
+ true, // unsigned
+ error_set_bits,
+ bigint.toConst(),
+ );
+ }
+
+ const debug_enum_type = try o.builder.debugEnumerationType(
+ try o.builder.metadataString("anyerror"),
+ null, // file
+ o.debug_compile_unit.unwrap().?, // scope
+ 0, // line
+ try o.getDebugType(pt, try pt.intType(.unsigned, error_set_bits)),
+ Type.anyerror.abiSize(zcu) * 8,
+ Type.anyerror.abiAlignment(zcu).toByteUnits().? * 8,
+ try o.builder.metadataTuple(enumerators),
+ );
+ try o.debug_enums.append(gpa, debug_enum_type);
+ return debug_enum_type;
+ }
+
fn namespaceToDebugScope(o: *Object, pt: Zcu.PerThread, namespace_index: InternPool.NamespaceIndex) !Builder.Metadata {
const zcu = pt.zcu;
const namespace = zcu.namespacePtr(namespace_index);
if (namespace.parent == .none) return try o.getDebugFile(pt, namespace.file_scope);
-
- const gop = try o.debug_unresolved_namespace_scopes.getOrPut(o.gpa, namespace_index);
-
- if (!gop.found_existing) gop.value_ptr.* = try o.builder.debugForwardReference();
-
- return gop.value_ptr.*;
- }
-
- fn makeEmptyNamespaceDebugType(o: *Object, pt: Zcu.PerThread, ty: Type) !Builder.Metadata {
- const zcu = pt.zcu;
- const ip = &zcu.intern_pool;
- const file = try o.getDebugFile(pt, ty.typeDeclInstAllowGeneratedTag(zcu).?.resolveFile(ip));
- const scope = if (ty.getParentNamespace(zcu).unwrap()) |parent_namespace|
- try o.namespaceToDebugScope(pt, parent_namespace)
- else
- file;
- return o.builder.debugStructType(
- try o.builder.metadataString(ty.containerTypeName(ip).toSlice(ip)), // TODO use fully qualified name
- file,
- scope,
- ty.typeDeclSrcLine(zcu).? + 1,
- null,
- 0,
- 0,
- null,
- );
+ return o.getDebugType(pt, .fromInterned(namespace.owner_type));
}
fn allocTypeName(o: *Object, pt: Zcu.PerThread, ty: Type) Allocator.Error![:0]const u8 {
@@ -2804,7 +2746,7 @@ pub const Object = struct {
function_index.setCallConv(cc_info.llvm_cc, &o.builder);
if (cc_info.align_stack) {
- try attributes.addFnAttr(.{ .alignstack = .fromByteUnits(target.stackAlignment()) }, &o.builder);
+ try attributes.addFnAttr(.{ .alignstack = .wrap(.fromByteUnits(target.stackAlignment())) }, &o.builder);
} else {
_ = try attributes.removeFnAttr(.alignstack);
}
@@ -2885,40 +2827,6 @@ pub const Object = struct {
if (fn_info.return_type == .noreturn_type) try attributes.addFnAttr(.noreturn, &o.builder);
- // Add parameter attributes. We handle only the case of extern functions (no body)
- // because functions with bodies are handled in `updateFunc`.
- if (is_extern) {
- var it = iterateParamTypes(o, pt, fn_info);
- it.llvm_index = llvm_arg_i;
- while (try it.next()) |lowering| switch (lowering) {
- .byval => {
- const param_index = it.zig_index - 1;
- const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[param_index]);
- if (!isByRef(param_ty, zcu)) {
- try o.addByValParamAttrs(pt, &attributes, param_ty, param_index, fn_info, it.llvm_index - 1);
- }
- },
- .byref => {
- const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);
- const param_llvm_ty = try o.lowerType(pt, param_ty);
- const alignment = param_ty.abiAlignment(zcu);
- try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment.toLlvm(), it.byval_attr, param_llvm_ty);
- },
- .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder),
- // No attributes needed for these.
- .no_bits,
- .abi_sized_int,
- .multiple_llvm_types,
- .float_array,
- .i32_array,
- .i64_array,
- => continue,
-
- .slice => unreachable, // extern functions do not support slice types.
-
- };
- }
-
function_index.setAttributes(try attributes.finish(&o.builder), &o.builder);
return function_index;
}
@@ -3223,7 +3131,7 @@ pub const Object = struct {
),
.opt_type => |child_ty| {
// Must stay in sync with `opt_payload` logic in `lowerPtr`.
- if (!Type.fromInterned(child_ty).hasRuntimeBitsIgnoreComptime(zcu)) return .i8;
+ if (!Type.fromInterned(child_ty).hasRuntimeBits(zcu)) return .i8;
const payload_ty = try o.lowerType(pt, Type.fromInterned(child_ty));
if (t.optionalReprIsPayload(zcu)) return payload_ty;
@@ -3245,7 +3153,7 @@ pub const Object = struct {
// Must stay in sync with `codegen.errUnionPayloadOffset`.
// See logic in `lowerPtr`.
const error_type = try o.errorIntType(pt);
- if (!Type.fromInterned(error_union_type.payload_type).hasRuntimeBitsIgnoreComptime(zcu))
+ if (!Type.fromInterned(error_union_type.payload_type).hasRuntimeBits(zcu))
return error_type;
const payload_type = try o.lowerType(pt, Type.fromInterned(error_union_type.payload_type));
@@ -3287,7 +3195,7 @@ pub const Object = struct {
const struct_type = ip.loadStructType(t.toIntern());
if (struct_type.layout == .@"packed") {
- const int_ty = try o.lowerType(pt, Type.fromInterned(struct_type.backingIntTypeUnordered(ip)));
+ const int_ty = try o.lowerType(pt, .fromInterned(struct_type.packed_backing_int_type));
try o.type_map.put(o.gpa, t.toIntern(), int_ty);
return int_ty;
}
@@ -3301,18 +3209,20 @@ pub const Object = struct {
comptime assert(struct_layout_version == 2);
var offset: u64 = 0;
- var big_align: InternPool.Alignment = .@"1";
var struct_kind: Builder.Type.Structure.Kind = .normal;
// When we encounter a zero-bit field, we place it here so we know to map it to the next non-zero-bit field (if any).
var it = struct_type.iterateRuntimeOrder(ip);
+ var max_field_ty_align: InternPool.Alignment = .@"1";
while (it.next()) |field_index| {
const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
- const field_align = t.fieldAlignment(field_index, zcu);
const field_ty_align = field_ty.abiAlignment(zcu);
- if (field_align.compare(.lt, field_ty_align)) struct_kind = .@"packed";
- big_align = big_align.max(field_align);
+ max_field_ty_align = max_field_ty_align.maxStrict(field_ty_align);
+
const prev_offset = offset;
- offset = field_align.forward(offset);
+ offset = struct_type.field_offsets.get(ip)[field_index];
+ if (@ctz(offset) < field_ty_align.toLog2Units()) {
+ struct_kind = .@"packed"; // prevent unexpected padding before this field
+ }
const padding_len = offset - prev_offset;
if (padding_len > 0) try llvm_field_types.append(
@@ -3320,11 +3230,11 @@ pub const Object = struct {
try o.builder.arrayType(padding_len, .i8),
);
- if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!field_ty.hasRuntimeBits(zcu)) {
// This is a zero-bit field. If there are runtime bits after this field,
// map to the next LLVM field (which we know exists): otherwise, don't
// map the field, indicating it's at the end of the struct.
- if (offset != struct_type.sizeUnordered(ip)) {
+ if (offset != struct_type.size) {
try o.struct_field_map.put(o.gpa, .{
.struct_ty = t.toIntern(),
.field_index = field_index,
@@ -3343,12 +3253,15 @@ pub const Object = struct {
}
{
const prev_offset = offset;
- offset = big_align.forward(offset);
+ offset = struct_type.alignment.forward(offset);
const padding_len = offset - prev_offset;
if (padding_len > 0) try llvm_field_types.append(
o.gpa,
try o.builder.arrayType(padding_len, .i8),
);
+ if (@ctz(offset) < max_field_ty_align.toLog2Units()) {
+ struct_kind = .@"packed"; // prevent unexpected trailing padding
+ }
}
const ty = try o.builder.opaqueType(try o.builder.string(t.containerTypeName(ip).toSlice(ip)));
@@ -3391,7 +3304,7 @@ pub const Object = struct {
o.gpa,
try o.builder.arrayType(padding_len, .i8),
);
- if (!Type.fromInterned(field_ty).hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!Type.fromInterned(field_ty).hasRuntimeBits(zcu)) {
// This is a zero-bit field. If there are runtime bits after this field,
// map to the next LLVM field (which we know exists): otherwise, don't
// map the field, indicating it's at the end of the struct.
@@ -3426,16 +3339,17 @@ pub const Object = struct {
if (o.type_map.get(t.toIntern())) |value| return value;
const union_obj = ip.loadUnionType(t.toIntern());
+
+ if (union_obj.layout == .@"packed") {
+ const int_ty = try o.lowerType(pt, .fromInterned(union_obj.packed_backing_int_type));
+ try o.type_map.put(o.gpa, t.toIntern(), int_ty);
+ return int_ty;
+ }
+
const layout = Type.getUnionLayout(union_obj, zcu);
- if (union_obj.flagsUnordered(ip).layout == .@"packed") {
- const int_ty = try o.builder.intType(@intCast(t.bitSize(zcu)));
- try o.type_map.put(o.gpa, t.toIntern(), int_ty);
- return int_ty;
- }
-
if (layout.payload_size == 0) {
- const enum_tag_ty = try o.lowerType(pt, Type.fromInterned(union_obj.enum_tag_ty));
+ const enum_tag_ty = try o.lowerType(pt, .fromInterned(union_obj.enum_tag_type));
try o.type_map.put(o.gpa, t.toIntern(), enum_tag_ty);
return enum_tag_ty;
}
@@ -3467,7 +3381,7 @@ pub const Object = struct {
);
return ty;
}
- const enum_tag_ty = try o.lowerType(pt, Type.fromInterned(union_obj.enum_tag_ty));
+ const enum_tag_ty = try o.lowerType(pt, .fromInterned(union_obj.enum_tag_type));
// Put the tag before or after the payload depending on which one's
// alignment is greater.
@@ -3502,7 +3416,7 @@ pub const Object = struct {
}
return gop.value_ptr.*;
},
- .enum_type => try o.lowerType(pt, Type.fromInterned(ip.loadEnumType(t.toIntern()).tag_ty)),
+ .enum_type => try o.lowerType(pt, t.intTagType(zcu)),
.func_type => |func_type| try o.lowerTypeFn(pt, func_type),
.error_set_type, .inferred_error_set_type => try o.errorIntType(pt),
// values, not types
@@ -3516,13 +3430,13 @@ pub const Object = struct {
.error_union,
.enum_literal,
.enum_tag,
- .empty_enum_value,
.float,
.ptr,
.slice,
.opt,
.aggregate,
.un,
+ .bitpack,
// memoization, not types
.memoized_call,
=> unreachable,
@@ -3530,20 +3444,6 @@ pub const Object = struct {
};
}
- /// Use this instead of lowerType when you want to handle correctly the case of elem_ty
- /// being a zero bit type, but it should still be lowered as an i8 in such case.
- /// There are other similar cases handled here as well.
- fn lowerPtrElemTy(o: *Object, pt: Zcu.PerThread, elem_ty: Type) Allocator.Error!Builder.Type {
- const zcu = pt.zcu;
- const lower_elem_ty = switch (elem_ty.zigTypeTag(zcu)) {
- .@"opaque" => true,
- .@"fn" => !zcu.typeToFunc(elem_ty).?.is_generic,
- .array => elem_ty.childType(zcu).hasRuntimeBitsIgnoreComptime(zcu),
- else => elem_ty.hasRuntimeBitsIgnoreComptime(zcu),
- };
- return if (lower_elem_ty) try o.lowerType(pt, elem_ty) else .i8;
- }
-
fn lowerTypeFn(o: *Object, pt: Zcu.PerThread, fn_info: InternPool.Key.FuncType) Allocator.Error!Builder.Type {
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
@@ -3558,9 +3458,9 @@ pub const Object = struct {
}
if (fn_info.cc == .auto and zcu.comp.config.any_error_tracing) {
- const stack_trace_ty = zcu.builtin_decl_values.get(.StackTrace);
- const ptr_ty = try pt.ptrType(.{ .child = stack_trace_ty });
- try llvm_params.append(o.gpa, try o.lowerType(pt, ptr_ty));
+ // First parameter is a pointer to `std.builtin.StackTrace`.
+ const llvm_ptr_ty = try o.builder.ptrType(toLlvmAddressSpace(.generic, target));
+ try llvm_params.append(o.gpa, llvm_ptr_ty);
}
var it = iterateParamTypes(o, pt, fn_info);
@@ -3610,84 +3510,6 @@ pub const Object = struct {
);
}
- fn lowerValueToInt(o: *Object, pt: Zcu.PerThread, llvm_int_ty: Builder.Type, arg_val: InternPool.Index) Error!Builder.Constant {
- const zcu = pt.zcu;
- const ip = &zcu.intern_pool;
- const target = zcu.getTarget();
-
- const val = Value.fromInterned(arg_val);
- const val_key = ip.indexToKey(val.toIntern());
-
- if (val.isUndef(zcu)) return o.builder.undefConst(llvm_int_ty);
-
- const ty = Type.fromInterned(val_key.typeOf());
- switch (val_key) {
- .@"extern" => |@"extern"| {
- const function_index = try o.resolveLlvmFunction(pt, @"extern".owner_nav);
- const ptr = function_index.ptrConst(&o.builder).global.toConst();
- return o.builder.convConst(ptr, llvm_int_ty);
- },
- .func => |func| {
- const function_index = try o.resolveLlvmFunction(pt, func.owner_nav);
- const ptr = function_index.ptrConst(&o.builder).global.toConst();
- return o.builder.convConst(ptr, llvm_int_ty);
- },
- .ptr => return o.builder.convConst(try o.lowerPtr(pt, arg_val, 0), llvm_int_ty),
- .aggregate => switch (ip.indexToKey(ty.toIntern())) {
- .struct_type, .vector_type => {},
- else => unreachable,
- },
- .un => |un| {
- const layout = ty.unionGetLayout(zcu);
- if (layout.payload_size == 0) return o.lowerValue(pt, un.tag);
-
- const union_obj = zcu.typeToUnion(ty).?;
- const container_layout = union_obj.flagsUnordered(ip).layout;
-
- assert(container_layout == .@"packed");
-
- var need_unnamed = false;
- if (un.tag == .none) {
- assert(layout.tag_size == 0);
- const union_val = try o.lowerValueToInt(pt, llvm_int_ty, un.val);
-
- need_unnamed = true;
- return union_val;
- }
- const field_index = zcu.unionTagFieldIndex(union_obj, Value.fromInterned(un.tag)).?;
- const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
- if (!field_ty.hasRuntimeBits(zcu)) return o.builder.intConst(llvm_int_ty, 0);
- return o.lowerValueToInt(pt, llvm_int_ty, un.val);
- },
- .simple_value => |simple_value| switch (simple_value) {
- .false, .true => {},
- else => unreachable,
- },
- .int,
- .float,
- .enum_tag,
- => {},
- .opt => {}, // pointer like optional expected
- else => unreachable,
- }
- var stack = std.heap.stackFallback(32, o.gpa);
- const allocator = stack.get();
-
- const bits: usize = @intCast(ty.bitSize(zcu));
-
- const buffer = try allocator.alloc(u8, (bits + 7) / 8);
- defer allocator.free(buffer);
- const limbs = try allocator.alloc(std.math.big.Limb, std.math.big.int.calcTwosCompLimbCount(bits));
- defer allocator.free(limbs);
-
- val.writeToPackedMemory(ty, pt, buffer, 0) catch unreachable;
-
- var big: std.math.big.int.Mutable = .init(limbs, 0);
- big.readTwosComplement(buffer, bits, target.cpu.arch.endian(), .unsigned);
-
- return o.builder.bigIntConst(llvm_int_ty, big.toConst());
- }
-
fn lowerValue(o: *Object, pt: Zcu.PerThread, arg_val: InternPool.Index) Error!Builder.Constant {
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
@@ -3700,7 +3522,9 @@ pub const Object = struct {
return o.builder.undefConst(try o.lowerType(pt, Type.fromInterned(val_key.typeOf())));
}
- const ty = Type.fromInterned(val_key.typeOf());
+ const ty: Type = .fromInterned(val_key.typeOf());
+ ty.assertHasLayout(zcu);
+
return switch (val_key) {
.int_type,
.ptr_type,
@@ -3722,10 +3546,8 @@ pub const Object = struct {
.undef => unreachable, // handled above
.simple_value => |simple_value| switch (simple_value) {
- .undefined => unreachable, // non-runtime value
.void => unreachable, // non-runtime value
.null => unreachable, // non-runtime value
- .empty_tuple => unreachable, // non-runtime value
.@"unreachable" => unreachable, // non-runtime value
.false => .false,
@@ -3733,7 +3555,6 @@ pub const Object = struct {
},
.variable,
.enum_literal,
- .empty_enum_value,
=> unreachable, // non-runtime values
.@"extern" => |@"extern"| {
const function_index = try o.resolveLlvmFunction(pt, @"extern".owner_nav);
@@ -3763,7 +3584,7 @@ pub const Object = struct {
};
const err_int_ty = try pt.errorIntType();
const payload_type = ty.errorUnionPayload(zcu);
- if (!payload_type.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!payload_type.hasRuntimeBits(zcu)) {
// We use the error type directly as the type.
return o.lowerValue(pt, err_val);
}
@@ -3825,7 +3646,7 @@ pub const Object = struct {
const payload_ty = ty.optionalChild(zcu);
const non_null_bit = try o.builder.intConst(.i8, @intFromBool(opt.val != .none));
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!payload_ty.hasRuntimeBits(zcu)) {
return non_null_bit;
}
const llvm_ty = try o.lowerType(pt, ty);
@@ -3861,6 +3682,7 @@ pub const Object = struct {
fields[0..llvm_ty_fields.len],
), vals[0..llvm_ty_fields.len]);
},
+ .bitpack => |bitpack| return o.lowerValue(pt, bitpack.backing_int_val),
.aggregate => |aggregate| switch (ip.indexToKey(ty.toIntern())) {
.array_type => |array_type| switch (aggregate.storage) {
.bytes => |bytes| try o.builder.stringConst(try o.builder.string(
@@ -3992,7 +3814,7 @@ pub const Object = struct {
0..,
) |field_ty, field_val, field_index| {
if (field_val != .none) continue;
- if (!Type.fromInterned(field_ty).hasRuntimeBitsIgnoreComptime(zcu)) continue;
+ if (!Type.fromInterned(field_ty).hasRuntimeBits(zcu)) continue;
const field_align = Type.fromInterned(field_ty).abiAlignment(zcu);
big_align = big_align.max(field_align);
@@ -4038,16 +3860,8 @@ pub const Object = struct {
},
.struct_type => {
const struct_type = ip.loadStructType(ty.toIntern());
- assert(struct_type.haveLayout(ip));
const struct_ty = try o.lowerType(pt, ty);
- if (struct_type.layout == .@"packed") {
- comptime assert(Type.packed_struct_layout_version == 2);
-
- const bits = ty.bitSize(zcu);
- const llvm_int_ty = try o.builder.intType(@intCast(bits));
-
- return o.lowerValueToInt(pt, llvm_int_ty, arg_val);
- }
+ assert(struct_type.layout != .@"packed");
const llvm_len = struct_ty.aggregateLen(&o.builder);
const ExpectedContents = extern struct {
@@ -4067,15 +3881,12 @@ pub const Object = struct {
comptime assert(struct_layout_version == 2);
var llvm_index: usize = 0;
var offset: u64 = 0;
- var big_align: InternPool.Alignment = .@"1";
var need_unnamed = false;
var field_it = struct_type.iterateRuntimeOrder(ip);
while (field_it.next()) |field_index| {
const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
- const field_align = ty.fieldAlignment(field_index, zcu);
- big_align = big_align.max(field_align);
const prev_offset = offset;
- offset = field_align.forward(offset);
+ offset = struct_type.field_offsets.get(ip)[field_index];
const padding_len = offset - prev_offset;
if (padding_len > 0) {
@@ -4088,7 +3899,7 @@ pub const Object = struct {
llvm_index += 1;
}
- if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!field_ty.hasRuntimeBits(zcu)) {
// This is a zero-bit field - we only needed it for the alignment.
continue;
}
@@ -4106,7 +3917,7 @@ pub const Object = struct {
}
{
const prev_offset = offset;
- offset = big_align.forward(offset);
+ offset = struct_type.alignment.forward(offset);
const padding_len = offset - prev_offset;
if (padding_len > 0) {
fields[llvm_index] = try o.builder.arrayType(padding_len, .i8);
@@ -4130,19 +3941,13 @@ pub const Object = struct {
if (layout.payload_size == 0) return o.lowerValue(pt, un.tag);
const union_obj = zcu.typeToUnion(ty).?;
- const container_layout = union_obj.flagsUnordered(ip).layout;
+ const container_layout = union_obj.layout;
+ assert(container_layout != .@"packed");
var need_unnamed = false;
const payload = if (un.tag != .none) p: {
const field_index = zcu.unionTagFieldIndex(union_obj, Value.fromInterned(un.tag)).?;
const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
- if (container_layout == .@"packed") {
- if (!field_ty.hasRuntimeBits(zcu)) return o.builder.intConst(union_ty, 0);
- const bits = ty.bitSize(zcu);
- const llvm_int_ty = try o.builder.intType(@intCast(bits));
-
- return o.lowerValueToInt(pt, llvm_int_ty, arg_val);
- }
// Sometimes we must make an unnamed struct because LLVM does
// not support bitcasting our payload struct to the true union payload type.
@@ -4150,14 +3955,14 @@ pub const Object = struct {
// must pointer cast to the expected type before accessing the union.
need_unnamed = layout.most_aligned_field != field_index;
- if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!field_ty.hasRuntimeBits(zcu)) {
const padding_len = layout.payload_size;
break :p try o.builder.undefConst(try o.builder.arrayType(padding_len, .i8));
}
const payload = try o.lowerValue(pt, un.val);
const payload_ty = payload.typeOf(&o.builder);
if (payload_ty != union_ty.structFields(&o.builder)[
- @intFromBool(layout.tag_align.compare(.gte, layout.payload_align))
+ @intFromBool(layout.tag_size > 0 and layout.tag_align.compare(.gte, layout.payload_align))
]) need_unnamed = true;
const field_size = field_ty.abiSize(zcu);
if (field_size == layout.payload_size) break :p payload;
@@ -4169,13 +3974,6 @@ pub const Object = struct {
);
} else p: {
assert(layout.tag_size == 0);
- if (container_layout == .@"packed") {
- const bits = ty.bitSize(zcu);
- const llvm_int_ty = try o.builder.intType(@intCast(bits));
-
- return o.lowerValueToInt(pt, llvm_int_ty, arg_val);
- }
-
const union_val = try o.lowerValue(pt, un.val);
need_unnamed = true;
break :p union_val;
@@ -4277,7 +4075,14 @@ pub const Object = struct {
};
return o.lowerPtr(pt, field.base, offset + field_off);
},
- .arr_elem, .comptime_field, .comptime_alloc => unreachable,
+ .arr_elem => |arr_elem| {
+ const base_ptr_ty = Value.fromInterned(arr_elem.base).typeOf(zcu);
+ assert(base_ptr_ty.ptrSize(zcu) == .many);
+ const elem_size = base_ptr_ty.childType(zcu).abiSize(zcu);
+ return o.lowerPtr(pt, arr_elem.base, offset + elem_size * arr_elem.index);
+ },
+ .comptime_field => unreachable,
+ .comptime_alloc => unreachable,
};
}
@@ -4302,12 +4107,11 @@ pub const Object = struct {
const ptr_ty = Type.fromInterned(uav.orig_ty);
- const is_fn_body = uav_ty.zigTypeTag(zcu) == .@"fn";
- if ((!is_fn_body and !uav_ty.hasRuntimeBits(zcu)) or
- (is_fn_body and zcu.typeToFunc(uav_ty).?.is_generic)) return o.lowerPtrToVoid(pt, ptr_ty);
+ if (!uav_ty.isRuntimeFnOrHasRuntimeBits(zcu)) {
+ return o.lowerPtrToVoid(pt, ptr_ty);
+ }
- if (is_fn_body)
- @panic("TODO");
+ assert(uav_ty.zigTypeTag(zcu) != .@"fn"); // should be using a Nav ref
const llvm_addr_space = toLlvmAddressSpace(ptr_ty.ptrAddressSpace(zcu), target);
const alignment = ptr_ty.ptrAlignment(zcu);
@@ -4330,14 +4134,11 @@ pub const Object = struct {
const nav_ty = Type.fromInterned(nav.typeOf(ip));
const ptr_ty = try pt.navPtrType(nav_index);
- const is_fn_body = nav_ty.zigTypeTag(zcu) == .@"fn";
- if ((!is_fn_body and !nav_ty.hasRuntimeBits(zcu)) or
- (is_fn_body and zcu.typeToFunc(nav_ty).?.is_generic))
- {
+ if (nav.getExtern(ip) == null and !nav_ty.isRuntimeFnOrHasRuntimeBits(zcu)) {
return o.lowerPtrToVoid(pt, ptr_ty);
}
- const llvm_global = if (is_fn_body)
+ const llvm_global = if (nav_ty.zigTypeTag(zcu) == .@"fn")
(try o.resolveLlvmFunction(pt, nav_index)).ptrConst(&o.builder).global
else
(try o.resolveGlobalNav(pt, nav_index)).ptrConst(&o.builder).global;
@@ -4380,21 +4181,18 @@ pub const Object = struct {
/// types to work around a LLVM deficiency when targeting ARM/AArch64.
fn getAtomicAbiType(o: *Object, pt: Zcu.PerThread, ty: Type, is_rmw_xchg: bool) Allocator.Error!Builder.Type {
const zcu = pt.zcu;
- const ip = &zcu.intern_pool;
- const int_ty = switch (ty.zigTypeTag(zcu)) {
- .int => ty,
- .@"enum" => ty.intTagType(zcu),
- .@"struct" => Type.fromInterned(ip.loadStructType(ty.toIntern()).backingIntTypeUnordered(ip)),
+ switch (ty.zigTypeTag(zcu)) {
+ .int, .@"enum", .@"struct", .@"union" => {},
.float => {
if (!is_rmw_xchg) return .none;
return o.builder.intType(@intCast(ty.abiSize(zcu) * 8));
},
.bool => return .i8,
else => return .none,
- };
- const bit_count = int_ty.intInfo(zcu).bits;
+ }
+ const bit_count = ty.bitSize(zcu);
if (!std.math.isPowerOfTwo(bit_count) or (bit_count % 8) != 0) {
- return o.builder.intType(@intCast(int_ty.abiSize(zcu) * 8));
+ return o.builder.intType(@intCast(ty.abiSize(zcu) * 8));
} else {
return .none;
}
@@ -4435,11 +4233,11 @@ pub const Object = struct {
if (ptr_info.flags.is_const) {
try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
}
- const elem_align = if (ptr_info.flags.alignment != .none)
- ptr_info.flags.alignment
- else
- Type.fromInterned(ptr_info.child).abiAlignment(zcu).max(.@"1");
- try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align.toLlvm() }, &o.builder);
+ const elem_align: Builder.Alignment.Lazy = switch (ptr_info.flags.alignment) {
+ else => |a| .wrap(a.toLlvm()),
+ .none => try o.lazyAbiAlignment(pt, .fromInterned(ptr_info.child)),
+ };
+ try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
} else if (ccAbiPromoteInt(fn_info.cc, zcu, param_ty)) |s| switch (s) {
.signed => try attributes.addParamAttr(llvm_arg_i, .signext, &o.builder),
.unsigned => try attributes.addParamAttr(llvm_arg_i, .zeroext, &o.builder),
@@ -4456,7 +4254,7 @@ pub const Object = struct {
) Allocator.Error!void {
try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
- try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = alignment }, &o.builder);
+ try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = .wrap(alignment) }, &o.builder);
if (byval) try attributes.addParamAttr(llvm_arg_i, .{ .byval = param_llvm_ty }, &o.builder);
}
@@ -4502,7 +4300,7 @@ pub const Object = struct {
const ret_ty = try o.lowerType(pt, Type.slice_const_u8_sentinel_0);
const target = &zcu.root_mod.resolved_target.result;
const function_index = try o.builder.addFunction(
- try o.builder.fnType(ret_ty, &.{try o.lowerType(pt, Type.fromInterned(enum_type.tag_ty))}, .normal),
+ try o.builder.fnType(ret_ty, &.{try o.lowerType(pt, Type.fromInterned(enum_type.int_tag_type))}, .normal),
try o.builder.strtabStringFmt("__zig_tag_name_{f}", .{enum_type.name.fmt(ip)}),
toLlvmAddressSpace(.generic, target),
);
@@ -4525,12 +4323,16 @@ pub const Object = struct {
const bad_value_block = try wip.block(1, "BadValue");
const tag_int_value = wip.arg(0);
- var wip_switch =
- try wip.@"switch"(tag_int_value, bad_value_block, @intCast(enum_type.names.len), .none);
+ var wip_switch = try wip.@"switch"(
+ tag_int_value,
+ bad_value_block,
+ @intCast(enum_type.field_names.len),
+ .none,
+ );
defer wip_switch.finish(&wip);
- for (0..enum_type.names.len) |field_index| {
- const name = try o.builder.stringNull(enum_type.names.get(ip)[field_index].toSlice(ip));
+ for (0..enum_type.field_names.len) |field_index| {
+ const name = try o.builder.stringNull(enum_type.field_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);
@@ -4562,6 +4364,11 @@ pub const Object = struct {
try wip.finish();
return function_index;
}
+
+ fn lazyAbiAlignment(o: *Object, pt: Zcu.PerThread, ty: Type) Allocator.Error!Builder.Alignment.Lazy {
+ const index = try o.type_pool.get(pt, .{ .llvm = o }, ty.toIntern());
+ return o.lazy_abi_aligns.items[@intFromEnum(index)];
+ }
};
pub const NavGen = struct {
@@ -4601,10 +4408,44 @@ pub const NavGen = struct {
const ty = Type.fromInterned(nav.typeOf(ip));
if (linkage != .internal and ip.isFunctionType(ty.toIntern())) {
- _ = try o.resolveLlvmFunction(pt, owner_nav);
+ const function_index = try o.resolveLlvmFunction(pt, owner_nav);
+ // Add parameter attributes which weren't set by `resolveLlvmFunction`
+ const fn_info = zcu.typeToFunc(ty).?;
+ var attributes = try function_index.ptrConst(&o.builder).attributes.toWip(&o.builder);
+ defer attributes.deinit(&o.builder);
+ var it = iterateParamTypes(o, pt, fn_info);
+ if (firstParamSRet(fn_info, zcu, zcu.getTarget())) it.llvm_index += 1;
+ if (fn_info.cc == .auto and zcu.comp.config.any_error_tracing) it.llvm_index += 1;
+ while (try it.next()) |lowering| switch (lowering) {
+ .byval => {
+ const param_index = it.zig_index - 1;
+ const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[param_index]);
+ if (!isByRef(param_ty, zcu)) {
+ try o.addByValParamAttrs(pt, &attributes, param_ty, param_index, fn_info, it.llvm_index - 1);
+ }
+ },
+ .byref => {
+ const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);
+ const param_llvm_ty = try o.lowerType(pt, param_ty);
+ const alignment = param_ty.abiAlignment(zcu);
+ try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment.toLlvm(), it.byval_attr, param_llvm_ty);
+ },
+ .byref_mut => try attributes.addParamAttr(it.llvm_index - 1, .noundef, &o.builder),
+ // No attributes needed for these.
+ .no_bits,
+ .abi_sized_int,
+ .multiple_llvm_types,
+ .float_array,
+ .i32_array,
+ .i64_array,
+ => continue,
+
+ .slice => unreachable, // extern functions do not support slice types.
+ };
+ function_index.setAttributes(try attributes.finish(&o.builder), &o.builder);
} else {
const variable_index = try o.resolveGlobalNav(pt, nav_index);
- variable_index.setAlignment(pt.navAlignment(nav_index).toLlvm(), &o.builder);
+ variable_index.setAlignment(zcu.navAlignment(nav_index).toLlvm(), &o.builder);
if (resolved.@"linksection".toSlice(ip)) |section|
variable_index.setSection(try o.builder.string(section), &o.builder);
if (is_const) variable_index.setMutability(.constant, &o.builder);
@@ -4630,7 +4471,7 @@ pub const NavGen = struct {
debug_file, // File
debug_file, // Scope
line_number,
- try o.lowerDebugType(pt, ty),
+ try o.getDebugType(pt, ty),
variable_index,
.{ .local = linkage == .internal },
);
@@ -4752,7 +4593,7 @@ pub const FuncGen = struct {
/// Have we seen loads or stores involving `allowzero` pointers?
allowzero_access: bool = false,
- pub fn maybeMarkAllowZeroAccess(self: *FuncGen, info: InternPool.Key.PtrType) void {
+ fn maybeMarkAllowZeroAccess(self: *FuncGen, info: InternPool.Key.PtrType) void {
// LLVM already considers null pointers to be valid in non-generic address spaces, so avoid
// pessimizing optimization for functions with accesses to such pointers.
if (info.flags.address_space == .generic and info.flags.is_allowzero) self.allowzero_access = true;
@@ -5220,7 +5061,7 @@ pub const FuncGen = struct {
try o.builder.metadataString(nav.fqn.toSlice(&zcu.intern_pool)),
line_number,
line_number + func.lbrace_line,
- try o.lowerDebugType(pt, fn_ty),
+ try o.getDebugType(pt, fn_ty),
.{
.di_flags = .{ .StaticMember = true },
.sp_flags = .{
@@ -5490,10 +5331,10 @@ pub const FuncGen = struct {
if (ptr_info.flags.is_const) {
try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder);
}
- const elem_align = (if (ptr_info.flags.alignment != .none)
- @as(InternPool.Alignment, ptr_info.flags.alignment)
- else
- Type.fromInterned(ptr_info.child).abiAlignment(zcu).max(.@"1")).toLlvm();
+ const elem_align: Builder.Alignment.Lazy = switch (ptr_info.flags.alignment) {
+ else => |a| .wrap(a.toLlvm()),
+ .none => try o.lazyAbiAlignment(pt, .fromInterned(ptr_info.child)),
+ };
try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder);
},
};
@@ -5518,7 +5359,7 @@ pub const FuncGen = struct {
return .none;
}
- if (self.liveness.isUnused(inst) or !return_type.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (self.liveness.isUnused(inst) or !return_type.hasRuntimeBits(zcu)) {
return .none;
}
@@ -5637,7 +5478,7 @@ pub const FuncGen = struct {
return;
}
const fn_info = zcu.typeToFunc(Type.fromInterned(ip.getNav(self.ng.nav_index).typeOf(ip))).?;
- if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!ret_ty.hasRuntimeBits(zcu)) {
if (Type.fromInterned(fn_info.return_type).isError(zcu)) {
// Functions with an empty error set are emitted with an error code
// return type and return zero so they can be function pointers coerced
@@ -5702,7 +5543,7 @@ pub const FuncGen = struct {
const ptr_ty = self.typeOf(un_op);
const ret_ty = ptr_ty.childType(zcu);
const fn_info = zcu.typeToFunc(Type.fromInterned(ip.getNav(self.ng.nav_index).typeOf(ip))).?;
- if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!ret_ty.hasRuntimeBits(zcu)) {
if (Type.fromInterned(fn_info.return_type).isError(zcu)) {
// Functions with an empty error set are emitted with an error code
// return type and return zero so they can be function pointers coerced
@@ -5833,14 +5674,13 @@ pub const FuncGen = struct {
const o = self.ng.object;
const pt = self.ng.pt;
const zcu = pt.zcu;
- const ip = &zcu.intern_pool;
const scalar_ty = operand_ty.scalarType(zcu);
const int_ty = switch (scalar_ty.zigTypeTag(zcu)) {
.@"enum" => scalar_ty.intTagType(zcu),
.int, .bool, .pointer, .error_set => scalar_ty,
.optional => blk: {
const payload_ty = operand_ty.optionalChild(zcu);
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu) or
+ if (!payload_ty.hasRuntimeBits(zcu) or
operand_ty.optionalReprIsPayload(zcu))
{
break :blk operand_ty;
@@ -5912,12 +5752,7 @@ pub const FuncGen = struct {
return phi.toValue();
},
.float => return self.buildFloatCmp(fast, op, operand_ty, .{ lhs, rhs }),
- .@"struct" => blk: {
- const struct_obj = ip.loadStructType(scalar_ty.toIntern());
- assert(struct_obj.layout == .@"packed");
- const backing_index = struct_obj.backingIntTypeUnordered(ip);
- break :blk Type.fromInterned(backing_index);
- },
+ .@"struct" => scalar_ty.bitpackBackingInt(zcu),
else => unreachable,
};
const is_signed = int_ty.isSignedInt(zcu);
@@ -5953,7 +5788,7 @@ pub const FuncGen = struct {
return .none;
}
- const have_block_result = inst_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu);
+ const have_block_result = inst_ty.hasRuntimeBits(zcu);
var breaks: BreakList = if (have_block_result) .{ .list = .{} } else .{ .len = 0 };
defer if (have_block_result) breaks.list.deinit(self.gpa);
@@ -6000,7 +5835,7 @@ pub const FuncGen = struct {
// Add the values to the lists only if the break provides a value.
const operand_ty = self.typeOf(branch.operand);
- if (operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {
+ if (operand_ty.hasRuntimeBits(zcu)) {
const val = try self.resolveInst(branch.operand);
// For the phi node, we need the basic blocks and the values of the
@@ -6309,7 +6144,7 @@ pub const FuncGen = struct {
const pt = fg.ng.pt;
const zcu = pt.zcu;
const payload_ty = err_union_ty.errorUnionPayload(zcu);
- const payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(zcu);
+ const payload_has_bits = payload_ty.hasRuntimeBits(zcu);
const err_union_llvm_ty = try o.lowerType(pt, err_union_ty);
const error_type = try o.errorIntType(pt);
@@ -6645,7 +6480,7 @@ pub const FuncGen = struct {
const len = try o.builder.intValue(llvm_usize, array_ty.arrayLen(zcu));
const slice_llvm_ty = try o.lowerType(pt, self.typeOfIndex(inst));
const operand = try self.resolveInst(ty_op.operand);
- if (!array_ty.hasRuntimeBitsIgnoreComptime(zcu))
+ if (!array_ty.hasRuntimeBits(zcu))
return self.wip.buildAggregate(slice_llvm_ty, &.{ operand, len }, "");
const ptr = try self.wip.gep(.inbounds, try o.lowerType(pt, array_ty), operand, &.{
try o.builder.intValue(llvm_usize, 0), try o.builder.intValue(llvm_usize, 0),
@@ -6828,7 +6663,7 @@ pub const FuncGen = struct {
const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
const slice_ptr = try self.resolveInst(ty_op.operand);
const slice_ptr_ty = self.typeOf(ty_op.operand);
- const slice_llvm_ty = try o.lowerPtrElemTy(pt, slice_ptr_ty.childType(zcu));
+ const slice_llvm_ty = try o.lowerType(pt, slice_ptr_ty.childType(zcu));
return self.wip.gepStruct(slice_llvm_ty, slice_ptr, index, "");
}
@@ -6842,7 +6677,7 @@ pub const FuncGen = struct {
const slice = try self.resolveInst(bin_op.lhs);
const index = try self.resolveInst(bin_op.rhs);
const elem_ty = slice_ty.childType(zcu);
- const llvm_elem_ty = try o.lowerPtrElemTy(pt, elem_ty);
+ const llvm_elem_ty = try o.lowerType(pt, elem_ty);
const base_ptr = try self.wip.extractValue(slice, &.{0}, "");
const ptr = try self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, &.{index}, "");
if (isByRef(elem_ty, zcu)) {
@@ -6867,7 +6702,7 @@ pub const FuncGen = struct {
const slice = try self.resolveInst(bin_op.lhs);
const index = try self.resolveInst(bin_op.rhs);
- const llvm_elem_ty = try o.lowerPtrElemTy(pt, slice_ty.childType(zcu));
+ const llvm_elem_ty = try o.lowerType(pt, slice_ty.childType(zcu));
const base_ptr = try self.wip.extractValue(slice, &.{0}, "");
return self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, &.{index}, "");
}
@@ -6906,16 +6741,11 @@ pub const FuncGen = struct {
const zcu = pt.zcu;
const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
const ptr_ty = self.typeOf(bin_op.lhs);
- const elem_ty = ptr_ty.childType(zcu);
- const llvm_elem_ty = try o.lowerPtrElemTy(pt, elem_ty);
+ const elem_ty = ptr_ty.indexableElem(zcu);
+ const llvm_elem_ty = try o.lowerType(pt, elem_ty);
const base_ptr = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
- // TODO: when we go fully opaque pointers in LLVM 16 we can remove this branch
- const ptr = try self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, if (ptr_ty.isSinglePointer(zcu))
- // If this is a single-item pointer to an array, we need another index in the GEP.
- &.{ try o.builder.intValue(try o.lowerType(pt, Type.usize), 0), rhs }
- else
- &.{rhs}, "");
+ const ptr = try self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, &.{rhs}, "");
if (isByRef(elem_ty, zcu)) {
self.maybeMarkAllowZeroAccess(ptr_ty.ptrInfo(zcu));
const ptr_align = (ptr_ty.ptrAlignment(zcu).min(elem_ty.abiAlignment(zcu))).toLlvm();
@@ -6934,8 +6764,8 @@ pub const FuncGen = struct {
const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
const ptr_ty = self.typeOf(bin_op.lhs);
- const elem_ty = ptr_ty.childType(zcu);
- if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) return self.resolveInst(bin_op.lhs);
+ const elem_ty = ptr_ty.indexableElem(zcu);
+ assert(elem_ty.hasRuntimeBits(zcu));
const base_ptr = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
@@ -6943,12 +6773,8 @@ pub const FuncGen = struct {
const elem_ptr = ty_pl.ty.toType();
if (elem_ptr.ptrInfo(zcu).flags.vector_index != .none) return base_ptr;
- const llvm_elem_ty = try o.lowerPtrElemTy(pt, elem_ty);
- return self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, if (ptr_ty.isSinglePointer(zcu))
- // If this is a single-item pointer to an array, we need another index in the GEP.
- &.{ try o.builder.intValue(try o.lowerType(pt, Type.usize), 0), rhs }
- else
- &.{rhs}, "");
+ const llvm_elem_ty = try o.lowerType(pt, elem_ty);
+ return self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, &.{rhs}, "");
}
fn airStructFieldPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
@@ -6956,7 +6782,7 @@ pub const FuncGen = struct {
const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;
const struct_ptr = try self.resolveInst(struct_field.struct_operand);
const struct_ptr_ty = self.typeOf(struct_field.struct_operand);
- return self.fieldPtr(inst, struct_ptr, struct_ptr_ty, struct_field.field_index);
+ return self.fieldPtr(struct_ptr, struct_ptr_ty, struct_field.field_index);
}
fn airStructFieldPtrIndex(
@@ -6967,7 +6793,7 @@ pub const FuncGen = struct {
const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
const struct_ptr = try self.resolveInst(ty_op.operand);
const struct_ptr_ty = self.typeOf(ty_op.operand);
- return self.fieldPtr(inst, struct_ptr, struct_ptr_ty, field_index);
+ return self.fieldPtr(struct_ptr, struct_ptr_ty, field_index);
}
fn airStructFieldVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
@@ -6980,7 +6806,7 @@ pub const FuncGen = struct {
const struct_llvm_val = try self.resolveInst(struct_field.struct_operand);
const field_index = struct_field.field_index;
const field_ty = struct_ty.fieldType(field_index, zcu);
- if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) return .none;
+ if (!field_ty.hasRuntimeBits(zcu)) return .none;
if (!isByRef(struct_ty, zcu)) {
assert(!isByRef(field_ty, zcu));
@@ -6999,11 +6825,6 @@ pub const FuncGen = struct {
const truncated_int =
try self.wip.cast(.trunc, shifted_value, same_size_int, "");
return self.wip.cast(.bitcast, truncated_int, elem_llvm_ty, "");
- } else if (field_ty.isPtrAtRuntime(zcu)) {
- const same_size_int = try o.builder.intType(@intCast(field_ty.bitSize(zcu)));
- const truncated_int =
- try self.wip.cast(.trunc, shifted_value, same_size_int, "");
- return self.wip.cast(.inttoptr, truncated_int, elem_llvm_ty, "");
}
return self.wip.cast(.trunc, shifted_value, elem_llvm_ty, "");
},
@@ -7021,11 +6842,6 @@ pub const FuncGen = struct {
const truncated_int =
try self.wip.cast(.trunc, containing_int, same_size_int, "");
return self.wip.cast(.bitcast, truncated_int, elem_llvm_ty, "");
- } else if (field_ty.isPtrAtRuntime(zcu)) {
- const same_size_int = try o.builder.intType(@intCast(field_ty.bitSize(zcu)));
- const truncated_int =
- try self.wip.cast(.trunc, containing_int, same_size_int, "");
- return self.wip.cast(.inttoptr, truncated_int, elem_llvm_ty, "");
}
return self.wip.cast(.trunc, containing_int, elem_llvm_ty, "");
},
@@ -7041,15 +6857,17 @@ pub const FuncGen = struct {
const llvm_field_index = o.llvmFieldIndex(struct_ty, field_index).?;
const field_ptr =
try self.wip.gepStruct(struct_llvm_ty, struct_llvm_val, llvm_field_index, "");
- const alignment = struct_ty.fieldAlignment(field_index, zcu);
+ const explicit_alignment = struct_ty.explicitFieldAlignment(field_index, zcu);
const field_ptr_ty = try pt.ptrType(.{
.child = field_ty.toIntern(),
- .flags = .{ .alignment = alignment },
+ .flags = .{ .alignment = explicit_alignment },
});
if (isByRef(field_ty, zcu)) {
- assert(alignment != .none);
- const field_alignment = alignment.toLlvm();
- return self.loadByRef(field_ptr, field_ty, field_alignment, .normal);
+ const alignment = switch (explicit_alignment) {
+ .none => field_ty.abiAlignment(zcu),
+ else => |a| a,
+ };
+ return self.loadByRef(field_ptr, field_ty, alignment.toLlvm(), .normal);
} else {
return self.load(field_ptr, field_ptr_ty);
}
@@ -7057,7 +6875,7 @@ pub const FuncGen = struct {
.@"union" => {
const union_llvm_ty = try o.lowerType(pt, struct_ty);
const layout = struct_ty.unionGetLayout(zcu);
- const payload_index = @intFromBool(layout.tag_align.compare(.gte, layout.payload_align));
+ const payload_index = @intFromBool(layout.tag_size > 0 and layout.tag_align.compare(.gte, layout.payload_align));
const field_ptr =
try self.wip.gepStruct(union_llvm_ty, struct_llvm_val, payload_index, "");
const payload_alignment = layout.payload_align.toLlvm();
@@ -7150,7 +6968,7 @@ pub const FuncGen = struct {
self.file,
self.scope,
self.prev_dbg_line,
- try o.lowerDebugType(pt, ptr_ty.childType(zcu)),
+ try o.getDebugType(pt, ptr_ty.childType(zcu)),
);
_ = try self.wip.callIntrinsic(
@@ -7183,7 +7001,7 @@ pub const FuncGen = struct {
self.file,
self.scope,
self.prev_dbg_line,
- try o.lowerDebugType(pt, operand_ty),
+ try o.getDebugType(pt, operand_ty),
arg_no: {
self.arg_inline_index += 1;
break :arg_no self.arg_inline_index;
@@ -7193,7 +7011,7 @@ pub const FuncGen = struct {
self.file,
self.scope,
self.prev_dbg_line,
- try o.lowerDebugType(pt, operand_ty),
+ try o.getDebugType(pt, operand_ty),
);
const zcu = pt.zcu;
@@ -7284,6 +7102,7 @@ pub const FuncGen = struct {
const llvm_param_attrs = try arena.alloc(Builder.Type, max_param_count);
const pt = self.ng.pt;
const zcu = pt.zcu;
+ const ip = &zcu.intern_pool;
const target = zcu.getTarget();
var llvm_ret_i: usize = 0;
@@ -7308,7 +7127,7 @@ pub const FuncGen = struct {
const output_inst = try self.resolveInst(output.operand);
const output_ty = self.typeOf(output.operand);
assert(output_ty.zigTypeTag(zcu) == .pointer);
- const elem_llvm_ty = try o.lowerPtrElemTy(pt, output_ty.childType(zcu));
+ const elem_llvm_ty = try o.lowerType(pt, output_ty.childType(zcu));
switch (constraint[0]) {
'=' => {},
@@ -7426,7 +7245,7 @@ pub const FuncGen = struct {
llvm_param_attrs[llvm_param_i] = if (constraint[0] == '*') blk: {
if (!is_by_ref) self.maybeMarkAllowZeroAccess(arg_ty.ptrInfo(zcu));
- break :blk try o.lowerPtrElemTy(pt, if (is_by_ref) arg_ty else arg_ty.childType(zcu));
+ break :blk try o.lowerType(pt, if (is_by_ref) arg_ty else arg_ty.childType(zcu));
} else .none;
llvm_param_i += 1;
@@ -7440,7 +7259,7 @@ pub const FuncGen = struct {
if (constraint[0] != '+') continue;
const rw_ty = self.typeOf(output.operand);
- const llvm_elem_ty = try o.lowerPtrElemTy(pt, rw_ty.childType(zcu));
+ const llvm_elem_ty = try o.lowerType(pt, rw_ty.childType(zcu));
if (llvm_ret_indirect[output.index]) {
llvm_param_values[llvm_param_i] = llvm_rw_vals[output.index];
llvm_param_types[llvm_param_i] = llvm_rw_vals[output.index].typeOfWip(&self.wip);
@@ -7467,30 +7286,21 @@ pub const FuncGen = struct {
total_i += 1;
}
- const ip = &zcu.intern_pool;
- const aggregate = ip.indexToKey(unwrapped_asm.clobbers).aggregate;
- const struct_type: Type = .fromInterned(aggregate.ty);
if (total_i != 0) try llvm_constraints.append(gpa, ',');
- switch (aggregate.storage) {
- .elems => |elems| for (elems, 0..) |elem, i| {
- switch (elem) {
- .bool_true => {
- const name = struct_type.structFieldName(i, zcu).toSlice(ip).?;
- total_i += try appendConstraints(gpa, &llvm_constraints, name, target);
- },
- .bool_false => continue,
- else => unreachable,
- }
- },
- .repeated_elem => |elem| switch (elem) {
- .bool_true => for (0..struct_type.structFieldCount(zcu)) |i| {
- const name = struct_type.structFieldName(i, zcu).toSlice(ip).?;
- total_i += try appendConstraints(gpa, &llvm_constraints, name, target);
- },
- .bool_false => {},
- else => unreachable,
- },
- .bytes => @panic("TODO"),
+ const clobbers_val: Value = .fromInterned(unwrapped_asm.clobbers);
+ const clobbers_ty = clobbers_val.typeOf(zcu);
+ var clobbers_bigint_buf: Value.BigIntSpace = undefined;
+ const clobbers_bigint = clobbers_val.toBigInt(&clobbers_bigint_buf, zcu);
+ for (0..clobbers_ty.structFieldCount(zcu)) |field_index| {
+ assert(clobbers_ty.fieldType(field_index, zcu).toIntern() == .bool_type);
+ const limb_bits = @bitSizeOf(std.math.big.Limb);
+ if (field_index / limb_bits >= clobbers_bigint.limbs.len) continue; // field is false
+ switch (@as(u1, @truncate(clobbers_bigint.limbs[field_index / limb_bits] >> @intCast(field_index % limb_bits)))) {
+ 0 => continue, // field is false
+ 1 => {}, // field is true
+ }
+ const name = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?;
+ total_i += try appendConstraints(gpa, &llvm_constraints, name, target);
}
// We have finished scanning through all inputs/outputs, so the number of
@@ -7676,7 +7486,7 @@ pub const FuncGen = struct {
comptime assert(optional_layout_version == 3);
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!payload_ty.hasRuntimeBits(zcu)) {
const loaded = if (operand_is_ptr)
try self.wip.load(access_kind, optional_llvm_ty, operand, .default, "")
else
@@ -7719,7 +7529,7 @@ pub const FuncGen = struct {
if (operand_is_ptr) self.maybeMarkAllowZeroAccess(operand_ty.ptrInfo(zcu));
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!payload_ty.hasRuntimeBits(zcu)) {
const loaded = if (operand_is_ptr)
try self.wip.load(access_kind, try o.lowerType(pt, err_union_ty), operand, .default, "")
else
@@ -7746,7 +7556,7 @@ pub const FuncGen = struct {
const operand = try self.resolveInst(ty_op.operand);
const optional_ty = self.typeOf(ty_op.operand).childType(zcu);
const payload_ty = optional_ty.optionalChild(zcu);
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!payload_ty.hasRuntimeBits(zcu)) {
// We have a pointer to a zero-bit value and we need to return
// a pointer to a zero-bit value.
return operand;
@@ -7774,7 +7584,7 @@ pub const FuncGen = struct {
const access_kind: Builder.MemoryAccessKind =
if (optional_ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal;
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!payload_ty.hasRuntimeBits(zcu)) {
self.maybeMarkAllowZeroAccess(optional_ptr_ty.ptrInfo(zcu));
// We have a pointer to a i8. We need to set it to 1 and then return the same pointer.
@@ -7810,7 +7620,7 @@ pub const FuncGen = struct {
const operand = try self.resolveInst(ty_op.operand);
const optional_ty = self.typeOf(ty_op.operand);
const payload_ty = self.typeOfIndex(inst);
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) return .none;
+ if (!payload_ty.hasRuntimeBits(zcu)) return .none;
if (optional_ty.optionalReprIsPayload(zcu)) {
// Payload value is the same as the optional value.
@@ -7832,7 +7642,7 @@ pub const FuncGen = struct {
const result_ty = self.typeOfIndex(inst);
const payload_ty = if (operand_is_ptr) result_ty.childType(zcu) else result_ty;
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!payload_ty.hasRuntimeBits(zcu)) {
return if (operand_is_ptr) operand else .none;
}
const offset = try errUnionPayloadOffset(payload_ty, pt);
@@ -7876,7 +7686,7 @@ pub const FuncGen = struct {
if (operand_is_ptr and operand_ty.isVolatilePtr(zcu)) .@"volatile" else .normal;
const payload_ty = err_union_ty.errorUnionPayload(zcu);
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!payload_ty.hasRuntimeBits(zcu)) {
if (!operand_is_ptr) return operand;
self.maybeMarkAllowZeroAccess(operand_ty.ptrInfo(zcu));
@@ -7912,7 +7722,7 @@ pub const FuncGen = struct {
const access_kind: Builder.MemoryAccessKind =
if (err_union_ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal;
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!payload_ty.hasRuntimeBits(zcu)) {
self.maybeMarkAllowZeroAccess(err_union_ptr_ty.ptrInfo(zcu));
_ = try self.wip.store(access_kind, non_error_val, operand, .default);
@@ -7959,9 +7769,8 @@ pub const FuncGen = struct {
const struct_llvm_ty = try o.lowerType(pt, struct_ty);
const llvm_field_index = o.llvmFieldIndex(struct_ty, field_index).?;
assert(self.err_ret_trace != .none);
- const field_ptr =
- try self.wip.gepStruct(struct_llvm_ty, self.err_ret_trace, llvm_field_index, "");
- const field_alignment = struct_ty.fieldAlignment(field_index, zcu);
+ const field_ptr = try self.wip.gepStruct(struct_llvm_ty, self.err_ret_trace, llvm_field_index, "");
+ const field_alignment = struct_ty.explicitFieldAlignment(field_index, zcu);
const field_ty = struct_ty.fieldType(field_index, zcu);
const field_ptr_ty = try pt.ptrType(.{
.child = field_ty.toIntern(),
@@ -8002,7 +7811,7 @@ pub const FuncGen = struct {
const payload_ty = self.typeOf(ty_op.operand);
const non_null_bit = try o.builder.intValue(.i8, 1);
comptime assert(optional_layout_version == 3);
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) return non_null_bit;
+ assert(payload_ty.hasRuntimeBits(zcu));
const operand = try self.resolveInst(ty_op.operand);
const optional_ty = self.typeOfIndex(inst);
if (optional_ty.optionalReprIsPayload(zcu)) return operand;
@@ -8036,9 +7845,7 @@ pub const FuncGen = struct {
const err_un_ty = self.typeOfIndex(inst);
const operand = try self.resolveInst(ty_op.operand);
const payload_ty = self.typeOf(ty_op.operand);
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
- return operand;
- }
+ assert(payload_ty.hasRuntimeBits(zcu));
const ok_err_code = try o.builder.intValue(try o.errorIntType(pt), 0);
const err_un_llvm_ty = try o.lowerType(pt, err_un_ty);
@@ -8078,7 +7885,7 @@ pub const FuncGen = struct {
const err_un_ty = self.typeOfIndex(inst);
const payload_ty = err_un_ty.errorUnionPayload(zcu);
const operand = try self.resolveInst(ty_op.operand);
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) return operand;
+ if (!payload_ty.hasRuntimeBits(zcu)) return operand;
const err_un_llvm_ty = try o.lowerType(pt, err_un_ty);
const payload_offset = try errUnionPayloadOffset(payload_ty, pt);
@@ -8530,7 +8337,7 @@ pub const FuncGen = struct {
const ptr = try self.resolveInst(bin_op.lhs);
const offset = try self.resolveInst(bin_op.rhs);
const ptr_ty = self.typeOf(bin_op.lhs);
- const llvm_elem_ty = try o.lowerPtrElemTy(pt, ptr_ty.childType(zcu));
+ const llvm_elem_ty = try o.lowerType(pt, ptr_ty.childType(zcu));
switch (ptr_ty.ptrSize(zcu)) {
// It's a pointer to an array, so according to LLVM we need an extra GEP index.
.one => return self.wip.gep(.inbounds, llvm_elem_ty, ptr, &.{
@@ -8554,7 +8361,7 @@ pub const FuncGen = struct {
const offset = try self.resolveInst(bin_op.rhs);
const negative_offset = try self.wip.neg(offset, "");
const ptr_ty = self.typeOf(bin_op.lhs);
- const llvm_elem_ty = try o.lowerPtrElemTy(pt, ptr_ty.childType(zcu));
+ const llvm_elem_ty = try o.lowerType(pt, ptr_ty.childType(zcu));
switch (ptr_ty.ptrSize(zcu)) {
// It's a pointer to an array, so according to LLVM we need an extra GEP index.
.one => return self.wip.gep(.inbounds, llvm_elem_ty, ptr, &.{
@@ -9515,7 +9322,7 @@ pub const FuncGen = struct {
self.file,
self.scope,
lbrace_line,
- try o.lowerDebugType(pt, inst_ty),
+ try o.getDebugType(pt, inst_ty),
self.arg_index,
);
@@ -9581,7 +9388,7 @@ pub const FuncGen = struct {
const zcu = pt.zcu;
const ptr_ty = self.typeOfIndex(inst);
const pointee_type = ptr_ty.childType(zcu);
- if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime(zcu))
+ if (!pointee_type.hasRuntimeBits(zcu))
return (try o.lowerPtrToVoid(pt, ptr_ty)).toValue();
const pointee_llvm_ty = try o.lowerType(pt, pointee_type);
@@ -9595,7 +9402,7 @@ pub const FuncGen = struct {
const zcu = pt.zcu;
const ptr_ty = self.typeOfIndex(inst);
const ret_ty = ptr_ty.childType(zcu);
- if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu))
+ if (!ret_ty.hasRuntimeBits(zcu))
return (try o.lowerPtrToVoid(pt, ptr_ty)).toValue();
if (self.ret_ptr != .none) return self.ret_ptr;
const ret_llvm_ty = try o.lowerType(pt, ret_ty);
@@ -9849,7 +9656,7 @@ pub const FuncGen = struct {
const ptr_ty = self.typeOf(atomic_load.ptr);
const info = ptr_ty.ptrInfo(zcu);
const elem_ty = Type.fromInterned(info.child);
- if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) return .none;
+ if (!elem_ty.hasRuntimeBits(zcu)) return .none;
const ordering = toLlvmAtomicOrdering(atomic_load.order);
const llvm_abi_ty = try o.getAtomicAbiType(pt, elem_ty, false);
const ptr_alignment = (if (info.flags.alignment != .none)
@@ -9897,7 +9704,7 @@ pub const FuncGen = struct {
const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
const ptr_ty = self.typeOf(bin_op.lhs);
const operand_ty = ptr_ty.childType(zcu);
- if (!operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return .none;
+ if (!operand_ty.hasRuntimeBits(zcu)) return .none;
const ptr = try self.resolveInst(bin_op.lhs);
var element = try self.resolveInst(bin_op.rhs);
const llvm_abi_ty = try o.getAtomicAbiType(pt, operand_ty, false);
@@ -10310,14 +10117,14 @@ pub const FuncGen = struct {
const ip = &zcu.intern_pool;
const enum_type = ip.loadEnumType(enum_ty.toIntern());
- // TODO: detect when the type changes and re-emit this function.
+ // TODO: detect when the type changes (`updateContainerType` will be called) and re-emit this function
const gop = try o.named_enum_map.getOrPut(o.gpa, enum_ty.toIntern());
if (gop.found_existing) return gop.value_ptr.*;
errdefer assert(o.named_enum_map.remove(enum_ty.toIntern()));
const target = &zcu.root_mod.resolved_target.result;
const function_index = try o.builder.addFunction(
- try o.builder.fnType(.i1, &.{try o.lowerType(pt, Type.fromInterned(enum_type.tag_ty))}, .normal),
+ try o.builder.fnType(.i1, &.{try o.lowerType(pt, Type.fromInterned(enum_type.int_tag_type))}, .normal),
try o.builder.strtabStringFmt("__zig_is_named_enum_value_{f}", .{enum_type.name.fmt(ip)}),
toLlvmAddressSpace(.generic, target),
);
@@ -10338,13 +10145,13 @@ pub const FuncGen = struct {
defer wip.deinit();
wip.cursor = .{ .block = try wip.block(0, "Entry") };
- const named_block = try wip.block(@intCast(enum_type.names.len), "Named");
+ const named_block = try wip.block(@intCast(enum_type.field_names.len), "Named");
const unnamed_block = try wip.block(1, "Unnamed");
const tag_int_value = wip.arg(0);
- var wip_switch = try wip.@"switch"(tag_int_value, unnamed_block, @intCast(enum_type.names.len), .none);
+ var wip_switch = try wip.@"switch"(tag_int_value, unnamed_block, @intCast(enum_type.field_names.len), .none);
defer wip_switch.finish(&wip);
- for (0..enum_type.names.len) |field_index| {
+ for (0..enum_type.field_names.len) |field_index| {
const this_tag_int_value = try o.lowerValue(
pt,
(try pt.enumValueFieldIndex(enum_ty, @intCast(field_index))).toIntern(),
@@ -10813,15 +10620,14 @@ pub const FuncGen = struct {
},
.@"struct" => {
if (zcu.typeToPackedStruct(result_ty)) |struct_type| {
- const backing_int_ty = struct_type.backingIntTypeUnordered(ip);
- assert(backing_int_ty != .none);
- const big_bits = Type.fromInterned(backing_int_ty).bitSize(zcu);
+ const backing_int_ty: Type = .fromInterned(struct_type.packed_backing_int_type);
+ const big_bits = backing_int_ty.bitSize(zcu);
const int_ty = try o.builder.intType(@intCast(big_bits));
comptime assert(Type.packed_struct_layout_version == 2);
var running_int = try o.builder.intValue(int_ty, 0);
var running_bits: u16 = 0;
for (elements, struct_type.field_types.get(ip)) |elem, field_ty| {
- if (!Type.fromInterned(field_ty).hasRuntimeBitsIgnoreComptime(zcu)) continue;
+ if (!Type.fromInterned(field_ty).hasRuntimeBits(zcu)) continue;
const non_int_val = try self.resolveInst(elem);
const ty_bit_size: u16 = @intCast(Type.fromInterned(field_ty).bitSize(zcu));
@@ -10853,12 +10659,12 @@ pub const FuncGen = struct {
const llvm_elem = try self.resolveInst(elem);
const llvm_i = o.llvmFieldIndex(result_ty, i).?;
- const field_ptr =
- try self.wip.gepStruct(llvm_result_ty, alloca_inst, llvm_i, "");
+ const field_ptr = try self.wip.gepStruct(llvm_result_ty, alloca_inst, llvm_i, "");
+
const field_ptr_ty = try pt.ptrType(.{
.child = self.typeOf(elem).toIntern(),
.flags = .{
- .alignment = result_ty.fieldAlignment(i, zcu),
+ .alignment = result_ty.explicitFieldAlignment(i, zcu),
},
});
try self.store(field_ptr, field_ptr_ty, llvm_elem, .none);
@@ -10920,28 +10726,16 @@ pub const FuncGen = struct {
const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;
const union_ty = self.typeOfIndex(inst);
const union_llvm_ty = try o.lowerType(pt, union_ty);
- const layout = union_ty.unionGetLayout(zcu);
const union_obj = zcu.typeToUnion(union_ty).?;
- if (union_obj.flagsUnordered(ip).layout == .@"packed") {
- const big_bits = union_ty.bitSize(zcu);
- const int_llvm_ty = try o.builder.intType(@intCast(big_bits));
- const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[extra.field_index]);
- const non_int_val = try self.resolveInst(extra.init);
- const small_int_ty = try o.builder.intType(@intCast(field_ty.bitSize(zcu)));
- const small_int_val = if (field_ty.isPtrAtRuntime(zcu))
- try self.wip.cast(.ptrtoint, non_int_val, small_int_ty, "")
- else
- try self.wip.cast(.bitcast, non_int_val, small_int_ty, "");
- return self.wip.conv(.unsigned, small_int_val, int_llvm_ty, "");
- }
+ assert(union_obj.layout != .@"packed");
+
+ const layout = Type.getUnionLayout(union_obj, zcu);
const tag_int_val = blk: {
const tag_ty = union_ty.unionTagTypeHypothetical(zcu);
- const union_field_name = union_obj.loadTagType(ip).names.get(ip)[extra.field_index];
- const enum_field_index = tag_ty.enumFieldIndex(union_field_name, zcu).?;
- const tag_val = try pt.enumValueFieldIndex(tag_ty, enum_field_index);
- break :blk try tag_val.intFromEnum(tag_ty, pt);
+ const tag_val = try pt.enumValueFieldIndex(tag_ty, extra.field_index);
+ break :blk tag_val.intFromEnum(zcu);
};
if (layout.payload_size == 0) {
if (layout.tag_size == 0) {
@@ -10963,16 +10757,14 @@ pub const FuncGen = struct {
const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[extra.field_index]);
const field_llvm_ty = try o.lowerType(pt, field_ty);
const field_size = field_ty.abiSize(zcu);
- const field_align = union_ty.fieldAlignment(extra.field_index, zcu);
+ const field_align = union_ty.explicitFieldAlignment(extra.field_index, zcu);
const llvm_usize = try o.lowerType(pt, Type.usize);
const usize_zero = try o.builder.intValue(llvm_usize, 0);
+ assert(field_ty.hasRuntimeBits(zcu));
+
const llvm_union_ty = t: {
const payload_ty = p: {
- if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
- const padding_len = layout.payload_size;
- break :p try o.builder.arrayType(padding_len, .i8);
- }
if (field_size == layout.payload_size) {
break :p field_llvm_ty;
}
@@ -10982,7 +10774,7 @@ pub const FuncGen = struct {
});
};
if (layout.tag_size == 0) break :t try o.builder.structType(.normal, &.{payload_ty});
- const tag_ty = try o.lowerType(pt, Type.fromInterned(union_obj.enum_tag_ty));
+ const tag_ty = try o.lowerType(pt, .fromInterned(union_obj.enum_tag_type));
var fields: [3]Builder.Type = undefined;
var fields_len: usize = 2;
if (layout.tag_align.compare(.gte, layout.payload_align)) {
@@ -11023,11 +10815,11 @@ pub const FuncGen = struct {
const tag_index = @intFromBool(layout.tag_align.compare(.lt, layout.payload_align));
const indices: [2]Builder.Value = .{ usize_zero, try o.builder.intValue(.i32, tag_index) };
const field_ptr = try self.wip.gep(.inbounds, llvm_union_ty, result_ptr, &indices, "");
- const tag_ty = try o.lowerType(pt, Type.fromInterned(union_obj.enum_tag_ty));
+ const tag_ty = try o.lowerType(pt, .fromInterned(union_obj.enum_tag_type));
var big_int_space: Value.BigIntSpace = undefined;
const tag_big_int = tag_int_val.toBigInt(&big_int_space, zcu);
const llvm_tag = try o.builder.bigIntValue(tag_ty, tag_big_int);
- const tag_alignment = Type.fromInterned(union_obj.enum_tag_ty).abiAlignment(zcu).toLlvm();
+ const tag_alignment = Type.fromInterned(union_obj.enum_tag_type).abiAlignment(zcu).toLlvm();
_ = try self.wip.store(.normal, llvm_tag, field_ptr, tag_alignment);
}
@@ -11274,63 +11066,45 @@ pub const FuncGen = struct {
fn fieldPtr(
self: *FuncGen,
- inst: Air.Inst.Index,
- struct_ptr: Builder.Value,
- struct_ptr_ty: Type,
+ aggregate_ptr: Builder.Value,
+ aggregate_ptr_ty: Type,
field_index: u32,
) !Builder.Value {
const o = self.ng.object;
const pt = self.ng.pt;
const zcu = pt.zcu;
- const struct_ty = struct_ptr_ty.childType(zcu);
- switch (struct_ty.zigTypeTag(zcu)) {
- .@"struct" => switch (struct_ty.containerLayout(zcu)) {
- .@"packed" => {
- const result_ty = self.typeOfIndex(inst);
- const result_ty_info = result_ty.ptrInfo(zcu);
- const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(zcu);
- const struct_type = zcu.typeToStruct(struct_ty).?;
-
- if (result_ty_info.packed_offset.host_size != 0) {
- // From LLVM's perspective, a pointer to a packed struct and a pointer
- // to a field of a packed struct are the same. The difference is in the
- // Zig pointer type which provides information for how to mask and shift
- // out the relevant bits when accessing the pointee.
- return struct_ptr;
- }
-
- // We have a pointer to a packed struct field that happens to be byte-aligned.
- // Offset our operand pointer by the correct number of bytes.
- const byte_offset = @divExact(zcu.structPackedFieldBitOffset(struct_type, field_index) + struct_ptr_ty_info.packed_offset.bit_offset, 8);
- if (byte_offset == 0) return struct_ptr;
- const usize_ty = try o.lowerType(pt, Type.usize);
- const llvm_index = try o.builder.intValue(usize_ty, byte_offset);
- return self.wip.gep(.inbounds, .i8, struct_ptr, &.{llvm_index}, "");
- },
- else => {
- const struct_llvm_ty = try o.lowerPtrElemTy(pt, struct_ty);
-
- if (o.llvmFieldIndex(struct_ty, field_index)) |llvm_field_index| {
- return self.wip.gepStruct(struct_llvm_ty, struct_ptr, llvm_field_index, "");
- } else {
- // If we found no index then this means this is a zero sized field at the
- // end of the struct. Treat our struct pointer as an array of two and get
- // the index to the element at index `1` to get a pointer to the end of
- // the struct.
- const llvm_index = try o.builder.intValue(
- try o.lowerType(pt, Type.usize),
- @intFromBool(struct_ty.hasRuntimeBitsIgnoreComptime(zcu)),
- );
- return self.wip.gep(.inbounds, struct_llvm_ty, struct_ptr, &.{llvm_index}, "");
- }
- },
+ const aggregate_ty = aggregate_ptr_ty.childType(zcu);
+ if (aggregate_ty.containerLayout(zcu) == .@"packed") {
+ // A pointer to a bitpack field is equivalent to a pointer to the whole bitpack; the
+ // bit offset is represented in the pointer *type*.
+ return aggregate_ptr;
+ }
+ switch (aggregate_ty.zigTypeTag(zcu)) {
+ .@"struct" => {
+ if (!aggregate_ty.hasRuntimeBits(zcu)) {
+ return aggregate_ptr;
+ }
+ const struct_llvm_ty = try o.lowerType(pt, aggregate_ty);
+ if (o.llvmFieldIndex(aggregate_ty, field_index)) |llvm_field_index| {
+ return self.wip.gepStruct(struct_llvm_ty, aggregate_ptr, llvm_field_index, "");
+ } else {
+ // If we found no index then this means this is a zero sized field at the
+ // end of the struct. Treat our struct pointer as an array of two and get
+ // the index to the element at index `1` to get a pointer to the end of
+ // the struct.
+ const llvm_index = try o.builder.intValue(
+ try o.lowerType(pt, Type.usize),
+ @intFromBool(aggregate_ty.hasRuntimeBits(zcu)),
+ );
+ return self.wip.gep(.inbounds, struct_llvm_ty, aggregate_ptr, &.{llvm_index}, "");
+ }
},
.@"union" => {
- const layout = struct_ty.unionGetLayout(zcu);
- if (layout.payload_size == 0 or struct_ty.containerLayout(zcu) == .@"packed") return struct_ptr;
- const payload_index = @intFromBool(layout.tag_align.compare(.gte, layout.payload_align));
- const union_llvm_ty = try o.lowerType(pt, struct_ty);
- return self.wip.gepStruct(union_llvm_ty, struct_ptr, payload_index, "");
+ const layout = aggregate_ty.unionGetLayout(zcu);
+ if (layout.payload_size == 0) return aggregate_ptr;
+ const payload_index = @intFromBool(layout.tag_size > 0 and layout.tag_align.compare(.gte, layout.payload_align));
+ const union_llvm_ty = try o.lowerType(pt, aggregate_ty);
+ return self.wip.gepStruct(union_llvm_ty, aggregate_ptr, payload_index, "");
},
else => unreachable,
}
@@ -11406,7 +11180,7 @@ pub const FuncGen = struct {
const zcu = pt.zcu;
const info = ptr_ty.ptrInfo(zcu);
const elem_ty = Type.fromInterned(info.child);
- if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) return .none;
+ if (!elem_ty.hasRuntimeBits(zcu)) return .none;
const ptr_alignment = (if (info.flags.alignment != .none)
@as(InternPool.Alignment, info.flags.alignment)
@@ -11478,7 +11252,7 @@ pub const FuncGen = struct {
const zcu = pt.zcu;
const info = ptr_ty.ptrInfo(zcu);
const elem_ty = Type.fromInterned(info.child);
- if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!elem_ty.hasRuntimeBits(zcu)) {
return;
}
const ptr_alignment = ptr_ty.ptrAlignment(zcu).toLlvm();
@@ -12061,7 +11835,7 @@ fn returnTypeByRef(zcu: *Zcu, target: *const std.Target, ty: Type) bool {
fn firstParamSRet(fn_info: InternPool.Key.FuncType, zcu: *Zcu, target: *const std.Target) bool {
const return_type = Type.fromInterned(fn_info.return_type);
- if (!return_type.hasRuntimeBitsIgnoreComptime(zcu)) return false;
+ if (!return_type.hasRuntimeBits(zcu)) return false;
return switch (fn_info.cc) {
.auto => returnTypeByRef(zcu, target, return_type),
@@ -12101,11 +11875,9 @@ fn firstParamSRetSystemV(ty: Type, zcu: *Zcu, target: *const std.Target) bool {
fn lowerFnRetTy(o: *Object, pt: Zcu.PerThread, fn_info: InternPool.Key.FuncType) Allocator.Error!Builder.Type {
const zcu = pt.zcu;
const return_type = Type.fromInterned(fn_info.return_type);
- if (!return_type.hasRuntimeBitsIgnoreComptime(zcu)) {
- // If the return type is an error set or an error union, then we make this
- // anyerror return type instead, so that it can be coerced into a function
- // pointer type which has anyerror as the return type.
- return if (return_type.isError(zcu)) try o.errorIntType(pt) else .void;
+ if (!return_type.hasRuntimeBits(zcu)) {
+ assert(!return_type.isError(zcu));
+ return .void;
}
const target = zcu.getTarget();
switch (fn_info.cc) {
@@ -12149,7 +11921,7 @@ fn lowerFnRetTy(o: *Object, pt: Zcu.PerThread, fn_info: InternPool.Key.FuncType)
var types: [8]Builder.Type = undefined;
for (0..return_type.structFieldCount(zcu)) |field_index| {
const field_ty = return_type.fieldType(field_index, zcu);
- if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
+ if (!field_ty.hasRuntimeBits(zcu)) continue;
types[types_len] = try o.lowerType(pt, field_ty);
types_len += 1;
}
@@ -12187,6 +11959,7 @@ fn lowerSystemVFnRetTy(o: *Object, pt: Zcu.PerThread, fn_info: InternPool.Key.Fu
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const return_type = Type.fromInterned(fn_info.return_type);
+ return_type.assertHasLayout(zcu);
if (isScalar(zcu, return_type)) {
return o.lowerType(pt, return_type);
}
@@ -12235,9 +12008,7 @@ fn lowerSystemVFnRetTy(o: *Object, pt: Zcu.PerThread, fn_info: InternPool.Key.Fu
assert(first_non_integer orelse classes.len == types_index);
switch (ip.indexToKey(return_type.toIntern())) {
.struct_type => {
- const struct_type = ip.loadStructType(return_type.toIntern());
- assert(struct_type.haveLayout(ip));
- const size: u64 = struct_type.sizeUnordered(ip);
+ const size = return_type.abiSize(zcu);
assert((std.math.divCeil(u64, size, 8) catch unreachable) == types_index);
if (size % 8 > 0) {
types_buffer[types_index - 1] = try o.builder.intType(@intCast(size % 8 * 8));
@@ -12273,7 +12044,7 @@ const ParamTypeIterator = struct {
i64_array: u8,
};
- pub fn next(it: *ParamTypeIterator) Allocator.Error!?Lowering {
+ fn next(it: *ParamTypeIterator) Allocator.Error!?Lowering {
if (it.zig_index >= it.fn_info.param_types.len) return null;
const ip = &it.pt.zcu.intern_pool;
const ty = it.fn_info.param_types.get(ip)[it.zig_index];
@@ -12282,7 +12053,7 @@ const ParamTypeIterator = struct {
}
/// `airCall` uses this instead of `next` so that it can take into account variadic functions.
- pub fn nextCall(it: *ParamTypeIterator, fg: *FuncGen, args: []const Air.Inst.Ref) Allocator.Error!?Lowering {
+ fn nextCall(it: *ParamTypeIterator, fg: *FuncGen, args: []const Air.Inst.Ref) Allocator.Error!?Lowering {
assert(std.meta.eql(it.pt, fg.ng.pt));
const ip = &it.pt.zcu.intern_pool;
if (it.zig_index >= it.fn_info.param_types.len) {
@@ -12301,7 +12072,7 @@ const ParamTypeIterator = struct {
const zcu = pt.zcu;
const target = zcu.getTarget();
- if (!ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!ty.hasRuntimeBits(zcu)) {
it.zig_index += 1;
return .no_bits;
}
@@ -12396,7 +12167,7 @@ const ParamTypeIterator = struct {
it.types_len = 0;
for (0..ty.structFieldCount(zcu)) |field_index| {
const field_ty = ty.fieldType(field_index, zcu);
- if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
+ if (!field_ty.hasRuntimeBits(zcu)) continue;
it.types_buffer[it.types_len] = try it.object.lowerType(pt, field_ty);
it.types_len += 1;
}
@@ -12473,6 +12244,7 @@ const ParamTypeIterator = struct {
fn nextSystemV(it: *ParamTypeIterator, ty: Type) Allocator.Error!?Lowering {
const zcu = it.pt.zcu;
const ip = &zcu.intern_pool;
+ ty.assertHasLayout(zcu);
const classes = x86_64_abi.classifySystemV(ty, zcu, zcu.getTarget(), .arg);
if (classes[0] == .memory) {
it.zig_index += 1;
@@ -12544,9 +12316,7 @@ const ParamTypeIterator = struct {
}
switch (ip.indexToKey(ty.toIntern())) {
.struct_type => {
- const struct_type = ip.loadStructType(ty.toIntern());
- assert(struct_type.haveLayout(ip));
- const size: u64 = struct_type.sizeUnordered(ip);
+ const size = ty.abiSize(zcu);
assert((std.math.divCeil(u64, size, 8) catch unreachable) == types_index);
if (size % 8 > 0) {
types_buffer[types_index - 1] =
@@ -12720,14 +12490,14 @@ fn isByRef(ty: Type, zcu: *Zcu) bool {
},
.error_union => {
const payload_ty = ty.errorUnionPayload(zcu);
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!payload_ty.hasRuntimeBits(zcu)) {
return false;
}
return true;
},
.optional => {
const payload_ty = ty.optionalChild(zcu);
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!payload_ty.hasRuntimeBits(zcu)) {
return false;
}
if (ty.optionalReprIsPayload(zcu)) {
diff --git a/src/codegen/mips/abi.zig b/src/codegen/mips/abi.zig
index 02c4c637a4c362ea4b3a826fbd27b72598fcc2cb..a27adb7ace40ff937a820a2e8bdfacea12f85d31 100644
--- a/src/codegen/mips/abi.zig
+++ b/src/codegen/mips/abi.zig
@@ -13,7 +13,7 @@ pub const Context = enum { ret, arg };
pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class {
const target = zcu.getTarget();
- std.debug.assert(ty.hasRuntimeBitsIgnoreComptime(zcu));
+ std.debug.assert(ty.hasRuntimeBits(zcu));
const max_direct_size = target.ptrBitWidth() * 2;
switch (ty.zigTypeTag(zcu)) {
@@ -44,7 +44,7 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class {
return .byval;
},
.vector => {
- const elem_type = ty.elemType2(zcu);
+ const elem_type = ty.childType(zcu);
switch (elem_type.zigTypeTag(zcu)) {
.bool, .int => {
const bit_size = ty.bitSize(zcu);
diff --git a/src/codegen/riscv64/CodeGen.zig b/src/codegen/riscv64/CodeGen.zig
index 1f70f5f4de379ad0e01f75be35f0d13695f5b766..3ad6faf805259154ae35f347e1dee712bea196cf 100644
--- a/src/codegen/riscv64/CodeGen.zig
+++ b/src/codegen/riscv64/CodeGen.zig
@@ -2673,7 +2673,7 @@ fn genBinOp(
defer func.register_manager.unlockReg(tmp_lock);
// RISC-V has no immediate mul, so we copy the size to a temporary register
- const elem_size = lhs_ty.elemType2(zcu).abiSize(zcu);
+ const elem_size = lhs_ty.indexableElem(zcu).abiSize(zcu);
const elem_size_reg = try func.copyToTmpRegister(Type.u64, .{ .immediate = elem_size });
try func.genBinOp(
@@ -3257,7 +3257,7 @@ fn airOptionalPayload(func: *Func, inst: Air.Inst.Index) !void {
const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
const result: MCValue = result: {
const pl_ty = func.typeOfIndex(inst);
- if (!pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .none;
+ if (!pl_ty.hasRuntimeBits(zcu)) break :result .none;
const opt_mcv = try func.resolveInst(ty_op.operand);
if (func.reuseOperand(inst, ty_op.operand, 0, opt_mcv)) {
@@ -3331,7 +3331,7 @@ fn airUnwrapErrErr(func: *Func, inst: Air.Inst.Index) !void {
break :result .{ .immediate = 0 };
}
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!payload_ty.hasRuntimeBits(zcu)) {
break :result operand;
}
@@ -3384,7 +3384,7 @@ fn genUnwrapErrUnionPayloadMir(
const payload_ty = err_union_ty.errorUnionPayload(zcu);
const result: MCValue = result: {
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .none;
+ if (!payload_ty.hasRuntimeBits(zcu)) break :result .none;
const payload_off: u31 = @intCast(errUnionPayloadOffset(payload_ty, zcu));
switch (err_union) {
@@ -3547,7 +3547,7 @@ fn airWrapErrUnionPayload(func: *Func, inst: Air.Inst.Index) !void {
const operand = try func.resolveInst(ty_op.operand);
const result: MCValue = result: {
- if (!pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .{ .immediate = 0 };
+ if (!pl_ty.hasRuntimeBits(zcu)) break :result .{ .immediate = 0 };
const frame_index = try func.allocFrameIndex(FrameAlloc.initSpill(eu_ty, zcu));
const pl_off: i32 = @intCast(errUnionPayloadOffset(pl_ty, zcu));
@@ -3571,7 +3571,7 @@ fn airWrapErrUnionErr(func: *Func, inst: Air.Inst.Index) !void {
const err_ty = eu_ty.errorUnionSet(zcu);
const result: MCValue = result: {
- if (!pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result try func.resolveInst(ty_op.operand);
+ if (!pl_ty.hasRuntimeBits(zcu)) break :result try func.resolveInst(ty_op.operand);
const frame_index = try func.allocFrameIndex(FrameAlloc.initSpill(eu_ty, zcu));
const pl_off: i32 = @intCast(errUnionPayloadOffset(pl_ty, zcu));
@@ -3761,7 +3761,7 @@ fn airSliceElemVal(func: *Func, inst: Air.Inst.Index) !void {
const result: MCValue = result: {
const elem_ty = func.typeOfIndex(inst);
- if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .none;
+ assert(elem_ty.hasRuntimeBits(zcu));
const slice_ty = func.typeOf(bin_op.lhs);
const slice_ptr_field_type = slice_ty.slicePtrFieldType(zcu);
@@ -3913,9 +3913,8 @@ fn airPtrElemVal(func: *Func, inst: Air.Inst.Index) !void {
const base_ptr_ty = func.typeOf(bin_op.lhs);
const result: MCValue = if (!is_volatile and func.liveness.isUnused(inst)) .unreach else result: {
- const elem_ty = base_ptr_ty.elemType2(zcu);
- if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .none;
-
+ const elem_ty = base_ptr_ty.indexableElem(zcu);
+ assert(elem_ty.hasRuntimeBits(zcu));
const base_ptr_mcv = try func.resolveInst(bin_op.lhs);
const base_ptr_lock: ?RegisterLock = switch (base_ptr_mcv) {
.register => |reg| func.register_manager.lockRegAssumeUnused(reg),
@@ -4618,7 +4617,7 @@ fn airStructFieldVal(func: *Func, inst: Air.Inst.Index) !void {
const src_mcv = try func.resolveInst(operand);
const struct_ty = func.typeOf(operand);
const field_ty = struct_ty.fieldType(index, zcu);
- if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .none;
+ assert(field_ty.hasRuntimeBits(zcu));
const field_off: u32 = switch (struct_ty.containerLayout(zcu)) {
.auto, .@"extern" => @intCast(struct_ty.structFieldOffset(index, zcu) * 8),
@@ -5127,7 +5126,6 @@ fn airCmp(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
const bin_op = func.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
const pt = func.pt;
const zcu = pt.zcu;
- const ip = &zcu.intern_pool;
const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
const lhs_ty = func.typeOf(bin_op.lhs);
@@ -5141,28 +5139,23 @@ fn airCmp(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
.optional,
.@"struct",
=> {
- const int_ty = switch (lhs_ty.zigTypeTag(zcu)) {
+ const int_ty: Type = switch (lhs_ty.zigTypeTag(zcu)) {
.@"enum" => lhs_ty.intTagType(zcu),
.int => lhs_ty,
- .bool => Type.u1,
- .pointer => Type.u64,
- .error_set => Type.anyerror,
+ .bool => .u1,
+ .pointer => .u64,
+ .error_set => .anyerror,
.optional => blk: {
const payload_ty = lhs_ty.optionalChild(zcu);
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
- break :blk Type.u1;
+ if (!payload_ty.hasRuntimeBits(zcu)) {
+ break :blk .u1;
} else if (lhs_ty.isPtrLikeOptional(zcu)) {
- break :blk Type.u64;
+ break :blk .u64;
} else {
return func.fail("TODO riscv cmp non-pointer optionals", .{});
}
},
- .@"struct" => blk: {
- const struct_obj = ip.loadStructType(lhs_ty.toIntern());
- assert(struct_obj.layout == .@"packed");
- const backing_index = struct_obj.backingIntTypeUnordered(ip);
- break :blk Type.fromInterned(backing_index);
- },
+ .@"struct", .@"union" => lhs_ty.bitpackBackingInt(zcu),
else => unreachable,
};
@@ -5926,8 +5919,7 @@ fn airBr(func: *Func, inst: Air.Inst.Index) !void {
const br = func.air.instructions.items(.data)[@intFromEnum(inst)].br;
const block_ty = func.typeOfIndex(br.block_inst);
- const block_unused =
- !block_ty.hasRuntimeBitsIgnoreComptime(zcu) or func.liveness.isUnused(br.block_inst);
+ const block_unused = !block_ty.hasRuntimeBits(zcu) or func.liveness.isUnused(br.block_inst);
const block_tracking = func.inst_tracking.getPtr(br.block_inst).?;
const block_data = func.blocks.getPtr(br.block_inst).?;
const first_br = block_data.relocs.items.len == 0;
@@ -6150,31 +6142,26 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {
const zcu = func.pt.zcu;
const ip = &zcu.intern_pool;
- const aggregate = ip.indexToKey(unwrapped_asm.clobbers).aggregate;
- const struct_type: Type = .fromInterned(aggregate.ty);
- switch (aggregate.storage) {
- .elems => |elems| for (elems, 0..) |elem, i| {
- switch (elem) {
- .bool_true => {
- const clobber = struct_type.structFieldName(i, zcu).toSlice(ip).?;
- assert(clobber.len != 0);
- if (std.mem.eql(u8, clobber, "memory")) {
- // nothing really to do
- } else {
- try func.register_manager.getReg(parseRegName(clobber) orelse
- return func.fail("invalid clobber: '{s}'", .{clobber}), null);
- }
- },
- .bool_false => continue,
- else => unreachable,
- }
- },
- .repeated_elem => |elem| switch (elem) {
- .bool_true => @panic("TODO"),
- .bool_false => {},
- else => unreachable,
- },
- .bytes => @panic("TODO"),
+ const clobbers_val: Value = .fromInterned(unwrapped_asm.clobbers);
+ const clobbers_ty = clobbers_val.typeOf(zcu);
+ var clobbers_bigint_buf: Value.BigIntSpace = undefined;
+ const clobbers_bigint = clobbers_val.toBigInt(&clobbers_bigint_buf, zcu);
+ for (0..clobbers_ty.structFieldCount(zcu)) |field_index| {
+ assert(clobbers_ty.fieldType(field_index, zcu).toIntern() == .bool_type);
+ const limb_bits = @bitSizeOf(std.math.big.Limb);
+ if (field_index / limb_bits >= clobbers_bigint.limbs.len) continue; // field is false
+ switch (@as(u1, @truncate(clobbers_bigint.limbs[field_index / limb_bits] >> @intCast(field_index % limb_bits)))) {
+ 0 => continue, // field is false
+ 1 => {}, // field is true
+ }
+ const clobber = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?;
+ assert(clobber.len != 0);
+ if (std.mem.eql(u8, clobber, "memory")) {
+ // nothing really to do
+ } else {
+ try func.register_manager.getReg(parseRegName(clobber) orelse
+ return func.fail("invalid clobber: '{s}'", .{clobber}), null);
+ }
}
const Label = struct {
@@ -8255,7 +8242,7 @@ fn resolveCallingConventionValues(
// Return values
if (ret_ty.zigTypeTag(zcu) == .noreturn) {
result.return_value = InstTracking.init(.unreach);
- } else if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ } else if (!ret_ty.hasRuntimeBits(zcu)) {
result.return_value = InstTracking.init(.none);
} else {
var ret_tracking: [2]InstTracking = undefined;
@@ -8306,7 +8293,7 @@ fn resolveCallingConventionValues(
var param_float_reg_i: usize = 0;
for (param_types, result.args) |ty, *arg| {
- if (!ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!ty.hasRuntimeBits(zcu)) {
assert(cc == .auto);
arg.* = .none;
continue;
@@ -8421,10 +8408,10 @@ fn hasFeature(func: *Func, feature: Target.riscv.Feature) bool {
}
pub fn errUnionPayloadOffset(payload_ty: Type, zcu: *Zcu) u64 {
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) return 0;
+ if (!payload_ty.hasRuntimeBits(zcu)) return 0;
const payload_align = payload_ty.abiAlignment(zcu);
const error_align = Type.anyerror.abiAlignment(zcu);
- if (payload_align.compare(.gte, error_align) or !payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (payload_align.compare(.gte, error_align) or !payload_ty.hasRuntimeBits(zcu)) {
return 0;
} else {
return payload_align.forward(Type.anyerror.abiSize(zcu));
@@ -8432,10 +8419,10 @@ pub fn errUnionPayloadOffset(payload_ty: Type, zcu: *Zcu) u64 {
}
pub fn errUnionErrorOffset(payload_ty: Type, zcu: *Zcu) u64 {
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) return 0;
+ if (!payload_ty.hasRuntimeBits(zcu)) return 0;
const payload_align = payload_ty.abiAlignment(zcu);
const error_align = Type.anyerror.abiAlignment(zcu);
- if (payload_align.compare(.gte, error_align) and payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (payload_align.compare(.gte, error_align) and payload_ty.hasRuntimeBits(zcu)) {
return error_align.forward(payload_ty.abiSize(zcu));
} else {
return 0;
diff --git a/src/codegen/riscv64/abi.zig b/src/codegen/riscv64/abi.zig
index 1a380eab905708b866f18a29762e1653cd0a521b..05164530df958129231fd514f8e4c17dff8e8590 100644
--- a/src/codegen/riscv64/abi.zig
+++ b/src/codegen/riscv64/abi.zig
@@ -11,7 +11,7 @@ pub const Class = enum { memory, byval, integer, double_integer, fields };
pub fn classifyType(ty: Type, zcu: *Zcu) Class {
const target = zcu.getTarget();
- std.debug.assert(ty.hasRuntimeBitsIgnoreComptime(zcu));
+ std.debug.assert(ty.hasRuntimeBits(zcu));
const max_byval_size = target.ptrBitWidth() * 2;
switch (ty.zigTypeTag(zcu)) {
@@ -27,7 +27,7 @@ pub fn classifyType(ty: Type, zcu: *Zcu) Class {
var field_count: usize = 0;
for (0..ty.structFieldCount(zcu)) |field_index| {
const field_ty = ty.fieldType(field_index, zcu);
- if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
+ if (!field_ty.hasRuntimeBits(zcu)) continue;
if (field_ty.isRuntimeFloat())
any_fp = true
else if (!field_ty.isAbiInt(zcu))
diff --git a/src/codegen/sparc64/CodeGen.zig b/src/codegen/sparc64/CodeGen.zig
index a246df12c59f3277001ba28fd671b6c42fe769e7..3b38d6319ac325cb462b805727197121be348bfd 100644
--- a/src/codegen/sparc64/CodeGen.zig
+++ b/src/codegen/sparc64/CodeGen.zig
@@ -1102,7 +1102,7 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
fn lowerBlock(self: *Self, inst: Air.Inst.Index, body: []const Air.Inst.Index) !void {
try self.blocks.putNoClobber(self.gpa, inst, .{
// A block is a setup to be able to jump to the end.
- .relocs = .{},
+ .relocs = .empty,
// It also acts as a receptacle for break operands.
// Here we use `MCValue.none` to represent a null value so that the first
// break instruction will choose a MCValue for the block result and overwrite
@@ -1376,19 +1376,19 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
const rhs = try self.resolveInst(bin_op.rhs);
const lhs_ty = self.typeOf(bin_op.lhs);
- const int_ty = switch (lhs_ty.zigTypeTag(zcu)) {
+ const int_ty: Type = switch (lhs_ty.zigTypeTag(zcu)) {
.vector => unreachable, // Handled by cmp_vector.
.@"enum" => lhs_ty.intTagType(zcu),
.int => lhs_ty,
- .bool => Type.u1,
- .pointer => Type.usize,
- .error_set => Type.u16,
+ .bool => .u1,
+ .pointer => .usize,
+ .error_set => .u16,
.optional => blk: {
const payload_ty = lhs_ty.optionalChild(zcu);
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
- break :blk Type.u1;
+ if (!payload_ty.hasRuntimeBits(zcu)) {
+ break :blk .u1;
} else if (lhs_ty.isPtrLikeOptional(zcu)) {
- break :blk Type.usize;
+ break :blk .usize;
} else {
return self.fail("TODO SPARCv9 cmp non-pointer optionals", .{});
}
@@ -3452,8 +3452,8 @@ fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type)
if (err_ty.errorSetIsEmpty(zcu)) {
return error_union_mcv;
}
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
- return MCValue.none;
+ if (!payload_ty.hasRuntimeBits(zcu)) {
+ return .none;
}
const payload_offset: u32 = @intCast(errUnionPayloadOffset(payload_ty, zcu));
@@ -4481,7 +4481,7 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue {
const ty = self.typeOf(ref);
// If the type has no codegen bits, no need to store it.
- if (!ty.hasRuntimeBitsIgnoreComptime(pt.zcu)) return .none;
+ if (!ty.hasRuntimeBits(pt.zcu)) return .none;
if (ref.toIndex()) |inst| {
return self.getResolvedInstValue(inst);
diff --git a/src/codegen/spirv/CodeGen.zig b/src/codegen/spirv/CodeGen.zig
index 2222bb9a050341495a7ca97f6b5a4b9dd5b189ec..d071952924eb9542036f80f13a2fc2dc3bf86d40 100644
--- a/src/codegen/spirv/CodeGen.zig
+++ b/src/codegen/spirv/CodeGen.zig
@@ -208,7 +208,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
try cg.args.ensureUnusedCapacity(gpa, fn_info.param_types.len);
for (fn_info.param_types.get(ip)) |param_ty_index| {
const param_ty: Type = .fromInterned(param_ty_index);
- if (!param_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
+ if (!param_ty.hasRuntimeBits(zcu)) continue;
const param_type_id = try cg.resolveType(param_ty, .direct);
const arg_result_id = cg.module.allocId();
@@ -689,7 +689,7 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {
.comptime_int => if (value < 0) .signed else .unsigned,
else => unreachable,
};
- if (@sizeOf(@TypeOf(value)) >= 4 and big_int) {
+ if (@TypeOf(value) != comptime_int and @sizeOf(@TypeOf(value)) >= 4 and big_int) {
const value64: u64 = switch (signedness) {
.signed => @bitCast(@as(i64, @intCast(value))),
.unsigned => @as(u64, @intCast(value)),
@@ -814,14 +814,11 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
.@"extern",
.func,
.enum_literal,
- .empty_enum_value,
=> unreachable, // non-runtime values
.simple_value => |simple_value| switch (simple_value) {
- .undefined,
.void,
.null,
- .empty_tuple,
.@"unreachable",
=> unreachable, // non-runtime values
@@ -887,7 +884,7 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
return try cg.constructComposite(comp_ty_id, &constituents);
},
.enum_tag => {
- const int_val = try val.intFromEnum(ty, pt);
+ const int_val = val.intFromEnum(zcu);
const int_ty = ty.intTagType(zcu);
break :cache try cg.constant(int_ty, int_val, repr);
},
@@ -962,18 +959,7 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
},
.struct_type => {
const struct_type = zcu.typeToStruct(ty).?;
-
- if (struct_type.layout == .@"packed") {
- // TODO: composite int
- // TODO: endianness
- const bits: u16 = @intCast(ty.bitSize(zcu));
- const bytes = std.mem.alignForward(u16, cg.module.backingIntBits(bits).@"0", 8) / 8;
- var limbs: [8]u8 = undefined;
- @memset(&limbs, 0);
- val.writeToPackedMemory(ty, pt, limbs[0..bytes], 0) catch unreachable;
- const backing_ty: Type = .fromInterned(struct_type.backingIntTypeUnordered(ip));
- return try cg.constInt(backing_ty, @as(u64, @bitCast(limbs)));
- }
+ assert(struct_type.layout != .@"packed"); // packed structs use `bitpack`
var types = std.array_list.Managed(Type).init(gpa);
defer types.deinit();
@@ -984,7 +970,7 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
var it = struct_type.iterateRuntimeOrder(ip);
while (it.next()) |field_index| {
const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);
- if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!field_ty.hasRuntimeBits(zcu)) {
// This is a zero-bit field - we only needed it for the alignment.
continue;
}
@@ -1004,20 +990,24 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
else => unreachable,
},
.un => |un| {
+ assert(ty.containerLayout(zcu) != .@"packed"); // packed unions use `bitpack`
if (un.tag == .none) {
- assert(ty.containerLayout(zcu) == .@"packed"); // TODO
- const int_ty = try pt.intType(.unsigned, @intCast(ty.bitSize(zcu)));
- return try cg.constInt(int_ty, Value.toUnsignedInt(.fromInterned(un.val), zcu));
+ @panic("TODO");
}
const active_field = ty.unionTagFieldIndex(.fromInterned(un.tag), zcu).?;
const union_obj = zcu.typeToUnion(ty).?;
const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[active_field]);
- const payload = if (field_ty.hasRuntimeBitsIgnoreComptime(zcu))
+ const payload = if (field_ty.hasRuntimeBits(zcu))
try cg.constant(field_ty, .fromInterned(un.val), .direct)
else
null;
return try cg.unionInit(ty, active_field, payload);
},
+ .bitpack => |bitpack| {
+ const int_val: Value = .fromInterned(bitpack.backing_int_val);
+ break :cache try cg.constant(int_val.typeOf(zcu), int_val, repr);
+ },
+
.memoized_call => unreachable,
}
};
@@ -1041,7 +1031,7 @@ fn constantPtr(cg: *CodeGen, ptr_val: Value) !Id {
var arena = std.heap.ArenaAllocator.init(gpa);
defer arena.deinit();
- const derivation = try ptr_val.pointerDerivation(arena.allocator(), pt);
+ const derivation = try ptr_val.pointerDerivation(arena.allocator(), pt, null);
return cg.derivePtr(derivation);
}
@@ -1150,7 +1140,7 @@ fn constantUavRef(
}
// const is_fn_body = decl_ty.zigTypeTag(zcu) == .@"fn";
- if (!uav_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!uav_ty.hasRuntimeBits(zcu)) {
// Pointer to nothing - return undefined
return cg.module.constUndef(ty_id);
}
@@ -1196,7 +1186,7 @@ fn constantNavRef(cg: *CodeGen, ty: Type, nav_index: InternPool.Nav.Index) !Id {
},
}
- if (!nav_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!nav_ty.hasRuntimeBits(zcu)) {
// Pointer to nothing - return undefined.
return cg.module.constUndef(ty_id);
}
@@ -1258,17 +1248,16 @@ fn resolveTypeName(cg: *CodeGen, ty: Type) ![]const u8 {
fn resolveUnionType(cg: *CodeGen, ty: Type) !Id {
const gpa = cg.module.gpa;
const zcu = cg.module.zcu;
- const ip = &zcu.intern_pool;
const union_obj = zcu.typeToUnion(ty).?;
- if (union_obj.flagsUnordered(ip).layout == .@"packed") {
+ if (union_obj.layout == .@"packed") {
return try cg.module.intType(.unsigned, @intCast(ty.bitSize(zcu)));
}
const layout = cg.unionLayout(ty);
if (!layout.has_payload) {
// No payload, so represent this as just the tag type.
- return try cg.resolveType(.fromInterned(union_obj.enum_tag_ty), .indirect);
+ return try cg.resolveType(.fromInterned(union_obj.enum_tag_type), .indirect);
}
var member_types: [4]Id = undefined;
@@ -1277,7 +1266,7 @@ fn resolveUnionType(cg: *CodeGen, ty: Type) !Id {
const u8_ty_id = try cg.resolveType(.u8, .direct);
if (layout.tag_size != 0) {
- const tag_ty_id = try cg.resolveType(.fromInterned(union_obj.enum_tag_ty), .indirect);
+ const tag_ty_id = try cg.resolveType(.fromInterned(union_obj.enum_tag_type), .indirect);
member_types[layout.tag_index] = tag_ty_id;
member_names[layout.tag_index] = "(tag)";
}
@@ -1318,7 +1307,7 @@ fn resolveUnionType(cg: *CodeGen, ty: Type) !Id {
fn resolveFnReturnType(cg: *CodeGen, ret_ty: Type) !Id {
const zcu = cg.module.zcu;
- if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!ret_ty.hasRuntimeBits(zcu)) {
// If the return type is an error set or an error union, then we make this
// anyerror return type instead, so that it can be coerced into a function
// pointer type which has anyerror as the return type.
@@ -1392,7 +1381,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
return cg.fail("array type of {} elements is too large", .{ty.arrayLenIncludingSentinel(zcu)});
};
- if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!elem_ty.hasRuntimeBits(zcu)) {
assert(repr == .indirect);
if (target.os.tag != .opencl) return cg.fail("cannot generate opaque type", .{});
return try cg.module.opaqueType("zero-sized-array");
@@ -1456,7 +1445,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
var param_index: usize = 0;
for (fn_info.param_types.get(ip)) |param_ty_index| {
const param_ty: Type = .fromInterned(param_ty_index);
- if (!param_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
+ if (!param_ty.hasRuntimeBits(zcu)) continue;
param_ty_ids[param_index] = try cg.resolveType(param_ty, .direct);
param_index += 1;
@@ -1521,7 +1510,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
};
if (struct_type.layout == .@"packed") {
- return try cg.resolveType(.fromInterned(struct_type.backingIntTypeUnordered(ip)), .direct);
+ return try cg.resolveType(.fromInterned(struct_type.packed_backing_int_type), .direct);
}
var member_types = std.array_list.Managed(Id).init(gpa);
@@ -1536,9 +1525,9 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
var it = struct_type.iterateRuntimeOrder(ip);
while (it.next()) |field_index| {
const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);
- if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
+ if (!field_ty.hasRuntimeBits(zcu)) continue;
- const field_name = struct_type.fieldName(ip, field_index);
+ const field_name = struct_type.field_names.get(ip)[field_index];
try member_types.append(try cg.resolveType(field_ty, .indirect));
try member_names.append(field_name.toSlice(ip));
try member_offsets.append(@intCast(ty.structFieldOffset(field_index, zcu)));
@@ -1559,7 +1548,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
},
.optional => {
const payload_ty = ty.optionalChild(zcu);
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!payload_ty.hasRuntimeBits(zcu)) {
// Just use a bool.
// Note: Always generate the bool with indirect format, to save on some sanity
// Perform the conversion to a direct bool when the field is extracted.
@@ -1656,7 +1645,7 @@ fn errorUnionLayout(cg: *CodeGen, payload_ty: Type) ErrorUnionLayout {
const error_first = error_align.compare(.gt, payload_align);
return .{
- .payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(zcu),
+ .payload_has_bits = payload_ty.hasRuntimeBits(zcu),
.error_first = error_first,
};
}
@@ -3727,7 +3716,6 @@ fn cmp(
const gpa = cg.module.gpa;
const pt = cg.pt;
const zcu = cg.module.zcu;
- const ip = &zcu.intern_pool;
const scalar_ty = lhs.ty.scalarType(zcu);
const is_vector = lhs.ty.isVector(zcu);
@@ -3740,7 +3728,7 @@ fn cmp(
},
.@"struct" => {
const struct_ty = zcu.typeToPackedStruct(scalar_ty).?;
- const ty: Type = .fromInterned(struct_ty.backingIntTypeUnordered(ip));
+ const ty: Type = .fromInterned(struct_ty.packed_backing_int_type);
return try cg.cmp(op, lhs.pun(ty), rhs.pun(ty));
},
.error_set => {
@@ -3781,7 +3769,7 @@ fn cmp(
const payload_ty = ty.optionalChild(zcu);
if (ty.optionalReprIsPayload(zcu)) {
- assert(payload_ty.hasRuntimeBitsIgnoreComptime(zcu));
+ assert(payload_ty.hasRuntimeBits(zcu));
assert(!payload_ty.isSlice(zcu));
return try cg.cmp(op, lhs.pun(payload_ty), rhs.pun(payload_ty));
@@ -3790,12 +3778,12 @@ fn cmp(
const lhs_id = try lhs.materialize(cg);
const rhs_id = try rhs.materialize(cg);
- const lhs_valid_id = if (payload_ty.hasRuntimeBitsIgnoreComptime(zcu))
+ const lhs_valid_id = if (payload_ty.hasRuntimeBits(zcu))
try cg.extractField(.bool, lhs_id, 1)
else
try cg.convertToDirect(.bool, lhs_id);
- const rhs_valid_id = if (payload_ty.hasRuntimeBitsIgnoreComptime(zcu))
+ const rhs_valid_id = if (payload_ty.hasRuntimeBits(zcu))
try cg.extractField(.bool, rhs_id, 1)
else
try cg.convertToDirect(.bool, rhs_id);
@@ -3803,7 +3791,7 @@ fn cmp(
const lhs_valid: Temporary = .init(.bool, lhs_valid_id);
const rhs_valid: Temporary = .init(.bool, rhs_valid_id);
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!payload_ty.hasRuntimeBits(zcu)) {
return try cg.cmp(op, lhs_valid, rhs_valid);
}
@@ -4141,7 +4129,7 @@ fn airArrayToSlice(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
const array_ptr_id = try cg.resolve(ty_op.operand);
const len_id = try cg.constInt(.usize, array_ty.arrayLen(zcu));
- const elem_ptr_id = if (!array_ty.hasRuntimeBitsIgnoreComptime(zcu))
+ const elem_ptr_id = if (!array_ty.hasRuntimeBits(zcu))
// Note: The pointer is something like *opaque{}, so we need to bitcast it to the element type.
try cg.bitCast(elem_ptr_ty, array_ptr_ty, array_ptr_id)
else
@@ -4177,12 +4165,12 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
.@"struct" => {
if (zcu.typeToPackedStruct(result_ty)) |struct_type| {
comptime assert(Type.packed_struct_layout_version == 2);
- const backing_int_ty: Type = .fromInterned(struct_type.backingIntTypeUnordered(ip));
+ const backing_int_ty: Type = .fromInterned(struct_type.packed_backing_int_type);
var running_int_id = try cg.constInt(backing_int_ty, 0);
var running_bits: u16 = 0;
for (struct_type.field_types.get(ip), elements) |field_ty_ip, element| {
const field_ty: Type = .fromInterned(field_ty_ip);
- if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
+ if (!field_ty.hasRuntimeBits(zcu)) continue;
const field_id = try cg.resolve(element);
const ty_bit_size: u16 = @intCast(field_ty.bitSize(zcu));
const field_int_ty = try cg.pt.intType(.unsigned, ty_bit_size);
@@ -4242,7 +4230,7 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
const field_index = it.next().?;
if ((try result_ty.structFieldValueComptime(pt, i)) != null) continue;
const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);
- assert(field_ty.hasRuntimeBitsIgnoreComptime(zcu));
+ assert(field_ty.hasRuntimeBits(zcu));
const id = try cg.resolve(element);
types[index] = field_ty;
@@ -4381,7 +4369,7 @@ fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
fn ptrElemPtr(cg: *CodeGen, ptr_ty: Type, ptr_id: Id, index_id: Id) !Id {
const zcu = cg.module.zcu;
// Construct new pointer type for the resulting pointer
- const elem_ty = ptr_ty.elemType2(zcu); // use elemType() so that we get T for *[N]T.
+ const elem_ty = ptr_ty.indexableElem(zcu);
const elem_ty_id = try cg.resolveType(elem_ty, .indirect);
const elem_ptr_ty_id = try cg.module.ptrType(elem_ty_id, cg.module.storageClass(ptr_ty.ptrAddressSpace(zcu)));
if (ptr_ty.isSinglePointer(zcu)) {
@@ -4402,10 +4390,7 @@ fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
const elem_ty = src_ptr_ty.childType(zcu);
const ptr_id = try cg.resolve(bin_op.lhs);
- if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
- const dst_ptr_ty = cg.typeOfIndex(inst);
- return try cg.bitCast(dst_ptr_ty, src_ptr_ty, ptr_id);
- }
+ assert(elem_ty.hasRuntimeBits(zcu));
const index_id = try cg.resolve(bin_op.rhs);
return try cg.ptrElemPtr(src_ptr_ty, ptr_id, index_id);
@@ -4483,7 +4468,7 @@ fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !void {
if (layout.tag_size == 0) return;
- const tag_ty = un_ty.unionTagTypeSafety(zcu).?;
+ const tag_ty = un_ty.unionTagTypeRuntime(zcu).?;
const tag_ty_id = try cg.resolveType(tag_ty, .indirect);
const tag_ptr_ty_id = try cg.module.ptrType(tag_ty_id, cg.module.storageClass(un_ptr_ty.ptrAddressSpace(zcu)));
@@ -4509,7 +4494,7 @@ fn airGetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
const union_handle = try cg.resolve(ty_op.operand);
if (!layout.has_payload) return union_handle;
- const tag_ty = un_ty.unionTagTypeSafety(zcu).?;
+ const tag_ty = un_ty.unionTagTypeRuntime(zcu).?;
return try cg.extractField(tag_ty, union_handle, layout.tag_index);
}
@@ -4529,39 +4514,16 @@ fn unionInit(
const zcu = cg.module.zcu;
const ip = &zcu.intern_pool;
const union_ty = zcu.typeToUnion(ty).?;
- const tag_ty: Type = .fromInterned(union_ty.enum_tag_ty);
+ const tag_ty: Type = .fromInterned(union_ty.enum_tag_type);
const layout = cg.unionLayout(ty);
const payload_ty: Type = .fromInterned(union_ty.field_types.get(ip)[active_field]);
- if (union_ty.flagsUnordered(ip).layout == .@"packed") {
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
- const int_ty = try pt.intType(.unsigned, @intCast(ty.bitSize(zcu)));
- return cg.constInt(int_ty, 0);
- }
-
- assert(payload != null);
- if (payload_ty.isInt(zcu)) {
- if (ty.bitSize(zcu) == payload_ty.bitSize(zcu)) {
- return cg.bitCast(ty, payload_ty, payload.?);
- }
-
- const trunc = try cg.buildConvert(ty, .{ .ty = payload_ty, .value = .{ .singleton = payload.? } });
- return try trunc.materialize(cg);
- }
-
- const payload_int_ty = try pt.intType(.unsigned, @intCast(payload_ty.bitSize(zcu)));
- const payload_int = if (payload_ty.ip_index == .bool_type)
- try cg.convertToIndirect(payload_ty, payload.?)
- else
- try cg.bitCast(payload_int_ty, payload_ty, payload.?);
- const trunc = try cg.buildConvert(ty, .{ .ty = payload_int_ty, .value = .{ .singleton = payload_int } });
- return try trunc.materialize(cg);
- }
+ assert(union_ty.layout != .@"packed");
const tag_int = if (layout.tag_size != 0) blk: {
const tag_val = try pt.enumValueFieldIndex(tag_ty, active_field);
- const tag_int_val = try tag_val.intFromEnum(tag_ty, pt);
+ const tag_int_val = tag_val.intFromEnum(zcu);
break :blk tag_int_val.toUnsignedInt(zcu);
} else 0;
@@ -4580,7 +4542,7 @@ fn unionInit(
try cg.store(tag_ty, ptr_id, tag_id, .{});
}
- if (payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (payload_ty.hasRuntimeBits(zcu)) {
const layout_payload_ty_id = try cg.resolveType(layout.payload_ty, .indirect);
const pl_ptr_ty_id = try cg.module.ptrType(layout_payload_ty_id, .function);
const pl_ptr_id = try cg.accessChain(pl_ptr_ty_id, tmp_id, &.{layout.payload_index});
@@ -4616,7 +4578,7 @@ fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
const union_obj = zcu.typeToUnion(ty).?;
const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[extra.field_index]);
- const payload = if (field_ty.hasRuntimeBitsIgnoreComptime(zcu))
+ const payload = if (field_ty.hasRuntimeBits(zcu))
try cg.resolve(extra.init)
else
null;
@@ -4634,7 +4596,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
const field_index = struct_field.field_index;
const field_ty = object_ty.fieldType(field_index, zcu);
- if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) return null;
+ assert(field_ty.hasRuntimeBits(zcu));
switch (object_ty.zigTypeTag(zcu)) {
.@"struct" => switch (object_ty.containerLayout(zcu)) {
@@ -4776,33 +4738,36 @@ fn structFieldPtr(
},
.@"struct" => switch (object_ty.containerLayout(zcu)) {
.@"packed" => return cg.todo("implement field access for packed structs", .{}),
- else => {
+ .auto, .@"extern" => {
return try cg.accessChain(result_ty_id, object_ptr, &.{field_index});
},
},
- .@"union" => {
- const layout = cg.unionLayout(object_ty);
- if (!layout.has_payload) {
- // Asked to get a pointer to a zero-sized field. Just lower this
- // to undefined, there is no reason to make it be a valid pointer.
- return try cg.module.constUndef(result_ty_id);
- }
+ .@"union" => switch (object_ty.containerLayout(zcu)) {
+ .@"packed" => return cg.todo("implement field access for packed unions", .{}),
+ .auto, .@"extern" => {
+ const layout = cg.unionLayout(object_ty);
+ if (!layout.has_payload) {
+ // Asked to get a pointer to a zero-sized field. Just lower this
+ // to undefined, there is no reason to make it be a valid pointer.
+ return try cg.module.constUndef(result_ty_id);
+ }
- const storage_class = cg.module.storageClass(object_ptr_ty.ptrAddressSpace(zcu));
- const layout_payload_ty_id = try cg.resolveType(layout.payload_ty, .indirect);
- const pl_ptr_ty_id = try cg.module.ptrType(layout_payload_ty_id, storage_class);
- const pl_ptr_id = blk: {
- if (object_ty.containerLayout(zcu) == .@"packed") break :blk object_ptr;
- break :blk try cg.accessChain(pl_ptr_ty_id, object_ptr, &.{layout.payload_index});
- };
+ const storage_class = cg.module.storageClass(object_ptr_ty.ptrAddressSpace(zcu));
+ const layout_payload_ty_id = try cg.resolveType(layout.payload_ty, .indirect);
+ const pl_ptr_ty_id = try cg.module.ptrType(layout_payload_ty_id, storage_class);
+ const pl_ptr_id = blk: {
+ if (object_ty.containerLayout(zcu) == .@"packed") break :blk object_ptr;
+ break :blk try cg.accessChain(pl_ptr_ty_id, object_ptr, &.{layout.payload_index});
+ };
- const active_pl_ptr_id = cg.module.allocId();
- try cg.body.emit(cg.module.gpa, .OpBitcast, .{
- .id_result_type = result_ty_id,
- .id_result = active_pl_ptr_id,
- .operand = pl_ptr_id,
- });
- return active_pl_ptr_id;
+ const active_pl_ptr_id = cg.module.allocId();
+ try cg.body.emit(cg.module.gpa, .OpBitcast, .{
+ .id_result_type = result_ty_id,
+ .id_result = active_pl_ptr_id,
+ .operand = pl_ptr_id,
+ });
+ return active_pl_ptr_id;
+ },
},
else => unreachable,
}
@@ -5028,7 +4993,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)
const gpa = cg.module.gpa;
const zcu = cg.module.zcu;
const ty = cg.typeOfIndex(inst);
- const have_block_result = ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu);
+ const have_block_result = ty.hasRuntimeBits(zcu);
const cf = switch (cg.control_flow) {
.structured => |*cf| cf,
@@ -5166,7 +5131,7 @@ fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
switch (cg.control_flow) {
.structured => |*cf| {
- if (operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {
+ if (operand_ty.hasRuntimeBits(zcu)) {
const operand_id = try cg.resolve(br.operand);
const block_result_var_id = cf.block_results.get(br.block_inst).?;
try cg.store(operand_ty, block_result_var_id, operand_id, .{});
@@ -5177,7 +5142,7 @@ fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
},
.unstructured => |cf| {
const block = cf.blocks.get(br.block_inst).?;
- if (operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {
+ if (operand_ty.hasRuntimeBits(zcu)) {
const operand_id = try cg.resolve(br.operand);
// block_label should not be undefined here, lest there
// is a br or br_void in the function's body.
@@ -5335,7 +5300,7 @@ fn airRet(cg: *CodeGen, inst: Air.Inst.Index) !void {
const zcu = cg.module.zcu;
const operand = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const ret_ty = cg.typeOf(operand);
- if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!ret_ty.hasRuntimeBits(zcu)) {
const fn_info = zcu.typeToFunc(zcu.navValue(cg.owner_nav).typeOf(zcu)).?;
if (Type.fromInterned(fn_info.return_type).isError(zcu)) {
// Functions with an empty error set are emitted with an error code
@@ -5359,7 +5324,7 @@ fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) !void {
const ptr_ty = cg.typeOf(un_op);
const ret_ty = ptr_ty.childType(zcu);
- if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!ret_ty.hasRuntimeBits(zcu)) {
const fn_info = zcu.typeToFunc(zcu.navValue(cg.owner_nav).typeOf(zcu)).?;
if (Type.fromInterned(fn_info.return_type).isError(zcu)) {
// Functions with an empty error set are emitted with an error code
@@ -5576,7 +5541,7 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum {
const is_non_null_id = blk: {
if (is_pointer) {
- if (payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (payload_ty.hasRuntimeBits(zcu)) {
const storage_class = cg.module.storageClass(operand_ty.ptrAddressSpace(zcu));
const bool_indirect_ty_id = try cg.resolveType(.bool, .indirect);
const bool_ptr_ty_id = try cg.module.ptrType(bool_indirect_ty_id, storage_class);
@@ -5587,7 +5552,7 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum {
break :blk try cg.load(.bool, operand_id, .{});
}
- break :blk if (payload_ty.hasRuntimeBitsIgnoreComptime(zcu))
+ break :blk if (payload_ty.hasRuntimeBits(zcu))
try cg.extractField(.bool, operand_id, 1)
else
// Optional representation is bool indicating whether the optional is set
@@ -5656,7 +5621,7 @@ fn airUnwrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
const optional_ty = cg.typeOf(ty_op.operand);
const payload_ty = cg.typeOfIndex(inst);
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) return null;
+ if (!payload_ty.hasRuntimeBits(zcu)) return null;
if (optional_ty.optionalReprIsPayload(zcu)) {
return operand_id;
@@ -5675,7 +5640,7 @@ fn airUnwrapOptionalPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
const result_ty = cg.typeOfIndex(inst);
const result_ty_id = try cg.resolveType(result_ty, .direct);
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!payload_ty.hasRuntimeBits(zcu)) {
// There is no payload, but we still need to return a valid pointer.
// We can just return anything here, so just return a pointer to the operand.
return try cg.bitCast(result_ty, operand_ty, operand_id);
@@ -5694,9 +5659,7 @@ fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
const payload_ty = cg.typeOf(ty_op.operand);
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
- return try cg.constBool(true, .indirect);
- }
+ assert(payload_ty.hasRuntimeBits(zcu));
const operand_id = try cg.resolve(ty_op.operand);
@@ -5792,8 +5755,7 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
const int_val: u64 = switch (cond_ty.zigTypeTag(zcu)) {
.bool, .int => if (cond_ty.isSignedInt(zcu)) @bitCast(value.toSignedInt(zcu)) else value.toUnsignedInt(zcu),
.@"enum" => blk: {
- // TODO: figure out of cond_ty is correct (something with enum literals)
- break :blk (try value.intFromEnum(cond_ty, pt)).toUnsignedInt(zcu); // TODO: composite integer constants
+ break :blk value.intFromEnum(zcu).toUnsignedInt(zcu); // TODO: composite integer constants
},
.error_set => value.getErrorInt(zcu),
.pointer => value.toUnsignedInt(zcu),
@@ -6070,7 +6032,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie
// before starting to emit OpFunctionCall instructions. Hence the
// temporary params buffer.
const arg_ty = cg.typeOf(arg);
- if (!arg_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
+ if (!arg_ty.hasRuntimeBits(zcu)) continue;
const arg_id = try cg.resolve(arg);
params[n_params] = arg_id;
@@ -6084,7 +6046,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie
.id_ref_3 = params[0..n_params],
});
- if (cg.liveness.isUnused(inst) or !Type.fromInterned(return_type).hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (cg.liveness.isUnused(inst) or !Type.fromInterned(return_type).hasRuntimeBits(zcu)) {
return null;
}
diff --git a/src/codegen/wasm/CodeGen.zig b/src/codegen/wasm/CodeGen.zig
index 90de3461cacbfdb90b07a3f2898598ed27be9ac7..a8f374772e3e042f0bd32a3eb29c5cd39141092d 100644
--- a/src/codegen/wasm/CodeGen.zig
+++ b/src/codegen/wasm/CodeGen.zig
@@ -759,7 +759,7 @@ fn resolveInst(cg: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue {
const zcu = pt.zcu;
const val = (try cg.air.value(ref, pt)).?;
const ty = cg.typeOf(ref);
- if (!ty.hasRuntimeBitsIgnoreComptime(zcu) and !ty.isInt(zcu) and !ty.isError(zcu)) {
+ if (!ty.hasRuntimeBits(zcu) and !ty.isInt(zcu) and !ty.isError(zcu)) {
gop.value_ptr.* = .none;
return .none;
}
@@ -773,7 +773,7 @@ fn resolveInst(cg: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue {
const result: WValue = if (isByRef(ty, zcu, cg.target))
.{ .uav_ref = .{ .ip_index = val.toIntern() } }
else
- try cg.lowerConstant(val, ty);
+ try cg.lowerConstant(val);
gop.value_ptr.* = result;
return result;
@@ -786,7 +786,7 @@ fn resolveValue(cg: *CodeGen, val: Value) InnerError!WValue {
return if (isByRef(ty, zcu, cg.target))
.{ .uav_ref = .{ .ip_index = val.toIntern() } }
else
- try cg.lowerConstant(val, ty);
+ try cg.lowerConstant(val);
}
/// NOTE: if result == .stack, it will be stored in .local
@@ -980,7 +980,6 @@ fn addExtraAssumeCapacity(cg: *CodeGen, extra: anytype) error{OutOfMemory}!u32 {
/// For `std.builtin.CallingConvention.auto`.
pub fn typeToValtype(ty: Type, zcu: *const Zcu, target: *const std.Target) std.wasm.Valtype {
- const ip = &zcu.intern_pool;
return switch (ty.zigTypeTag(zcu)) {
.float => switch (ty.floatBits(target)) {
16 => .i32, // stored/loaded as u16
@@ -994,25 +993,13 @@ pub fn typeToValtype(ty: Type, zcu: *const Zcu, target: *const std.Target) std.w
33...64 => .i64,
else => .i32,
},
- .@"struct" => blk: {
- if (zcu.typeToPackedStruct(ty)) |packed_struct| {
- const backing_int_ty = Type.fromInterned(packed_struct.backingIntTypeUnordered(ip));
- break :blk typeToValtype(backing_int_ty, zcu, target);
- } else {
- break :blk .i32;
- }
- },
.vector => switch (CodeGen.determineSimdStoreStrategy(ty, zcu, target)) {
.direct => .v128,
.unrolled => .i32,
},
- .@"union" => switch (ty.containerLayout(zcu)) {
- .@"packed" => switch (ty.bitSize(zcu)) {
- 0...32 => .i32,
- 33...64 => .i64,
- else => .i32,
- },
- else => .i32,
+ .@"union", .@"struct" => switch (ty.containerLayout(zcu)) {
+ .@"packed" => typeToValtype(ty.bitpackBackingInt(zcu), zcu, target),
+ .auto, .@"extern" => .i32,
},
else => .i32, // all represented as reference/immediate
};
@@ -1185,7 +1172,7 @@ pub fn generate(
const fn_ty = zcu.navValue(cg.owner_nav).typeOf(zcu);
const fn_info = zcu.typeToFunc(fn_ty).?;
const ret_ty: Type = .fromInterned(fn_info.return_type);
- const any_returns = !firstParamSRet(fn_info.cc, ret_ty, zcu, target) and ret_ty.hasRuntimeBitsIgnoreComptime(zcu);
+ const any_returns = !firstParamSRet(fn_info.cc, ret_ty, zcu, target) and ret_ty.hasRuntimeBits(zcu);
var cc_result = try resolveCallingConventionValues(zcu, fn_ty, target);
defer cc_result.deinit(gpa);
@@ -1244,7 +1231,7 @@ fn generateInner(cg: *CodeGen, any_returns: bool) InnerError!Mir {
if (any_returns and cg.air.instructions.len > 0) {
const inst: Air.Inst.Index = @enumFromInt(cg.air.instructions.len - 1);
const last_inst_ty = cg.typeOfIndex(inst);
- if (!last_inst_ty.hasRuntimeBitsIgnoreComptime(zcu) or last_inst_ty.isNoReturn(zcu)) {
+ if (!last_inst_ty.hasRuntimeBits(zcu)) {
try cg.addTag(.@"unreachable");
}
}
@@ -1316,7 +1303,7 @@ fn resolveCallingConventionValues(
switch (cc) {
.auto => {
for (fn_info.param_types.get(ip)) |ty| {
- if (!Type.fromInterned(ty).hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!Type.fromInterned(ty).hasRuntimeBits(zcu)) {
continue;
}
@@ -1326,7 +1313,7 @@ fn resolveCallingConventionValues(
},
.wasm_mvp => {
for (fn_info.param_types.get(ip)) |ty| {
- if (!Type.fromInterned(ty).hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!Type.fromInterned(ty).hasRuntimeBits(zcu)) {
continue;
}
switch (abi.classifyType(.fromInterned(ty), zcu)) {
@@ -1357,7 +1344,7 @@ pub fn firstParamSRet(
zcu: *const Zcu,
target: *const std.Target,
) bool {
- if (!return_type.hasRuntimeBitsIgnoreComptime(zcu)) return false;
+ if (!return_type.hasRuntimeBits(zcu)) return false;
switch (cc) {
.@"inline" => unreachable,
.auto => return isByRef(return_type, zcu, target),
@@ -1457,7 +1444,7 @@ fn restoreStackPointer(cg: *CodeGen) !void {
fn allocStack(cg: *CodeGen, ty: Type) !WValue {
const pt = cg.pt;
const zcu = pt.zcu;
- assert(ty.hasRuntimeBitsIgnoreComptime(zcu));
+ assert(ty.hasRuntimeBits(zcu));
if (cg.initial_stack_value == .none) {
try cg.initializeStack();
}
@@ -1491,7 +1478,7 @@ fn allocStackPtr(cg: *CodeGen, inst: Air.Inst.Index) !WValue {
try cg.initializeStack();
}
- if (!pointee_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!pointee_ty.hasRuntimeBits(zcu)) {
return cg.allocStack(Type.usize); // create a value containing just the stack pointer.
}
@@ -1676,7 +1663,6 @@ fn ptrSize(cg: *const CodeGen) u16 {
/// For a given `Type`, will return true when the type will be passed
/// by reference, rather than by value
fn isByRef(ty: Type, zcu: *const Zcu, target: *const std.Target) bool {
- const ip = &zcu.intern_pool;
switch (ty.zigTypeTag(zcu)) {
.type,
.comptime_int,
@@ -1697,20 +1683,10 @@ fn isByRef(ty: Type, zcu: *const Zcu, target: *const std.Target) bool {
.array,
.frame,
- => return ty.hasRuntimeBitsIgnoreComptime(zcu),
- .@"union" => {
- if (zcu.typeToUnion(ty)) |union_obj| {
- if (union_obj.flagsUnordered(ip).layout == .@"packed") {
- return ty.abiSize(zcu) > 8;
- }
- }
- return ty.hasRuntimeBitsIgnoreComptime(zcu);
- },
- .@"struct" => {
- if (zcu.typeToPackedStruct(ty)) |packed_struct| {
- return isByRef(Type.fromInterned(packed_struct.backingIntTypeUnordered(ip)), zcu, target);
- }
- return ty.hasRuntimeBitsIgnoreComptime(zcu);
+ => return ty.hasRuntimeBits(zcu),
+ .@"struct", .@"union" => switch (ty.containerLayout(zcu)) {
+ .@"packed" => return isByRef(ty.bitpackBackingInt(zcu), zcu, target),
+ .@"extern", .auto => return ty.hasRuntimeBits(zcu),
},
.vector => return determineSimdStoreStrategy(ty, zcu, target) == .unrolled,
.int => return ty.intInfo(zcu).bits > 64,
@@ -1718,7 +1694,7 @@ fn isByRef(ty: Type, zcu: *const Zcu, target: *const std.Target) bool {
.float => return ty.floatBits(target) > 64,
.error_union => {
const pl_ty = ty.errorUnionPayload(zcu);
- if (!pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!pl_ty.hasRuntimeBits(zcu)) {
return false;
}
return true;
@@ -1727,7 +1703,7 @@ fn isByRef(ty: Type, zcu: *const Zcu, target: *const std.Target) bool {
if (ty.isPtrLikeOptional(zcu)) return false;
const pl_type = ty.optionalChild(zcu);
if (pl_type.zigTypeTag(zcu) == .error_set) return false;
- return pl_type.hasRuntimeBitsIgnoreComptime(zcu);
+ return pl_type.hasRuntimeBits(zcu);
},
.pointer => {
// Slices act like struct and will be passed by reference
@@ -2069,7 +2045,7 @@ fn airRet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
// to the stack instead
if (cg.return_value != .none) {
try cg.store(cg.return_value, operand, ret_ty, 0);
- } else if (fn_info.cc == .wasm_mvp and ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ } else if (fn_info.cc == .wasm_mvp and ret_ty.hasRuntimeBits(zcu)) {
switch (abi.classifyType(ret_ty, zcu)) {
.direct => |scalar_type| {
assert(!abi.lowerAsDoubleI64(scalar_type, zcu));
@@ -2082,7 +2058,7 @@ fn airRet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
.indirect => unreachable,
}
} else {
- if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu) and ret_ty.isError(zcu)) {
+ if (!ret_ty.hasRuntimeBits(zcu) and ret_ty.isError(zcu)) {
try cg.addImm32(0);
} else {
try cg.emitWValue(operand);
@@ -2099,7 +2075,7 @@ fn airRetPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
const child_type = cg.typeOfIndex(inst).childType(zcu);
const result = result: {
- if (!child_type.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!child_type.hasRuntimeBits(zcu)) {
break :result try cg.allocStack(Type.usize); // create pointer to void
}
@@ -2121,7 +2097,7 @@ fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
const ret_ty = cg.typeOf(un_op).childType(zcu);
const fn_info = zcu.typeToFunc(zcu.navValue(cg.owner_nav).typeOf(zcu)).?;
- if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!ret_ty.hasRuntimeBits(zcu)) {
if (ret_ty.isError(zcu)) {
try cg.addImm32(0);
}
@@ -2177,7 +2153,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie
const arg_val = try cg.resolveInst(arg);
const arg_ty = cg.typeOf(arg);
- if (!arg_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
+ if (!arg_ty.hasRuntimeBits(zcu)) continue;
try cg.lowerArg(zcu.typeToFunc(fn_ty).?.cc, arg_ty, arg_val);
}
@@ -2199,10 +2175,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie
}
const result_value = result_value: {
- if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu) and !ret_ty.isError(zcu)) {
- break :result_value .none;
- } else if (ret_ty.isNoReturn(zcu)) {
- try cg.addTag(.@"unreachable");
+ if (!ret_ty.hasRuntimeBits(zcu) and !ret_ty.isError(zcu)) {
break :result_value .none;
} else if (first_param_sret) {
break :result_value sret;
@@ -2323,12 +2296,12 @@ fn store(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErr
const zcu = pt.zcu;
const abi_size = ty.abiSize(zcu);
- if (!ty.hasRuntimeBitsIgnoreComptime(zcu)) return;
+ if (!ty.hasRuntimeBits(zcu)) return;
switch (ty.zigTypeTag(zcu)) {
.error_union => {
const pl_ty = ty.errorUnionPayload(zcu);
- if (!pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!pl_ty.hasRuntimeBits(zcu)) {
return cg.store(lhs, rhs, Type.anyerror, offset);
}
@@ -2341,7 +2314,7 @@ fn store(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErr
return cg.store(lhs, rhs, Type.usize, offset);
}
const pl_ty = ty.optionalChild(zcu);
- if (!pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!pl_ty.hasRuntimeBits(zcu)) {
return cg.store(lhs, rhs, Type.u8, offset);
}
if (pl_ty.zigTypeTag(zcu) == .error_set) {
@@ -2441,7 +2414,7 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
const ptr_ty = cg.typeOf(ty_op.operand);
const ptr_info = ptr_ty.ptrInfo(zcu);
- if (!ty.hasRuntimeBitsIgnoreComptime(zcu)) return cg.finishAir(inst, .none, &.{ty_op.operand});
+ if (!ty.hasRuntimeBits(zcu)) return cg.finishAir(inst, .none, &.{ty_op.operand});
const result = result: {
if (isByRef(ty, zcu, cg.target)) {
@@ -3092,7 +3065,7 @@ fn lowerPtr(cg: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerErro
return switch (ptr.base_addr) {
.nav => |nav| return .{ .nav_ref = .{ .nav_index = nav, .offset = @intCast(offset) } },
.uav => |uav| return .{ .uav_ref = .{ .ip_index = uav.val, .offset = @intCast(offset), .orig_ptr_ty = uav.orig_ty } },
- .int => return cg.lowerConstant(try pt.intValue(Type.usize, offset), Type.usize),
+ .int => return cg.lowerConstant(try pt.intValue(.usize, offset)),
.eu_payload => |eu_ptr| try cg.lowerPtr(
eu_ptr,
offset + codegen.errUnionPayloadOffset(
@@ -3129,10 +3102,11 @@ fn lowerPtr(cg: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerErro
};
}
-/// Asserts that `isByRef` returns `false` for `ty`.
-fn lowerConstant(cg: *CodeGen, val: Value, ty: Type) InnerError!WValue {
+/// Asserts that `isByRef` returns `false` for `val.typeOf(zcu)`.
+fn lowerConstant(cg: *CodeGen, val: Value) InnerError!WValue {
const pt = cg.pt;
const zcu = pt.zcu;
+ const ty = val.typeOf(zcu);
assert(!isByRef(ty, zcu, cg.target));
const ip = &zcu.intern_pool;
if (val.isUndef(zcu)) return cg.emitUndefined(ty);
@@ -3158,10 +3132,8 @@ fn lowerConstant(cg: *CodeGen, val: Value, ty: Type) InnerError!WValue {
.undef => unreachable, // handled above
.simple_value => |simple_value| switch (simple_value) {
- .undefined,
.void,
.null,
- .empty_tuple,
.@"unreachable",
=> unreachable, // non-runtime values
.false, .true => return .{ .imm32 = switch (simple_value) {
@@ -3174,7 +3146,6 @@ fn lowerConstant(cg: *CodeGen, val: Value, ty: Type) InnerError!WValue {
.@"extern",
.func,
.enum_literal,
- .empty_enum_value,
=> unreachable, // non-runtime values
.int => {
const int_info = ty.intInfo(zcu);
@@ -3197,31 +3168,22 @@ fn lowerConstant(cg: *CodeGen, val: Value, ty: Type) InnerError!WValue {
},
.error_union => |error_union| {
const err_int_ty = try pt.errorIntType();
- const err_ty, const err_val = switch (error_union.val) {
- .err_name => |err_name| .{
- ty.errorUnionSet(zcu),
- Value.fromInterned(try pt.intern(.{ .err = .{
- .ty = ty.errorUnionSet(zcu).toIntern(),
- .name = err_name,
- } })),
- },
- .payload => .{
- err_int_ty,
- try pt.intValue(err_int_ty, 0),
- },
+ const err_val: Value = switch (error_union.val) {
+ .err_name => |err_name| .fromInterned(try pt.intern(.{ .err = .{
+ .ty = ty.errorUnionSet(zcu).toIntern(),
+ .name = err_name,
+ } })),
+ .payload => try pt.intValue(err_int_ty, 0),
};
const payload_type = ty.errorUnionPayload(zcu);
- if (!payload_type.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!payload_type.hasRuntimeBits(zcu)) {
// We use the error type directly as the type.
- return cg.lowerConstant(err_val, err_ty);
+ return cg.lowerConstant(err_val);
}
return cg.fail("Wasm TODO: lowerConstant error union with non-zero-bit payload type", .{});
},
- .enum_tag => |enum_tag| {
- const int_tag_ty = ip.typeOf(enum_tag.int);
- return cg.lowerConstant(Value.fromInterned(enum_tag.int), Type.fromInterned(int_tag_ty));
- },
+ .enum_tag => |enum_tag| return cg.lowerConstant(.fromInterned(enum_tag.int)),
.float => |float| switch (float.storage) {
.f16 => |f16_val| return .{ .imm32 = @as(u16, @bitCast(f16_val)) },
.f32 => |f32_val| return .{ .float32 = f32_val },
@@ -3231,9 +3193,8 @@ fn lowerConstant(cg: *CodeGen, val: Value, ty: Type) InnerError!WValue {
.slice => unreachable, // isByRef == true
.ptr => return cg.lowerPtr(val.toIntern(), 0),
.opt => if (ty.optionalReprIsPayload(zcu)) {
- const pl_ty = ty.optionalChild(zcu);
if (val.optionalValue(zcu)) |payload| {
- return cg.lowerConstant(payload, pl_ty);
+ return cg.lowerConstant(payload);
} else {
return .{ .imm32 = 0 };
}
@@ -3248,33 +3209,11 @@ fn lowerConstant(cg: *CodeGen, val: Value, ty: Type) InnerError!WValue {
val.writeToMemory(pt, &buf) catch unreachable;
return cg.storeSimdImmd(buf);
},
- .struct_type => {
- const struct_type = ip.loadStructType(ty.toIntern());
- // non-packed structs are not handled in this function because they
- // are by-ref types.
- assert(struct_type.layout == .@"packed");
- var buf: [8]u8 = .{0} ** 8; // zero the buffer so we do not read 0xaa as integer
- val.writeToPackedMemory(ty, pt, &buf, 0) catch unreachable;
- const backing_int_ty = Type.fromInterned(struct_type.backingIntTypeUnordered(ip));
- const int_val = try pt.intValue(
- backing_int_ty,
- mem.readInt(u64, &buf, .little),
- );
- return cg.lowerConstant(int_val, backing_int_ty);
- },
+ .struct_type => unreachable, // packed structs use `bitpack`
else => unreachable,
},
- .un => {
- const int_type = try pt.intType(.unsigned, @intCast(ty.bitSize(zcu)));
-
- var buf: [8]u8 = .{0} ** 8; // zero the buffer so we do not read 0xaa as integer
- val.writeToPackedMemory(ty, pt, &buf, 0) catch unreachable;
- const int_val = try pt.intValue(
- int_type,
- mem.readInt(u64, &buf, .little),
- );
- return cg.lowerConstant(int_val, int_type);
- },
+ .un => unreachable, // packed unions use `bitpack`
+ .bitpack => |bitpack| return cg.lowerConstant(.fromInterned(bitpack.backing_int_val)),
.memoized_call => unreachable,
}
}
@@ -3289,7 +3228,6 @@ fn storeSimdImmd(cg: *CodeGen, value: [16]u8) !WValue {
fn emitUndefined(cg: *CodeGen, ty: Type) InnerError!WValue {
const zcu = cg.pt.zcu;
- const ip = &zcu.intern_pool;
switch (ty.zigTypeTag(zcu)) {
.bool, .error_set => return .{ .imm32 = 0xaaaaaaaa },
.int, .@"enum" => switch (ty.intInfo(zcu).bits) {
@@ -3317,17 +3255,9 @@ fn emitUndefined(cg: *CodeGen, ty: Type) InnerError!WValue {
.error_union => {
return .{ .imm32 = 0xaaaaaaaa };
},
- .@"struct" => {
- const packed_struct = zcu.typeToPackedStruct(ty).?;
- return cg.emitUndefined(Type.fromInterned(packed_struct.backingIntTypeUnordered(ip)));
- },
- .@"union" => switch (ty.containerLayout(zcu)) {
- .@"packed" => switch (ty.bitSize(zcu)) {
- 0...32 => return .{ .imm32 = 0xaaaaaaaa },
- 33...64 => return .{ .imm64 = 0xaaaaaaaaaaaaaaaa },
- else => unreachable,
- },
- else => unreachable,
+ .@"struct", .@"union" => {
+ const backing_int_ty = ty.bitpackBackingInt(zcu);
+ return cg.emitUndefined(backing_int_ty);
},
else => return cg.fail("Wasm TODO: emitUndefined for type: {t}\n", .{ty.zigTypeTag(zcu)}),
}
@@ -3341,7 +3271,7 @@ fn airBlock(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, block_ty: Type, body: []const Air.Inst.Index) InnerError!void {
const zcu = cg.pt.zcu;
// if wasm_block_ty is non-empty, we create a register to store the temporary value
- const block_result: WValue = if (block_ty.hasRuntimeBitsIgnoreComptime(zcu))
+ const block_result: WValue = if (block_ty.hasRuntimeBits(zcu))
try cg.allocLocal(block_ty)
else
.none;
@@ -3455,7 +3385,7 @@ fn cmp(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOpe
const zcu = cg.pt.zcu;
if (ty.zigTypeTag(zcu) == .optional and !ty.optionalReprIsPayload(zcu)) {
const payload_ty = ty.optionalChild(zcu);
- if (payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (payload_ty.hasRuntimeBits(zcu)) {
// When we hit this case, we must check the value of optionals
// that are not pointers. This means first checking against non-null for
// both lhs and rhs, as well as checking the payload are matching of lhs and rhs
@@ -3798,7 +3728,6 @@ fn structFieldPtr(
fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
const pt = cg.pt;
const zcu = pt.zcu;
- const ip = &zcu.intern_pool;
const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const struct_field = cg.air.extraData(Air.StructField, ty_pl.payload).data;
@@ -3806,14 +3735,14 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
const operand = try cg.resolveInst(struct_field.struct_operand);
const field_index = struct_field.field_index;
const field_ty = struct_ty.fieldType(field_index, zcu);
- if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) return cg.finishAir(inst, .none, &.{struct_field.struct_operand});
+ if (!field_ty.hasRuntimeBits(zcu)) return cg.finishAir(inst, .none, &.{struct_field.struct_operand});
const result: WValue = switch (struct_ty.containerLayout(zcu)) {
.@"packed" => switch (struct_ty.zigTypeTag(zcu)) {
.@"struct" => result: {
const packed_struct = zcu.typeToPackedStruct(struct_ty).?;
const offset = zcu.structPackedFieldBitOffset(packed_struct, field_index);
- const backing_ty = Type.fromInterned(packed_struct.backingIntTypeUnordered(ip));
+ const backing_ty = Type.fromInterned(packed_struct.packed_backing_int_type);
const host_bits = backing_ty.intInfo(zcu).bits;
const const_wvalue: WValue = if (33 <= host_bits and host_bits <= 64)
@@ -3891,7 +3820,7 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner
const switch_br = cg.air.unwrapSwitch(inst);
const target_ty = cg.typeOf(switch_br.operand);
- assert(target_ty.hasRuntimeBitsIgnoreComptime(zcu));
+ assert(target_ty.hasRuntimeBits(zcu));
// swap target value with placeholder local, for dispatching
const target = if (is_dispatch_loop) target: {
@@ -4125,7 +4054,7 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode, op_kind
}
try cg.emitWValue(operand);
- if (op_kind == .ptr or pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (op_kind == .ptr or pl_ty.hasRuntimeBits(zcu)) {
try cg.addMemArg(.i32_load16_u, .{
.offset = operand.offset() + @as(u32, @intCast(errUnionErrorOffset(pl_ty, zcu))),
.alignment = @intCast(Type.anyerror.abiAlignment(zcu).toByteUnits().?),
@@ -4152,7 +4081,7 @@ fn airUnwrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool)
const payload_ty = eu_ty.errorUnionPayload(zcu);
const result: WValue = result: {
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!payload_ty.hasRuntimeBits(zcu)) {
if (op_is_ptr) {
break :result cg.reuseOperand(ty_op.operand, operand);
} else {
@@ -4172,7 +4101,7 @@ fn airUnwrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool)
}
/// E!T -> E op_is_ptr == false
-/// *(E!T) -> E op_is_prt == true
+/// *(E!T) -> E op_is_ptr == true
/// NOTE: op_is_ptr will not change return type
fn airUnwrapErrUnionError(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!void {
const zcu = cg.pt.zcu;
@@ -4192,7 +4121,7 @@ fn airUnwrapErrUnionError(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) I
if (op_is_ptr or isByRef(eu_ty, zcu, cg.target)) {
break :result try cg.load(operand, Type.anyerror, err_offset);
} else {
- assert(!payload_ty.hasRuntimeBitsIgnoreComptime(zcu));
+ assert(!payload_ty.hasRuntimeBits(zcu));
break :result cg.reuseOperand(ty_op.operand, operand);
}
};
@@ -4208,7 +4137,7 @@ fn airWrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
const pl_ty = cg.typeOf(ty_op.operand);
const result = result: {
- if (!pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!pl_ty.hasRuntimeBits(zcu)) {
break :result cg.reuseOperand(ty_op.operand, operand);
}
@@ -4238,7 +4167,7 @@ fn airWrapErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
const pl_ty = err_ty.errorUnionPayload(zcu);
const result = result: {
- if (!pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!pl_ty.hasRuntimeBits(zcu)) {
break :result cg.reuseOperand(ty_op.operand, operand);
}
@@ -4354,7 +4283,7 @@ fn isNull(cg: *CodeGen, operand: WValue, optional_ty: Type, opcode: std.wasm.Opc
if (!optional_ty.optionalReprIsPayload(zcu)) {
// When payload is zero-bits, we can treat operand as a value, rather than
// a pointer to the stack value
- if (payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (payload_ty.hasRuntimeBits(zcu)) {
const offset = std.math.cast(u32, payload_ty.abiSize(zcu)) orelse {
return cg.fail("Optional type {f} too big to fit into stack frame", .{optional_ty.fmt(pt)});
};
@@ -4379,7 +4308,7 @@ fn airOptionalPayload(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
const opt_ty = cg.typeOf(ty_op.operand);
const payload_ty = cg.typeOfIndex(inst);
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!payload_ty.hasRuntimeBits(zcu)) {
return cg.finishAir(inst, .none, &.{ty_op.operand});
}
@@ -4404,7 +4333,7 @@ fn airOptionalPayloadPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
const result = result: {
const payload_ty = opt_ty.optionalChild(zcu);
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu) or opt_ty.optionalReprIsPayload(zcu)) {
+ if (!payload_ty.hasRuntimeBits(zcu) or opt_ty.optionalReprIsPayload(zcu)) {
break :result cg.reuseOperand(ty_op.operand, operand);
}
@@ -4444,7 +4373,7 @@ fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
const zcu = pt.zcu;
const result = result: {
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!payload_ty.hasRuntimeBits(zcu)) {
const non_null_bit = try cg.allocStack(Type.u1);
try cg.emitWValue(non_null_bit);
try cg.addImm32(1);
@@ -4612,7 +4541,7 @@ fn airArrayToSlice(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
const slice_local = try cg.allocStack(slice_ty);
// store the array ptr in the slice
- if (array_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (array_ty.hasRuntimeBits(zcu)) {
try cg.store(slice_local, operand, Type.usize, 0);
}
@@ -5111,7 +5040,7 @@ fn airShuffleOne(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
try cg.emitWValue(dest_alloc);
const elem_val = switch (mask_elem.unwrap()) {
.elem => |idx| try cg.load(operand, elem_ty, @intCast(elem_size * idx)),
- .value => |val| try cg.lowerConstant(.fromInterned(val), elem_ty),
+ .value => |val| try cg.lowerConstant(.fromInterned(val)),
};
try cg.store(.stack, elem_val, elem_ty, @intCast(dest_alloc.offset() + elem_size * out_idx));
}
@@ -5252,7 +5181,7 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
}
const packed_struct = zcu.typeToPackedStruct(result_ty).?;
const field_types = packed_struct.field_types;
- const backing_type = Type.fromInterned(packed_struct.backingIntTypeUnordered(ip));
+ const backing_type = Type.fromInterned(packed_struct.packed_backing_int_type);
// ensure the result is zero'd
const result = try cg.allocLocal(backing_type);
@@ -5265,7 +5194,7 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
var current_bit: u16 = 0;
for (elements, 0..) |elem, elem_index| {
const field_ty = Type.fromInterned(field_types.get(ip)[elem_index]);
- if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
+ if (!field_ty.hasRuntimeBits(zcu)) continue;
const shift_val: WValue = if (backing_type.bitSize(zcu) <= 32)
.{ .imm32 = current_bit }
@@ -5338,13 +5267,13 @@ fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
const layout = union_ty.unionGetLayout(zcu);
const union_obj = zcu.typeToUnion(union_ty).?;
const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[extra.field_index]);
- const field_name = union_obj.loadTagType(ip).names.get(ip)[extra.field_index];
+ const field_name = ip.loadEnumType(union_obj.enum_tag_type).field_names.get(ip)[extra.field_index];
const tag_int = blk: {
const tag_ty = union_ty.unionTagTypeHypothetical(zcu);
const enum_field_index = tag_ty.enumFieldIndex(field_name, zcu).?;
const tag_val = try pt.enumValueFieldIndex(tag_ty, enum_field_index);
- break :blk try cg.lowerConstant(tag_val, tag_ty);
+ break :blk try cg.lowerConstant(tag_val);
};
if (layout.payload_size == 0) {
if (layout.tag_size == 0) {
@@ -5366,7 +5295,7 @@ fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
}
if (layout.tag_size > 0) {
- try cg.store(result_ptr, tag_int, Type.fromInterned(union_obj.enum_tag_ty), 0);
+ try cg.store(result_ptr, tag_int, .fromInterned(union_obj.enum_tag_type), 0);
}
} else {
try cg.store(result_ptr, payload, field_ty, 0);
@@ -5374,7 +5303,7 @@ fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
try cg.store(
result_ptr,
tag_int,
- Type.fromInterned(union_obj.enum_tag_ty),
+ .fromInterned(union_obj.enum_tag_type),
@intCast(layout.payload_size),
);
}
@@ -5421,7 +5350,7 @@ fn airWasmMemoryGrow(cg: *CodeGen, inst: Air.Inst.Index) !void {
fn cmpOptionals(cg: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {
const zcu = cg.pt.zcu;
- assert(operand_ty.hasRuntimeBitsIgnoreComptime(zcu));
+ assert(operand_ty.hasRuntimeBits(zcu));
assert(op == .eq or op == .neq);
const payload_ty = operand_ty.optionalChild(zcu);
assert(!isByRef(payload_ty, zcu, cg.target));
@@ -5675,7 +5604,7 @@ fn airErrUnionPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void
);
const result = result: {
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!payload_ty.hasRuntimeBits(zcu)) {
break :result cg.reuseOperand(ty_op.operand, operand);
}
@@ -6464,7 +6393,7 @@ fn lowerTry(
const zcu = cg.pt.zcu;
const pl_ty = err_union_ty.errorUnionPayload(zcu);
- const pl_has_bits = pl_ty.hasRuntimeBitsIgnoreComptime(zcu);
+ const pl_has_bits = pl_ty.hasRuntimeBits(zcu);
if (!err_union_ty.errorUnionSet(zcu).errorSetIsEmpty(zcu)) {
// Block we can jump out of when error is not set
@@ -7102,16 +7031,13 @@ fn callIntrinsic(
// Lower all arguments to the stack before we call our function
for (args, 0..) |arg, arg_i| {
assert(!(want_sret_param and arg == .stack));
- assert(Type.fromInterned(param_types[arg_i]).hasRuntimeBitsIgnoreComptime(zcu));
+ assert(Type.fromInterned(param_types[arg_i]).hasRuntimeBits(zcu));
try cg.lowerArg(.{ .wasm_mvp = .{} }, Type.fromInterned(param_types[arg_i]), arg);
}
try cg.addInst(.{ .tag = .call_intrinsic, .data = .{ .intrinsic = intrinsic } });
- if (!return_type.hasRuntimeBitsIgnoreComptime(zcu)) {
- return .none;
- } else if (return_type.isNoReturn(zcu)) {
- try cg.addTag(.@"unreachable");
+ if (!return_type.hasRuntimeBits(zcu)) {
return .none;
} else if (want_sret_param) {
return sret;
diff --git a/src/codegen/wasm/abi.zig b/src/codegen/wasm/abi.zig
index a1fa8126491def2d9e2717faa0ccedcd2ee24805..d59047044b302fc86485237e03300efb89d7c151 100644
--- a/src/codegen/wasm/abi.zig
+++ b/src/codegen/wasm/abi.zig
@@ -22,7 +22,7 @@ pub const Class = union(enum) {
/// or returned as value within a wasm function.
pub fn classifyType(ty: Type, zcu: *const Zcu) Class {
const ip = &zcu.intern_pool;
- assert(ty.hasRuntimeBitsIgnoreComptime(zcu));
+ assert(ty.hasRuntimeBits(zcu));
switch (ty.zigTypeTag(zcu)) {
.int, .@"enum", .error_set => return .{ .direct = ty },
.float => return .{ .direct = ty },
@@ -47,7 +47,7 @@ pub fn classifyType(ty: Type, zcu: *const Zcu) Class {
return .indirect;
}
const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[0]);
- const explicit_align = struct_type.fieldAlign(ip, 0);
+ const explicit_align = struct_type.field_aligns.getOrNone(ip, 0);
if (explicit_align != .none) {
if (explicit_align.compareStrict(.gt, field_ty.abiAlignment(zcu)))
return .indirect;
@@ -56,7 +56,7 @@ pub fn classifyType(ty: Type, zcu: *const Zcu) Class {
},
.@"union" => {
const union_obj = zcu.typeToUnion(ty).?;
- if (union_obj.flagsUnordered(ip).layout == .@"packed") {
+ if (union_obj.layout == .@"packed") {
return .{ .direct = ty };
}
const layout = ty.unionGetLayout(zcu);
diff --git a/src/codegen/x86_64/CodeGen.zig b/src/codegen/x86_64/CodeGen.zig
index 6144a421c8cb132aebd77f745bff78618a3e7a0f..7bd81c13ffeb499bfd44209daee0204bd08f4865 100644
--- a/src/codegen/x86_64/CodeGen.zig
+++ b/src/codegen/x86_64/CodeGen.zig
@@ -43261,7 +43261,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
try ops[0].toSlicePtr(cg);
var res: [1]Temp = undefined;
- if (!hack_around_sema_opv_bugs or ty_pl.ty.toType().elemType2(zcu).hasRuntimeBitsIgnoreComptime(zcu)) cg.select(&res, &.{ty_pl.ty.toType()}, &ops, comptime &.{ .{
+ if (!hack_around_sema_opv_bugs or ty_pl.ty.toType().childType(zcu).hasRuntimeBits(zcu)) cg.select(&res, &.{ty_pl.ty.toType()}, &ops, comptime &.{ .{
.patterns = &.{
.{ .src = .{ .to_gpr, .simm32, .none } },
},
@@ -43375,7 +43375,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
try ops[0].toSlicePtr(cg);
var res: [1]Temp = undefined;
- if (!hack_around_sema_opv_bugs or ty_pl.ty.toType().elemType2(zcu).hasRuntimeBitsIgnoreComptime(zcu)) cg.select(&res, &.{ty_pl.ty.toType()}, &ops, comptime &.{ .{
+ if (!hack_around_sema_opv_bugs or ty_pl.ty.toType().childType(zcu).hasRuntimeBits(zcu)) cg.select(&res, &.{ty_pl.ty.toType()}, &ops, comptime &.{ .{
.patterns = &.{
.{ .src = .{ .to_gpr, .simm32, .none } },
},
@@ -103699,7 +103699,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.optional_payload => {
const ty_op = air_datas[@intFromEnum(inst)].ty_op;
var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
- const pl = if (!hack_around_sema_opv_bugs or ty_op.ty.toType().hasRuntimeBitsIgnoreComptime(zcu))
+ const pl = if (!hack_around_sema_opv_bugs or ty_op.ty.toType().hasRuntimeBits(zcu))
try ops[0].read(ty_op.ty.toType(), .{}, cg)
else
try cg.tempInit(ty_op.ty.toType(), .none);
@@ -103745,7 +103745,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
const eu_pl_ty = ty_op.ty.toType();
const eu_pl_off: i32 = @intCast(codegen.errUnionPayloadOffset(eu_pl_ty, zcu));
var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
- const pl = if (!hack_around_sema_opv_bugs or eu_pl_ty.hasRuntimeBitsIgnoreComptime(zcu))
+ const pl = if (!hack_around_sema_opv_bugs or eu_pl_ty.hasRuntimeBits(zcu))
try ops[0].read(eu_pl_ty, .{ .disp = eu_pl_off }, cg)
else
try cg.tempInit(eu_pl_ty, .none);
@@ -103864,7 +103864,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.@"packed" => unreachable,
};
var ops = try cg.tempsFromOperands(inst, .{struct_field.struct_operand});
- var res = if (!hack_around_sema_opv_bugs or field_ty.hasRuntimeBitsIgnoreComptime(zcu))
+ var res = if (!hack_around_sema_opv_bugs or field_ty.hasRuntimeBits(zcu))
try ops[0].read(field_ty, .{ .disp = field_off }, cg)
else
try cg.tempInit(field_ty, .none);
@@ -103926,7 +103926,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.array_elem_val, .legalize_vec_elem_val => {
const bin_op = air_datas[@intFromEnum(inst)].bin_op;
const array_ty = cg.typeOf(bin_op.lhs);
- const res_ty = array_ty.elemType2(zcu);
+ const res_ty = array_ty.childType(zcu);
var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
var res: [1]Temp = undefined;
cg.select(&res, &.{res_ty}, &ops, comptime &.{ .{
@@ -104121,11 +104121,11 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
},
.slice_elem_val, .ptr_elem_val => {
const bin_op = air_datas[@intFromEnum(inst)].bin_op;
- const res_ty = cg.typeOf(bin_op.lhs).elemType2(zcu);
+ const res_ty = cg.typeOf(bin_op.lhs).indexableElem(zcu);
var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
try ops[0].toSlicePtr(cg);
var res: [1]Temp = undefined;
- if (!hack_around_sema_opv_bugs or res_ty.hasRuntimeBitsIgnoreComptime(zcu)) cg.select(&res, &.{res_ty}, &ops, comptime &.{ .{
+ if (!hack_around_sema_opv_bugs or res_ty.hasRuntimeBits(zcu)) cg.select(&res, &.{res_ty}, &ops, comptime &.{ .{
.dst_constraints = .{ .{ .int = .byte }, .any },
.patterns = &.{
.{ .src = .{ .to_gpr, .simm32, .none } },
@@ -171422,10 +171422,10 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.auto, .@"extern" => {
for (elems, 0..) |elem_ref, field_index| {
const elem_dies = bt.feed();
- if (loaded_struct.fieldIsComptime(ip, field_index)) continue;
- if (!hack_around_sema_opv_bugs or Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]).hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (loaded_struct.field_is_comptime_bits.get(ip, field_index)) continue;
+ if (!hack_around_sema_opv_bugs or Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]).hasRuntimeBits(zcu)) {
var elem = try cg.tempFromOperand(elem_ref, elem_dies);
- try res.write(&elem, .{ .disp = @intCast(loaded_struct.offsets.get(ip)[field_index]) }, cg);
+ try res.write(&elem, .{ .disp = @intCast(loaded_struct.field_offsets.get(ip)[field_index]) }, cg);
try elem.die(cg);
try cg.resetTemps(reset_index);
}
@@ -171441,7 +171441,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
const elem_dies = bt.feed();
if (tuple_type.values.get(ip)[field_index] != .none) continue;
const field_type = Type.fromInterned(tuple_type.types.get(ip)[field_index]);
- if (!hack_around_sema_opv_bugs or field_type.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!hack_around_sema_opv_bugs or field_type.hasRuntimeBits(zcu)) {
elem_disp = @intCast(field_type.abiAlignment(zcu).forward(elem_disp));
var elem = try cg.tempFromOperand(elem_ref, elem_dies);
try res.write(&elem, .{ .disp = elem_disp }, cg);
@@ -171467,7 +171467,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
const union_layout = union_ty.unionGetLayout(zcu);
if (union_layout.tag_size > 0) {
var tag_temp = try cg.tempFromValue(try pt.enumValueFieldIndex(
- union_ty.unionTagTypeSafety(zcu).?,
+ union_ty.unionTagTypeRuntime(zcu).?,
union_init.field_index,
));
try res.write(&tag_temp, .{
@@ -173756,7 +173756,7 @@ fn genLazy(cg: *CodeGen, lazy_sym: link.File.LazySymbol) InnerError!void {
var data_off: i32 = 0;
const reset_index = cg.next_temp_index;
- const tag_names = ip.loadEnumType(lazy_sym.ty).names;
+ const tag_names = ip.loadEnumType(lazy_sym.ty).field_names;
for (0..tag_names.len) |tag_index| {
var enum_temp = try cg.tempInit(enum_ty, if (enum_ty.abiSize(zcu) <= @as(u4, switch (cg.target.cpu.arch) {
else => unreachable,
@@ -174334,7 +174334,7 @@ fn genUnwrapErrUnionPayloadMir(
const payload_ty = err_union_ty.errorUnionPayload(zcu);
const result: MCValue = result: {
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .none;
+ if (!payload_ty.hasRuntimeBits(zcu)) break :result .none;
const payload_off: u31 = @intCast(codegen.errUnionPayloadOffset(payload_ty, zcu));
switch (err_union) {
@@ -174450,7 +174450,7 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE
const pt = self.pt;
const zcu = pt.zcu;
const dst_ty = ptr_ty.childType(zcu);
- if (!dst_ty.hasRuntimeBitsIgnoreComptime(zcu)) return;
+ if (!dst_ty.hasRuntimeBits(zcu)) return;
switch (ptr_mcv) {
.none,
.unreach,
@@ -174503,7 +174503,7 @@ fn store(
const pt = self.pt;
const zcu = pt.zcu;
const src_ty = ptr_ty.childType(zcu);
- if (!src_ty.hasRuntimeBitsIgnoreComptime(zcu)) return;
+ if (!src_ty.hasRuntimeBits(zcu)) return;
switch (ptr_mcv) {
.none,
.unreach,
@@ -176615,7 +176615,7 @@ fn lowerSwitchBr(
break :condition_index condition_index;
};
try cg.spillEflagsIfOccupied();
- if (min.?.orderAgainstZero(zcu).compare(.neq)) try cg.genBinOpMir(
+ if (Value.compareHetero(min.?, .neq, .zero_comptime_int, zcu)) try cg.genBinOpMir(
.{ ._, .sub },
condition_ty,
condition_index,
@@ -176957,7 +176957,7 @@ fn airSwitchDispatch(self: *CodeGen, inst: Air.Inst.Index) !void {
const unsigned_condition_ty = try self.pt.intType(.unsigned, self.intInfo(condition_ty).?.bits);
const condition_mcv = block_tracking.short;
try self.spillEflagsIfOccupied();
- if (table.min.orderAgainstZero(self.pt.zcu).compare(.neq)) try self.genBinOpMir(
+ if (Value.compareHetero(table.min, .neq, .zero_comptime_int, self.pt.zcu)) try self.genBinOpMir(
.{ ._, .sub },
condition_ty,
condition_mcv,
@@ -177054,8 +177054,7 @@ fn airBr(self: *CodeGen, inst: Air.Inst.Index) !void {
const br = self.air.instructions.items(.data)[@intFromEnum(inst)].br;
const block_ty = self.typeOfIndex(br.block_inst);
- const block_unused =
- !block_ty.hasRuntimeBitsIgnoreComptime(zcu) or self.liveness.isUnused(br.block_inst);
+ const block_unused = !block_ty.hasRuntimeBits(zcu) or self.liveness.isUnused(br.block_inst);
const block_tracking = self.inst_tracking.getPtr(br.block_inst).?;
const block_data = self.blocks.getPtr(br.block_inst).?;
const first_br = block_data.relocs.items.len == 0;
@@ -177295,41 +177294,38 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
}
const ip = &zcu.intern_pool;
- const aggregate = ip.indexToKey(unwrapped_asm.clobbers).aggregate;
- const struct_type: Type = .fromInterned(aggregate.ty);
- switch (aggregate.storage) {
- .elems => |elems| for (elems, 0..) |elem, i| switch (elem) {
- .bool_true => {
- const clobber = struct_type.structFieldName(i, zcu).toSlice(ip).?;
- assert(clobber.len != 0);
+ const clobbers_val: Value = .fromInterned(unwrapped_asm.clobbers);
+ const clobbers_ty = clobbers_val.typeOf(zcu);
+ var clobbers_bigint_buf: Value.BigIntSpace = undefined;
+ const clobbers_bigint = clobbers_val.toBigInt(&clobbers_bigint_buf, zcu);
+ for (0..clobbers_ty.structFieldCount(zcu)) |field_index| {
+ assert(clobbers_ty.fieldType(field_index, zcu).toIntern() == .bool_type);
+ const limb_bits = @bitSizeOf(std.math.big.Limb);
+ if (field_index / limb_bits >= clobbers_bigint.limbs.len) continue; // field is false
+ switch (@as(u1, @truncate(clobbers_bigint.limbs[field_index / limb_bits] >> @intCast(field_index % limb_bits)))) {
+ 0 => continue, // field is false
+ 1 => {}, // field is true
+ }
+ const clobber = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?;
+ assert(clobber.len != 0);
- if (std.mem.eql(u8, clobber, "memory") or
- std.mem.eql(u8, clobber, "fpsr") or
- std.mem.eql(u8, clobber, "fpcr") or
- std.mem.eql(u8, clobber, "mxcsr") or
- std.mem.eql(u8, clobber, "dirflag"))
- {
- // ok, sure
- } else if (std.mem.eql(u8, clobber, "cc") or
- std.mem.eql(u8, clobber, "flags") or
- std.mem.eql(u8, clobber, "eflags") or
- std.mem.eql(u8, clobber, "rflags"))
- {
- try self.spillEflagsIfOccupied();
- } else {
- try self.register_manager.getReg(parseRegName(clobber) orelse
- return self.fail("invalid clobber: '{s}'", .{clobber}), null);
- }
- },
- .bool_false => continue,
- else => unreachable,
- },
- .repeated_elem => |elem| switch (elem) {
- .bool_true => @panic("TODO"),
- .bool_false => {},
- else => unreachable,
- },
- .bytes => @panic("TODO"),
+ if (std.mem.eql(u8, clobber, "memory") or
+ std.mem.eql(u8, clobber, "fpsr") or
+ std.mem.eql(u8, clobber, "fpcr") or
+ std.mem.eql(u8, clobber, "mxcsr") or
+ std.mem.eql(u8, clobber, "dirflag"))
+ {
+ // ok, sure
+ } else if (std.mem.eql(u8, clobber, "cc") or
+ std.mem.eql(u8, clobber, "flags") or
+ std.mem.eql(u8, clobber, "eflags") or
+ std.mem.eql(u8, clobber, "rflags"))
+ {
+ try self.spillEflagsIfOccupied();
+ } else {
+ try self.register_manager.getReg(parseRegName(clobber) orelse
+ return self.fail("invalid clobber: '{s}'", .{clobber}), null);
+ }
}
const Label = struct {
@@ -180986,7 +180982,7 @@ fn resolveInst(self: *CodeGen, ref: Air.Inst.Ref) InnerError!MCValue {
const ty = self.typeOf(ref);
// If the type has no codegen bits, no need to store it.
- if (!ty.hasRuntimeBitsIgnoreComptime(zcu)) return .none;
+ if (!ty.hasRuntimeBits(zcu)) return .none;
const mcv: MCValue = if (ref.toIndex()) |inst| mcv: {
break :mcv self.inst_tracking.getPtr(inst).?.short;
@@ -181105,7 +181101,7 @@ fn resolveCallingConventionValues(
// Return values
if (ret_ty.isNoReturn(zcu)) {
result.return_value = .init(.unreach);
- } else if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ } else if (!ret_ty.hasRuntimeBits(zcu)) {
// TODO: is this even possible for C calling convention?
result.return_value = .init(.none);
} else {
@@ -181115,7 +181111,7 @@ fn resolveCallingConventionValues(
var ret_sse = abi.getCAbiSseReturnRegs(cc);
var ret_x87 = abi.getCAbiX87ReturnRegs(cc);
- const classes = switch (cc) {
+ const classes: []const abi.Class = switch (cc) {
.x86_64_sysv => std.mem.sliceTo(&abi.classifySystemV(ret_ty, zcu, cg.target, .ret), .none),
.x86_64_win => &.{abi.classifyWindows(ret_ty, zcu, cg.target, .ret)},
else => unreachable,
@@ -181182,7 +181178,7 @@ fn resolveCallingConventionValues(
// Input params
params: for (param_types, result.args) |ty, *arg| {
- assert(ty.hasRuntimeBitsIgnoreComptime(zcu));
+ assert(ty.hasRuntimeBits(zcu));
result.air_arg_count += 1;
switch (cc) {
.x86_64_sysv => {},
@@ -181327,7 +181323,7 @@ fn resolveCallingConventionValues(
// Return values
result.return_value = if (ret_ty.isNoReturn(zcu))
.init(.unreach)
- else if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu))
+ else if (!ret_ty.hasRuntimeBits(zcu))
.init(.none)
else return_value: {
const ret_gpr = abi.getCAbiIntReturnRegs(cc);
@@ -181357,7 +181353,7 @@ fn resolveCallingConventionValues(
// Input params
for (param_types, result.args) |param_ty, *arg| {
- if (!param_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ if (!param_ty.hasRuntimeBits(zcu)) {
arg.* = .none;
continue;
}
@@ -181721,7 +181717,7 @@ fn intInfo(cg: *CodeGen, ty: Type) ?std.builtin.Type.Int {
.one, .many, .c => .{ .signedness = .unsigned, .bits = cg.target.ptrBitWidth() },
.slice => null,
},
- .opt_type => |opt_child| return if (!Type.fromInterned(opt_child).hasRuntimeBitsIgnoreComptime(zcu))
+ .opt_type => |opt_child| return if (!Type.fromInterned(opt_child).hasRuntimeBits(zcu))
.{ .signedness = .unsigned, .bits = 1 }
else switch (ip.indexToKey(opt_child)) {
.ptr_type => |ptr_type| switch (ptr_type.flags.size) {
@@ -181734,7 +181730,7 @@ fn intInfo(cg: *CodeGen, ty: Type) ?std.builtin.Type.Int {
else => null,
},
.error_union_type => |error_union_type| return if (!Type.fromInterned(error_union_type.payload_type)
- .hasRuntimeBitsIgnoreComptime(zcu)) .{ .signedness = .unsigned, .bits = zcu.errorSetBits() } else null,
+ .hasRuntimeBits(zcu)) .{ .signedness = .unsigned, .bits = zcu.errorSetBits() } else null,
.simple_type => |simple_type| return switch (simple_type) {
.bool => .{ .signedness = .unsigned, .bits = 1 },
.anyerror => .{ .signedness = .unsigned, .bits = zcu.errorSetBits() },
@@ -181767,14 +181763,17 @@ fn intInfo(cg: *CodeGen, ty: Type) ?std.builtin.Type.Int {
const loaded_struct = ip.loadStructType(ty_index);
switch (loaded_struct.layout) {
.auto, .@"extern" => return null,
- .@"packed" => ty_index = loaded_struct.backingIntTypeUnordered(ip),
+ .@"packed" => ty_index = loaded_struct.packed_backing_int_type,
}
},
- .union_type => return switch (ip.loadUnionType(ty_index).flagsUnordered(ip).layout) {
- .auto, .@"extern" => null,
- .@"packed" => .{ .signedness = .unsigned, .bits = @intCast(ty.bitSize(zcu)) },
+ .union_type => {
+ const loaded_union = ip.loadUnionType(ty_index);
+ switch (loaded_union.layout) {
+ .auto, .@"extern" => return null,
+ .@"packed" => ty_index = loaded_union.packed_backing_int_type,
+ }
},
- .enum_type => ty_index = ip.loadEnumType(ty_index).tag_ty,
+ .enum_type => ty_index = ip.loadEnumType(ty_index).int_tag_type,
.error_set_type, .inferred_error_set_type => return .{ .signedness = .unsigned, .bits = zcu.errorSetBits() },
else => return null,
};
@@ -187919,7 +187918,6 @@ const Select = struct {
unsigned_int: Memory.Size,
elem_size_is: u8,
po2_elem_size,
- elem_int: Memory.Size,
const OfIsSizes = struct { of: Memory.Size, is: Memory.Size };
@@ -188178,12 +188176,8 @@ const Select = struct {
.signed => false,
.unsigned => size.bitSize(cg.target) >= int_info.bits,
} else false,
- .elem_size_is => |size| size == ty.elemType2(zcu).abiSize(zcu),
- .po2_elem_size => std.math.isPowerOfTwo(ty.elemType2(zcu).abiSize(zcu)),
- .elem_int => |size| if (cg.intInfo(ty.elemType2(zcu))) |elem_int_info|
- size.bitSize(cg.target) >= elem_int_info.bits
- else
- false,
+ .elem_size_is => |size| size == ty.indexableElem(zcu).abiSize(zcu),
+ .po2_elem_size => std.math.isPowerOfTwo(ty.indexableElem(zcu).abiSize(zcu)),
};
}
};
@@ -189918,20 +189912,20 @@ const Select = struct {
.dst0_size => @intCast(Select.Operand.Ref.dst0.typeOf(s).abiSize(s.cg.pt.zcu)),
.delta_size => @intCast(@as(SignedImm, @intCast(op.flags.base.ref.typeOf(s).abiSize(s.cg.pt.zcu))) -
@as(SignedImm, @intCast(op.flags.index.ref.typeOf(s).abiSize(s.cg.pt.zcu)))),
- .delta_elem_size => @intCast(@as(SignedImm, @intCast(op.flags.base.ref.typeOf(s).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu))) -
- @as(SignedImm, @intCast(op.flags.index.ref.typeOf(s).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)))),
+ .delta_elem_size => @intCast(@as(SignedImm, @intCast(op.flags.base.ref.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu))) -
+ @as(SignedImm, @intCast(op.flags.index.ref.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)))),
.unaligned_size => @intCast(s.cg.unalignedSize(op.flags.base.ref.typeOf(s))),
.unaligned_size_add_elem_size => {
const ty = op.flags.base.ref.typeOf(s);
- break :lhs @intCast(s.cg.unalignedSize(ty) + ty.elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu));
+ break :lhs @intCast(s.cg.unalignedSize(ty) + ty.scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu));
},
.unaligned_size_sub_elem_size => {
const ty = op.flags.base.ref.typeOf(s);
- break :lhs @intCast(s.cg.unalignedSize(ty) - ty.elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu));
+ break :lhs @intCast(s.cg.unalignedSize(ty) - ty.scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu));
},
.unaligned_size_sub_2_elem_size => {
const ty = op.flags.base.ref.typeOf(s);
- break :lhs @intCast(s.cg.unalignedSize(ty) - ty.elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu) * 2);
+ break :lhs @intCast(s.cg.unalignedSize(ty) - ty.scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu) * 2);
},
.bit_size => @intCast(s.cg.nonBoolScalarBitSize(op.flags.base.ref.typeOf(s))),
.src0_bit_size => @intCast(s.cg.nonBoolScalarBitSize(Select.Operand.Ref.src0.typeOf(s))),
@@ -189944,10 +189938,10 @@ const Select = struct {
op.flags.base.ref.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu),
@divExact(op.flags.base.size.bitSize(s.cg.target), 8),
)),
- .elem_size => @intCast(op.flags.base.ref.typeOf(s).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)),
- .src0_elem_size => @intCast(Select.Operand.Ref.src0.typeOf(s).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)),
- .dst0_elem_size => @intCast(Select.Operand.Ref.dst0.typeOf(s).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)),
- .src0_elem_size_mul_src1 => @intCast(Select.Operand.Ref.src0.typeOf(s).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu) *
+ .elem_size => @intCast(op.flags.base.ref.typeOf(s).indexableElem(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)),
+ .src0_elem_size => @intCast(Select.Operand.Ref.src0.typeOf(s).indexableElem(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)),
+ .dst0_elem_size => @intCast(Select.Operand.Ref.dst0.typeOf(s).indexableElem(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)),
+ .src0_elem_size_mul_src1 => @intCast(Select.Operand.Ref.src0.typeOf(s).indexableElem(s.cg.pt.zcu).abiSize(s.cg.pt.zcu) *
Select.Operand.Ref.src1.valueOf(s).immediate),
.vector_index => switch (op.flags.base.ref.typeOf(s).ptrInfo(s.cg.pt.zcu).flags.vector_index) {
.none => unreachable,
@@ -189956,7 +189950,7 @@ const Select = struct {
.src1 => @intCast(Select.Operand.Ref.src1.valueOf(s).immediate),
.src1_sub_bit_size => @as(SignedImm, @intCast(Select.Operand.Ref.src1.valueOf(s).immediate)) -
@as(SignedImm, @intCast(s.cg.nonBoolScalarBitSize(op.flags.base.ref.typeOf(s)))),
- .log2_src0_elem_size => @intCast(std.math.log2(Select.Operand.Ref.src0.typeOf(s).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu))),
+ .log2_src0_elem_size => @intCast(std.math.log2(Select.Operand.Ref.src0.typeOf(s).indexableElem(s.cg.pt.zcu).abiSize(s.cg.pt.zcu))),
.elem_mask => @as(u8, std.math.maxInt(u8)) >> @intCast(
8 - ((s.cg.unalignedSize(op.flags.base.ref.typeOf(s)) - 1) %
@divExact(op.flags.base.size.bitSize(s.cg.target), 8) + 1 >>
diff --git a/src/codegen/x86_64/abi.zig b/src/codegen/x86_64/abi.zig
index 2a296dc9304266d85d8fd8618c88b8c20c4c4f33..e0838d23264a61048e55ad2567a590075044284b 100644
--- a/src/codegen/x86_64/abi.zig
+++ b/src/codegen/x86_64/abi.zig
@@ -339,7 +339,7 @@ fn classifySystemVStruct(
var field_it = loaded_struct.iterateRuntimeOrder(ip);
while (field_it.next()) |field_index| {
const field_ty = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
- const field_align = loaded_struct.fieldAlign(ip, field_index);
+ const field_align = loaded_struct.field_aligns.getOrNone(ip, field_index);
byte_offset = std.mem.alignForward(
u64,
byte_offset,
@@ -355,7 +355,7 @@ fn classifySystemVStruct(
.@"packed" => {},
}
} else if (zcu.typeToUnion(field_ty)) |field_loaded_union| {
- switch (field_loaded_union.flagsUnordered(ip).layout) {
+ switch (field_loaded_union.layout) {
.auto => unreachable,
.@"extern" => {
byte_offset = classifySystemVUnion(result, byte_offset, field_loaded_union, zcu, target);
@@ -369,11 +369,11 @@ fn classifySystemVStruct(
result_class.* = result_class.combineSystemV(field_class);
byte_offset += field_ty.abiSize(zcu);
}
- const final_byte_offset = starting_byte_offset + loaded_struct.sizeUnordered(ip);
+ const final_byte_offset = starting_byte_offset + loaded_struct.size;
std.debug.assert(final_byte_offset == std.mem.alignForward(
u64,
byte_offset,
- loaded_struct.flagsUnordered(ip).alignment.toByteUnits().?,
+ loaded_struct.alignment.toByteUnits().?,
));
return final_byte_offset;
}
@@ -398,7 +398,7 @@ fn classifySystemVUnion(
.@"packed" => {},
}
} else if (zcu.typeToUnion(field_ty)) |field_loaded_union| {
- switch (field_loaded_union.flagsUnordered(ip).layout) {
+ switch (field_loaded_union.layout) {
.auto => unreachable,
.@"extern" => {
_ = classifySystemVUnion(result, starting_byte_offset, field_loaded_union, zcu, target);
@@ -411,7 +411,7 @@ fn classifySystemVUnion(
for (result[@intCast(starting_byte_offset / 8)..][0..field_classes.len], field_classes) |*result_class, field_class|
result_class.* = result_class.combineSystemV(field_class);
}
- return starting_byte_offset + loaded_union.sizeUnordered(ip);
+ return starting_byte_offset + loaded_union.size;
}
pub const zigcc = struct {
diff --git a/src/link.zig b/src/link.zig
index 4999c8a31affc3964f8cf129f6bb50c8c5a87675..80141676d414a40cf3cbbd29c213afe62a65d20d 100644
--- a/src/link.zig
+++ b/src/link.zig
@@ -29,6 +29,7 @@ const codegen = @import("codegen.zig");
pub const aarch64 = @import("link/aarch64.zig");
pub const LdScript = @import("link/LdScript.zig");
pub const Queue = @import("link/Queue.zig");
+pub const ConstPool = @import("link/ConstPool.zig");
pub const Diags = struct {
/// Stored here so that function definitions can distinguish between
@@ -798,14 +799,27 @@ pub const File = struct {
};
/// Never called when LLVM is codegenning the ZCU.
- fn updateContainerType(base: *File, pt: Zcu.PerThread, ty: InternPool.Index) UpdateContainerTypeError!void {
+ fn updateContainerType(base: *File, pt: Zcu.PerThread, ty: InternPool.Index, success: bool) UpdateContainerTypeError!void {
+ assert(base.comp.zcu.?.llvm_object == null);
+ switch (base.tag) {
+ .lld => unreachable,
+ else => {},
+ inline .elf, .c => |tag| {
+ dev.check(tag.devFeature());
+ return @as(*tag.Type(), @fieldParentPtr("base", base)).updateContainerType(pt, ty, success);
+ },
+ }
+ }
+
+ /// Never called when LLVM is codegenning the ZCU.
+ fn clearContainerType(base: *File, pt: Zcu.PerThread, ty: InternPool.Index) UpdateContainerTypeError!void {
assert(base.comp.zcu.?.llvm_object == null);
switch (base.tag) {
.lld => unreachable,
else => {},
inline .elf => |tag| {
dev.check(tag.devFeature());
- return @as(*tag.Type(), @fieldParentPtr("base", base)).updateContainerType(pt, ty);
+ return @as(*tag.Type(), @fieldParentPtr("base", base)).clearContainerType(pt, ty);
},
}
}
@@ -1375,8 +1389,14 @@ pub const ZcuTask = union(enum) {
link_nav: InternPool.Nav.Index,
/// Write the machine code for a function to the output file.
link_func: Zcu.CodegenTaskPool.Index,
- link_type: InternPool.Index,
- update_line_number: InternPool.TrackedInst.Index,
+ /// This struct/union/enum type has finished type resolution (successfully or otherwise), so the
+ /// linker can now lower debug information for this type (and any structural types which depend
+ /// on it, such as `?T`, `struct { T }`, `[2]T`, etc).
+ debug_update_container_type: struct {
+ ty: InternPool.Index,
+ success: bool,
+ },
+ debug_update_line_number: InternPool.TrackedInst.Index,
};
pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void {
@@ -1537,7 +1557,10 @@ pub fn doZcuTask(comp: *Compilation, tid: Zcu.PerThread.Id, task: ZcuTask) void
.link_func => |codegen_task| nav: {
timer.pause(io);
const func, var mir = codegen_task.wait(&zcu.codegen_task_pool, io) catch |err| switch (err) {
- error.Canceled, error.AlreadyReported => return,
+ error.Canceled, error.AlreadyReported => {
+ comp.link_prog_node.completeOne();
+ return;
+ },
};
defer mir.deinit(zcu);
timer.@"resume"(io);
@@ -1563,21 +1586,25 @@ pub fn doZcuTask(comp: *Compilation, tid: Zcu.PerThread.Id, task: ZcuTask) void
}
break :nav ip.indexToKey(func).func.owner_nav;
},
- .link_type => |ty| nav: {
- const name = Type.fromInterned(ty).containerTypeName(ip).toSlice(ip);
- const nav_prog_node = comp.link_prog_node.start(name, 0);
- defer nav_prog_node.end();
- if (zcu.llvm_object == null) {
+ .debug_update_container_type => |container_update| nav: {
+ const name = Type.fromInterned(container_update.ty).containerTypeName(ip).toSlice(ip);
+ const ty_prog_node = comp.link_prog_node.start(name, 0);
+ defer ty_prog_node.end();
+ if (zcu.llvm_object) |llvm_object| {
+ llvm_object.updateContainerType(pt, container_update.ty, container_update.success) catch |err| switch (err) {
+ error.OutOfMemory => diags.setAllocFailure(),
+ };
+ } else {
if (comp.bin_file) |lf| {
- lf.updateContainerType(pt, ty) catch |err| switch (err) {
+ lf.updateContainerType(pt, container_update.ty, container_update.success) catch |err| switch (err) {
error.OutOfMemory => diags.setAllocFailure(),
- error.TypeFailureReported => assert(zcu.failed_types.contains(ty)),
+ error.TypeFailureReported => assert(zcu.failed_types.contains(container_update.ty)),
};
}
}
break :nav null;
},
- .update_line_number => |ti| nav: {
+ .debug_update_line_number => |ti| nav: {
const nav_prog_node = comp.link_prog_node.start("Update line number", 0);
defer nav_prog_node.end();
if (pt.zcu.llvm_object == null) {
diff --git a/src/link/C.zig b/src/link/C.zig
index 93e771ebfc3d01a61f7fb5268bd84fe8b639f489..3c71206cc70db582e6d1d462cb49bcb80e51da7b 100644
--- a/src/link/C.zig
+++ b/src/link/C.zig
@@ -1,3 +1,9 @@
+/// Unlike other linker implementations, `link.C` does not attempt to incrementally link its output,
+/// because C has many language rules which make that impractical. Instead, we individually generate
+/// each declaration (NAV), and the output is stitched together (alongside types and UAVs) in an
+/// appropriate order in `flush`.
+const C = @This();
+
const std = @import("std");
const mem = std.mem;
const assert = std.debug.assert;
@@ -5,7 +11,6 @@ const Allocator = std.mem.Allocator;
const fs = std.fs;
const Path = std.Build.Cache.Path;
-const C = @This();
const build_options = @import("build_options");
const Zcu = @import("../Zcu.zig");
const Module = @import("../Package/Module.zig");
@@ -19,40 +24,45 @@ const Type = @import("../Type.zig");
const Value = @import("../Value.zig");
const AnyMir = @import("../codegen.zig").AnyMir;
-pub const zig_h = "#include \"zig.h\"\n";
-
base: link.File,
-/// This linker backend does not try to incrementally link output C source code.
-/// Instead, it tracks all declarations in this table, and iterates over it
-/// in the flush function, stitching pre-rendered pieces of C code together.
-navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, AvBlock),
-/// All the string bytes of rendered C code, all squished into one array.
-/// While in progress, a separate buffer is used, and then when finished, the
-/// buffer is copied into this one.
+
+/// All the string bytes of rendered C code, all squished into one array. `String` is used to refer
+/// to specific slices of this array, used for the rendered C code of an individual UAV/NAV/type.
+///
+/// During code generation for functions, a separate buffer is used, and the contents of that buffer
+/// are copied into `string_bytes` when the function is emitted by `updateFunc`.
string_bytes: std.ArrayList(u8),
-/// Tracks all the anonymous decls that are used by all the decls so they can
-/// be rendered during flush().
-uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, AvBlock),
-/// Sparse set of uavs that are overaligned. Underaligned anon decls are
-/// lowered the same as ABI-aligned anon decls. The keys here are a subset of
-/// the keys of `uavs`.
-aligned_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment),
-exported_navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, ExportedBlock),
-exported_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, ExportedBlock),
+/// Like with `string_bytes`, we concatenate all type dependencies into one array, and slice into it
+/// for specific groups of dependencies. These values are indices into `type_pool`, and thus also
+/// into `types`. We store these instead of `InternPool.Index` because it lets us avoid some hash
+/// map lookups in `flush`.
+type_dependencies: std.ArrayList(link.ConstPool.Index),
+/// For storing dependencies on "aligned" versions of types, we must associate each type with a
+/// bitmask of required alignments. As with `type_dependencies`, we concatenate all such masks into
+/// one array.
+align_dependency_masks: std.ArrayList(u64),
-/// Optimization, `updateDecl` reuses this buffer rather than creating a new
-/// one with every call.
-fwd_decl_buf: []u8,
-/// Optimization, `updateDecl` reuses this buffer rather than creating a new
-/// one with every call.
-code_header_buf: []u8,
-/// Optimization, `updateDecl` reuses this buffer rather than creating a new
-/// one with every call.
-code_buf: []u8,
-/// Optimization, `flush` reuses this buffer rather than creating a new
-/// one with every call.
-scratch_buf: []u32,
+/// All NAVs, regardless of whether they are functions or simple constants, are put in this map.
+navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, RenderedDecl),
+/// All UAVs which may be referenced are in this map. The UAV alignment is not included in the
+/// rendered C code stored here, because we don't know the alignment a UAV needs until `flush`.
+uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, RenderedDecl),
+/// Contains all types which are needed by some other rendered code. Does not contain any constants
+/// other than types.
+type_pool: link.ConstPool,
+/// Indices are `link.ConstPool.Index` from `type_pool`. Contains rendered C code for every type
+/// which may be referenced. Logic in `flush` will perform the appropriate topological sort to emit
+/// these type definitions in an order which C allows.
+types: std.ArrayList(RenderedType),
+
+/// The set of big int types required by *any* generated code so far. These are always safe to emit,
+/// so they do not participate in the dependency graph traversal in `flush`. Therefore, redundant
+/// big-int types may be emitted under incremental compilation.
+bigint_types: std.AutoArrayHashMapUnmanaged(codegen.CType.BigInt, void),
+
+exported_navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, String),
+exported_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, String),
/// A reference into `string_bytes`.
const String = extern struct {
@@ -64,50 +74,320 @@ const String = extern struct {
.len = 0,
};
- fn concat(lhs: String, rhs: String) String {
- assert(lhs.start + lhs.len == rhs.start);
+ fn get(s: String, c: *C) []const u8 {
+ return c.string_bytes.items[s.start..][0..s.len];
+ }
+};
+
+const CTypeDependencies = struct {
+ len: u32,
+ errunion_len: u32,
+ fwd_len: u32,
+ errunion_fwd_len: u32,
+ aligned_fwd_len: u32,
+
+ /// Index into `C.type_dependencies`. Starting at this index are:
+ /// * `len` dependencies on complete types
+ /// * `errunion_len` dependencies on complete error union types
+ /// * `fwd_len` dependencies on forward-declared types
+ /// * `errunion_fwd_len` dependencies on forward-declared error union types
+ /// * `aligned_fwd_len` dependencies on aligned types
+ type_start: u32,
+ /// Index into `C.align_dependency_masks`. Starting at this index are `aligned_type_fwd_len`
+ /// items containing the bitmasks for each aligned type (in `C.type_dependencies`).
+ align_mask_start: u32,
+
+ const Resolved = struct {
+ type: []const link.ConstPool.Index,
+ errunion_type: []const link.ConstPool.Index,
+ type_fwd: []const link.ConstPool.Index,
+ errunion_type_fwd: []const link.ConstPool.Index,
+ aligned_type_fwd: []const link.ConstPool.Index,
+ aligned_type_masks: []const u64,
+ };
+
+ fn get(td: *const CTypeDependencies, c: *const C) Resolved {
+ const types_overlong = c.type_dependencies.items[td.type_start..];
return .{
- .start = lhs.start,
- .len = lhs.len + rhs.len,
+ .type = types_overlong[0..td.len],
+ .errunion_type = types_overlong[td.len..][0..td.errunion_len],
+ .type_fwd = types_overlong[td.len + td.errunion_len ..][0..td.fwd_len],
+ .errunion_type_fwd = types_overlong[td.len + td.errunion_len + td.fwd_len ..][0..td.errunion_fwd_len],
+ .aligned_type_fwd = types_overlong[td.len + td.errunion_len + td.fwd_len + td.errunion_fwd_len ..][0..td.aligned_fwd_len],
+ .aligned_type_masks = c.align_dependency_masks.items[td.align_mask_start..][0..td.aligned_fwd_len],
};
}
+
+ const empty: CTypeDependencies = .{
+ .len = 0,
+ .errunion_len = 0,
+ .fwd_len = 0,
+ .errunion_fwd_len = 0,
+ .aligned_fwd_len = 0,
+ .type_start = 0,
+ .align_mask_start = 0,
+ };
};
-/// Per-declaration data.
-pub const AvBlock = struct {
- fwd_decl: String = .empty,
- code: String = .empty,
- /// Each `Decl` stores a set of used `CType`s. In `flush()`, we iterate
- /// over each `Decl` and generate the definition for each used `CType` once.
- ctype_pool: codegen.CType.Pool = .empty,
- /// May contain string references to ctype_pool
- lazy_fns: codegen.LazyFnMap = .{},
-
- fn deinit(ab: *AvBlock, gpa: Allocator) void {
- ab.lazy_fns.deinit(gpa);
- ab.ctype_pool.deinit(gpa);
- ab.* = undefined;
+const RenderedDecl = struct {
+ fwd_decl: String,
+ code: String,
+ ctype_deps: CTypeDependencies,
+ need_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment),
+ need_tag_name_funcs: std.AutoArrayHashMapUnmanaged(InternPool.Index, void),
+ need_never_tail_funcs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void),
+ need_never_inline_funcs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void),
+
+ const init: RenderedDecl = .{
+ .fwd_decl = .empty,
+ .code = .empty,
+ .ctype_deps = .empty,
+ .need_uavs = .empty,
+ .need_tag_name_funcs = .empty,
+ .need_never_tail_funcs = .empty,
+ .need_never_inline_funcs = .empty,
+ };
+
+ fn deinit(rd: *RenderedDecl, gpa: Allocator) void {
+ rd.need_uavs.deinit(gpa);
+ rd.need_tag_name_funcs.deinit(gpa);
+ rd.need_never_tail_funcs.deinit(gpa);
+ rd.need_never_inline_funcs.deinit(gpa);
+ rd.* = undefined;
+ }
+
+ /// We are about to re-render this declaration, but we want to reuse the existing buffers, so
+ /// call `clearRetainCapacity` on the containers. Sets `fwd_decl` and `code` to `undefined`,
+ /// because we shouldn't be using the old values any longer.
+ fn clearRetainingCapacity(rd: *RenderedDecl) void {
+ rd.fwd_decl = undefined;
+ rd.code = undefined;
+ rd.need_uavs.clearRetainingCapacity();
+ rd.need_tag_name_funcs.clearRetainingCapacity();
+ rd.need_never_tail_funcs.clearRetainingCapacity();
+ rd.need_never_inline_funcs.clearRetainingCapacity();
}
};
-/// Per-exported-symbol data.
-pub const ExportedBlock = struct {
- fwd_decl: String = .empty,
+const RenderedType = struct {
+ /// If this type lowers to an aggregate, this is a forward declaration of its struct/union tag.
+ /// Otherwise, this is `.empty`.
+ ///
+ /// Populated immediately and never changes.
+ fwd_decl: String,
+
+ /// A forward declaration of an error union type with this type as its *payload*.
+ ///
+ /// Populated immediately and never changes.
+ errunion_fwd_decl: String,
+
+ /// If this type lowers to an aggregate, this is the struct/union definition.
+ /// If this type lowers to a typedef, this is that typedef.
+ /// Otherwise, this is `.empty`.
+ definition: String,
+ /// The `struct` definition for an error union type with this type as its *payload*.
+ ///
+ /// This string is empty iff the payload type does not have a resolved layout. If the layout is
+ /// resolved, the error union struct is defined, even if the payload type lacks runtime bits.
+ errunion_definition: String,
+
+ /// Dependencies which must be satisfied before emitting the name of this type. As such, they
+ /// must be satisfied before emitting `errunion_definition` or any aligned typedef.
+ ///
+ /// Populated immediately and never changes.
+ deps: CTypeDependencies,
+
+ /// Dependencies which must be satisfied before emitting `definition`.
+ definition_deps: CTypeDependencies,
};
-pub fn getString(this: C, s: String) []const u8 {
- return this.string_bytes.items[s.start..][0..s.len];
+/// Only called by `link.ConstPool` due to `c.type_pool`, so `val` is always a type.
+pub fn addConst(
+ c: *C,
+ pt: Zcu.PerThread,
+ pool_index: link.ConstPool.Index,
+ val: InternPool.Index,
+) Allocator.Error!void {
+ const zcu = pt.zcu;
+ const gpa = zcu.comp.gpa;
+ assert(zcu.intern_pool.typeOf(val) == .type_type);
+ assert(@intFromEnum(pool_index) == c.types.items.len);
+
+ const ty: Type = .fromInterned(val);
+
+ const fwd_decl: String = fwd_decl: {
+ var aw: std.Io.Writer.Allocating = .fromArrayList(gpa, &c.string_bytes);
+ defer c.string_bytes = aw.toArrayList();
+ const start = aw.written().len;
+ codegen.CType.render_defs.fwdDecl(ty, &aw.writer, zcu) catch |err| switch (err) {
+ error.WriteFailed => return error.OutOfMemory,
+ };
+ break :fwd_decl .{
+ .start = @intCast(start),
+ .len = @intCast(aw.written().len - start),
+ };
+ };
+
+ const errunion_fwd_decl: String = errunion_fwd_decl: {
+ var aw: std.Io.Writer.Allocating = .fromArrayList(gpa, &c.string_bytes);
+ defer c.string_bytes = aw.toArrayList();
+ const start = aw.written().len;
+ codegen.CType.render_defs.errunionFwdDecl(ty, &aw.writer, zcu) catch |err| switch (err) {
+ error.WriteFailed => return error.OutOfMemory,
+ };
+ break :errunion_fwd_decl .{
+ .start = @intCast(start),
+ .len = @intCast(aw.written().len - start),
+ };
+ };
+
+ try c.types.append(gpa, .{
+ .fwd_decl = fwd_decl,
+ .errunion_fwd_decl = errunion_fwd_decl,
+ // This field will be populated just below.
+ .deps = undefined,
+ // The remaining fields will be populated later by either `updateConstIncomplete` or
+ // `updateConstComplete` (it is guaranteed that at least one will be called).
+ .definition = undefined,
+ .errunion_definition = undefined,
+ .definition_deps = undefined,
+ });
+
+ {
+ // Find the dependencies required to just render the type `ty`.
+ var arena: std.heap.ArenaAllocator = .init(gpa);
+ defer arena.deinit();
+ var deps: codegen.CType.Dependencies = .empty;
+ defer deps.deinit(gpa);
+ _ = try codegen.CType.lower(ty, &deps, arena.allocator(), zcu);
+ // This call may add more items to `c.types`.
+ const type_deps = try c.addCTypeDependencies(pt, &deps);
+ c.types.items[@intFromEnum(pool_index)].deps = type_deps;
+ }
}
-pub fn addString(this: *C, s: []const u8) Allocator.Error!String {
- const comp = this.base.comp;
- const gpa = comp.gpa;
- try this.string_bytes.appendSlice(gpa, s);
- return .{
- .start = @intCast(this.string_bytes.items.len - s.len),
- .len = @intCast(s.len),
+/// Only called by `link.ConstPool` due to `c.type_pool`, so `val` is always a type.
+pub fn updateConstIncomplete(
+ c: *C,
+ pt: Zcu.PerThread,
+ index: link.ConstPool.Index,
+ val: InternPool.Index,
+) Allocator.Error!void {
+ const zcu = pt.zcu;
+ const gpa = zcu.comp.gpa;
+
+ assert(zcu.intern_pool.typeOf(val) == .type_type);
+ const ty: Type = .fromInterned(val);
+
+ const rendered: *RenderedType = &c.types.items[@intFromEnum(index)];
+
+ rendered.errunion_definition = .empty;
+ rendered.definition_deps = .empty;
+ rendered.definition = definition: {
+ if (rendered.fwd_decl.len != 0) {
+ // This is a struct or union type. We will never complete it, but we must forward
+ // declare it to ensure that its first usage does not appear in a different scope.
+ break :definition rendered.fwd_decl;
+ }
+ // Otherwise, we might need to `typedef` to `void`.
+ var aw: std.Io.Writer.Allocating = .fromArrayList(gpa, &c.string_bytes);
+ defer c.string_bytes = aw.toArrayList();
+ const start = aw.written().len;
+ codegen.CType.render_defs.defineIncomplete(ty, &aw.writer, pt) catch |err| switch (err) {
+ error.WriteFailed => return error.OutOfMemory,
+ };
+ break :definition .{
+ .start = @intCast(start),
+ .len = @intCast(aw.written().len - start),
+ };
};
}
+/// Only called by `link.ConstPool` due to `c.type_pool`, so `val` is always a type.
+pub fn updateConst(
+ c: *C,
+ pt: Zcu.PerThread,
+ index: link.ConstPool.Index,
+ val: InternPool.Index,
+) Allocator.Error!void {
+ const zcu = pt.zcu;
+ const gpa = zcu.comp.gpa;
+
+ assert(zcu.intern_pool.typeOf(val) == .type_type);
+ const ty: Type = .fromInterned(val);
+
+ const rendered: *RenderedType = &c.types.items[@intFromEnum(index)];
+
+ var arena: std.heap.ArenaAllocator = .init(gpa);
+ defer arena.deinit();
+
+ var deps: codegen.CType.Dependencies = .empty;
+ defer deps.deinit(gpa);
+
+ {
+ var aw: std.Io.Writer.Allocating = .fromArrayList(gpa, &c.string_bytes);
+ defer c.string_bytes = aw.toArrayList();
+ const start = aw.written().len;
+ codegen.CType.render_defs.errunionDefineComplete(
+ ty,
+ &deps,
+ arena.allocator(),
+ &aw.writer,
+ pt,
+ ) catch |err| switch (err) {
+ error.WriteFailed => return error.OutOfMemory,
+ error.OutOfMemory => |e| return e,
+ };
+ rendered.errunion_definition = .{
+ .start = @intCast(start),
+ .len = @intCast(aw.written().len - start),
+ };
+ }
+
+ deps.clearRetainingCapacity();
+
+ {
+ var aw: std.Io.Writer.Allocating = .fromArrayList(gpa, &c.string_bytes);
+ defer c.string_bytes = aw.toArrayList();
+ const start = aw.written().len;
+ codegen.CType.render_defs.defineComplete(
+ ty,
+ &deps,
+ arena.allocator(),
+ &aw.writer,
+ pt,
+ ) catch |err| switch (err) {
+ error.WriteFailed => return error.OutOfMemory,
+ error.OutOfMemory => |e| return e,
+ };
+ // Remove dependency on a forward declaration of ourselves; we're defining this type so that
+ // forward declaration obviously exists!
+ _ = deps.type_fwd.swapRemove(ty.toIntern());
+ rendered.definition = .{
+ .start = @intCast(start),
+ .len = @intCast(aw.written().len - start),
+ };
+ }
+
+ {
+ // This call invalidates `rendered`.
+ const definition_deps = try c.addCTypeDependencies(pt, &deps);
+ c.types.items[@intFromEnum(index)].definition_deps = definition_deps;
+ }
+}
+
+fn addString(c: *C, vec: []const []const u8) Allocator.Error!String {
+ const gpa = c.base.comp.gpa;
+
+ var len: u32 = 0;
+ for (vec) |s| len += @intCast(s.len);
+ try c.string_bytes.ensureUnusedCapacity(gpa, len);
+
+ const start: u32 = @intCast(c.string_bytes.items.len);
+ for (vec) |s| c.string_bytes.appendSliceAssumeCapacity(s);
+ assert(c.string_bytes.items.len == start + len);
+
+ return .{ .start = start, .len = len };
+}
pub fn open(
arena: Allocator,
@@ -156,267 +436,622 @@ pub fn createEmpty(
.file = file,
.build_id = options.build_id,
},
- .navs = .empty,
.string_bytes = .empty,
+ .type_dependencies = .empty,
+ .align_dependency_masks = .empty,
+ .navs = .empty,
.uavs = .empty,
- .aligned_uavs = .empty,
+ .type_pool = .empty,
+ .types = .empty,
+ .bigint_types = .empty,
.exported_navs = .empty,
.exported_uavs = .empty,
- .fwd_decl_buf = &.{},
- .code_header_buf = &.{},
- .code_buf = &.{},
- .scratch_buf = &.{},
};
return c_file;
}
-pub fn deinit(self: *C) void {
- const gpa = self.base.comp.gpa;
+pub fn deinit(c: *C) void {
+ const gpa = c.base.comp.gpa;
- for (self.navs.values()) |*db| {
- db.deinit(gpa);
- }
- self.navs.deinit(gpa);
+ for (c.navs.values()) |*r| r.deinit(gpa);
+ for (c.uavs.values()) |*r| r.deinit(gpa);
- for (self.uavs.values()) |*db| {
- db.deinit(gpa);
- }
- self.uavs.deinit(gpa);
- self.aligned_uavs.deinit(gpa);
+ c.string_bytes.deinit(gpa);
+ c.type_dependencies.deinit(gpa);
+ c.align_dependency_masks.deinit(gpa);
+ c.navs.deinit(gpa);
+ c.uavs.deinit(gpa);
+ c.type_pool.deinit(gpa);
+ c.types.deinit(gpa);
+ c.bigint_types.deinit(gpa);
+ c.exported_navs.deinit(gpa);
+ c.exported_uavs.deinit(gpa);
+}
- self.exported_navs.deinit(gpa);
- self.exported_uavs.deinit(gpa);
-
- self.string_bytes.deinit(gpa);
- gpa.free(self.fwd_decl_buf);
- gpa.free(self.code_header_buf);
- gpa.free(self.code_buf);
- gpa.free(self.scratch_buf);
+pub fn updateContainerType(
+ c: *C,
+ pt: Zcu.PerThread,
+ ty: InternPool.Index,
+ success: bool,
+) link.File.UpdateContainerTypeError!void {
+ try c.type_pool.updateContainerType(pt, .{ .c = c }, ty, success);
}
pub fn updateFunc(
- self: *C,
+ c: *C,
pt: Zcu.PerThread,
func_index: InternPool.Index,
mir: *AnyMir,
-) link.File.UpdateNavError!void {
+) Allocator.Error!void {
const zcu = pt.zcu;
const gpa = zcu.gpa;
- const func = zcu.funcInfo(func_index);
+ const nav = zcu.funcInfo(func_index).owner_nav;
- const gop = try self.navs.getOrPut(gpa, func.owner_nav);
- if (gop.found_existing) gop.value_ptr.deinit(gpa);
- gop.value_ptr.* = .{
- .code = .empty,
- .fwd_decl = .empty,
- .ctype_pool = mir.c.ctype_pool.move(),
- .lazy_fns = mir.c.lazy_fns.move(),
+ const rendered_decl: *RenderedDecl = rd: {
+ const gop = try c.navs.getOrPut(gpa, nav);
+ if (gop.found_existing) gop.value_ptr.deinit(gpa);
+ break :rd gop.value_ptr;
};
- gop.value_ptr.fwd_decl = try self.addString(mir.c.fwd_decl);
- const code_header = try self.addString(mir.c.code_header);
- const code = try self.addString(mir.c.code);
- gop.value_ptr.code = code_header.concat(code);
- try self.addUavsFromCodegen(&mir.c.uavs);
-}
+ c.navs.lockPointers();
+ defer c.navs.unlockPointers();
-fn updateUav(self: *C, pt: Zcu.PerThread, i: usize) link.File.FlushError!void {
- const gpa = self.base.comp.gpa;
- const uav = self.uavs.keys()[i];
-
- var object: codegen.Object = .{
- .dg = .{
- .gpa = gpa,
- .pt = pt,
- .mod = pt.zcu.root_mod,
- .error_msg = null,
- .pass = .{ .uav = uav },
- .is_naked_fn = false,
- .expected_block = null,
- .fwd_decl = undefined,
- .ctype_pool = .empty,
- .scratch = .initBuffer(self.scratch_buf),
- .uavs = .empty,
- },
- .code_header = undefined,
- .code = undefined,
- .indent_counter = 0,
+ rendered_decl.* = .{
+ .fwd_decl = try c.addString(&.{mir.c.fwd_decl}),
+ .code = try c.addString(&.{ mir.c.code_header, mir.c.code }),
+ .ctype_deps = try c.addCTypeDependencies(pt, &mir.c.ctype_deps),
+ .need_uavs = mir.c.need_uavs.move(),
+ .need_tag_name_funcs = mir.c.need_tag_name_funcs.move(),
+ .need_never_tail_funcs = mir.c.need_never_tail_funcs.move(),
+ .need_never_inline_funcs = mir.c.need_never_inline_funcs.move(),
};
- object.dg.fwd_decl = .initOwnedSlice(gpa, self.fwd_decl_buf);
- object.code = .initOwnedSlice(gpa, self.code_buf);
- defer {
- object.dg.uavs.deinit(gpa);
- object.dg.ctype_pool.deinit(object.dg.gpa);
- self.fwd_decl_buf = object.dg.fwd_decl.toArrayList().allocatedSlice();
- self.code_buf = object.code.toArrayList().allocatedSlice();
- self.scratch_buf = object.dg.scratch.allocatedSlice();
+ const old_uavs_len = c.uavs.count();
+ try c.uavs.ensureUnusedCapacity(gpa, rendered_decl.need_uavs.count());
+ for (rendered_decl.need_uavs.keys()) |val| {
+ const gop = c.uavs.getOrPutAssumeCapacity(val);
+ if (gop.found_existing) {
+ assert(gop.index < old_uavs_len);
+ } else {
+ assert(gop.index >= old_uavs_len);
+ }
}
- try object.dg.ctype_pool.init(gpa);
+ try c.updateNewUavs(pt, old_uavs_len);
- const c_value: codegen.CValue = .{ .constant = Value.fromInterned(uav) };
- const alignment: Alignment = self.aligned_uavs.get(uav) orelse .none;
- codegen.genDeclValue(&object, c_value.constant, c_value, alignment, .none) catch |err| switch (err) {
- error.AnalysisFail => {
- @panic("TODO: C backend AnalysisFail on anonymous decl");
- //try zcu.failed_decls.put(gpa, decl_index, object.dg.error_msg.?);
- //return;
- },
- error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
- };
-
- try self.addUavsFromCodegen(&object.dg.uavs);
-
- object.dg.ctype_pool.freeUnusedCapacity(gpa);
- self.uavs.values()[i] = .{
- .fwd_decl = try self.addString(object.dg.fwd_decl.written()),
- .code = try self.addString(object.code.written()),
- .ctype_pool = object.dg.ctype_pool.move(),
- };
+ try c.type_pool.flushPending(pt, .{ .c = c });
}
-pub fn updateNav(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) link.File.UpdateNavError!void {
+pub fn updateNav(
+ c: *C,
+ pt: Zcu.PerThread,
+ nav_index: InternPool.Nav.Index,
+) Allocator.Error!void {
const tracy = trace(@src());
defer tracy.end();
- const gpa = self.base.comp.gpa;
+ const gpa = c.base.comp.gpa;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const nav = ip.getNav(nav_index);
- const nav_init = switch (ip.indexToKey(nav.status.fully_resolved.val)) {
+ switch (ip.indexToKey(nav.status.fully_resolved.val)) {
.func => return,
- .@"extern" => .none,
- .variable => |variable| variable.init,
- else => nav.status.fully_resolved.val,
+ .@"extern" => {},
+ else => {
+ const nav_ty: Type = .fromInterned(nav.typeOf(ip));
+ if (!nav_ty.hasRuntimeBits(zcu)) {
+ if (c.navs.fetchSwapRemove(nav_index)) |kv| {
+ var old_rendered = kv.value;
+ old_rendered.deinit(gpa);
+ }
+ return;
+ }
+ },
+ }
+
+ const rendered_decl: *RenderedDecl = rd: {
+ const gop = try c.navs.getOrPut(gpa, nav_index);
+ if (gop.found_existing) {
+ gop.value_ptr.clearRetainingCapacity();
+ } else {
+ gop.value_ptr.* = .init;
+ }
+ break :rd gop.value_ptr;
};
- if (nav_init != .none and !Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(zcu)) return;
+ c.navs.lockPointers();
+ defer c.navs.unlockPointers();
- const gop = try self.navs.getOrPut(gpa, nav_index);
- errdefer _ = self.navs.pop();
- if (!gop.found_existing) gop.value_ptr.* = .{};
- const ctype_pool = &gop.value_ptr.ctype_pool;
- try ctype_pool.init(gpa);
- ctype_pool.clearRetainingCapacity();
+ {
+ var arena: std.heap.ArenaAllocator = .init(gpa);
+ defer arena.deinit();
- var object: codegen.Object = .{
- .dg = .{
+ var dg: codegen.DeclGen = .{
.gpa = gpa,
+ .arena = arena.allocator(),
.pt = pt,
.mod = zcu.navFileScope(nav_index).mod.?,
.error_msg = null,
- .pass = .{ .nav = nav_index },
+ .owner_nav = nav_index.toOptional(),
.is_naked_fn = false,
.expected_block = null,
- .fwd_decl = undefined,
- .ctype_pool = ctype_pool.*,
- .scratch = .initBuffer(self.scratch_buf),
- .uavs = .empty,
- },
- .code_header = undefined,
- .code = undefined,
- .indent_counter = 0,
+ .ctype_deps = .empty,
+ .uavs = rendered_decl.need_uavs.move(),
+ };
+
+ defer {
+ rendered_decl.need_uavs = dg.uavs.move();
+ dg.ctype_deps.deinit(gpa);
+ }
+
+ rendered_decl.fwd_decl = fwd_decl: {
+ var aw: std.Io.Writer.Allocating = .fromArrayList(gpa, &c.string_bytes);
+ defer c.string_bytes = aw.toArrayList();
+ const start = aw.written().len;
+ codegen.genDeclFwd(&dg, &aw.writer) catch |err| switch (err) {
+ error.AnalysisFail => switch (zcu.codegenFailMsg(nav_index, dg.error_msg.?)) {
+ error.CodegenFail => return,
+ error.OutOfMemory => |e| return e,
+ },
+ error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
+ };
+ break :fwd_decl .{
+ .start = @intCast(start),
+ .len = @intCast(aw.written().len - start),
+ };
+ };
+
+ rendered_decl.code = code: {
+ var aw: std.Io.Writer.Allocating = .fromArrayList(gpa, &c.string_bytes);
+ defer c.string_bytes = aw.toArrayList();
+ const start = aw.written().len;
+ codegen.genDecl(&dg, &aw.writer) catch |err| switch (err) {
+ error.AnalysisFail => switch (zcu.codegenFailMsg(nav_index, dg.error_msg.?)) {
+ error.CodegenFail => return,
+ error.OutOfMemory => |e| return e,
+ },
+ error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
+ };
+ break :code .{
+ .start = @intCast(start),
+ .len = @intCast(aw.written().len - start),
+ };
+ };
+
+ rendered_decl.ctype_deps = try c.addCTypeDependencies(pt, &dg.ctype_deps);
+ }
+
+ const old_uavs_len = c.uavs.count();
+ try c.uavs.ensureUnusedCapacity(gpa, rendered_decl.need_uavs.count());
+ for (rendered_decl.need_uavs.keys()) |val| {
+ const gop = c.uavs.getOrPutAssumeCapacity(val);
+ if (gop.found_existing) {
+ assert(gop.index < old_uavs_len);
+ } else {
+ assert(gop.index >= old_uavs_len);
+ }
+ }
+ try c.updateNewUavs(pt, old_uavs_len);
+
+ try c.type_pool.flushPending(pt, .{ .c = c });
+}
+
+/// Unlike `updateNav` and `updateFunc`, this does *not* add newly-discovered UAVs to `c.uavs`. The
+/// caller is instead responsible for doing that (by iterating `rendered_decl.need_uavs`). However,
+/// this function *does* still add newly-discovered *types* to `c.type_pool`.
+///
+/// This function does not accept an alignment for the UAV, because the alignment needed on a UAV is
+/// not known until `flush` (since we need to have seen all uses of the UAV first). Instead, `flush`
+/// will prefix the UAV definition with an appropriate alignment annotation if necessary.
+fn updateUav(
+ c: *C,
+ pt: Zcu.PerThread,
+ val: Value,
+ rendered_decl: *RenderedDecl,
+) Allocator.Error!void {
+ const tracy = trace(@src());
+ defer tracy.end();
+
+ const gpa = c.base.comp.gpa;
+
+ var arena: std.heap.ArenaAllocator = .init(gpa);
+ defer arena.deinit();
+
+ var dg: codegen.DeclGen = .{
+ .gpa = gpa,
+ .arena = arena.allocator(),
+ .pt = pt,
+ .mod = pt.zcu.root_mod,
+ .error_msg = null,
+ .owner_nav = .none,
+ .is_naked_fn = false,
+ .expected_block = null,
+ .ctype_deps = .empty,
+ .uavs = .empty,
};
- object.dg.fwd_decl = .initOwnedSlice(gpa, self.fwd_decl_buf);
- object.code = .initOwnedSlice(gpa, self.code_buf);
defer {
- object.dg.uavs.deinit(gpa);
- ctype_pool.* = object.dg.ctype_pool.move();
- ctype_pool.freeUnusedCapacity(gpa);
-
- self.fwd_decl_buf = object.dg.fwd_decl.toArrayList().allocatedSlice();
- self.code_buf = object.code.toArrayList().allocatedSlice();
- self.scratch_buf = object.dg.scratch.allocatedSlice();
+ rendered_decl.need_uavs = dg.uavs.move();
+ dg.ctype_deps.deinit(gpa);
}
- codegen.genDecl(&object) catch |err| switch (err) {
- error.AnalysisFail => switch (zcu.codegenFailMsg(nav_index, object.dg.error_msg.?)) {
- error.CodegenFail => return,
- error.OutOfMemory => |e| return e,
- },
- error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
+ rendered_decl.fwd_decl = fwd_decl: {
+ var aw: std.Io.Writer.Allocating = .fromArrayList(gpa, &c.string_bytes);
+ defer c.string_bytes = aw.toArrayList();
+ const start = aw.written().len;
+ codegen.genDeclValueFwd(&dg, &aw.writer, .{
+ .name = .{ .constant = val },
+ .@"const" = true,
+ .@"threadlocal" = false,
+ .init_val = val,
+ }) catch |err| switch (err) {
+ error.AnalysisFail => {
+ @panic("TODO: CBE error.AnalysisFail on uav");
+ },
+ error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
+ };
+ break :fwd_decl .{
+ .start = @intCast(start),
+ .len = @intCast(aw.written().len - start),
+ };
};
- gop.value_ptr.fwd_decl = try self.addString(object.dg.fwd_decl.written());
- gop.value_ptr.code = try self.addString(object.code.written());
- try self.addUavsFromCodegen(&object.dg.uavs);
+
+ rendered_decl.code = code: {
+ var aw: std.Io.Writer.Allocating = .fromArrayList(gpa, &c.string_bytes);
+ defer c.string_bytes = aw.toArrayList();
+ const start = aw.written().len;
+ codegen.genDeclValue(&dg, &aw.writer, .{
+ .name = .{ .constant = val },
+ .@"const" = true,
+ .@"threadlocal" = false,
+ .init_val = val,
+ }) catch |err| switch (err) {
+ error.AnalysisFail => {
+ @panic("TODO: CBE error.AnalysisFail on uav");
+ },
+ error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
+ };
+ break :code .{
+ .start = @intCast(start),
+ .len = @intCast(aw.written().len - start),
+ };
+ };
+
+ rendered_decl.ctype_deps = try c.addCTypeDependencies(pt, &dg.ctype_deps);
}
-pub fn updateLineNumber(self: *C, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void {
- // The C backend does not have the ability to fix line numbers without re-generating
- // the entire Decl.
- _ = self;
+pub fn updateLineNumber(c: *C, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) error{}!void {
+ // The C backend does not currently emit "#line" directives. Even if it did, it would not be
+ // capable of updating those line numbers without re-generating the entire declaration.
+ _ = c;
_ = pt;
_ = ti_id;
}
-fn abiDefines(w: *std.Io.Writer, target: *const std.Target) !void {
- switch (target.abi) {
- .msvc, .itanium => try w.writeAll("#define ZIG_TARGET_ABI_MSVC\n"),
- else => {},
- }
- try w.print("#define ZIG_TARGET_MAX_INT_ALIGNMENT {d}\n", .{
- target.cMaxIntAlignment(),
- });
-}
-
-pub fn flush(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
- _ = arena; // Has the same lifetime as the call to Compilation.update.
-
+pub fn flush(c: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
const tracy = trace(@src());
defer tracy.end();
const sub_prog_node = prog_node.start("Flush Module", 0);
defer sub_prog_node.end();
- const comp = self.base.comp;
+ const comp = c.base.comp;
const diags = &comp.link_diags;
const gpa = comp.gpa;
const io = comp.io;
- const zcu = self.base.comp.zcu.?;
+ const zcu = c.base.comp.zcu.?;
const ip = &zcu.intern_pool;
+ const target = zcu.getTarget();
const pt: Zcu.PerThread = .activate(zcu, tid);
defer pt.deactivate();
+ // If it's somehow not made it into the pool, we need to generate the type `[:0]const u8` for
+ // error names.
+ const slice_const_u8_sentinel_0_pool_index = try c.type_pool.get(
+ pt,
+ .{ .c = c },
+ .slice_const_u8_sentinel_0_type,
+ );
+ try c.type_pool.flushPending(pt, .{ .c = c });
+
+ // Find the set of referenced NAVs; these are the ones we'll emit. It is important in this
+ // backend that we only emit referenced NAVs, because other ones may contain code from past
+ // incremental updates which is invalid C (due to e.g. types changing). Machine code backends
+ // don't have this problem because there are, of course, no type checking performed when you
+ // *execute* a binary!
+ var need_navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void) = .empty;
+ defer need_navs.deinit(gpa);
{
- var i: usize = 0;
- while (i < self.uavs.count()) : (i += 1) {
- try self.updateUav(pt, i);
+ const unit_references = try zcu.resolveReferences();
+ for (c.navs.keys()) |nav| {
+ const nav_val = ip.getNav(nav).status.fully_resolved.val;
+ const check_unit: ?InternPool.AnalUnit = switch (ip.indexToKey(nav_val)) {
+ else => .wrap(.{ .nav_val = nav }),
+ .func => .wrap(.{ .func = nav_val }),
+ // TODO: this is a hack to deal with the fact that there's currently no good way to
+ // know which `extern`s are alive. This can and will break in certain patterns of
+ // incremental update. We kind of need to think a bit more about how the frontend
+ // actually represents `extern`, it's a bit awkward right now.
+ .@"extern" => null,
+ };
+ if (check_unit) |u| {
+ if (!unit_references.contains(u)) continue;
+ }
+ try need_navs.putNoClobber(gpa, nav, {});
}
}
- // This code path happens exclusively with -ofmt=c. The flush logic for
- // emit-h is in `flushEmitH` below.
+ // Using our knowledge of which NAVs are referenced, we now need to discover the set of UAVs and
+ // C types which are referenced (and hence must be emitted). As above, this is necessary to make
+ // sure we only emit valid C code.
+ //
+ // At the same time, we will discover the set of lazy functions which are referenced.
+
+ var need_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment) = .empty;
+ defer need_uavs.deinit(gpa);
+
+ var need_types: std.AutoArrayHashMapUnmanaged(link.ConstPool.Index, void) = .empty;
+ defer need_types.deinit(gpa);
+ var need_errunion_types: std.AutoArrayHashMapUnmanaged(link.ConstPool.Index, void) = .empty;
+ defer need_errunion_types.deinit(gpa);
+ var need_aligned_types: std.AutoArrayHashMapUnmanaged(link.ConstPool.Index, u64) = .empty;
+ defer need_aligned_types.deinit(gpa);
+
+ var need_tag_name_funcs: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .empty;
+ defer need_tag_name_funcs.deinit(gpa);
+
+ var need_never_tail_funcs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void) = .empty;
+ defer need_never_tail_funcs.deinit(gpa);
+
+ var need_never_inline_funcs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void) = .empty;
+ defer need_never_inline_funcs.deinit(gpa);
+
+ // As mentioned above, we need this type for error names.
+ try need_types.put(gpa, slice_const_u8_sentinel_0_pool_index, {});
+
+ // Every exported NAV should have been discovered via `zcu.resolveReferences`...
+ for (c.exported_navs.keys()) |nav| assert(need_navs.contains(nav));
+ // ...but we *do* need to add exported UAVs to the set.
+ try need_uavs.ensureUnusedCapacity(gpa, c.exported_uavs.count());
+ for (c.exported_uavs.keys()) |uav| {
+ const gop = need_uavs.getOrPutAssumeCapacity(uav);
+ if (!gop.found_existing) gop.value_ptr.* = .none;
+ }
+
+ // For every referenced NAV, some UAVs, C types, and lazy functions may be referenced.
+ for (need_navs.keys()) |nav| {
+ const rendered = c.navs.getPtr(nav).?;
+ try mergeNeededCTypes(
+ c,
+ &need_types,
+ &need_errunion_types,
+ &need_aligned_types,
+ &rendered.ctype_deps,
+ );
+ try mergeNeededUavs(zcu, &need_uavs, &rendered.need_uavs);
+
+ try need_tag_name_funcs.ensureUnusedCapacity(gpa, rendered.need_tag_name_funcs.count());
+ for (rendered.need_tag_name_funcs.keys()) |enum_type| {
+ need_tag_name_funcs.putAssumeCapacity(enum_type, {});
+ }
+
+ try need_never_tail_funcs.ensureUnusedCapacity(gpa, rendered.need_never_tail_funcs.count());
+ for (rendered.need_never_tail_funcs.keys()) |fn_nav| {
+ need_never_tail_funcs.putAssumeCapacity(fn_nav, {});
+ }
- var f: Flush = .{
- .ctype_pool = .empty,
- .ctype_global_from_decl_map = .empty,
- .ctypes = .empty,
+ try need_never_inline_funcs.ensureUnusedCapacity(gpa, rendered.need_never_inline_funcs.count());
+ for (rendered.need_never_inline_funcs.keys()) |fn_nav| {
+ need_never_inline_funcs.putAssumeCapacity(fn_nav, {});
+ }
+ }
+
+ // UAVs may reference other UAVs or C types.
+ {
+ var index: usize = 0;
+ while (need_uavs.count() > index) : (index += 1) {
+ const val = need_uavs.keys()[index];
+ const rendered = c.uavs.getPtr(val).?;
+ try mergeNeededCTypes(
+ c,
+ &need_types,
+ &need_errunion_types,
+ &need_aligned_types,
+ &rendered.ctype_deps,
+ );
+ try mergeNeededUavs(zcu, &need_uavs, &rendered.need_uavs);
+ }
+ }
+
+ // Finally, C types may reference other C types.
+ {
+ var index: usize = 0;
+ var errunion_index: usize = 0;
+ var aligned_index: usize = 0;
+ while (true) {
+ if (index < need_types.count()) {
+ const pool_index = need_types.keys()[index];
+ const rendered = &c.types.items[@intFromEnum(pool_index)];
+ try mergeNeededCTypes(
+ c,
+ &need_types,
+ &need_errunion_types,
+ &need_aligned_types,
+ &rendered.definition_deps, // we're tasked with emitting the *definition* of this type
+ );
+ index += 1;
+ continue;
+ }
+
+ if (errunion_index < need_errunion_types.count()) {
+ const payload_pool_index = need_errunion_types.keys()[errunion_index];
+ const rendered = &c.types.items[@intFromEnum(payload_pool_index)];
+ try mergeNeededCTypes(
+ c,
+ &need_types,
+ &need_errunion_types,
+ &need_aligned_types,
+ &rendered.deps, // the error union type requires emitting this type's *name*
+ );
+ errunion_index += 1;
+ continue;
+ }
+
+ if (aligned_index < need_aligned_types.count()) {
+ const pool_index = need_aligned_types.keys()[aligned_index];
+ const rendered = &c.types.items[@intFromEnum(pool_index)];
+ try mergeNeededCTypes(
+ c,
+ &need_types,
+ &need_errunion_types,
+ &need_aligned_types,
+ &rendered.deps, // an aligned typedef requires emitting this type's *name*
+ );
+ aligned_index += 1;
+ continue;
+ }
+
+ break;
+ }
+ }
+
+ // Now that we know which types are required, generate aligned typedefs. One buffer per aligned
+ // type, with *all* aligned typedefs for that type.
+ const aligned_type_strings = try arena.alloc([]const u8, need_aligned_types.count());
+ {
+ var aw: std.Io.Writer.Allocating = .init(gpa);
+ defer aw.deinit();
+ var unused_deps: codegen.CType.Dependencies = .empty;
+ defer unused_deps.deinit(gpa);
+ for (
+ need_aligned_types.keys(),
+ need_aligned_types.values(),
+ aligned_type_strings,
+ ) |pool_index, align_mask, *str_out| {
+ const ty: Type = .fromInterned(pool_index.val(&c.type_pool));
+ const has_layout = c.types.items[@intFromEnum(pool_index)].errunion_definition.len > 0;
+ for (0..@bitSizeOf(@TypeOf(align_mask))) |bit_index| {
+ switch (@as(u1, @truncate(align_mask >> @intCast(bit_index)))) {
+ 0 => continue,
+ 1 => {},
+ }
+ codegen.CType.render_defs.defineAligned(
+ ty,
+ .fromLog2Units(@intCast(bit_index)),
+ has_layout,
+ &unused_deps,
+ arena,
+ &aw.writer,
+ pt,
+ ) catch |err| switch (err) {
+ error.WriteFailed => return error.OutOfMemory,
+ error.OutOfMemory => |e| return e,
+ };
+ }
+ str_out.* = try arena.dupe(u8, aw.written());
+ aw.clearRetainingCapacity();
+ }
+ }
- .lazy_ctype_pool = .empty,
- .lazy_fns = .empty,
- .lazy_fwd_decl = .empty,
- .lazy_code = .empty,
+ // We have discovered the full set of NAVs, UAVs, and types we need to emit, and will now begin
+ // to build the output buffer. Our strategy is to emit the C source in this order:
+ //
+ // * ABI defines and `#include "zig.h"`
+ // * Big-int type definitions
+ // * Other CType definitions (traversing the dependency graph to sort topologically)
+ // * Global assembly
+ // * UAV exports
+ // * NAV exports
+ // * UAV forward declarations
+ // * NAV forward declarations
+ // * Lazy declarations (error names; @tagName functions; never_tail/never_inline wrappers)
+ // * UAV definitions
+ // * NAV definitions
+ //
+ // Most of these sections are order-independent within themselves, with the exception of the
+ // type definitions, which must be ordered to avoid a struct/union from embedding a type which
+ // is currently incomplete.
+ //
+ // When emitting UAV forward declarations, if the UAV requires alignment, we must prefix it with
+ // an alignment annotation. We couldn't emit the alignment into the UAV's `RenderedDecl` because
+ // we couldn't have known the required alignment until now!
- .all_buffers = .empty,
- .file_size = 0,
- };
+ var f: Flush = .{ .all_buffers = .empty, .file_size = 0 };
defer f.deinit(gpa);
- var abi_defines_aw: std.Io.Writer.Allocating = .init(gpa);
- defer abi_defines_aw.deinit();
- abiDefines(&abi_defines_aw.writer, zcu.getTarget()) catch |err| switch (err) {
- error.WriteFailed => return error.OutOfMemory,
- };
+ // We know exactly what we'll be emitting, so can reserve capacity for all of our buffers!
- // Covers defines, zig.h, ctypes, asm, lazy fwd.
- try f.all_buffers.ensureUnusedCapacity(gpa, 5);
+ try f.all_buffers.ensureUnusedCapacity(gpa, 3 + // ABI defines and `#include "zig.h"`
+ 1 + // Big-int type definitions
+ need_types.count() + // `RenderedType.fwd_decl` (worst-case)
+ need_types.count() + // `RenderedType.definition`
+ need_errunion_types.count() + // `RenderedType.errunion_fwd_decl` (worst-case)
+ need_errunion_types.count() + // `RenderedType.errunion_definition`
+ need_aligned_types.count() + // `aligned_type_strings`
+ 1 + // Global assembly
+ c.exported_uavs.count() + // UAV export block
+ c.exported_navs.count() + // NAV export block
+ need_uavs.count() + // UAV forward declarations
+ need_navs.count() + // NAV forward declarations
+ 1 + // Lazy declarations
+ need_uavs.count() * 3 + // UAV definitions ("static ", "zig_align(4)", "")
+ need_navs.count() * 2); // NAV definitions ("static ", "")
- f.appendBufAssumeCapacity(abi_defines_aw.written());
- f.appendBufAssumeCapacity(zig_h);
+ // ABI defines and `#include "zig.h"`
+ switch (target.abi) {
+ .msvc, .itanium => f.appendBufAssumeCapacity("#define ZIG_TARGET_ABI_MSVC\n"),
+ else => {},
+ }
+ f.appendBufAssumeCapacity(try std.fmt.allocPrint(
+ arena,
+ "#define ZIG_TARGET_MAX_INT_ALIGNMENT {d}\n",
+ .{target.cMaxIntAlignment()},
+ ));
+ f.appendBufAssumeCapacity(
+ \\#include "zig.h"
+ \\
+ );
- const ctypes_index = f.all_buffers.items.len;
- f.all_buffers.items.len += 1;
+ // Big-int type definitions
+ var bigint_aw: std.Io.Writer.Allocating = .init(gpa);
+ defer bigint_aw.deinit();
+ for (c.bigint_types.keys()) |bigint| {
+ codegen.CType.render_defs.defineBigInt(bigint, &bigint_aw.writer, zcu) catch |err| switch (err) {
+ error.WriteFailed => return error.OutOfMemory,
+ };
+ }
+ f.appendBufAssumeCapacity(bigint_aw.written());
+ // CType definitions
+ {
+ var ft: FlushTypes = .{
+ .c = c,
+ .f = &f,
+ .aligned_types = &need_aligned_types,
+ .aligned_type_strings = aligned_type_strings,
+ .status = .empty,
+ .errunion_status = .empty,
+ .aligned_status = .empty,
+ };
+ defer {
+ ft.status.deinit(gpa);
+ ft.errunion_status.deinit(gpa);
+ ft.aligned_status.deinit(gpa);
+ }
+ try ft.status.ensureUnusedCapacity(gpa, need_types.count());
+ try ft.errunion_status.ensureUnusedCapacity(gpa, need_errunion_types.count());
+ try ft.aligned_status.ensureUnusedCapacity(gpa, need_aligned_types.count());
+
+ for (need_types.keys()) |pool_index| {
+ ft.doType(pool_index);
+ }
+ for (need_errunion_types.keys()) |pool_index| {
+ ft.doErrunionType(pool_index);
+ }
+ for (need_aligned_types.keys()) |pool_index| {
+ ft.doAlignedTypeFwd(pool_index);
+ }
+ }
+
+ // Global assembly
var asm_aw: std.Io.Writer.Allocating = .init(gpa);
defer asm_aw.deinit();
codegen.genGlobalAsm(zcu, &asm_aw.writer) catch |err| switch (err) {
@@ -424,435 +1059,228 @@ pub fn flush(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.P
};
f.appendBufAssumeCapacity(asm_aw.written());
- const lazy_index = f.all_buffers.items.len;
- f.all_buffers.items.len += 1;
+ var export_names: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void) = .empty;
+ defer export_names.deinit(gpa);
+ try export_names.ensureTotalCapacity(gpa, @intCast(zcu.single_exports.count()));
+ for (zcu.single_exports.values()) |export_index| {
+ export_names.putAssumeCapacity(export_index.ptr(zcu).opts.name, {});
+ }
+ for (zcu.multi_exports.values()) |info| {
+ try export_names.ensureUnusedCapacity(gpa, info.len);
+ for (zcu.all_exports.items[info.index..][0..info.len]) |@"export"| {
+ export_names.putAssumeCapacity(@"export".opts.name, {});
+ }
+ }
- try f.lazy_ctype_pool.init(gpa);
- try self.flushErrDecls(pt, &f);
+ // UAV export block
+ for (c.exported_uavs.values()) |code| {
+ f.appendBufAssumeCapacity(code.get(c));
+ }
- // Unlike other backends, the .c code we are emitting has order-dependent decls.
- // `CType`s, forward decls, and non-functions first.
+ // NAV export block
+ for (c.exported_navs.values()) |code| {
+ f.appendBufAssumeCapacity(code.get(c));
+ }
- {
- var export_names: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void) = .empty;
- defer export_names.deinit(gpa);
- try export_names.ensureTotalCapacity(gpa, @intCast(zcu.single_exports.count()));
- for (zcu.single_exports.values()) |export_index| {
- export_names.putAssumeCapacity(export_index.ptr(zcu).opts.name, {});
- }
- for (zcu.multi_exports.values()) |info| {
- try export_names.ensureUnusedCapacity(gpa, info.len);
- for (zcu.all_exports.items[info.index..][0..info.len]) |@"export"| {
- export_names.putAssumeCapacity(@"export".opts.name, {});
- }
+ // UAV forward declarations
+ for (need_uavs.keys()) |val| {
+ if (c.exported_uavs.contains(val)) continue; // the export was the declaration
+ const fwd_decl = c.uavs.getPtr(val).?.fwd_decl;
+ f.appendBufAssumeCapacity(fwd_decl.get(c));
+ }
+
+ // NAV forward declarations
+ for (need_navs.keys()) |nav| {
+ if (c.exported_navs.contains(nav)) continue; // the export was the declaration
+ if (ip.getNav(nav).getExtern(ip)) |e| {
+ if (export_names.contains(e.name)) continue;
}
+ const fwd_decl = c.navs.getPtr(nav).?.fwd_decl;
+ f.appendBufAssumeCapacity(fwd_decl.get(c));
+ }
- for (self.uavs.keys(), self.uavs.values()) |uav, *av_block| try self.flushAvBlock(
- pt,
- zcu.root_mod,
- &f,
- av_block,
- self.exported_uavs.getPtr(uav),
- export_names,
- .none,
+ // Lazy declarations
+ var lazy_decls_aw: std.Io.Writer.Allocating = .init(gpa);
+ defer lazy_decls_aw.deinit();
+ {
+ var lazy_dg: codegen.DeclGen = .{
+ .gpa = gpa,
+ .arena = arena,
+ .pt = pt,
+ .mod = pt.zcu.root_mod,
+ .owner_nav = .none,
+ .is_naked_fn = false,
+ .expected_block = null,
+ .error_msg = null,
+ .ctype_deps = .empty,
+ .uavs = .empty,
+ };
+ defer {
+ assert(lazy_dg.uavs.count() == 0);
+ lazy_dg.ctype_deps.deinit(gpa);
+ }
+ const slice_const_u8_sentinel_0_cty: codegen.CType = try .lower(
+ .slice_const_u8_sentinel_0,
+ &lazy_dg.ctype_deps,
+ arena,
+ zcu,
);
-
- for (self.navs.keys(), self.navs.values()) |nav, *av_block| try self.flushAvBlock(
- pt,
- zcu.navFileScope(nav).mod.?,
- &f,
- av_block,
- self.exported_navs.getPtr(nav),
- export_names,
- if (ip.getNav(nav).getExtern(ip) != null)
- ip.getNav(nav).name.toOptional()
- else
- .none,
+ const slice_const_u8_sentinel_0_name = try std.fmt.allocPrint(
+ arena,
+ "{f}",
+ .{slice_const_u8_sentinel_0_cty.fmtTypeName(zcu)},
);
+ codegen.genErrDecls(zcu, &lazy_decls_aw.writer, slice_const_u8_sentinel_0_name) catch |err| switch (err) {
+ error.WriteFailed => return error.OutOfMemory,
+ };
+ for (need_tag_name_funcs.keys()) |enum_ty_ip| {
+ const enum_ty: Type = .fromInterned(enum_ty_ip);
+ const enum_cty: codegen.CType = try .lower(
+ enum_ty,
+ &lazy_dg.ctype_deps,
+ arena,
+ zcu,
+ );
+ codegen.genTagNameFn(
+ zcu,
+ &lazy_decls_aw.writer,
+ slice_const_u8_sentinel_0_name,
+ enum_ty,
+ try std.fmt.allocPrint(arena, "{f}", .{enum_cty.fmtTypeName(zcu)}),
+ ) catch |err| switch (err) {
+ error.WriteFailed => return error.OutOfMemory,
+ };
+ }
+ for (need_never_tail_funcs.keys()) |fn_nav| {
+ codegen.genLazyCallModifierFn(&lazy_dg, fn_nav, .never_tail, &lazy_decls_aw.writer) catch |err| switch (err) {
+ error.WriteFailed => return error.OutOfMemory,
+ error.OutOfMemory => |e| return e,
+ error.AnalysisFail => unreachable,
+ };
+ }
+ for (need_never_inline_funcs.keys()) |fn_nav| {
+ codegen.genLazyCallModifierFn(&lazy_dg, fn_nav, .never_inline, &lazy_decls_aw.writer) catch |err| switch (err) {
+ error.WriteFailed => return error.OutOfMemory,
+ error.OutOfMemory => |e| return e,
+ error.AnalysisFail => unreachable,
+ };
+ }
}
+ f.appendBufAssumeCapacity(lazy_decls_aw.written());
- {
- // We need to flush lazy ctypes after flushing all decls but before flushing any decl ctypes.
- // This ensures that every lazy CType.Index exactly matches the global CType.Index.
- try f.ctype_pool.init(gpa);
- try self.flushCTypes(zcu, &f, .flush, &f.lazy_ctype_pool);
-
- for (self.uavs.keys(), self.uavs.values()) |uav, av_block| {
- try self.flushCTypes(zcu, &f, .{ .uav = uav }, &av_block.ctype_pool);
+ // UAV definitions
+ for (need_uavs.keys(), need_uavs.values()) |val, overalign| {
+ const code = c.uavs.getPtr(val).?.code;
+ if (code.len == 0) continue;
+ if (!c.exported_uavs.contains(val)) {
+ f.appendBufAssumeCapacity("static ");
}
-
- for (self.navs.keys(), self.navs.values()) |nav, av_block| {
- try self.flushCTypes(zcu, &f, .{ .nav = nav }, &av_block.ctype_pool);
+ if (overalign != .none) {
+ // As long as `Alignment` isn't too big, it's reasonable to just generate all possible
+ // alignment annotations statically into a LUT, which avoids allocating strings on this
+ // path.
+ comptime assert(@bitSizeOf(Alignment) < 8);
+ const table_len = (1 << @bitSizeOf(Alignment)) - 1;
+ const table: [table_len][]const u8 = comptime table: {
+ @setEvalBranchQuota(16_000);
+ var table: [table_len][]const u8 = undefined;
+ for (&table, 0..) |*str, log2_align| {
+ const byte_align = Alignment.fromLog2Units(log2_align).toByteUnits().?;
+ str.* = std.fmt.comptimePrint("zig_align({d}) ", .{byte_align});
+ }
+ break :table table;
+ };
+ f.appendBufAssumeCapacity(table[overalign.toLog2Units()]);
}
+ f.appendBufAssumeCapacity(code.get(c));
}
- f.all_buffers.items[ctypes_index] = f.ctypes.items;
- f.file_size += f.ctypes.items.len;
-
- f.all_buffers.items[lazy_index] = f.lazy_fwd_decl.items;
- f.file_size += f.lazy_fwd_decl.items.len;
-
- // Now the code.
- try f.all_buffers.ensureUnusedCapacity(gpa, 1 + (self.uavs.count() + self.navs.count()) * 2);
- f.appendBufAssumeCapacity(f.lazy_code.items);
- for (self.uavs.keys(), self.uavs.values()) |uav, av_block| f.appendCodeAssumeCapacity(
- if (self.exported_uavs.contains(uav)) .default else switch (ip.indexToKey(uav)) {
- .@"extern" => .zig_extern,
- else => .static,
- },
- self.getString(av_block.code),
- );
- for (self.navs.keys(), self.navs.values()) |nav, av_block| f.appendCodeAssumeCapacity(storage: {
- if (self.exported_navs.contains(nav)) break :storage .default;
- if (ip.getNav(nav).getExtern(ip) != null) break :storage .zig_extern;
- break :storage .static;
- }, self.getString(av_block.code));
+ // NAV definitions
+ for (need_navs.keys()) |nav| {
+ const code = c.navs.getPtr(nav).?.code;
+ if (code.len == 0) continue;
+ if (!c.exported_navs.contains(nav)) {
+ const is_extern = ip.getNav(nav).getExtern(ip) != null;
+ f.appendBufAssumeCapacity(if (is_extern) "zig_extern " else "static ");
+ }
+ f.appendBufAssumeCapacity(code.get(c));
+ }
- const file = self.base.file.?;
+ // We've collected all of our buffers; it's now time to actually write the file!
+ const file = c.base.file.?;
file.setLength(io, f.file_size) catch |err| return diags.fail("failed to allocate file: {t}", .{err});
var fw = file.writer(io, &.{});
var w = &fw.interface;
w.writeVecAll(f.all_buffers.items) catch |err| switch (err) {
error.WriteFailed => return diags.fail("failed to write to '{f}': {s}", .{
- std.fmt.alt(self.base.emit, .formatEscapeChar), @errorName(fw.err.?),
+ std.fmt.alt(c.base.emit, .formatEscapeChar), @errorName(fw.err.?),
}),
};
}
const Flush = struct {
- ctype_pool: codegen.CType.Pool,
- ctype_global_from_decl_map: std.ArrayList(codegen.CType),
- ctypes: std.ArrayList(u8),
-
- lazy_ctype_pool: codegen.CType.Pool,
- lazy_fns: LazyFns,
- lazy_fwd_decl: std.ArrayList(u8),
- lazy_code: std.ArrayList(u8),
-
/// We collect a list of buffers to write, and write them all at once with pwritev 😎
all_buffers: std.ArrayList([]const u8),
/// Keeps track of the total bytes of `all_buffers`.
file_size: u64,
- const LazyFns = std.AutoHashMapUnmanaged(codegen.LazyFnKey, void);
-
fn appendBufAssumeCapacity(f: *Flush, buf: []const u8) void {
if (buf.len == 0) return;
f.all_buffers.appendAssumeCapacity(buf);
f.file_size += buf.len;
}
- fn appendCodeAssumeCapacity(f: *Flush, storage: enum { default, zig_extern, static }, code: []const u8) void {
- if (code.len == 0) return;
- f.appendBufAssumeCapacity(switch (storage) {
- .default => "\n",
- .zig_extern => "\nzig_extern ",
- .static => "\nstatic ",
- });
- f.appendBufAssumeCapacity(code);
- }
-
fn deinit(f: *Flush, gpa: Allocator) void {
- f.ctype_pool.deinit(gpa);
- assert(f.ctype_global_from_decl_map.items.len == 0);
- f.ctype_global_from_decl_map.deinit(gpa);
- f.ctypes.deinit(gpa);
- f.lazy_ctype_pool.deinit(gpa);
- f.lazy_fns.deinit(gpa);
- f.lazy_fwd_decl.deinit(gpa);
- f.lazy_code.deinit(gpa);
f.all_buffers.deinit(gpa);
}
};
-const FlushDeclError = error{
- OutOfMemory,
-};
-
-fn flushCTypes(
- self: *C,
- zcu: *Zcu,
- f: *Flush,
- pass: codegen.DeclGen.Pass,
- decl_ctype_pool: *const codegen.CType.Pool,
-) FlushDeclError!void {
- const gpa = self.base.comp.gpa;
- const global_ctype_pool = &f.ctype_pool;
-
- const global_from_decl_map = &f.ctype_global_from_decl_map;
- assert(global_from_decl_map.items.len == 0);
- try global_from_decl_map.ensureTotalCapacity(gpa, decl_ctype_pool.items.len);
- defer global_from_decl_map.clearRetainingCapacity();
-
- var ctypes_aw: std.Io.Writer.Allocating = .fromArrayList(gpa, &f.ctypes);
- const ctypes_bw = &ctypes_aw.writer;
- defer f.ctypes = ctypes_aw.toArrayList();
-
- for (0..decl_ctype_pool.items.len) |decl_ctype_pool_index| {
- const PoolAdapter = struct {
- global_from_decl_map: []const codegen.CType,
- pub fn eql(pool_adapter: @This(), decl_ctype: codegen.CType, global_ctype: codegen.CType) bool {
- return if (decl_ctype.toPoolIndex()) |decl_pool_index|
- decl_pool_index < pool_adapter.global_from_decl_map.len and
- pool_adapter.global_from_decl_map[decl_pool_index].eql(global_ctype)
- else
- decl_ctype.index == global_ctype.index;
- }
- pub fn copy(pool_adapter: @This(), decl_ctype: codegen.CType) codegen.CType {
- return if (decl_ctype.toPoolIndex()) |decl_pool_index|
- pool_adapter.global_from_decl_map[decl_pool_index]
- else
- decl_ctype;
- }
- };
- const decl_ctype = codegen.CType.fromPoolIndex(decl_ctype_pool_index);
- const global_ctype, const found_existing = try global_ctype_pool.getOrPutAdapted(
- gpa,
- decl_ctype_pool,
- decl_ctype,
- PoolAdapter{ .global_from_decl_map = global_from_decl_map.items },
- );
- global_from_decl_map.appendAssumeCapacity(global_ctype);
- codegen.genTypeDecl(
- zcu,
- ctypes_bw,
- global_ctype_pool,
- global_ctype,
- pass,
- decl_ctype_pool,
- decl_ctype,
- found_existing,
- ) catch |err| switch (err) {
- error.WriteFailed => return error.OutOfMemory,
- };
- }
-}
-
-fn flushErrDecls(self: *C, pt: Zcu.PerThread, f: *Flush) FlushDeclError!void {
- const gpa = self.base.comp.gpa;
-
- var object: codegen.Object = .{
- .dg = .{
- .gpa = gpa,
- .pt = pt,
- .mod = pt.zcu.root_mod,
- .error_msg = null,
- .pass = .flush,
- .is_naked_fn = false,
- .expected_block = null,
- .fwd_decl = undefined,
- .ctype_pool = f.lazy_ctype_pool,
- .scratch = .initBuffer(self.scratch_buf),
- .uavs = .empty,
- },
- .code_header = undefined,
- .code = undefined,
- .indent_counter = 0,
- };
- object.dg.fwd_decl = .fromArrayList(gpa, &f.lazy_fwd_decl);
- object.code = .fromArrayList(gpa, &f.lazy_code);
- defer {
- object.dg.uavs.deinit(gpa);
- f.lazy_ctype_pool = object.dg.ctype_pool.move();
- f.lazy_ctype_pool.freeUnusedCapacity(gpa);
-
- f.lazy_fwd_decl = object.dg.fwd_decl.toArrayList();
- f.lazy_code = object.code.toArrayList();
- self.scratch_buf = object.dg.scratch.allocatedSlice();
- }
-
- codegen.genErrDecls(&object) catch |err| switch (err) {
- error.AnalysisFail => unreachable,
- error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
- };
-
- try self.addUavsFromCodegen(&object.dg.uavs);
-}
-
-fn flushLazyFn(
- self: *C,
- pt: Zcu.PerThread,
- mod: *Module,
- f: *Flush,
- lazy_ctype_pool: *const codegen.CType.Pool,
- lazy_fn: codegen.LazyFnMap.Entry,
-) FlushDeclError!void {
- const gpa = self.base.comp.gpa;
-
- var object: codegen.Object = .{
- .dg = .{
- .gpa = gpa,
- .pt = pt,
- .mod = mod,
- .error_msg = null,
- .pass = .flush,
- .is_naked_fn = false,
- .expected_block = null,
- .fwd_decl = undefined,
- .ctype_pool = f.lazy_ctype_pool,
- .scratch = .initBuffer(self.scratch_buf),
- .uavs = .empty,
- },
- .code_header = undefined,
- .code = undefined,
- .indent_counter = 0,
- };
- object.dg.fwd_decl = .fromArrayList(gpa, &f.lazy_fwd_decl);
- object.code = .fromArrayList(gpa, &f.lazy_code);
- defer {
- // If this assert trips just handle the anon_decl_deps the same as
- // `updateFunc()` does.
- assert(object.dg.uavs.count() == 0);
- f.lazy_ctype_pool = object.dg.ctype_pool.move();
- f.lazy_ctype_pool.freeUnusedCapacity(gpa);
-
- f.lazy_fwd_decl = object.dg.fwd_decl.toArrayList();
- f.lazy_code = object.code.toArrayList();
- self.scratch_buf = object.dg.scratch.allocatedSlice();
- }
-
- codegen.genLazyFn(&object, lazy_ctype_pool, lazy_fn) catch |err| switch (err) {
- error.AnalysisFail => unreachable,
- error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
- };
-}
-
-fn flushLazyFns(
- self: *C,
- pt: Zcu.PerThread,
- mod: *Module,
- f: *Flush,
- lazy_ctype_pool: *const codegen.CType.Pool,
- lazy_fns: codegen.LazyFnMap,
-) FlushDeclError!void {
- const gpa = self.base.comp.gpa;
- try f.lazy_fns.ensureUnusedCapacity(gpa, @intCast(lazy_fns.count()));
-
- var it = lazy_fns.iterator();
- while (it.next()) |entry| {
- const gop = f.lazy_fns.getOrPutAssumeCapacity(entry.key_ptr.*);
- if (gop.found_existing) continue;
- gop.value_ptr.* = {};
- try self.flushLazyFn(pt, mod, f, lazy_ctype_pool, entry);
- }
-}
-
-fn flushAvBlock(
- self: *C,
- pt: Zcu.PerThread,
- mod: *Module,
- f: *Flush,
- av_block: *const AvBlock,
- exported_block: ?*const ExportedBlock,
- export_names: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void),
- extern_name: InternPool.OptionalNullTerminatedString,
-) FlushDeclError!void {
- const gpa = self.base.comp.gpa;
- try self.flushLazyFns(pt, mod, f, &av_block.ctype_pool, av_block.lazy_fns);
- try f.all_buffers.ensureUnusedCapacity(gpa, 1);
- // avoid emitting extern decls that are already exported
- if (extern_name.unwrap()) |name| if (export_names.contains(name)) return;
- f.appendBufAssumeCapacity(self.getString(if (exported_block) |exported|
- exported.fwd_decl
- else
- av_block.fwd_decl));
-}
-
-pub fn flushEmitH(zcu: *Zcu) !void {
- const tracy = trace(@src());
- defer tracy.end();
-
- if (true) return; // emit-h is regressed
-
- const emit_h = zcu.emit_h orelse return;
- const io = zcu.comp.io;
-
- // We collect a list of buffers to write, and write them all at once with pwritev 😎
- const num_buffers = emit_h.decl_table.count() + 1;
- var all_buffers = try std.array_list.Managed(std.posix.iovec_const).initCapacity(zcu.gpa, num_buffers);
- defer all_buffers.deinit();
-
- var file_size: u64 = zig_h.len;
- if (zig_h.len != 0) {
- all_buffers.appendAssumeCapacity(.{
- .base = zig_h,
- .len = zig_h.len,
- });
- }
-
- for (emit_h.decl_table.keys()) |decl_index| {
- const decl_emit_h = emit_h.declPtr(decl_index);
- const buf = decl_emit_h.fwd_decl.items;
- if (buf.len != 0) {
- all_buffers.appendAssumeCapacity(.{
- .base = buf.ptr,
- .len = buf.len,
- });
- file_size += buf.len;
- }
- }
-
- const directory = emit_h.loc.directory orelse zcu.comp.local_cache_directory;
- const file = try directory.handle.createFile(io, emit_h.loc.basename, .{
- // We set the end position explicitly below; by not truncating the file, we possibly
- // make it easier on the file system by doing 1 reallocation instead of two.
- .truncate = false,
- });
- defer file.close(io);
-
- try file.setLength(io, file_size);
- try file.pwritevAll(all_buffers.items, 0);
-}
-
pub fn updateExports(
- self: *C,
+ c: *C,
pt: Zcu.PerThread,
exported: Zcu.Exported,
export_indices: []const Zcu.Export.Index,
-) !void {
+) Allocator.Error!void {
const zcu = pt.zcu;
const gpa = zcu.gpa;
- const mod, const pass: codegen.DeclGen.Pass, const decl_block, const exported_block = switch (exported) {
- .nav => |nav| .{
- zcu.navFileScope(nav).mod.?,
- .{ .nav = nav },
- self.navs.getPtr(nav).?,
- (try self.exported_navs.getOrPut(gpa, nav)).value_ptr,
- },
- .uav => |uav| .{
- zcu.root_mod,
- .{ .uav = uav },
- self.uavs.getPtr(uav).?,
- (try self.exported_uavs.getOrPut(gpa, uav)).value_ptr,
- },
- };
- const ctype_pool = &decl_block.ctype_pool;
+
+ var arena: std.heap.ArenaAllocator = .init(gpa);
+ defer arena.deinit();
+
var dg: codegen.DeclGen = .{
.gpa = gpa,
+ .arena = arena.allocator(),
.pt = pt,
- .mod = mod,
- .error_msg = null,
- .pass = pass,
+ .mod = zcu.root_mod,
+ .owner_nav = .none,
.is_naked_fn = false,
.expected_block = null,
- .fwd_decl = undefined,
- .ctype_pool = decl_block.ctype_pool,
- .scratch = .initBuffer(self.scratch_buf),
+ .error_msg = null,
+ .ctype_deps = .empty,
.uavs = .empty,
};
- dg.fwd_decl = .initOwnedSlice(gpa, self.fwd_decl_buf);
defer {
assert(dg.uavs.count() == 0);
- ctype_pool.* = dg.ctype_pool.move();
- ctype_pool.freeUnusedCapacity(gpa);
+ dg.ctype_deps.deinit(gpa);
+ }
- self.fwd_decl_buf = dg.fwd_decl.toArrayList().allocatedSlice();
- self.scratch_buf = dg.scratch.allocatedSlice();
- }
- codegen.genExports(&dg, exported, export_indices) catch |err| switch (err) {
- error.WriteFailed, error.OutOfMemory => return error.OutOfMemory,
+ const code: String = code: {
+ var aw: std.Io.Writer.Allocating = .fromArrayList(gpa, &c.string_bytes);
+ defer c.string_bytes = aw.toArrayList();
+ const start = aw.written().len;
+ codegen.genExports(&dg, &aw.writer, exported, export_indices) catch |err| switch (err) {
+ error.WriteFailed => return error.OutOfMemory,
+ error.OutOfMemory => |e| return e,
+ };
+ break :code .{
+ .start = @intCast(start),
+ .len = @intCast(aw.written().len - start),
+ };
};
- exported_block.* = .{ .fwd_decl = try self.addString(dg.fwd_decl.written()) };
+ switch (exported) {
+ .nav => |nav| try c.exported_navs.put(gpa, nav, code),
+ .uav => |uav| try c.exported_uavs.put(gpa, uav, code),
+ }
}
pub fn deleteExport(
@@ -866,20 +1294,237 @@ pub fn deleteExport(
}
}
-fn addUavsFromCodegen(c: *C, uavs: *const std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment)) Allocator.Error!void {
+fn mergeNeededCTypes(
+ c: *C,
+ need_types: *std.AutoArrayHashMapUnmanaged(link.ConstPool.Index, void),
+ need_errunion_types: *std.AutoArrayHashMapUnmanaged(link.ConstPool.Index, void),
+ need_aligned_types: *std.AutoArrayHashMapUnmanaged(link.ConstPool.Index, u64),
+ deps: *const CTypeDependencies,
+) Allocator.Error!void {
const gpa = c.base.comp.gpa;
- try c.uavs.ensureUnusedCapacity(gpa, uavs.count());
- try c.aligned_uavs.ensureUnusedCapacity(gpa, uavs.count());
- for (uavs.keys(), uavs.values()) |uav_val, uav_align| {
- {
- const gop = c.uavs.getOrPutAssumeCapacity(uav_val);
- if (!gop.found_existing) gop.value_ptr.* = .{};
+
+ const resolved = deps.get(c);
+
+ try need_types.ensureUnusedCapacity(gpa, resolved.type.len + resolved.type_fwd.len);
+ try need_errunion_types.ensureUnusedCapacity(gpa, resolved.errunion_type.len + resolved.errunion_type_fwd.len);
+ try need_aligned_types.ensureUnusedCapacity(gpa, resolved.aligned_type_fwd.len);
+
+ for (resolved.type) |index| need_types.putAssumeCapacity(index, {});
+ for (resolved.type_fwd) |index| need_types.putAssumeCapacity(index, {});
+
+ for (resolved.errunion_type) |index| need_errunion_types.putAssumeCapacity(index, {});
+ for (resolved.errunion_type_fwd) |index| need_errunion_types.putAssumeCapacity(index, {});
+
+ for (resolved.aligned_type_fwd, resolved.aligned_type_masks) |ty_index, align_mask| {
+ const gop = need_aligned_types.getOrPutAssumeCapacity(ty_index);
+ if (!gop.found_existing) gop.value_ptr.* = 0;
+ gop.value_ptr.* |= align_mask;
+ }
+}
+
+fn mergeNeededUavs(
+ zcu: *const Zcu,
+ global: *std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment),
+ new: *const std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment),
+) Allocator.Error!void {
+ const gpa = zcu.comp.gpa;
+
+ try global.ensureUnusedCapacity(gpa, new.count());
+ for (new.keys(), new.values()) |uav_val, need_align| {
+ const gop = global.getOrPutAssumeCapacity(uav_val);
+ if (!gop.found_existing) gop.value_ptr.* = .none;
+
+ if (need_align != .none) {
+ const cur_align = switch (gop.value_ptr.*) {
+ .none => Value.fromInterned(uav_val).typeOf(zcu).abiAlignment(zcu),
+ else => |a| a,
+ };
+ if (need_align.compareStrict(.gt, cur_align)) {
+ gop.value_ptr.* = need_align;
+ }
}
- if (uav_align != .none) {
- const gop = c.aligned_uavs.getOrPutAssumeCapacity(uav_val);
- gop.value_ptr.* = if (gop.found_existing) max: {
- break :max gop.value_ptr.*.maxStrict(uav_align);
- } else uav_align;
+ }
+}
+
+fn addCTypeDependencies(
+ c: *C,
+ pt: Zcu.PerThread,
+ deps: *const codegen.CType.Dependencies,
+) Allocator.Error!CTypeDependencies {
+ const gpa = pt.zcu.comp.gpa;
+
+ try c.bigint_types.ensureUnusedCapacity(gpa, deps.bigint.count());
+ for (deps.bigint.keys()) |bigint| c.bigint_types.putAssumeCapacity(bigint, {});
+
+ const type_start = c.type_dependencies.items.len;
+ const errunion_type_start = type_start + deps.type.count();
+ const type_fwd_start = errunion_type_start + deps.errunion_type.count();
+ const errunion_type_fwd_start = type_fwd_start + deps.type_fwd.count();
+ const aligned_type_fwd_start = errunion_type_fwd_start + deps.errunion_type_fwd.count();
+ try c.type_dependencies.appendNTimes(gpa, undefined, deps.type.count() +
+ deps.errunion_type.count() +
+ deps.type_fwd.count() +
+ deps.errunion_type_fwd.count() +
+ deps.aligned_type_fwd.count());
+
+ const align_mask_start = c.align_dependency_masks.items.len;
+ try c.align_dependency_masks.appendSlice(gpa, deps.aligned_type_fwd.values());
+
+ for (deps.type.keys(), type_start..) |ty, i| {
+ const pool_index = try c.type_pool.get(pt, .{ .c = c }, ty);
+ c.type_dependencies.items[i] = pool_index;
+ }
+
+ for (deps.errunion_type.keys(), errunion_type_start..) |ty, i| {
+ const pool_index = try c.type_pool.get(pt, .{ .c = c }, ty);
+ c.type_dependencies.items[i] = pool_index;
+ }
+
+ for (deps.type_fwd.keys(), type_fwd_start..) |ty, i| {
+ const pool_index = try c.type_pool.get(pt, .{ .c = c }, ty);
+ c.type_dependencies.items[i] = pool_index;
+ }
+
+ for (deps.errunion_type_fwd.keys(), errunion_type_fwd_start..) |ty, i| {
+ const pool_index = try c.type_pool.get(pt, .{ .c = c }, ty);
+ c.type_dependencies.items[i] = pool_index;
+ }
+
+ for (deps.aligned_type_fwd.keys(), aligned_type_fwd_start..) |ty, i| {
+ const pool_index = try c.type_pool.get(pt, .{ .c = c }, ty);
+ c.type_dependencies.items[i] = pool_index;
+ }
+
+ return .{
+ .len = @intCast(deps.type.count()),
+ .errunion_len = @intCast(deps.errunion_type.count()),
+ .fwd_len = @intCast(deps.type_fwd.count()),
+ .errunion_fwd_len = @intCast(deps.errunion_type_fwd.count()),
+ .aligned_fwd_len = @intCast(deps.aligned_type_fwd.count()),
+ .type_start = @intCast(type_start),
+ .align_mask_start = @intCast(align_mask_start),
+ };
+}
+
+fn updateNewUavs(c: *C, pt: Zcu.PerThread, old_uavs_len: usize) Allocator.Error!void {
+ const gpa = pt.zcu.comp.gpa;
+ var index = old_uavs_len;
+ while (index < c.uavs.count()) : (index += 1) {
+ // `new_uavs` is UAVs discovered while lowering *this* UAV.
+ const new_uavs: []const InternPool.Index = new: {
+ c.uavs.lockPointers();
+ defer c.uavs.unlockPointers();
+ const val: Value = .fromInterned(c.uavs.keys()[index]);
+ const rendered_decl = &c.uavs.values()[index];
+ rendered_decl.* = .init;
+ try c.updateUav(pt, val, rendered_decl);
+ break :new rendered_decl.need_uavs.keys();
+ };
+ try c.uavs.ensureUnusedCapacity(gpa, new_uavs.len);
+ for (new_uavs) |val| {
+ const gop = c.uavs.getOrPutAssumeCapacity(val);
+ if (!gop.found_existing) {
+ assert(gop.index > index);
+ }
}
}
}
+
+const FlushTypes = struct {
+ c: *C,
+ f: *Flush,
+
+ aligned_types: *const std.AutoArrayHashMapUnmanaged(link.ConstPool.Index, u64),
+ aligned_type_strings: []const []const u8,
+
+ status: std.AutoArrayHashMapUnmanaged(link.ConstPool.Index, bool),
+ errunion_status: std.AutoArrayHashMapUnmanaged(link.ConstPool.Index, bool),
+ aligned_status: std.AutoArrayHashMapUnmanaged(link.ConstPool.Index, void),
+
+ fn processDeps(ft: *FlushTypes, deps: *const CTypeDependencies) void {
+ const resolved = deps.get(ft.c);
+ for (resolved.type) |pool_index| ft.doType(pool_index);
+ for (resolved.type_fwd) |pool_index| ft.doTypeFwd(pool_index);
+ for (resolved.errunion_type) |pool_index| ft.doErrunionType(pool_index);
+ for (resolved.errunion_type_fwd) |pool_index| ft.doErrunionTypeFwd(pool_index);
+ for (resolved.aligned_type_fwd) |pool_index| ft.doAlignedTypeFwd(pool_index);
+ }
+ fn processDepsAsFwd(ft: *FlushTypes, deps: *const CTypeDependencies) void {
+ const resolved = deps.get(ft.c);
+ for (resolved.type) |pool_index| ft.doTypeFwd(pool_index);
+ for (resolved.type_fwd) |pool_index| ft.doTypeFwd(pool_index);
+ for (resolved.errunion_type) |pool_index| ft.doErrunionTypeFwd(pool_index);
+ for (resolved.errunion_type_fwd) |pool_index| ft.doErrunionTypeFwd(pool_index);
+ for (resolved.aligned_type_fwd) |pool_index| ft.doAlignedTypeFwd(pool_index);
+ }
+
+ fn doAlignedTypeFwd(ft: *FlushTypes, pool_index: link.ConstPool.Index) void {
+ const c = ft.c;
+ if (ft.aligned_status.contains(pool_index)) return;
+ if (ft.aligned_types.getIndex(pool_index)) |i| {
+ const rendered = &c.types.items[@intFromEnum(pool_index)];
+ ft.processDepsAsFwd(&rendered.deps);
+ ft.f.appendBufAssumeCapacity(ft.aligned_type_strings[i]);
+ }
+ ft.aligned_status.putAssumeCapacity(pool_index, {});
+ }
+ fn doTypeFwd(ft: *FlushTypes, pool_index: link.ConstPool.Index) void {
+ const c = ft.c;
+ if (ft.status.contains(pool_index)) return;
+ const rendered = &c.types.items[@intFromEnum(pool_index)];
+ if (rendered.fwd_decl.len > 0) {
+ ft.f.appendBufAssumeCapacity(rendered.fwd_decl.get(c));
+ ft.status.putAssumeCapacityNoClobber(pool_index, false);
+ } else {
+ ft.processDepsAsFwd(&rendered.definition_deps);
+ const gop = ft.status.getOrPutAssumeCapacity(pool_index);
+ if (!gop.found_existing) {
+ gop.value_ptr.* = false;
+ ft.f.appendBufAssumeCapacity(rendered.definition.get(c));
+ }
+ }
+ }
+ fn doType(ft: *FlushTypes, pool_index: link.ConstPool.Index) void {
+ const c = ft.c;
+ if (ft.status.get(pool_index)) |completed| {
+ if (completed) return;
+ }
+ const rendered = &c.types.items[@intFromEnum(pool_index)];
+ ft.processDeps(&rendered.definition_deps);
+ if (rendered.fwd_decl.len == 0 and ft.status.contains(pool_index)) {
+ // `doTypeFwd` already rendered the defintion, we just had to complete the type by
+ // fully resolving its dependencies.
+ } else if (rendered.definition.len > 0) {
+ ft.f.appendBufAssumeCapacity(rendered.definition.get(c));
+ } else if (!ft.status.contains(pool_index)) {
+ // The type will never be completed, but it must be forward declared to avoid it being
+ // declared in the wrong scope.
+ ft.f.appendBufAssumeCapacity(rendered.fwd_decl.get(c));
+ }
+ ft.status.putAssumeCapacity(pool_index, true);
+ }
+ fn doErrunionTypeFwd(ft: *FlushTypes, pool_index: link.ConstPool.Index) void {
+ const c = ft.c;
+ const gop = ft.errunion_status.getOrPutAssumeCapacity(pool_index);
+ if (gop.found_existing) return;
+ const rendered = &c.types.items[@intFromEnum(pool_index)];
+ ft.f.appendBufAssumeCapacity(rendered.errunion_fwd_decl.get(c));
+ gop.value_ptr.* = false;
+ }
+ fn doErrunionType(ft: *FlushTypes, pool_index: link.ConstPool.Index) void {
+ const c = ft.c;
+ if (ft.errunion_status.get(pool_index)) |completed| {
+ if (completed) return;
+ }
+ const rendered = &c.types.items[@intFromEnum(pool_index)];
+ ft.processDeps(&rendered.deps);
+ if (rendered.errunion_definition.len > 0) {
+ ft.f.appendBufAssumeCapacity(rendered.errunion_definition.get(c));
+ } else {
+ // The error union type will never be completed, but forward declare it to avoid the
+ // type being first declared in a different scope.
+ ft.f.appendBufAssumeCapacity(rendered.errunion_fwd_decl.get(c));
+ }
+ ft.errunion_status.putAssumeCapacity(pool_index, true);
+ }
+};
diff --git a/src/link/Coff.zig b/src/link/Coff.zig
index 03b757f5b4c9e079cb61c277e305ccc4bdd81472..7440711574f72c47d003f63ff48adee2e522b9e8 100644
--- a/src/link/Coff.zig
+++ b/src/link/Coff.zig
@@ -1552,7 +1552,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
const sec_si = try coff.navSection(zcu, nav.status.fully_resolved);
try coff.nodes.ensureUnusedCapacity(gpa, 1);
const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{
- .alignment = pt.navAlignment(nav_index).toStdMem(),
+ .alignment = zcu.navAlignment(nav_index).toStdMem(),
.moved = true,
});
coff.nodes.appendAssumeCapacity(.{ .nav = nmi });
diff --git a/src/link/ConstPool.zig b/src/link/ConstPool.zig
new file mode 100644
index 0000000000000000000000000000000000000000..1282ad67c4b5fc49bac914bfeede2da46301ee91
--- /dev/null
+++ b/src/link/ConstPool.zig
@@ -0,0 +1,288 @@
+/// Helper type for debug information implementations (such as `link.Dwarf`) to help them emit
+/// information about comptime-known values (constants), including types.
+///
+/// Every constant with associated debug information is assigned an `Index` by calling `get`. The
+/// pool will track which container types do and do not have a resolved layout, as well as which
+/// constants in the pool depend on which types, and call into the implementation to emit debug
+/// information for a constant only when all information is available.
+///
+/// Indices into the pool are dense, and constants are never removed from the pool, so the debug
+/// info implementation can store information for each one with a simple `ArrayList`.
+///
+/// To use `ConstPool`, the debug info implementation is required to:
+/// * forward `updateContainerType` calls to its `ConstPool`
+/// * expose some callback functions---see functions in `User`
+/// * ensure that any `get` call is eventually followed by a `flushPending` call
+const ConstPool = @This();
+
+values: std.AutoArrayHashMapUnmanaged(InternPool.Index, void),
+pending: std.ArrayList(Index),
+complete_containers: std.AutoArrayHashMapUnmanaged(InternPool.Index, void),
+container_deps: std.AutoArrayHashMapUnmanaged(InternPool.Index, ContainerDepEntry.Index),
+container_dep_entries: std.ArrayList(ContainerDepEntry),
+
+pub const empty: ConstPool = .{
+ .values = .empty,
+ .pending = .empty,
+ .complete_containers = .empty,
+ .container_deps = .empty,
+ .container_dep_entries = .empty,
+};
+
+pub fn deinit(pool: *ConstPool, gpa: Allocator) void {
+ pool.values.deinit(gpa);
+ pool.pending.deinit(gpa);
+ pool.complete_containers.deinit(gpa);
+ pool.container_deps.deinit(gpa);
+ pool.container_dep_entries.deinit(gpa);
+}
+
+pub const Index = enum(u32) {
+ _,
+ pub fn val(i: Index, pool: *const ConstPool) InternPool.Index {
+ return pool.values.keys()[@intFromEnum(i)];
+ }
+};
+
+pub const User = union(enum) {
+ dwarf: *@import("Dwarf.zig"),
+ c: *@import("C.zig"),
+ llvm: @import("../codegen/llvm.zig").Object.Ptr,
+
+ /// Inform the debug info implementation that the new constant `val` was added to the pool at
+ /// the given index (which equals the current pool length) due to a `get` call. It is guaranteed
+ /// that there will eventually be a call to either `updateConst` or `updateConstIncomplete`
+ /// following the `addConst` call, to actually populate the constant's debug info.
+ fn addConst(
+ user: User,
+ pt: Zcu.PerThread,
+ index: Index,
+ val: InternPool.Index,
+ ) Allocator.Error!void {
+ switch (user) {
+ inline else => |impl| return impl.addConst(pt, index, val),
+ }
+ }
+
+ /// Tell the debug info implementation to emit information for the constant `val`, which is in
+ /// the pool at the given index. `val` is "complete", which means:
+ /// * If it is a type, its layout is known.
+ /// * Otherwise, the layout of its type is known.
+ fn updateConst(
+ user: User,
+ pt: Zcu.PerThread,
+ index: Index,
+ val: InternPool.Index,
+ ) Allocator.Error!void {
+ switch (user) {
+ inline else => |impl| return impl.updateConst(pt, index, val),
+ }
+ }
+
+ /// Tell the debug info implementation to emit information for the constant `val`, which is in
+ /// the pool at the given index. `val` is "incomplete", meaning the implementation cannot emit
+ /// full information for it (for instance, perhaps it is a struct type which was never actually
+ /// initialized so never had its layout resolved). Instead, the implementation must emit some
+ /// form of placeholder entry representing an incomplete/unknown constant.
+ fn updateConstIncomplete(
+ user: User,
+ pt: Zcu.PerThread,
+ index: Index,
+ val: InternPool.Index,
+ ) Allocator.Error!void {
+ switch (user) {
+ inline else => |impl| return impl.updateConstIncomplete(pt, index, val),
+ }
+ }
+};
+
+const ContainerDepEntry = extern struct {
+ next: ContainerDepEntry.Index.Optional,
+ depender: ConstPool.Index,
+ const Index = enum(u32) {
+ _,
+ const Optional = enum(u32) {
+ none = std.math.maxInt(u32),
+ _,
+ fn unwrap(o: Optional) ?ContainerDepEntry.Index {
+ return switch (o) {
+ .none => null,
+ else => @enumFromInt(@intFromEnum(o)),
+ };
+ }
+ };
+ fn toOptional(i: ContainerDepEntry.Index) Optional {
+ return @enumFromInt(@intFromEnum(i));
+ }
+ fn ptr(i: ContainerDepEntry.Index, pool: *ConstPool) *ContainerDepEntry {
+ return &pool.container_dep_entries.items[@intFromEnum(i)];
+ }
+ };
+};
+
+/// Calls to `link.File.updateContainerType` must be forwarded to this function so that the debug
+/// constant pool has up-to-date information about the resolution status of types.
+pub fn updateContainerType(
+ pool: *ConstPool,
+ pt: Zcu.PerThread,
+ user: User,
+ container_ty: InternPool.Index,
+ success: bool,
+) Allocator.Error!void {
+ if (success) {
+ const gpa = pt.zcu.comp.gpa;
+ try pool.complete_containers.put(gpa, container_ty, {});
+ } else {
+ _ = pool.complete_containers.fetchSwapRemove(container_ty);
+ }
+ var opt_dep = pool.container_deps.get(container_ty);
+ while (opt_dep) |dep| : (opt_dep = dep.ptr(pool).next.unwrap()) {
+ try pool.update(pt, user, dep.ptr(pool).depender);
+ }
+}
+
+/// After this is called, there may be a constant for which debug information (complete or not) has
+/// not yet been emitted, so the user must call `flushPending` at some point after this call.
+pub fn get(pool: *ConstPool, pt: Zcu.PerThread, user: User, val: InternPool.Index) Allocator.Error!ConstPool.Index {
+ const zcu = pt.zcu;
+ const ip = &zcu.intern_pool;
+ const gpa = zcu.comp.gpa;
+ const gop = try pool.values.getOrPut(gpa, val);
+ const index: ConstPool.Index = @enumFromInt(gop.index);
+ if (!gop.found_existing) {
+ const ty: Type = switch (ip.typeOf(val)) {
+ .type_type => if (ip.isUndef(val)) .type else .fromInterned(val),
+ else => |ty| .fromInterned(ty),
+ };
+ try pool.registerTypeDeps(index, ty, zcu);
+ try pool.pending.append(gpa, index);
+ try user.addConst(pt, index, val);
+ }
+ return index;
+}
+pub fn flushPending(pool: *ConstPool, pt: Zcu.PerThread, user: User) Allocator.Error!void {
+ while (pool.pending.pop()) |pending_ty| {
+ try pool.update(pt, user, pending_ty);
+ }
+}
+
+fn update(pool: *ConstPool, pt: Zcu.PerThread, user: User, index: ConstPool.Index) Allocator.Error!void {
+ const zcu = pt.zcu;
+ const ip = &zcu.intern_pool;
+ const val = index.val(pool);
+ const ty: Type = switch (ip.typeOf(val)) {
+ .type_type => if (ip.isUndef(val)) .type else .fromInterned(val),
+ else => |ty| .fromInterned(ty),
+ };
+ if (pool.checkType(ty, zcu)) {
+ try user.updateConst(pt, index, val);
+ } else {
+ try user.updateConstIncomplete(pt, index, val);
+ }
+}
+fn checkType(pool: *const ConstPool, ty: Type, zcu: *const Zcu) bool {
+ if (ty.isGenericPoison()) return true;
+ return switch (ty.zigTypeTag(zcu)) {
+ .type,
+ .void,
+ .bool,
+ .noreturn,
+ .int,
+ .float,
+ .pointer,
+ .comptime_float,
+ .comptime_int,
+ .undefined,
+ .null,
+ .error_set,
+ .@"opaque",
+ .frame,
+ .@"anyframe",
+ .enum_literal,
+ => true,
+
+ .array, .vector => pool.checkType(ty.childType(zcu), zcu),
+ .optional => pool.checkType(ty.optionalChild(zcu), zcu),
+ .error_union => pool.checkType(ty.errorUnionPayload(zcu), zcu),
+ .@"fn" => {
+ const ip = &zcu.intern_pool;
+ const func = ip.indexToKey(ty.toIntern()).func_type;
+ for (func.param_types.get(ip)) |param_ty_ip| {
+ if (!pool.checkType(.fromInterned(param_ty_ip), zcu)) return false;
+ }
+ return pool.checkType(.fromInterned(func.return_type), zcu);
+ },
+ .@"struct" => if (ty.isTuple(zcu)) {
+ for (0..ty.structFieldCount(zcu)) |field_index| {
+ if (!pool.checkType(ty.fieldType(field_index, zcu), zcu)) return false;
+ }
+ return true;
+ } else {
+ return pool.complete_containers.contains(ty.toIntern());
+ },
+ .@"union", .@"enum" => {
+ return pool.complete_containers.contains(ty.toIntern());
+ },
+ };
+}
+fn registerTypeDeps(pool: *ConstPool, root: Index, ty: Type, zcu: *const Zcu) Allocator.Error!void {
+ if (ty.isGenericPoison()) return;
+ switch (ty.zigTypeTag(zcu)) {
+ .type,
+ .void,
+ .bool,
+ .noreturn,
+ .int,
+ .float,
+ .pointer,
+ .comptime_float,
+ .comptime_int,
+ .undefined,
+ .null,
+ .error_set,
+ .@"opaque",
+ .frame,
+ .@"anyframe",
+ .enum_literal,
+ => {},
+
+ .array, .vector => try pool.registerTypeDeps(root, ty.childType(zcu), zcu),
+ .optional => try pool.registerTypeDeps(root, ty.optionalChild(zcu), zcu),
+ .error_union => try pool.registerTypeDeps(root, ty.errorUnionPayload(zcu), zcu),
+ .@"fn" => {
+ const ip = &zcu.intern_pool;
+ const func = ip.indexToKey(ty.toIntern()).func_type;
+ for (func.param_types.get(ip)) |param_ty_ip| {
+ try pool.registerTypeDeps(root, .fromInterned(param_ty_ip), zcu);
+ }
+ try pool.registerTypeDeps(root, .fromInterned(func.return_type), zcu);
+ },
+ .@"struct", .@"union", .@"enum" => if (ty.isTuple(zcu)) {
+ for (0..ty.structFieldCount(zcu)) |field_index| {
+ try pool.registerTypeDeps(root, ty.fieldType(field_index, zcu), zcu);
+ }
+ } else {
+ // `ty` is a container; register the dependency.
+
+ const gpa = zcu.comp.gpa;
+ try pool.container_deps.ensureUnusedCapacity(gpa, 1);
+ try pool.container_dep_entries.ensureUnusedCapacity(gpa, 1);
+ errdefer comptime unreachable;
+
+ const gop = pool.container_deps.getOrPutAssumeCapacity(ty.toIntern());
+ const entry: ContainerDepEntry.Index = @enumFromInt(pool.container_dep_entries.items.len);
+ pool.container_dep_entries.appendAssumeCapacity(.{
+ .next = if (gop.found_existing) gop.value_ptr.toOptional() else .none,
+ .depender = root,
+ });
+ gop.value_ptr.* = entry;
+ },
+ }
+}
+
+const std = @import("std");
+const Allocator = std.mem.Allocator;
+
+const InternPool = @import("../InternPool.zig");
+const Type = @import("../Type.zig");
+const Zcu = @import("../Zcu.zig");
diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig
index 19bbee45b3a12d6883f3e7803475eb960c5a1784..4260ffb9e9d11ad488ef132553b82180bdc6d64a 100644
--- a/src/link/Dwarf.zig
+++ b/src/link/Dwarf.zig
@@ -25,9 +25,11 @@ format: DW.Format,
endian: std.builtin.Endian,
address_size: AddressSize,
+const_pool: link.ConstPool,
+
mods: std.AutoArrayHashMapUnmanaged(*Module, ModInfo),
-types: std.AutoArrayHashMapUnmanaged(InternPool.Index, Entry.Index),
-values: std.AutoArrayHashMapUnmanaged(InternPool.Index, Entry.Index),
+/// Indices are `link.ConstPool.Index`.
+values: std.ArrayList(struct { Unit.Index, Entry.Index }),
navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Entry.Index),
decls: std.AutoArrayHashMapUnmanaged(InternPool.TrackedInst.Index, Entry.Index),
@@ -1034,15 +1036,14 @@ const Entry = struct {
});
const zcu = dwarf.bin_file.comp.zcu.?;
const ip = &zcu.intern_pool;
- for (dwarf.types.keys(), dwarf.types.values()) |ty, other_entry| {
- const ty_unit: Unit.Index = if (Type.fromInterned(ty).typeDeclInst(zcu)) |inst_index|
- dwarf.getUnit(zcu.fileByIndex(inst_index.resolveFile(ip)).mod.?) catch unreachable
- else
- .main;
- if (sec.getUnit(ty_unit) == unit and unit.getEntry(other_entry) == entry)
- log.err("missing Type({f}({d}))", .{
- Type.fromInterned(ty).fmt(.{ .tid = .main, .zcu = zcu }),
- @intFromEnum(ty),
+ for (0.., dwarf.values.items) |raw_index, unit_and_entry| {
+ const index: link.ConstPool.Index = @enumFromInt(raw_index);
+ const val = index.val(&dwarf.const_pool);
+ const val_unit, const val_entry = unit_and_entry;
+ if (sec.getUnit(val_unit) == unit and unit.getEntry(val_entry) == entry)
+ log.err("missing Value({f}({d}))", .{
+ Value.fromInterned(val).fmtValue(.{ .tid = .main, .zcu = zcu }),
+ @intFromEnum(val),
});
}
for (dwarf.navs.keys(), dwarf.navs.values()) |nav, other_entry| {
@@ -1520,7 +1521,6 @@ pub const WipNav = struct {
debug_info: Writer.Allocating,
debug_line: Writer.Allocating,
debug_loclists: Writer.Allocating,
- pending_lazy: PendingLazy,
pub fn deinit(wip_nav: *WipNav) void {
const gpa = wip_nav.dwarf.gpa;
@@ -1529,8 +1529,6 @@ pub const WipNav = struct {
wip_nav.debug_info.deinit();
wip_nav.debug_line.deinit();
wip_nav.debug_loclists.deinit();
- wip_nav.pending_lazy.types.deinit(gpa);
- wip_nav.pending_lazy.values.deinit(gpa);
}
pub fn genDebugFrame(wip_nav: *WipNav, loc: u32, cfa: Cfa) UpdateError!void {
@@ -1603,7 +1601,7 @@ pub const WipNav = struct {
const zcu = pt.zcu;
const ty = val.typeOf(zcu);
const has_runtime_bits = ty.hasRuntimeBits(zcu);
- const has_comptime_state = ty.comptimeOnly(zcu) and try ty.onePossibleValue(pt) == null;
+ const has_comptime_state = ty.comptimeOnly(zcu);
try wip_nav.abbrevCode(if (has_runtime_bits and has_comptime_state) switch (tag) {
.comptime_arg => if (opt_name) |_| .comptime_arg_runtime_bits_comptime_state else .unnamed_comptime_arg_runtime_bits_comptime_state,
.local_const => if (opt_name) |_| .local_const_runtime_bits_comptime_state else unreachable,
@@ -1945,6 +1943,12 @@ pub const WipNav = struct {
try wip_nav.infoSectionOffset(.debug_str, StringSection.unit, try wip_nav.dwarf.debug_str.addString(wip_nav.dwarf, str), 0);
}
+ fn strpFmt(wip_nav: *WipNav, comptime fmt: []const u8, args: anytype) (UpdateError || Writer.Error)!void {
+ const str = try std.fmt.allocPrint(wip_nav.dwarf.gpa, fmt, args);
+ defer wip_nav.dwarf.gpa.free(str);
+ return wip_nav.strp(str);
+ }
+
const ExprLocCounter = struct {
dw: Writer.Discarding,
section_offset_bytes: u32,
@@ -2054,74 +2058,16 @@ pub const WipNav = struct {
try dfw.splatByteAll(0, @intFromEnum(wip_nav.dwarf.address_size));
}
- fn getNavEntry(
- wip_nav: *WipNav,
- nav_index: InternPool.Nav.Index,
- ) UpdateError!struct { Unit.Index, Entry.Index } {
- const zcu = wip_nav.pt.zcu;
- const ip = &zcu.intern_pool;
- const nav = ip.getNav(nav_index);
- const unit = try wip_nav.dwarf.getUnit(zcu.fileByIndex(nav.srcInst(ip).resolveFile(ip)).mod.?);
- const gop = try wip_nav.dwarf.navs.getOrPut(wip_nav.dwarf.gpa, nav_index);
- if (gop.found_existing) return .{ unit, gop.value_ptr.* };
- const entry = try wip_nav.dwarf.addCommonEntry(unit);
- gop.value_ptr.* = entry;
- return .{ unit, entry };
- }
-
fn refNav(
wip_nav: *WipNav,
nav_index: InternPool.Nav.Index,
) (UpdateError || Writer.Error)!void {
- const unit, const entry = try wip_nav.getNavEntry(nav_index);
+ const unit, const entry = try wip_nav.dwarf.getNavEntry(nav_index);
try wip_nav.infoSectionOffset(.debug_info, unit, entry, 0);
}
- fn getTypeEntry(wip_nav: *WipNav, ty: Type) UpdateError!struct { Unit.Index, Entry.Index } {
- const zcu = wip_nav.pt.zcu;
- const ip = &zcu.intern_pool;
- const maybe_inst_index = ty.typeDeclInst(zcu);
- const unit = if (maybe_inst_index) |inst_index| switch (switch (ip.indexToKey(ty.toIntern())) {
- else => unreachable,
- .struct_type => ip.loadStructType(ty.toIntern()).name_nav,
- .union_type => ip.loadUnionType(ty.toIntern()).name_nav,
- .enum_type => ip.loadEnumType(ty.toIntern()).name_nav,
- .opaque_type => ip.loadOpaqueType(ty.toIntern()).name_nav,
- }) {
- .none => try wip_nav.dwarf.getUnit(zcu.fileByIndex(inst_index.resolveFile(ip)).mod.?),
- else => |name_nav| return wip_nav.getNavEntry(name_nav.unwrap().?),
- } else .main;
- const gop = try wip_nav.dwarf.types.getOrPut(wip_nav.dwarf.gpa, ty.toIntern());
- if (gop.found_existing) return .{ unit, gop.value_ptr.* };
- const entry = try wip_nav.dwarf.addCommonEntry(unit);
- gop.value_ptr.* = entry;
- if (maybe_inst_index == null) try wip_nav.pending_lazy.types.append(wip_nav.dwarf.gpa, ty.toIntern());
- return .{ unit, entry };
- }
-
fn refType(wip_nav: *WipNav, ty: Type) (UpdateError || Writer.Error)!void {
- const unit, const entry = try wip_nav.getTypeEntry(ty);
- try wip_nav.infoSectionOffset(.debug_info, unit, entry, 0);
- }
-
- fn getValueEntry(wip_nav: *WipNav, value: Value) UpdateError!struct { Unit.Index, Entry.Index } {
- const zcu = wip_nav.pt.zcu;
- const ip = &zcu.intern_pool;
- const ty = value.typeOf(zcu);
- if (std.debug.runtime_safety) assert(ty.comptimeOnly(zcu) and try ty.onePossibleValue(wip_nav.pt) == null);
- if (ty.toIntern() == .type_type) return wip_nav.getTypeEntry(value.toType());
- if (ip.isFunctionType(ty.toIntern()) and !value.isUndef(zcu)) return wip_nav.getNavEntry(switch (ip.indexToKey(value.toIntern())) {
- else => unreachable,
- .func => |func| func.owner_nav,
- .@"extern" => |@"extern"| @"extern".owner_nav,
- });
- const gop = try wip_nav.dwarf.values.getOrPut(wip_nav.dwarf.gpa, value.toIntern());
- const unit: Unit.Index = .main;
- if (gop.found_existing) return .{ unit, gop.value_ptr.* };
- const entry = try wip_nav.dwarf.addCommonEntry(unit);
- gop.value_ptr.* = entry;
- try wip_nav.pending_lazy.values.append(wip_nav.dwarf.gpa, value.toIntern());
- return .{ unit, entry };
+ return wip_nav.refValue(ty.toValue());
}
fn refValue(wip_nav: *WipNav, value: Value) (UpdateError || Writer.Error)!void {
@@ -2129,6 +2075,15 @@ pub const WipNav = struct {
try wip_nav.infoSectionOffset(.debug_info, unit, entry, 0);
}
+ fn getValueEntry(wip_nav: *WipNav, value: Value) UpdateError!struct { Unit.Index, Entry.Index } {
+ if (value.typeOf(wip_nav.pt.zcu).toIntern() != .type_type) {
+ assert(value.typeOf(wip_nav.pt.zcu).comptimeOnly(wip_nav.pt.zcu));
+ }
+ const dwarf = wip_nav.dwarf;
+ const index = try dwarf.const_pool.get(wip_nav.pt, .{ .dwarf = dwarf }, value.toIntern());
+ return dwarf.values.items[@intFromEnum(index)];
+ }
+
fn refForward(wip_nav: *WipNav) (Allocator.Error || Writer.Error)!u32 {
const dwarf = wip_nav.dwarf;
const diw = &wip_nav.debug_info.writer;
@@ -2156,7 +2111,7 @@ pub const WipNav = struct {
) (UpdateError || Writer.Error)!void {
const ty = val.typeOf(wip_nav.pt.zcu);
const diw = &wip_nav.debug_info.writer;
- const size = if (ty.hasRuntimeBits(wip_nav.pt.zcu)) ty.abiSize(wip_nav.pt.zcu) else 0;
+ const size = ty.abiSize(wip_nav.pt.zcu);
try diw.writeUleb128(size);
if (size == 0) return;
const old_end = wip_nav.debug_info.writer.end;
@@ -2243,8 +2198,8 @@ pub const WipNav = struct {
const zcu = wip_nav.pt.zcu;
const ip = &zcu.intern_pool;
var big_int_space: Value.BigIntSpace = undefined;
- try wip_nav.bigIntConstValue(abbrev_code, .fromInterned(loaded_enum.tag_ty), if (loaded_enum.values.len > 0)
- Value.fromInterned(loaded_enum.values.get(ip)[field_index]).toBigInt(&big_int_space, zcu)
+ try wip_nav.bigIntConstValue(abbrev_code, .fromInterned(loaded_enum.int_tag_type), if (loaded_enum.field_values.len > 0)
+ Value.fromInterned(loaded_enum.field_values.get(ip)[field_index]).toBigInt(&big_int_space, zcu)
else
std.math.big.int.Mutable.init(&big_int_space.limbs, field_index).toConst());
}
@@ -2297,6 +2252,12 @@ pub const WipNav = struct {
.generic_decl_const,
.generic_decl_func,
=> true,
+
+ // This comes from a decl which was previously generated as an incomplete value
+ // (I think that must mean either a function or an extern which previously had
+ // incomplete types).
+ .undefined_comptime_value => false,
+
else => |t| std.debug.panic("bad decl abbrev code: {t}", .{t}),
};
if (parent_type.getCaptures(zcu).len == 0) {
@@ -2331,22 +2292,6 @@ pub const WipNav = struct {
try wip_nav.refType(parent_type.?);
try wip_nav.infoSectionOffset(.debug_info, wip_nav.unit, generic_decl_entry, 0);
}
-
- const PendingLazy = struct {
- types: std.ArrayList(InternPool.Index),
- values: std.ArrayList(InternPool.Index),
-
- const empty: PendingLazy = .{ .types = .empty, .values = .empty };
- };
-
- fn updateLazy(wip_nav: *WipNav, src_loc: Zcu.LazySrcLoc) (UpdateError || Writer.Error)!void {
- while (true) if (wip_nav.pending_lazy.types.pop()) |pending_ty|
- try wip_nav.dwarf.updateLazyType(wip_nav.pt, src_loc, pending_ty, &wip_nav.pending_lazy)
- else if (wip_nav.pending_lazy.values.pop()) |pending_val|
- try wip_nav.dwarf.updateLazyValue(wip_nav.pt, src_loc, pending_val, &wip_nav.pending_lazy)
- else
- break;
- }
};
/// When allocating, the ideal_capacity is calculated by
@@ -2372,8 +2317,9 @@ pub fn init(lf: *link.File, format: DW.Format) Dwarf {
},
.endian = target.cpu.arch.endian(),
+ .const_pool = .empty,
+
.mods = .empty,
- .types = .empty,
.values = .empty,
.navs = .empty,
.decls = .empty,
@@ -2544,9 +2490,9 @@ pub fn initMetadata(dwarf: *Dwarf) UpdateError!void {
pub fn deinit(dwarf: *Dwarf) void {
const gpa = dwarf.gpa;
+ dwarf.const_pool.deinit(gpa);
for (dwarf.mods.values()) |*mod_info| mod_info.deinit(gpa);
dwarf.mods.deinit(gpa);
- dwarf.types.deinit(gpa);
dwarf.values.deinit(gpa);
dwarf.navs.deinit(gpa);
dwarf.decls.deinit(gpa);
@@ -2562,6 +2508,21 @@ pub fn deinit(dwarf: *Dwarf) void {
dwarf.* = undefined;
}
+fn getNavEntry(
+ dwarf: *Dwarf,
+ nav_index: InternPool.Nav.Index,
+) UpdateError!struct { Unit.Index, Entry.Index } {
+ const zcu = dwarf.bin_file.comp.zcu.?;
+ const ip = &zcu.intern_pool;
+ const nav = ip.getNav(nav_index);
+ const unit = try dwarf.getUnit(zcu.fileByIndex(nav.srcInst(ip).resolveFile(ip)).mod.?);
+ const gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
+ if (gop.found_existing) return .{ unit, gop.value_ptr.* };
+ const entry = try dwarf.addCommonEntry(unit);
+ gop.value_ptr.* = entry;
+ return .{ unit, entry };
+}
+
fn getUnit(dwarf: *Dwarf, mod: *Module) !Unit.Index {
const mod_gop = try dwarf.mods.getOrPut(dwarf.gpa, mod);
const unit: Unit.Index = @enumFromInt(mod_gop.index);
@@ -2622,6 +2583,10 @@ fn getModInfo(dwarf: *Dwarf, unit: Unit.Index) *ModInfo {
return &dwarf.mods.values()[@intFromEnum(unit)];
}
+fn getUnitModule(dwarf: *Dwarf, unit: Unit.Index) *Module {
+ return dwarf.mods.keys()[@intFromEnum(unit)];
+}
+
pub fn initWipNav(
dwarf: *Dwarf,
pt: Zcu.PerThread,
@@ -2683,7 +2648,6 @@ fn initWipNavInner(
.debug_info = .init(dwarf.gpa),
.debug_line = .init(dwarf.gpa),
.debug_loclists = .init(dwarf.gpa),
- .pending_lazy = .empty,
};
errdefer wip_nav.deinit();
@@ -2705,7 +2669,7 @@ fn initWipNavInner(
try wip_nav.refType(.fromInterned(if (maybe_func_type) |func_type| func_type.return_type else @"extern".ty));
if (maybe_func_type) |func_type| {
try wip_nav.infoAddrSym(sym_index, 0);
- try diw.writeByte(@intFromBool(ip.isNoReturn(func_type.return_type)));
+ try diw.writeByte(@intFromBool(Type.fromInterned(func_type.return_type).isNoReturn(zcu)));
if (func_type.param_types.len > 0 or func_type.is_var_args) {
for (func_type.param_types.get(ip)) |param_type| {
try wip_nav.abbrevCode(.extern_param);
@@ -2733,7 +2697,7 @@ fn initWipNavInner(
try wip_nav.strp(@"extern".name.toSlice(ip));
try wip_nav.refType(.fromInterned(func_type.return_type));
try wip_nav.infoAddrSym(sym_index, 0);
- try diw.writeByte(@intFromBool(ip.isNoReturn(func_type.return_type)));
+ try diw.writeByte(@intFromBool(Type.fromInterned(func_type.return_type).isNoReturn(zcu)));
if (func_type.param_types.len > 0 or func_type.is_var_args) {
for (func_type.param_types.get(ip)) |param_type| {
try wip_nav.abbrevCode(.extern_param);
@@ -2818,7 +2782,7 @@ fn initWipNavInner(
else => |a| a.maxStrict(target_info.minFunctionAlignment(target)),
}.toByteUnits().?);
try diw.writeByte(@intFromBool(decl.linkage != .normal));
- try diw.writeByte(@intFromBool(ip.isNoReturn(func_type.return_type)));
+ try diw.writeByte(@intFromBool(Type.fromInterned(func_type.return_type).isNoReturn(zcu)));
const dlw = &wip_nav.debug_line.writer;
try dlw.writeByte(DW.LNS.extended_op);
@@ -3050,7 +3014,7 @@ fn finishWipNavWriterError(
}
try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.written());
- try wip_nav.updateLazy(zcu.navSrcLoc(nav_index));
+ try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });
}
pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) error{ OutOfMemory, CodegenFail }!void {
@@ -3087,34 +3051,12 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
return;
}
- var wip_nav: WipNav = .{
- .dwarf = dwarf,
- .pt = pt,
- .unit = try dwarf.getUnit(file.mod.?),
- .entry = undefined,
- .any_children = false,
- .func = .none,
- .func_sym_index = undefined,
- .func_high_pc = undefined,
- .blocks = undefined,
- .cfi = undefined,
- .debug_frame = .init(dwarf.gpa),
- .debug_info = .init(dwarf.gpa),
- .debug_line = .init(dwarf.gpa),
- .debug_loclists = .init(dwarf.gpa),
- .pending_lazy = .empty,
- };
- defer wip_nav.deinit();
-
- const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
- errdefer _ = if (!nav_gop.found_existing) dwarf.navs.pop();
-
const tag: union(enum) {
- done,
- decl_alias,
- decl_var,
- decl_const,
- decl_func_alias: InternPool.Nav.Index,
+ alias,
+ @"var",
+ @"const",
+ func: Type,
+ func_alias: InternPool.Nav.Index,
} = switch (ip.indexToKey(nav_val.toIntern())) {
.int_type,
.ptr_type,
@@ -3128,242 +3070,49 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
.func_type,
.error_set_type,
.inferred_error_set_type,
- => .decl_alias,
+ => .alias,
+
.struct_type => tag: {
const loaded_struct = ip.loadStructType(nav_val.toIntern());
- if (loaded_struct.zir_index.resolveFile(ip) != inst_info.file) break :tag .decl_alias;
-
- const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
- if (type_gop.found_existing) {
- if (dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).len > 0) break :tag .decl_alias;
- assert(!nav_gop.found_existing);
- nav_gop.value_ptr.* = type_gop.value_ptr.*;
- } else {
- if (nav_gop.found_existing)
- dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
- else
- nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
- type_gop.value_ptr.* = nav_gop.value_ptr.*;
+ if (nav_index.toOptional() == loaded_struct.name_nav) {
+ // This Nav's entry is populated by the type, not the actual Nav.
+ _ = try dwarf.const_pool.get(pt, .{ .dwarf = dwarf }, nav_val.toIntern());
+ try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });
+ return;
}
- wip_nav.entry = nav_gop.value_ptr.*;
-
- const diw = &wip_nav.debug_info.writer;
-
- switch (loaded_struct.layout) {
- .auto, .@"extern" => {
- try wip_nav.declCommon(if (loaded_struct.field_types.len == 0) .{
- .decl = .decl_namespace_struct,
- .generic_decl = .generic_decl_const,
- .decl_instance = .decl_instance_namespace_struct,
- } else .{
- .decl = .decl_struct,
- .generic_decl = .generic_decl_const,
- .decl_instance = .decl_instance_struct,
- }, &nav, inst_info.file, &decl);
- if (loaded_struct.field_types.len == 0) try diw.writeByte(@intFromBool(false)) else {
- try diw.writeUleb128(nav_val.toType().abiSize(zcu));
- try diw.writeUleb128(nav_val.toType().abiAlignment(zcu).toByteUnits().?);
- for (0..loaded_struct.field_types.len) |field_index| {
- const is_comptime = loaded_struct.fieldIsComptime(ip, field_index);
- const field_init = loaded_struct.fieldInit(ip, field_index);
- assert(!(is_comptime and field_init == .none));
- const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
- const has_runtime_bits, const has_comptime_state = switch (field_init) {
- .none => .{ false, false },
- else => .{
- field_type.hasRuntimeBits(zcu),
- field_type.comptimeOnly(zcu) and try field_type.onePossibleValue(pt) == null,
- },
- };
- try wip_nav.abbrevCode(if (is_comptime)
- if (has_comptime_state)
- .struct_field_comptime_comptime_state
- else if (has_runtime_bits)
- .struct_field_comptime_runtime_bits
- else
- .struct_field_comptime
- else if (field_init != .none)
- if (has_comptime_state)
- .struct_field_default_comptime_state
- else if (has_runtime_bits)
- .struct_field_default_runtime_bits
- else
- .struct_field
- else
- .struct_field);
- try wip_nav.strp(loaded_struct.fieldName(ip, field_index).toSlice(ip));
- try wip_nav.refType(field_type);
- if (!is_comptime) {
- try diw.writeUleb128(loaded_struct.offsets.get(ip)[field_index]);
- try diw.writeUleb128(loaded_struct.fieldAlign(ip, field_index).toByteUnits() orelse
- field_type.abiAlignment(zcu).toByteUnits().?);
- }
- if (has_comptime_state)
- try wip_nav.refValue(.fromInterned(field_init))
- else if (has_runtime_bits)
- try wip_nav.blockValue(nav_src_loc, .fromInterned(field_init));
- }
- try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
- }
- },
- .@"packed" => {
- try wip_nav.declCommon(.{
- .decl = .decl_packed_struct,
- .generic_decl = .generic_decl_const,
- .decl_instance = .decl_instance_packed_struct,
- }, &nav, inst_info.file, &decl);
- try wip_nav.refType(.fromInterned(loaded_struct.backingIntTypeUnordered(ip)));
- var field_bit_offset: u16 = 0;
- for (0..loaded_struct.field_types.len) |field_index| {
- try wip_nav.abbrevCode(.packed_struct_field);
- try wip_nav.strp(loaded_struct.fieldName(ip, field_index).toSlice(ip));
- const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
- try wip_nav.refType(field_type);
- try diw.writeUleb128(field_bit_offset);
- field_bit_offset += @intCast(field_type.bitSize(zcu));
- }
- try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
- },
- }
- break :tag .done;
+ break :tag .alias;
},
.enum_type => tag: {
const loaded_enum = ip.loadEnumType(nav_val.toIntern());
- const type_zir_index = loaded_enum.zir_index.unwrap() orelse break :tag .decl_alias;
- if (type_zir_index.resolveFile(ip) != inst_info.file) break :tag .decl_alias;
-
- const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
- if (type_gop.found_existing) {
- if (dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).len > 0) break :tag .decl_alias;
- assert(!nav_gop.found_existing);
- nav_gop.value_ptr.* = type_gop.value_ptr.*;
- } else {
- if (nav_gop.found_existing)
- dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
- else
- nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
- type_gop.value_ptr.* = nav_gop.value_ptr.*;
+ if (nav_index.toOptional() == loaded_enum.name_nav) {
+ // This Nav's entry is populated by the type, not the actual Nav.
+ _ = try dwarf.const_pool.get(pt, .{ .dwarf = dwarf }, nav_val.toIntern());
+ try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });
+ return;
}
- wip_nav.entry = nav_gop.value_ptr.*;
- const diw = &wip_nav.debug_info.writer;
- try wip_nav.declCommon(if (loaded_enum.names.len > 0) .{
- .decl = .decl_enum,
- .generic_decl = .generic_decl_const,
- .decl_instance = .decl_instance_enum,
- } else .{
- .decl = .decl_empty_enum,
- .generic_decl = .generic_decl_const,
- .decl_instance = .decl_instance_empty_enum,
- }, &nav, inst_info.file, &decl);
- try wip_nav.refType(.fromInterned(loaded_enum.tag_ty));
- for (0..loaded_enum.names.len) |field_index| {
- try wip_nav.enumConstValue(loaded_enum, .{
- .sdata = .signed_enum_field,
- .udata = .unsigned_enum_field,
- .block = .big_enum_field,
- }, field_index);
- try wip_nav.strp(loaded_enum.names.get(ip)[field_index].toSlice(ip));
- }
- if (loaded_enum.names.len > 0) try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
- break :tag .done;
+ break :tag .alias;
},
.union_type => tag: {
const loaded_union = ip.loadUnionType(nav_val.toIntern());
- if (loaded_union.zir_index.resolveFile(ip) != inst_info.file) break :tag .decl_alias;
-
- const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
- if (type_gop.found_existing) {
- if (dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).len > 0) break :tag .decl_alias;
- assert(!nav_gop.found_existing);
- nav_gop.value_ptr.* = type_gop.value_ptr.*;
- } else {
- if (nav_gop.found_existing)
- dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
- else
- nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
- type_gop.value_ptr.* = nav_gop.value_ptr.*;
+ if (nav_index.toOptional() == loaded_union.name_nav) {
+ // This Nav's entry is populated by the type, not the actual Nav.
+ _ = try dwarf.const_pool.get(pt, .{ .dwarf = dwarf }, nav_val.toIntern());
+ try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });
+ return;
}
- wip_nav.entry = nav_gop.value_ptr.*;
- const diw = &wip_nav.debug_info.writer;
- try wip_nav.declCommon(.{
- .decl = .decl_union,
- .generic_decl = .generic_decl_const,
- .decl_instance = .decl_instance_union,
- }, &nav, inst_info.file, &decl);
- const union_layout = Type.getUnionLayout(loaded_union, zcu);
- try diw.writeUleb128(union_layout.abi_size);
- try diw.writeUleb128(union_layout.abi_align.toByteUnits().?);
- const loaded_tag = loaded_union.loadTagType(ip);
- if (loaded_union.hasTag(ip)) {
- try wip_nav.abbrevCode(.tagged_union);
- try wip_nav.infoSectionOffset(
- .debug_info,
- wip_nav.unit,
- wip_nav.entry,
- @intCast(diw.end + dwarf.sectionOffsetBytes()),
- );
- {
- try wip_nav.abbrevCode(.generated_field);
- try wip_nav.strp("tag");
- try wip_nav.refType(.fromInterned(loaded_union.enum_tag_ty));
- try diw.writeUleb128(union_layout.tagOffset());
-
- for (0..loaded_union.field_types.len) |field_index| {
- try wip_nav.enumConstValue(loaded_tag, .{
- .sdata = .signed_tagged_union_field,
- .udata = .unsigned_tagged_union_field,
- .block = .big_tagged_union_field,
- }, field_index);
- {
- try wip_nav.abbrevCode(.struct_field);
- try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
- const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]);
- try wip_nav.refType(field_type);
- try diw.writeUleb128(union_layout.payloadOffset());
- try diw.writeUleb128(loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse
- if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(zcu).toByteUnits().?);
- }
- try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
- }
- }
- try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
- } else for (0..loaded_union.field_types.len) |field_index| {
- try wip_nav.abbrevCode(.untagged_union_field);
- try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
- const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]);
- try wip_nav.refType(field_type);
- try diw.writeUleb128(loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse
- if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(zcu).toByteUnits().?);
- }
- try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
- break :tag .done;
+ break :tag .alias;
},
.opaque_type => tag: {
const loaded_opaque = ip.loadOpaqueType(nav_val.toIntern());
- if (loaded_opaque.zir_index.resolveFile(ip) != inst_info.file) break :tag .decl_alias;
-
- const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
- if (type_gop.found_existing) {
- if (dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).len > 0) break :tag .decl_alias;
- assert(!nav_gop.found_existing);
- nav_gop.value_ptr.* = type_gop.value_ptr.*;
- } else {
- if (nav_gop.found_existing)
- dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
- else
- nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
- type_gop.value_ptr.* = nav_gop.value_ptr.*;
+ if (nav_index.toOptional() == loaded_opaque.name_nav) {
+ // This Nav's entry is populated by the type, not the actual Nav.
+ _ = try dwarf.const_pool.get(pt, .{ .dwarf = dwarf }, nav_val.toIntern());
+ try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });
+ return;
}
- wip_nav.entry = nav_gop.value_ptr.*;
- const diw = &wip_nav.debug_info.writer;
- try wip_nav.declCommon(.{
- .decl = .decl_namespace_struct,
- .generic_decl = .generic_decl_const,
- .decl_instance = .decl_instance_namespace_struct,
- }, &nav, inst_info.file, &decl);
- try diw.writeByte(@intFromBool(true));
- break :tag .done;
+ break :tag .alias;
},
+
.undef,
.simple_value,
.int,
@@ -3371,70 +3120,76 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
.error_union,
.enum_literal,
.enum_tag,
- .empty_enum_value,
.float,
.ptr,
.slice,
.opt,
.aggregate,
.un,
- => .decl_const,
- .variable => .decl_var,
+ .bitpack,
+ => .@"const",
+
+ .variable => .@"var",
+
.@"extern" => unreachable,
+
.func => |func| tag: {
- if (func.owner_nav != nav_index) break :tag .{ .decl_func_alias = func.owner_nav };
- if (nav_gop.found_existing) switch (try dwarf.debug_info.declAbbrevCode(wip_nav.unit, nav_gop.value_ptr.*)) {
- .null => {},
- else => unreachable,
- .decl_nullary_func, .decl_func, .decl_instance_nullary_func, .decl_instance_func => return,
- .decl_nullary_func_generic,
- .decl_func_generic,
- .decl_instance_nullary_func_generic,
- .decl_instance_func_generic,
- => dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear(),
- } else nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
- wip_nav.entry = nav_gop.value_ptr.*;
-
- const func_type = ip.indexToKey(func.ty).func_type;
- const is_nullary = !func_type.is_var_args and for (0..func_type.param_types.len) |param_index| {
- if (!func_type.paramIsComptime(std.math.cast(u5, param_index) orelse break false)) break false;
- } else true;
- const diw = &wip_nav.debug_info.writer;
- try wip_nav.declCommon(if (is_nullary) .{
- .decl = .decl_nullary_func_generic,
- .generic_decl = .generic_decl_func,
- .decl_instance = .decl_instance_nullary_func_generic,
- } else .{
- .decl = .decl_func_generic,
- .generic_decl = .generic_decl_func,
- .decl_instance = .decl_instance_func_generic,
- }, &nav, inst_info.file, &decl);
- try wip_nav.refType(.fromInterned(func_type.return_type));
- if (!is_nullary) {
- for (0..func_type.param_types.len) |param_index| {
- if (std.math.cast(u5, param_index)) |small_param_index|
- if (func_type.paramIsComptime(small_param_index)) continue;
- try wip_nav.abbrevCode(.func_type_param);
- try wip_nav.refType(.fromInterned(func_type.param_types.get(ip)[param_index]));
- }
- if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args);
- try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
- }
- break :tag .done;
+ if (func.owner_nav != nav_index) break :tag .{ .func_alias = func.owner_nav };
+ break :tag .{ .func = .fromInterned(func.ty) };
},
+
// memoization, not types
.memoized_call => unreachable,
};
- if (tag != .done) {
- if (nav_gop.found_existing)
- dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
- else
- nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
- wip_nav.entry = nav_gop.value_ptr.*;
+
+ const unit = try dwarf.getUnit(file.mod.?);
+
+ const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
+ errdefer _ = if (!nav_gop.found_existing) dwarf.navs.pop();
+
+ if (nav_gop.found_existing) {
+ if (tag == .func) switch (try dwarf.debug_info.declAbbrevCode(unit, nav_gop.value_ptr.*)) {
+ else => unreachable,
+
+ .decl_nullary_func,
+ .decl_func,
+ .decl_instance_nullary_func,
+ .decl_instance_func,
+ => return,
+
+ .null,
+ .decl_nullary_func_generic,
+ .decl_func_generic,
+ .decl_instance_nullary_func_generic,
+ .decl_instance_func_generic,
+ => {},
+ };
+ dwarf.debug_info.section.getUnit(unit).getEntry(nav_gop.value_ptr.*).clear();
+ } else {
+ nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
}
+
+ var wip_nav: WipNav = .{
+ .dwarf = dwarf,
+ .pt = pt,
+ .unit = unit,
+ .entry = nav_gop.value_ptr.*,
+ .any_children = false,
+ .func = .none,
+ .func_sym_index = undefined,
+ .func_high_pc = undefined,
+ .blocks = undefined,
+ .cfi = undefined,
+ .debug_frame = .init(dwarf.gpa),
+ .debug_info = .init(dwarf.gpa),
+ .debug_line = .init(dwarf.gpa),
+ .debug_loclists = .init(dwarf.gpa),
+ };
+ defer wip_nav.deinit();
+ const diw = &wip_nav.debug_info.writer;
+
switch (tag) {
- .done => {},
- .decl_alias => {
+ .alias => {
try wip_nav.declCommon(.{
.decl = .decl_alias,
.generic_decl = .generic_decl_const,
@@ -3442,8 +3197,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
}, &nav, inst_info.file, &decl);
try wip_nav.refType(nav_val.toType());
},
- .decl_var => {
- const diw = &wip_nav.debug_info.writer;
+ .@"var" => {
try wip_nav.declCommon(.{
.decl = .decl_var,
.generic_decl = .generic_decl_var,
@@ -3460,11 +3214,10 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
nav_ty.abiAlignment(zcu).toByteUnits().?);
try diw.writeByte(@intFromBool(decl.linkage != .normal));
},
- .decl_const => {
- const diw = &wip_nav.debug_info.writer;
+ .@"const" => {
const nav_ty = nav_val.typeOf(zcu);
const has_runtime_bits = nav_ty.hasRuntimeBits(zcu);
- const has_comptime_state = nav_ty.comptimeOnly(zcu) and try nav_ty.onePossibleValue(pt) == null;
+ const has_comptime_state = nav_ty.comptimeOnly(zcu);
try wip_nav.declCommon(if (has_runtime_bits and has_comptime_state) .{
.decl = .decl_const_runtime_bits_comptime_state,
.generic_decl = .generic_decl_const,
@@ -3496,7 +3249,33 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
try wip_nav.abbrevCode(.is_const);
try wip_nav.refType(nav_ty);
},
- .decl_func_alias => |owner_nav| {
+ .func => |func_ty| {
+ const func_type = ip.indexToKey(func_ty.toIntern()).func_type;
+ const is_nullary = !func_type.is_var_args and for (0..func_type.param_types.len) |param_index| {
+ if (!func_type.paramIsComptime(std.math.cast(u5, param_index) orelse break false)) break false;
+ } else true;
+ try wip_nav.declCommon(if (is_nullary) .{
+ .decl = .decl_nullary_func_generic,
+ .generic_decl = .generic_decl_func,
+ .decl_instance = .decl_instance_nullary_func_generic,
+ } else .{
+ .decl = .decl_func_generic,
+ .generic_decl = .generic_decl_func,
+ .decl_instance = .decl_instance_func_generic,
+ }, &nav, inst_info.file, &decl);
+ try wip_nav.refType(.fromInterned(func_type.return_type));
+ if (!is_nullary) {
+ for (0..func_type.param_types.len) |param_index| {
+ if (std.math.cast(u5, param_index)) |small_param_index|
+ if (func_type.paramIsComptime(small_param_index)) continue;
+ try wip_nav.abbrevCode(.func_type_param);
+ try wip_nav.refType(.fromInterned(func_type.param_types.get(ip)[param_index]));
+ }
+ if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args);
+ try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
+ }
+ },
+ .func_alias => |owner_nav| {
try wip_nav.declCommon(.{
.decl = .decl_alias,
.generic_decl = .generic_decl_const,
@@ -3505,31 +3284,94 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
try wip_nav.refNav(owner_nav);
},
}
- try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
- try wip_nav.updateLazy(nav_src_loc);
+ try dwarf.debug_info.section.replaceEntry(unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
+ try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });
}
-fn updateLazyType(
+pub fn updateContainerType(
dwarf: *Dwarf,
pt: Zcu.PerThread,
- src_loc: Zcu.LazySrcLoc,
- type_index: InternPool.Index,
- pending_lazy: *WipNav.PendingLazy,
-) (UpdateError || Writer.Error)!void {
+ ty: InternPool.Index,
+ success: bool,
+) !void {
+ try dwarf.const_pool.updateContainerType(pt, .{ .dwarf = dwarf }, ty, success);
+}
+/// Should only be called by the `link.ConstPool` implementation.
+pub fn addConst(dwarf: *Dwarf, pt: Zcu.PerThread, index: link.ConstPool.Index, val: InternPool.Index) Allocator.Error!void {
+ addConstInner(dwarf, pt, index, val) catch |err| switch (err) {
+ error.OutOfMemory => |e| return e,
+ else => |e| std.debug.panic("DWARF TODO: '{t}' while registering constant\n", .{e}),
+ };
+}
+fn addConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, index: link.ConstPool.Index, val: InternPool.Index) !void {
+ const zcu = pt.zcu;
+ const ip = &zcu.intern_pool;
+
+ const unit: Unit.Index, const entry: Entry.Index = switch (ip.indexToKey(val)) {
+ else => .{ .main, try dwarf.addCommonEntry(.main) },
+ .func => |func| try dwarf.getNavEntry(func.owner_nav),
+ .@"extern" => |@"extern"| try dwarf.getNavEntry(@"extern".owner_nav),
+ .struct_type, .union_type, .enum_type, .opaque_type => |_, tag| entry: {
+ const name_nav = switch (tag) {
+ .struct_type => ip.loadStructType(val).name_nav,
+ .union_type => ip.loadUnionType(val).name_nav,
+ .enum_type => ip.loadEnumType(val).name_nav,
+ .opaque_type => ip.loadOpaqueType(val).name_nav,
+ else => unreachable,
+ };
+ if (name_nav.unwrap()) |nav| {
+ break :entry try dwarf.getNavEntry(nav);
+ } else {
+ const zir_index = Type.fromInterned(val).typeDeclInstAllowGeneratedTag(zcu).?;
+ const unit = try dwarf.getUnit(zcu.fileByIndex(zir_index.resolveFile(ip)).mod.?);
+ break :entry .{ unit, try dwarf.addCommonEntry(unit) };
+ }
+ },
+ };
+
+ assert(@intFromEnum(index) == dwarf.values.items.len);
+ try dwarf.values.append(dwarf.gpa, .{ unit, entry });
+}
+/// Should only be called by the `link.ConstPool` implementation.
+///
+/// Emits a "dummy" DIE for the given comptime-only value (which may be a type). For types, this is
+/// an opaque type. Otherwise, it is an undefined value of the value's type.
+pub fn updateConstIncomplete(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.ConstPool.Index, value_index: InternPool.Index) Allocator.Error!void {
+ updateConstIncompleteInner(dwarf, pt, debug_const_index, value_index) catch |err| switch (err) {
+ error.OutOfMemory => |e| return e,
+ else => |e| std.debug.panic("DWARF TODO: '{t}' while updating incomplete constant\n", .{e}),
+ };
+}
+fn updateConstIncompleteInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.ConstPool.Index, value_index: InternPool.Index) !void {
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
- assert(ip.typeOf(type_index) == .type_type);
- const ty: Type = .fromInterned(type_index);
- switch (type_index) {
- .generic_poison_type => log.debug("updateLazyType({s})", .{"anytype"}),
- else => log.debug("updateLazyType({f})", .{ty.fmt(pt)}),
+
+ const val: Value = .fromInterned(value_index);
+
+ switch (value_index) {
+ .generic_poison_type => log.debug("updateValueIncomplete(anytype)", .{}),
+ else => log.debug("updateValueIncomplete(@as({f}, {f}))", .{
+ val.typeOf(zcu).fmt(pt),
+ val.fmtValue(pt),
+ }),
}
+ const unit, const entry = dwarf.values.items[@intFromEnum(debug_const_index)];
+
+ for ([_]*Section{
+ &dwarf.debug_aranges.section,
+ &dwarf.debug_aranges.section,
+ &dwarf.debug_info.section,
+ &dwarf.debug_line.section,
+ &dwarf.debug_loclists.section,
+ &dwarf.debug_rnglists.section,
+ }) |sec| sec.getUnit(unit).getEntry(entry).clear();
+
var wip_nav: WipNav = .{
.dwarf = dwarf,
.pt = pt,
- .unit = .main,
- .entry = dwarf.types.get(type_index).?,
+ .unit = unit,
+ .entry = entry,
.any_children = false,
.func = .none,
.func_sym_index = undefined,
@@ -3540,43 +3382,216 @@ fn updateLazyType(
.debug_info = .init(dwarf.gpa),
.debug_line = .init(dwarf.gpa),
.debug_loclists = .init(dwarf.gpa),
- .pending_lazy = pending_lazy.*,
};
- defer {
- pending_lazy.* = wip_nav.pending_lazy;
- wip_nav.pending_lazy = .empty;
- wip_nav.deinit();
+ defer wip_nav.deinit();
+
+ switch (ip.indexToKey(value_index)) {
+ // Container types still need to be valid namespaces.
+ .struct_type => {
+ const loaded_struct = ip.loadStructType(value_index);
+ const root_of_file: ?Zcu.File.Index = if (loaded_struct.zir_index.resolveFull(ip)) |r| f: {
+ if (r.inst != .main_struct_inst) break :f null;
+ break :f r.file;
+ } else null;
+ if (root_of_file) |file_index| {
+ assert(loaded_struct.name_nav == .none);
+ const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file_index);
+ try wip_nav.abbrevCode(.empty_file);
+ try wip_nav.debug_info.writer.writeUleb128(file_gop.index);
+ try wip_nav.strp(loaded_struct.name.toSlice(ip));
+ } else {
+ try dwarf.emitIncompleteContainerType(
+ &wip_nav,
+ loaded_struct.zir_index,
+ loaded_struct.name,
+ loaded_struct.name_nav,
+ );
+ }
+ },
+ .union_type => {
+ const loaded_union = ip.loadUnionType(value_index);
+ try dwarf.emitIncompleteContainerType(
+ &wip_nav,
+ loaded_union.zir_index,
+ loaded_union.name,
+ loaded_union.name_nav,
+ );
+ },
+ .enum_type => {
+ const loaded_enum = ip.loadEnumType(value_index);
+ if (loaded_enum.zir_index.unwrap()) |zir_index| {
+ try dwarf.emitIncompleteContainerType(
+ &wip_nav,
+ zir_index,
+ loaded_enum.name,
+ loaded_enum.name_nav,
+ );
+ } else {
+ try wip_nav.abbrevCode(.generated_empty_struct_type);
+ try wip_nav.strp(loaded_enum.name.toSlice(ip));
+ try wip_nav.debug_info.writer.writeByte(@intFromBool(true));
+ }
+ },
+ .opaque_type => {
+ const loaded_opaque = ip.loadOpaqueType(value_index);
+ try dwarf.emitIncompleteContainerType(
+ &wip_nav,
+ loaded_opaque.zir_index,
+ loaded_opaque.name,
+ loaded_opaque.name_nav,
+ );
+ },
+ // Not a container type, so just emit a dummy entry. If `val` happens to be a type, we'll
+ // emit it as if it were an opaque type so that we can name it.
+ else => |val_key| switch (val_key.typeOf()) {
+ .type_type => {
+ try wip_nav.abbrevCode(.generated_empty_struct_type);
+ try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
+ try wip_nav.debug_info.writer.writeByte(@intFromBool(true));
+ },
+ else => |ty| {
+ try wip_nav.abbrevCode(.undefined_comptime_value);
+ try wip_nav.refType(.fromInterned(ty));
+ },
+ },
+ }
+ try dwarf.debug_info.section.replaceEntry(unit, entry, dwarf, wip_nav.debug_info.written());
+ try dwarf.debug_loclists.section.replaceEntry(unit, entry, dwarf, wip_nav.debug_loclists.written());
+}
+fn emitIncompleteContainerType(
+ dwarf: *Dwarf,
+ wip_nav: *WipNav,
+ zir_index: InternPool.TrackedInst.Index,
+ name: InternPool.NullTerminatedString,
+ name_nav: InternPool.Nav.Index.Optional,
+) !void {
+ const zcu = wip_nav.pt.zcu;
+ const ip = &zcu.intern_pool;
+ const file = zir_index.resolveFile(ip);
+ if (name_nav.unwrap()) |nav_index| {
+ const nav = ip.getNav(nav_index);
+ const decl_inst = nav.srcInst(ip).resolve(ip).?;
+ const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
+ try wip_nav.declCommon(.{
+ .decl = .decl_namespace_struct,
+ .generic_decl = .generic_decl_const,
+ .decl_instance = .decl_instance_namespace_struct,
+ }, &nav, file, &decl);
+ try wip_nav.debug_info.writer.writeByte(@intFromBool(true));
+ } else {
+ const diw = &wip_nav.debug_info.writer;
+ const file_gop = try dwarf.getModInfo(wip_nav.unit).files.getOrPut(dwarf.gpa, file);
+ try wip_nav.abbrevCode(.empty_struct_type);
+ try diw.writeUleb128(file_gop.index);
+ try wip_nav.strp(name.toSlice(ip));
+ try diw.writeByte(@intFromBool(true));
+ }
+}
+/// Should only be called by the `link.ConstPool` implementation.
+///
+/// Emits a DIE for the given comptime-only value (which may be a type).
+pub fn updateConst(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.ConstPool.Index, value_index: InternPool.Index) Allocator.Error!void {
+ updateConstInner(dwarf, pt, debug_const_index, value_index) catch |err| switch (err) {
+ error.OutOfMemory => |e| return e,
+ else => |e| std.debug.panic("DWARF TODO: '{t}' while updating constant\n", .{e}),
+ };
+}
+fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.ConstPool.Index, value_index: InternPool.Index) !void {
+ const zcu = pt.zcu;
+ const ip = &zcu.intern_pool;
+
+ const val: Value = .fromInterned(value_index);
+
+ if (val.typeOf(zcu).toIntern() == .type_type and !val.isUndef(zcu)) {
+ val.toType().assertHasLayout(zcu);
+ } else {
+ val.typeOf(zcu).assertHasLayout(zcu);
+ }
+
+ if (value_index == .anyerror_type) return; // handled in `flush` instead
+
+ const value_ip_key = ip.indexToKey(value_index);
+ switch (value_ip_key) {
+ .func => return, // populated by the Nav instead (`updateComptimeNav` or `initWipNav`)
+ .@"extern" => return, // populated by the Nav instead (`initWipNav`)
+ else => {},
}
+
+ switch (value_index) {
+ .generic_poison_type => log.debug("updateValue(anytype)", .{}),
+ else => log.debug("updateValue(@as({f}, {f}))", .{
+ val.typeOf(zcu).fmt(pt),
+ val.fmtValue(pt),
+ }),
+ }
+
+ const unit, const entry = dwarf.values.items[@intFromEnum(debug_const_index)];
+
+ for ([_]*Section{
+ &dwarf.debug_aranges.section,
+ &dwarf.debug_info.section,
+ &dwarf.debug_line.section,
+ &dwarf.debug_loclists.section,
+ &dwarf.debug_rnglists.section,
+ }) |sec| sec.getUnit(unit).getEntry(entry).clear();
+
+ var wip_nav: WipNav = .{
+ .dwarf = dwarf,
+ .pt = pt,
+ .unit = unit,
+ .entry = entry,
+ .any_children = false,
+ .func = .none,
+ .func_sym_index = undefined,
+ .func_high_pc = undefined,
+ .blocks = undefined,
+ .cfi = undefined,
+ .debug_frame = .init(dwarf.gpa),
+ .debug_info = .init(dwarf.gpa),
+ .debug_line = .init(dwarf.gpa),
+ .debug_loclists = .init(dwarf.gpa),
+ };
+ defer wip_nav.deinit();
+
+ // TODO: we really shouldn't need source locations at this point in the pipeline: we've lost
+ // that information by now. If the linker fundamentally cannot lower certain values, that needs
+ // to be caught in the frontend; if it can only hit transient failures, they should be reported
+ // without trying to tie them to a bogus source location.
+ const src_loc: Zcu.LazySrcLoc = .{
+ .base_node_inst = inst: {
+ const mod_root_file_index = zcu.module_roots.get(zcu.std_mod).?.unwrap().?;
+ const mod_root_type_index = zcu.fileRootType(mod_root_file_index);
+ break :inst ip.loadStructType(mod_root_type_index).zir_index;
+ },
+ .offset = .{ .byte_abs = 0 },
+ };
+
const diw = &wip_nav.debug_info.writer;
- const name = switch (type_index) {
- .generic_poison_type => "",
- else => try std.fmt.allocPrint(dwarf.gpa, "{f}", .{ty.fmt(pt)}),
- };
- defer dwarf.gpa.free(name);
+ var big_int_space: Value.BigIntSpace = undefined;
+ switch (value_ip_key) {
+ .func => unreachable, // handled above
+ .@"extern" => unreachable, // handled above
- switch (ip.indexToKey(type_index)) {
- .undef => {
- try wip_nav.abbrevCode(.undefined_comptime_value);
- try wip_nav.refType(.type);
- },
.int_type => |int_type| {
try wip_nav.abbrevCode(.numeric_type);
- try wip_nav.strp(name);
+ try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
try diw.writeByte(switch (int_type.signedness) {
inline .signed, .unsigned => |signedness| @field(DW.ATE, @tagName(signedness)),
});
try diw.writeUleb128(int_type.bits);
- try diw.writeUleb128(ty.abiSize(zcu));
- try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
+ try diw.writeUleb128(val.toType().abiSize(zcu));
+ try diw.writeUleb128(val.toType().abiAlignment(zcu).toByteUnits().?);
},
.ptr_type => |ptr_type| switch (ptr_type.flags.size) {
.one, .many, .c => {
const ptr_child_type: Type = .fromInterned(ptr_type.child);
- try wip_nav.abbrevCode(if (ptr_type.sentinel == .none) .ptr_type else .ptr_sentinel_type);
- try wip_nav.strp(name);
+ try wip_nav.abbrevCode(switch (ptr_type.flags.alignment) {
+ .none => if (ptr_type.sentinel == .none) .ptr_type else .ptr_sentinel_type,
+ else => if (ptr_type.sentinel == .none) .ptr_aligned_type else .ptr_aligned_sentinel_type,
+ });
+ try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
if (ptr_type.sentinel != .none) try wip_nav.blockValue(src_loc, .fromInterned(ptr_type.sentinel));
- try diw.writeUleb128(ptr_type.flags.alignment.toByteUnits() orelse
- ptr_child_type.abiAlignment(zcu).toByteUnits().?);
+ if (ptr_type.flags.alignment.toByteUnits()) |a| try diw.writeUleb128(a);
try diw.writeByte(@intFromEnum(ptr_type.flags.address_space));
if (ptr_type.flags.is_const or ptr_type.flags.is_volatile) try wip_nav.infoSectionOffset(
.debug_info,
@@ -3600,12 +3615,12 @@ fn updateLazyType(
},
.slice => {
try wip_nav.abbrevCode(.generated_struct_type);
- try wip_nav.strp(name);
- try diw.writeUleb128(ty.abiSize(zcu));
- try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
+ try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
+ try diw.writeUleb128(val.toType().abiSize(zcu));
+ try diw.writeUleb128(val.toType().abiAlignment(zcu).toByteUnits().?);
try wip_nav.abbrevCode(.generated_field);
try wip_nav.strp("ptr");
- const ptr_field_type = ty.slicePtrFieldType(zcu);
+ const ptr_field_type = val.toType().slicePtrFieldType(zcu);
try wip_nav.refType(ptr_field_type);
try diw.writeUleb128(0);
try wip_nav.abbrevCode(.generated_field);
@@ -3619,7 +3634,7 @@ fn updateLazyType(
.array_type => |array_type| {
const array_child_type: Type = .fromInterned(array_type.child);
try wip_nav.abbrevCode(if (array_type.sentinel == .none) .array_type else .array_sentinel_type);
- try wip_nav.strp(name);
+ try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
if (array_type.sentinel != .none) try wip_nav.blockValue(src_loc, .fromInterned(array_type.sentinel));
try wip_nav.refType(array_child_type);
try wip_nav.abbrevCode(.array_len);
@@ -3629,7 +3644,7 @@ fn updateLazyType(
},
.vector_type => |vector_type| {
try wip_nav.abbrevCode(.vector_type);
- try wip_nav.strp(name);
+ try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
try wip_nav.refType(.fromInterned(vector_type.child));
try wip_nav.abbrevCode(.array_len);
try wip_nav.refType(.usize);
@@ -3640,9 +3655,9 @@ fn updateLazyType(
const opt_child_type: Type = .fromInterned(opt_child_type_index);
const opt_repr = optRepr(opt_child_type, zcu);
try wip_nav.abbrevCode(.generated_union_type);
- try wip_nav.strp(name);
- try diw.writeUleb128(ty.abiSize(zcu));
- try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
+ try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
+ try diw.writeUleb128(val.toType().abiSize(zcu));
+ try diw.writeUleb128(val.toType().abiAlignment(zcu).toByteUnits().?);
switch (opt_repr) {
.opv_null => {
try wip_nav.abbrevCode(.generated_field);
@@ -3720,12 +3735,12 @@ fn updateLazyType(
};
try wip_nav.abbrevCode(.generated_union_type);
- try wip_nav.strp(name);
+ try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
if (error_union_type.error_set_type != .generic_poison_type and
error_union_type.payload_type != .generic_poison_type)
{
- try diw.writeUleb128(ty.abiSize(zcu));
- try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
+ try diw.writeUleb128(val.toType().abiSize(zcu));
+ try diw.writeUleb128(val.toType().abiAlignment(zcu).toByteUnits().?);
} else {
try diw.writeUleb128(0);
try diw.writeUleb128(1);
@@ -3791,20 +3806,24 @@ fn updateLazyType(
.bool,
=> {
try wip_nav.abbrevCode(.numeric_type);
- try wip_nav.strp(name);
- try diw.writeByte(if (type_index == .bool_type)
+ try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
+ try diw.writeByte(if (value_index == .bool_type)
DW.ATE.boolean
- else if (ty.isRuntimeFloat())
+ else if (val.toType().isRuntimeFloat())
DW.ATE.float
- else if (ty.isSignedInt(zcu))
+ else if (val.toType().isSignedInt(zcu))
DW.ATE.signed
- else if (ty.isUnsignedInt(zcu))
+ else if (val.toType().isUnsignedInt(zcu))
DW.ATE.unsigned
else
unreachable);
- try diw.writeUleb128(ty.bitSize(zcu));
- try diw.writeUleb128(ty.abiSize(zcu));
- try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
+ try diw.writeUleb128(val.toType().bitSize(zcu));
+ try diw.writeUleb128(val.toType().abiSize(zcu));
+ try diw.writeUleb128(val.toType().abiAlignment(zcu).toByteUnits().?);
+ },
+ .generic_poison => {
+ try wip_nav.abbrevCode(.void_type);
+ try wip_nav.strp("anytype");
},
.anyopaque,
.void,
@@ -3815,37 +3834,29 @@ fn updateLazyType(
.null,
.undefined,
.enum_literal,
- .generic_poison,
=> {
try wip_nav.abbrevCode(.void_type);
- try wip_nav.strp(if (type_index == .generic_poison_type) "anytype" else name);
+ try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
},
- .anyerror => return, // delay until flush
+ .anyerror => unreachable, // already did early return above
.adhoc_inferred_error_set => unreachable,
},
- .struct_type,
- .union_type,
- .opaque_type,
- => unreachable,
.tuple_type => |tuple_type| if (tuple_type.types.len == 0) {
try wip_nav.abbrevCode(.generated_empty_struct_type);
- try wip_nav.strp(name);
+ try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
try diw.writeByte(@intFromBool(false));
} else {
try wip_nav.abbrevCode(.generated_struct_type);
- try wip_nav.strp(name);
- try diw.writeUleb128(ty.abiSize(zcu));
- try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
+ try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
+ try diw.writeUleb128(val.toType().abiSize(zcu));
+ try diw.writeUleb128(val.toType().abiAlignment(zcu).toByteUnits().?);
var field_byte_offset: u64 = 0;
for (0..tuple_type.types.len) |field_index| {
const comptime_value = tuple_type.values.get(ip)[field_index];
const field_type: Type = .fromInterned(tuple_type.types.get(ip)[field_index]);
const has_runtime_bits, const has_comptime_state = switch (comptime_value) {
.none => .{ false, false },
- else => .{
- field_type.hasRuntimeBits(zcu),
- field_type.comptimeOnly(zcu) and try field_type.onePossibleValue(pt) == null,
- },
+ else => .{ field_type.hasRuntimeBits(zcu), field_type.comptimeOnly(zcu) },
};
try wip_nav.abbrevCode(if (has_comptime_state)
.struct_field_comptime_comptime_state
@@ -3875,25 +3886,284 @@ fn updateLazyType(
}
try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
},
+ .struct_type => {
+ const loaded_struct = ip.loadStructType(value_index);
+ const ty = val.toType();
+ const file = loaded_struct.zir_index.resolveFile(ip);
+ switch (loaded_struct.layout) {
+ .auto, .@"extern" => {
+ const struct_is_file: bool = if (loaded_struct.zir_index.resolve(ip)) |inst| f: {
+ break :f inst == .main_struct_inst;
+ } else false;
+ if (loaded_struct.name_nav.unwrap()) |nav_index| {
+ assert(!struct_is_file);
+ const nav = ip.getNav(nav_index);
+ const decl_inst = nav.srcInst(ip).resolve(ip).?;
+ const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
+ try wip_nav.declCommon(if (loaded_struct.field_types.len == 0) .{
+ .decl = .decl_namespace_struct,
+ .generic_decl = .generic_decl_const,
+ .decl_instance = .decl_instance_namespace_struct,
+ } else .{
+ .decl = .decl_struct,
+ .generic_decl = .generic_decl_const,
+ .decl_instance = .decl_instance_struct,
+ }, &nav, file, &decl);
+ } else {
+ const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
+ try wip_nav.abbrevCode(switch (loaded_struct.field_types.len) {
+ 0 => if (struct_is_file) .empty_file else .empty_struct_type,
+ else => if (struct_is_file) .file else .struct_type,
+ });
+ try diw.writeUleb128(file_gop.index);
+ try wip_nav.strp(loaded_struct.name.toSlice(ip));
+ }
+ if (loaded_struct.field_types.len == 0) {
+ if (!struct_is_file) try diw.writeByte(@intFromBool(false));
+ } else {
+ try diw.writeUleb128(ty.abiSize(zcu));
+ try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
+ for (0..loaded_struct.field_types.len) |field_index| {
+ const is_comptime = loaded_struct.field_is_comptime_bits.get(ip, field_index);
+ // TODO: we currently don't emit information about default values for
+ // non-`comptime` fields, because these default values are resolved at a
+ // separate time in the compiler frontend. To emit this information, the
+ // frontend needs to tell us when the default values are available: like
+ // how `Zcu.PerThread.ensureTypeLayoutUpToDate` enqueues a link task to
+ // indicate completion of the type's layout, a task should be enqueued
+ // by `Zcu.PerThread.ensureStructDefaultsUpToDate`, and upon receiving
+ // it we should patch the correct default field values in.
+ const field_init: InternPool.Index = if (is_comptime) loaded_struct.field_defaults.getOrNone(ip, field_index) else .none;
+ assert(!(is_comptime and field_init == .none));
+ const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
+ const has_runtime_bits, const has_comptime_state = switch (field_init) {
+ .none => .{ false, false },
+ else => .{
+ field_type.hasRuntimeBits(zcu),
+ field_type.comptimeOnly(zcu),
+ },
+ };
+ try wip_nav.abbrevCode(if (is_comptime)
+ if (has_comptime_state)
+ .struct_field_comptime_comptime_state
+ else if (has_runtime_bits)
+ .struct_field_comptime_runtime_bits
+ else
+ .struct_field_comptime
+ else if (field_init != .none)
+ if (has_comptime_state)
+ .struct_field_default_comptime_state
+ else if (has_runtime_bits)
+ .struct_field_default_runtime_bits
+ else
+ .struct_field
+ else
+ .struct_field);
+ try wip_nav.strp(loaded_struct.field_names.get(ip)[field_index].toSlice(ip));
+ try wip_nav.refType(field_type);
+ if (!is_comptime) {
+ try diw.writeUleb128(loaded_struct.field_offsets.get(ip)[field_index]);
+ try diw.writeUleb128(loaded_struct.field_aligns.getOrNone(ip, field_index).toByteUnits() orelse
+ field_type.abiAlignment(zcu).toByteUnits().?);
+ }
+ if (has_comptime_state)
+ try wip_nav.refValue(.fromInterned(field_init))
+ else if (has_runtime_bits)
+ try wip_nav.blockValue(ty.srcLoc(zcu), .fromInterned(field_init));
+ }
+ try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
+ }
+ },
+ .@"packed" => {
+ const need_terminator: bool = if (loaded_struct.name_nav.unwrap()) |nav_index| t: {
+ const nav = ip.getNav(nav_index);
+ const decl_inst = nav.srcInst(ip).resolve(ip).?;
+ const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
+ try wip_nav.declCommon(.{
+ .decl = .decl_packed_struct,
+ .generic_decl = .generic_decl_const,
+ .decl_instance = .decl_instance_packed_struct,
+ }, &nav, file, &decl);
+ break :t true;
+ } else t: {
+ const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
+ try wip_nav.abbrevCode(if (loaded_struct.field_types.len > 0) .packed_struct_type else .empty_packed_struct_type);
+ try diw.writeUleb128(file_gop.index);
+ try wip_nav.strp(loaded_struct.name.toSlice(ip));
+ break :t loaded_struct.field_types.len > 0;
+ };
+ try wip_nav.refType(.fromInterned(loaded_struct.packed_backing_int_type));
+ var field_bit_offset: u16 = 0;
+ for (0..loaded_struct.field_types.len) |field_index| {
+ try wip_nav.abbrevCode(.packed_struct_field);
+ try wip_nav.strp(loaded_struct.field_names.get(ip)[field_index].toSlice(ip));
+ const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
+ try wip_nav.refType(field_type);
+ try diw.writeUleb128(field_bit_offset);
+ field_bit_offset += @intCast(field_type.bitSize(zcu));
+ }
+ if (need_terminator) try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
+ },
+ }
+ },
+ .union_type => {
+ const loaded_union = ip.loadUnionType(value_index);
+ const file = loaded_union.zir_index.resolveFile(ip);
+ switch (loaded_union.layout) {
+ .auto, .@"extern" => {
+ const need_terminator: bool = if (loaded_union.name_nav.unwrap()) |nav_index| t: {
+ const nav = ip.getNav(nav_index);
+ const decl_inst = nav.srcInst(ip).resolve(ip).?;
+ const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
+ try wip_nav.declCommon(.{
+ .decl = .decl_union,
+ .generic_decl = .generic_decl_const,
+ .decl_instance = .decl_instance_union,
+ }, &nav, file, &decl);
+ break :t true;
+ } else t: {
+ const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
+ try wip_nav.abbrevCode(if (loaded_union.field_types.len > 0) .union_type else .empty_union_type);
+ try diw.writeUleb128(file_gop.index);
+ try wip_nav.strp(loaded_union.name.toSlice(ip));
+ break :t loaded_union.field_types.len > 0;
+ };
+ const union_layout = Type.getUnionLayout(loaded_union, zcu);
+ try diw.writeUleb128(union_layout.abi_size);
+ try diw.writeUleb128(union_layout.abi_align.toByteUnits().?);
+ const loaded_tag = ip.loadEnumType(loaded_union.enum_tag_type);
+ if (loaded_union.has_runtime_tag) {
+ try wip_nav.abbrevCode(.tagged_union);
+ try wip_nav.infoSectionOffset(
+ .debug_info,
+ wip_nav.unit,
+ wip_nav.entry,
+ @intCast(diw.end + dwarf.sectionOffsetBytes()),
+ );
+ {
+ try wip_nav.abbrevCode(.generated_field);
+ try wip_nav.strp("tag");
+ try wip_nav.refType(.fromInterned(loaded_union.enum_tag_type));
+ try diw.writeUleb128(union_layout.tagOffset());
+
+ for (0..loaded_union.field_types.len) |field_index| {
+ try wip_nav.enumConstValue(loaded_tag, .{
+ .sdata = .signed_tagged_union_field,
+ .udata = .unsigned_tagged_union_field,
+ .block = .big_tagged_union_field,
+ }, field_index);
+ {
+ try wip_nav.abbrevCode(.struct_field);
+ try wip_nav.strp(loaded_tag.field_names.get(ip)[field_index].toSlice(ip));
+ const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]);
+ try wip_nav.refType(field_type);
+ try diw.writeUleb128(union_layout.payloadOffset());
+ try diw.writeUleb128(loaded_union.field_aligns.getOrNone(ip, field_index).toByteUnits() orelse
+ if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(zcu).toByteUnits().?);
+ }
+ try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
+ }
+ }
+ try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
+ } else for (0..loaded_union.field_types.len) |field_index| {
+ try wip_nav.abbrevCode(.untagged_union_field);
+ try wip_nav.strp(loaded_tag.field_names.get(ip)[field_index].toSlice(ip));
+ const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]);
+ try wip_nav.refType(field_type);
+ try diw.writeUleb128(loaded_union.field_aligns.getOrNone(ip, field_index).toByteUnits() orelse
+ if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(zcu).toByteUnits().?);
+ }
+ if (need_terminator) try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
+ },
+ .@"packed" => {
+ // TODO: debug info for packed unions
+ try wip_nav.abbrevCode(.numeric_type);
+ try wip_nav.strp(loaded_union.name.toSlice(ip));
+ const backing_int_ty: Type = .fromInterned(loaded_union.packed_backing_int_type);
+ const int_info = backing_int_ty.intInfo(zcu);
+ try diw.writeByte(switch (int_info.signedness) {
+ inline .signed, .unsigned => |signedness| @field(DW.ATE, @tagName(signedness)),
+ });
+ try diw.writeUleb128(int_info.bits);
+ try diw.writeUleb128(backing_int_ty.abiSize(zcu));
+ try diw.writeUleb128(backing_int_ty.abiAlignment(zcu).toByteUnits().?);
+ },
+ }
+ },
.enum_type => {
- const loaded_enum = ip.loadEnumType(type_index);
- try wip_nav.abbrevCode(if (loaded_enum.names.len == 0) .generated_empty_enum_type else .generated_enum_type);
- try wip_nav.strp(name);
- try wip_nav.refType(.fromInterned(loaded_enum.tag_ty));
- for (0..loaded_enum.names.len) |field_index| {
- try wip_nav.enumConstValue(loaded_enum, .{
- .sdata = .signed_enum_field,
- .udata = .unsigned_enum_field,
- .block = .big_enum_field,
- }, field_index);
- try wip_nav.strp(loaded_enum.names.get(ip)[field_index].toSlice(ip));
+ const loaded_enum = ip.loadEnumType(value_index);
+ if (loaded_enum.zir_index.unwrap()) |zir_index| {
+ assert(loaded_enum.owner_union == .none);
+ const file = zir_index.resolveFile(ip);
+ if (loaded_enum.name_nav.unwrap()) |nav_index| {
+ const nav = ip.getNav(nav_index);
+ const decl_inst = nav.srcInst(ip).resolve(ip).?;
+ const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
+ try wip_nav.declCommon(if (loaded_enum.field_names.len > 0) .{
+ .decl = .decl_enum,
+ .generic_decl = .generic_decl_const,
+ .decl_instance = .decl_instance_enum,
+ } else .{
+ .decl = .decl_empty_enum,
+ .generic_decl = .generic_decl_const,
+ .decl_instance = .decl_instance_empty_enum,
+ }, &nav, file, &decl);
+ } else {
+ const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
+ try wip_nav.abbrevCode(if (loaded_enum.field_names.len > 0) .enum_type else .empty_enum_type);
+ try diw.writeUleb128(file_gop.index);
+ try wip_nav.strp(loaded_enum.name.toSlice(ip));
+ }
+ try wip_nav.refType(.fromInterned(loaded_enum.int_tag_type));
+ for (0..loaded_enum.field_names.len) |field_index| {
+ try wip_nav.enumConstValue(loaded_enum, .{
+ .sdata = .signed_enum_field,
+ .udata = .unsigned_enum_field,
+ .block = .big_enum_field,
+ }, field_index);
+ try wip_nav.strp(loaded_enum.field_names.get(ip)[field_index].toSlice(ip));
+ }
+ if (loaded_enum.field_names.len > 0) try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
+ } else {
+ assert(loaded_enum.owner_union != .none);
+ try wip_nav.abbrevCode(if (loaded_enum.field_names.len == 0) .generated_empty_enum_type else .generated_enum_type);
+ try wip_nav.strp(loaded_enum.name.toSlice(ip));
+ try wip_nav.refType(.fromInterned(loaded_enum.int_tag_type));
+ for (0..loaded_enum.field_names.len) |field_index| {
+ try wip_nav.enumConstValue(loaded_enum, .{
+ .sdata = .signed_enum_field,
+ .udata = .unsigned_enum_field,
+ .block = .big_enum_field,
+ }, field_index);
+ try wip_nav.strp(loaded_enum.field_names.get(ip)[field_index].toSlice(ip));
+ }
+ if (loaded_enum.field_names.len > 0) try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
}
- if (loaded_enum.names.len > 0) try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
+ },
+ .opaque_type => {
+ const loaded_opaque = ip.loadOpaqueType(value_index);
+ const file = loaded_opaque.zir_index.resolveFile(ip);
+ if (loaded_opaque.name_nav.unwrap()) |nav_index| {
+ const nav = ip.getNav(nav_index);
+ const decl_inst = nav.srcInst(ip).resolve(ip).?;
+ const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
+ try wip_nav.declCommon(.{
+ .decl = .decl_namespace_struct,
+ .generic_decl = .generic_decl_const,
+ .decl_instance = .decl_instance_namespace_struct,
+ }, &nav, file, &decl);
+ } else {
+ const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
+ try wip_nav.abbrevCode(.empty_struct_type);
+ try diw.writeUleb128(file_gop.index);
+ try wip_nav.strp(loaded_opaque.name.toSlice(ip));
+ }
+ try diw.writeByte(@intFromBool(true));
},
.func_type => |func_type| {
const is_nullary = func_type.param_types.len == 0 and !func_type.is_var_args;
try wip_nav.abbrevCode(if (is_nullary) .nullary_func_type else .func_type);
- try wip_nav.strp(name);
+ try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
const cc: DW.CC = cc: {
if (zcu.getTarget().cCallingConvention()) |cc| {
if (@as(std.builtin.CallingConvention.Tag, cc) == func_type.cc) {
@@ -3975,7 +4245,7 @@ fn updateLazyType(
},
.error_set_type => |error_set_type| {
try wip_nav.abbrevCode(if (error_set_type.names.len == 0) .generated_empty_enum_type else .generated_enum_type);
- try wip_nav.strp(name);
+ try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
try wip_nav.refType(.fromInterned(try pt.intern(.{ .int_type = .{
.signedness = .unsigned,
.bits = zcu.errorSetBits(),
@@ -3990,100 +4260,28 @@ fn updateLazyType(
},
.inferred_error_set_type => |func| {
try wip_nav.abbrevCode(.inferred_error_set_type);
- try wip_nav.strp(name);
+ try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
try wip_nav.refType(.fromInterned(switch (ip.funcIesResolvedUnordered(func)) {
.none => .anyerror_type,
else => |ies| ies,
}));
},
- // values, not types
- .simple_value,
- .variable,
- .@"extern",
- .func,
- .int,
- .err,
- .error_union,
- .enum_literal,
- .enum_tag,
- .empty_enum_value,
- .float,
- .ptr,
- .slice,
- .opt,
- .aggregate,
- .un,
- // memoization, not types
- .memoized_call,
- => unreachable,
- }
- try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
-}
-
-fn updateLazyValue(
- dwarf: *Dwarf,
- pt: Zcu.PerThread,
- src_loc: Zcu.LazySrcLoc,
- value_index: InternPool.Index,
- pending_lazy: *WipNav.PendingLazy,
-) (UpdateError || Writer.Error)!void {
- const zcu = pt.zcu;
- const ip = &zcu.intern_pool;
- assert(ip.typeOf(value_index) != .type_type);
- log.debug("updateLazyValue(@as({f}, {f}))", .{
- Value.fromInterned(value_index).typeOf(zcu).fmt(pt),
- Value.fromInterned(value_index).fmtValue(pt),
- });
- var wip_nav: WipNav = .{
- .dwarf = dwarf,
- .pt = pt,
- .unit = .main,
- .entry = dwarf.values.get(value_index).?,
- .any_children = false,
- .func = .none,
- .func_sym_index = undefined,
- .func_high_pc = undefined,
- .blocks = undefined,
- .cfi = undefined,
- .debug_frame = .init(dwarf.gpa),
- .debug_info = .init(dwarf.gpa),
- .debug_line = .init(dwarf.gpa),
- .debug_loclists = .init(dwarf.gpa),
- .pending_lazy = pending_lazy.*,
- };
- defer {
- pending_lazy.* = wip_nav.pending_lazy;
- wip_nav.pending_lazy = .empty;
- wip_nav.deinit();
- }
- const diw = &wip_nav.debug_info.writer;
- var big_int_space: Value.BigIntSpace = undefined;
- switch (ip.indexToKey(value_index)) {
- .int_type,
- .ptr_type,
- .array_type,
- .vector_type,
- .opt_type,
- .anyframe_type,
- .error_union_type,
- .simple_type,
- .struct_type,
- .tuple_type,
- .union_type,
- .opaque_type,
- .enum_type,
- .func_type,
- .error_set_type,
- .inferred_error_set_type,
- => unreachable, // already handled
.undef => |ty| {
try wip_nav.abbrevCode(.undefined_comptime_value);
try wip_nav.refType(.fromInterned(ty));
},
- .simple_value => unreachable, // opv state
- .variable, .@"extern" => unreachable, // not a value
- .func => unreachable, // already handled
+ .simple_value => |simple_value| switch (simple_value) {
+ .void => unreachable, // opv state
+ .true, .false => unreachable, // runtime bits
+ .@"unreachable" => unreachable, // not a value
+ .null => {
+ // TODO: proper representation for this
+ try wip_nav.abbrevCode(.undefined_comptime_value);
+ try wip_nav.refType(.null);
+ },
+ },
+ .variable => unreachable, // not a value
.int => |int| {
try wip_nav.bigIntConstValue(.{
.sdata = .sdata_comptime_value,
@@ -4092,6 +4290,15 @@ fn updateLazyValue(
}, .fromInterned(int.ty), Value.fromInterned(value_index).toBigInt(&big_int_space, zcu));
try wip_nav.refType(.fromInterned(int.ty));
},
+ .bitpack => |bitpack| {
+ const backing_int_val: Value = .fromInterned(bitpack.backing_int_val);
+ try wip_nav.bigIntConstValue(.{
+ .sdata = .sdata_comptime_value,
+ .udata = .udata_comptime_value,
+ .block = .block_comptime_value,
+ }, backing_int_val.typeOf(zcu), backing_int_val.toBigInt(&big_int_space, zcu));
+ try wip_nav.refType(.fromInterned(bitpack.ty));
+ },
.err => |err| {
try wip_nav.abbrevCode(.udata_comptime_value);
try wip_nav.refType(.fromInterned(err.ty));
@@ -4117,7 +4324,7 @@ fn updateLazyValue(
.payload => |payload_val| {
const payload_type: Type = .fromInterned(ip.typeOf(payload_val));
const has_runtime_bits = payload_type.hasRuntimeBits(zcu);
- const has_comptime_state = payload_type.comptimeOnly(zcu) and try payload_type.onePossibleValue(pt) == null;
+ const has_comptime_state = payload_type.comptimeOnly(zcu);
try wip_nav.abbrevCode(if (has_comptime_state)
.comptime_value_field_comptime_state
else if (has_runtime_bits)
@@ -4153,7 +4360,6 @@ fn updateLazyValue(
}, .fromInterned(int.ty), Value.fromInterned(value_index).toBigInt(&big_int_space, zcu));
try wip_nav.refType(.fromInterned(enum_tag.ty));
},
- .empty_enum_value => unreachable,
.float => |float| {
switch (float.storage) {
.f16 => |f16_val| {
@@ -4194,11 +4400,11 @@ fn updateLazyValue(
var byte_offset = ptr.byte_offset;
const base_unit, const base_entry = while (true) {
const base_ptr, const access: Access = base_ptr_access: switch (base_addr) {
- .nav => |nav_index| break try wip_nav.getNavEntry(nav_index),
+ .nav => |nav_index| break try dwarf.getNavEntry(nav_index),
.comptime_alloc, .comptime_field => unreachable,
.uav => |uav| {
const uav_ty: Type = .fromInterned(ip.typeOf(uav.val));
- if (try uav_ty.onePossibleValue(pt)) |_| {
+ if (uav_ty.classify(zcu) == .one_possible_value) {
try wip_nav.abbrevCode(if (zero_bit_accesses.items.len > 0)
.aggregate_udata_comptime_value
else
@@ -4311,22 +4517,12 @@ fn updateLazyValue(
switch (optRepr(opt_child_type, zcu)) {
.opv_null => try diw.writeUleb128(0),
.unpacked => try wip_nav.blockValue(src_loc, .makeBool(opt.val != .none)),
- .error_set => try wip_nav.blockValue(src_loc, .fromInterned(value_index)),
- .pointer => if (opt_child_type.comptimeOnly(zcu)) {
- var buf: [8]u8 = undefined;
- const bytes = buf[0..@divExact(zcu.getTarget().ptrBitWidth(), 8)];
- dwarf.writeInt(bytes, switch (opt.val) {
- .none => 0,
- else => opt_child_type.ptrAlignment(zcu).toByteUnits().?,
- });
- try diw.writeUleb128(bytes.len);
- try diw.writeAll(bytes);
- } else try wip_nav.blockValue(src_loc, .fromInterned(value_index)),
+ .error_set, .pointer => try wip_nav.blockValue(src_loc, .fromInterned(value_index)),
}
}
if (opt.val != .none) child_field: {
const has_runtime_bits = opt_child_type.hasRuntimeBits(zcu);
- const has_comptime_state = opt_child_type.comptimeOnly(zcu) and try opt_child_type.onePossibleValue(pt) == null;
+ const has_comptime_state = opt_child_type.comptimeOnly(zcu);
try wip_nav.abbrevCode(if (has_comptime_state)
.comptime_value_field_comptime_state
else if (has_runtime_bits)
@@ -4349,17 +4545,17 @@ fn updateLazyValue(
const loaded_struct_type = ip.loadStructType(aggregate.ty);
assert(loaded_struct_type.layout == .auto);
for (0..loaded_struct_type.field_types.len) |field_index| {
- if (loaded_struct_type.fieldIsComptime(ip, field_index)) continue;
+ if (loaded_struct_type.field_is_comptime_bits.get(ip, field_index)) continue;
const field_type: Type = .fromInterned(loaded_struct_type.field_types.get(ip)[field_index]);
const has_runtime_bits = field_type.hasRuntimeBits(zcu);
- const has_comptime_state = field_type.comptimeOnly(zcu) and try field_type.onePossibleValue(pt) == null;
+ const has_comptime_state = field_type.comptimeOnly(zcu);
try wip_nav.abbrevCode(if (has_comptime_state)
.comptime_value_field_comptime_state
else if (has_runtime_bits)
.comptime_value_field_runtime_bits
else
continue);
- try wip_nav.strp(loaded_struct_type.fieldName(ip, field_index).toSlice(ip));
+ try wip_nav.strp(loaded_struct_type.field_names.get(ip)[field_index].toSlice(ip));
const field_value: Value = .fromInterned(switch (aggregate.storage) {
.bytes => unreachable,
.elems => |elems| elems[field_index],
@@ -4375,7 +4571,7 @@ fn updateLazyValue(
if (tuple_type.values.get(ip)[field_index] != .none) continue;
const field_type: Type = .fromInterned(tuple_type.types.get(ip)[field_index]);
const has_runtime_bits = field_type.hasRuntimeBits(zcu);
- const has_comptime_state = field_type.comptimeOnly(zcu) and try field_type.onePossibleValue(pt) == null;
+ const has_comptime_state = field_type.comptimeOnly(zcu);
try wip_nav.abbrevCode(if (has_comptime_state)
.comptime_value_field_comptime_state
else if (has_runtime_bits)
@@ -4400,7 +4596,7 @@ fn updateLazyValue(
inline .array_type, .vector_type => |sequence_type| {
const child_type: Type = .fromInterned(sequence_type.child);
const has_runtime_bits = child_type.hasRuntimeBits(zcu);
- const has_comptime_state = child_type.comptimeOnly(zcu) and try child_type.onePossibleValue(pt) == null;
+ const has_comptime_state = child_type.comptimeOnly(zcu);
for (switch (aggregate.storage) {
.bytes => unreachable,
.elems => |elems| elems,
@@ -4427,12 +4623,12 @@ fn updateLazyValue(
try wip_nav.refType(.fromInterned(un.ty));
field: {
const loaded_union_type = ip.loadUnionType(un.ty);
- assert(loaded_union_type.flagsUnordered(ip).layout == .auto);
+ assert(loaded_union_type.layout == .auto);
const field_index = zcu.unionTagFieldIndex(loaded_union_type, Value.fromInterned(un.tag)).?;
const field_ty: Type = .fromInterned(loaded_union_type.field_types.get(ip)[field_index]);
- const field_name = loaded_union_type.loadTagType(ip).names.get(ip)[field_index];
+ const field_name = ip.loadEnumType(loaded_union_type.enum_tag_type).field_names.get(ip)[field_index];
const has_runtime_bits = field_ty.hasRuntimeBits(zcu);
- const has_comptime_state = field_ty.comptimeOnly(zcu) and try field_ty.onePossibleValue(pt) == null;
+ const has_comptime_state = field_ty.comptimeOnly(zcu);
try wip_nav.abbrevCode(if (has_comptime_state)
.comptime_value_field_comptime_state
else if (has_runtime_bits)
@@ -4449,7 +4645,8 @@ fn updateLazyValue(
},
.memoized_call => unreachable, // not a value
}
- try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
+ try dwarf.debug_info.section.replaceEntry(unit, entry, dwarf, wip_nav.debug_info.written());
+ try dwarf.debug_loclists.section.replaceEntry(unit, entry, dwarf, wip_nav.debug_loclists.written());
}
fn optRepr(opt_child_type: Type, zcu: *const Zcu) enum { unpacked, opv_null, error_set, pointer } {
@@ -4464,312 +4661,6 @@ fn optRepr(opt_child_type: Type, zcu: *const Zcu) enum { unpacked, opv_null, err
};
}
-pub fn updateContainerType(
- dwarf: *Dwarf,
- pt: Zcu.PerThread,
- type_index: InternPool.Index,
-) UpdateError!void {
- return dwarf.updateContainerTypeWriterError(pt, type_index) catch |err| switch (err) {
- error.WriteFailed => error.OutOfMemory,
- else => |e| e,
- };
-}
-fn updateContainerTypeWriterError(
- dwarf: *Dwarf,
- pt: Zcu.PerThread,
- type_index: InternPool.Index,
-) (UpdateError || Writer.Error)!void {
- const zcu = pt.zcu;
- const ip = &zcu.intern_pool;
- const ty: Type = .fromInterned(type_index);
- const ty_src_loc = ty.srcLoc(zcu);
- log.debug("updateContainerType({f})", .{ty.fmt(pt)});
-
- const inst_info = ty.typeDeclInst(zcu).?.resolveFull(ip).?;
- const file = zcu.fileByIndex(inst_info.file);
- const unit = try dwarf.getUnit(file.mod.?);
- const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, inst_info.file);
- if (inst_info.inst == .main_struct_inst) {
- const type_gop = try dwarf.types.getOrPut(dwarf.gpa, type_index);
- if (!type_gop.found_existing) type_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
- var wip_nav: WipNav = .{
- .dwarf = dwarf,
- .pt = pt,
- .unit = unit,
- .entry = type_gop.value_ptr.*,
- .any_children = false,
- .func = .none,
- .func_sym_index = undefined,
- .func_high_pc = undefined,
- .blocks = undefined,
- .cfi = undefined,
- .debug_frame = .init(dwarf.gpa),
- .debug_info = .init(dwarf.gpa),
- .debug_line = .init(dwarf.gpa),
- .debug_loclists = .init(dwarf.gpa),
- .pending_lazy = .empty,
- };
- defer wip_nav.deinit();
-
- const loaded_struct = ip.loadStructType(type_index);
-
- const diw = &wip_nav.debug_info.writer;
- try wip_nav.abbrevCode(if (loaded_struct.field_types.len == 0) .empty_file else .file);
- try diw.writeUleb128(file_gop.index);
- try wip_nav.strp(loaded_struct.name.toSlice(ip));
- if (loaded_struct.field_types.len > 0) {
- try diw.writeUleb128(ty.abiSize(zcu));
- try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
- for (0..loaded_struct.field_types.len) |field_index| {
- const is_comptime = loaded_struct.fieldIsComptime(ip, field_index);
- const field_init = loaded_struct.fieldInit(ip, field_index);
- assert(!(is_comptime and field_init == .none));
- const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
- const has_runtime_bits, const has_comptime_state = switch (field_init) {
- .none => .{ false, false },
- else => .{
- field_type.hasRuntimeBits(zcu),
- field_type.comptimeOnly(zcu) and try field_type.onePossibleValue(pt) == null,
- },
- };
- try wip_nav.abbrevCode(if (is_comptime)
- if (has_comptime_state)
- .struct_field_comptime_comptime_state
- else if (has_runtime_bits)
- .struct_field_comptime_runtime_bits
- else
- .struct_field_comptime
- else if (field_init != .none)
- if (has_comptime_state)
- .struct_field_default_comptime_state
- else if (has_runtime_bits)
- .struct_field_default_runtime_bits
- else
- .struct_field
- else
- .struct_field);
- try wip_nav.strp(loaded_struct.fieldName(ip, field_index).toSlice(ip));
- try wip_nav.refType(field_type);
- if (!is_comptime) {
- try diw.writeUleb128(loaded_struct.offsets.get(ip)[field_index]);
- try diw.writeUleb128(loaded_struct.fieldAlign(ip, field_index).toByteUnits() orelse
- field_type.abiAlignment(zcu).toByteUnits().?);
- }
- if (has_comptime_state)
- try wip_nav.refValue(.fromInterned(field_init))
- else if (has_runtime_bits)
- try wip_nav.blockValue(ty_src_loc, .fromInterned(field_init));
- }
- try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
- }
-
- try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
- try wip_nav.updateLazy(ty_src_loc);
- } else {
- {
- // Note that changes to ZIR instruction tracking only need to update this code
- // if a newly-tracked instruction can be a type's owner `zir_index`.
- comptime assert(Zir.inst_tracking_version == 0);
-
- const decl_inst = file.zir.?.instructions.get(@intFromEnum(inst_info.inst));
- const name_strat: Zir.Inst.NameStrategy = switch (decl_inst.tag) {
- .struct_init, .struct_init_ref, .struct_init_anon => .anon,
- .extended => switch (decl_inst.data.extended.opcode) {
- .struct_decl => @as(Zir.Inst.StructDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
- .enum_decl => @as(Zir.Inst.EnumDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
- .union_decl => @as(Zir.Inst.UnionDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
- .opaque_decl => @as(Zir.Inst.OpaqueDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,
-
- .reify_enum,
- .reify_struct,
- .reify_union,
- => @enumFromInt(decl_inst.data.extended.small),
-
- else => unreachable,
- },
- else => unreachable,
- };
- if (name_strat == .parent) return;
- }
-
- const type_gop = try dwarf.types.getOrPut(dwarf.gpa, type_index);
- if (!type_gop.found_existing) type_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
- var wip_nav: WipNav = .{
- .dwarf = dwarf,
- .pt = pt,
- .unit = unit,
- .entry = type_gop.value_ptr.*,
- .any_children = false,
- .func = .none,
- .func_sym_index = undefined,
- .func_high_pc = undefined,
- .blocks = undefined,
- .cfi = undefined,
- .debug_frame = .init(dwarf.gpa),
- .debug_info = .init(dwarf.gpa),
- .debug_line = .init(dwarf.gpa),
- .debug_loclists = .init(dwarf.gpa),
- .pending_lazy = .empty,
- };
- defer wip_nav.deinit();
- const diw = &wip_nav.debug_info.writer;
- const name = try std.fmt.allocPrint(dwarf.gpa, "{f}", .{ty.fmt(pt)});
- defer dwarf.gpa.free(name);
-
- switch (ip.indexToKey(type_index)) {
- .struct_type => {
- const loaded_struct = ip.loadStructType(type_index);
- switch (loaded_struct.layout) {
- .auto, .@"extern" => {
- try wip_nav.abbrevCode(if (loaded_struct.field_types.len == 0) .empty_struct_type else .struct_type);
- try diw.writeUleb128(file_gop.index);
- try wip_nav.strp(name);
- if (loaded_struct.field_types.len == 0) try diw.writeByte(@intFromBool(false)) else {
- try diw.writeUleb128(ty.abiSize(zcu));
- try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
- for (0..loaded_struct.field_types.len) |field_index| {
- const is_comptime = loaded_struct.fieldIsComptime(ip, field_index);
- const field_init = loaded_struct.fieldInit(ip, field_index);
- assert(!(is_comptime and field_init == .none));
- const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
- const has_runtime_bits, const has_comptime_state = switch (field_init) {
- .none => .{ false, false },
- else => .{
- field_type.hasRuntimeBits(zcu),
- field_type.comptimeOnly(zcu) and try field_type.onePossibleValue(pt) == null,
- },
- };
- try wip_nav.abbrevCode(if (is_comptime)
- if (has_comptime_state)
- .struct_field_comptime_comptime_state
- else if (has_runtime_bits)
- .struct_field_comptime_runtime_bits
- else
- .struct_field_comptime
- else if (field_init != .none)
- if (has_comptime_state)
- .struct_field_default_comptime_state
- else if (has_runtime_bits)
- .struct_field_default_runtime_bits
- else
- .struct_field
- else
- .struct_field);
- try wip_nav.strp(loaded_struct.fieldName(ip, field_index).toSlice(ip));
- try wip_nav.refType(field_type);
- if (!is_comptime) {
- try diw.writeUleb128(loaded_struct.offsets.get(ip)[field_index]);
- try diw.writeUleb128(loaded_struct.fieldAlign(ip, field_index).toByteUnits() orelse
- field_type.abiAlignment(zcu).toByteUnits().?);
- }
- if (has_comptime_state)
- try wip_nav.refValue(.fromInterned(field_init))
- else if (has_runtime_bits)
- try wip_nav.blockValue(ty_src_loc, .fromInterned(field_init));
- }
- try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
- }
- },
- .@"packed" => {
- try wip_nav.abbrevCode(if (loaded_struct.field_types.len > 0) .packed_struct_type else .empty_packed_struct_type);
- try diw.writeUleb128(file_gop.index);
- try wip_nav.strp(name);
- try wip_nav.refType(.fromInterned(loaded_struct.backingIntTypeUnordered(ip)));
- var field_bit_offset: u16 = 0;
- for (0..loaded_struct.field_types.len) |field_index| {
- try wip_nav.abbrevCode(.packed_struct_field);
- try wip_nav.strp(loaded_struct.fieldName(ip, field_index).toSlice(ip));
- const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
- try wip_nav.refType(field_type);
- try diw.writeUleb128(field_bit_offset);
- field_bit_offset += @intCast(field_type.bitSize(zcu));
- }
- if (loaded_struct.field_types.len > 0) try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
- },
- }
- },
- .enum_type => {
- const loaded_enum = ip.loadEnumType(type_index);
- try wip_nav.abbrevCode(if (loaded_enum.names.len > 0) .enum_type else .empty_enum_type);
- try diw.writeUleb128(file_gop.index);
- try wip_nav.strp(name);
- try wip_nav.refType(.fromInterned(loaded_enum.tag_ty));
- for (0..loaded_enum.names.len) |field_index| {
- try wip_nav.enumConstValue(loaded_enum, .{
- .sdata = .signed_enum_field,
- .udata = .unsigned_enum_field,
- .block = .big_enum_field,
- }, field_index);
- try wip_nav.strp(loaded_enum.names.get(ip)[field_index].toSlice(ip));
- }
- if (loaded_enum.names.len > 0) try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
- },
- .union_type => {
- const loaded_union = ip.loadUnionType(type_index);
- try wip_nav.abbrevCode(if (loaded_union.field_types.len > 0) .union_type else .empty_union_type);
- try diw.writeUleb128(file_gop.index);
- try wip_nav.strp(name);
- const union_layout = Type.getUnionLayout(loaded_union, zcu);
- try diw.writeUleb128(union_layout.abi_size);
- try diw.writeUleb128(union_layout.abi_align.toByteUnits().?);
- const loaded_tag = loaded_union.loadTagType(ip);
- if (loaded_union.hasTag(ip)) {
- try wip_nav.abbrevCode(.tagged_union);
- try wip_nav.infoSectionOffset(
- .debug_info,
- wip_nav.unit,
- wip_nav.entry,
- @intCast(diw.end + dwarf.sectionOffsetBytes()),
- );
- {
- try wip_nav.abbrevCode(.generated_field);
- try wip_nav.strp("tag");
- try wip_nav.refType(.fromInterned(loaded_union.enum_tag_ty));
- try diw.writeUleb128(union_layout.tagOffset());
-
- for (0..loaded_union.field_types.len) |field_index| {
- try wip_nav.enumConstValue(loaded_tag, .{
- .sdata = .signed_tagged_union_field,
- .udata = .unsigned_tagged_union_field,
- .block = .big_tagged_union_field,
- }, field_index);
- {
- try wip_nav.abbrevCode(.struct_field);
- try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
- const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]);
- try wip_nav.refType(field_type);
- try diw.writeUleb128(union_layout.payloadOffset());
- try diw.writeUleb128(loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse
- if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(zcu).toByteUnits().?);
- }
- try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
- }
- }
- try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
- } else for (0..loaded_union.field_types.len) |field_index| {
- try wip_nav.abbrevCode(.untagged_union_field);
- try wip_nav.strp(loaded_tag.names.get(ip)[field_index].toSlice(ip));
- const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]);
- try wip_nav.refType(field_type);
- try diw.writeUleb128(loaded_union.fieldAlign(ip, field_index).toByteUnits() orelse
- if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(zcu).toByteUnits().?);
- }
- if (loaded_union.field_types.len > 0) try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
- },
- .opaque_type => {
- try wip_nav.abbrevCode(.empty_struct_type);
- try diw.writeUleb128(file_gop.index);
- try wip_nav.strp(name);
- try diw.writeByte(@intFromBool(true));
- },
- else => unreachable,
- }
- try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
- try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.written());
- try wip_nav.updateLazy(ty_src_loc);
- }
-}
-
pub fn updateLineNumber(dwarf: *Dwarf, zcu: *Zcu, zir_index: InternPool.TrackedInst.Index) UpdateError!void {
const comp = dwarf.bin_file.comp;
const io = comp.io;
@@ -4832,14 +4723,15 @@ fn flushWriterError(dwarf: *Dwarf, pt: Zcu.PerThread) (FlushError || Writer.Erro
const comp = dwarf.bin_file.comp;
const io = comp.io;
+ // Update `anyerror` based on the finished global error set.
{
- const type_gop = try dwarf.types.getOrPut(dwarf.gpa, .anyerror_type);
- if (!type_gop.found_existing) type_gop.value_ptr.* = try dwarf.addCommonEntry(.main);
+ const index = try dwarf.const_pool.get(pt, .{ .dwarf = dwarf }, .anyerror_type);
+ const unit, const entry = dwarf.values.items[@intFromEnum(index)];
var wip_nav: WipNav = .{
.dwarf = dwarf,
.pt = pt,
- .unit = .main,
- .entry = type_gop.value_ptr.*,
+ .unit = unit,
+ .entry = entry,
.any_children = false,
.func = .none,
.func_sym_index = undefined,
@@ -4850,7 +4742,6 @@ fn flushWriterError(dwarf: *Dwarf, pt: Zcu.PerThread) (FlushError || Writer.Erro
.debug_info = .init(dwarf.gpa),
.debug_line = .init(dwarf.gpa),
.debug_loclists = .init(dwarf.gpa),
- .pending_lazy = .empty,
};
defer wip_nav.deinit();
const diw = &wip_nav.debug_info.writer;
@@ -4868,7 +4759,7 @@ fn flushWriterError(dwarf: *Dwarf, pt: Zcu.PerThread) (FlushError || Writer.Erro
}
if (global_error_set_names.len > 0) try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
- try wip_nav.updateLazy(.unneeded);
+ try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });
}
for (dwarf.mods.keys(), dwarf.mods.values()) |mod, *mod_info| {
@@ -5316,6 +5207,8 @@ const AbbrevCode = enum {
inferred_error_set_type,
ptr_type,
ptr_sentinel_type,
+ ptr_aligned_type,
+ ptr_aligned_sentinel_type,
is_const,
is_volatile,
array_type,
@@ -5952,12 +5845,29 @@ const AbbrevCode = enum {
.tag = .pointer_type,
.attrs = &.{
.{ .name, .strp },
- .{ .alignment, .udata },
.{ .address_class, .data1 },
.{ .type, .ref_addr },
},
},
.ptr_sentinel_type = .{
+ .tag = .pointer_type,
+ .attrs = &.{
+ .{ .name, .strp },
+ .{ .ZIG_sentinel, .block },
+ .{ .address_class, .data1 },
+ .{ .type, .ref_addr },
+ },
+ },
+ .ptr_aligned_type = .{
+ .tag = .pointer_type,
+ .attrs = &.{
+ .{ .name, .strp },
+ .{ .alignment, .udata },
+ .{ .address_class, .data1 },
+ .{ .type, .ref_addr },
+ },
+ },
+ .ptr_aligned_sentinel_type = .{
.tag = .pointer_type,
.attrs = &.{
.{ .name, .strp },
diff --git a/src/link/Elf.zig b/src/link/Elf.zig
index 85f37f88ce8b55c984f6d1e5c97c689b80659d4b..c45f73d97a35c8e6435bfded3f5f2defddd55ac4 100644
--- a/src/link/Elf.zig
+++ b/src/link/Elf.zig
@@ -1711,23 +1711,13 @@ pub fn updateContainerType(
self: *Elf,
pt: Zcu.PerThread,
ty: InternPool.Index,
+ success: bool,
) link.File.UpdateContainerTypeError!void {
if (build_options.skip_non_native and builtin.object_format != .elf) {
@panic("Attempted to compile for object format that was disabled by build configuration");
}
- const zcu = pt.zcu;
- const gpa = zcu.gpa;
- return self.zigObjectPtr().?.updateContainerType(pt, ty) catch |err| switch (err) {
+ return self.zigObjectPtr().?.updateContainerType(pt, ty, success) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
- else => |e| {
- try zcu.failed_types.putNoClobber(gpa, ty, try Zcu.ErrorMsg.create(
- gpa,
- zcu.typeSrcLoc(ty),
- "failed to update container type: {s}",
- .{@errorName(e)},
- ));
- return error.TypeFailureReported;
- },
};
}
diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig
index ebdd1f20989a897c831738289772906a98afe0fd..d17b0b7b17d4bd28db40bf57f561f02a19d4c988 100644
--- a/src/link/Elf/Object.zig
+++ b/src/link/Elf/Object.zig
@@ -775,7 +775,7 @@ pub fn checkDuplicates(self: *Object, dupes: anytype, elf_file: *Elf) error{OutO
const gop = try dupes.getOrPut(self.symbols_resolver.items[i]);
if (!gop.found_existing) {
- gop.value_ptr.* = .{};
+ gop.value_ptr.* = .empty;
}
try gop.value_ptr.append(elf_file.base.comp.gpa, self.index);
}
diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig
index 588b4e3fc39a2f2af664b996575157558991db75..91133412e8fc85f75e02070f546deb174a0c128a 100644
--- a/src/link/Elf/ZigObject.zig
+++ b/src/link/Elf/ZigObject.zig
@@ -84,7 +84,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
const ptr_size = elf_file.ptrWidthBytes();
try self.atoms.append(gpa, .{ .extra_index = try self.addAtomExtra(gpa, .{}) }); // null input section
- try self.relocs.append(gpa, .{}); // null relocs section
+ try self.relocs.append(gpa, .empty); // null relocs section
try self.strtab.buffer.append(gpa, 0);
{
@@ -546,7 +546,7 @@ fn newAtom(self: *ZigObject, allocator: Allocator, name_off: u32) !Atom.Index {
atom_ptr.name_offset = name_off;
const relocs_index: u32 = @intCast(self.relocs.items.len);
- self.relocs.addOneAssumeCapacity().* = .{};
+ self.relocs.addOneAssumeCapacity().* = .empty;
atom_ptr.relocs_section_index = relocs_index;
return index;
@@ -730,7 +730,7 @@ pub fn checkDuplicates(self: *ZigObject, dupes: anytype, elf_file: *Elf) error{O
const gop = try dupes.getOrPut(self.symbols_resolver.items[i]);
if (!gop.found_existing) {
- gop.value_ptr.* = .{};
+ gop.value_ptr.* = .empty;
}
try gop.value_ptr.append(elf_file.base.comp.gpa, self.index);
}
@@ -1479,7 +1479,7 @@ fn updateTlv(
log.debug("updateTlv {f}({d})", .{ nav.fqn.fmt(ip), nav_index });
- const required_alignment = pt.navAlignment(nav_index);
+ const required_alignment = zcu.navAlignment(nav_index);
const sym = self.symbol(sym_index);
const esym = &self.symtab.items(.elf_sym)[sym.esym_index];
@@ -1719,11 +1719,12 @@ pub fn updateContainerType(
self: *ZigObject,
pt: Zcu.PerThread,
ty: InternPool.Index,
+ success: bool,
) !void {
const tracy = trace(@src());
defer tracy.end();
- if (self.dwarf) |*dwarf| try dwarf.updateContainerType(pt, ty);
+ if (self.dwarf) |*dwarf| try dwarf.updateContainerType(pt, ty, success);
}
fn updateLazySymbol(
diff --git a/src/link/Elf2.zig b/src/link/Elf2.zig
index 81e6c23af82805f96d09409637b0e14e0dc49165..bab805af760d7ea4a5c6433bf6bccb96602dcb5b 100644
--- a/src/link/Elf2.zig
+++ b/src/link/Elf2.zig
@@ -2906,7 +2906,7 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
try elf.nodes.ensureUnusedCapacity(gpa, 1);
const sec_si = elf.navSection(ip, nav.status.fully_resolved);
const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{
- .alignment = pt.navAlignment(nav_index).toStdMem(),
+ .alignment = zcu.navAlignment(nav_index).toStdMem(),
.moved = true,
});
elf.nodes.appendAssumeCapacity(.{ .nav = nmi });
diff --git a/src/link/MachO/Atom.zig b/src/link/MachO/Atom.zig
index 8f0f8019493d82a4eec9718e0f95344b48bf1d48..df9dc381ab025711c7086515e71af1c3303251ca 100644
--- a/src/link/MachO/Atom.zig
+++ b/src/link/MachO/Atom.zig
@@ -561,7 +561,7 @@ fn reportUndefSymbol(self: Atom, rel: Relocation, macho_file: *MachO) !bool {
defer macho_file.undefs_mutex.unlock(io);
const gop = try macho_file.undefs.getOrPut(gpa, file.getGlobals()[rel.target]);
if (!gop.found_existing) {
- gop.value_ptr.* = .{ .refs = .{} };
+ gop.value_ptr.* = .{ .refs = .empty };
}
try gop.value_ptr.refs.append(gpa, .{ .index = self.atom_index, .file = self.file });
return true;
diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig
index 49555c2746a46dc0ee9617aea5f0de67d35ef313..5d71e46eaaf90e3d3b34c2a81db173dddc1ccdb2 100644
--- a/src/link/MachO/ZigObject.zig
+++ b/src/link/MachO/ZigObject.zig
@@ -3,7 +3,7 @@ data: std.ArrayList(u8) = .empty,
basename: []const u8,
index: File.Index,
-symtab: std.MultiArrayList(Nlist) = .{},
+symtab: std.MultiArrayList(Nlist) = .empty,
strtab: StringTable = .{},
symbols: std.ArrayList(Symbol) = .empty,
@@ -29,7 +29,7 @@ uavs: UavTable = .{},
tlv_initializers: TlvInitializerTable = .{},
/// A table of relocations.
-relocs: RelocationTable = .{},
+relocs: RelocationTable = .empty,
dwarf: ?Dwarf = null,
@@ -150,7 +150,7 @@ fn newAtom(self: *ZigObject, allocator: Allocator, name: MachO.String, macho_fil
atom.name = name;
const relocs_index = @as(u32, @intCast(self.relocs.items.len));
- self.relocs.addOneAssumeCapacity().* = .{};
+ self.relocs.addOneAssumeCapacity().* = .empty;
atom.addExtra(.{ .rel_index = relocs_index, .rel_count = 0 }, macho_file);
return index;
@@ -925,7 +925,7 @@ pub fn updateNav(
const sect_index = try self.getNavOutputSection(macho_file, zcu, nav_index, code);
if (isThreadlocal(macho_file, nav_index))
- try self.updateTlv(macho_file, pt, nav_index, sym_index, sect_index, code)
+ try self.updateTlv(macho_file, zcu, nav_index, sym_index, sect_index, code)
else
try self.updateNavCode(macho_file, pt, nav_index, sym_index, sect_index, code);
@@ -1030,13 +1030,13 @@ fn updateNavCode(
fn updateTlv(
self: *ZigObject,
macho_file: *MachO,
- pt: Zcu.PerThread,
+ zcu: *Zcu,
nav_index: InternPool.Nav.Index,
sym_index: Symbol.Index,
sect_index: u8,
code: []const u8,
) !void {
- const ip = &pt.zcu.intern_pool;
+ const ip = &zcu.intern_pool;
const nav = ip.getNav(nav_index);
log.debug("updateTlv {f} (0x{x})", .{ nav.fqn.fmt(ip), nav_index });
@@ -1045,7 +1045,7 @@ fn updateTlv(
const init_sym_index = try self.createTlvInitializer(
macho_file,
nav.fqn.toSlice(ip),
- pt.navAlignment(nav_index),
+ zcu.navAlignment(nav_index),
sect_index,
code,
);
diff --git a/src/link/MachO/file.zig b/src/link/MachO/file.zig
index cd687a4941b2e73915a7daafe31b8d996cee37a5..4f6f70debeef007b915bfeb07d5317b87fffabc2 100644
--- a/src/link/MachO/file.zig
+++ b/src/link/MachO/file.zig
@@ -258,7 +258,7 @@ pub const File = union(enum) {
const gop = try macho_file.dupes.getOrPut(gpa, file.getGlobals()[i]);
if (!gop.found_existing) {
- gop.value_ptr.* = .{};
+ gop.value_ptr.* = .empty;
}
try gop.value_ptr.append(gpa, file.getIndex());
}
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig
index af800d77d263b0a99a43833494ad90884a2dd260..1975ad9ba9dc15477e3510377701e5666539bec6 100644
--- a/src/link/Wasm.zig
+++ b/src/link/Wasm.zig
@@ -78,7 +78,7 @@ export_table: bool,
/// Output name of the file
name: []const u8,
/// List of relocatable files to be linked into the final binary.
-objects: std.ArrayList(Object) = .{},
+objects: std.ArrayList(Object) = .empty,
func_types: std.AutoArrayHashMapUnmanaged(FunctionType, void) = .empty,
/// Provides a mapping of both imports and provided functions to symbol name.
@@ -278,7 +278,7 @@ any_tls_relocs: bool = false,
any_passive_inits: bool = false,
/// All MIR instructions for all Zcu functions.
-mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
+mir_instructions: std.MultiArrayList(Mir.Inst) = .empty,
/// Corresponds to `mir_instructions`.
mir_extra: std.ArrayList(u32) = .empty,
/// All local types for all Zcu functions.
@@ -4226,7 +4226,7 @@ fn convertZcuFnType(
if (CodeGen.firstParamSRet(cc, return_type, zcu, target)) {
try params_buffer.append(gpa, .i32); // memory address is always a 32-bit handle
- } else if (return_type.hasRuntimeBitsIgnoreComptime(zcu)) {
+ } else if (return_type.hasRuntimeBits(zcu)) {
if (cc == .wasm_mvp) {
switch (abi.classifyType(return_type, zcu)) {
.direct => |scalar_ty| {
@@ -4245,7 +4245,7 @@ fn convertZcuFnType(
// param types
for (params) |param_type_ip| {
const param_type = Zcu.Type.fromInterned(param_type_ip);
- if (!param_type.hasRuntimeBitsIgnoreComptime(zcu)) continue;
+ if (!param_type.hasRuntimeBits(zcu)) continue;
switch (cc) {
.wasm_mvp => {
diff --git a/src/link/Wasm/Flush.zig b/src/link/Wasm/Flush.zig
index 8197d35b724f6278d0edf4a719319fadd3cda270..5d19f5b159badbaaab884523b875996547df76ad 100644
--- a/src/link/Wasm/Flush.zig
+++ b/src/link/Wasm/Flush.zig
@@ -154,7 +154,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
.type_index = try wasm.internFunctionType(.auto, &.{int_tag_ty.ip_index}, .slice_const_u8_sentinel_0, target),
.table_index = @intCast(wasm.tag_name_offs.items.len),
} };
- const tag_names = ip.loadEnumType(data.ip_index).names;
+ const tag_names = ip.loadEnumType(data.ip_index).field_names;
for (tag_names.get(ip)) |tag_name| {
const slice = tag_name.toSlice(ip);
try wasm.tag_name_offs.append(gpa, @intCast(wasm.tag_name_bytes.items.len));
@@ -1869,7 +1869,7 @@ fn emitTagNameFunction(
const zcu = comp.zcu.?;
const ip = &zcu.intern_pool;
const enum_type = ip.loadEnumType(enum_type_ip);
- const tag_values = enum_type.values.get(ip);
+ const tag_values = enum_type.field_values.get(ip);
const slice_abi_size = 8;
const encoded_alignment = @ctz(@as(u32, 4));
@@ -1908,7 +1908,7 @@ fn emitTagNameFunction(
return;
}
- const int_info = Zcu.Type.intInfo(.fromInterned(enum_type.tag_ty), zcu);
+ const int_info = Zcu.Type.intInfo(.fromInterned(enum_type.int_tag_type), zcu);
const outer_block_type: std.wasm.BlockType = switch (int_info.bits) {
0...32 => .i32,
33...64 => .i64,
diff --git a/src/link/tapi/parse.zig b/src/link/tapi/parse.zig
index 4483d359eb002e95823a4d6e1ecd64fefddfc0ec..487b609bcab3bd93fa38a2fa25026ebfc93cff85 100644
--- a/src/link/tapi/parse.zig
+++ b/src/link/tapi/parse.zig
@@ -530,7 +530,7 @@ const Parser = struct {
fn leaf_value(self: *Parser) ParseError!*Node {
const node = try self.allocator.create(Node.Value);
errdefer self.allocator.destroy(node);
- node.* = .{ .string_value = .{} };
+ node.* = .{ .string_value = .empty };
node.base.tree = self.tree;
node.base.start = self.token_it.pos;
errdefer node.string_value.deinit(self.allocator);
diff --git a/src/main.zig b/src/main.zig
index bb36d00376d5410ed4612feab04b9128871bacd8..7167cae4e29b3e36b4c46589e0be178f1e4f501b 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -979,7 +979,7 @@ fn buildOutputType(
.dirs = undefined,
.object_format = null,
.dynamic_linker = null,
- .modules = .{},
+ .modules = .empty,
.opts = .{
.is_test = switch (arg_mode) {
.zig_test, .zig_test_obj => true,
@@ -1006,18 +1006,18 @@ fn buildOutputType(
.windows_libs = .empty,
.link_inputs = .empty,
- .c_source_files = .{},
- .rc_source_files = .{},
+ .c_source_files = .empty,
+ .rc_source_files = .empty,
- .llvm_m_args = .{},
+ .llvm_m_args = .empty,
.sysroot = null,
- .lib_directories = .{}, // populated by createModule()
- .lib_dir_args = .{}, // populated from CLI arg parsing
+ .lib_directories = .empty, // populated by createModule()
+ .lib_dir_args = .empty, // populated from CLI arg parsing
.libc_installation = null,
.want_native_include_dirs = false,
- .frameworks = .{},
- .framework_dirs = .{},
- .rpath_list = .{},
+ .frameworks = .empty,
+ .framework_dirs = .empty,
+ .rpath_list = .empty,
.each_lib_rpath = null,
.libc_paths_file = EnvVar.ZIG_LIBC.get(environ_map),
.native_system_include_paths = &.{},
diff --git a/src/mutable_value.zig b/src/mutable_value.zig
index c9eb993944e15366de31846611b76cd070064fe9..8ddd434837ea2d1036229757d8ec20c3df5a45e5 100644
--- a/src/mutable_value.zig
+++ b/src/mutable_value.zig
@@ -18,7 +18,7 @@ pub const MutableValue = union(enum) {
opt_payload: SubValue,
/// An aggregate consisting of a single repeated value.
repeated: SubValue,
- /// An aggregate of `u8` consisting of "plain" bytes (no lazy or undefined elements).
+ /// An aggregate of `u8` consisting of "plain" bytes (no undefined elements).
bytes: Bytes,
/// An aggregate with arbitrary sub-values.
aggregate: Aggregate,
@@ -97,8 +97,8 @@ pub const MutableValue = union(enum) {
/// * Non-error error unions use `eu_payload`
/// * Non-null optionals use `eu_payload
/// * Slices use `slice`
- /// * Unions use `un`
- /// * Aggregates use `repeated` or `bytes` or `aggregate`
+ /// * Unions use `un` (excluding packed unions)
+ /// * Aggregates use `repeated` or `bytes` or `aggregate` (excluding packed structs)
/// If `!allow_bytes`, the `bytes` representation will not be used.
/// If `!allow_repeated`, the `repeated` representation will not be used.
pub fn unintern(
@@ -209,6 +209,7 @@ pub const MutableValue = union(enum) {
.undef => |ty_ip| switch (Type.fromInterned(ty_ip).zigTypeTag(zcu)) {
.@"struct", .array, .vector => |type_tag| {
const ty = Type.fromInterned(ty_ip);
+ if (type_tag == .@"struct" and ty.containerLayout(zcu) == .@"packed") return;
const opt_sent = ty.sentinel(zcu);
if (type_tag == .@"struct" or opt_sent != null or !allow_repeated) {
const len_no_sent = ip.aggregateTypeLen(ty_ip);
@@ -241,15 +242,18 @@ pub const MutableValue = union(enum) {
} };
}
},
- .@"union" => {
- const payload = try arena.create(MutableValue);
- const backing_ty = try Type.fromInterned(ty_ip).unionBackingType(pt);
- payload.* = .{ .interned = try pt.intern(.{ .undef = backing_ty.toIntern() }) };
- mv.* = .{ .un = .{
- .ty = ty_ip,
- .tag = .none,
- .payload = payload,
- } };
+ .@"union" => switch (Type.fromInterned(ty_ip).containerLayout(zcu)) {
+ .auto, .@"packed" => {},
+ .@"extern" => {
+ const payload = try arena.create(MutableValue);
+ const backing_ty = try Type.fromInterned(ty_ip).externUnionBackingType(pt);
+ payload.* = .{ .interned = try pt.intern(.{ .undef = backing_ty.toIntern() }) };
+ mv.* = .{ .un = .{
+ .ty = ty_ip,
+ .tag = .none,
+ .payload = payload,
+ } };
+ },
},
.pointer => {
const ptr_ty = ip.indexToKey(ty_ip).ptr_type;
@@ -415,16 +419,7 @@ pub const MutableValue = union(enum) {
} else if (!is_struct and is_trivial_int and Type.fromInterned(a.ty).childType(zcu).toIntern() == .u8_type) {
// See if we can switch to `bytes` repr
for (a.elems) |e| {
- switch (e) {
- else => break,
- .interned => |ip_index| switch (ip.indexToKey(ip_index)) {
- else => break,
- .int => |int| switch (int.storage) {
- .u64, .i64, .big_int => {},
- .lazy_align, .lazy_size => break,
- },
- },
- }
+ if (!e.isTrivialInt(zcu)) break;
} else {
const bytes = try arena.alloc(u8, a.elems.len);
for (a.elems, bytes) |elem_val, *b| {
@@ -494,10 +489,7 @@ pub const MutableValue = union(enum) {
else => false,
.interned => |ip_index| switch (zcu.intern_pool.indexToKey(ip_index)) {
else => false,
- .int => |int| switch (int.storage) {
- .u64, .i64, .big_int => true,
- .lazy_align, .lazy_size => false,
- },
+ .int => true,
},
};
}
diff --git a/src/print_value.zig b/src/print_value.zig
index 28c25954272bccaa8069ff570043e34625236c6c..626a11e1b335a197b855af6051e03adf760fba99 100644
--- a/src/print_value.zig
+++ b/src/print_value.zig
@@ -25,10 +25,7 @@ pub fn formatSema(ctx: FormatContext, writer: *Writer) Writer.Error!void {
const sema = ctx.opt_sema.?;
return print(ctx.val, writer, ctx.depth, ctx.pt, sema) catch |err| switch (err) {
error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function
- error.ComptimeBreak, error.ComptimeReturn => unreachable,
- error.AnalysisFail => unreachable, // TODO: re-evaluate when we use `sema` more fully
- error.Canceled => @panic("TODO"), // pls stop returning this error mlugg
- else => |e| return e,
+ error.WriteFailed => |e| return e,
};
}
@@ -36,9 +33,7 @@ pub fn format(ctx: FormatContext, writer: *Writer) Writer.Error!void {
std.debug.assert(ctx.opt_sema == null);
return print(ctx.val, writer, ctx.depth, ctx.pt, null) catch |err| switch (err) {
error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function
- error.ComptimeBreak, error.ComptimeReturn, error.AnalysisFail => unreachable,
- error.Canceled => @panic("TODO"), // pls stop returning this error mlugg
- else => |e| return e,
+ error.WriteFailed => |e| return e,
};
}
@@ -48,7 +43,7 @@ pub fn print(
level: u8,
pt: Zcu.PerThread,
opt_sema: ?*Sema,
-) (Writer.Error || Zcu.CompileError)!void {
+) (Writer.Error || Allocator.Error)!void {
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
switch (ip.indexToKey(val.toIntern())) {
@@ -72,8 +67,12 @@ pub fn print(
.undef => try writer.writeAll("undefined"),
.simple_value => |simple_value| switch (simple_value) {
.void => try writer.writeAll("{}"),
- .empty_tuple => try writer.writeAll(".{}"),
- else => try writer.writeAll(@tagName(simple_value)),
+
+ .null,
+ .true,
+ .false,
+ .@"unreachable",
+ => try writer.writeAll(@tagName(simple_value)),
},
.variable => try writer.writeAll("(variable)"),
.@"extern" => |e| try writer.print("(extern '{f}')", .{e.name.fmt(ip)}),
@@ -81,14 +80,6 @@ pub fn print(
.int => |int| switch (int.storage) {
inline .u64, .i64 => |x| try writer.print("{d}", .{x}),
.big_int => |x| try writer.print("{d}", .{x}),
- .lazy_align => |ty| if (opt_sema != null) {
- const a = try Type.fromInterned(ty).abiAlignmentSema(pt);
- try writer.print("{d}", .{a.toByteUnits() orelse 0});
- } else try writer.print("@alignOf({f})", .{Type.fromInterned(ty).fmt(pt)}),
- .lazy_size => |ty| if (opt_sema != null) {
- const s = try Type.fromInterned(ty).abiSizeSema(pt);
- try writer.print("{d}", .{s});
- } else try writer.print("@sizeOf({f})", .{Type.fromInterned(ty).fmt(pt)}),
},
.err => |err| try writer.print("error.{f}", .{
err.name.fmt(ip),
@@ -104,8 +95,8 @@ pub fn print(
}),
.enum_tag => |enum_tag| {
const enum_type = ip.loadEnumType(val.typeOf(zcu).toIntern());
- if (enum_type.tagValueIndex(ip, val.toIntern())) |tag_index| {
- return writer.print(".{f}", .{enum_type.names.get(ip)[tag_index].fmt(ip)});
+ if (enum_type.tagValueIndex(ip, enum_tag.int)) |tag_index| {
+ return writer.print(".{f}", .{enum_type.field_names.get(ip)[tag_index].fmt(ip)});
}
if (level == 0) {
return writer.writeAll("@enumFromInt(...)");
@@ -114,7 +105,6 @@ pub fn print(
try print(Value.fromInterned(enum_tag.int), writer, level - 1, pt, opt_sema);
try writer.writeAll(")");
},
- .empty_enum_value => try writer.writeAll("(empty enum value)"),
.float => |float| switch (float.storage) {
inline else => |x| try writer.print("{d}", .{@as(f64, @floatCast(x))}),
},
@@ -123,7 +113,7 @@ pub fn print(
if (slice.len == .zero_usize) {
return writer.writeAll("&.{}");
}
- try print(.fromInterned(slice.ptr), writer, level - 1, pt, opt_sema);
+ try print(.fromInterned(slice.ptr), writer, level, pt, opt_sema);
} else {
const print_contents = switch (ip.getBackingAddrTag(slice.ptr).?) {
.field, .arr_elem, .eu_payload, .opt_payload => unreachable,
@@ -167,7 +157,7 @@ pub fn print(
return;
}
if (un.tag == .none) {
- const backing_ty = try val.typeOf(zcu).unionBackingType(pt);
+ const backing_ty = try val.typeOf(zcu).externUnionBackingType(pt);
try writer.print("@bitCast(@as({f}, ", .{backing_ty.fmt(pt)});
try print(Value.fromInterned(un.val), writer, level - 1, pt, opt_sema);
try writer.writeAll("))");
@@ -179,6 +169,35 @@ pub fn print(
try writer.writeAll(" }");
}
},
+ .bitpack => |bitpack| {
+ if (level == 0) {
+ return writer.writeAll(".{ ... }");
+ }
+ const ty: Type = .fromInterned(bitpack.ty);
+ switch (ty.zigTypeTag(zcu)) {
+ .@"struct" => {
+ if (ty.structFieldCount(zcu) == 0) {
+ return writer.writeAll(".{}");
+ }
+ try writer.writeAll(".{ ");
+ const max_len = @min(ty.structFieldCount(zcu), max_aggregate_items);
+ for (0..max_len) |i| {
+ if (i != 0) try writer.writeAll(", ");
+ const field_name = ty.structFieldName(@intCast(i), zcu).unwrap().?;
+ try writer.print(".{f} = ", .{field_name.fmt(ip)});
+ try print(try val.fieldValue(pt, i), writer, level - 1, pt, opt_sema);
+ }
+ try writer.writeAll(" }");
+ return;
+ },
+ .@"union" => {
+ try writer.print("@bitCast(@as({f}, ", .{ty.bitpackBackingInt(zcu).fmt(pt)});
+ try print(.fromInterned(bitpack.backing_int_val), writer, level - 1, pt, opt_sema);
+ try writer.writeAll("))");
+ },
+ else => unreachable,
+ }
+ },
.memoized_call => unreachable,
}
}
@@ -191,7 +210,7 @@ fn printAggregate(
level: u8,
pt: Zcu.PerThread,
opt_sema: ?*Sema,
-) (Writer.Error || Zcu.CompileError)!void {
+) (Writer.Error || Allocator.Error)!void {
if (level == 0) {
if (is_ref) try writer.writeByte('&');
return writer.writeAll(".{ ... }");
@@ -256,17 +275,26 @@ fn printAggregate(
const len = ty.arrayLen(zcu);
if (is_ref) try writer.writeByte('&');
- try writer.writeAll(".{ ");
-
- const max_len = @min(len, max_aggregate_items);
- for (0..max_len) |i| {
- if (i != 0) try writer.writeAll(", ");
- try print(try val.fieldValue(pt, i), writer, level - 1, pt, opt_sema);
+ switch (len) {
+ 0 => try writer.writeAll(".{}"),
+ 1 => {
+ try writer.writeAll(".{");
+ try print(try val.fieldValue(pt, 0), writer, level - 1, pt, opt_sema);
+ try writer.writeByte('}');
+ },
+ else => {
+ try writer.writeAll(".{ ");
+ const max_len = @min(len, max_aggregate_items);
+ for (0..max_len) |i| {
+ if (i != 0) try writer.writeAll(", ");
+ try print(try val.fieldValue(pt, i), writer, level - 1, pt, opt_sema);
+ }
+ if (len > max_aggregate_items) {
+ try writer.writeAll(", ...");
+ }
+ try writer.writeAll(" }");
+ },
}
- if (len > max_aggregate_items) {
- try writer.writeAll(", ...");
- }
- return writer.writeAll(" }");
}
fn printPtr(
@@ -277,7 +305,7 @@ fn printPtr(
level: u8,
pt: Zcu.PerThread,
opt_sema: ?*Sema,
-) (Writer.Error || Zcu.CompileError)!void {
+) (Writer.Error || Allocator.Error)!void {
const ptr = switch (pt.zcu.intern_pool.indexToKey(ptr_val.toIntern())) {
.undef => return writer.writeAll("undefined"),
.ptr => |ptr| ptr,
@@ -302,10 +330,7 @@ fn printPtr(
var arena = std.heap.ArenaAllocator.init(pt.zcu.gpa);
defer arena.deinit();
- const derivation = if (opt_sema) |sema|
- try ptr_val.pointerDerivationAdvanced(arena.allocator(), pt, true, sema)
- else
- try ptr_val.pointerDerivationAdvanced(arena.allocator(), pt, false, null);
+ const derivation = try ptr_val.pointerDerivation(arena.allocator(), pt, opt_sema);
_ = try printPtrDerivation(derivation, writer, pt, want_kind, .{ .print_val = .{
.level = level,
@@ -442,18 +467,30 @@ pub fn printPtrDerivation(
.uav_ptr => |uav| {
const ty = Value.fromInterned(uav.val).typeOf(zcu);
try writer.print("@as({f}, ", .{ty.fmt(pt)});
- try print(Value.fromInterned(uav.val), writer, x.level - 1, pt, x.opt_sema);
+ if (x.level == 0) {
+ try writer.writeAll("...");
+ } else {
+ try print(Value.fromInterned(uav.val), writer, x.level - 1, pt, x.opt_sema);
+ }
try writer.writeByte(')');
},
.comptime_alloc_ptr => |info| {
try writer.print("@as({f}, ", .{info.val.typeOf(zcu).fmt(pt)});
- try print(info.val, writer, x.level - 1, pt, x.opt_sema);
+ if (x.level == 0) {
+ try writer.writeAll("...");
+ } else {
+ try print(info.val, writer, x.level - 1, pt, x.opt_sema);
+ }
try writer.writeByte(')');
},
.comptime_field_ptr => |val| {
const ty = val.typeOf(zcu);
try writer.print("@as({f}, ", .{ty.fmt(pt)});
- try print(val, writer, x.level - 1, pt, x.opt_sema);
+ if (x.level == 0) {
+ try writer.writeAll("...");
+ } else {
+ try print(val, writer, x.level - 1, pt, x.opt_sema);
+ }
try writer.writeByte(')');
},
else => unreachable,
diff --git a/src/print_zir.zig b/src/print_zir.zig
index c3a494de8466600670dff6d74b567cd80ee04a71..34c816fad62fc80355601fdbc723d2b3e8d02974 100644
--- a/src/print_zir.zig
+++ b/src/print_zir.zig
@@ -548,10 +548,10 @@ const Writer = struct {
.shl_with_overflow,
=> try self.writeOverflowArithmetic(stream, extended),
- .struct_decl => try self.writeStructDecl(stream, extended),
- .union_decl => try self.writeUnionDecl(stream, extended),
- .enum_decl => try self.writeEnumDecl(stream, extended),
- .opaque_decl => try self.writeOpaqueDecl(stream, extended),
+ .struct_decl => try self.writeStructDecl(stream, inst),
+ .union_decl => try self.writeUnionDecl(stream, inst),
+ .enum_decl => try self.writeEnumDecl(stream, inst),
+ .opaque_decl => try self.writeOpaqueDecl(stream, inst),
.tuple_decl => try self.writeTupleDecl(stream, extended),
@@ -1427,187 +1427,57 @@ const Writer = struct {
try self.writeSrcNode(stream, inst_data.src_node);
}
- fn writeStructDecl(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
- const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
-
- const extra = self.code.extraData(Zir.Inst.StructDecl, extended.operand);
+ fn writeStructDecl(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
+ const struct_decl = self.code.getStructDecl(inst);
const prev_parent_decl_node = self.parent_decl_node;
- self.parent_decl_node = extra.data.src_node;
+ self.parent_decl_node = struct_decl.src_node;
defer self.parent_decl_node = prev_parent_decl_node;
- const fields_hash: std.zig.SrcHash = @bitCast([4]u32{
- extra.data.fields_hash_0,
- extra.data.fields_hash_1,
- extra.data.fields_hash_2,
- extra.data.fields_hash_3,
- });
-
+ const fields_hash = self.code.getAssociatedSrcHash(inst).?;
try stream.print("hash({x}) ", .{&fields_hash});
- var extra_index: usize = extra.end;
+ try stream.print("{s}, ", .{@tagName(struct_decl.name_strategy)});
- const captures_len = if (small.has_captures_len) blk: {
- const captures_len = self.code.extra[extra_index];
- extra_index += 1;
- break :blk captures_len;
- } else 0;
-
- const fields_len = if (small.has_fields_len) blk: {
- const fields_len = self.code.extra[extra_index];
- extra_index += 1;
- break :blk fields_len;
- } else 0;
-
- const decls_len = if (small.has_decls_len) blk: {
- const decls_len = self.code.extra[extra_index];
- extra_index += 1;
- break :blk decls_len;
- } else 0;
-
- try self.writeFlag(stream, "known_non_opv, ", small.known_non_opv);
- try self.writeFlag(stream, "known_comptime_only, ", small.known_comptime_only);
-
- try stream.print("{s}, ", .{@tagName(small.name_strategy)});
-
- extra_index = try self.writeCaptures(stream, extra_index, captures_len);
- try stream.writeAll(", ");
-
- if (small.has_backing_int) {
- const backing_int_body_len = self.code.extra[extra_index];
- extra_index += 1;
+ if (struct_decl.backing_int_type_body) |backing_int_type_body| {
+ assert(struct_decl.layout == .@"packed");
try stream.writeAll("packed(");
- if (backing_int_body_len == 0) {
- const backing_int_ref: Zir.Inst.Ref = @enumFromInt(self.code.extra[extra_index]);
- extra_index += 1;
- try self.writeInstRef(stream, backing_int_ref);
- } else {
- const body = self.code.bodySlice(extra_index, backing_int_body_len);
- extra_index += backing_int_body_len;
- self.indent += 2;
- try self.writeBracedDecl(stream, body);
- self.indent -= 2;
- }
+ try self.writeBracedDecl(stream, backing_int_type_body);
try stream.writeAll("), ");
} else {
- try stream.print("{s}, ", .{@tagName(small.layout)});
+ try stream.print("{s}, ", .{@tagName(struct_decl.layout)});
}
- if (decls_len == 0) {
- try stream.writeAll("{}, ");
- } else {
- try stream.writeAll("{\n");
- self.indent += 2;
- try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
- self.indent -= 2;
- extra_index += decls_len;
- try stream.splatByteAll(' ', self.indent);
- try stream.writeAll("}, ");
- }
+ try self.writeCaptures(stream, struct_decl.captures, struct_decl.capture_names);
+ try stream.writeAll(", ");
+ try self.writeBracedDecl(stream, struct_decl.decls);
+ try stream.writeAll(", ");
- if (fields_len == 0) {
- try stream.writeAll("{}, {}) ");
+ if (struct_decl.field_names.len == 0) {
+ try stream.writeAll("{}) ");
} else {
- const bits_per_field = 4;
- const fields_per_u32 = 32 / bits_per_field;
- const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
- const Field = struct {
- type_len: u32 = 0,
- align_len: u32 = 0,
- init_len: u32 = 0,
- type: Zir.Inst.Ref = .none,
- name: Zir.NullTerminatedString,
- is_comptime: bool,
- };
- const fields = try self.arena.alloc(Field, fields_len);
- {
- var bit_bag_index: usize = extra_index;
- extra_index += bit_bags_count;
- var cur_bit_bag: u32 = undefined;
- var field_i: u32 = 0;
- while (field_i < fields_len) : (field_i += 1) {
- if (field_i % fields_per_u32 == 0) {
- cur_bit_bag = self.code.extra[bit_bag_index];
- bit_bag_index += 1;
- }
- const has_align = @as(u1, @truncate(cur_bit_bag)) != 0;
- cur_bit_bag >>= 1;
- const has_default = @as(u1, @truncate(cur_bit_bag)) != 0;
- cur_bit_bag >>= 1;
- const is_comptime = @as(u1, @truncate(cur_bit_bag)) != 0;
- cur_bit_bag >>= 1;
- const has_type_body = @as(u1, @truncate(cur_bit_bag)) != 0;
- cur_bit_bag >>= 1;
-
- const field_name_index: Zir.NullTerminatedString = @enumFromInt(self.code.extra[extra_index]);
- extra_index += 1;
-
- fields[field_i] = .{
- .is_comptime = is_comptime,
- .name = field_name_index,
- };
-
- if (has_type_body) {
- fields[field_i].type_len = self.code.extra[extra_index];
- } else {
- fields[field_i].type = @enumFromInt(self.code.extra[extra_index]);
- }
- extra_index += 1;
-
- if (has_align) {
- fields[field_i].align_len = self.code.extra[extra_index];
- extra_index += 1;
- }
-
- if (has_default) {
- fields[field_i].init_len = self.code.extra[extra_index];
- extra_index += 1;
- }
- }
- }
-
try stream.writeAll("{\n");
self.indent += 2;
- for (fields, 0..) |field, i| {
+ var it = struct_decl.iterateFields();
+ while (it.next()) |field| {
try stream.splatByteAll(' ', self.indent);
try self.writeFlag(stream, "comptime ", field.is_comptime);
- if (field.name != .empty) {
- const field_name = self.code.nullTerminatedString(field.name);
- try stream.print("{f}: ", .{std.zig.fmtIdP(field_name)});
- } else {
- try stream.print("@\"{d}\": ", .{i});
- }
- if (field.type != .none) {
- try self.writeInstRef(stream, field.type);
- }
+ const field_name = self.code.nullTerminatedString(field.name);
+ try stream.print("{f}: ", .{std.zig.fmtIdP(field_name)});
- if (field.type_len > 0) {
- const body = self.code.bodySlice(extra_index, field.type_len);
- extra_index += body.len;
- self.indent += 2;
- try self.writeBracedDecl(stream, body);
- self.indent -= 2;
- }
-
- if (field.align_len > 0) {
- const body = self.code.bodySlice(extra_index, field.align_len);
- extra_index += body.len;
- self.indent += 2;
+ self.indent += 2;
+ try self.writeBracedDecl(stream, field.type_body);
+ if (field.align_body) |body| {
try stream.writeAll(" align(");
try self.writeBracedDecl(stream, body);
- try stream.writeAll(")");
- self.indent -= 2;
+ try stream.writeByte(')');
}
-
- if (field.init_len > 0) {
- const body = self.code.bodySlice(extra_index, field.init_len);
- extra_index += body.len;
- self.indent += 2;
+ if (field.default_body) |body| {
try stream.writeAll(" = ");
try self.writeBracedDecl(stream, body);
- self.indent -= 2;
}
+ self.indent -= 2;
try stream.writeAll(",\n");
}
@@ -1619,267 +1489,73 @@ const Writer = struct {
try self.writeSrcNode(stream, .zero);
}
- fn writeUnionDecl(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
- const small = @as(Zir.Inst.UnionDecl.Small, @bitCast(extended.small));
-
- const extra = self.code.extraData(Zir.Inst.UnionDecl, extended.operand);
+ fn writeUnionDecl(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
+ const union_decl = self.code.getUnionDecl(inst);
const prev_parent_decl_node = self.parent_decl_node;
- self.parent_decl_node = extra.data.src_node;
+ self.parent_decl_node = union_decl.src_node;
defer self.parent_decl_node = prev_parent_decl_node;
- const fields_hash: std.zig.SrcHash = @bitCast([4]u32{
- extra.data.fields_hash_0,
- extra.data.fields_hash_1,
- extra.data.fields_hash_2,
- extra.data.fields_hash_3,
- });
-
+ const fields_hash = self.code.getAssociatedSrcHash(inst).?;
try stream.print("hash({x}) ", .{&fields_hash});
- var extra_index: usize = extra.end;
-
- const tag_type_ref = if (small.has_tag_type) blk: {
- const tag_type_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
- extra_index += 1;
- break :blk tag_type_ref;
- } else .none;
-
- const captures_len = if (small.has_captures_len) blk: {
- const captures_len = self.code.extra[extra_index];
- extra_index += 1;
- break :blk captures_len;
- } else 0;
-
- const body_len = if (small.has_body_len) blk: {
- const body_len = self.code.extra[extra_index];
- extra_index += 1;
- break :blk body_len;
- } else 0;
-
- const fields_len = if (small.has_fields_len) blk: {
- const fields_len = self.code.extra[extra_index];
- extra_index += 1;
- break :blk fields_len;
- } else 0;
-
- const decls_len = if (small.has_decls_len) blk: {
- const decls_len = self.code.extra[extra_index];
- extra_index += 1;
- break :blk decls_len;
- } else 0;
-
- try stream.print("{s}, {s}, ", .{
- @tagName(small.name_strategy), @tagName(small.layout),
- });
- try self.writeFlag(stream, "autoenum, ", small.auto_enum_tag);
-
- extra_index = try self.writeCaptures(stream, extra_index, captures_len);
- try stream.writeAll(", ");
-
- if (decls_len == 0) {
- try stream.writeAll("{}");
- } else {
- try stream.writeAll("{\n");
- self.indent += 2;
- try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
- self.indent -= 2;
- extra_index += decls_len;
- try stream.splatByteAll(' ', self.indent);
- try stream.writeAll("}");
+ try stream.print("{s}, ", .{@tagName(union_decl.name_strategy)});
+
+ switch (union_decl.kind) {
+ .auto => try stream.writeAll("auto, "),
+ .@"extern" => try stream.writeAll("extern, "),
+ .@"packed" => try stream.writeAll("packed, "),
+ .packed_explicit => {
+ try stream.writeAll("packed(");
+ try self.writeBracedDecl(stream, union_decl.arg_type_body.?);
+ try stream.writeAll("), ");
+ },
+ .tagged_explicit => {
+ try stream.writeAll("tagged(");
+ try self.writeBracedDecl(stream, union_decl.arg_type_body.?);
+ try stream.writeAll("), ");
+ },
+ .tagged_enum => try stream.writeAll("tagged(enum), "),
+ .tagged_enum_explicit => {
+ try stream.writeAll("tagged(enum(");
+ try self.writeBracedDecl(stream, union_decl.arg_type_body.?);
+ try stream.writeAll(")), ");
+ },
}
- if (tag_type_ref != .none) {
- try stream.writeAll(", ");
- try self.writeInstRef(stream, tag_type_ref);
- }
+ try self.writeCaptures(stream, union_decl.captures, union_decl.capture_names);
+ try stream.writeAll(", ");
+ try self.writeBracedDecl(stream, union_decl.decls);
+ try stream.writeAll(", ");
- if (fields_len == 0) {
+ if (union_decl.field_names.len == 0) {
try stream.writeAll("}) ");
- try self.writeSrcNode(stream, .zero);
- return;
- }
- try stream.writeAll(", ");
-
- const body = self.code.bodySlice(extra_index, body_len);
- extra_index += body.len;
-
- try self.writeBracedDecl(stream, body);
- try stream.writeAll(", {\n");
-
- self.indent += 2;
- const bits_per_field = 4;
- const fields_per_u32 = 32 / bits_per_field;
- const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
- const body_end = extra_index;
- extra_index += bit_bags_count;
- var bit_bag_index: usize = body_end;
- var cur_bit_bag: u32 = undefined;
- var field_i: u32 = 0;
- while (field_i < fields_len) : (field_i += 1) {
- if (field_i % fields_per_u32 == 0) {
- cur_bit_bag = self.code.extra[bit_bag_index];
- bit_bag_index += 1;
- }
- const has_type = @as(u1, @truncate(cur_bit_bag)) != 0;
- cur_bit_bag >>= 1;
- const has_align = @as(u1, @truncate(cur_bit_bag)) != 0;
- cur_bit_bag >>= 1;
- const has_value = @as(u1, @truncate(cur_bit_bag)) != 0;
- cur_bit_bag >>= 1;
- const unused = @as(u1, @truncate(cur_bit_bag)) != 0;
- cur_bit_bag >>= 1;
-
- _ = unused;
-
- const field_name_index: Zir.NullTerminatedString = @enumFromInt(self.code.extra[extra_index]);
- const field_name = self.code.nullTerminatedString(field_name_index);
- extra_index += 1;
-
- try stream.splatByteAll(' ', self.indent);
- try stream.print("{f}", .{std.zig.fmtIdP(field_name)});
-
- if (has_type) {
- const field_type = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
- extra_index += 1;
-
- try stream.writeAll(": ");
- try self.writeInstRef(stream, field_type);
- }
- if (has_align) {
- const align_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
- extra_index += 1;
-
- try stream.writeAll(" align(");
- try self.writeInstRef(stream, align_ref);
- try stream.writeAll(")");
- }
- if (has_value) {
- const default_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
- extra_index += 1;
-
- try stream.writeAll(" = ");
- try self.writeInstRef(stream, default_ref);
- }
- try stream.writeAll(",\n");
- }
-
- self.indent -= 2;
- try stream.splatByteAll(' ', self.indent);
- try stream.writeAll("}) ");
- try self.writeSrcNode(stream, .zero);
- }
-
- fn writeEnumDecl(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
- const small = @as(Zir.Inst.EnumDecl.Small, @bitCast(extended.small));
-
- const extra = self.code.extraData(Zir.Inst.EnumDecl, extended.operand);
-
- const prev_parent_decl_node = self.parent_decl_node;
- self.parent_decl_node = extra.data.src_node;
- defer self.parent_decl_node = prev_parent_decl_node;
-
- const fields_hash: std.zig.SrcHash = @bitCast([4]u32{
- extra.data.fields_hash_0,
- extra.data.fields_hash_1,
- extra.data.fields_hash_2,
- extra.data.fields_hash_3,
- });
-
- try stream.print("hash({x}) ", .{&fields_hash});
-
- var extra_index: usize = extra.end;
-
- const tag_type_ref = if (small.has_tag_type) blk: {
- const tag_type_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
- extra_index += 1;
- break :blk tag_type_ref;
- } else .none;
-
- const captures_len = if (small.has_captures_len) blk: {
- const captures_len = self.code.extra[extra_index];
- extra_index += 1;
- break :blk captures_len;
- } else 0;
-
- const body_len = if (small.has_body_len) blk: {
- const body_len = self.code.extra[extra_index];
- extra_index += 1;
- break :blk body_len;
- } else 0;
-
- const fields_len = if (small.has_fields_len) blk: {
- const fields_len = self.code.extra[extra_index];
- extra_index += 1;
- break :blk fields_len;
- } else 0;
-
- const decls_len = if (small.has_decls_len) blk: {
- const decls_len = self.code.extra[extra_index];
- extra_index += 1;
- break :blk decls_len;
- } else 0;
-
- try stream.print("{s}, ", .{@tagName(small.name_strategy)});
- try self.writeFlag(stream, "nonexhaustive, ", small.nonexhaustive);
-
- extra_index = try self.writeCaptures(stream, extra_index, captures_len);
- try stream.writeAll(", ");
-
- if (decls_len == 0) {
- try stream.writeAll("{}, ");
} else {
try stream.writeAll("{\n");
self.indent += 2;
- try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
- self.indent -= 2;
- extra_index += decls_len;
- try stream.splatByteAll(' ', self.indent);
- try stream.writeAll("}, ");
- }
-
- if (tag_type_ref != .none) {
- try self.writeInstRef(stream, tag_type_ref);
- try stream.writeAll(", ");
- }
-
- const body = self.code.bodySlice(extra_index, body_len);
- extra_index += body.len;
-
- try self.writeBracedDecl(stream, body);
- if (fields_len == 0) {
- try stream.writeAll(", {}) ");
- } else {
- try stream.writeAll(", {\n");
-
- self.indent += 2;
- const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
- const body_end = extra_index;
- extra_index += bit_bags_count;
- var bit_bag_index: usize = body_end;
- var cur_bit_bag: u32 = undefined;
- var field_i: u32 = 0;
- while (field_i < fields_len) : (field_i += 1) {
- if (field_i % 32 == 0) {
- cur_bit_bag = self.code.extra[bit_bag_index];
- bit_bag_index += 1;
- }
- const has_tag_value = @as(u1, @truncate(cur_bit_bag)) != 0;
- cur_bit_bag >>= 1;
-
- const field_name = self.code.nullTerminatedString(@enumFromInt(self.code.extra[extra_index]));
- extra_index += 1;
+ var it = union_decl.iterateFields();
+ while (it.next()) |field| {
try stream.splatByteAll(' ', self.indent);
+ const field_name = self.code.nullTerminatedString(field.name);
try stream.print("{f}", .{std.zig.fmtIdP(field_name)});
- if (has_tag_value) {
- const tag_value_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
- extra_index += 1;
-
+ self.indent += 2;
+ if (field.type_body) |body| {
+ try stream.writeAll(": ");
+ try self.writeBracedDecl(stream, body);
+ }
+ if (field.align_body) |body| {
+ try stream.writeAll(" align(");
+ try self.writeBracedDecl(stream, body);
+ try stream.writeByte(')');
+ }
+ if (field.value_body) |body| {
try stream.writeAll(" = ");
- try self.writeInstRef(stream, tag_value_ref);
+ try self.writeBracedDecl(stream, body);
}
+ self.indent -= 2;
+
try stream.writeAll(",\n");
}
self.indent -= 2;
@@ -1889,43 +1565,46 @@ const Writer = struct {
try self.writeSrcNode(stream, .zero);
}
- fn writeOpaqueDecl(
- self: *Writer,
- stream: *std.Io.Writer,
- extended: Zir.Inst.Extended.InstData,
- ) !void {
- const small = @as(Zir.Inst.OpaqueDecl.Small, @bitCast(extended.small));
- const extra = self.code.extraData(Zir.Inst.OpaqueDecl, extended.operand);
+ fn writeEnumDecl(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
+ const enum_decl = self.code.getEnumDecl(inst);
const prev_parent_decl_node = self.parent_decl_node;
- self.parent_decl_node = extra.data.src_node;
+ self.parent_decl_node = enum_decl.src_node;
defer self.parent_decl_node = prev_parent_decl_node;
- var extra_index: usize = extra.end;
+ const fields_hash = self.code.getAssociatedSrcHash(inst).?;
+ try stream.print("hash({x}) ", .{&fields_hash});
- const captures_len = if (small.has_captures_len) blk: {
- const captures_len = self.code.extra[extra_index];
- extra_index += 1;
- break :blk captures_len;
- } else 0;
+ try stream.print("{s}, ", .{@tagName(enum_decl.name_strategy)});
+ try self.writeFlag(stream, "nonexhaustive, ", enum_decl.nonexhaustive);
+ if (enum_decl.tag_type_body) |tag_type_body| {
+ try stream.writeAll("tag(");
+ try self.writeBracedDecl(stream, tag_type_body);
+ try stream.writeAll("), ");
+ }
- const decls_len = if (small.has_decls_len) blk: {
- const decls_len = self.code.extra[extra_index];
- extra_index += 1;
- break :blk decls_len;
- } else 0;
-
- try stream.print("{s}, ", .{@tagName(small.name_strategy)});
-
- extra_index = try self.writeCaptures(stream, extra_index, captures_len);
+ try self.writeCaptures(stream, enum_decl.captures, enum_decl.capture_names);
+ try stream.writeAll(", ");
+ try self.writeBracedDecl(stream, enum_decl.decls);
try stream.writeAll(", ");
- if (decls_len == 0) {
+ if (enum_decl.field_names.len == 0) {
try stream.writeAll("{}) ");
} else {
try stream.writeAll("{\n");
self.indent += 2;
- try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
+
+ var it = enum_decl.iterateFields();
+ while (it.next()) |field| {
+ try stream.splatByteAll(' ', self.indent);
+ const field_name = self.code.nullTerminatedString(field.name);
+ try stream.print("{f}", .{std.zig.fmtIdP(field_name)});
+ if (field.value_body) |body| {
+ try stream.writeAll(" = ");
+ try self.writeBracedDecl(stream, body);
+ }
+ try stream.writeAll(",\n");
+ }
self.indent -= 2;
try stream.splatByteAll(' ', self.indent);
try stream.writeAll("}) ");
@@ -1933,6 +1612,21 @@ const Writer = struct {
try self.writeSrcNode(stream, .zero);
}
+ fn writeOpaqueDecl(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
+ const opaque_decl = self.code.getOpaqueDecl(inst);
+
+ const prev_parent_decl_node = self.parent_decl_node;
+ self.parent_decl_node = opaque_decl.src_node;
+ defer self.parent_decl_node = prev_parent_decl_node;
+
+ try stream.print("{s}, ", .{@tagName(opaque_decl.name_strategy)});
+ try self.writeCaptures(stream, opaque_decl.captures, opaque_decl.capture_names);
+ try stream.writeAll(", ");
+ try self.writeBracedDecl(stream, opaque_decl.decls);
+ try stream.writeAll(") ");
+ try self.writeSrcNode(stream, .zero);
+ }
+
fn writeTupleDecl(self: *Writer, stream: *std.Io.Writer, extended: Zir.Inst.Extended.InstData) !void {
const fields_len = extended.small;
assert(fields_len != 0);
@@ -2588,14 +2282,11 @@ const Writer = struct {
return stream.print("%{d}", .{@intFromEnum(inst)});
}
- fn writeCaptures(self: *Writer, stream: *std.Io.Writer, extra_index: usize, captures_len: u32) !usize {
- if (captures_len == 0) {
- try stream.writeAll("{}");
- return extra_index;
+ fn writeCaptures(self: *Writer, stream: *std.Io.Writer, captures: []const Zir.Inst.Capture, capture_names: []const Zir.NullTerminatedString) !void {
+ if (captures.len == 0) {
+ assert(capture_names.len == 0);
+ return stream.writeAll("{}");
}
-
- const captures: []const Zir.Inst.Capture = @ptrCast(self.code.extra[extra_index..][0..captures_len]);
- const capture_names: []const Zir.NullTerminatedString = @ptrCast(self.code.extra[extra_index + captures_len ..][0..captures_len]);
for (captures, capture_names) |capture, name| {
try stream.writeAll("{ ");
if (name != .empty) {
@@ -2604,8 +2295,6 @@ const Writer = struct {
}
try self.writeCapture(stream, capture);
}
-
- return extra_index + 2 * captures_len;
}
fn writeCapture(self: *Writer, stream: *std.Io.Writer, capture: Zir.Inst.Capture) !void {
diff --git a/stage1/zig.h b/stage1/zig.h
index 81a815ab5568b57f5d48c8da91a04b761d4f9a2a..0b9c6e58ca6d9f1800fd8059e5db9d3636faa35c 100644
--- a/stage1/zig.h
+++ b/stage1/zig.h
@@ -151,6 +151,14 @@
#define zig_has_attribute(attribute) 0
#endif
+#if __STDC_VERSION__ >= 201112L
+#define zig_static_assert(cond, msg) _Static_assert(cond, msg)
+#elif zig_has_attribute(unused)
+#define zig_static_assert(cond, _) typedef char zig_expand_concat(zig_static_assert_fail_, __LINE__)[!!(cond)] __attribute__((unused))
+#else
+#define zig_static_assert(cond, _) typedef char zig_expand_concat(zig_static_assert_fail_, __LINE__)[!!(cond)]
+#endif
+
#if __STDC_VERSION__ >= 202311L
#define zig_threadlocal thread_local
#elif __STDC_VERSION__ >= 201112L
@@ -259,7 +267,7 @@
#endif
#if zig_has_attribute(packed) || defined(zig_tinyc)
-#define zig_packed(definition) __attribute__((packed)) definition
+#define zig_packed(definition) definition __attribute__((packed))
#elif defined(zig_msvc)
#define zig_packed(definition) __pragma(pack(1)) definition __pragma(pack())
#else
diff --git a/stage1/zig1.wasm b/stage1/zig1.wasm
index 0c68522efc27ffeefbdc88b1591ea60c7ff102fc..11942012c73145171942c837b7c61c783f13203b 100644
Binary files a/stage1/zig1.wasm and b/stage1/zig1.wasm differ
diff --git a/test/behavior.zig b/test/behavior.zig
index e4153c91bbea3721f79807393053f87c22f4ac52..c9c06e934230692c95d07b96d911fb09a80d3bdf 100644
--- a/test/behavior.zig
+++ b/test/behavior.zig
@@ -24,7 +24,6 @@ test {
_ = @import("behavior/duplicated_test_names.zig");
_ = @import("behavior/defer.zig");
_ = @import("behavior/destructure.zig");
- _ = @import("behavior/empty_union.zig");
_ = @import("behavior/enum.zig");
_ = @import("behavior/error.zig");
_ = @import("behavior/eval.zig");
diff --git a/test/behavior/align.zig b/test/behavior/align.zig
index b971c78596d2ef0811c8041fa199d9d387492ed3..550d7008b419474cbb9b207fc2b22fcd5549960f 100644
--- a/test/behavior/align.zig
+++ b/test/behavior/align.zig
@@ -18,6 +18,7 @@ test "global variable alignment" {
test "large alignment of local constant" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // flaky
+ if (builtin.zig_backend == .stage2_c and builtin.target.abi == .msvc) return error.SkipZigTest;
const x: f32 align(128) = 12.34;
try std.testing.expect(@intFromPtr(&x) % 128 == 0);
@@ -30,13 +31,41 @@ test "slicing array of length 1 can not assume runtime index is always zero" {
var runtime_index: usize = 1;
_ = &runtime_index;
const slice = @as(*align(4) [1]u8, &foo)[runtime_index..];
- try expect(@TypeOf(slice) == []u8);
+ try expect(@TypeOf(slice) == []align(1) u8);
try expect(slice.len == 0);
try expect(@as(u2, @truncate(@intFromPtr(slice.ptr) - 1)) == 0);
}
-test "default alignment allows unspecified in type syntax" {
- try expect(*u32 == *align(@alignOf(u32)) u32);
+test "implicitly-aligned pointer is coercible to equivalent explicitly-aligned pointer" {
+ const A = *u32;
+ const B = *align(@alignOf(u32)) u32;
+
+ comptime assert(A != B);
+
+ const static = struct {
+ fn doTheTest() !void {
+ var buf: u32 = 123;
+
+ const ptr: A = &buf;
+ const coerced_ptr: B = ptr;
+
+ try expect(ptr == coerced_ptr);
+ try expect(ptr.* == 123);
+ try expect(coerced_ptr.* == 123);
+
+ const ptr_ptr: *const A = &ptr;
+ const coerced_ptr_ptr: *const B = ptr_ptr;
+
+ try expect(ptr_ptr == coerced_ptr_ptr);
+ try expect(ptr_ptr.* == &buf);
+ try expect(coerced_ptr_ptr.* == &buf);
+ try expect(ptr_ptr.*.* == 123);
+ try expect(coerced_ptr_ptr.*.* == 123);
+ }
+ };
+
+ try static.doTheTest();
+ try comptime static.doTheTest();
}
test "implicitly decreasing pointer alignment" {
@@ -307,11 +336,15 @@ test "runtime-known array index has best alignment possible" {
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
// take full advantage of over-alignment
- var array align(4) = [_]u8{ 1, 2, 3, 4 };
+ var array align(4) = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
comptime assert(@TypeOf(&array[0]) == *align(4) u8);
- comptime assert(@TypeOf(&array[1]) == *u8);
+ comptime assert(@TypeOf(&array[1]) == *align(1) u8);
comptime assert(@TypeOf(&array[2]) == *align(2) u8);
- comptime assert(@TypeOf(&array[3]) == *u8);
+ comptime assert(@TypeOf(&array[3]) == *align(1) u8);
+ comptime assert(@TypeOf(&array[4]) == *align(4) u8);
+ comptime assert(@TypeOf(&array[5]) == *align(1) u8);
+ comptime assert(@TypeOf(&array[6]) == *align(2) u8);
+ comptime assert(@TypeOf(&array[7]) == *align(1) u8);
// because align is too small but we still figure out to use 2
var bigger align(2) = [_]u64{ 1, 2, 3, 4 };
@@ -332,10 +365,14 @@ test "runtime-known array index has best alignment possible" {
try testIndex(smaller[runtime_zero..].ptr, 3, *align(2) u32);
// has to use ABI alignment because index known at runtime only
- try testIndex2(&array, 0, *u8);
- try testIndex2(&array, 1, *u8);
- try testIndex2(&array, 2, *u8);
- try testIndex2(&array, 3, *u8);
+ try testIndex2(&array, 0, *align(1) u8);
+ try testIndex2(&array, 1, *align(1) u8);
+ try testIndex2(&array, 2, *align(1) u8);
+ try testIndex2(&array, 3, *align(1) u8);
+ try testIndex2(&array, 4, *align(1) u8);
+ try testIndex2(&array, 5, *align(1) u8);
+ try testIndex2(&array, 6, *align(1) u8);
+ try testIndex2(&array, 7, *align(1) u8);
}
fn testIndex(smaller: [*]align(2) u32, index: usize, comptime T: type) !void {
comptime assert(@TypeOf(&smaller[index]) == T);
diff --git a/test/behavior/alignof.zig b/test/behavior/alignof.zig
index 7adec6168fa79169d21894fe63116f32b49c286d..f8914ead80b5dc4ee8eed3039e0ad96d7f880961 100644
--- a/test/behavior/alignof.zig
+++ b/test/behavior/alignof.zig
@@ -39,3 +39,8 @@ test "correct alignment for elements and slices of aligned array" {
try expect(@alignOf(@TypeOf(&buf[start..end])) == @alignOf(*u8));
try expect(@alignOf(@TypeOf(&buf[start])) == @alignOf(*u8));
}
+
+test "@alignOf(anyerror!noreturn)" {
+ try expect(@alignOf(anyerror!noreturn) == @alignOf(anyerror));
+ try expect(@alignOf(anyerror!anyerror!noreturn) == @alignOf(anyerror));
+}
diff --git a/test/behavior/array.zig b/test/behavior/array.zig
index b28ee267c2e03a1a1b758ea6256b7f3fc23ebb09..2bd85555297beed2d7b33de499e272ddc639a175 100644
--- a/test/behavior/array.zig
+++ b/test/behavior/array.zig
@@ -539,28 +539,6 @@ test "sentinel element count towards the ABI size calculation" {
try comptime S.doTheTest();
}
-test "zero-sized array with recursive type definition" {
- if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
-
- const U = struct {
- fn foo(comptime T: type, comptime n: usize) type {
- return struct {
- s: [n]T,
- x: usize = n,
- };
- }
- };
-
- const S = struct {
- list: U.foo(@This(), 0),
- };
-
- var t: S = .{ .list = .{ .s = undefined } };
- _ = &t;
- try expect(@as(usize, 0) == t.list.x);
-}
-
test "type coercion of anon struct literal to array" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
diff --git a/test/behavior/bitcast.zig b/test/behavior/bitcast.zig
index 90cf8a5c776b07b538a27b19df5a3362471319a0..910356e3608f50f60873d7e565f027c5dce041ed 100644
--- a/test/behavior/bitcast.zig
+++ b/test/behavior/bitcast.zig
@@ -350,9 +350,6 @@ test "comptime @bitCast packed struct to int and back" {
iint_neg2: i3 = -2,
float: f32 = 3.14,
@"enum": enum(u2) { A, B = 1, C, D } = .B,
- vectorb: @Vector(3, bool) = .{ true, false, true },
- vectori: @Vector(2, u8) = .{ 127, 42 },
- vectorf: @Vector(2, f16) = .{ 3.14, 2.71 },
};
const Int = @typeInfo(S).@"struct".backing_integer.?;
@@ -511,35 +508,6 @@ test "@bitCast of packed struct of bools all false" {
try expect(@as(u8, @as(u4, @bitCast(p))) == 0);
}
-test "@bitCast of packed struct containing pointer" {
- 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_spirv) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://discourse.llvm.org/t/rfc-remove-most-constant-expressions/63179
-
- const S = struct {
- const A = packed struct {
- ptr: *const u32,
- };
-
- const B = packed struct {
- ptr: *const i32,
- };
-
- fn doTheTest() !void {
- const x: u32 = 123;
- var a: A = undefined;
- a = .{ .ptr = &x };
- const b: B = @bitCast(a);
- try expect(b.ptr.* == 123);
- }
- };
-
- try S.doTheTest();
- try comptime S.doTheTest();
-}
-
test "@bitCast of extern struct containing pointer" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
diff --git a/test/behavior/call.zig b/test/behavior/call.zig
index 3433cc59712750f434f33f9112c68846126020e0..fd134499439cc8fd647aac316e5f2e6f3e2de910 100644
--- a/test/behavior/call.zig
+++ b/test/behavior/call.zig
@@ -551,19 +551,18 @@ test "generic function pointer can be called" {
test "value returned from comptime function is comptime known" {
const S = struct {
- fn fields(comptime T: type) switch (@typeInfo(T)) {
- .@"struct" => []const std.builtin.Type.StructField,
+ fn fieldCount(comptime T: type) switch (@typeInfo(T)) {
+ .@"struct" => comptime_int,
else => unreachable,
} {
return switch (@typeInfo(T)) {
- .@"struct" => |info| info.fields,
+ .@"struct" => |info| info.fields.len,
else => unreachable,
};
}
};
- const fields_list = S.fields(@TypeOf(.{}));
- if (fields_list.len != 0)
- @compileError("Argument count mismatch");
+ const fields_len = S.fieldCount(@TypeOf(.{}));
+ comptime assert(fields_len == 0);
}
test "registers get overwritten when ignoring return" {
diff --git a/test/behavior/empty_union.zig b/test/behavior/empty_union.zig
deleted file mode 100644
index f05feacfafd7e429ff01aa3c65e376acaba63441..0000000000000000000000000000000000000000
--- a/test/behavior/empty_union.zig
+++ /dev/null
@@ -1,66 +0,0 @@
-const builtin = @import("builtin");
-const std = @import("std");
-const expect = std.testing.expect;
-
-test "switch on empty enum" {
- const E = enum {};
- var e: E = undefined;
- _ = &e;
- switch (e) {}
-}
-
-test "switch on empty enum with a specified tag type" {
- const E = enum(u8) {};
- var e: E = undefined;
- _ = &e;
- switch (e) {}
-}
-
-test "switch on empty auto numbered tagged union" {
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
-
- const U = union(enum(u8)) {};
- var u: U = undefined;
- _ = &u;
- switch (u) {}
-}
-
-test "switch on empty tagged union" {
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
-
- const E = enum {};
- const U = union(E) {};
- var u: U = undefined;
- _ = &u;
- switch (u) {}
-}
-
-test "empty union" {
- const U = union {};
- try expect(@sizeOf(U) == 0);
- try expect(@alignOf(U) == 1);
-}
-
-test "empty extern union" {
- const U = extern union {};
- try expect(@sizeOf(U) == 0);
- try expect(@alignOf(U) == 1);
-}
-
-test "empty union passed as argument" {
- const U = union(enum) {
- fn f(u: @This()) void {
- switch (u) {}
- }
- };
- U.f(@as(U, undefined));
-}
-
-test "empty enum passed as argument" {
- const E = enum {
- fn f(e: @This()) void {
- switch (e) {}
- }
- };
- E.f(@as(E, undefined));
-}
diff --git a/test/behavior/enum.zig b/test/behavior/enum.zig
index d49b27d4d41841bc40b5b8bd61fff45ebc709942..9ec1ed8c35b920957ed77582a56775c6b0618519 100644
--- a/test/behavior/enum.zig
+++ b/test/behavior/enum.zig
@@ -823,15 +823,6 @@ test "enum with one member and u1 tag type @intFromEnum" {
try expect(@intFromEnum(Enum.Test) == 0);
}
-test "enum with comptime_int tag type" {
- const Enum = enum(comptime_int) {
- One = 3,
- Two = 2,
- Three = 1,
- };
- comptime assert(Tag(Enum) == comptime_int);
-}
-
test "enum with one member default to u0 tag type" {
const E0 = enum { X };
comptime assert(Tag(E0) == u0);
@@ -1274,13 +1265,6 @@ fn getLazyInitialized(param: enum(u8) {
return @intFromEnum(param);
}
-test "Non-exhaustive enum backed by comptime_int" {
- const E = enum(comptime_int) { a, b, c, _ };
- comptime var e: E = .a;
- e = @as(E, @enumFromInt(378089457309184723749));
- try expect(@intFromEnum(e) == 378089457309184723749);
-}
-
test "matching captures causes enum equivalence" {
const S = struct {
fn Nonexhaustive(comptime I: type) type {
@@ -1347,3 +1331,41 @@ test "comptime @enumFromInt with signed arithmetic" {
comptime assert(x == .bar);
comptime assert(@intFromEnum(x) == 0);
}
+
+test "switch on empty enum" {
+ const E = enum {};
+ var e: E = undefined;
+ _ = &e;
+ switch (e) {}
+}
+
+test "switch on empty enum with a specified tag type" {
+ const E = enum(u8) {};
+ var e: E = undefined;
+ _ = &e;
+ switch (e) {}
+}
+
+test "empty enum passed as argument" {
+ const E = enum {
+ fn f(e: @This()) void {
+ switch (e) {}
+ }
+ };
+ E.f(@as(E, undefined));
+}
+
+test "enum int tag type uses declaration inside the enum" {
+ const static = struct {
+ const E = enum(E.IntTag) {
+ const IntTag = u8;
+ a,
+ b,
+ c,
+ };
+ };
+ try expect(@sizeOf(static.E) == @sizeOf(u8));
+ const val: static.E = .b;
+ try expect(val == .b);
+ try expect(@intFromEnum(val) == 1);
+}
diff --git a/test/behavior/error.zig b/test/behavior/error.zig
index d74a7668a97eb29982a0ebf50a87948b8a629ee5..0679736ac34d478cdaa2212e4836670ce9d3fabb 100644
--- a/test/behavior/error.zig
+++ b/test/behavior/error.zig
@@ -1109,3 +1109,36 @@ test "'if' ignores error via local while 'else' ignores error directly" {
try S.testOne(false);
try S.testOne(true);
}
+
+test "@errorCast into own inferred error set" {
+ const static = struct {
+ fn foo(b: bool) !void {
+ if (b) {
+ return @errorCast(error.Bad);
+ }
+ }
+ };
+ try static.foo(false);
+ if (static.foo(true)) {
+ return error.ExpectedError;
+ } else |err| {
+ try expect(err == error.Bad);
+ }
+
+ const errors = @typeInfo(@typeInfo(@TypeOf(static.foo(false))).error_union.error_set).error_set.?;
+ comptime assert(errors.len == 1);
+ comptime assert(std.mem.eql(u8, errors[0].name, "Bad"));
+}
+
+test "@errorCast into other inferred error set" {
+ const static = struct {
+ fn foo() !void {
+ return error.Bad;
+ }
+ };
+ const Ies = @typeInfo(@TypeOf(static.foo())).error_union.error_set;
+ const err: Ies = @errorCast(error.Bad);
+ try expect(err == error.Bad);
+ const non_err: Ies!u32 = @errorCast(@as(error{}!u32, 123));
+ try expect(try non_err == 123);
+}
diff --git a/test/behavior/eval.zig b/test/behavior/eval.zig
index 8f45405e94838c9c7768616a9f1f1dd24c2baa7f..03550fef70d73da7b334842a25ed383d8867cc8b 100644
--- a/test/behavior/eval.zig
+++ b/test/behavior/eval.zig
@@ -719,13 +719,6 @@ fn testVarInsideInlineLoop(args: anytype) !void {
}
}
-test "*align(1) u16 is the same as *align(1:0:2) u16" {
- comptime {
- try expect(*align(1:0:2) u16 == *align(1) u16);
- try expect(*align(2:0:2) u16 == *u16);
- }
-}
-
test "array concatenation of function calls" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -1081,120 +1074,6 @@ test "comptime break operand passing through runtime switch converted to runtime
try comptime S.doTheTest('b');
}
-test "no dependency loop for alignment of self struct" {
- if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
-
- const S = struct {
- fn doTheTest() !void {
- var a: namespace.A = undefined;
- a.d = .{ .g = &buf };
- a.d.g[3] = 42;
- a.d.g[3] += 1;
- try expect(a.d.g[3] == 43);
- }
-
- var buf: [10]u8 align(@alignOf([*]u8)) = undefined;
-
- const namespace = struct {
- const B = struct { a: A };
- const A = C(B);
- };
-
- pub fn C(comptime B: type) type {
- return struct {
- d: D(F) = .{},
-
- const F = struct { b: B };
- };
- }
-
- pub fn D(comptime F: type) type {
- return struct {
- g: [*]align(@alignOf(F)) u8 = undefined,
- };
- }
- };
- try S.doTheTest();
-}
-
-test "no dependency loop for alignment of self bare union" {
- if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
-
- const S = struct {
- fn doTheTest() !void {
- var a: namespace.A = undefined;
- a.d = .{ .g = &buf };
- a.d.g[3] = 42;
- a.d.g[3] += 1;
- try expect(a.d.g[3] == 43);
- }
-
- var buf: [10]u8 align(@alignOf([*]u8)) = undefined;
-
- const namespace = struct {
- const B = union { a: A, b: void };
- const A = C(B);
- };
-
- pub fn C(comptime B: type) type {
- return struct {
- d: D(F) = .{},
-
- const F = struct { b: B };
- };
- }
-
- pub fn D(comptime F: type) type {
- return struct {
- g: [*]align(@alignOf(F)) u8 = undefined,
- };
- }
- };
- try S.doTheTest();
-}
-
-test "no dependency loop for alignment of self tagged union" {
- if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
-
- const S = struct {
- fn doTheTest() !void {
- var a: namespace.A = undefined;
- a.d = .{ .g = &buf };
- a.d.g[3] = 42;
- a.d.g[3] += 1;
- try expect(a.d.g[3] == 43);
- }
-
- var buf: [10]u8 align(@alignOf([*]u8)) = undefined;
-
- const namespace = struct {
- const B = union(enum) { a: A, b: void };
- const A = C(B);
- };
-
- pub fn C(comptime B: type) type {
- return struct {
- d: D(F) = .{},
-
- const F = struct { b: B };
- };
- }
-
- pub fn D(comptime F: type) type {
- return struct {
- g: [*]align(@alignOf(F)) u8 = undefined,
- };
- }
- };
- try S.doTheTest();
-}
-
test "equality of pointers to comptime const" {
const a: i32 = undefined;
comptime assert(&a == &a);
diff --git a/test/behavior/generics.zig b/test/behavior/generics.zig
index 65a5a1b0070fa81c60774de2686f0b215f95f5ca..89ff5764a88bc2428ec76312e7702b6bf558fd11 100644
--- a/test/behavior/generics.zig
+++ b/test/behavior/generics.zig
@@ -339,7 +339,7 @@ test "generic instantiation of tagged union with only one field" {
try expect(S.foo(.{ .s = "ab" }) == 2);
}
-test "nested generic function" {
+test "generic parameter type is function type" {
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
const S = struct {
@@ -349,10 +349,7 @@ test "nested generic function" {
fn bar(a: u32) anyerror!void {
try expect(a == 123);
}
-
- fn g(_: *const fn (anytype) void) void {}
};
- try expect(@typeInfo(@TypeOf(S.g)).@"fn".is_generic);
try S.foo(u32, S.bar, 123);
}
diff --git a/test/behavior/packed-struct.zig b/test/behavior/packed-struct.zig
index 72e97bef959debf39b1a3d22b6a13cf96bd56682..d5b01f7c12f71ac5e88976a4d50587ffc460a857 100644
--- a/test/behavior/packed-struct.zig
+++ b/test/behavior/packed-struct.zig
@@ -438,27 +438,6 @@ test "nested packed struct field pointers" {
try expectEqual(6, ptr_p1_b.*);
}
-test "load pointer from packed struct" {
- 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; // TODO
- if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
-
- const A = struct {
- index: u16,
- };
- const B = packed struct {
- x: *A,
- y: u32,
- };
- var a: A = .{ .index = 123 };
- const b_list: []const B = &.{.{ .x = &a, .y = 99 }};
- for (b_list) |b| {
- try expect(b.x.index == 123);
- }
-}
-
test "@intFromPtr on a packed struct field" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -601,19 +580,6 @@ test "packed struct fields modification" {
try expect(@as(u16, @bitCast(Small.p)) == 0x1313);
}
-test "optional pointer in packed struct" {
- 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; // TODO
- if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
-
- const T = packed struct { ptr: ?*const u8 };
- var n: u8 = 0;
- const x = T{ .ptr = &n };
- try expect(x.ptr.? == &n);
-}
-
test "nested packed struct field access test" {
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO packed structs larger than 64 bits
@@ -854,7 +820,7 @@ test "packed struct passed to callconv(.c) function" {
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
const S = struct {
- const Packed = packed struct {
+ const Packed = packed struct(u64) {
a: u16,
b: bool = true,
c: bool = true,
@@ -1042,48 +1008,6 @@ test "packed struct acts as a namespace" {
try expect(foo == .fizz);
}
-test "pointer loaded correctly from packed struct" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
-
- if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // crashes MSVC
-
- const RAM = struct {
- data: [0xFFFF + 1]u8,
- fn new() !@This() {
- return .{ .data = [_]u8{0} ** 0x10000 };
- }
- fn get(self: *@This(), addr: u16) u8 {
- return self.data[addr];
- }
- };
-
- const CPU = packed struct {
- interrupts: bool,
- ram: *RAM,
- fn new(ram: *RAM) !@This() {
- return .{
- .ram = ram,
- .interrupts = false,
- };
- }
- fn tick(self: *@This()) !void {
- const queued_interrupts = self.ram.get(0xFFFF) & self.ram.get(0xFF0F);
- if (self.interrupts and queued_interrupts != 0) {
- self.interrupts = false;
- }
- }
- };
-
- var ram = try RAM.new();
- var cpu = try CPU.new(&ram);
- try cpu.tick();
- try std.testing.expect(cpu.interrupts == false);
-}
-
test "assignment to non-byte-aligned field in packed struct" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
@@ -1227,13 +1151,6 @@ test "2-byte packed struct argument in C calling convention" {
}
}
-test "packed struct contains optional pointer" {
- const foo: packed struct {
- a: ?*@This() = null,
- } = .{};
- try expect(foo.a == null);
-}
-
test "packed struct equality" {
const Foo = packed struct {
a: u4,
@@ -1297,21 +1214,6 @@ test "assign packed struct initialized with RLS to packed struct literal field"
try expect(outer.x == x);
}
-test "byte-aligned packed relocation" {
- if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
-
- const S = struct {
- var global: u8 align(2) = 0;
- var packed_value: packed struct { x: u8, y: *align(2) u8 } = .{ .x = 111, .y = &global };
- };
- try expect(S.packed_value.x == 111);
- try expect(S.packed_value.y == &S.global);
-}
-
test "packed struct store of comparison result" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
diff --git a/test/behavior/packed-union.zig b/test/behavior/packed-union.zig
index bbb2f612b6788be2b1a7be647195004dd81da0c2..330a4853b13383b05fc4b7363c8b35e916085d9f 100644
--- a/test/behavior/packed-union.zig
+++ b/test/behavior/packed-union.zig
@@ -1,6 +1,7 @@
const std = @import("std");
const builtin = @import("builtin");
const assert = std.debug.assert;
+const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
test "flags in packed union" {
@@ -178,14 +179,23 @@ test "assigning to non-active field at comptime" {
}
}
-test "comptime packed union of pointers" {
- const U = packed union {
- a: *const u32,
- b: *const [1]u32,
+test "packed union with explicit backing integer" {
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
+
+ const U = packed union(i32) {
+ raw: i32,
+ unsigned_halves: packed struct { low: u16, high: u16 },
+
+ fn check(val: @This()) !void {
+ try expect(@as(i32, @bitCast(val)) == -2);
+ try expect(@as(u32, @bitCast(val)) == 0xFFFFFFFE);
+ try expect(val.raw == -2);
+ try expect(val.unsigned_halves.low == 0xFFFE);
+ try expect(val.unsigned_halves.high == 0xFFFF);
+ }
};
-
- const x: u32 = 123;
- const u: U = .{ .a = &x };
-
- comptime assert(u.b[0] == 123);
+ try U.check(.{ .raw = -2 });
+ try comptime U.check(.{ .raw = -2 });
}
diff --git a/test/behavior/sizeof_and_typeof.zig b/test/behavior/sizeof_and_typeof.zig
index a6087787b5bfec02334554fa527d1011a8bf4a96..cb6c334cb7448bdd403c419baaad2eb9d92443d9 100644
--- a/test/behavior/sizeof_and_typeof.zig
+++ b/test/behavior/sizeof_and_typeof.zig
@@ -11,13 +11,6 @@ test "@sizeOf and @TypeOf" {
const x: u16 = 13;
const z: @TypeOf(x) = 19;
-test "@sizeOf on compile-time types" {
- try expect(@sizeOf(comptime_int) == 0);
- try expect(@sizeOf(comptime_float) == 0);
- try expect(@sizeOf(@TypeOf(.hi)) == 0);
- try expect(@sizeOf(@TypeOf(type)) == 0);
-}
-
test "@TypeOf() with multiple arguments" {
{
var var_1: u32 = undefined;
@@ -127,21 +120,6 @@ test "@bitOffsetOf" {
try expect(@offsetOf(A, "g") * 8 == @bitOffsetOf(A, "g"));
}
-test "@sizeOf(T) == 0 doesn't force resolving struct size" {
- const S = struct {
- const Foo = struct {
- y: if (@sizeOf(Foo) == 0) u64 else u32,
- };
- const Bar = struct {
- x: i32,
- y: if (0 == @sizeOf(Bar)) u64 else u32,
- };
- };
-
- try expect(@sizeOf(S.Foo) == 4);
- try expect(@sizeOf(S.Bar) == 8);
-}
-
test "@TypeOf() has no runtime side effects" {
const S = struct {
fn foo(comptime T: type, ptr: *T) T {
@@ -265,10 +243,6 @@ test "lazy size cast to float" {
}
}
-test "bitSizeOf comptime_int" {
- try expect(@bitSizeOf(comptime_int) == 0);
-}
-
test "runtime instructions inside typeof in comptime only scope" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -336,20 +310,6 @@ test "peer type resolution with @TypeOf doesn't trigger dependency loop check" {
try std.testing.expect(t.next == null);
}
-test "@sizeOf reified union zero-size payload fields" {
- comptime {
- try std.testing.expect(0 == @sizeOf(@Union(.auto, null, &.{}, &.{}, &.{})));
- try std.testing.expect(0 == @sizeOf(@Union(.auto, null, &.{"a"}, &.{void}, &.{.{}})));
- if (builtin.mode == .Debug or builtin.mode == .ReleaseSafe) {
- try std.testing.expect(1 == @sizeOf(@Union(.auto, null, &.{ "a", "b" }, &.{ void, void }, &.{ .{}, .{} })));
- try std.testing.expect(1 == @sizeOf(@Union(.auto, null, &.{ "a", "b", "c" }, &.{ void, void, void }, &.{ .{}, .{}, .{} })));
- } else {
- try std.testing.expect(0 == @sizeOf(@Union(.auto, null, &.{ "a", "b" }, &.{ void, void }, &.{ .{}, .{} })));
- try std.testing.expect(0 == @sizeOf(@Union(.auto, null, &.{ "a", "b", "c" }, &.{ void, void, void }, &.{ .{}, .{}, .{} })));
- }
- }
-}
-
const FILE = extern struct {
dummy_field: u8,
};
@@ -391,7 +351,7 @@ test "Extern function calls in @TypeOf" {
extern fn s_do_thing([*c]const @This(), b: c_int) c_short;
};
- const E = struct {
+ const E = extern struct {
export fn s_do_thing(a: [*c]const @This(), b: c_int) c_short {
_ = a;
_ = b;
diff --git a/test/behavior/slice.zig b/test/behavior/slice.zig
index 4de7b26d34f735b5a11976b3c3d05734e5f39e56..b13003dc5092f4395e211d24b2fef3baad0c05a4 100644
--- a/test/behavior/slice.zig
+++ b/test/behavior/slice.zig
@@ -160,7 +160,7 @@ test "slice of type" {
test "pass a slice of types to a function" {
const S = struct {
- fn checkTypesSlice(types_slice: []const type) !void {
+ fn checkTypesSlice(comptime types_slice: []const type) !void {
try expect(types_slice.len == 2);
try expect(types_slice[0] == anyerror);
try expect(types_slice[1] == bool);
diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig
index 6422aef034bf3b4fbcf1e16acce3742944828a04..3c2d01f6a4014556c4b87ef66a804e5eacb381af 100644
--- a/test/behavior/struct.zig
+++ b/test/behavior/struct.zig
@@ -2177,7 +2177,7 @@ test "avoid unused field function body compile error" {
test "pass a pointer to a comptime-only struct field to a function" {
const S = struct {
- fn checkField(field_ptr: *const type) !void {
+ fn checkField(comptime field_ptr: *const type) !void {
try expect(field_ptr.* == u42);
}
};
@@ -2233,3 +2233,75 @@ test "overaligned extern struct fields" {
try expect(std.mem.isAligned(@intFromPtr(&e.c), @alignOf(u32)));
try expect(std.mem.isAligned(@intFromPtr(&e.d), @alignOf(B)));
}
+
+test "runtime-known slice of comptime-only struct" {
+ const Mixed = struct { index: u32, T: type };
+
+ const static = struct {
+ fn doTheTest(index_offset: usize, s: []const Mixed) !void {
+ for (s, index_offset..) |*mixed, index| {
+ try expect(mixed.index == index);
+ }
+ }
+ };
+
+ try static.doTheTest(10, &.{
+ .{ .index = 10, .T = u8 },
+ .{ .index = 11, .T = noreturn },
+ .{ .index = 12, .T = *opaque {} },
+ .{ .index = 13, .T = undefined },
+ .{ .index = 14, .T = @TypeOf(undefined) },
+ .{ .index = 15, .T = Mixed },
+ });
+}
+
+test "struct contains aligned pointer to itself through type decl" {
+ const Slab = struct {
+ const Ptr = *align(64) const @This();
+ next: Ptr,
+ };
+ // We intentionally use `Slab.Ptr` before `Slab`.
+ var ptr: Slab.Ptr = undefined;
+ var slab: Slab align(64) = undefined;
+ ptr = &slab;
+ slab.next = ptr;
+
+ try expect(ptr == &slab);
+ try expect(slab.next == &slab);
+ try expect(slab.next.next == &slab);
+ try expect(slab.next.next.next == &slab);
+}
+
+test "struct contains underaligned field with overaligned pointer to itself" {
+ if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+ const S = struct {
+ ptr: *align(8) @This() align(1),
+ };
+ var val: S align(8) = undefined;
+ val.ptr = &val;
+ try expect(val.ptr == &val);
+ try expect(val.ptr.ptr == &val);
+ try expect(val.ptr.ptr.ptr == &val);
+}
+
+test "struct contains pointer to function accepting that struct" {
+ const S = struct {
+ const FnPtr = ?*const fn (@This()) void;
+ fn_ptr: FnPtr,
+ };
+ const dummy_fn_ptr: S.FnPtr = @ptrFromInt(0x100000);
+ const dummy_s: S = .{ .fn_ptr = dummy_fn_ptr };
+ try expect(dummy_s.fn_ptr == dummy_fn_ptr);
+ try expect(@TypeOf(dummy_s.fn_ptr.?) == *const fn (S) void);
+}
+
+test "struct queries typeinfo of struct containing pointer back to first struct" {
+ const static = struct {
+ const A = struct { b: *B };
+ const B = struct { a: T: {
+ _ = @typeInfo(A);
+ break :T u32;
+ } };
+ };
+ _ = @as(static.A, undefined);
+}
diff --git a/test/behavior/struct_contains_slice_of_itself.zig b/test/behavior/struct_contains_slice_of_itself.zig
index 5cf8d8134a1cc91abbc392c0acf7c1765f3e50bc..541babee6bb62d10cf05f141545eafe9766aefd7 100644
--- a/test/behavior/struct_contains_slice_of_itself.zig
+++ b/test/behavior/struct_contains_slice_of_itself.zig
@@ -8,7 +8,7 @@ const Node = struct {
const NodeAligned = struct {
payload: i32,
- children: []align(@alignOf(NodeAligned)) NodeAligned,
+ children: []align(1) NodeAligned,
};
test "struct contains slice of itself" {
diff --git a/test/behavior/switch.zig b/test/behavior/switch.zig
index 316421ea3603c98f9a6313ca3c9f60a39a5302f7..784305bca786a054dd19d32fa97f58087635818f 100644
--- a/test/behavior/switch.zig
+++ b/test/behavior/switch.zig
@@ -645,7 +645,7 @@ test "switch prong pointer capture alignment" {
}
switch (u) {
- .a, .c => |*p| comptime assert(@TypeOf(p) == *const u8),
+ .a, .c => |*p| comptime assert(@TypeOf(p) == *align(1) const u8),
.b => |*p| {
_ = p;
return error.TestFailed;
@@ -1141,24 +1141,23 @@ test "decl literals as switch cases" {
try comptime E.doTheTest(.foo);
}
-// TODO audit after #15909 and/or #19855 are decided/implemented
+// TODO audit after #15909 and/or #19855 are decided/implemented.
+// When we do that, consider adding an 'error{}' case if possible.
test "switch with uninstantiable union fields" {
const U = union(enum) {
ok: void,
a: noreturn,
b: noreturn,
- c: error{},
fn doTheTest(u: @This()) void {
switch (u) {
.ok => {},
.a => comptime unreachable,
.b => comptime unreachable,
- .c => comptime unreachable,
}
switch (u) {
.ok => {},
- .a, .b, .c => comptime unreachable,
+ .a, .b => comptime unreachable,
}
switch (u) {
.ok => {},
@@ -1166,7 +1165,7 @@ test "switch with uninstantiable union fields" {
}
switch (u) {
.a => comptime unreachable,
- .ok, .b, .c => {},
+ .ok, .b => {},
}
}
};
diff --git a/test/behavior/tuple.zig b/test/behavior/tuple.zig
index a88a99171b9ed3e7106d48abf76f1c57afce0da0..75cf4515a514512b24fff32410d0d3ccb397552c 100644
--- a/test/behavior/tuple.zig
+++ b/test/behavior/tuple.zig
@@ -592,3 +592,14 @@ test "array of tuples that end with a zero-bit field followed by padding" {
try expect(S.foo[1][1] == 4);
try expect(S.foo[1][2] == {});
}
+
+test "call function at comptime through container-level const tuple" {
+ const static = struct {
+ const MyTuple = struct { (fn () u32) };
+ const val: MyTuple = .{foo};
+ fn foo() u32 {
+ return 1234;
+ }
+ };
+ comptime assert(static.val[0]() == 1234);
+}
diff --git a/test/behavior/tuple_declarations.zig b/test/behavior/tuple_declarations.zig
index 643d79baa1c84073b106b70cdd3fc5509f4e0c42..cc87913975fdd126f85239fa83765d34f7d5c80c 100644
--- a/test/behavior/tuple_declarations.zig
+++ b/test/behavior/tuple_declarations.zig
@@ -22,13 +22,13 @@ test "tuple declaration type info" {
try expect(info.fields[0].type == u32);
try expect(info.fields[0].defaultValue() == 1);
try expect(info.fields[0].is_comptime);
- try expect(info.fields[0].alignment == @alignOf(u32));
+ try expect(info.fields[0].alignment == null);
try expectEqualStrings(info.fields[1].name, "1");
try expect(info.fields[1].type == []const u8);
try expect(info.fields[1].defaultValue() == null);
try expect(!info.fields[1].is_comptime);
- try expect(info.fields[1].alignment == @alignOf([]const u8));
+ try expect(info.fields[1].alignment == null);
}
}
diff --git a/test/behavior/type.zig b/test/behavior/type.zig
index ef27522a63038a36429063607d7d48768195268f..88358db1829cdb9b51018b595d49170f7482b8bc 100644
--- a/test/behavior/type.zig
+++ b/test/behavior/type.zig
@@ -278,13 +278,13 @@ test "Type.Union from regular enum" {
test "Type.Union from empty regular enum" {
const E = enum {};
const U = @Union(.auto, E, &.{}, &.{}, &.{});
- try testing.expectEqual(@sizeOf(U), 0);
+ try testing.expectEqual(@typeInfo(U).@"union".fields.len, 0);
}
test "Type.Union from empty Type.Enum" {
const E = @Enum(u0, .exhaustive, &.{}, &.{});
const U = @Union(.auto, E, &.{}, &.{}, &.{});
- try testing.expectEqual(@sizeOf(U), 0);
+ try testing.expectEqual(@typeInfo(U).@"union".fields.len, 0);
}
test "Type.Fn" {
diff --git a/test/behavior/type_info.zig b/test/behavior/type_info.zig
index 48b10c458aa325007a6975dbf78373248d717ee3..cd1455e5235a5bacd1a783f2309a0c4fe30839bd 100644
--- a/test/behavior/type_info.zig
+++ b/test/behavior/type_info.zig
@@ -82,7 +82,7 @@ fn testPointer() !void {
try expect(u32_ptr_info.pointer.size == .one);
try expect(u32_ptr_info.pointer.is_const == false);
try expect(u32_ptr_info.pointer.is_volatile == false);
- try expect(u32_ptr_info.pointer.alignment == @alignOf(u32));
+ try expect(u32_ptr_info.pointer.alignment == null);
try expect(u32_ptr_info.pointer.child == u32);
try expect(u32_ptr_info.pointer.sentinel() == null);
}
@@ -99,7 +99,7 @@ fn testUnknownLenPtr() !void {
try expect(u32_ptr_info.pointer.is_const == true);
try expect(u32_ptr_info.pointer.is_volatile == true);
try expect(u32_ptr_info.pointer.sentinel() == null);
- try expect(u32_ptr_info.pointer.alignment == @alignOf(f64));
+ try expect(u32_ptr_info.pointer.alignment == null);
try expect(u32_ptr_info.pointer.child == f64);
}
@@ -130,7 +130,7 @@ fn testSlice() !void {
try expect(u32_slice_info.pointer.size == .slice);
try expect(u32_slice_info.pointer.is_const == false);
try expect(u32_slice_info.pointer.is_volatile == false);
- try expect(u32_slice_info.pointer.alignment == 4);
+ try expect(u32_slice_info.pointer.alignment == null);
try expect(u32_slice_info.pointer.child == u32);
}
@@ -266,9 +266,9 @@ fn testUnion() !void {
try expect(notag_union_info.@"union".tag_type == null);
try expect(notag_union_info.@"union".layout == .auto);
try expect(notag_union_info.@"union".fields.len == 2);
- try expect(notag_union_info.@"union".fields[0].alignment == @alignOf(void));
+ try expect(notag_union_info.@"union".fields[0].alignment == null);
try expect(notag_union_info.@"union".fields[1].type == u32);
- try expect(notag_union_info.@"union".fields[1].alignment == @alignOf(u32));
+ try expect(notag_union_info.@"union".fields[1].alignment == null);
const TestExternUnion = extern union {
foo: *anyopaque,
@@ -292,7 +292,7 @@ fn testStruct() !void {
const unpacked_struct_info = @typeInfo(TestStruct);
try expect(unpacked_struct_info.@"struct".is_tuple == false);
try expect(unpacked_struct_info.@"struct".backing_integer == null);
- try expect(unpacked_struct_info.@"struct".fields[0].alignment == @alignOf(u32));
+ try expect(unpacked_struct_info.@"struct".fields[0].alignment == null);
try expect(unpacked_struct_info.@"struct".fields[0].defaultValue().? == 4);
try expect(mem.eql(u8, "foobar", unpacked_struct_info.@"struct".fields[1].defaultValue().?));
}
@@ -314,11 +314,11 @@ fn testPackedStruct() !void {
try expect(struct_info.@"struct".layout == .@"packed");
try expect(struct_info.@"struct".backing_integer == u128);
try expect(struct_info.@"struct".fields.len == 4);
- try expect(struct_info.@"struct".fields[0].alignment == 0);
+ try expect(struct_info.@"struct".fields[0].alignment == null);
try expect(struct_info.@"struct".fields[2].type == f32);
try expect(struct_info.@"struct".fields[2].defaultValue() == null);
try expect(struct_info.@"struct".fields[3].defaultValue().? == 4);
- try expect(struct_info.@"struct".fields[3].alignment == 0);
+ try expect(struct_info.@"struct".fields[3].alignment == null);
try expect(struct_info.@"struct".decls.len == 1);
}
diff --git a/test/behavior/union.zig b/test/behavior/union.zig
index a9e950a255cc6036e75e6d6df584756b537b0ac9..faa3f42ea5f8f1415efdf5dcf2b887a0ba0066c4 100644
--- a/test/behavior/union.zig
+++ b/test/behavior/union.zig
@@ -148,6 +148,7 @@ const err = @as(anyerror!Agg, Agg{
const array = [_]Value{ v1, v2, v1, v2 };
test "unions embedded in aggregate types" {
+ if (builtin.zig_backend == .stage2_c and builtin.target.abi == .msvc) return error.SkipZigTest;
switch (array[1]) {
Value.Array => |arr| try expect(arr[4] == 3),
else => unreachable,
@@ -217,26 +218,6 @@ test "union with specified enum tag" {
try comptime doTest();
}
-test "packed union generates correctly aligned type" {
- // This test will be removed after the following accepted proposal is implemented:
- // https://github.com/ziglang/zig/issues/24657
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
-
- const U = packed union {
- f1: *const fn () error{TestUnexpectedResult}!void,
- f2: usize,
- };
- var foo = [_]U{
- U{ .f1 = doTest },
- U{ .f2 = 0 },
- };
- try foo[0].f1();
-}
-
fn doTest() error{TestUnexpectedResult}!void {
try expect((try bar(Payload{ .A = 1234 })) == -10);
}
@@ -359,12 +340,12 @@ test "simple union(enum(u32))" {
try expect(@intFromEnum(@as(Tag(MultipleChoice), x)) == 60);
}
-const PackedPtrOrInt = packed union {
- ptr: *u8,
- int: usize,
-};
test "packed union size" {
- comptime assert(@sizeOf(PackedPtrOrInt) == @sizeOf(usize));
+ const U = packed union {
+ signed: isize,
+ unsigned: usize,
+ };
+ comptime assert(@sizeOf(U) == @sizeOf(usize));
}
const ZeroBits = union {
@@ -703,25 +684,23 @@ test "union with only 1 field casted to its enum type which has enum value speci
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
const Literal = union(enum) {
- Number: f64,
- Bool: bool,
+ number: f64,
+ bool: bool,
};
- const ExprTag = enum(comptime_int) {
- Literal = 33,
- };
+ const ExprTag = enum(u32) { literal = 33 };
+ const Expr = union(ExprTag) { literal: Literal };
- const Expr = union(ExprTag) {
- Literal: Literal,
- };
+ comptime assert(Tag(ExprTag) == u32);
+
+ var e: Expr = undefined;
+ e = .{ .literal = .{ .bool = true } };
- var e = Expr{ .Literal = Literal{ .Bool = true } };
- _ = &e;
- comptime assert(Tag(ExprTag) == comptime_int);
- const t = comptime @as(ExprTag, e);
- try expect(t == Expr.Literal);
- try expect(@intFromEnum(t) == 33);
+ const t: ExprTag = e;
+ comptime assert(t == Expr.literal);
comptime assert(@intFromEnum(t) == 33);
+ try expect(t == Expr.literal);
+ try expect(@intFromEnum(t) == 33);
}
test "@intFromEnum works on unions" {
@@ -893,15 +872,6 @@ test "union no tag with struct member" {
u.foo();
}
-test "union with comptime_int tag" {
- const Union = union(enum(comptime_int)) {
- X: u32,
- Y: u16,
- Z: u8,
- };
- comptime assert(Tag(Tag(Union)) == comptime_int);
-}
-
test "extern union doesn't trigger field check at comptime" {
const U = extern union {
x: u32,
@@ -1031,7 +1001,7 @@ test "containers with single-field enums" {
try comptime S.doTheTest();
}
-test "@unionInit on union with tag but no fields" {
+test "@unionInit on union with u8 tag but no fields" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -1047,10 +1017,6 @@ test "@unionInit on union with tag but no fields" {
}
};
- comptime {
- assert(@sizeOf(Data) == 1);
- }
-
fn doTheTest() !void {
var data: Data = .{ .no_op = {} };
_ = &data;
@@ -2057,6 +2023,7 @@ test "runtime union init, most-aligned field != largest" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_c and builtin.target.abi == .msvc) return error.SkipZigTest;
const U = union(enum) {
x: u128,
diff --git a/test/c_abi/main.zig b/test/c_abi/main.zig
index 5d02e5e87dda46805e24dd64bb3e741dff161e60..218c75189e11ac0f9369ea8de3cf865766a8b7fe 100644
--- a/test/c_abi/main.zig
+++ b/test/c_abi/main.zig
@@ -718,7 +718,7 @@ export fn zig_med_struct_ints(s: MedStructInts) void {
expect(s.z == 3) catch @panic("test failure");
}
-const SmallPackedStruct = packed struct {
+const SmallPackedStruct = packed struct(u8) {
a: u2,
b: u2,
c: u2,
@@ -744,7 +744,7 @@ test "C ABI small packed struct" {
try expect(s2.d == 3);
}
-const BigPackedStruct = packed struct {
+const BigPackedStruct = packed struct(u128) {
a: u64,
b: u64,
};
diff --git a/test/cases/compile_errors/@import_zon_bad_type.zig b/test/cases/compile_errors/@import_zon_bad_type.zig
index 9fe3c887213b9f8972ee829c90f6c0e69fa6b53d..bcb1de5d4249cbdb50ba3ae7de4acb8395954602 100644
--- a/test/cases/compile_errors/@import_zon_bad_type.zig
+++ b/test/cases/compile_errors/@import_zon_bad_type.zig
@@ -116,13 +116,13 @@ export fn testMutablePointer() void {
// tmp.zig:85:26: note: ZON does not allow nested optionals
// tmp.zig:90:29: error: type '*i32' is not available in ZON
// tmp.zig:90:29: note: ZON does not allow mutable pointers
-// neg_inf.zon:1:1: error: expected type '@EnumLiteral()'
-// tmp.zig:37:38: note: imported here
// neg_inf.zon:1:1: error: expected type '?u8'
// tmp.zig:57:28: note: imported here
+// neg_inf.zon:1:1: error: expected type '@EnumLiteral()'
+// tmp.zig:37:38: note: imported here
// neg_inf.zon:1:1: error: expected type 'tmp.E'
// tmp.zig:63:26: note: imported here
-// neg_inf.zon:1:1: error: expected type 'tmp.U'
-// tmp.zig:69:26: note: imported here
// neg_inf.zon:1:1: error: expected type 'tmp.EU'
// tmp.zig:75:27: note: imported here
+// neg_inf.zon:1:1: error: expected type 'tmp.U'
+// tmp.zig:69:26: note: imported here
diff --git a/test/cases/compile_errors/@import_zon_opt_in_err.zig b/test/cases/compile_errors/@import_zon_opt_in_err.zig
index 29cf412eab32989359bd57ed259598865064337a..f975a3fa1e25d53facf9f2366dcfac1004387a95 100644
--- a/test/cases/compile_errors/@import_zon_opt_in_err.zig
+++ b/test/cases/compile_errors/@import_zon_opt_in_err.zig
@@ -58,25 +58,25 @@ export fn testVector() void {
// error
// imports=zon/vec2.zon
//
-// vec2.zon:1:2: error: expected type '?f32'
-// tmp.zig:2:29: note: imported here
// vec2.zon:1:2: error: expected type '*const ?f32'
// tmp.zig:7:36: note: imported here
// vec2.zon:1:2: error: expected type '?*const f32'
// tmp.zig:12:36: note: imported here
+// vec2.zon:1:2: error: expected type '?@EnumLiteral()'
+// tmp.zig:33:39: note: imported here
+// vec2.zon:1:2: error: expected type '?@Vector(3, f32)'
+// tmp.zig:54:41: note: imported here
+// vec2.zon:1:2: error: expected type '?[1]u8'
+// tmp.zig:38:31: note: imported here
+// vec2.zon:1:2: error: expected type '?[]const u8'
+// tmp.zig:49:36: note: imported here
// vec2.zon:1:2: error: expected type '?bool'
// tmp.zig:17:30: note: imported here
+// vec2.zon:1:2: error: expected type '?f32'
+// tmp.zig:2:29: note: imported here
// vec2.zon:1:2: error: expected type '?i32'
// tmp.zig:22:29: note: imported here
// vec2.zon:1:2: error: expected type '?tmp.Enum'
// tmp.zig:28:30: note: imported here
-// vec2.zon:1:2: error: expected type '?@EnumLiteral()'
-// tmp.zig:33:39: note: imported here
-// vec2.zon:1:2: error: expected type '?[1]u8'
-// tmp.zig:38:31: note: imported here
// vec2.zon:1:2: error: expected type '?tmp.Union'
// tmp.zig:44:31: note: imported here
-// vec2.zon:1:2: error: expected type '?[]const u8'
-// tmp.zig:49:36: note: imported here
-// vec2.zon:1:2: error: expected type '?@Vector(3, f32)'
-// tmp.zig:54:41: note: imported here
diff --git a/test/cases/compile_errors/@import_zon_opt_in_err_struct.zig b/test/cases/compile_errors/@import_zon_opt_in_err_struct.zig
index a284fd7c6dd6e2eac930fe48f74ad3fcff3d364a..a931f5a8cd305ae33bcc9e68ca296c74406134a7 100644
--- a/test/cases/compile_errors/@import_zon_opt_in_err_struct.zig
+++ b/test/cases/compile_errors/@import_zon_opt_in_err_struct.zig
@@ -13,7 +13,7 @@ export fn testTuple() void {
// error
// imports=zon/nan.zon
//
-//nan.zon:1:1: error: expected type '?tmp.Struct'
-//tmp.zig:3:32: note: imported here
-//nan.zon:1:1: error: expected type '?struct { bool }'
-//tmp.zig:9:31: note: imported here
+// nan.zon:1:1: error: expected type '?struct { bool }'
+// tmp.zig:9:31: note: imported here
+// nan.zon:1:1: error: expected type '?tmp.Struct'
+// tmp.zig:3:32: note: imported here
diff --git a/test/cases/compile_errors/@intFromPtr_with_bad_type.zig b/test/cases/compile_errors/@intFromPtr_with_bad_type.zig
deleted file mode 100644
index ec98c1bc14425d91c36a56735502cdefc5d0eba4..0000000000000000000000000000000000000000
--- a/test/cases/compile_errors/@intFromPtr_with_bad_type.zig
+++ /dev/null
@@ -1,9 +0,0 @@
-const x = 42;
-const y = @intFromPtr(&x);
-pub export fn entry() void {
- _ = y;
-}
-
-// error
-//
-// :2:23: error: comptime-only type 'comptime_int' has no pointer address
diff --git a/test/cases/compile_errors/AstGen_comptime_known_struct_is_resolved_before_error.zig b/test/cases/compile_errors/AstGen_comptime_known_struct_is_resolved_before_error.zig
deleted file mode 100644
index 03b4a425a547bf441f1c8195660699a88d7d3af2..0000000000000000000000000000000000000000
--- a/test/cases/compile_errors/AstGen_comptime_known_struct_is_resolved_before_error.zig
+++ /dev/null
@@ -1,17 +0,0 @@
-const S1 = struct {
- a: S2,
-};
-const S2 = struct {
- b: fn () void,
-};
-pub export fn entry() void {
- var s: S1 = undefined;
- _ = &s;
-}
-
-// error
-//
-// :8:12: error: variable of type 'tmp.S1' must be const or comptime
-// :2:8: note: struct requires comptime because of this field
-// :5:8: note: struct requires comptime because of this field
-// :5:8: note: use '*const fn () void' for a function pointer type
diff --git a/test/cases/compile_errors/C_pointer_pointing_to_non_C_ABI_compatible_type_or_has_align_attr.zig b/test/cases/compile_errors/C_pointer_pointing_to_non_C_ABI_compatible_type_or_has_align_attr.zig
deleted file mode 100644
index a578ebd84b758fb18e4f688982f917dc5639a0b1..0000000000000000000000000000000000000000
--- a/test/cases/compile_errors/C_pointer_pointing_to_non_C_ABI_compatible_type_or_has_align_attr.zig
+++ /dev/null
@@ -1,12 +0,0 @@
-const Foo = struct { a: u32 };
-export fn a() void {
- const T = [*c]Foo;
- const t: T = undefined;
- _ = t;
-}
-
-// error
-//
-// :3:19: error: C pointers cannot point to non-C-ABI-compatible type 'tmp.Foo'
-// :3:19: note: only extern structs and ABI sized packed structs are extern compatible
-// :1:13: note: struct declared here
diff --git a/test/cases/compile_errors/aggregate_too_large.zig b/test/cases/compile_errors/aggregate_too_large.zig
index 4a4daeda939c6711fd1dd31ece3ad396f838815c..ecab43d01109669047fc167d811df43456df0105 100644
--- a/test/cases/compile_errors/aggregate_too_large.zig
+++ b/test/cases/compile_errors/aggregate_too_large.zig
@@ -12,16 +12,14 @@ const U = union {
b: [1 << 32]u8,
};
-const V = union {
- a: u32,
- b: T,
-};
-
comptime {
- _ = S;
- _ = T;
- _ = U;
- _ = V;
+ _ = @as(S, undefined);
+}
+comptime {
+ _ = @as(T, undefined);
+}
+comptime {
+ _ = @as(U, undefined);
}
// error
diff --git a/test/cases/compile_errors/alignOf_bad_type.zig b/test/cases/compile_errors/alignOf_bad_type.zig
index 253adceb0547552ba531eb93a50f989d770a3b7c..4689fad821bd31e66f136101d1d1612c153ec9d0 100644
--- a/test/cases/compile_errors/alignOf_bad_type.zig
+++ b/test/cases/compile_errors/alignOf_bad_type.zig
@@ -1,7 +1,13 @@
-export fn entry() usize {
+export fn entry0() usize {
return @alignOf(noreturn);
}
+const S = struct { a: u32, b: noreturn };
+export fn entry1() usize {
+ return @alignOf(S);
+}
// error
//
-// :2:21: error: no align available for type 'noreturn'
+// :2:21: error: no align available for uninstantiable type 'noreturn'
+// :6:21: error: no align available for uninstantiable type 'tmp.S'
+// :4:11: note: struct declared here
diff --git a/test/cases/compile_errors/align_zero.zig b/test/cases/compile_errors/align_zero.zig
index 632d146dc5c44ce161c54a425c7755f8686ba3f2..7b68dee5e44e13cf94437d5c885f8831befa9f8f 100644
--- a/test/cases/compile_errors/align_zero.zig
+++ b/test/cases/compile_errors/align_zero.zig
@@ -30,11 +30,11 @@ export fn g() void {
}
export fn h() void {
- _ = struct { field: i32 align(0) };
+ _ = @as(struct { field: i32 align(0) }, undefined);
}
export fn i() void {
- _ = union { field: i32 align(0) };
+ _ = @as(union { field: i32 align(0) }, undefined);
}
export fn j() void {
@@ -54,7 +54,7 @@ export fn k() void {
// :20:30: error: alignment must be >= 1
// :25:16: error: alignment must be >= 1
// :29:17: error: alignment must be >= 1
-// :33:35: error: alignment must be >= 1
-// :37:34: error: alignment must be >= 1
+// :33:39: error: alignment must be >= 1
+// :37:38: error: alignment must be >= 1
// :41:51: error: alignment must be >= 1
// :45:25: error: alignment must be >= 1
diff --git a/test/cases/compile_errors/assign_inline_fn_to_non-comptime_var.zig b/test/cases/compile_errors/assign_inline_fn_to_non-comptime_var.zig
deleted file mode 100644
index ee666a028b1c633f35ae87e3de37ae0ff5126048..0000000000000000000000000000000000000000
--- a/test/cases/compile_errors/assign_inline_fn_to_non-comptime_var.zig
+++ /dev/null
@@ -1,10 +0,0 @@
-export fn entry() void {
- var a = &b;
- _ = &a;
-}
-inline fn b() void {}
-
-// error
-//
-// :2:9: error: variable of type '*const fn () callconv(.@"inline") void' must be const or comptime
-// :2:9: note: function has inline calling convention
diff --git a/test/cases/compile_errors/bit_ptr_non_packed.zig b/test/cases/compile_errors/bit_ptr_non_packed.zig
index 2b8190836906e8f6975d135d7bdce0452de2c90c..706dc12b9963168cd79d4fc474c4e73fe129dbcd 100644
--- a/test/cases/compile_errors/bit_ptr_non_packed.zig
+++ b/test/cases/compile_errors/bit_ptr_non_packed.zig
@@ -16,7 +16,11 @@ export fn entry3() void {
// error
//
// :3:23: error: bit-pointer cannot refer to value of type 'tmp.entry1.S'
-// :3:23: note: only packed structs layout are allowed in packed types
+// :3:23: note: non-packed structs do not have a bit-packed representation
+// :2:22: note: struct declared here
// :8:36: error: bit-pointer cannot refer to value of type 'tmp.entry2.S'
-// :8:36: note: only packed structs layout are allowed in packed types
+// :8:36: note: non-packed structs do not have a bit-packed representation
+// :7:15: note: struct declared here
// :13:23: error: bit-pointer cannot refer to value of type 'tmp.entry3.E'
+// :12:15: note: integer tag type of enum is inferred
+// :12:15: note: consider explicitly specifying the integer tag type
diff --git a/test/cases/compile_errors/bitsize_of_packed_struct_checks_backing_int_ty.zig b/test/cases/compile_errors/bitsize_of_packed_struct_checks_backing_int_ty.zig
index 9ee45b63565e0df5f6ceaa981c21f39578964ae4..f833ee08fe3056eb66d7d88feef4537a0a8a540e 100644
--- a/test/cases/compile_errors/bitsize_of_packed_struct_checks_backing_int_ty.zig
+++ b/test/cases/compile_errors/bitsize_of_packed_struct_checks_backing_int_ty.zig
@@ -8,4 +8,6 @@ pub export fn entry() void {
// error
//
-// :1:27: error: backing integer type 'u32' has bit size 32 but the struct fields have a total bit size of 1
+// :1:20: error: backing integer bit width does not match total bit width of fields
+// :1:27: note: backing integer 'u32' has bit width '32'
+// :1:20: note: struct fields have total bit width '1'
diff --git a/test/cases/compile_errors/c_pointer_to_void.zig b/test/cases/compile_errors/c_pointer_to_void.zig
deleted file mode 100644
index 4a532a22ae1f1e914bd669294bb90513f65e6dc5..0000000000000000000000000000000000000000
--- a/test/cases/compile_errors/c_pointer_to_void.zig
+++ /dev/null
@@ -1,9 +0,0 @@
-export fn entry() void {
- const a: [*c]void = undefined;
- _ = a;
-}
-
-// error
-//
-// :2:18: error: C pointers cannot point to non-C-ABI-compatible type 'void'
-// :2:18: note: 'void' is a zero bit type; for C 'void' use 'anyopaque'
diff --git a/test/cases/compile_errors/call_runtime_known_inline_fn_ptr.zig b/test/cases/compile_errors/call_runtime_known_inline_fn_ptr.zig
new file mode 100644
index 0000000000000000000000000000000000000000..635b169df01fdc2498c537160e47bdceea6e39cd
--- /dev/null
+++ b/test/cases/compile_errors/call_runtime_known_inline_fn_ptr.zig
@@ -0,0 +1,11 @@
+export fn entry() void {
+ var a = &b;
+ a = a;
+ a();
+}
+inline fn b() void {}
+
+// error
+//
+// :4:5: error: unable to resolve comptime value
+// :4:5: note: function being called inline must be comptime-known
diff --git a/test/cases/compile_errors/coerce_int_to_float.zig b/test/cases/compile_errors/coerce_int_to_float.zig
index bd167b36ad2b7a1947e23a1f422a7a7882b4220f..d1bf6eb2be077f38245412ee237a9c84f8291fbe 100644
--- a/test/cases/compile_errors/coerce_int_to_float.zig
+++ b/test/cases/compile_errors/coerce_int_to_float.zig
@@ -40,13 +40,13 @@ export fn entry() void {
// error
//
-// :6:20: error: expected type 'f16', found 'u12'
+// :6:20: error: expected type 'f128', found 'i115'
+// :6:20: error: expected type 'f128', found 'u114'
// :6:20: error: expected type 'f16', found 'i13'
-// :6:20: error: expected type 'f32', found 'u25'
+// :6:20: error: expected type 'f16', found 'u12'
// :6:20: error: expected type 'f32', found 'i26'
-// :6:20: error: expected type 'f64', found 'u54'
+// :6:20: error: expected type 'f32', found 'u25'
// :6:20: error: expected type 'f64', found 'i55'
-// :6:20: error: expected type 'f80', found 'u65'
+// :6:20: error: expected type 'f64', found 'u54'
// :6:20: error: expected type 'f80', found 'i66'
-// :6:20: error: expected type 'f128', found 'u114'
-// :6:20: error: expected type 'f128', found 'i115'
+// :6:20: error: expected type 'f80', found 'u65'
diff --git a/test/cases/compile_errors/comptime_var_referenced_by_type.zig b/test/cases/compile_errors/comptime_var_referenced_by_type.zig
index 1b476d9cdef1af9269ebe8ef4619dbf6a67e6bc9..62af2aed48b7446d40ede9c59864e50e1fe2f309 100644
--- a/test/cases/compile_errors/comptime_var_referenced_by_type.zig
+++ b/test/cases/compile_errors/comptime_var_referenced_by_type.zig
@@ -21,6 +21,6 @@ comptime {
// error
//
// :7:16: error: captured value contains reference to comptime var
-// :7:16: note: 'wrapper' points to '@as(*const tmp.Wrapper, @ptrCast(&v0)).*', where
+// :7:16: note: 'wrapper' points to 'v0', where
// :16:5: note: 'v0.ptr' points to comptime var declared here
// :17:29: note: called at comptime here
diff --git a/test/cases/compile_errors/direct_struct_loop.zig b/test/cases/compile_errors/direct_struct_loop.zig
index 4abd10da714e359a4b7561775df063c6e42bd1e6..e50867d36a943c4a7a7f121fa3ed86e5661ca49e 100644
--- a/test/cases/compile_errors/direct_struct_loop.zig
+++ b/test/cases/compile_errors/direct_struct_loop.zig
@@ -7,4 +7,4 @@ export fn entry() usize {
// error
//
-// :1:11: error: struct 'tmp.A' depends on itself
+// :2:8: error: type 'tmp.A' depends on itself for field declared here
diff --git a/test/cases/compile_errors/directly_embedding_opaque_type_in_struct_and_union.zig b/test/cases/compile_errors/directly_embedding_opaque_type_in_struct_and_union.zig
index 7c5085daf03627737f765638539c5c775bdfa732..ff3edd5fc96c339bbb84d1a981d4fead2e68a851 100644
--- a/test/cases/compile_errors/directly_embedding_opaque_type_in_struct_and_union.zig
+++ b/test/cases/compile_errors/directly_embedding_opaque_type_in_struct_and_union.zig
@@ -26,9 +26,11 @@ export fn d() void {
// error
//
-// :3:8: error: opaque types have unknown size and therefore cannot be directly embedded in structs
+// :3:8: error: cannot directly embed opaque type 'tmp.O' in struct
+// :3:8: note: opaque types have unknown size
// :1:11: note: opaque declared here
-// :7:10: error: opaque types have unknown size and therefore cannot be directly embedded in unions
+// :7:10: error: cannot directly embed opaque type 'tmp.O' in union
+// :7:10: note: opaque types have unknown size
// :1:11: note: opaque declared here
// :18:24: error: cannot cast to opaque type 'tmp.O'
// :1:11: note: opaque declared here
diff --git a/test/cases/compile_errors/empty_extern_union.zig b/test/cases/compile_errors/empty_extern_union.zig
new file mode 100644
index 0000000000000000000000000000000000000000..44d6269617ec06c17a97a544085070af52fa1e9d
--- /dev/null
+++ b/test/cases/compile_errors/empty_extern_union.zig
@@ -0,0 +1,8 @@
+export fn foo() void {
+ const U = extern union {};
+ _ = @as(U, undefined);
+}
+
+// error
+//
+// :2:22: error: extern union has no fields
diff --git a/test/cases/compile_errors/empty_packed_union.zig b/test/cases/compile_errors/empty_packed_union.zig
new file mode 100644
index 0000000000000000000000000000000000000000..87209670974eb706dd1385ba8e427944b5209278
--- /dev/null
+++ b/test/cases/compile_errors/empty_packed_union.zig
@@ -0,0 +1,8 @@
+export fn foo() void {
+ const U = packed union {};
+ _ = @as(U, undefined);
+}
+
+// error
+//
+// :2:22: error: packed union has no fields
diff --git a/test/cases/compile_errors/enum_backed_by_comptime_int.zig b/test/cases/compile_errors/enum_backed_by_comptime_int.zig
new file mode 100644
index 0000000000000000000000000000000000000000..069e36ecc4b6d321fd5f621e8875199b389be711
--- /dev/null
+++ b/test/cases/compile_errors/enum_backed_by_comptime_int.zig
@@ -0,0 +1,8 @@
+const E = enum(comptime_int) { a };
+comptime {
+ _ = E.a;
+}
+
+// error
+//
+// :1:16: error: expected integer tag type, found 'comptime_int'
diff --git a/test/cases/compile_errors/enum_backed_by_comptime_int_must_be_casted_from_comptime_value.zig b/test/cases/compile_errors/enum_backed_by_comptime_int_must_be_casted_from_comptime_value.zig
deleted file mode 100644
index a4ce1680ffd32acf2e0edde87dab93378099f57a..0000000000000000000000000000000000000000
--- a/test/cases/compile_errors/enum_backed_by_comptime_int_must_be_casted_from_comptime_value.zig
+++ /dev/null
@@ -1,12 +0,0 @@
-export fn entry() void {
- const Tag = enum(comptime_int) { a, b };
-
- var v: u32 = 0;
- _ = &v;
- _ = @as(Tag, @enumFromInt(v));
-}
-
-// error
-//
-// :6:31: error: unable to resolve comptime value
-// :6:31: note: value casted to enum with 'comptime_int' tag type must be comptime-known
diff --git a/test/cases/compile_errors/enum_backed_by_comptime_int_must_be_comptime.zig b/test/cases/compile_errors/enum_backed_by_comptime_int_must_be_comptime.zig
deleted file mode 100644
index 6f55e8c2779e5312647910553e4ffbadb8454c3c..0000000000000000000000000000000000000000
--- a/test/cases/compile_errors/enum_backed_by_comptime_int_must_be_comptime.zig
+++ /dev/null
@@ -1,9 +0,0 @@
-pub export fn entry() void {
- const E = enum(comptime_int) { a, b, c, _ };
- var e: E = .a;
- _ = &e;
-}
-
-// error
-//
-// :3:12: error: variable of type 'tmp.entry.E' must be const or comptime
diff --git a/test/cases/compile_errors/enum_field_value_references_enum.zig b/test/cases/compile_errors/enum_field_value_references_enum.zig
index 29150487089ec1e4f45f50080dec181d8dd72141..ba07e80bf8e058d273f9beb151059f8914aa118a 100644
--- a/test/cases/compile_errors/enum_field_value_references_enum.zig
+++ b/test/cases/compile_errors/enum_field_value_references_enum.zig
@@ -1,15 +1,11 @@
pub const Foo = enum(c_int) {
- A = Foo.B,
- C = D,
-
- pub const B = 0;
+ a = 10,
+ b = @intFromEnum(Foo.a) - 1,
};
export fn entry() void {
- const s: Foo = Foo.E;
- _ = s;
+ _ = @as(Foo, .a);
}
-const D = 1;
// error
//
-// :1:5: error: dependency loop detected
+// :3:25: error: type 'tmp.Foo' depends on itself for field usage here
diff --git a/test/cases/compile_errors/enum_field_value_references_nonexistent_circular.zig b/test/cases/compile_errors/enum_field_value_references_nonexistent_circular.zig
index d658876cf63ab6c11a1bbf6862f3e723681ec148..69b6111bbf98285ea7067260a4099e8cf00d4828 100644
--- a/test/cases/compile_errors/enum_field_value_references_nonexistent_circular.zig
+++ b/test/cases/compile_errors/enum_field_value_references_nonexistent_circular.zig
@@ -10,4 +10,4 @@ const D = 1;
// error
//
-// :1:5: error: dependency loop detected
+// :2:12: error: type 'tmp.Foo' depends on itself for field usage here
diff --git a/test/cases/compile_errors/enum_uses_own_typeinfo.zig b/test/cases/compile_errors/enum_uses_own_typeinfo.zig
new file mode 100644
index 0000000000000000000000000000000000000000..5906ba6bcb386e4f36bb1f7d343675e5ba8c248e
--- /dev/null
+++ b/test/cases/compile_errors/enum_uses_own_typeinfo.zig
@@ -0,0 +1,15 @@
+const E = enum(u9) {
+ const a_val: @typeInfo(E).@"enum".tag_type = 0;
+ a = a_val,
+};
+comptime {
+ _ = E.a;
+}
+
+// error
+//
+// error: dependency loop with length 3
+// :3:9: note: type 'tmp.E' uses value of declaration 'tmp.E.a_val' here
+// :2:50: note: value of declaration 'tmp.E.a_val' uses type of declaration 'tmp.E.a_val' here
+// :2:18: note: type of declaration 'tmp.E.a_val' depends on type 'tmp.E' for type information query here
+// note: eliminate any one of these dependencies to break the loop
diff --git a/test/cases/compile_errors/enum_value_already_taken.zig b/test/cases/compile_errors/enum_value_already_taken.zig
index 30e332b3be2cf931b2353f61efa9b57bfc997a4e..b83217ce788d97a32bbc6cdb3f7d58dc0f92d98e 100644
--- a/test/cases/compile_errors/enum_value_already_taken.zig
+++ b/test/cases/compile_errors/enum_value_already_taken.zig
@@ -12,5 +12,5 @@ export fn entry() void {
// error
//
-// :6:9: error: enum tag value 60 already taken
-// :4:9: note: other occurrence here
+// :6:9: error: enum tag value '60' for field 'E' already taken
+// :4:9: note: previous occurrence in field 'C'
diff --git a/test/cases/compile_errors/error_set_membership.zig b/test/cases/compile_errors/error_set_membership.zig
index 96c50a8ee6dc806a118431db096498af97e9547b..5caf26d46921cba6a2bbde4abc87da90ca6a4d50 100644
--- a/test/cases/compile_errors/error_set_membership.zig
+++ b/test/cases/compile_errors/error_set_membership.zig
@@ -26,5 +26,6 @@ pub fn main() Error!void {
// error
// target=x86_64-linux
//
-// :23:29: error: expected type 'error{InvalidCharacter}', found '@typeInfo(@typeInfo(@TypeOf(tmp.fooey)).@"fn".return_type.?).error_union.error_set'
+// :23:29: error: expected type 'error{InvalidCharacter}!void', found '@typeInfo(@typeInfo(@TypeOf(tmp.fooey)).@"fn".return_type.?).error_union.error_set'
// :23:29: note: 'error.InvalidDirection' not a member of destination error set
+// :22:20: note: function return type declared here
diff --git a/test/cases/compile_errors/exported_enum_without_explicit_integer_tag_type.zig b/test/cases/compile_errors/exported_enum_without_explicit_integer_tag_type.zig
index 3ff9961de81d96f945efd09d7eee724ca0bcaf2c..aa79ee1ad631d7658cd64346ad84d8fe531db306 100644
--- a/test/cases/compile_errors/exported_enum_without_explicit_integer_tag_type.zig
+++ b/test/cases/compile_errors/exported_enum_without_explicit_integer_tag_type.zig
@@ -11,6 +11,6 @@ comptime {
//
// :3:5: error: unable to export type 'type'
// :7:5: error: unable to export type 'tmp.E'
-// :7:5: note: enum tag type 'u1' is not extern compatible
-// :7:5: note: only integers with 0, 8, 16, 32, 64 and 128 bits are extern compatible
+// :1:11: note: integer tag type of enum is inferred
+// :1:11: note: consider explicitly specifying the integer tag type
// :1:11: note: enum declared here
diff --git a/test/cases/compile_errors/extern_struct_with_extern-compatible_but_inferred_integer_tag_type.zig b/test/cases/compile_errors/extern_struct_with_extern-compatible_but_inferred_integer_tag_type.zig
deleted file mode 100644
index a0e476f087629eb0e720a4f06e8db692d46508e6..0000000000000000000000000000000000000000
--- a/test/cases/compile_errors/extern_struct_with_extern-compatible_but_inferred_integer_tag_type.zig
+++ /dev/null
@@ -1,45 +0,0 @@
-// zig fmt: off
-pub const E = enum {
-@"0",@"1",@"2",@"3",@"4",@"5",@"6",@"7",@"8",@"9",@"10",@"11",@"12",
-@"13",@"14",@"15",@"16",@"17",@"18",@"19",@"20",@"21",@"22",@"23",
-@"24",@"25",@"26",@"27",@"28",@"29",@"30",@"31",@"32",@"33",@"34",
-@"35",@"36",@"37",@"38",@"39",@"40",@"41",@"42",@"43",@"44",@"45",
-@"46",@"47",@"48",@"49",@"50",@"51",@"52",@"53",@"54",@"55",@"56",
-@"57",@"58",@"59",@"60",@"61",@"62",@"63",@"64",@"65",@"66",@"67",
-@"68",@"69",@"70",@"71",@"72",@"73",@"74",@"75",@"76",@"77",@"78",
-@"79",@"80",@"81",@"82",@"83",@"84",@"85",@"86",@"87",@"88",@"89",
-@"90",@"91",@"92",@"93",@"94",@"95",@"96",@"97",@"98",@"99",@"100",
-@"101",@"102",@"103",@"104",@"105",@"106",@"107",@"108",@"109",
-@"110",@"111",@"112",@"113",@"114",@"115",@"116",@"117",@"118",
-@"119",@"120",@"121",@"122",@"123",@"124",@"125",@"126",@"127",
-@"128",@"129",@"130",@"131",@"132",@"133",@"134",@"135",@"136",
-@"137",@"138",@"139",@"140",@"141",@"142",@"143",@"144",@"145",
-@"146",@"147",@"148",@"149",@"150",@"151",@"152",@"153",@"154",
-@"155",@"156",@"157",@"158",@"159",@"160",@"161",@"162",@"163",
-@"164",@"165",@"166",@"167",@"168",@"169",@"170",@"171",@"172",
-@"173",@"174",@"175",@"176",@"177",@"178",@"179",@"180",@"181",
-@"182",@"183",@"184",@"185",@"186",@"187",@"188",@"189",@"190",
-@"191",@"192",@"193",@"194",@"195",@"196",@"197",@"198",@"199",
-@"200",@"201",@"202",@"203",@"204",@"205",@"206",@"207",@"208",
-@"209",@"210",@"211",@"212",@"213",@"214",@"215",@"216",@"217",
-@"218",@"219",@"220",@"221",@"222",@"223",@"224",@"225",@"226",
-@"227",@"228",@"229",@"230",@"231",@"232",@"233",@"234",@"235",
-@"236",@"237",@"238",@"239",@"240",@"241",@"242",@"243",@"244",
-@"245",@"246",@"247",@"248",@"249",@"250",@"251",@"252",@"253",
-@"254",@"255", @"256"
-};
-// zig fmt: on
-pub const S = extern struct {
- e: E,
-};
-export fn entry() void {
- const s: S = undefined;
- _ = s;
-}
-
-// error
-//
-// :33:8: error: extern structs cannot contain fields of type 'tmp.E'
-// :33:8: note: enum tag type 'u9' is not extern compatible
-// :33:8: note: only integers with 0 or power of two bits are extern compatible
-// :2:15: note: enum declared here
diff --git a/test/cases/compile_errors/extern_struct_with_non-extern-compatible_integer_tag_type.zig b/test/cases/compile_errors/extern_struct_with_non-extern-compatible_integer_tag_type.zig
index 373f10444d3ce322d0c3822a031461a74c2d97ed..fdf0f9aadd08021eb5a34367e80b93ade4ea1b3b 100644
--- a/test/cases/compile_errors/extern_struct_with_non-extern-compatible_integer_tag_type.zig
+++ b/test/cases/compile_errors/extern_struct_with_non-extern-compatible_integer_tag_type.zig
@@ -10,6 +10,6 @@ export fn entry() void {
// error
//
// :3:8: error: extern structs cannot contain fields of type 'tmp.E'
-// :3:8: note: enum tag type 'u31' is not extern compatible
-// :3:8: note: only integers with 0 or power of two bits are extern compatible
+// :1:15: note: enum tag type 'u31' is not extern compatible
+// :1:15: note: only integers with 0 or power of two bits are extern compatible
// :1:15: note: enum declared here
diff --git a/test/cases/compile_errors/fn_body_in_struct_runtime_known.zig b/test/cases/compile_errors/fn_body_in_struct_runtime_known.zig
new file mode 100644
index 0000000000000000000000000000000000000000..03b4a425a547bf441f1c8195660699a88d7d3af2
--- /dev/null
+++ b/test/cases/compile_errors/fn_body_in_struct_runtime_known.zig
@@ -0,0 +1,17 @@
+const S1 = struct {
+ a: S2,
+};
+const S2 = struct {
+ b: fn () void,
+};
+pub export fn entry() void {
+ var s: S1 = undefined;
+ _ = &s;
+}
+
+// error
+//
+// :8:12: error: variable of type 'tmp.S1' must be const or comptime
+// :2:8: note: struct requires comptime because of this field
+// :5:8: note: struct requires comptime because of this field
+// :5:8: note: use '*const fn () void' for a function pointer type
diff --git a/test/cases/compile_errors/fn_type_returning_pointer_to_itself.zig b/test/cases/compile_errors/fn_type_returning_pointer_to_itself.zig
new file mode 100644
index 0000000000000000000000000000000000000000..4afacccc8d813ddaa9a7cdd0e2641e4f6d492de0
--- /dev/null
+++ b/test/cases/compile_errors/fn_type_returning_pointer_to_itself.zig
@@ -0,0 +1,8 @@
+const MyFn = fn () ?*const MyFn;
+comptime {
+ _ = MyFn;
+}
+
+// error
+//
+// :1:28: error: value of declaration 'tmp.MyFn' depends on itself here
diff --git a/test/cases/compile_errors/function_ptr_alignment.zig b/test/cases/compile_errors/function_ptr_alignment.zig
index 66e80a95a6deaee73187dd3a4970685923d50a43..6396a08009a978d784698025616e9167eab397cf 100644
--- a/test/cases/compile_errors/function_ptr_alignment.zig
+++ b/test/cases/compile_errors/function_ptr_alignment.zig
@@ -11,5 +11,5 @@ comptime {
// error
// target=x86_64-linux
//
-// :8:41: error: expected type '*align(2) const fn () void', found '*const fn () void'
+// :8:41: error: expected type '*align(2) const fn () void', found '*align(1) const fn () void'
// :8:41: note: pointer alignment '1' cannot cast into pointer alignment '2'
diff --git a/test/cases/compile_errors/function_with_non-extern_non-packed_enum_parameter.zig b/test/cases/compile_errors/function_with_non-extern_non-packed_enum_parameter.zig
index 8122a89adc26bafa30189e9a3217b2e1dd19d372..ed9828c6921f5e46fc658d2857dc4f06f6971687 100644
--- a/test/cases/compile_errors/function_with_non-extern_non-packed_enum_parameter.zig
+++ b/test/cases/compile_errors/function_with_non-extern_non-packed_enum_parameter.zig
@@ -7,6 +7,6 @@ export fn entry(foo: Foo) void {
// target=x86_64-linux
//
// :2:17: error: parameter of type 'tmp.Foo' not allowed in function with calling convention 'x86_64_sysv'
-// :2:17: note: enum tag type 'u2' is not extern compatible
-// :2:17: note: only integers with 0, 8, 16, 32, 64 and 128 bits are extern compatible
+// :1:13: note: integer tag type of enum is inferred
+// :1:13: note: consider explicitly specifying the integer tag type
// :1:13: note: enum declared here
diff --git a/test/cases/compile_errors/function_with_non-extern_non-packed_struct_parameter.zig b/test/cases/compile_errors/function_with_non-extern_non-packed_struct_parameter.zig
index bb41a2ddb981ef7eaa99bc5b45ae0f6cb8c85a9e..d3e995734fe20899d04201fc0ca33bbd148c9a64 100644
--- a/test/cases/compile_errors/function_with_non-extern_non-packed_struct_parameter.zig
+++ b/test/cases/compile_errors/function_with_non-extern_non-packed_struct_parameter.zig
@@ -11,5 +11,5 @@ export fn entry(foo: Foo) void {
// target=x86_64-linux
//
// :6:17: error: parameter of type 'tmp.Foo' not allowed in function with calling convention 'x86_64_sysv'
-// :6:17: note: only extern structs and ABI sized packed structs are extern compatible
+// :6:17: note: struct with automatic layout has no guaranteed in-memory representation
// :1:13: note: struct declared here
diff --git a/test/cases/compile_errors/function_with_non-extern_non-packed_union_parameter.zig b/test/cases/compile_errors/function_with_non-extern_non-packed_union_parameter.zig
index 220dbd146d714e4697264b627476f3cb77cbf543..e02e072aa05cf25c432637ee602eda0f975feec0 100644
--- a/test/cases/compile_errors/function_with_non-extern_non-packed_union_parameter.zig
+++ b/test/cases/compile_errors/function_with_non-extern_non-packed_union_parameter.zig
@@ -11,5 +11,5 @@ export fn entry(foo: Foo) void {
// target=x86_64-linux
//
// :6:17: error: parameter of type 'tmp.Foo' not allowed in function with calling convention 'x86_64_sysv'
-// :6:17: note: only extern unions and ABI sized packed unions are extern compatible
+// :6:17: note: union with automatic layout has no guaranteed in-memory representation
// :1:13: note: union declared here
diff --git a/test/cases/compile_errors/generic_function_returning_opaque_type.zig b/test/cases/compile_errors/generic_function_returning_opaque_type.zig
index 78ffde8961669985cf82192137bab6048197d6db..b3f4b757e1c43c7b9af8692452b283acde889992 100644
--- a/test/cases/compile_errors/generic_function_returning_opaque_type.zig
+++ b/test/cases/compile_errors/generic_function_returning_opaque_type.zig
@@ -11,6 +11,6 @@ export fn bar() void {
// error
//
+// :1:30: error: opaque return type 'anyopaque' not allowed
// :1:30: error: opaque return type 'tmp.MyOpaque' not allowed
// :4:18: note: opaque declared here
-// :1:30: error: opaque return type 'anyopaque' not allowed
diff --git a/test/cases/compile_errors/implicit_backing_type_in_extern_context.zig b/test/cases/compile_errors/implicit_backing_type_in_extern_context.zig
new file mode 100644
index 0000000000000000000000000000000000000000..5d1b8e75ae054a60dbccb25435130acbfe6039f8
--- /dev/null
+++ b/test/cases/compile_errors/implicit_backing_type_in_extern_context.zig
@@ -0,0 +1,51 @@
+const PackedStruct = packed struct { x: u32 };
+const PackedUnion = packed union { x: u32 };
+
+/// This enum has 256 fields, so `u8` will be its inferred tag type.
+const Enum = enum {
+ // zig fmt: off
+ _00, _01, _02, _03, _04, _05, _06, _07, _08, _09, _0a, _0b, _0c, _0d, _0e, _0f,
+ _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _1a, _1b, _1c, _1d, _1e, _1f,
+ _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _2a, _2b, _2c, _2d, _2e, _2f,
+ _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _3a, _3b, _3c, _3d, _3e, _3f,
+ _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _4a, _4b, _4c, _4d, _4e, _4f,
+ _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _5a, _5b, _5c, _5d, _5e, _5f,
+ _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _6a, _6b, _6c, _6d, _6e, _6f,
+ _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _7a, _7b, _7c, _7d, _7e, _7f,
+ _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _8a, _8b, _8c, _8d, _8e, _8f,
+ _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _9a, _9b, _9c, _9d, _9e, _9f,
+ _a0, _a1, _a2, _a3, _a4, _a5, _a6, _a7, _a8, _a9, _aa, _ab, _ac, _ad, _ae, _af,
+ _b0, _b1, _b2, _b3, _b4, _b5, _b6, _b7, _b8, _b9, _ba, _bb, _bc, _bd, _be, _bf,
+ _c0, _c1, _c2, _c3, _c4, _c5, _c6, _c7, _c8, _c9, _ca, _cb, _cc, _cd, _ce, _cf,
+ _d0, _d1, _d2, _d3, _d4, _d5, _d6, _d7, _d8, _d9, _da, _db, _dc, _dd, _de, _df,
+ _e0, _e1, _e2, _e3, _e4, _e5, _e6, _e7, _e8, _e9, _ea, _eb, _ec, _ed, _ee, _ef,
+ _f0, _f1, _f2, _f3, _f4, _f5, _f6, _f7, _f8, _f9, _fa, _fb, _fc, _fd, _fe, _ff,
+ // zig fmt: on
+};
+
+const Extern0 = extern struct { val: PackedStruct };
+const Extern1 = extern struct { val: PackedUnion };
+const Extern2 = extern struct { val: Enum };
+
+comptime {
+ _ = @as(Extern0, undefined);
+}
+comptime {
+ _ = @as(Extern1, undefined);
+}
+comptime {
+ _ = @as(Extern2, undefined);
+}
+
+// error
+//
+// :26:38: error: extern structs cannot contain fields of type 'tmp.PackedStruct'
+// :26:38: note: inferred backing integer of packed struct has unspecified signedness
+// :1:29: note: struct declared here
+// :27:38: error: extern structs cannot contain fields of type 'tmp.PackedUnion'
+// :27:38: note: inferred backing integer of packed union has unspecified signedness
+// :2:28: note: union declared here
+// :28:38: error: extern structs cannot contain fields of type 'tmp.Enum'
+// :5:14: note: integer tag type of enum is inferred
+// :5:14: note: consider explicitly specifying the integer tag type
+// :5:14: note: enum declared here
diff --git a/test/cases/compile_errors/indexing_an_array_of_size_zero.zig b/test/cases/compile_errors/indexing_an_array_of_size_zero.zig
index 356425d8152c2d9847eeceaaa6f50fd9264fe246..92ded154c130014da0ab0206c44c260c63a448ab 100644
--- a/test/cases/compile_errors/indexing_an_array_of_size_zero.zig
+++ b/test/cases/compile_errors/indexing_an_array_of_size_zero.zig
@@ -6,4 +6,4 @@ export fn foo() void {
// error
//
-// :3:27: error: indexing into empty array is not allowed
+// :3:27: error: cannot index into empty array
diff --git a/test/cases/compile_errors/indexing_an_array_of_size_zero_with_runtime_index.zig b/test/cases/compile_errors/indexing_an_array_of_size_zero_with_runtime_index.zig
index 29d522aad96879fbaf79b175baf2408c76b50da2..b06b7bed554c13518c9a277557477f87ba630333 100644
--- a/test/cases/compile_errors/indexing_an_array_of_size_zero_with_runtime_index.zig
+++ b/test/cases/compile_errors/indexing_an_array_of_size_zero_with_runtime_index.zig
@@ -8,4 +8,4 @@ export fn foo() void {
// error
//
-// :5:27: error: indexing into empty array is not allowed
+// :5:27: error: cannot index into empty array
diff --git a/test/cases/compile_errors/indirect_struct_loop.zig b/test/cases/compile_errors/indirect_struct_loop.zig
index 7975ecddf5716171d803cc2549b7a59e4b864521..ac85a64a0c64ae17a78621f6b22bc8efd3c25c97 100644
--- a/test/cases/compile_errors/indirect_struct_loop.zig
+++ b/test/cases/compile_errors/indirect_struct_loop.zig
@@ -13,4 +13,8 @@ export fn entry() usize {
// error
//
-// :1:11: error: struct 'tmp.A' depends on itself
+// error: dependency loop with length 3
+// :2:8: note: type 'tmp.A' depends on type 'tmp.B' for field declared here
+// :5:8: note: type 'tmp.B' depends on type 'tmp.C' for field declared here
+// :8:8: note: type 'tmp.C' depends on type 'tmp.A' for field declared here
+// note: eliminate any one of these dependencies to break the loop
diff --git a/test/cases/compile_errors/initialize_empty_union.zig b/test/cases/compile_errors/initialize_empty_union.zig
new file mode 100644
index 0000000000000000000000000000000000000000..2847446b2516a1eb4f968a8bb31b24abc7bd132d
--- /dev/null
+++ b/test/cases/compile_errors/initialize_empty_union.zig
@@ -0,0 +1,81 @@
+const EnumInferred = enum {};
+const EnumExplicit = enum(u8) {};
+const EnumNonexhaustive = enum(u8) { _ };
+
+const U0 = union {};
+const U1 = union(enum) {};
+const U2 = union(enum(u8)) {};
+const U3 = union(EnumInferred) {};
+const U4 = union(EnumExplicit) {};
+const U5 = union(EnumNonexhaustive) {};
+
+export fn init0() void {
+ _ = @as(U0, undefined);
+}
+export fn init1() void {
+ _ = @as(U1, undefined);
+}
+export fn init2() void {
+ _ = @as(U2, undefined);
+}
+export fn init3() void {
+ _ = @as(U3, undefined);
+}
+export fn init4() void {
+ _ = @as(U4, undefined);
+}
+export fn init5() void {
+ _ = @as(U5, undefined);
+}
+
+export fn deref0(ptr: *const U0) void {
+ _ = ptr.*;
+}
+export fn deref1(ptr: *const U1) void {
+ _ = ptr.*;
+}
+export fn deref2(ptr: *const U2) void {
+ _ = ptr.*;
+}
+export fn deref3(ptr: *const U3) void {
+ _ = ptr.*;
+}
+export fn deref4(ptr: *const U4) void {
+ _ = ptr.*;
+}
+export fn deref5(ptr: *const U5) void {
+ _ = ptr.*;
+}
+
+// error
+//
+// :13:17: error: expected type 'tmp.U0', found '@TypeOf(undefined)'
+// :13:17: note: cannot coerce to uninstantiable type 'tmp.U0'
+// :5:12: note: union declared here
+// :16:17: error: expected type 'tmp.U1', found '@TypeOf(undefined)'
+// :16:17: note: cannot coerce to uninstantiable type 'tmp.U1'
+// :6:12: note: union declared here
+// :19:17: error: expected type 'tmp.U2', found '@TypeOf(undefined)'
+// :19:17: note: cannot coerce to uninstantiable type 'tmp.U2'
+// :7:12: note: union declared here
+// :22:17: error: expected type 'tmp.U3', found '@TypeOf(undefined)'
+// :22:17: note: cannot coerce to uninstantiable type 'tmp.U3'
+// :8:12: note: union declared here
+// :25:17: error: expected type 'tmp.U4', found '@TypeOf(undefined)'
+// :25:17: note: cannot coerce to uninstantiable type 'tmp.U4'
+// :9:12: note: union declared here
+// :28:17: error: expected type 'tmp.U5', found '@TypeOf(undefined)'
+// :28:17: note: cannot coerce to uninstantiable type 'tmp.U5'
+// :10:12: note: union declared here
+// :32:12: error: cannot load uninstantiable type 'tmp.U0'
+// :5:12: note: union declared here
+// :35:12: error: cannot load uninstantiable type 'tmp.U1'
+// :6:12: note: union declared here
+// :38:12: error: cannot load uninstantiable type 'tmp.U2'
+// :7:12: note: union declared here
+// :41:12: error: cannot load uninstantiable type 'tmp.U3'
+// :8:12: note: union declared here
+// :44:12: error: cannot load uninstantiable type 'tmp.U4'
+// :9:12: note: union declared here
+// :47:12: error: cannot load uninstantiable type 'tmp.U5'
+// :10:12: note: union declared here
diff --git a/test/cases/compile_errors/instantiating_an_undefined_value_for_an_invalid_struct_that_contains_itself.zig b/test/cases/compile_errors/instantiating_an_undefined_value_for_an_invalid_struct_that_contains_itself.zig
index 5507dbc34e3d8243162cab38e7b9606d3856daa1..2e602ee6a6dd7d8bba15f763709350c3530bd325 100644
--- a/test/cases/compile_errors/instantiating_an_undefined_value_for_an_invalid_struct_that_contains_itself.zig
+++ b/test/cases/compile_errors/instantiating_an_undefined_value_for_an_invalid_struct_that_contains_itself.zig
@@ -10,4 +10,4 @@ export fn entry() usize {
// error
//
-// :1:13: error: struct 'tmp.Foo' depends on itself
+// :2:8: error: type 'tmp.Foo' depends on itself for field declared here
diff --git a/test/cases/compile_errors/instantiating_an_undefined_value_for_an_invalid_union_that_contains_itself.zig b/test/cases/compile_errors/instantiating_an_undefined_value_for_an_invalid_union_that_contains_itself.zig
index 9886c42bae362bbcdab8c490dfae04c0f0d4d86a..c503c0b3da6b991a661023701dfef7e09a05580a 100644
--- a/test/cases/compile_errors/instantiating_an_undefined_value_for_an_invalid_union_that_contains_itself.zig
+++ b/test/cases/compile_errors/instantiating_an_undefined_value_for_an_invalid_union_that_contains_itself.zig
@@ -10,4 +10,4 @@ export fn entry() usize {
// error
//
-// :1:13: error: union 'tmp.Foo' depends on itself
+// :2:8: error: type 'tmp.Foo' depends on itself for field declared here
diff --git a/test/cases/compile_errors/invalid_dependency_on_struct_size.zig b/test/cases/compile_errors/invalid_dependency_on_struct_size.zig
index 14cd363a1426188858d321d616f299e2e3607dc8..39fc37ab3e5520d1224cc83b08e9f27afb09d738 100644
--- a/test/cases/compile_errors/invalid_dependency_on_struct_size.zig
+++ b/test/cases/compile_errors/invalid_dependency_on_struct_size.zig
@@ -1,16 +1,18 @@
+const S = struct {
+ const Foo = struct {
+ y: Bar,
+ };
+ const Bar = struct {
+ y: if (@sizeOf(Foo) == 0) u64 else void,
+ };
+};
comptime {
- const S = struct {
- const Foo = struct {
- y: Bar,
- };
- const Bar = struct {
- y: if (@sizeOf(Foo) == 0) u64 else void,
- };
- };
-
_ = @sizeOf(S.Foo) + 1;
}
// error
//
-// :6:21: error: struct layout depends on it having runtime bits
+// error: dependency loop with length 2
+// :3:12: note: type 'tmp.S.Foo' depends on type 'tmp.S.Bar' for field declared here
+// :6:24: note: type 'tmp.S.Bar' depends on type 'tmp.S.Foo' for size query here
+// note: eliminate any one of these dependencies to break the loop
diff --git a/test/cases/compile_errors/invalid_optional_type_in_extern_struct.zig b/test/cases/compile_errors/invalid_optional_type_in_extern_struct.zig
index 68d4603a4af51511417c417fe42be863c343e0f0..dfb497660015537a2d05a877430f776df61331a6 100644
--- a/test/cases/compile_errors/invalid_optional_type_in_extern_struct.zig
+++ b/test/cases/compile_errors/invalid_optional_type_in_extern_struct.zig
@@ -2,10 +2,10 @@ const stroo = extern struct {
moo: ?[*c]u8,
};
export fn testf(fluff: *stroo) void {
- _ = fluff;
+ _ = fluff.*;
}
// error
//
// :2:10: error: extern structs cannot contain fields of type '?[*c]u8'
-// :2:10: note: only pointer like optionals are extern compatible
+// :2:10: note: non-pointer optionals have no guaranteed in-memory representation
diff --git a/test/cases/compile_errors/invalid_pointer_arithmetic.zig b/test/cases/compile_errors/invalid_pointer_arithmetic.zig
index a571d5d4c2771a1931d7ca4eb29cdfb399caad06..e590087dffdba353d60d60c36247978100045687 100644
--- a/test/cases/compile_errors/invalid_pointer_arithmetic.zig
+++ b/test/cases/compile_errors/invalid_pointer_arithmetic.zig
@@ -26,11 +26,6 @@ comptime {
_ = x - y;
}
-comptime {
- const x: [*]u0 = @ptrFromInt(1);
- _ = x + 1;
-}
-
comptime {
const x: *u0 = @ptrFromInt(1);
const y: *u0 = @ptrFromInt(2);
@@ -46,5 +41,4 @@ comptime {
// :12:11: error: invalid operands to binary expression: 'pointer' and 'pointer'
// :20:11: error: incompatible pointer arithmetic operands '[*]u8' and '[*]u16'
// :26:11: error: incompatible pointer arithmetic operands '*u8' and '*u16'
-// :31:11: error: pointer arithmetic requires element type 'u0' to have runtime bits
-// :37:11: error: pointer arithmetic requires element type 'u0' to have runtime bits
+// :32:11: error: pointer subtraction requires element type 'u0' to have runtime bits
diff --git a/test/cases/compile_errors/invalid_type_in_builtin_extern.zig b/test/cases/compile_errors/invalid_type_in_builtin_extern.zig
index 5528c9c7132f197b9e702a7029c50bd49166be9f..444ab528b337a85ec6b776c37e15b8c513d7f3ea 100644
--- a/test/cases/compile_errors/invalid_type_in_builtin_extern.zig
+++ b/test/cases/compile_errors/invalid_type_in_builtin_extern.zig
@@ -1,16 +1,22 @@
const x = @extern(*comptime_int, .{ .name = "foo" });
const y = @extern(*fn (u8) u8, .{ .name = "bar" });
-pub export fn entry() void {
+const z = @extern(*fn (u8) callconv(.c) u8, .{ .name = "bar" });
+comptime {
_ = x;
}
-pub export fn entry2() void {
+comptime {
_ = y;
}
+comptime {
+ _ = z;
+}
// error
//
// :1:19: error: extern symbol cannot have type '*comptime_int'
-// :1:19: note: pointer to comptime-only type 'comptime_int'
+// :1:19: note: pointer element type 'comptime_int' is not extern compatible
// :2:19: error: extern symbol cannot have type '*fn (u8) u8'
-// :2:19: note: pointer to extern function must be 'const'
+// :2:19: note: pointer element type 'fn (u8) u8' is not extern compatible
// :2:19: note: extern function must specify calling convention
+// :3:19: error: extern symbol cannot have type '*fn (u8) callconv(.c) u8'
+// :3:19: note: pointer to extern function must be 'const'
diff --git a/test/cases/compile_errors/non-const_variables_of_things_that_require_const_variables.zig b/test/cases/compile_errors/non-const_variables_of_things_that_require_const_variables.zig
index 373ac8e2d92f1bd5e18a14f324e374bfae90337c..66fb6c6cec77ea4423874ca288abba11737c3a67 100644
--- a/test/cases/compile_errors/non-const_variables_of_things_that_require_const_variables.zig
+++ b/test/cases/compile_errors/non-const_variables_of_things_that_require_const_variables.zig
@@ -1,49 +1,44 @@
-export fn entry1() void {
- var m2 = &2;
- _ = &m2;
-}
-export fn entry2() void {
+export fn entry0() void {
var a = undefined;
_ = &a;
}
-export fn entry3() void {
+export fn entry1() void {
var b = 1;
_ = &b;
}
-export fn entry4() void {
+export fn entry2() void {
var c = 1.0;
_ = &c;
}
-export fn entry5() void {
+export fn entry3() void {
var d = null;
_ = &d;
}
-export fn entry6(opaque_: *Opaque) void {
+export fn entry4(opaque_: *Opaque) void {
var e = opaque_.*;
_ = &e;
}
-export fn entry7() void {
+export fn entry5() void {
var f = i32;
_ = &f;
}
const Opaque = opaque {};
-export fn entry8() void {
+export fn entry6() void {
var e: Opaque = undefined;
_ = &e;
}
// error
//
-// :2:9: error: variable of type '*const comptime_int' must be const or comptime
-// :6:9: error: variable of type '@TypeOf(undefined)' must be const or comptime
-// :10:9: error: variable of type 'comptime_int' must be const or comptime
+// :2:9: error: variable of type '@TypeOf(undefined)' must be const or comptime
+// :6:9: error: variable of type 'comptime_int' must be const or comptime
+// :6:9: note: to modify this variable at runtime, it must be given an explicit fixed-size number type
+// :10:9: error: variable of type 'comptime_float' must be const or comptime
// :10:9: note: to modify this variable at runtime, it must be given an explicit fixed-size number type
-// :14:9: error: variable of type 'comptime_float' must be const or comptime
-// :14:9: note: to modify this variable at runtime, it must be given an explicit fixed-size number type
-// :18:9: error: variable of type '@TypeOf(null)' must be const or comptime
-// :22:20: error: cannot load opaque type 'tmp.Opaque'
-// :29:16: note: opaque declared here
-// :26:9: error: variable of type 'type' must be const or comptime
-// :26:9: note: types are not available at runtime
-// :31:12: error: non-extern variable with opaque type 'tmp.Opaque'
-// :29:16: note: opaque declared here
+// :14:9: error: variable of type '@TypeOf(null)' must be const or comptime
+// :18:20: error: cannot load opaque type 'tmp.Opaque'
+// :25:16: note: opaque declared here
+// :22:9: error: variable of type 'type' must be const or comptime
+// :22:9: note: types are not available at runtime
+// :27:12: error: non-extern variable with opaque type 'tmp.Opaque'
+// :25:16: note: opaque declared here
diff --git a/test/cases/compile_errors/non-exhaustive_enum_marker_assigned_a_value.zig b/test/cases/compile_errors/non-exhaustive_enum_marker_assigned_a_value.zig
index bd659f8e32a2808cdfe63c4d987443aac7925ee0..01b999e924a65cf53a064d375f4ca52ee2c8386b 100644
--- a/test/cases/compile_errors/non-exhaustive_enum_marker_assigned_a_value.zig
+++ b/test/cases/compile_errors/non-exhaustive_enum_marker_assigned_a_value.zig
@@ -3,18 +3,7 @@ const A = enum {
b,
_ = 1,
};
-const B = enum {
- a,
- b,
- _,
-};
-comptime {
- _ = A;
- _ = B;
-}
// error
//
// :4:9: error: '_' is used to mark an enum as non-exhaustive and cannot be assigned a value
-// :6:11: error: non-exhaustive enum missing integer tag type
-// :9:5: note: marked non-exhaustive here
diff --git a/test/cases/compile_errors/non-exhaustive_enum_missing_tag_type.zig b/test/cases/compile_errors/non-exhaustive_enum_missing_tag_type.zig
new file mode 100644
index 0000000000000000000000000000000000000000..fa0b9d432dd65bf8203dd39cbadcad909b8024ed
--- /dev/null
+++ b/test/cases/compile_errors/non-exhaustive_enum_missing_tag_type.zig
@@ -0,0 +1,10 @@
+const E = enum {
+ a,
+ b,
+ _,
+};
+
+// error
+//
+// :1:11: error: non-exhaustive enum missing integer tag type
+// :4:5: note: marked non-exhaustive here
diff --git a/test/cases/compile_errors/non-exhaustive_enum_specifies_every_value.zig b/test/cases/compile_errors/non-exhaustive_enum_specifies_every_value.zig
index 8adaac649f2297ece6a93388a80c7e4e779800b7..6c4902ba5c2733d12efeed907309bbc0a1d15547 100644
--- a/test/cases/compile_errors/non-exhaustive_enum_specifies_every_value.zig
+++ b/test/cases/compile_errors/non-exhaustive_enum_specifies_every_value.zig
@@ -4,7 +4,7 @@ const C = enum(u1) {
_,
};
pub export fn entry() void {
- _ = C;
+ _ = C.a;
}
// error
diff --git a/test/cases/compile_errors/non-inline_for_loop_on_a_type_that_requires_comptime.zig b/test/cases/compile_errors/non-inline_for_loop_on_a_type_that_requires_comptime.zig
index adb6583757e58518f1200100d504eebbcb9259b4..a895c263a0e2acd38c343166cd9afbb65e569ac5 100644
--- a/test/cases/compile_errors/non-inline_for_loop_on_a_type_that_requires_comptime.zig
+++ b/test/cases/compile_errors/non-inline_for_loop_on_a_type_that_requires_comptime.zig
@@ -11,6 +11,6 @@ export fn entry() void {
// error
//
-// :7:10: error: values of type '[2]tmp.Foo' must be comptime-known, but index value is runtime-known
+// :7:10: error: values of type 'tmp.Foo' must be comptime-known, but index value is runtime-known
// :3:8: note: struct requires comptime because of this field
// :3:8: note: types are not available at runtime
diff --git a/test/cases/compile_errors/non_constant_expression_in_array_size.zig b/test/cases/compile_errors/non_constant_expression_in_array_size.zig
index 0f64e1263b2e2475c8335c0a0ae333a987ce4ca0..6b344ba4a1d6a3abc7e7bc36d7fc895a5dc73d01 100644
--- a/test/cases/compile_errors/non_constant_expression_in_array_size.zig
+++ b/test/cases/compile_errors/non_constant_expression_in_array_size.zig
@@ -14,4 +14,4 @@ export fn entry() usize {
//
// :6:12: error: unable to resolve comptime value
// :2:12: note: called at comptime from here
-// :1:13: note: types must be comptime-known
+// :2:8: note: struct field types must be comptime-known
diff --git a/test/cases/compile_errors/noreturn_struct_field.zig b/test/cases/compile_errors/noreturn_struct_field.zig
deleted file mode 100644
index 8a68496bdedc29169071432fa7af33410c1c33fa..0000000000000000000000000000000000000000
--- a/test/cases/compile_errors/noreturn_struct_field.zig
+++ /dev/null
@@ -1,10 +0,0 @@
-const S = struct {
- s: noreturn,
-};
-comptime {
- _ = @typeInfo(S);
-}
-
-// error
-//
-// :2:8: error: struct fields cannot be 'noreturn'
diff --git a/test/cases/compile_errors/old_fn_ptr_in_extern_context.zig b/test/cases/compile_errors/old_fn_ptr_in_extern_context.zig
index 701636e7636541cb7e54d1b50107ab83f6dd71c6..85ff0539804cdcb553dfe521aa6f908148ecdb82 100644
--- a/test/cases/compile_errors/old_fn_ptr_in_extern_context.zig
+++ b/test/cases/compile_errors/old_fn_ptr_in_extern_context.zig
@@ -4,15 +4,9 @@ const S = extern struct {
comptime {
_ = @sizeOf(S) == 1;
}
-comptime {
- _ = [*c][4]fn () callconv(.c) void;
-}
// error
//
// :2:8: error: extern structs cannot contain fields of type 'fn () callconv(.c) void'
// :2:8: note: type has no guaranteed in-memory representation
// :2:8: note: use '*const ' to make a function pointer type
-// :8:13: error: C pointers cannot point to non-C-ABI-compatible type '[4]fn () callconv(.c) void'
-// :8:13: note: type has no guaranteed in-memory representation
-// :8:13: note: use '*const ' to make a function pointer type
diff --git a/test/cases/compile_errors/overflow_in_enum_value_allocation.zig b/test/cases/compile_errors/overflow_in_enum_value_allocation.zig
index 35f3c193dfe343fdc387c972f7fb145af8f4190d..fdf2cf4efb9ca5f02199f071ffe9550b597ac45f 100644
--- a/test/cases/compile_errors/overflow_in_enum_value_allocation.zig
+++ b/test/cases/compile_errors/overflow_in_enum_value_allocation.zig
@@ -9,4 +9,4 @@ pub export fn entry() void {
// error
//
-// :3:5: error: enumeration value '256' too large for type 'u8'
+// :3:5: error: enum tag value '256' too large for type 'u8'
diff --git a/test/cases/compile_errors/packed_struct_backing_int_wrong.zig b/test/cases/compile_errors/packed_struct_backing_int_wrong.zig
index 25872cbf7e8c975e74cfb3760f8faa382024eedc..5fa4f258d53e2d92c861f312e97e8bee68f866ff 100644
--- a/test/cases/compile_errors/packed_struct_backing_int_wrong.zig
+++ b/test/cases/compile_errors/packed_struct_backing_int_wrong.zig
@@ -44,8 +44,12 @@ export fn entry7() void {
// error
//
-// :2:31: error: backing integer type 'u32' has bit size 32 but the struct fields have a total bit size of 29
-// :9:31: error: backing integer type 'i31' has bit size 31 but the struct fields have a total bit size of 32
+// :2:24: error: backing integer bit width does not match total bit width of fields
+// :2:31: note: backing integer 'u32' has bit width '32'
+// :2:24: note: struct fields have total bit width '29'
+// :9:24: error: backing integer bit width does not match total bit width of fields
+// :9:31: note: backing integer 'i31' has bit width '31'
+// :9:24: note: struct fields have total bit width '32'
// :17:31: error: expected backing integer type, found 'void'
// :23:31: error: expected backing integer type, found 'void'
// :27:31: error: expected backing integer type, found 'noreturn'
diff --git a/test/cases/compile_errors/packed_struct_uses_own_size.zig b/test/cases/compile_errors/packed_struct_uses_own_size.zig
new file mode 100644
index 0000000000000000000000000000000000000000..7d5a7613df01e43086ba47b73ff741ece4e0ab04
--- /dev/null
+++ b/test/cases/compile_errors/packed_struct_uses_own_size.zig
@@ -0,0 +1,10 @@
+const S = packed struct {
+ x: @Int(.unsigned, @sizeOf(S)),
+};
+comptime {
+ _ = @as(S, undefined);
+}
+
+// error
+//
+// :2:32: error: type 'tmp.S' depends on itself for size query here
diff --git a/test/cases/compile_errors/packed_struct_uses_own_typeinfo.zig b/test/cases/compile_errors/packed_struct_uses_own_typeinfo.zig
new file mode 100644
index 0000000000000000000000000000000000000000..6a1fe41eb9463f994ae44f7e12c02cb5b57f230e
--- /dev/null
+++ b/test/cases/compile_errors/packed_struct_uses_own_typeinfo.zig
@@ -0,0 +1,13 @@
+const S = packed struct(u16) {
+ a: bool,
+ b: bool,
+ _padding: @Int(.unsigned, 17 - @typeInfo(S).Struct.fields.len) = 0,
+};
+
+comptime {
+ _ = @as(S, .{ .a = true, .b = true });
+}
+
+// error
+//
+// :4:36: error: type 'tmp.S' depends on itself for type information query here
diff --git a/test/cases/compile_errors/packed_struct_with_fields_of_not_allowed_types.zig b/test/cases/compile_errors/packed_struct_with_fields_of_not_allowed_types.zig
index b5bf3d6f3a2b2c8d44f30e0e08ec78961f5eec59..d7a5d355c9d26a565b179d3610255a55bafaaab7 100644
--- a/test/cases/compile_errors/packed_struct_with_fields_of_not_allowed_types.zig
+++ b/test/cases/compile_errors/packed_struct_with_fields_of_not_allowed_types.zig
@@ -76,30 +76,41 @@ export fn entry14() void {
x: E,
});
}
+export fn entry15() void {
+ _ = @sizeOf(packed struct {
+ x: *const u32,
+ });
+}
// error
//
// :3:12: error: packed structs cannot contain fields of type 'anyerror'
-// :3:12: note: type has no guaranteed in-memory representation
+// :3:12: note: type does not have a bit-packed representation
// :8:12: error: packed structs cannot contain fields of type '[2]u24'
-// :8:12: note: type has no guaranteed in-memory representation
+// :8:12: note: type does not have a bit-packed representation
// :13:20: error: packed structs cannot contain fields of type 'anyerror!u32'
-// :13:20: note: type has no guaranteed in-memory representation
+// :13:20: note: type does not have a bit-packed representation
// :18:12: error: packed structs cannot contain fields of type 'tmp.S'
-// :18:12: note: only packed structs layout are allowed in packed types
+// :18:12: note: non-packed structs do not have a bit-packed representation
// :56:11: note: struct declared here
// :23:12: error: packed structs cannot contain fields of type 'tmp.U'
-// :23:12: note: only packed unions layout are allowed in packed types
+// :23:12: note: non-packed unions do not have a bit-packed representation
// :59:18: note: union declared here
// :28:12: error: packed structs cannot contain fields of type '?anyerror'
-// :28:12: note: type has no guaranteed in-memory representation
+// :28:12: note: type does not have a bit-packed representation
// :38:12: error: packed structs cannot contain fields of type 'fn () void'
-// :38:12: note: type has no guaranteed in-memory representation
-// :38:12: note: use '*const ' to make a function pointer type
+// :38:12: note: type does not have a bit-packed representation
+// :43:12: error: packed structs cannot contain fields of type '*const fn () void'
+// :43:12: note: pointers cannot be directly bitpacked
+// :43:12: note: consider using 'usize' and '@intFromPtr'
// :65:31: error: packed structs cannot contain fields of type '[]u8'
-// :65:31: note: slices have no guaranteed in-memory representation
+// :65:31: note: slices do not have a bit-packed representation
// :70:12: error: packed structs cannot contain fields of type '*type'
-// :70:12: note: comptime-only pointer has no guaranteed in-memory representation
-// :70:12: note: types are not available at runtime
+// :70:12: note: pointers cannot be directly bitpacked
+// :70:12: note: consider using 'usize' and '@intFromPtr'
// :76:12: error: packed structs cannot contain fields of type 'tmp.entry14.E'
-// :74:15: note: enum declared here
+// :74:15: note: integer tag type of enum is inferred
+// :74:15: note: consider explicitly specifying the integer tag type
+// :81:12: error: packed structs cannot contain fields of type '*const u32'
+// :81:12: note: pointers cannot be directly bitpacked
+// :81:12: note: consider using 'usize' and '@intFromPtr'
diff --git a/test/cases/compile_errors/packed_union_fields_mismatch.zig b/test/cases/compile_errors/packed_union_fields_mismatch.zig
index 7f5ac456bfe246c5a69c9b00545d64749d27871f..1e815838a9b948b4fceb619a9ef78dc6c5feaafd 100644
--- a/test/cases/compile_errors/packed_union_fields_mismatch.zig
+++ b/test/cases/compile_errors/packed_union_fields_mismatch.zig
@@ -1,12 +1,14 @@
export fn entry1() void {
- _ = packed union {
+ const U = packed union {
a: u1,
b: u2,
};
+ _ = @as(U, undefined);
}
// error
//
-// :2:16: error: packed union has fields with mismatching bit sizes
-// :3:12: note: 1 bits here
-// :4:12: note: 2 bits here
+// :4:12: error: field bit width does not match earlier field
+// :4:12: note: field type 'u2' has bit width '2'
+// :3:12: note: other field type 'u1' has bit width '1'
+// :4:12: note: all fields in a packed union must have the same bit width
diff --git a/test/cases/compile_errors/packed_union_given_enum_tag_type.zig b/test/cases/compile_errors/packed_union_given_enum_tag_type.zig
deleted file mode 100644
index f95c1739c0cd3dcd3cfc865ab20415c9b95fddf1..0000000000000000000000000000000000000000
--- a/test/cases/compile_errors/packed_union_given_enum_tag_type.zig
+++ /dev/null
@@ -1,18 +0,0 @@
-const Letter = enum {
- A,
- B,
- C,
-};
-const Payload = packed union(Letter) {
- A: i32,
- B: f64,
- C: bool,
-};
-export fn entry() void {
- const a: Payload = .{ .A = 1234 };
- _ = a;
-}
-
-// error
-//
-// :6:30: error: packed union does not support enum tag type
diff --git a/test/cases/compile_errors/packed_union_with_automatic_layout_field.zig b/test/cases/compile_errors/packed_union_with_automatic_layout_field.zig
deleted file mode 100644
index c37e987c1c15399d22f8ffe5eab38bdd9ef2b4b1..0000000000000000000000000000000000000000
--- a/test/cases/compile_errors/packed_union_with_automatic_layout_field.zig
+++ /dev/null
@@ -1,18 +0,0 @@
-const Foo = struct {
- a: u32,
- b: f32,
-};
-const Payload = packed union {
- A: Foo,
- B: bool,
-};
-export fn entry() void {
- const a: Payload = .{ .B = true };
- _ = a;
-}
-
-// error
-//
-// :6:8: error: packed unions cannot contain fields of type 'tmp.Foo'
-// :6:8: note: only packed structs layout are allowed in packed types
-// :1:13: note: struct declared here
diff --git a/test/cases/compile_errors/packed_union_with_fields_of_not_allowed_types.zig b/test/cases/compile_errors/packed_union_with_fields_of_not_allowed_types.zig
new file mode 100644
index 0000000000000000000000000000000000000000..d0e09742b5080e165af9fc105ff62fad177ff993
--- /dev/null
+++ b/test/cases/compile_errors/packed_union_with_fields_of_not_allowed_types.zig
@@ -0,0 +1,21 @@
+const S = struct { a: u32 };
+export fn entry0() void {
+ _ = @sizeOf(packed union {
+ foo: S,
+ bar: bool,
+ });
+}
+export fn entry1() void {
+ _ = @sizeOf(packed union {
+ x: *const u32,
+ });
+}
+
+// error
+//
+// :4:14: error: packed unions cannot contain fields of type 'tmp.S'
+// :4:14: note: non-packed structs do not have a bit-packed representation
+// :1:11: note: struct declared here
+// :10:12: error: packed unions cannot contain fields of type '*const u32'
+// :10:12: note: pointers cannot be directly bitpacked
+// :10:12: note: consider using 'usize' and '@intFromPtr'
diff --git a/test/cases/compile_errors/pointer_in_bitpack.zig b/test/cases/compile_errors/pointer_in_bitpack.zig
new file mode 100644
index 0000000000000000000000000000000000000000..fa3d8130fa11ea0e44562266b39dc6bc9ce67df9
--- /dev/null
+++ b/test/cases/compile_errors/pointer_in_bitpack.zig
@@ -0,0 +1,22 @@
+const S = packed struct {
+ ptr: *u32,
+};
+export fn foo() void {
+ _ = @as(S, undefined);
+}
+
+const U = packed union {
+ ptr: *u32,
+};
+export fn bar() void {
+ _ = @as(U, undefined);
+}
+
+// error
+//
+// :2:10: error: packed structs cannot contain fields of type '*u32'
+// :2:10: note: pointers cannot be directly bitpacked
+// :2:10: note: consider using 'usize' and '@intFromPtr'
+// :9:10: error: packed unions cannot contain fields of type '*u32'
+// :9:10: note: pointers cannot be directly bitpacked
+// :9:10: note: consider using 'usize' and '@intFromPtr'
diff --git a/test/cases/compile_errors/reify_enum_with_duplicate_field.zig b/test/cases/compile_errors/reify_enum_with_duplicate_field.zig
index 73df5e1a869a3fe6c8255945fc6e98f8d82e2a85..efa0e51dee32d9058fc2f1f73d46cb3aaa953b6f 100644
--- a/test/cases/compile_errors/reify_enum_with_duplicate_field.zig
+++ b/test/cases/compile_errors/reify_enum_with_duplicate_field.zig
@@ -1,8 +1,9 @@
export fn entry() void {
- _ = @Enum(u32, .nonexhaustive, &.{ "A", "A" }, &.{ 0, 1 });
+ const E = @Enum(u32, .nonexhaustive, &.{ "A", "A" }, &.{ 0, 1 });
+ _ = @as(E, undefined);
}
// error
//
-// :2:36: error: duplicate enum field 'A'
-// :2:36: note: other field here
+// :2:42: error: duplicate enum field 'A' at index '1'
+// :2:42: note: previous field at index '0'
diff --git a/test/cases/compile_errors/reify_enum_with_duplicate_tag_value.zig b/test/cases/compile_errors/reify_enum_with_duplicate_tag_value.zig
index 6343782ca7b2e53a9c0f1bfe2b5f3189b7cd5b0b..c60589f7e02075a59a82f0f02423312b5c709c88 100644
--- a/test/cases/compile_errors/reify_enum_with_duplicate_tag_value.zig
+++ b/test/cases/compile_errors/reify_enum_with_duplicate_tag_value.zig
@@ -1,8 +1,9 @@
export fn entry() void {
- _ = @Enum(u32, .nonexhaustive, &.{ "A", "B" }, &.{ 10, 10 });
+ const E = @Enum(u32, .nonexhaustive, &.{ "a", "b" }, &.{ 10, 10 });
+ _ = E.a;
}
// error
//
-// :2:52: error: enum tag value 10 already taken
-// :2:52: note: other enum tag value here
+// :2:58: error: enum tag value '10' for field 'b' already taken
+// :2:58: note: previous occurrence in field 'a'
diff --git a/test/cases/compile_errors/reify_type_for_exhaustive_enum_with_non-integer_tag_type.zig b/test/cases/compile_errors/reify_type_for_exhaustive_enum_with_non-integer_tag_type.zig
index d74e0b2b53104178bae00a1799d6013a76f6df28..8e684cba560d5af4f7189fc9d0d16ed554e0e5e4 100644
--- a/test/cases/compile_errors/reify_type_for_exhaustive_enum_with_non-integer_tag_type.zig
+++ b/test/cases/compile_errors/reify_type_for_exhaustive_enum_with_non-integer_tag_type.zig
@@ -5,4 +5,4 @@ export fn entry() void {
// error
//
-// :1:19: error: tag type must be an integer type
+// :1:19: error: expected integer tag type, found 'bool'
diff --git a/test/cases/compile_errors/reify_type_for_tagged_packed_union.zig b/test/cases/compile_errors/reify_type_for_tagged_packed_union.zig
deleted file mode 100644
index f602771bc68874789ce8b2f79afbe12cdc571f5b..0000000000000000000000000000000000000000
--- a/test/cases/compile_errors/reify_type_for_tagged_packed_union.zig
+++ /dev/null
@@ -1,11 +0,0 @@
-const Tag = @Enum(u2, .exhaustive, &.{ "signed", "unsigned" }, &.{ 0, 1 });
-const Packed = @Union(.@"packed", Tag, &.{ "signed", "unsigned" }, &.{ i32, u32 }, &@splat(.{}));
-
-export fn entry() void {
- const tagged: Packed = .{ .signed = -1 };
- _ = tagged;
-}
-
-// error
-//
-// :2:35: error: packed union does not support enum tag type
diff --git a/test/cases/compile_errors/reify_type_for_tagged_union_with_extra_enum_field.zig b/test/cases/compile_errors/reify_type_for_tagged_union_with_extra_enum_field.zig
index 5b56a98eb3d9c058708f2685738d518e36759a8d..0b62e7b6d945bcb1808710411ce4f465cd859b1e 100644
--- a/test/cases/compile_errors/reify_type_for_tagged_union_with_extra_enum_field.zig
+++ b/test/cases/compile_errors/reify_type_for_tagged_union_with_extra_enum_field.zig
@@ -7,6 +7,5 @@ export fn entry() void {
// error
//
-// :2:35: error: 1 enum fields missing in union
-// :1:13: note: field 'arst' missing, declared here
-// :1:13: note: enum declared here
+// :2:16: error: enum field 'arst' missing from union
+// :1:36: note: enum field here
diff --git a/test/cases/compile_errors/reify_type_for_tagged_union_with_no_union_fields.zig b/test/cases/compile_errors/reify_type_for_tagged_union_with_no_union_fields.zig
index 245bd472ccfdc6b1be0d3f78c7fa63f649e97f4b..ae4903c4d8739f08607d656306b9f013f21ccefc 100644
--- a/test/cases/compile_errors/reify_type_for_tagged_union_with_no_union_fields.zig
+++ b/test/cases/compile_errors/reify_type_for_tagged_union_with_no_union_fields.zig
@@ -7,7 +7,5 @@ export fn entry() void {
// error
//
-// :2:35: error: 2 enum fields missing in union
-// :1:13: note: field 'signed' missing, declared here
-// :1:13: note: field 'unsigned' missing, declared here
-// :1:13: note: enum declared here
+// :2:16: error: enum field 'signed' missing from union
+// :1:36: note: enum field here
diff --git a/test/cases/compile_errors/reify_type_for_union_with_opaque_field.zig b/test/cases/compile_errors/reify_type_for_union_with_opaque_field.zig
index e2be15f1a4239d4cd3721dc05652a203e8754d07..3a1b64e58ef3303189d885c757b25459a1668e3c 100644
--- a/test/cases/compile_errors/reify_type_for_union_with_opaque_field.zig
+++ b/test/cases/compile_errors/reify_type_for_union_with_opaque_field.zig
@@ -1,9 +1,11 @@
-const Untagged = @Union(.auto, null, &.{"foo"}, &.{opaque {}}, &.{.{}});
+const Opaque = opaque {};
+const Untagged = @Union(.auto, null, &.{"foo"}, &.{Opaque}, &.{.{}});
export fn entry() usize {
return @sizeOf(Untagged);
}
// error
//
-// :1:49: error: opaque types have unknown size and therefore cannot be directly embedded in unions
-// :1:52: note: opaque declared here
+// :2:49: error: cannot directly embed opaque type 'tmp.Opaque' in union
+// :2:49: note: opaque types have unknown size
+// :1:16: note: opaque declared here
diff --git a/test/cases/compile_errors/reify_type_with_invalid_field_alignment.zig b/test/cases/compile_errors/reify_type_with_invalid_field_alignment.zig
index e6b9e1435a68f238a977042f4349d8b124682f74..b71480ed265099f5a5e88ddd407369b0b8431831 100644
--- a/test/cases/compile_errors/reify_type_with_invalid_field_alignment.zig
+++ b/test/cases/compile_errors/reify_type_with_invalid_field_alignment.zig
@@ -2,7 +2,11 @@ comptime {
_ = @Union(.auto, null, &.{"foo"}, &.{usize}, &.{.{ .@"align" = 3 }});
}
comptime {
- _ = @Struct(.auto, null, &.{"a"}, &.{u32}, &.{.{ .@"comptime" = true, .@"align" = 5 }});
+ _ = @Struct(.auto, null, &.{"a"}, &.{u32}, &.{.{
+ .@"comptime" = true,
+ .@"align" = 5,
+ .default_value_ptr = &@as(u32, 0),
+ }});
}
comptime {
_ = @Pointer(.many, .{ .@"align" = 7 }, u8, null);
@@ -12,4 +16,4 @@ comptime {
//
// :2:51: error: alignment value '3' is not a power of two
// :5:48: error: alignment value '5' is not a power of two
-// :8:26: error: alignment value '7' is not a power of two
+// :12:26: error: alignment value '7' is not a power of two
diff --git a/test/cases/compile_errors/resolve_inferred_error_set_of_generic_fn.zig b/test/cases/compile_errors/resolve_inferred_error_set_of_generic_fn.zig
index f6c98d68b1e8aa8bc0b939e96dfca4f2ca479197..91ece712e03db5d6370c71e64623a46d9f213d37 100644
--- a/test/cases/compile_errors/resolve_inferred_error_set_of_generic_fn.zig
+++ b/test/cases/compile_errors/resolve_inferred_error_set_of_generic_fn.zig
@@ -12,5 +12,4 @@ export fn entry() void {
// error
//
-// :10:15: error: unable to resolve inferred error set of generic function
-// :1:1: note: generic function declared here
+// :1:1: error: cannot resolve inferred error set of generic function type 'fn (anytype) @typeInfo(@typeInfo(@TypeOf(tmp.foo)).@"fn".return_type.?).error_union.error_set!void'
diff --git a/test/cases/compile_errors/runtime_@ptrFromInt_to_comptime_only_type.zig b/test/cases/compile_errors/runtime_@ptrFromInt_to_comptime_only_type.zig
index 04dc92f86ba16035fc5cd5f118b1e310e5617ff6..6e21501dcffbe65ccc1dddfe25508f5ad006f0ef 100644
--- a/test/cases/compile_errors/runtime_@ptrFromInt_to_comptime_only_type.zig
+++ b/test/cases/compile_errors/runtime_@ptrFromInt_to_comptime_only_type.zig
@@ -10,6 +10,5 @@ pub export fn callbackFin(id: c_int, arg: ?*anyopaque) void {
// error
//
-// :5:54: error: pointer to comptime-only type '?*tmp.GuSettings' must be comptime-known, but operand is runtime-known
-// :2:10: note: struct requires comptime because of this field
-// :2:10: note: use '*const fn (c_int) callconv(.c) void' for a function pointer type
+// :6:19: error: cannot load comptime-only type '?fn (c_int) callconv(.c) void'
+// :6:20: note: pointer of type '*?fn (c_int) callconv(.c) void' is runtime-known
diff --git a/test/cases/compile_errors/runtime_index_into_comptime_only_many_ptr.zig b/test/cases/compile_errors/runtime_index_into_comptime_only_many_ptr.zig
index 4a2d475b1f14451e0a0370ba315d54b5f4ad66dd..3f645862fa7be40c0ed11d0e6c9505b00870f4f4 100644
--- a/test/cases/compile_errors/runtime_index_into_comptime_only_many_ptr.zig
+++ b/test/cases/compile_errors/runtime_index_into_comptime_only_many_ptr.zig
@@ -1,10 +1,10 @@
var rt: usize = 0;
export fn foo() void {
const x: [*]const type = &.{ u8, u16 };
- _ = &x[rt];
+ _ = x[rt];
}
// error
//
-// :4:12: error: values of type '[*]const type' must be comptime-known, but index value is runtime-known
-// :4:11: note: types are not available at runtime
+// :4:11: error: values of type 'type' must be comptime-known, but index value is runtime-known
+// :4:10: note: types are not available at runtime
diff --git a/test/cases/compile_errors/runtime_index_into_comptime_type_slice.zig b/test/cases/compile_errors/runtime_index_into_comptime_type_slice.zig
index b4781a3c680abe53388eed2196ceeaa13c216527..b4cf100c19978597ccf5f987f69fdebe1345a848 100644
--- a/test/cases/compile_errors/runtime_index_into_comptime_type_slice.zig
+++ b/test/cases/compile_errors/runtime_index_into_comptime_type_slice.zig
@@ -12,7 +12,6 @@ export fn entry() void {
// error
//
-// :9:54: error: values of type '[]const builtin.Type.StructField' must be comptime-known, but index value is runtime-known
+// :9:54: error: values of type 'builtin.Type.StructField' must be comptime-known, but index value is runtime-known
// : note: struct requires comptime because of this field
// : note: types are not available at runtime
-// : struct requires comptime because of this field
diff --git a/test/cases/compile_errors/runtime_indexing_comptime_array.zig b/test/cases/compile_errors/runtime_indexing_comptime_array.zig
index 3fcf57dd47bfe4883850f96fd955f481a8768b36..f82991dd3974cdfc754ae4746cc0ac6847f4829a 100644
--- a/test/cases/compile_errors/runtime_indexing_comptime_array.zig
+++ b/test/cases/compile_errors/runtime_indexing_comptime_array.zig
@@ -24,9 +24,9 @@ pub export fn entry3() void {
}
// error
//
-// :7:10: error: values of type '[2]fn () void' must be comptime-known, but index value is runtime-known
+// :7:10: error: values of type 'fn () void' must be comptime-known, but index value is runtime-known
// :7:10: note: use '*const fn () void' for a function pointer type
-// :15:18: error: values of type '[2]fn () void' must be comptime-known, but index value is runtime-known
+// :15:18: error: values of type 'fn () void' must be comptime-known, but index value is runtime-known
// :15:17: note: use '*const fn () void' for a function pointer type
-// :22:19: error: values of type '[2]fn () void' must be comptime-known, but index value is runtime-known
+// :22:19: error: values of type 'fn () void' must be comptime-known, but index value is runtime-known
// :22:18: note: use '*const fn () void' for a function pointer type
diff --git a/test/cases/compile_errors/runtime_operation_in_comptime_scope.zig b/test/cases/compile_errors/runtime_operation_in_comptime_scope.zig
index 73220b0ba4e1de7273b2bb2c7b85ef232d225596..1631fc07fc41aee4e21324478e9d294b0bb6459a 100644
--- a/test/cases/compile_errors/runtime_operation_in_comptime_scope.zig
+++ b/test/cases/compile_errors/runtime_operation_in_comptime_scope.zig
@@ -25,13 +25,13 @@ var rt: u32 = undefined;
//
// :19:8: error: unable to evaluate comptime expression
// :19:5: note: operation is runtime due to this operand
+// :6:8: note: called at comptime from here
+// :5:1: note: 'comptime' keyword forces comptime evaluation
+// :19:8: error: unable to evaluate comptime expression
+// :19:5: note: operation is runtime due to this operand
// :14:8: note: called at comptime from here
// :10:12: note: called at comptime from here
// :10:12: note: call to function with comptime-only return type 'type' is evaluated at comptime
// :13:10: note: return type declared here
// :10:12: note: types are not available at runtime
// :2:8: note: called inline here
-// :19:8: error: unable to evaluate comptime expression
-// :19:5: note: operation is runtime due to this operand
-// :6:8: note: called at comptime from here
-// :5:1: note: 'comptime' keyword forces comptime evaluation
diff --git a/test/cases/compile_errors/self_referential_struct_requires_comptime.zig b/test/cases/compile_errors/self_referential_struct_requires_comptime.zig
index 5205702b679e3ca9d09351af5f8a76b7687983fb..81a0813d9b63b49cbda15cc79ba7b3bf4c67d5ec 100644
--- a/test/cases/compile_errors/self_referential_struct_requires_comptime.zig
+++ b/test/cases/compile_errors/self_referential_struct_requires_comptime.zig
@@ -12,4 +12,3 @@ pub export fn entry() void {
// :6:12: error: variable of type 'tmp.S' must be const or comptime
// :2:8: note: struct requires comptime because of this field
// :2:8: note: use '*const fn () void' for a function pointer type
-// :3:8: note: struct requires comptime because of this field
diff --git a/test/cases/compile_errors/self_referential_union_requires_comptime.zig b/test/cases/compile_errors/self_referential_union_requires_comptime.zig
index 6ab0af996596a9bc021466ff95d71c2ff6ec79db..fbf00ce69a6b4ccfeb763b394d9581377a81b16e 100644
--- a/test/cases/compile_errors/self_referential_union_requires_comptime.zig
+++ b/test/cases/compile_errors/self_referential_union_requires_comptime.zig
@@ -12,4 +12,3 @@ pub export fn entry() void {
// :6:12: error: variable of type 'tmp.U' must be const or comptime
// :2:8: note: union requires comptime because of this field
// :2:8: note: use '*const fn () void' for a function pointer type
-// :3:8: note: union requires comptime because of this field
diff --git a/test/cases/compile_errors/simple_struct_loop.zig b/test/cases/compile_errors/simple_struct_loop.zig
new file mode 100644
index 0000000000000000000000000000000000000000..3ae0b2ed82862430fcfaf2f301cae7c4eadc7d09
--- /dev/null
+++ b/test/cases/compile_errors/simple_struct_loop.zig
@@ -0,0 +1,16 @@
+const A = struct {
+ b: B,
+};
+const B = struct {
+ a: A,
+};
+comptime {
+ _ = @as(A, undefined);
+}
+
+// error
+//
+// error: dependency loop with length 2
+// :2:8: note: type 'tmp.A' depends on type 'tmp.B' for field declared here
+// :5:8: note: type 'tmp.B' depends on type 'tmp.A' for field declared here
+// note: eliminate any one of these dependencies to break the loop
diff --git a/test/cases/compile_errors/sizeOf_bad_type.zig b/test/cases/compile_errors/sizeOf_bad_type.zig
index 93dec1f88eeddfaf5352b183ad54886cbfb3e39c..08ce7f4358f19781ba6fa007f5120978894c049b 100644
--- a/test/cases/compile_errors/sizeOf_bad_type.zig
+++ b/test/cases/compile_errors/sizeOf_bad_type.zig
@@ -1,7 +1,31 @@
-export fn entry() usize {
+export fn entry0() usize {
return @sizeOf(@TypeOf(null));
}
+export fn entry1() usize {
+ return @sizeOf(comptime_int);
+}
+export fn entry2() usize {
+ return @sizeOf(noreturn);
+}
+const S3 = struct { a: u32, b: comptime_int };
+export fn entry3() usize {
+ return @sizeOf(S3);
+}
+const S4 = struct { a: u32, b: noreturn };
+export fn entry4() usize {
+ return @sizeOf(S4);
+}
+export fn entry5() usize {
+ return @sizeOf([1]fn () void);
+}
// error
//
-// :2:20: error: no size available for type '@TypeOf(null)'
+// :2:20: error: no size available for comptime-only type '@TypeOf(null)'
+// :5:20: error: no size available for comptime-only type 'comptime_int'
+// :8:20: error: no size available for uninstantiable type 'noreturn'
+// :12:20: error: no size available for comptime-only type 'tmp.S3'
+// :10:12: note: struct declared here
+// :16:20: error: no size available for uninstantiable type 'tmp.S4'
+// :14:12: note: struct declared here
+// :19:20: error: no size available for comptime-only type '[1]fn () void'
diff --git a/test/cases/compile_errors/sizeof_alignof_empty_union.zig b/test/cases/compile_errors/sizeof_alignof_empty_union.zig
new file mode 100644
index 0000000000000000000000000000000000000000..58e6aa635088c30cab0c1d7306f088406fcb34d1
--- /dev/null
+++ b/test/cases/compile_errors/sizeof_alignof_empty_union.zig
@@ -0,0 +1,75 @@
+const EnumInferred = enum {};
+const EnumExplicit = enum(u8) {};
+const EnumNonexhaustive = enum(u8) { _ };
+
+const U0 = union {};
+const U1 = union(enum) {};
+const U2 = union(enum(u8)) {};
+const U3 = union(EnumInferred) {};
+const U4 = union(EnumExplicit) {};
+const U5 = union(EnumNonexhaustive) {};
+
+export fn size0() void {
+ _ = @sizeOf(U0);
+}
+export fn size1() void {
+ _ = @sizeOf(U1);
+}
+export fn size2() void {
+ _ = @sizeOf(U2);
+}
+export fn size3() void {
+ _ = @sizeOf(U3);
+}
+export fn size4() void {
+ _ = @sizeOf(U4);
+}
+export fn size5() void {
+ _ = @sizeOf(U5);
+}
+
+export fn align0() void {
+ _ = @alignOf(U0);
+}
+export fn align1() void {
+ _ = @alignOf(U1);
+}
+export fn align2() void {
+ _ = @alignOf(U2);
+}
+export fn align3() void {
+ _ = @alignOf(U3);
+}
+export fn align4() void {
+ _ = @alignOf(U4);
+}
+export fn align5() void {
+ _ = @alignOf(U5);
+}
+
+// error
+//
+// :13:17: error: no size available for uninstantiable type 'tmp.U0'
+// :5:12: note: union declared here
+// :16:17: error: no size available for uninstantiable type 'tmp.U1'
+// :6:12: note: union declared here
+// :19:17: error: no size available for uninstantiable type 'tmp.U2'
+// :7:12: note: union declared here
+// :22:17: error: no size available for uninstantiable type 'tmp.U3'
+// :8:12: note: union declared here
+// :25:17: error: no size available for uninstantiable type 'tmp.U4'
+// :9:12: note: union declared here
+// :28:17: error: no size available for uninstantiable type 'tmp.U5'
+// :10:12: note: union declared here
+// :32:18: error: no align available for uninstantiable type 'tmp.U0'
+// :5:12: note: union declared here
+// :35:18: error: no align available for uninstantiable type 'tmp.U1'
+// :6:12: note: union declared here
+// :38:18: error: no align available for uninstantiable type 'tmp.U2'
+// :7:12: note: union declared here
+// :41:18: error: no align available for uninstantiable type 'tmp.U3'
+// :8:12: note: union declared here
+// :44:18: error: no align available for uninstantiable type 'tmp.U4'
+// :9:12: note: union declared here
+// :47:18: error: no align available for uninstantiable type 'tmp.U5'
+// :10:12: note: union declared here
diff --git a/test/cases/compile_errors/slice_used_as_extern_fn_param.zig b/test/cases/compile_errors/slice_used_as_extern_fn_param.zig
index 522e4eba8ce278e56afc5643813d84db253bc0ea..e056aa23800a0a9810d3da6b3c66ce8ad82ac31d 100644
--- a/test/cases/compile_errors/slice_used_as_extern_fn_param.zig
+++ b/test/cases/compile_errors/slice_used_as_extern_fn_param.zig
@@ -1,6 +1,6 @@
extern fn Text(str: []const u8, num: i32) callconv(.c) void;
export fn entry() void {
- _ = Text;
+ Text(undefined, undefined);
}
// error
diff --git a/test/cases/compile_errors/specify_enum_tag_type_that_is_too_small.zig b/test/cases/compile_errors/specify_enum_tag_type_that_is_too_small.zig
index f00c363aae5fad3620c6d5c54625153b44ac3740..b6d9bd7d21ad217efe00ba4fa88c1cbe440d75a3 100644
--- a/test/cases/compile_errors/specify_enum_tag_type_that_is_too_small.zig
+++ b/test/cases/compile_errors/specify_enum_tag_type_that_is_too_small.zig
@@ -1,9 +1,9 @@
const Small = enum(u2) {
- One,
- Two,
- Three,
- Four,
- Five,
+ one,
+ two,
+ three,
+ four,
+ five,
};
const SmallUnion = union(enum(u2)) {
@@ -14,13 +14,13 @@ const SmallUnion = union(enum(u2)) {
};
comptime {
- _ = Small;
+ _ = Small.one;
}
comptime {
- _ = SmallUnion;
+ _ = SmallUnion.one;
}
// error
//
-// :6:5: error: enumeration value '4' too large for type 'u2'
-// :13:5: error: enumeration value '4' too large for type 'u2'
+// :6:5: error: enum tag value '4' too large for type 'u2'
+// :13:5: error: enum tag value '4' too large for type 'u2'
diff --git a/test/cases/compile_errors/store_comptime_only_type_to_runtime_pointer.zig b/test/cases/compile_errors/store_comptime_only_type_to_runtime_pointer.zig
index af30c80f7040e148eadb1e0965c9d3b24c81c15f..05ae6f920205b98525020c71038b593a7d487f9b 100644
--- a/test/cases/compile_errors/store_comptime_only_type_to_runtime_pointer.zig
+++ b/test/cases/compile_errors/store_comptime_only_type_to_runtime_pointer.zig
@@ -21,22 +21,15 @@ export fn e() void {
p.* = undefined;
}
-export fn f() void {
- const p: **comptime_int = @ptrFromInt(16); // double pointer ('*comptime_int' is comptime-only)
- p.* = undefined;
-}
-
// error
//
// :3:9: error: cannot store comptime-only type 'fn () void' at runtime
// :3:6: note: operation is runtime due to this pointer
// :7:11: error: expected type 'anyopaque', found '@TypeOf(undefined)'
-// :7:11: note: cannot coerce to 'anyopaque'
+// :7:11: note: cannot coerce to uninstantiable type 'anyopaque'
// :11:12: error: cannot load opaque type 'anyopaque'
// :16:11: error: expected type 'tmp.Opaque', found '@TypeOf(undefined)'
-// :16:11: note: cannot coerce to 'tmp.Opaque'
+// :16:11: note: cannot coerce to uninstantiable type 'tmp.Opaque'
// :14:16: note: opaque declared here
// :21:9: error: cannot store comptime-only type 'comptime_int' at runtime
// :21:6: note: operation is runtime due to this pointer
-// :26:9: error: cannot store comptime-only type '*comptime_int' at runtime
-// :26:6: note: operation is runtime due to this pointer
diff --git a/test/cases/compile_errors/struct_depends_on_itself_via_non_initial_field.zig b/test/cases/compile_errors/struct_depends_on_itself_via_non_initial_field.zig
index b514bc10e7bf8c1ced988e2b14e6c80afcc40605..7d2ddaa2096fd10f1be1f6c113bcf236ecd58ef5 100644
--- a/test/cases/compile_errors/struct_depends_on_itself_via_non_initial_field.zig
+++ b/test/cases/compile_errors/struct_depends_on_itself_via_non_initial_field.zig
@@ -4,9 +4,9 @@ const A = struct {
};
comptime {
- _ = A;
+ _ = @as(A, undefined);
}
// error
//
-// :1:11: error: struct 'tmp.A' depends on itself
+// :3:21: error: type 'tmp.A' depends on itself for size query here
diff --git a/test/cases/compile_errors/struct_depends_on_itself_via_optional_field.zig b/test/cases/compile_errors/struct_depends_on_itself_via_optional_field.zig
index a8614baf79d03384d38c67044a32920a260b7ec2..bc4ad96555a6f9ff02d95637a74342104cb0566a 100644
--- a/test/cases/compile_errors/struct_depends_on_itself_via_optional_field.zig
+++ b/test/cases/compile_errors/struct_depends_on_itself_via_optional_field.zig
@@ -12,4 +12,7 @@ export fn entry() void {
// error
//
-// :1:17: error: struct 'tmp.LhsExpr' depends on itself
+// error: dependency loop with length 2
+// :2:14: note: type 'tmp.LhsExpr' depends on type 'tmp.AstObject' for field declared here
+// :5:14: note: type 'tmp.AstObject' depends on type 'tmp.LhsExpr' for field declared here
+// note: eliminate any one of these dependencies to break the loop
diff --git a/test/cases/compile_errors/struct_depends_on_pointer_alignment.zig b/test/cases/compile_errors/struct_depends_on_pointer_alignment.zig
deleted file mode 100644
index ca15cc6bf26d17527cd77fe73200130ab130609c..0000000000000000000000000000000000000000
--- a/test/cases/compile_errors/struct_depends_on_pointer_alignment.zig
+++ /dev/null
@@ -1,11 +0,0 @@
-const S = struct {
- next: ?*align(1) S align(128),
-};
-
-export fn entry() usize {
- return @alignOf(S);
-}
-
-// error
-//
-// :1:11: error: struct layout depends on being pointer aligned
diff --git a/test/cases/compile_errors/struct_field_queries_hasfield_of_itself.zig b/test/cases/compile_errors/struct_field_queries_hasfield_of_itself.zig
new file mode 100644
index 0000000000000000000000000000000000000000..593b440149a93b4a1d0f2aec20ad1b58b6f2bdff
--- /dev/null
+++ b/test/cases/compile_errors/struct_field_queries_hasfield_of_itself.zig
@@ -0,0 +1,14 @@
+const Foo = packed struct {
+ bar: (T: {
+ _ = @hasField(Foo, "bar");
+ break :T void;
+ }),
+};
+
+comptime {
+ _ = @as(Foo, undefined);
+}
+
+// error
+//
+// :3:23: error: type 'tmp.Foo' depends on itself for field query here
diff --git a/test/cases/compile_errors/struct_uses_reified_type_which_queries_struct_alignment.zig b/test/cases/compile_errors/struct_uses_reified_type_which_queries_struct_alignment.zig
new file mode 100644
index 0000000000000000000000000000000000000000..f3f7361de750573d0fc15298c42ae95c7c3873f0
--- /dev/null
+++ b/test/cases/compile_errors/struct_uses_reified_type_which_queries_struct_alignment.zig
@@ -0,0 +1,13 @@
+const A = struct { b: *B };
+const B = @Struct(.auto, null, &.{"x"}, &.{A}, &.{.{ .@"align" = @alignOf(A) }});
+comptime {
+ _ = @as(A, undefined);
+ _ = @as(B, undefined);
+}
+
+// error
+//
+// error: dependency loop with length 2
+// :1:24: note: type 'tmp.A' uses value of declaration 'tmp.B' here
+// :2:75: note: value of declaration 'tmp.B' depends on type 'tmp.A' for alignment query here
+// note: eliminate any one of these dependencies to break the loop
diff --git a/test/cases/compile_errors/struct_uses_sizeof_self_as_array_len.zig b/test/cases/compile_errors/struct_uses_sizeof_self_as_array_len.zig
new file mode 100644
index 0000000000000000000000000000000000000000..a8e0183465c2f643d026231f7ad6b28f0879f345
--- /dev/null
+++ b/test/cases/compile_errors/struct_uses_sizeof_self_as_array_len.zig
@@ -0,0 +1,10 @@
+const S = struct {
+ a: *[@sizeOf(S)]u8,
+};
+comptime {
+ _ = @as(S, undefined);
+}
+
+// error
+//
+// :2:18: error: type 'tmp.S' depends on itself for size query here
diff --git a/test/cases/compile_errors/too_big_packed_struct.zig b/test/cases/compile_errors/too_big_packed_struct.zig
index b5b585b70ca1f5a71867f8afe3751733bfea8f02..425442ae179ee3649a9247a8f8fa1d550ee5bebe 100644
--- a/test/cases/compile_errors/too_big_packed_struct.zig
+++ b/test/cases/compile_errors/too_big_packed_struct.zig
@@ -8,4 +8,4 @@ pub export fn entry() void {
// error
//
-// :2:22: error: size of packed struct '131070' exceeds maximum bit width of 65535
+// :2:22: error: packed struct bit width '131070' exceeds maximum bit width of 65535
diff --git a/test/cases/compile_errors/top_level_decl_dependency_loop.zig b/test/cases/compile_errors/top_level_decl_dependency_loop.zig
index fbfd0e9cb376a385b2f19c0edc239d97e6777a38..4412c38f6e672b4a6ca8e2e26dca77ba1fee3bb8 100644
--- a/test/cases/compile_errors/top_level_decl_dependency_loop.zig
+++ b/test/cases/compile_errors/top_level_decl_dependency_loop.zig
@@ -7,4 +7,9 @@ export fn entry() void {
// error
//
-// :1:1: error: dependency loop detected
+// error: dependency loop with length 4
+// :1:23: note: value of declaration 'tmp.a' uses type of declaration 'tmp.a' here
+// :1:18: note: type of declaration 'tmp.a' uses value of declaration 'tmp.b' here
+// :2:23: note: value of declaration 'tmp.b' uses type of declaration 'tmp.b' here
+// :2:18: note: type of declaration 'tmp.b' uses value of declaration 'tmp.a' here
+// note: eliminate any one of these dependencies to break the loop
diff --git a/test/cases/compile_errors/unable_to_evaluate_comptime_expr.zig b/test/cases/compile_errors/unable_to_evaluate_comptime_expr.zig
index ba9de49ebca46fe46ae1fb823f399b8926e978ae..e1cff784d522ac3fad1806c93fd3999eb379e930 100644
--- a/test/cases/compile_errors/unable_to_evaluate_comptime_expr.zig
+++ b/test/cases/compile_errors/unable_to_evaluate_comptime_expr.zig
@@ -16,22 +16,6 @@ pub export fn entry2() void {
_ = b;
}
-const Int = @typeInfo(bar).@"struct".backing_integer.?;
-
-const foo = enum(Int) {
- c = @bitCast(bar{
- .name = "test",
- }),
-};
-
-const bar = packed struct {
- name: [*:0]const u8,
-};
-
-pub export fn entry3() void {
- _ = @field(foo, "c");
-}
-
// error
//
// :7:13: error: unable to evaluate comptime expression
@@ -40,6 +24,3 @@ pub export fn entry3() void {
// :13:13: error: unable to evaluate comptime expression
// :13:16: note: operation is runtime due to this operand
// :13:13: note: initializer of container-level variable must be comptime-known
-// :22:9: error: unable to evaluate comptime expression
-// :22:21: note: operation is runtime due to this operand
-// :21:13: note: enum field values must be comptime-known
diff --git a/test/cases/compile_errors/undef_arith_is_illegal.zig b/test/cases/compile_errors/undef_arith_is_illegal.zig
index 21ca597e878507ab1d723017e061d3a201cdef6b..92279a055835346547e5143a031aa8f0612278bc 100644
--- a/test/cases/compile_errors/undef_arith_is_illegal.zig
+++ b/test/cases/compile_errors/undef_arith_is_illegal.zig
@@ -192,50 +192,30 @@ const std = @import("std");
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '1'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '1'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '1'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '1'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
@@ -244,10 +224,6 @@ const std = @import("std");
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '1'
-// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '1'
-// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
@@ -256,7 +232,9 @@ const std = @import("std");
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
+// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
+// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
@@ -266,9 +244,9 @@ const std = @import("std");
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '1'
+// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '1'
+// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
@@ -278,7 +256,9 @@ const std = @import("std");
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
+// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
+// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
@@ -288,9 +268,9 @@ const std = @import("std");
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '1'
+// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '1'
+// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
@@ -300,7 +280,9 @@ const std = @import("std");
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
+// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
+// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
@@ -310,9 +292,9 @@ const std = @import("std");
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '1'
+// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '1'
+// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
@@ -322,7 +304,9 @@ const std = @import("std");
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
+// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
+// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
@@ -332,9 +316,9 @@ const std = @import("std");
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '1'
+// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '1'
+// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
@@ -344,7 +328,9 @@ const std = @import("std");
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
+// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
+// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
@@ -354,9 +340,9 @@ const std = @import("std");
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '1'
+// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '1'
+// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
@@ -366,7 +352,9 @@ const std = @import("std");
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
+// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
+// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
@@ -376,9 +364,9 @@ const std = @import("std");
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '1'
+// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '1'
+// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
@@ -388,7 +376,9 @@ const std = @import("std");
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
+// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
+// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '0'
// :65:17: error: use of undefined value here causes illegal behavior
@@ -402,35 +392,45 @@ const std = @import("std");
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '1'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '0'
+// :65:17: note: when computing vector element at index '1'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '0'
+// :65:17: note: when computing vector element at index '1'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '0'
+// :65:17: note: when computing vector element at index '1'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '0'
+// :65:17: note: when computing vector element at index '1'
// :65:17: error: use of undefined value here causes illegal behavior
+// :65:17: note: when computing vector element at index '1'
// :65:17: error: use of undefined value here causes illegal behavior
+// :65:17: note: when computing vector element at index '1'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '0'
+// :65:17: note: when computing vector element at index '1'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '0'
+// :65:17: note: when computing vector element at index '1'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '0'
+// :65:17: note: when computing vector element at index '1'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '0'
+// :65:17: note: when computing vector element at index '1'
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '1'
// :65:17: error: use of undefined value here causes illegal behavior
// :65:17: note: when computing vector element at index '1'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '0'
+// :65:17: note: when computing vector element at index '1'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '0'
+// :65:17: note: when computing vector element at index '1'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '0'
+// :65:17: note: when computing vector element at index '1'
// :65:17: error: use of undefined value here causes illegal behavior
-// :65:17: note: when computing vector element at index '0'
+// :65:17: note: when computing vector element at index '1'
+// :65:17: error: use of undefined value here causes illegal behavior
+// :65:17: note: when computing vector element at index '1'
+// :65:17: error: use of undefined value here causes illegal behavior
+// :65:17: note: when computing vector element at index '1'
+// :65:17: error: use of undefined value here causes illegal behavior
+// :65:17: note: when computing vector element at index '1'
+// :65:17: error: use of undefined value here causes illegal behavior
+// :65:17: note: when computing vector element at index '1'
// :65:21: error: use of undefined value here causes illegal behavior
// :65:21: note: when computing vector element at index '0'
// :65:21: error: use of undefined value here causes illegal behavior
@@ -478,50 +478,30 @@ const std = @import("std");
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '1'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '1'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '1'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '1'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
@@ -530,10 +510,6 @@ const std = @import("std");
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '1'
-// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '1'
-// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
@@ -542,7 +518,9 @@ const std = @import("std");
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
+// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
+// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
@@ -552,9 +530,9 @@ const std = @import("std");
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '1'
+// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '1'
+// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
@@ -564,7 +542,9 @@ const std = @import("std");
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
+// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
+// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
@@ -574,9 +554,9 @@ const std = @import("std");
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '1'
+// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '1'
+// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
@@ -586,7 +566,9 @@ const std = @import("std");
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
+// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
+// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
@@ -596,9 +578,9 @@ const std = @import("std");
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '1'
+// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '1'
+// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
@@ -608,7 +590,9 @@ const std = @import("std");
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
+// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
+// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
@@ -618,9 +602,9 @@ const std = @import("std");
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '1'
+// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '1'
+// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
@@ -630,7 +614,9 @@ const std = @import("std");
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
+// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
+// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
@@ -640,9 +626,9 @@ const std = @import("std");
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '1'
+// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '1'
+// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
@@ -652,7 +638,9 @@ const std = @import("std");
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
+// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
+// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
@@ -662,9 +650,9 @@ const std = @import("std");
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '1'
+// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '1'
+// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
@@ -674,7 +662,9 @@ const std = @import("std");
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
+// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
+// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '0'
// :69:27: error: use of undefined value here causes illegal behavior
@@ -688,35 +678,45 @@ const std = @import("std");
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '1'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '0'
+// :69:27: note: when computing vector element at index '1'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '0'
+// :69:27: note: when computing vector element at index '1'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '0'
+// :69:27: note: when computing vector element at index '1'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '0'
+// :69:27: note: when computing vector element at index '1'
// :69:27: error: use of undefined value here causes illegal behavior
+// :69:27: note: when computing vector element at index '1'
// :69:27: error: use of undefined value here causes illegal behavior
+// :69:27: note: when computing vector element at index '1'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '0'
+// :69:27: note: when computing vector element at index '1'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '0'
+// :69:27: note: when computing vector element at index '1'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '0'
+// :69:27: note: when computing vector element at index '1'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '0'
+// :69:27: note: when computing vector element at index '1'
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '1'
// :69:27: error: use of undefined value here causes illegal behavior
// :69:27: note: when computing vector element at index '1'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '0'
+// :69:27: note: when computing vector element at index '1'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '0'
+// :69:27: note: when computing vector element at index '1'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '0'
+// :69:27: note: when computing vector element at index '1'
// :69:27: error: use of undefined value here causes illegal behavior
-// :69:27: note: when computing vector element at index '0'
+// :69:27: note: when computing vector element at index '1'
+// :69:27: error: use of undefined value here causes illegal behavior
+// :69:27: note: when computing vector element at index '1'
+// :69:27: error: use of undefined value here causes illegal behavior
+// :69:27: note: when computing vector element at index '1'
+// :69:27: error: use of undefined value here causes illegal behavior
+// :69:27: note: when computing vector element at index '1'
+// :69:27: error: use of undefined value here causes illegal behavior
+// :69:27: note: when computing vector element at index '1'
// :69:30: error: use of undefined value here causes illegal behavior
// :69:30: note: when computing vector element at index '0'
// :69:30: error: use of undefined value here causes illegal behavior
@@ -764,50 +764,30 @@ const std = @import("std");
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
@@ -816,10 +796,6 @@ const std = @import("std");
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
-// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
-// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
@@ -828,7 +804,9 @@ const std = @import("std");
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
@@ -838,9 +816,9 @@ const std = @import("std");
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
@@ -850,7 +828,9 @@ const std = @import("std");
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
@@ -860,9 +840,9 @@ const std = @import("std");
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
@@ -872,7 +852,9 @@ const std = @import("std");
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
@@ -882,9 +864,9 @@ const std = @import("std");
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
@@ -894,7 +876,9 @@ const std = @import("std");
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
@@ -904,9 +888,9 @@ const std = @import("std");
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
@@ -916,7 +900,9 @@ const std = @import("std");
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
@@ -926,9 +912,9 @@ const std = @import("std");
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
@@ -938,7 +924,9 @@ const std = @import("std");
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
@@ -948,9 +936,9 @@ const std = @import("std");
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
@@ -960,7 +948,9 @@ const std = @import("std");
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
@@ -974,35 +964,45 @@ const std = @import("std");
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
+// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
+// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
+// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
+// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
+// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
+// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
+// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
+// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
+// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
+// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
+// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
+// :73:27: note: when computing vector element at index '1'
+// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '1'
+// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '1'
+// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '1'
+// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '1'
// :73:30: error: use of undefined value here causes illegal behavior
// :73:30: note: when computing vector element at index '0'
// :73:30: error: use of undefined value here causes illegal behavior
@@ -1050,50 +1050,30 @@ const std = @import("std");
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '1'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '1'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '1'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '1'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
@@ -1102,10 +1082,6 @@ const std = @import("std");
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '1'
-// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '1'
-// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
@@ -1114,7 +1090,9 @@ const std = @import("std");
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
+// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
+// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
@@ -1124,9 +1102,9 @@ const std = @import("std");
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '1'
+// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '1'
+// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
@@ -1136,7 +1114,9 @@ const std = @import("std");
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
+// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
+// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
@@ -1146,9 +1126,9 @@ const std = @import("std");
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '1'
+// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '1'
+// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
@@ -1158,7 +1138,9 @@ const std = @import("std");
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
+// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
+// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
@@ -1168,9 +1150,9 @@ const std = @import("std");
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '1'
+// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '1'
+// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
@@ -1180,7 +1162,9 @@ const std = @import("std");
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
+// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
+// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
@@ -1190,9 +1174,9 @@ const std = @import("std");
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '1'
+// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '1'
+// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
@@ -1202,7 +1186,9 @@ const std = @import("std");
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
+// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
+// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
@@ -1212,9 +1198,9 @@ const std = @import("std");
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '1'
+// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '1'
+// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
@@ -1224,7 +1210,9 @@ const std = @import("std");
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
+// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
+// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
@@ -1234,9 +1222,9 @@ const std = @import("std");
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '1'
+// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '1'
+// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
@@ -1246,7 +1234,9 @@ const std = @import("std");
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
+// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
+// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '0'
// :77:27: error: use of undefined value here causes illegal behavior
@@ -1260,35 +1250,45 @@ const std = @import("std");
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '1'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '0'
+// :77:27: note: when computing vector element at index '1'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '0'
+// :77:27: note: when computing vector element at index '1'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '0'
+// :77:27: note: when computing vector element at index '1'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '0'
+// :77:27: note: when computing vector element at index '1'
// :77:27: error: use of undefined value here causes illegal behavior
+// :77:27: note: when computing vector element at index '1'
// :77:27: error: use of undefined value here causes illegal behavior
+// :77:27: note: when computing vector element at index '1'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '0'
+// :77:27: note: when computing vector element at index '1'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '0'
+// :77:27: note: when computing vector element at index '1'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '0'
+// :77:27: note: when computing vector element at index '1'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '0'
+// :77:27: note: when computing vector element at index '1'
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '1'
// :77:27: error: use of undefined value here causes illegal behavior
// :77:27: note: when computing vector element at index '1'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '0'
+// :77:27: note: when computing vector element at index '1'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '0'
+// :77:27: note: when computing vector element at index '1'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '0'
+// :77:27: note: when computing vector element at index '1'
// :77:27: error: use of undefined value here causes illegal behavior
-// :77:27: note: when computing vector element at index '0'
+// :77:27: note: when computing vector element at index '1'
+// :77:27: error: use of undefined value here causes illegal behavior
+// :77:27: note: when computing vector element at index '1'
+// :77:27: error: use of undefined value here causes illegal behavior
+// :77:27: note: when computing vector element at index '1'
+// :77:27: error: use of undefined value here causes illegal behavior
+// :77:27: note: when computing vector element at index '1'
+// :77:27: error: use of undefined value here causes illegal behavior
+// :77:27: note: when computing vector element at index '1'
// :77:30: error: use of undefined value here causes illegal behavior
// :77:30: note: when computing vector element at index '0'
// :77:30: error: use of undefined value here causes illegal behavior
@@ -1336,50 +1336,30 @@ const std = @import("std");
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '1'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '1'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '1'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '1'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
@@ -1388,10 +1368,6 @@ const std = @import("std");
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '1'
-// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '1'
-// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
@@ -1400,7 +1376,9 @@ const std = @import("std");
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
+// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
+// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
@@ -1410,9 +1388,9 @@ const std = @import("std");
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '1'
+// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '1'
+// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
@@ -1422,7 +1400,9 @@ const std = @import("std");
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
+// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
+// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
@@ -1432,9 +1412,9 @@ const std = @import("std");
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '1'
+// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '1'
+// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
@@ -1444,7 +1424,9 @@ const std = @import("std");
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
+// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
+// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
@@ -1454,9 +1436,9 @@ const std = @import("std");
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '1'
+// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '1'
+// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
@@ -1466,7 +1448,9 @@ const std = @import("std");
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
+// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
+// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
@@ -1476,9 +1460,9 @@ const std = @import("std");
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '1'
+// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '1'
+// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
@@ -1488,7 +1472,9 @@ const std = @import("std");
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
+// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
+// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
@@ -1498,9 +1484,9 @@ const std = @import("std");
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '1'
+// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '1'
+// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
@@ -1510,7 +1496,9 @@ const std = @import("std");
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
+// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
+// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
@@ -1520,9 +1508,9 @@ const std = @import("std");
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '1'
+// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '1'
+// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
@@ -1532,7 +1520,9 @@ const std = @import("std");
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
+// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
+// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '0'
// :81:17: error: use of undefined value here causes illegal behavior
@@ -1546,35 +1536,45 @@ const std = @import("std");
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '1'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '0'
+// :81:17: note: when computing vector element at index '1'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '0'
+// :81:17: note: when computing vector element at index '1'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '0'
+// :81:17: note: when computing vector element at index '1'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '0'
+// :81:17: note: when computing vector element at index '1'
// :81:17: error: use of undefined value here causes illegal behavior
+// :81:17: note: when computing vector element at index '1'
// :81:17: error: use of undefined value here causes illegal behavior
+// :81:17: note: when computing vector element at index '1'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '0'
+// :81:17: note: when computing vector element at index '1'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '0'
+// :81:17: note: when computing vector element at index '1'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '0'
+// :81:17: note: when computing vector element at index '1'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '0'
+// :81:17: note: when computing vector element at index '1'
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '1'
// :81:17: error: use of undefined value here causes illegal behavior
// :81:17: note: when computing vector element at index '1'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '0'
+// :81:17: note: when computing vector element at index '1'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '0'
+// :81:17: note: when computing vector element at index '1'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '0'
+// :81:17: note: when computing vector element at index '1'
// :81:17: error: use of undefined value here causes illegal behavior
-// :81:17: note: when computing vector element at index '0'
+// :81:17: note: when computing vector element at index '1'
+// :81:17: error: use of undefined value here causes illegal behavior
+// :81:17: note: when computing vector element at index '1'
+// :81:17: error: use of undefined value here causes illegal behavior
+// :81:17: note: when computing vector element at index '1'
+// :81:17: error: use of undefined value here causes illegal behavior
+// :81:17: note: when computing vector element at index '1'
+// :81:17: error: use of undefined value here causes illegal behavior
+// :81:17: note: when computing vector element at index '1'
// :81:21: error: use of undefined value here causes illegal behavior
// :81:21: note: when computing vector element at index '0'
// :81:21: error: use of undefined value here causes illegal behavior
@@ -1622,39 +1622,25 @@ const std = @import("std");
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '1'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '1'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '1'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '1'
+// :85:22: error: use of undefined value here causes illegal behavior
+// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
@@ -1664,7 +1650,9 @@ const std = @import("std");
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
+// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
+// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
@@ -1674,9 +1662,9 @@ const std = @import("std");
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '1'
+// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '1'
+// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
@@ -1686,7 +1674,9 @@ const std = @import("std");
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
+// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
+// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
@@ -1696,9 +1686,9 @@ const std = @import("std");
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '1'
+// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '1'
+// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
@@ -1708,7 +1698,9 @@ const std = @import("std");
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
+// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
+// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
@@ -1718,10 +1710,6 @@ const std = @import("std");
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '1'
-// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '1'
-// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
@@ -1730,8 +1718,6 @@ const std = @import("std");
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
@@ -1740,10 +1726,6 @@ const std = @import("std");
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '1'
-// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '1'
-// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
@@ -1752,7 +1734,9 @@ const std = @import("std");
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
+// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
+// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
@@ -1762,9 +1746,9 @@ const std = @import("std");
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '1'
+// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '1'
+// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
@@ -1774,7 +1758,9 @@ const std = @import("std");
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
+// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
+// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
@@ -1784,9 +1770,9 @@ const std = @import("std");
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '1'
+// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '1'
+// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
@@ -1796,7 +1782,9 @@ const std = @import("std");
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
+// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
+// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
@@ -1806,9 +1794,9 @@ const std = @import("std");
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '1'
+// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '1'
+// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
@@ -1818,7 +1806,9 @@ const std = @import("std");
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
+// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
+// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '0'
// :85:22: error: use of undefined value here causes illegal behavior
@@ -1832,35 +1822,45 @@ const std = @import("std");
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '1'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '0'
+// :85:22: note: when computing vector element at index '1'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '0'
+// :85:22: note: when computing vector element at index '1'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '0'
+// :85:22: note: when computing vector element at index '1'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '0'
+// :85:22: note: when computing vector element at index '1'
// :85:22: error: use of undefined value here causes illegal behavior
+// :85:22: note: when computing vector element at index '1'
// :85:22: error: use of undefined value here causes illegal behavior
+// :85:22: note: when computing vector element at index '1'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '0'
+// :85:22: note: when computing vector element at index '1'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '0'
+// :85:22: note: when computing vector element at index '1'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '0'
+// :85:22: note: when computing vector element at index '1'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '0'
+// :85:22: note: when computing vector element at index '1'
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '1'
// :85:22: error: use of undefined value here causes illegal behavior
// :85:22: note: when computing vector element at index '1'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '0'
+// :85:22: note: when computing vector element at index '1'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '0'
+// :85:22: note: when computing vector element at index '1'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '0'
+// :85:22: note: when computing vector element at index '1'
// :85:22: error: use of undefined value here causes illegal behavior
-// :85:22: note: when computing vector element at index '0'
+// :85:22: note: when computing vector element at index '1'
+// :85:22: error: use of undefined value here causes illegal behavior
+// :85:22: note: when computing vector element at index '1'
+// :85:22: error: use of undefined value here causes illegal behavior
+// :85:22: note: when computing vector element at index '1'
+// :85:22: error: use of undefined value here causes illegal behavior
+// :85:22: note: when computing vector element at index '1'
+// :85:22: error: use of undefined value here causes illegal behavior
+// :85:22: note: when computing vector element at index '1'
// :85:25: error: use of undefined value here causes illegal behavior
// :85:25: note: when computing vector element at index '0'
// :85:25: error: use of undefined value here causes illegal behavior
@@ -1908,50 +1908,30 @@ const std = @import("std");
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '1'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '1'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '1'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '1'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
@@ -1960,10 +1940,6 @@ const std = @import("std");
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '1'
-// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '1'
-// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
@@ -1972,7 +1948,9 @@ const std = @import("std");
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
+// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
+// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
@@ -1982,9 +1960,9 @@ const std = @import("std");
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '1'
+// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '1'
+// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
@@ -1994,7 +1972,9 @@ const std = @import("std");
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
+// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
+// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
@@ -2004,9 +1984,9 @@ const std = @import("std");
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '1'
+// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '1'
+// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
@@ -2016,7 +1996,9 @@ const std = @import("std");
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
+// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
+// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
@@ -2026,9 +2008,9 @@ const std = @import("std");
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '1'
+// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '1'
+// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
@@ -2038,7 +2020,9 @@ const std = @import("std");
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
+// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
+// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
@@ -2048,9 +2032,9 @@ const std = @import("std");
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '1'
+// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '1'
+// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
@@ -2060,7 +2044,9 @@ const std = @import("std");
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
+// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
+// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
@@ -2070,9 +2056,9 @@ const std = @import("std");
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '1'
+// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '1'
+// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
@@ -2082,7 +2068,9 @@ const std = @import("std");
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
+// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
+// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
@@ -2092,9 +2080,9 @@ const std = @import("std");
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '1'
+// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '1'
+// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
@@ -2104,7 +2092,9 @@ const std = @import("std");
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
+// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
+// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '0'
// :89:22: error: use of undefined value here causes illegal behavior
@@ -2118,35 +2108,45 @@ const std = @import("std");
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '1'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '0'
+// :89:22: note: when computing vector element at index '1'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '0'
+// :89:22: note: when computing vector element at index '1'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '0'
+// :89:22: note: when computing vector element at index '1'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '0'
+// :89:22: note: when computing vector element at index '1'
// :89:22: error: use of undefined value here causes illegal behavior
+// :89:22: note: when computing vector element at index '1'
// :89:22: error: use of undefined value here causes illegal behavior
+// :89:22: note: when computing vector element at index '1'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '0'
+// :89:22: note: when computing vector element at index '1'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '0'
+// :89:22: note: when computing vector element at index '1'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '0'
+// :89:22: note: when computing vector element at index '1'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '0'
+// :89:22: note: when computing vector element at index '1'
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '1'
// :89:22: error: use of undefined value here causes illegal behavior
// :89:22: note: when computing vector element at index '1'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '0'
+// :89:22: note: when computing vector element at index '1'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '0'
+// :89:22: note: when computing vector element at index '1'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '0'
+// :89:22: note: when computing vector element at index '1'
// :89:22: error: use of undefined value here causes illegal behavior
-// :89:22: note: when computing vector element at index '0'
+// :89:22: note: when computing vector element at index '1'
+// :89:22: error: use of undefined value here causes illegal behavior
+// :89:22: note: when computing vector element at index '1'
+// :89:22: error: use of undefined value here causes illegal behavior
+// :89:22: note: when computing vector element at index '1'
+// :89:22: error: use of undefined value here causes illegal behavior
+// :89:22: note: when computing vector element at index '1'
+// :89:22: error: use of undefined value here causes illegal behavior
+// :89:22: note: when computing vector element at index '1'
// :89:25: error: use of undefined value here causes illegal behavior
// :89:25: note: when computing vector element at index '0'
// :89:25: error: use of undefined value here causes illegal behavior
@@ -2198,21 +2198,13 @@ const std = @import("std");
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: error: use of undefined value here causes illegal behavior
@@ -2220,21 +2212,13 @@ const std = @import("std");
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: error: use of undefined value here causes illegal behavior
@@ -2242,21 +2226,13 @@ const std = @import("std");
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: error: use of undefined value here causes illegal behavior
@@ -2264,21 +2240,13 @@ const std = @import("std");
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: error: use of undefined value here causes illegal behavior
@@ -2286,13 +2254,9 @@ const std = @import("std");
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
@@ -2302,19 +2266,21 @@ const std = @import("std");
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
-// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
-// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
+// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
+// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
@@ -2324,19 +2290,25 @@ const std = @import("std");
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
+// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
+// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
+// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
+// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
@@ -2346,19 +2318,25 @@ const std = @import("std");
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
+// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
+// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
+// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '1'
+// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
@@ -2368,11 +2346,17 @@ const std = @import("std");
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: note: when computing vector element at index '0'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
@@ -2382,19 +2366,25 @@ const std = @import("std");
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '0'
+// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '0'
+// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '0'
+// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '0'
+// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
@@ -2404,19 +2394,25 @@ const std = @import("std");
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '0'
+// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '0'
+// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '0'
+// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '0'
+// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
@@ -2426,13 +2422,17 @@ const std = @import("std");
// :95:17: error: use of undefined value here causes illegal behavior
// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '0'
+// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '0'
+// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '0'
+// :95:17: note: when computing vector element at index '1'
// :95:17: error: use of undefined value here causes illegal behavior
-// :95:17: note: when computing vector element at index '0'
+// :95:17: note: when computing vector element at index '1'
+// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '1'
+// :95:17: error: use of undefined value here causes illegal behavior
+// :95:17: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: error: use of undefined value here causes illegal behavior
@@ -2440,21 +2440,13 @@ const std = @import("std");
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: error: use of undefined value here causes illegal behavior
@@ -2462,21 +2454,13 @@ const std = @import("std");
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: error: use of undefined value here causes illegal behavior
@@ -2484,21 +2468,13 @@ const std = @import("std");
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: error: use of undefined value here causes illegal behavior
@@ -2506,21 +2482,13 @@ const std = @import("std");
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: error: use of undefined value here causes illegal behavior
@@ -2528,13 +2496,9 @@ const std = @import("std");
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
@@ -2544,19 +2508,21 @@ const std = @import("std");
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
-// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
-// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
@@ -2566,19 +2532,25 @@ const std = @import("std");
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
@@ -2588,19 +2560,25 @@ const std = @import("std");
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
@@ -2610,11 +2588,17 @@ const std = @import("std");
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
@@ -2624,19 +2608,25 @@ const std = @import("std");
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
@@ -2646,19 +2636,25 @@ const std = @import("std");
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
@@ -2668,13 +2664,17 @@ const std = @import("std");
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
+// :99:27: note: when computing vector element at index '1'
+// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '1'
+// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: error: use of undefined value here causes illegal behavior
@@ -2682,21 +2682,13 @@ const std = @import("std");
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: error: use of undefined value here causes illegal behavior
@@ -2704,21 +2696,13 @@ const std = @import("std");
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: error: use of undefined value here causes illegal behavior
@@ -2726,21 +2710,13 @@ const std = @import("std");
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: error: use of undefined value here causes illegal behavior
@@ -2748,21 +2724,13 @@ const std = @import("std");
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: error: use of undefined value here causes illegal behavior
@@ -2770,13 +2738,9 @@ const std = @import("std");
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
@@ -2786,19 +2750,21 @@ const std = @import("std");
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
-// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
-// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
+// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
+// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
@@ -2808,19 +2774,25 @@ const std = @import("std");
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
+// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
+// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
+// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
+// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
@@ -2830,19 +2802,25 @@ const std = @import("std");
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
+// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
+// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
+// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '1'
+// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
@@ -2852,11 +2830,17 @@ const std = @import("std");
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: note: when computing vector element at index '0'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
@@ -2866,19 +2850,25 @@ const std = @import("std");
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '0'
+// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '0'
+// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '0'
+// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '0'
+// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
@@ -2888,19 +2878,25 @@ const std = @import("std");
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '0'
+// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '0'
+// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '0'
+// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '0'
+// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
@@ -2910,13 +2906,17 @@ const std = @import("std");
// :103:27: error: use of undefined value here causes illegal behavior
// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '0'
+// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '0'
+// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '0'
+// :103:27: note: when computing vector element at index '1'
// :103:27: error: use of undefined value here causes illegal behavior
-// :103:27: note: when computing vector element at index '0'
+// :103:27: note: when computing vector element at index '1'
+// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '1'
+// :103:27: error: use of undefined value here causes illegal behavior
+// :103:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: error: use of undefined value here causes illegal behavior
@@ -2924,21 +2924,13 @@ const std = @import("std");
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: error: use of undefined value here causes illegal behavior
@@ -2946,21 +2938,13 @@ const std = @import("std");
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: error: use of undefined value here causes illegal behavior
@@ -2968,21 +2952,13 @@ const std = @import("std");
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: error: use of undefined value here causes illegal behavior
@@ -2990,21 +2966,13 @@ const std = @import("std");
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: error: use of undefined value here causes illegal behavior
@@ -3012,13 +2980,9 @@ const std = @import("std");
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
@@ -3028,19 +2992,21 @@ const std = @import("std");
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
-// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
-// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
+// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
+// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
@@ -3050,19 +3016,25 @@ const std = @import("std");
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
+// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
+// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
+// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
+// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
@@ -3072,19 +3044,25 @@ const std = @import("std");
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
+// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
+// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
+// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '1'
+// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
@@ -3094,11 +3072,17 @@ const std = @import("std");
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: note: when computing vector element at index '0'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
@@ -3108,19 +3092,25 @@ const std = @import("std");
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '0'
+// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '0'
+// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '0'
+// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '0'
+// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
@@ -3130,19 +3120,29 @@ const std = @import("std");
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '0'
+// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '0'
+// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '0'
+// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '0'
+// :107:27: note: when computing vector element at index '1'
+// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '1'
+// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
+// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
@@ -3152,13 +3152,13 @@ const std = @import("std");
// :107:27: error: use of undefined value here causes illegal behavior
// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '0'
+// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '0'
+// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '0'
+// :107:27: note: when computing vector element at index '1'
// :107:27: error: use of undefined value here causes illegal behavior
-// :107:27: note: when computing vector element at index '0'
+// :107:27: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: error: use of undefined value here causes illegal behavior
@@ -3166,21 +3166,13 @@ const std = @import("std");
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: error: use of undefined value here causes illegal behavior
@@ -3188,21 +3180,13 @@ const std = @import("std");
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: error: use of undefined value here causes illegal behavior
@@ -3210,21 +3194,13 @@ const std = @import("std");
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: error: use of undefined value here causes illegal behavior
@@ -3232,21 +3208,13 @@ const std = @import("std");
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: error: use of undefined value here causes illegal behavior
@@ -3254,13 +3222,9 @@ const std = @import("std");
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
@@ -3270,19 +3234,21 @@ const std = @import("std");
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
-// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
-// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
+// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
+// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
@@ -3292,19 +3258,25 @@ const std = @import("std");
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
+// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
+// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
+// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
+// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
@@ -3314,19 +3286,25 @@ const std = @import("std");
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
+// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
+// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
+// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '1'
+// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
@@ -3336,11 +3314,17 @@ const std = @import("std");
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: note: when computing vector element at index '0'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
@@ -3350,19 +3334,25 @@ const std = @import("std");
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '0'
+// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '0'
+// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '0'
+// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '0'
+// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
@@ -3372,19 +3362,25 @@ const std = @import("std");
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '0'
+// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '0'
+// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '0'
+// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '0'
+// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
@@ -3394,13 +3390,17 @@ const std = @import("std");
// :111:22: error: use of undefined value here causes illegal behavior
// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '0'
+// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '0'
+// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '0'
+// :111:22: note: when computing vector element at index '1'
// :111:22: error: use of undefined value here causes illegal behavior
-// :111:22: note: when computing vector element at index '0'
+// :111:22: note: when computing vector element at index '1'
+// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '1'
+// :111:22: error: use of undefined value here causes illegal behavior
+// :111:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: error: use of undefined value here causes illegal behavior
@@ -3408,21 +3408,13 @@ const std = @import("std");
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: error: use of undefined value here causes illegal behavior
@@ -3430,21 +3422,13 @@ const std = @import("std");
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: error: use of undefined value here causes illegal behavior
@@ -3452,21 +3436,13 @@ const std = @import("std");
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: error: use of undefined value here causes illegal behavior
@@ -3474,21 +3450,13 @@ const std = @import("std");
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: error: use of undefined value here causes illegal behavior
@@ -3496,13 +3464,9 @@ const std = @import("std");
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
@@ -3512,19 +3476,21 @@ const std = @import("std");
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
-// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
-// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
+// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
+// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
@@ -3534,19 +3500,25 @@ const std = @import("std");
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
+// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
+// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
+// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
+// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
@@ -3556,19 +3528,25 @@ const std = @import("std");
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
+// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
+// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
+// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '1'
+// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
@@ -3578,11 +3556,17 @@ const std = @import("std");
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: note: when computing vector element at index '0'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
@@ -3592,19 +3576,25 @@ const std = @import("std");
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '0'
+// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '0'
+// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '0'
+// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '0'
+// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
@@ -3614,19 +3604,27 @@ const std = @import("std");
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '0'
+// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '0'
+// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '0'
+// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '0'
+// :115:22: note: when computing vector element at index '1'
+// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
@@ -3636,37 +3634,32 @@ const std = @import("std");
// :115:22: error: use of undefined value here causes illegal behavior
// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '0'
+// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '0'
+// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '0'
+// :115:22: note: when computing vector element at index '1'
// :115:22: error: use of undefined value here causes illegal behavior
-// :115:22: note: when computing vector element at index '0'
+// :115:22: note: when computing vector element at index '1'
+// :115:22: error: use of undefined value here causes illegal behavior
+// :115:22: note: when computing vector element at index '1'
+// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: error: use of undefined value here causes illegal behavior
-// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
-// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
-// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
-// :121:17: note: when computing vector element at index '1'
// :121:17: error: use of undefined value here causes illegal behavior
-// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
-// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
-// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: error: use of undefined value here causes illegal behavior
-// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
-// :121:17: note: when computing vector element at index '1'
+// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
@@ -3674,6 +3667,7 @@ const std = @import("std");
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
+// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
@@ -3681,7 +3675,7 @@ const std = @import("std");
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
-// :121:17: note: when computing vector element at index '1'
+// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
@@ -3689,6 +3683,7 @@ const std = @import("std");
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
+// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
@@ -3696,7 +3691,7 @@ const std = @import("std");
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
-// :121:17: note: when computing vector element at index '1'
+// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
@@ -3704,6 +3699,7 @@ const std = @import("std");
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
+// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
@@ -3711,7 +3707,7 @@ const std = @import("std");
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
-// :121:17: note: when computing vector element at index '1'
+// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
@@ -3719,6 +3715,7 @@ const std = @import("std");
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
+// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
@@ -3726,7 +3723,7 @@ const std = @import("std");
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
-// :121:17: note: when computing vector element at index '1'
+// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
@@ -3734,6 +3731,7 @@ const std = @import("std");
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
+// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
@@ -3741,7 +3739,7 @@ const std = @import("std");
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
-// :121:17: note: when computing vector element at index '1'
+// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
@@ -3749,6 +3747,7 @@ const std = @import("std");
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
+// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
@@ -3756,7 +3755,7 @@ const std = @import("std");
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
-// :121:17: note: when computing vector element at index '1'
+// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
@@ -3764,6 +3763,7 @@ const std = @import("std");
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
+// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
@@ -3771,7 +3771,7 @@ const std = @import("std");
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
-// :121:17: note: when computing vector element at index '1'
+// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
@@ -3779,6 +3779,7 @@ const std = @import("std");
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
+// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '0'
// :121:17: error: use of undefined value here causes illegal behavior
@@ -3788,126 +3789,120 @@ const std = @import("std");
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '1'
// :121:17: error: use of undefined value here causes illegal behavior
-// :121:17: note: when computing vector element at index '0'
-// :121:17: error: use of undefined value here causes illegal behavior
-// :121:17: note: when computing vector element at index '0'
+// :121:17: note: when computing vector element at index '1'
// :121:17: error: use of undefined value here causes illegal behavior
-// :121:17: note: when computing vector element at index '0'
+// :121:17: note: when computing vector element at index '1'
// :121:17: error: use of undefined value here causes illegal behavior
+// :121:17: note: when computing vector element at index '1'
// :121:17: error: use of undefined value here causes illegal behavior
-// :121:17: note: when computing vector element at index '0'
+// :121:17: note: when computing vector element at index '1'
// :121:17: error: use of undefined value here causes illegal behavior
-// :121:17: note: when computing vector element at index '0'
+// :121:17: note: when computing vector element at index '1'
// :121:17: error: use of undefined value here causes illegal behavior
-// :121:17: note: when computing vector element at index '0'
+// :121:17: note: when computing vector element at index '1'
// :121:17: error: use of undefined value here causes illegal behavior
// :121:17: note: when computing vector element at index '1'
// :121:17: error: use of undefined value here causes illegal behavior
-// :121:17: note: when computing vector element at index '0'
+// :121:17: note: when computing vector element at index '1'
// :121:17: error: use of undefined value here causes illegal behavior
-// :121:17: note: when computing vector element at index '0'
+// :121:17: note: when computing vector element at index '1'
// :121:17: error: use of undefined value here causes illegal behavior
-// :121:17: note: when computing vector element at index '0'
+// :121:17: note: when computing vector element at index '1'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: error: use of undefined value here causes illegal behavior
-// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
-// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
-// :121:21: note: when computing vector element at index '1'
// :121:21: error: use of undefined value here causes illegal behavior
-// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
-// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: error: use of undefined value here causes illegal behavior
-// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
-// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
-// :121:21: note: when computing vector element at index '1'
// :121:21: error: use of undefined value here causes illegal behavior
-// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
-// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
-// :121:21: note: when computing vector element at index '1'
-// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
+// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
-// :121:21: note: when computing vector element at index '1'
+// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
+// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
-// :121:21: note: when computing vector element at index '1'
+// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
+// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
-// :121:21: note: when computing vector element at index '1'
+// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
+// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
-// :121:21: note: when computing vector element at index '1'
+// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
+// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
-// :121:21: note: when computing vector element at index '1'
+// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
+// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
-// :121:21: note: when computing vector element at index '1'
+// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
+// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '0'
// :121:21: error: use of undefined value here causes illegal behavior
@@ -3915,44 +3910,42 @@ const std = @import("std");
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '1'
// :121:21: error: use of undefined value here causes illegal behavior
-// :121:21: note: when computing vector element at index '0'
+// :121:21: note: when computing vector element at index '1'
// :121:21: error: use of undefined value here causes illegal behavior
-// :121:21: note: when computing vector element at index '0'
+// :121:21: note: when computing vector element at index '1'
// :121:21: error: use of undefined value here causes illegal behavior
+// :121:21: note: when computing vector element at index '1'
// :121:21: error: use of undefined value here causes illegal behavior
-// :121:21: note: when computing vector element at index '0'
+// :121:21: note: when computing vector element at index '1'
// :121:21: error: use of undefined value here causes illegal behavior
-// :121:21: note: when computing vector element at index '0'
+// :121:21: note: when computing vector element at index '1'
// :121:21: error: use of undefined value here causes illegal behavior
// :121:21: note: when computing vector element at index '1'
// :121:21: error: use of undefined value here causes illegal behavior
-// :121:21: note: when computing vector element at index '0'
+// :121:21: note: when computing vector element at index '1'
// :121:21: error: use of undefined value here causes illegal behavior
-// :121:21: note: when computing vector element at index '0'
+// :121:21: note: when computing vector element at index '1'
+// :121:21: error: use of undefined value here causes illegal behavior
+// :121:21: note: when computing vector element at index '1'
+// :121:21: error: use of undefined value here causes illegal behavior
+// :121:21: note: when computing vector element at index '1'
+// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: error: use of undefined value here causes illegal behavior
-// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
-// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
-// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
-// :125:27: note: when computing vector element at index '1'
// :125:27: error: use of undefined value here causes illegal behavior
-// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
-// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
-// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: error: use of undefined value here causes illegal behavior
-// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
-// :125:27: note: when computing vector element at index '1'
+// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
@@ -3960,6 +3953,7 @@ const std = @import("std");
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
+// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
@@ -3967,7 +3961,7 @@ const std = @import("std");
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
-// :125:27: note: when computing vector element at index '1'
+// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
@@ -3975,6 +3969,7 @@ const std = @import("std");
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
+// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
@@ -3982,7 +3977,7 @@ const std = @import("std");
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
-// :125:27: note: when computing vector element at index '1'
+// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
@@ -3990,6 +3985,7 @@ const std = @import("std");
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
+// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
@@ -3997,7 +3993,7 @@ const std = @import("std");
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
-// :125:27: note: when computing vector element at index '1'
+// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
@@ -4005,6 +4001,7 @@ const std = @import("std");
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
+// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
@@ -4012,7 +4009,7 @@ const std = @import("std");
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
-// :125:27: note: when computing vector element at index '1'
+// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
@@ -4020,6 +4017,7 @@ const std = @import("std");
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
+// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
@@ -4027,7 +4025,7 @@ const std = @import("std");
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
-// :125:27: note: when computing vector element at index '1'
+// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
@@ -4035,6 +4033,7 @@ const std = @import("std");
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
+// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
@@ -4042,7 +4041,7 @@ const std = @import("std");
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
-// :125:27: note: when computing vector element at index '1'
+// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
@@ -4050,6 +4049,7 @@ const std = @import("std");
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
+// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
@@ -4057,7 +4057,7 @@ const std = @import("std");
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
-// :125:27: note: when computing vector element at index '1'
+// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
@@ -4065,6 +4065,7 @@ const std = @import("std");
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
+// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '0'
// :125:27: error: use of undefined value here causes illegal behavior
@@ -4074,126 +4075,120 @@ const std = @import("std");
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '1'
// :125:27: error: use of undefined value here causes illegal behavior
-// :125:27: note: when computing vector element at index '0'
-// :125:27: error: use of undefined value here causes illegal behavior
-// :125:27: note: when computing vector element at index '0'
+// :125:27: note: when computing vector element at index '1'
// :125:27: error: use of undefined value here causes illegal behavior
-// :125:27: note: when computing vector element at index '0'
+// :125:27: note: when computing vector element at index '1'
// :125:27: error: use of undefined value here causes illegal behavior
+// :125:27: note: when computing vector element at index '1'
// :125:27: error: use of undefined value here causes illegal behavior
-// :125:27: note: when computing vector element at index '0'
+// :125:27: note: when computing vector element at index '1'
// :125:27: error: use of undefined value here causes illegal behavior
-// :125:27: note: when computing vector element at index '0'
+// :125:27: note: when computing vector element at index '1'
// :125:27: error: use of undefined value here causes illegal behavior
-// :125:27: note: when computing vector element at index '0'
+// :125:27: note: when computing vector element at index '1'
// :125:27: error: use of undefined value here causes illegal behavior
// :125:27: note: when computing vector element at index '1'
// :125:27: error: use of undefined value here causes illegal behavior
-// :125:27: note: when computing vector element at index '0'
+// :125:27: note: when computing vector element at index '1'
// :125:27: error: use of undefined value here causes illegal behavior
-// :125:27: note: when computing vector element at index '0'
+// :125:27: note: when computing vector element at index '1'
// :125:27: error: use of undefined value here causes illegal behavior
-// :125:27: note: when computing vector element at index '0'
+// :125:27: note: when computing vector element at index '1'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: error: use of undefined value here causes illegal behavior
-// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
-// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
-// :125:30: note: when computing vector element at index '1'
// :125:30: error: use of undefined value here causes illegal behavior
-// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
-// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: error: use of undefined value here causes illegal behavior
-// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
-// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
-// :125:30: note: when computing vector element at index '1'
// :125:30: error: use of undefined value here causes illegal behavior
-// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
-// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
-// :125:30: note: when computing vector element at index '1'
-// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
+// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
-// :125:30: note: when computing vector element at index '1'
+// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
+// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
-// :125:30: note: when computing vector element at index '1'
+// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
+// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
-// :125:30: note: when computing vector element at index '1'
+// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
+// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
-// :125:30: note: when computing vector element at index '1'
+// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
+// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
-// :125:30: note: when computing vector element at index '1'
+// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
+// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
-// :125:30: note: when computing vector element at index '1'
+// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
+// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '0'
// :125:30: error: use of undefined value here causes illegal behavior
@@ -4201,44 +4196,42 @@ const std = @import("std");
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '1'
// :125:30: error: use of undefined value here causes illegal behavior
-// :125:30: note: when computing vector element at index '0'
+// :125:30: note: when computing vector element at index '1'
// :125:30: error: use of undefined value here causes illegal behavior
-// :125:30: note: when computing vector element at index '0'
+// :125:30: note: when computing vector element at index '1'
// :125:30: error: use of undefined value here causes illegal behavior
+// :125:30: note: when computing vector element at index '1'
// :125:30: error: use of undefined value here causes illegal behavior
-// :125:30: note: when computing vector element at index '0'
+// :125:30: note: when computing vector element at index '1'
// :125:30: error: use of undefined value here causes illegal behavior
-// :125:30: note: when computing vector element at index '0'
+// :125:30: note: when computing vector element at index '1'
// :125:30: error: use of undefined value here causes illegal behavior
// :125:30: note: when computing vector element at index '1'
// :125:30: error: use of undefined value here causes illegal behavior
-// :125:30: note: when computing vector element at index '0'
+// :125:30: note: when computing vector element at index '1'
// :125:30: error: use of undefined value here causes illegal behavior
-// :125:30: note: when computing vector element at index '0'
+// :125:30: note: when computing vector element at index '1'
+// :125:30: error: use of undefined value here causes illegal behavior
+// :125:30: note: when computing vector element at index '1'
+// :125:30: error: use of undefined value here causes illegal behavior
+// :125:30: note: when computing vector element at index '1'
+// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: error: use of undefined value here causes illegal behavior
-// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
-// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
-// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
-// :129:27: note: when computing vector element at index '1'
// :129:27: error: use of undefined value here causes illegal behavior
-// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
-// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
-// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: error: use of undefined value here causes illegal behavior
-// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
-// :129:27: note: when computing vector element at index '1'
+// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
@@ -4246,6 +4239,7 @@ const std = @import("std");
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
+// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
@@ -4253,7 +4247,7 @@ const std = @import("std");
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
-// :129:27: note: when computing vector element at index '1'
+// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
@@ -4261,6 +4255,7 @@ const std = @import("std");
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
+// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
@@ -4268,7 +4263,7 @@ const std = @import("std");
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
-// :129:27: note: when computing vector element at index '1'
+// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
@@ -4276,6 +4271,7 @@ const std = @import("std");
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
+// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
@@ -4283,7 +4279,7 @@ const std = @import("std");
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
-// :129:27: note: when computing vector element at index '1'
+// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
@@ -4291,6 +4287,7 @@ const std = @import("std");
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
+// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
@@ -4298,7 +4295,7 @@ const std = @import("std");
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
-// :129:27: note: when computing vector element at index '1'
+// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
@@ -4306,6 +4303,7 @@ const std = @import("std");
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
+// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
@@ -4313,7 +4311,7 @@ const std = @import("std");
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
-// :129:27: note: when computing vector element at index '1'
+// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
@@ -4321,6 +4319,7 @@ const std = @import("std");
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
+// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
@@ -4328,7 +4327,7 @@ const std = @import("std");
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
-// :129:27: note: when computing vector element at index '1'
+// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
@@ -4336,6 +4335,7 @@ const std = @import("std");
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
+// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
@@ -4343,7 +4343,7 @@ const std = @import("std");
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
-// :129:27: note: when computing vector element at index '1'
+// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
@@ -4351,6 +4351,7 @@ const std = @import("std");
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
+// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '0'
// :129:27: error: use of undefined value here causes illegal behavior
@@ -4360,126 +4361,120 @@ const std = @import("std");
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '1'
// :129:27: error: use of undefined value here causes illegal behavior
-// :129:27: note: when computing vector element at index '0'
-// :129:27: error: use of undefined value here causes illegal behavior
-// :129:27: note: when computing vector element at index '0'
+// :129:27: note: when computing vector element at index '1'
// :129:27: error: use of undefined value here causes illegal behavior
-// :129:27: note: when computing vector element at index '0'
+// :129:27: note: when computing vector element at index '1'
// :129:27: error: use of undefined value here causes illegal behavior
+// :129:27: note: when computing vector element at index '1'
// :129:27: error: use of undefined value here causes illegal behavior
-// :129:27: note: when computing vector element at index '0'
+// :129:27: note: when computing vector element at index '1'
// :129:27: error: use of undefined value here causes illegal behavior
-// :129:27: note: when computing vector element at index '0'
+// :129:27: note: when computing vector element at index '1'
// :129:27: error: use of undefined value here causes illegal behavior
-// :129:27: note: when computing vector element at index '0'
+// :129:27: note: when computing vector element at index '1'
// :129:27: error: use of undefined value here causes illegal behavior
// :129:27: note: when computing vector element at index '1'
// :129:27: error: use of undefined value here causes illegal behavior
-// :129:27: note: when computing vector element at index '0'
+// :129:27: note: when computing vector element at index '1'
// :129:27: error: use of undefined value here causes illegal behavior
-// :129:27: note: when computing vector element at index '0'
+// :129:27: note: when computing vector element at index '1'
// :129:27: error: use of undefined value here causes illegal behavior
-// :129:27: note: when computing vector element at index '0'
+// :129:27: note: when computing vector element at index '1'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: error: use of undefined value here causes illegal behavior
-// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
-// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
-// :129:30: note: when computing vector element at index '1'
// :129:30: error: use of undefined value here causes illegal behavior
-// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
-// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: error: use of undefined value here causes illegal behavior
-// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
-// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
-// :129:30: note: when computing vector element at index '1'
// :129:30: error: use of undefined value here causes illegal behavior
-// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
-// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
-// :129:30: note: when computing vector element at index '1'
-// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
+// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
-// :129:30: note: when computing vector element at index '1'
+// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
+// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
-// :129:30: note: when computing vector element at index '1'
+// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
+// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
-// :129:30: note: when computing vector element at index '1'
+// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
+// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
-// :129:30: note: when computing vector element at index '1'
+// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
+// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
-// :129:30: note: when computing vector element at index '1'
+// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
+// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
-// :129:30: note: when computing vector element at index '1'
+// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
+// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '0'
// :129:30: error: use of undefined value here causes illegal behavior
@@ -4487,44 +4482,42 @@ const std = @import("std");
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '1'
// :129:30: error: use of undefined value here causes illegal behavior
-// :129:30: note: when computing vector element at index '0'
+// :129:30: note: when computing vector element at index '1'
// :129:30: error: use of undefined value here causes illegal behavior
-// :129:30: note: when computing vector element at index '0'
+// :129:30: note: when computing vector element at index '1'
+// :129:30: error: use of undefined value here causes illegal behavior
+// :129:30: note: when computing vector element at index '1'
// :129:30: error: use of undefined value here causes illegal behavior
+// :129:30: note: when computing vector element at index '1'
// :129:30: error: use of undefined value here causes illegal behavior
-// :129:30: note: when computing vector element at index '0'
+// :129:30: note: when computing vector element at index '1'
// :129:30: error: use of undefined value here causes illegal behavior
-// :129:30: note: when computing vector element at index '0'
+// :129:30: note: when computing vector element at index '1'
// :129:30: error: use of undefined value here causes illegal behavior
// :129:30: note: when computing vector element at index '1'
// :129:30: error: use of undefined value here causes illegal behavior
-// :129:30: note: when computing vector element at index '0'
+// :129:30: note: when computing vector element at index '1'
// :129:30: error: use of undefined value here causes illegal behavior
-// :129:30: note: when computing vector element at index '0'
+// :129:30: note: when computing vector element at index '1'
+// :129:30: error: use of undefined value here causes illegal behavior
+// :129:30: note: when computing vector element at index '1'
+// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: error: use of undefined value here causes illegal behavior
-// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
-// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
-// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
-// :133:27: note: when computing vector element at index '1'
// :133:27: error: use of undefined value here causes illegal behavior
-// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
-// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
-// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: error: use of undefined value here causes illegal behavior
-// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
-// :133:27: note: when computing vector element at index '1'
+// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
@@ -4532,6 +4525,7 @@ const std = @import("std");
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
+// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
@@ -4539,7 +4533,7 @@ const std = @import("std");
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
-// :133:27: note: when computing vector element at index '1'
+// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
@@ -4547,6 +4541,7 @@ const std = @import("std");
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
+// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
@@ -4554,7 +4549,7 @@ const std = @import("std");
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
-// :133:27: note: when computing vector element at index '1'
+// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
@@ -4562,6 +4557,7 @@ const std = @import("std");
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
+// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
@@ -4569,7 +4565,7 @@ const std = @import("std");
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
-// :133:27: note: when computing vector element at index '1'
+// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
@@ -4577,6 +4573,7 @@ const std = @import("std");
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
+// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
@@ -4584,7 +4581,7 @@ const std = @import("std");
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
-// :133:27: note: when computing vector element at index '1'
+// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
@@ -4592,6 +4589,7 @@ const std = @import("std");
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
+// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
@@ -4599,7 +4597,7 @@ const std = @import("std");
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
-// :133:27: note: when computing vector element at index '1'
+// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
@@ -4607,6 +4605,7 @@ const std = @import("std");
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
+// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
@@ -4614,7 +4613,7 @@ const std = @import("std");
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
-// :133:27: note: when computing vector element at index '1'
+// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
@@ -4622,6 +4621,7 @@ const std = @import("std");
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
+// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
@@ -4629,7 +4629,7 @@ const std = @import("std");
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
-// :133:27: note: when computing vector element at index '1'
+// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
@@ -4637,6 +4637,7 @@ const std = @import("std");
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
+// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '0'
// :133:27: error: use of undefined value here causes illegal behavior
@@ -4646,126 +4647,120 @@ const std = @import("std");
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '1'
// :133:27: error: use of undefined value here causes illegal behavior
-// :133:27: note: when computing vector element at index '0'
-// :133:27: error: use of undefined value here causes illegal behavior
-// :133:27: note: when computing vector element at index '0'
+// :133:27: note: when computing vector element at index '1'
// :133:27: error: use of undefined value here causes illegal behavior
-// :133:27: note: when computing vector element at index '0'
+// :133:27: note: when computing vector element at index '1'
// :133:27: error: use of undefined value here causes illegal behavior
+// :133:27: note: when computing vector element at index '1'
// :133:27: error: use of undefined value here causes illegal behavior
-// :133:27: note: when computing vector element at index '0'
+// :133:27: note: when computing vector element at index '1'
// :133:27: error: use of undefined value here causes illegal behavior
-// :133:27: note: when computing vector element at index '0'
+// :133:27: note: when computing vector element at index '1'
// :133:27: error: use of undefined value here causes illegal behavior
-// :133:27: note: when computing vector element at index '0'
+// :133:27: note: when computing vector element at index '1'
// :133:27: error: use of undefined value here causes illegal behavior
// :133:27: note: when computing vector element at index '1'
// :133:27: error: use of undefined value here causes illegal behavior
-// :133:27: note: when computing vector element at index '0'
+// :133:27: note: when computing vector element at index '1'
// :133:27: error: use of undefined value here causes illegal behavior
-// :133:27: note: when computing vector element at index '0'
+// :133:27: note: when computing vector element at index '1'
// :133:27: error: use of undefined value here causes illegal behavior
-// :133:27: note: when computing vector element at index '0'
+// :133:27: note: when computing vector element at index '1'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: error: use of undefined value here causes illegal behavior
-// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
-// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
-// :133:30: note: when computing vector element at index '1'
// :133:30: error: use of undefined value here causes illegal behavior
-// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
-// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: error: use of undefined value here causes illegal behavior
-// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
-// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
-// :133:30: note: when computing vector element at index '1'
// :133:30: error: use of undefined value here causes illegal behavior
-// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
-// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
-// :133:30: note: when computing vector element at index '1'
-// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
+// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
-// :133:30: note: when computing vector element at index '1'
+// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
+// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
-// :133:30: note: when computing vector element at index '1'
+// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
+// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
-// :133:30: note: when computing vector element at index '1'
+// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
+// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
-// :133:30: note: when computing vector element at index '1'
+// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
+// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
-// :133:30: note: when computing vector element at index '1'
+// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
+// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
-// :133:30: note: when computing vector element at index '1'
+// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
+// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '0'
// :133:30: error: use of undefined value here causes illegal behavior
@@ -4773,44 +4768,42 @@ const std = @import("std");
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '1'
// :133:30: error: use of undefined value here causes illegal behavior
-// :133:30: note: when computing vector element at index '0'
+// :133:30: note: when computing vector element at index '1'
// :133:30: error: use of undefined value here causes illegal behavior
-// :133:30: note: when computing vector element at index '0'
+// :133:30: note: when computing vector element at index '1'
// :133:30: error: use of undefined value here causes illegal behavior
+// :133:30: note: when computing vector element at index '1'
// :133:30: error: use of undefined value here causes illegal behavior
-// :133:30: note: when computing vector element at index '0'
+// :133:30: note: when computing vector element at index '1'
// :133:30: error: use of undefined value here causes illegal behavior
-// :133:30: note: when computing vector element at index '0'
+// :133:30: note: when computing vector element at index '1'
// :133:30: error: use of undefined value here causes illegal behavior
// :133:30: note: when computing vector element at index '1'
// :133:30: error: use of undefined value here causes illegal behavior
-// :133:30: note: when computing vector element at index '0'
+// :133:30: note: when computing vector element at index '1'
// :133:30: error: use of undefined value here causes illegal behavior
-// :133:30: note: when computing vector element at index '0'
+// :133:30: note: when computing vector element at index '1'
+// :133:30: error: use of undefined value here causes illegal behavior
+// :133:30: note: when computing vector element at index '1'
+// :133:30: error: use of undefined value here causes illegal behavior
+// :133:30: note: when computing vector element at index '1'
+// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: error: use of undefined value here causes illegal behavior
-// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
-// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
-// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
-// :137:17: note: when computing vector element at index '1'
// :137:17: error: use of undefined value here causes illegal behavior
-// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
-// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
-// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: error: use of undefined value here causes illegal behavior
-// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
-// :137:17: note: when computing vector element at index '1'
+// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
@@ -4818,6 +4811,7 @@ const std = @import("std");
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
+// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
@@ -4825,7 +4819,7 @@ const std = @import("std");
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
-// :137:17: note: when computing vector element at index '1'
+// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
@@ -4833,6 +4827,7 @@ const std = @import("std");
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
+// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
@@ -4840,7 +4835,7 @@ const std = @import("std");
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
-// :137:17: note: when computing vector element at index '1'
+// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
@@ -4848,6 +4843,7 @@ const std = @import("std");
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
+// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
@@ -4855,7 +4851,7 @@ const std = @import("std");
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
-// :137:17: note: when computing vector element at index '1'
+// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
@@ -4863,6 +4859,7 @@ const std = @import("std");
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
+// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
@@ -4870,7 +4867,7 @@ const std = @import("std");
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
-// :137:17: note: when computing vector element at index '1'
+// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
@@ -4878,6 +4875,7 @@ const std = @import("std");
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
+// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
@@ -4885,7 +4883,7 @@ const std = @import("std");
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
-// :137:17: note: when computing vector element at index '1'
+// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
@@ -4893,6 +4891,7 @@ const std = @import("std");
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
+// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
@@ -4900,7 +4899,7 @@ const std = @import("std");
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
-// :137:17: note: when computing vector element at index '1'
+// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
@@ -4908,6 +4907,7 @@ const std = @import("std");
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
+// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
@@ -4915,7 +4915,7 @@ const std = @import("std");
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
-// :137:17: note: when computing vector element at index '1'
+// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
@@ -4923,6 +4923,7 @@ const std = @import("std");
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
+// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '0'
// :137:17: error: use of undefined value here causes illegal behavior
@@ -4932,126 +4933,120 @@ const std = @import("std");
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '1'
// :137:17: error: use of undefined value here causes illegal behavior
-// :137:17: note: when computing vector element at index '0'
-// :137:17: error: use of undefined value here causes illegal behavior
-// :137:17: note: when computing vector element at index '0'
+// :137:17: note: when computing vector element at index '1'
// :137:17: error: use of undefined value here causes illegal behavior
-// :137:17: note: when computing vector element at index '0'
+// :137:17: note: when computing vector element at index '1'
// :137:17: error: use of undefined value here causes illegal behavior
+// :137:17: note: when computing vector element at index '1'
// :137:17: error: use of undefined value here causes illegal behavior
-// :137:17: note: when computing vector element at index '0'
+// :137:17: note: when computing vector element at index '1'
// :137:17: error: use of undefined value here causes illegal behavior
-// :137:17: note: when computing vector element at index '0'
+// :137:17: note: when computing vector element at index '1'
// :137:17: error: use of undefined value here causes illegal behavior
-// :137:17: note: when computing vector element at index '0'
+// :137:17: note: when computing vector element at index '1'
// :137:17: error: use of undefined value here causes illegal behavior
// :137:17: note: when computing vector element at index '1'
// :137:17: error: use of undefined value here causes illegal behavior
-// :137:17: note: when computing vector element at index '0'
+// :137:17: note: when computing vector element at index '1'
// :137:17: error: use of undefined value here causes illegal behavior
-// :137:17: note: when computing vector element at index '0'
+// :137:17: note: when computing vector element at index '1'
// :137:17: error: use of undefined value here causes illegal behavior
-// :137:17: note: when computing vector element at index '0'
+// :137:17: note: when computing vector element at index '1'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: error: use of undefined value here causes illegal behavior
-// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
-// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
-// :137:21: note: when computing vector element at index '1'
// :137:21: error: use of undefined value here causes illegal behavior
-// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
-// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: error: use of undefined value here causes illegal behavior
-// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
-// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
-// :137:21: note: when computing vector element at index '1'
// :137:21: error: use of undefined value here causes illegal behavior
-// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
-// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
-// :137:21: note: when computing vector element at index '1'
-// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
+// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
-// :137:21: note: when computing vector element at index '1'
+// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
+// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
-// :137:21: note: when computing vector element at index '1'
+// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
+// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
-// :137:21: note: when computing vector element at index '1'
+// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
+// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
-// :137:21: note: when computing vector element at index '1'
+// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
+// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
-// :137:21: note: when computing vector element at index '1'
+// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
+// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
-// :137:21: note: when computing vector element at index '1'
+// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
+// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '0'
// :137:21: error: use of undefined value here causes illegal behavior
@@ -5059,44 +5054,42 @@ const std = @import("std");
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '1'
// :137:21: error: use of undefined value here causes illegal behavior
-// :137:21: note: when computing vector element at index '0'
+// :137:21: note: when computing vector element at index '1'
// :137:21: error: use of undefined value here causes illegal behavior
-// :137:21: note: when computing vector element at index '0'
+// :137:21: note: when computing vector element at index '1'
// :137:21: error: use of undefined value here causes illegal behavior
+// :137:21: note: when computing vector element at index '1'
// :137:21: error: use of undefined value here causes illegal behavior
-// :137:21: note: when computing vector element at index '0'
+// :137:21: note: when computing vector element at index '1'
// :137:21: error: use of undefined value here causes illegal behavior
-// :137:21: note: when computing vector element at index '0'
+// :137:21: note: when computing vector element at index '1'
// :137:21: error: use of undefined value here causes illegal behavior
// :137:21: note: when computing vector element at index '1'
// :137:21: error: use of undefined value here causes illegal behavior
-// :137:21: note: when computing vector element at index '0'
+// :137:21: note: when computing vector element at index '1'
// :137:21: error: use of undefined value here causes illegal behavior
-// :137:21: note: when computing vector element at index '0'
+// :137:21: note: when computing vector element at index '1'
+// :137:21: error: use of undefined value here causes illegal behavior
+// :137:21: note: when computing vector element at index '1'
+// :137:21: error: use of undefined value here causes illegal behavior
+// :137:21: note: when computing vector element at index '1'
+// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: error: use of undefined value here causes illegal behavior
-// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
-// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
-// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
-// :141:22: note: when computing vector element at index '1'
// :141:22: error: use of undefined value here causes illegal behavior
-// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
-// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
-// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: error: use of undefined value here causes illegal behavior
-// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
-// :141:22: note: when computing vector element at index '1'
+// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
@@ -5104,6 +5097,7 @@ const std = @import("std");
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
+// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
@@ -5111,7 +5105,7 @@ const std = @import("std");
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
-// :141:22: note: when computing vector element at index '1'
+// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
@@ -5119,6 +5113,7 @@ const std = @import("std");
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
+// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
@@ -5126,7 +5121,7 @@ const std = @import("std");
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
-// :141:22: note: when computing vector element at index '1'
+// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
@@ -5134,6 +5129,7 @@ const std = @import("std");
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
+// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
@@ -5141,7 +5137,7 @@ const std = @import("std");
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
-// :141:22: note: when computing vector element at index '1'
+// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
@@ -5149,6 +5145,7 @@ const std = @import("std");
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
+// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
@@ -5156,7 +5153,7 @@ const std = @import("std");
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
-// :141:22: note: when computing vector element at index '1'
+// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
@@ -5164,6 +5161,7 @@ const std = @import("std");
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
+// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
@@ -5171,7 +5169,7 @@ const std = @import("std");
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
-// :141:22: note: when computing vector element at index '1'
+// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
@@ -5179,6 +5177,7 @@ const std = @import("std");
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
+// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
@@ -5186,7 +5185,7 @@ const std = @import("std");
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
-// :141:22: note: when computing vector element at index '1'
+// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
@@ -5194,6 +5193,7 @@ const std = @import("std");
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
+// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
@@ -5201,7 +5201,7 @@ const std = @import("std");
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
-// :141:22: note: when computing vector element at index '1'
+// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
@@ -5209,6 +5209,7 @@ const std = @import("std");
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
+// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '0'
// :141:22: error: use of undefined value here causes illegal behavior
@@ -5218,126 +5219,120 @@ const std = @import("std");
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '1'
// :141:22: error: use of undefined value here causes illegal behavior
-// :141:22: note: when computing vector element at index '0'
-// :141:22: error: use of undefined value here causes illegal behavior
-// :141:22: note: when computing vector element at index '0'
+// :141:22: note: when computing vector element at index '1'
// :141:22: error: use of undefined value here causes illegal behavior
-// :141:22: note: when computing vector element at index '0'
+// :141:22: note: when computing vector element at index '1'
// :141:22: error: use of undefined value here causes illegal behavior
+// :141:22: note: when computing vector element at index '1'
// :141:22: error: use of undefined value here causes illegal behavior
-// :141:22: note: when computing vector element at index '0'
+// :141:22: note: when computing vector element at index '1'
// :141:22: error: use of undefined value here causes illegal behavior
-// :141:22: note: when computing vector element at index '0'
+// :141:22: note: when computing vector element at index '1'
// :141:22: error: use of undefined value here causes illegal behavior
-// :141:22: note: when computing vector element at index '0'
+// :141:22: note: when computing vector element at index '1'
// :141:22: error: use of undefined value here causes illegal behavior
// :141:22: note: when computing vector element at index '1'
// :141:22: error: use of undefined value here causes illegal behavior
-// :141:22: note: when computing vector element at index '0'
+// :141:22: note: when computing vector element at index '1'
// :141:22: error: use of undefined value here causes illegal behavior
-// :141:22: note: when computing vector element at index '0'
+// :141:22: note: when computing vector element at index '1'
// :141:22: error: use of undefined value here causes illegal behavior
-// :141:22: note: when computing vector element at index '0'
+// :141:22: note: when computing vector element at index '1'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: error: use of undefined value here causes illegal behavior
-// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
-// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
-// :141:25: note: when computing vector element at index '1'
// :141:25: error: use of undefined value here causes illegal behavior
-// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
-// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: error: use of undefined value here causes illegal behavior
-// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
-// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
-// :141:25: note: when computing vector element at index '1'
// :141:25: error: use of undefined value here causes illegal behavior
-// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
-// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
-// :141:25: note: when computing vector element at index '1'
-// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
+// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
-// :141:25: note: when computing vector element at index '1'
+// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
+// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
-// :141:25: note: when computing vector element at index '1'
+// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
+// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
-// :141:25: note: when computing vector element at index '1'
+// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
+// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
-// :141:25: note: when computing vector element at index '1'
+// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
+// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
-// :141:25: note: when computing vector element at index '1'
+// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
+// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
-// :141:25: note: when computing vector element at index '1'
+// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
+// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '0'
// :141:25: error: use of undefined value here causes illegal behavior
@@ -5345,44 +5340,42 @@ const std = @import("std");
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '1'
// :141:25: error: use of undefined value here causes illegal behavior
-// :141:25: note: when computing vector element at index '0'
+// :141:25: note: when computing vector element at index '1'
// :141:25: error: use of undefined value here causes illegal behavior
-// :141:25: note: when computing vector element at index '0'
+// :141:25: note: when computing vector element at index '1'
// :141:25: error: use of undefined value here causes illegal behavior
+// :141:25: note: when computing vector element at index '1'
// :141:25: error: use of undefined value here causes illegal behavior
-// :141:25: note: when computing vector element at index '0'
+// :141:25: note: when computing vector element at index '1'
// :141:25: error: use of undefined value here causes illegal behavior
-// :141:25: note: when computing vector element at index '0'
+// :141:25: note: when computing vector element at index '1'
// :141:25: error: use of undefined value here causes illegal behavior
// :141:25: note: when computing vector element at index '1'
// :141:25: error: use of undefined value here causes illegal behavior
-// :141:25: note: when computing vector element at index '0'
+// :141:25: note: when computing vector element at index '1'
// :141:25: error: use of undefined value here causes illegal behavior
-// :141:25: note: when computing vector element at index '0'
+// :141:25: note: when computing vector element at index '1'
+// :141:25: error: use of undefined value here causes illegal behavior
+// :141:25: note: when computing vector element at index '1'
+// :141:25: error: use of undefined value here causes illegal behavior
+// :141:25: note: when computing vector element at index '1'
+// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: error: use of undefined value here causes illegal behavior
-// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
-// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
-// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
-// :145:22: note: when computing vector element at index '1'
// :145:22: error: use of undefined value here causes illegal behavior
-// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
-// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
-// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: error: use of undefined value here causes illegal behavior
-// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
-// :145:22: note: when computing vector element at index '1'
+// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
@@ -5390,6 +5383,7 @@ const std = @import("std");
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
+// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
@@ -5397,7 +5391,7 @@ const std = @import("std");
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
-// :145:22: note: when computing vector element at index '1'
+// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
@@ -5405,6 +5399,7 @@ const std = @import("std");
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
+// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
@@ -5412,7 +5407,7 @@ const std = @import("std");
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
-// :145:22: note: when computing vector element at index '1'
+// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
@@ -5420,6 +5415,7 @@ const std = @import("std");
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
+// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
@@ -5427,7 +5423,7 @@ const std = @import("std");
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
-// :145:22: note: when computing vector element at index '1'
+// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
@@ -5435,6 +5431,7 @@ const std = @import("std");
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
+// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
@@ -5442,7 +5439,7 @@ const std = @import("std");
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
-// :145:22: note: when computing vector element at index '1'
+// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
@@ -5450,6 +5447,7 @@ const std = @import("std");
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
+// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
@@ -5457,7 +5455,7 @@ const std = @import("std");
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
-// :145:22: note: when computing vector element at index '1'
+// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
@@ -5465,6 +5463,7 @@ const std = @import("std");
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
+// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
@@ -5472,7 +5471,7 @@ const std = @import("std");
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
-// :145:22: note: when computing vector element at index '1'
+// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
@@ -5480,6 +5479,7 @@ const std = @import("std");
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
+// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
@@ -5487,7 +5487,7 @@ const std = @import("std");
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
-// :145:22: note: when computing vector element at index '1'
+// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
@@ -5495,6 +5495,7 @@ const std = @import("std");
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
+// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '0'
// :145:22: error: use of undefined value here causes illegal behavior
@@ -5504,126 +5505,120 @@ const std = @import("std");
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '1'
// :145:22: error: use of undefined value here causes illegal behavior
-// :145:22: note: when computing vector element at index '0'
-// :145:22: error: use of undefined value here causes illegal behavior
-// :145:22: note: when computing vector element at index '0'
+// :145:22: note: when computing vector element at index '1'
// :145:22: error: use of undefined value here causes illegal behavior
-// :145:22: note: when computing vector element at index '0'
+// :145:22: note: when computing vector element at index '1'
// :145:22: error: use of undefined value here causes illegal behavior
+// :145:22: note: when computing vector element at index '1'
// :145:22: error: use of undefined value here causes illegal behavior
-// :145:22: note: when computing vector element at index '0'
+// :145:22: note: when computing vector element at index '1'
// :145:22: error: use of undefined value here causes illegal behavior
-// :145:22: note: when computing vector element at index '0'
+// :145:22: note: when computing vector element at index '1'
// :145:22: error: use of undefined value here causes illegal behavior
-// :145:22: note: when computing vector element at index '0'
+// :145:22: note: when computing vector element at index '1'
// :145:22: error: use of undefined value here causes illegal behavior
// :145:22: note: when computing vector element at index '1'
// :145:22: error: use of undefined value here causes illegal behavior
-// :145:22: note: when computing vector element at index '0'
+// :145:22: note: when computing vector element at index '1'
// :145:22: error: use of undefined value here causes illegal behavior
-// :145:22: note: when computing vector element at index '0'
+// :145:22: note: when computing vector element at index '1'
// :145:22: error: use of undefined value here causes illegal behavior
-// :145:22: note: when computing vector element at index '0'
+// :145:22: note: when computing vector element at index '1'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: error: use of undefined value here causes illegal behavior
-// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
-// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
-// :145:25: note: when computing vector element at index '1'
// :145:25: error: use of undefined value here causes illegal behavior
-// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
-// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: error: use of undefined value here causes illegal behavior
-// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
-// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
-// :145:25: note: when computing vector element at index '1'
// :145:25: error: use of undefined value here causes illegal behavior
-// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
-// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
-// :145:25: note: when computing vector element at index '1'
-// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
+// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
-// :145:25: note: when computing vector element at index '1'
+// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
+// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
-// :145:25: note: when computing vector element at index '1'
+// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
+// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
-// :145:25: note: when computing vector element at index '1'
+// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
+// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
-// :145:25: note: when computing vector element at index '1'
+// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
+// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
-// :145:25: note: when computing vector element at index '1'
+// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
+// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
-// :145:25: note: when computing vector element at index '1'
+// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
+// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '0'
// :145:25: error: use of undefined value here causes illegal behavior
@@ -5631,20 +5626,25 @@ const std = @import("std");
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '1'
// :145:25: error: use of undefined value here causes illegal behavior
-// :145:25: note: when computing vector element at index '0'
+// :145:25: note: when computing vector element at index '1'
// :145:25: error: use of undefined value here causes illegal behavior
-// :145:25: note: when computing vector element at index '0'
+// :145:25: note: when computing vector element at index '1'
+// :145:25: error: use of undefined value here causes illegal behavior
+// :145:25: note: when computing vector element at index '1'
// :145:25: error: use of undefined value here causes illegal behavior
+// :145:25: note: when computing vector element at index '1'
// :145:25: error: use of undefined value here causes illegal behavior
-// :145:25: note: when computing vector element at index '0'
+// :145:25: note: when computing vector element at index '1'
// :145:25: error: use of undefined value here causes illegal behavior
-// :145:25: note: when computing vector element at index '0'
+// :145:25: note: when computing vector element at index '1'
// :145:25: error: use of undefined value here causes illegal behavior
// :145:25: note: when computing vector element at index '1'
// :145:25: error: use of undefined value here causes illegal behavior
-// :145:25: note: when computing vector element at index '0'
+// :145:25: note: when computing vector element at index '1'
// :145:25: error: use of undefined value here causes illegal behavior
-// :145:25: note: when computing vector element at index '0'
+// :145:25: note: when computing vector element at index '1'
+// :145:25: error: use of undefined value here causes illegal behavior
+// :145:25: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: error: use of undefined value here causes illegal behavior
@@ -5652,21 +5652,13 @@ const std = @import("std");
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: error: use of undefined value here causes illegal behavior
@@ -5674,21 +5666,13 @@ const std = @import("std");
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: error: use of undefined value here causes illegal behavior
@@ -5696,21 +5680,13 @@ const std = @import("std");
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: error: use of undefined value here causes illegal behavior
@@ -5718,21 +5694,13 @@ const std = @import("std");
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: error: use of undefined value here causes illegal behavior
@@ -5740,13 +5708,9 @@ const std = @import("std");
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
@@ -5756,19 +5720,21 @@ const std = @import("std");
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
-// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
-// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
+// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
+// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
@@ -5778,19 +5744,25 @@ const std = @import("std");
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
+// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
+// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
+// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
+// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
@@ -5800,19 +5772,25 @@ const std = @import("std");
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
+// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
+// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
+// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '1'
+// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
@@ -5822,11 +5800,17 @@ const std = @import("std");
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: note: when computing vector element at index '0'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
@@ -5836,19 +5820,25 @@ const std = @import("std");
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '0'
+// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '0'
+// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '0'
+// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '0'
+// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
@@ -5858,19 +5848,25 @@ const std = @import("std");
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '0'
+// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '0'
+// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '0'
+// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '0'
+// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
@@ -5880,13 +5876,17 @@ const std = @import("std");
// :151:21: error: use of undefined value here causes illegal behavior
// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '0'
+// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '0'
+// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '0'
+// :151:21: note: when computing vector element at index '1'
// :151:21: error: use of undefined value here causes illegal behavior
-// :151:21: note: when computing vector element at index '0'
+// :151:21: note: when computing vector element at index '1'
+// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '1'
+// :151:21: error: use of undefined value here causes illegal behavior
+// :151:21: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: error: use of undefined value here causes illegal behavior
@@ -5894,21 +5894,13 @@ const std = @import("std");
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: error: use of undefined value here causes illegal behavior
@@ -5916,21 +5908,13 @@ const std = @import("std");
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: error: use of undefined value here causes illegal behavior
@@ -5938,21 +5922,13 @@ const std = @import("std");
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: error: use of undefined value here causes illegal behavior
@@ -5960,21 +5936,13 @@ const std = @import("std");
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: error: use of undefined value here causes illegal behavior
@@ -5982,13 +5950,9 @@ const std = @import("std");
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
@@ -5998,19 +5962,21 @@ const std = @import("std");
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
-// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
-// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
+// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
+// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
@@ -6020,19 +5986,25 @@ const std = @import("std");
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
+// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
+// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
+// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
+// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
@@ -6042,19 +6014,25 @@ const std = @import("std");
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
+// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
+// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
+// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '1'
+// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
@@ -6064,11 +6042,17 @@ const std = @import("std");
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: note: when computing vector element at index '0'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
@@ -6078,19 +6062,25 @@ const std = @import("std");
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '0'
+// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '0'
+// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '0'
+// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '0'
+// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
@@ -6100,19 +6090,25 @@ const std = @import("std");
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '0'
+// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '0'
+// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '0'
+// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '0'
+// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
@@ -6122,13 +6118,17 @@ const std = @import("std");
// :155:30: error: use of undefined value here causes illegal behavior
// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '0'
+// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '0'
+// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '0'
+// :155:30: note: when computing vector element at index '1'
// :155:30: error: use of undefined value here causes illegal behavior
-// :155:30: note: when computing vector element at index '0'
+// :155:30: note: when computing vector element at index '1'
+// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '1'
+// :155:30: error: use of undefined value here causes illegal behavior
+// :155:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: error: use of undefined value here causes illegal behavior
@@ -6136,21 +6136,13 @@ const std = @import("std");
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: error: use of undefined value here causes illegal behavior
@@ -6158,21 +6150,13 @@ const std = @import("std");
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: error: use of undefined value here causes illegal behavior
@@ -6180,21 +6164,13 @@ const std = @import("std");
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: error: use of undefined value here causes illegal behavior
@@ -6202,21 +6178,13 @@ const std = @import("std");
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: error: use of undefined value here causes illegal behavior
@@ -6224,13 +6192,9 @@ const std = @import("std");
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
@@ -6240,19 +6204,21 @@ const std = @import("std");
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
-// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
-// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
+// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
+// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
@@ -6262,19 +6228,25 @@ const std = @import("std");
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
+// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
+// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
+// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
+// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
@@ -6284,19 +6256,25 @@ const std = @import("std");
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
+// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
+// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
+// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '1'
+// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
@@ -6306,11 +6284,17 @@ const std = @import("std");
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: note: when computing vector element at index '0'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
@@ -6320,19 +6304,25 @@ const std = @import("std");
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '0'
+// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '0'
+// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '0'
+// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '0'
+// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
@@ -6342,19 +6332,27 @@ const std = @import("std");
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '0'
+// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '0'
+// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '0'
+// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '0'
+// :159:30: note: when computing vector element at index '1'
+// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
@@ -6364,13 +6362,15 @@ const std = @import("std");
// :159:30: error: use of undefined value here causes illegal behavior
// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '0'
+// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '0'
+// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '0'
+// :159:30: note: when computing vector element at index '1'
// :159:30: error: use of undefined value here causes illegal behavior
-// :159:30: note: when computing vector element at index '0'
+// :159:30: note: when computing vector element at index '1'
+// :159:30: error: use of undefined value here causes illegal behavior
+// :159:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: error: use of undefined value here causes illegal behavior
@@ -6378,21 +6378,13 @@ const std = @import("std");
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: error: use of undefined value here causes illegal behavior
@@ -6400,21 +6392,13 @@ const std = @import("std");
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: error: use of undefined value here causes illegal behavior
@@ -6422,21 +6406,13 @@ const std = @import("std");
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: error: use of undefined value here causes illegal behavior
@@ -6444,21 +6420,13 @@ const std = @import("std");
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: error: use of undefined value here causes illegal behavior
@@ -6466,13 +6434,9 @@ const std = @import("std");
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
@@ -6482,19 +6446,21 @@ const std = @import("std");
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
-// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
-// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
+// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
+// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
@@ -6504,19 +6470,25 @@ const std = @import("std");
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
+// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
+// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
+// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
+// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
@@ -6526,19 +6498,25 @@ const std = @import("std");
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
+// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
+// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
+// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '1'
+// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
@@ -6548,11 +6526,19 @@ const std = @import("std");
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: note: when computing vector element at index '0'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '1'
+// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
@@ -6562,19 +6548,27 @@ const std = @import("std");
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '0'
+// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '0'
+// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '0'
+// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '0'
+// :163:30: note: when computing vector element at index '1'
+// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
@@ -6584,19 +6578,25 @@ const std = @import("std");
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '0'
+// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '0'
+// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '0'
+// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '0'
+// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
+// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
@@ -6606,13 +6606,13 @@ const std = @import("std");
// :163:30: error: use of undefined value here causes illegal behavior
// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '0'
+// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '0'
+// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '0'
+// :163:30: note: when computing vector element at index '1'
// :163:30: error: use of undefined value here causes illegal behavior
-// :163:30: note: when computing vector element at index '0'
+// :163:30: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: error: use of undefined value here causes illegal behavior
@@ -6620,21 +6620,13 @@ const std = @import("std");
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: error: use of undefined value here causes illegal behavior
@@ -6642,21 +6634,13 @@ const std = @import("std");
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: error: use of undefined value here causes illegal behavior
@@ -6664,21 +6648,13 @@ const std = @import("std");
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: error: use of undefined value here causes illegal behavior
@@ -6686,21 +6662,13 @@ const std = @import("std");
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: error: use of undefined value here causes illegal behavior
@@ -6708,13 +6676,9 @@ const std = @import("std");
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
@@ -6724,19 +6688,21 @@ const std = @import("std");
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
-// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
-// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
+// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
+// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
@@ -6746,19 +6712,25 @@ const std = @import("std");
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
+// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
+// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
+// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
+// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
@@ -6768,19 +6740,25 @@ const std = @import("std");
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
+// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
+// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
+// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '1'
+// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
@@ -6790,11 +6768,21 @@ const std = @import("std");
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: note: when computing vector element at index '0'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '1'
+// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '1'
+// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
@@ -6804,19 +6792,25 @@ const std = @import("std");
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '0'
+// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '0'
+// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '0'
+// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '0'
+// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
@@ -6826,19 +6820,25 @@ const std = @import("std");
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '0'
+// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '0'
+// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '0'
+// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '0'
+// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
+// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
@@ -6848,13 +6848,13 @@ const std = @import("std");
// :167:25: error: use of undefined value here causes illegal behavior
// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '0'
+// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '0'
+// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '0'
+// :167:25: note: when computing vector element at index '1'
// :167:25: error: use of undefined value here causes illegal behavior
-// :167:25: note: when computing vector element at index '0'
+// :167:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: error: use of undefined value here causes illegal behavior
@@ -6862,21 +6862,13 @@ const std = @import("std");
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: error: use of undefined value here causes illegal behavior
@@ -6884,21 +6876,13 @@ const std = @import("std");
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: error: use of undefined value here causes illegal behavior
@@ -6906,21 +6890,13 @@ const std = @import("std");
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: error: use of undefined value here causes illegal behavior
@@ -6928,21 +6904,13 @@ const std = @import("std");
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: error: use of undefined value here causes illegal behavior
@@ -6950,13 +6918,9 @@ const std = @import("std");
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
@@ -6966,19 +6930,21 @@ const std = @import("std");
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
-// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
-// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
+// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
+// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
@@ -6988,19 +6954,25 @@ const std = @import("std");
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
+// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
+// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
+// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
+// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
@@ -7010,19 +6982,25 @@ const std = @import("std");
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
+// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
+// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
+// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '1'
+// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
@@ -7032,11 +7010,17 @@ const std = @import("std");
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: note: when computing vector element at index '0'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
@@ -7046,19 +7030,25 @@ const std = @import("std");
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '0'
+// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '0'
+// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '0'
+// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '0'
+// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
@@ -7068,19 +7058,25 @@ const std = @import("std");
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '0'
+// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '0'
+// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '0'
+// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '0'
+// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
@@ -7090,37 +7086,33 @@ const std = @import("std");
// :171:25: error: use of undefined value here causes illegal behavior
// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '0'
+// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '0'
+// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '0'
+// :171:25: note: when computing vector element at index '1'
// :171:25: error: use of undefined value here causes illegal behavior
-// :171:25: note: when computing vector element at index '0'
+// :171:25: note: when computing vector element at index '1'
+// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '1'
+// :171:25: error: use of undefined value here causes illegal behavior
+// :171:25: note: when computing vector element at index '1'
// :177:17: error: use of undefined value here causes illegal behavior
// :177:17: error: use of undefined value here causes illegal behavior
// :177:17: error: use of undefined value here causes illegal behavior
-// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
-// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
-// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
-// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
-// :177:17: note: when computing vector element at index '1'
// :177:17: error: use of undefined value here causes illegal behavior
-// :177:17: note: when computing vector element at index '1'
// :177:17: error: use of undefined value here causes illegal behavior
-// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
-// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
-// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
-// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
+// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
+// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
@@ -7130,9 +7122,9 @@ const std = @import("std");
// :177:17: error: use of undefined value here causes illegal behavior
// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
-// :177:17: note: when computing vector element at index '1'
+// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
-// :177:17: note: when computing vector element at index '1'
+// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
@@ -7142,7 +7134,9 @@ const std = @import("std");
// :177:17: error: use of undefined value here causes illegal behavior
// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
+// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
+// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
@@ -7152,9 +7146,9 @@ const std = @import("std");
// :177:17: error: use of undefined value here causes illegal behavior
// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
-// :177:17: note: when computing vector element at index '1'
+// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
-// :177:17: note: when computing vector element at index '1'
+// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
@@ -7164,7 +7158,9 @@ const std = @import("std");
// :177:17: error: use of undefined value here causes illegal behavior
// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
+// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
+// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
@@ -7174,9 +7170,9 @@ const std = @import("std");
// :177:17: error: use of undefined value here causes illegal behavior
// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
-// :177:17: note: when computing vector element at index '1'
+// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
-// :177:17: note: when computing vector element at index '1'
+// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
@@ -7186,7 +7182,9 @@ const std = @import("std");
// :177:17: error: use of undefined value here causes illegal behavior
// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
+// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
+// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
@@ -7196,9 +7194,9 @@ const std = @import("std");
// :177:17: error: use of undefined value here causes illegal behavior
// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
-// :177:17: note: when computing vector element at index '1'
+// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
-// :177:17: note: when computing vector element at index '1'
+// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
@@ -7208,27 +7206,29 @@ const std = @import("std");
// :177:17: error: use of undefined value here causes illegal behavior
// :177:17: note: when computing vector element at index '0'
// :177:17: error: use of undefined value here causes illegal behavior
+// :177:17: note: when computing vector element at index '1'
// :177:17: error: use of undefined value here causes illegal behavior
+// :177:17: note: when computing vector element at index '1'
// :177:17: error: use of undefined value here causes illegal behavior
-// :177:17: note: when computing vector element at index '0'
+// :177:17: note: when computing vector element at index '1'
// :177:17: error: use of undefined value here causes illegal behavior
-// :177:17: note: when computing vector element at index '0'
+// :177:17: note: when computing vector element at index '1'
// :177:17: error: use of undefined value here causes illegal behavior
-// :177:17: note: when computing vector element at index '0'
+// :177:17: note: when computing vector element at index '1'
// :177:17: error: use of undefined value here causes illegal behavior
-// :177:17: note: when computing vector element at index '0'
+// :177:17: note: when computing vector element at index '1'
// :177:17: error: use of undefined value here causes illegal behavior
// :177:17: note: when computing vector element at index '1'
// :177:17: error: use of undefined value here causes illegal behavior
// :177:17: note: when computing vector element at index '1'
// :177:17: error: use of undefined value here causes illegal behavior
-// :177:17: note: when computing vector element at index '0'
+// :177:17: note: when computing vector element at index '1'
// :177:17: error: use of undefined value here causes illegal behavior
-// :177:17: note: when computing vector element at index '0'
+// :177:17: note: when computing vector element at index '1'
// :177:17: error: use of undefined value here causes illegal behavior
-// :177:17: note: when computing vector element at index '0'
+// :177:17: note: when computing vector element at index '1'
// :177:17: error: use of undefined value here causes illegal behavior
-// :177:17: note: when computing vector element at index '0'
+// :177:17: note: when computing vector element at index '1'
// :177:21: error: use of undefined value here causes illegal behavior
// :177:21: note: when computing vector element at index '0'
// :177:21: error: use of undefined value here causes illegal behavior
@@ -7256,27 +7256,19 @@ const std = @import("std");
// :180:17: error: use of undefined value here causes illegal behavior
// :180:17: error: use of undefined value here causes illegal behavior
// :180:17: error: use of undefined value here causes illegal behavior
-// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
-// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
-// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
-// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
-// :180:17: note: when computing vector element at index '1'
// :180:17: error: use of undefined value here causes illegal behavior
-// :180:17: note: when computing vector element at index '1'
// :180:17: error: use of undefined value here causes illegal behavior
-// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
-// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
-// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
-// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
+// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
+// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
@@ -7286,9 +7278,9 @@ const std = @import("std");
// :180:17: error: use of undefined value here causes illegal behavior
// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
-// :180:17: note: when computing vector element at index '1'
+// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
-// :180:17: note: when computing vector element at index '1'
+// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
@@ -7298,7 +7290,9 @@ const std = @import("std");
// :180:17: error: use of undefined value here causes illegal behavior
// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
+// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
+// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
@@ -7308,9 +7302,9 @@ const std = @import("std");
// :180:17: error: use of undefined value here causes illegal behavior
// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
-// :180:17: note: when computing vector element at index '1'
+// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
-// :180:17: note: when computing vector element at index '1'
+// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
@@ -7320,7 +7314,9 @@ const std = @import("std");
// :180:17: error: use of undefined value here causes illegal behavior
// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
+// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
+// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
@@ -7330,9 +7326,9 @@ const std = @import("std");
// :180:17: error: use of undefined value here causes illegal behavior
// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
-// :180:17: note: when computing vector element at index '1'
+// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
-// :180:17: note: when computing vector element at index '1'
+// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
@@ -7342,7 +7338,9 @@ const std = @import("std");
// :180:17: error: use of undefined value here causes illegal behavior
// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
+// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
+// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
@@ -7352,9 +7350,9 @@ const std = @import("std");
// :180:17: error: use of undefined value here causes illegal behavior
// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
-// :180:17: note: when computing vector element at index '1'
+// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
-// :180:17: note: when computing vector element at index '1'
+// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
@@ -7364,27 +7362,29 @@ const std = @import("std");
// :180:17: error: use of undefined value here causes illegal behavior
// :180:17: note: when computing vector element at index '0'
// :180:17: error: use of undefined value here causes illegal behavior
+// :180:17: note: when computing vector element at index '1'
// :180:17: error: use of undefined value here causes illegal behavior
+// :180:17: note: when computing vector element at index '1'
// :180:17: error: use of undefined value here causes illegal behavior
-// :180:17: note: when computing vector element at index '0'
+// :180:17: note: when computing vector element at index '1'
// :180:17: error: use of undefined value here causes illegal behavior
-// :180:17: note: when computing vector element at index '0'
+// :180:17: note: when computing vector element at index '1'
// :180:17: error: use of undefined value here causes illegal behavior
-// :180:17: note: when computing vector element at index '0'
+// :180:17: note: when computing vector element at index '1'
// :180:17: error: use of undefined value here causes illegal behavior
-// :180:17: note: when computing vector element at index '0'
+// :180:17: note: when computing vector element at index '1'
// :180:17: error: use of undefined value here causes illegal behavior
// :180:17: note: when computing vector element at index '1'
// :180:17: error: use of undefined value here causes illegal behavior
// :180:17: note: when computing vector element at index '1'
// :180:17: error: use of undefined value here causes illegal behavior
-// :180:17: note: when computing vector element at index '0'
+// :180:17: note: when computing vector element at index '1'
// :180:17: error: use of undefined value here causes illegal behavior
-// :180:17: note: when computing vector element at index '0'
+// :180:17: note: when computing vector element at index '1'
// :180:17: error: use of undefined value here causes illegal behavior
-// :180:17: note: when computing vector element at index '0'
+// :180:17: note: when computing vector element at index '1'
// :180:17: error: use of undefined value here causes illegal behavior
-// :180:17: note: when computing vector element at index '0'
+// :180:17: note: when computing vector element at index '1'
// :180:21: error: use of undefined value here causes illegal behavior
// :180:21: note: when computing vector element at index '0'
// :180:21: error: use of undefined value here causes illegal behavior
@@ -7412,27 +7412,19 @@ const std = @import("std");
// :183:17: error: use of undefined value here causes illegal behavior
// :183:17: error: use of undefined value here causes illegal behavior
// :183:17: error: use of undefined value here causes illegal behavior
-// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
-// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
-// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
-// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
-// :183:17: note: when computing vector element at index '1'
// :183:17: error: use of undefined value here causes illegal behavior
-// :183:17: note: when computing vector element at index '1'
// :183:17: error: use of undefined value here causes illegal behavior
-// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
-// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
-// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
-// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
+// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
+// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
@@ -7442,9 +7434,9 @@ const std = @import("std");
// :183:17: error: use of undefined value here causes illegal behavior
// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
-// :183:17: note: when computing vector element at index '1'
+// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
-// :183:17: note: when computing vector element at index '1'
+// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
@@ -7454,7 +7446,9 @@ const std = @import("std");
// :183:17: error: use of undefined value here causes illegal behavior
// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
+// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
+// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
@@ -7464,9 +7458,9 @@ const std = @import("std");
// :183:17: error: use of undefined value here causes illegal behavior
// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
-// :183:17: note: when computing vector element at index '1'
+// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
-// :183:17: note: when computing vector element at index '1'
+// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
@@ -7476,7 +7470,9 @@ const std = @import("std");
// :183:17: error: use of undefined value here causes illegal behavior
// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
+// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
+// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
@@ -7486,9 +7482,9 @@ const std = @import("std");
// :183:17: error: use of undefined value here causes illegal behavior
// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
-// :183:17: note: when computing vector element at index '1'
+// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
-// :183:17: note: when computing vector element at index '1'
+// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
@@ -7498,7 +7494,9 @@ const std = @import("std");
// :183:17: error: use of undefined value here causes illegal behavior
// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
+// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
+// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
@@ -7508,9 +7506,9 @@ const std = @import("std");
// :183:17: error: use of undefined value here causes illegal behavior
// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
-// :183:17: note: when computing vector element at index '1'
+// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
-// :183:17: note: when computing vector element at index '1'
+// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
@@ -7520,27 +7518,29 @@ const std = @import("std");
// :183:17: error: use of undefined value here causes illegal behavior
// :183:17: note: when computing vector element at index '0'
// :183:17: error: use of undefined value here causes illegal behavior
+// :183:17: note: when computing vector element at index '1'
// :183:17: error: use of undefined value here causes illegal behavior
+// :183:17: note: when computing vector element at index '1'
// :183:17: error: use of undefined value here causes illegal behavior
-// :183:17: note: when computing vector element at index '0'
+// :183:17: note: when computing vector element at index '1'
// :183:17: error: use of undefined value here causes illegal behavior
-// :183:17: note: when computing vector element at index '0'
+// :183:17: note: when computing vector element at index '1'
// :183:17: error: use of undefined value here causes illegal behavior
-// :183:17: note: when computing vector element at index '0'
+// :183:17: note: when computing vector element at index '1'
// :183:17: error: use of undefined value here causes illegal behavior
-// :183:17: note: when computing vector element at index '0'
+// :183:17: note: when computing vector element at index '1'
// :183:17: error: use of undefined value here causes illegal behavior
// :183:17: note: when computing vector element at index '1'
// :183:17: error: use of undefined value here causes illegal behavior
// :183:17: note: when computing vector element at index '1'
// :183:17: error: use of undefined value here causes illegal behavior
-// :183:17: note: when computing vector element at index '0'
+// :183:17: note: when computing vector element at index '1'
// :183:17: error: use of undefined value here causes illegal behavior
-// :183:17: note: when computing vector element at index '0'
+// :183:17: note: when computing vector element at index '1'
// :183:17: error: use of undefined value here causes illegal behavior
-// :183:17: note: when computing vector element at index '0'
+// :183:17: note: when computing vector element at index '1'
// :183:17: error: use of undefined value here causes illegal behavior
-// :183:17: note: when computing vector element at index '0'
+// :183:17: note: when computing vector element at index '1'
// :183:21: error: use of undefined value here causes illegal behavior
// :183:21: note: when computing vector element at index '0'
// :183:21: error: use of undefined value here causes illegal behavior
diff --git a/test/cases/compile_errors/undef_arith_returns_undef.zig b/test/cases/compile_errors/undef_arith_returns_undef.zig
index 4c2c096b98ebc47c05bc9246e08e047d1b312119..40dbe1671523e24358e9260f9d90a9ef70afdbec 100644
--- a/test/cases/compile_errors/undef_arith_returns_undef.zig
+++ b/test/cases/compile_errors/undef_arith_returns_undef.zig
@@ -681,810 +681,260 @@ inline fn testFloatWithValue(comptime Float: type, x: Float) void {
// @as(@Vector(2, u8), undefined)
// @as(@Vector(2, u8), [runtime value])
// @as(@Vector(2, u8), [runtime value])
-// @as(i8, undefined)
-// @as(i8, undefined)
-// @as(@Vector(2, i8), .{ 6, undefined })
-// @as(@Vector(2, i8), .{ undefined, 6 })
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), .{ 6, undefined })
-// @as(@Vector(2, i8), .{ 6, undefined })
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), .{ undefined, 6 })
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), .{ undefined, 6 })
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(i8, undefined)
-// @as(i8, undefined)
-// @as(@Vector(2, i8), .{ 6, undefined })
-// @as(@Vector(2, i8), .{ undefined, 6 })
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), .{ 6, undefined })
-// @as(@Vector(2, i8), .{ 6, undefined })
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), .{ undefined, 6 })
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), .{ undefined, 6 })
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(i8, undefined)
-// @as(i8, undefined)
-// @as(@Vector(2, i8), .{ 0, undefined })
-// @as(@Vector(2, i8), .{ undefined, 0 })
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), .{ 0, undefined })
-// @as(@Vector(2, i8), .{ 0, undefined })
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), .{ undefined, 0 })
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), .{ undefined, 0 })
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(i8, undefined)
-// @as(i8, undefined)
-// @as(@Vector(2, i8), .{ 0, undefined })
-// @as(@Vector(2, i8), .{ undefined, 0 })
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), .{ 0, undefined })
-// @as(@Vector(2, i8), .{ 0, undefined })
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), .{ undefined, 0 })
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), .{ undefined, 0 })
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(i8, undefined)
-// @as(i8, undefined)
-// @as(@Vector(2, i8), .{ 9, undefined })
-// @as(@Vector(2, i8), .{ undefined, 9 })
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), .{ 9, undefined })
-// @as(@Vector(2, i8), .{ 9, undefined })
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), .{ undefined, 9 })
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), .{ undefined, 9 })
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(i8, undefined)
-// @as(i8, undefined)
-// @as(@Vector(2, i8), .{ 9, undefined })
-// @as(@Vector(2, i8), .{ undefined, 9 })
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), .{ 9, undefined })
-// @as(@Vector(2, i8), .{ 9, undefined })
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), .{ undefined, 9 })
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), .{ undefined, 9 })
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(i8, undefined)
-// @as(i8, undefined)
-// @as(@Vector(2, i8), .{ 0, undefined })
-// @as(@Vector(2, i8), .{ undefined, 0 })
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), .{ 0, undefined })
-// @as(@Vector(2, i8), .{ 0, undefined })
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), .{ undefined, 0 })
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), .{ undefined, 0 })
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(i8, undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(i8, undefined)
-// @as(i8, undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(i8, undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(i8, undefined)
-// @as(i8, undefined)
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(i8, undefined)
-// @as(i8, undefined)
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(i8, undefined)
-// @as(i8, undefined)
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(i8, undefined)
-// @as(i8, undefined)
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(i8, undefined)
-// @as(i8, undefined)
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(i8, undefined)
-// @as(i8, undefined)
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(i8, [runtime value])
-// @as(i8, [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), [runtime value])
-// @as(@Vector(2, i8), undefined)
-// @as(i8, undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(i8, undefined)
-// @as(i8, undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(i8, undefined)
-// @as(@Vector(2, i8), undefined)
-// @as(u32, undefined)
-// @as(u32, undefined)
-// @as(@Vector(2, u32), .{ 6, undefined })
-// @as(@Vector(2, u32), .{ undefined, 6 })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), .{ 6, undefined })
-// @as(@Vector(2, u32), .{ 6, undefined })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), .{ undefined, 6 })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), .{ undefined, 6 })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(u32, undefined)
-// @as(u32, undefined)
-// @as(@Vector(2, u32), .{ 6, undefined })
-// @as(@Vector(2, u32), .{ undefined, 6 })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), .{ 6, undefined })
-// @as(@Vector(2, u32), .{ 6, undefined })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), .{ undefined, 6 })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), .{ undefined, 6 })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(u32, undefined)
-// @as(u32, undefined)
-// @as(@Vector(2, u32), .{ 0, undefined })
-// @as(@Vector(2, u32), .{ undefined, 0 })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), .{ 0, undefined })
-// @as(@Vector(2, u32), .{ 0, undefined })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), .{ undefined, 0 })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), .{ undefined, 0 })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(u32, undefined)
-// @as(u32, undefined)
-// @as(@Vector(2, u32), .{ 0, undefined })
-// @as(@Vector(2, u32), .{ undefined, 0 })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), .{ 0, undefined })
-// @as(@Vector(2, u32), .{ 0, undefined })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), .{ undefined, 0 })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), .{ undefined, 0 })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(u32, undefined)
-// @as(u32, undefined)
-// @as(@Vector(2, u32), .{ 9, undefined })
-// @as(@Vector(2, u32), .{ undefined, 9 })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), .{ 9, undefined })
-// @as(@Vector(2, u32), .{ 9, undefined })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), .{ undefined, 9 })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), .{ undefined, 9 })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(u32, undefined)
-// @as(u32, undefined)
-// @as(@Vector(2, u32), .{ 9, undefined })
-// @as(@Vector(2, u32), .{ undefined, 9 })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), .{ 9, undefined })
-// @as(@Vector(2, u32), .{ 9, undefined })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), .{ undefined, 9 })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), .{ undefined, 9 })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(u32, undefined)
-// @as(u32, undefined)
-// @as(@Vector(2, u32), .{ 24, undefined })
-// @as(@Vector(2, u32), .{ undefined, 24 })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), .{ 24, undefined })
-// @as(@Vector(2, u32), .{ 24, undefined })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), .{ undefined, 24 })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), .{ undefined, 24 })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(u32, undefined)
-// @as(u32, undefined)
-// @as(@Vector(2, u32), .{ 0, undefined })
-// @as(@Vector(2, u32), .{ undefined, 0 })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), .{ 0, undefined })
-// @as(@Vector(2, u32), .{ 0, undefined })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), .{ undefined, 0 })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), .{ undefined, 0 })
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(u32, undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(u32, undefined)
-// @as(u32, undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(u1, undefined)
-// @as(@Vector(2, u1), .{ 1, undefined })
-// @as(@Vector(2, u1), .{ undefined, 1 })
-// @as(@Vector(2, u1), undefined)
-// @as(u32, undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(u32, undefined)
-// @as(u32, undefined)
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(u32, undefined)
-// @as(u32, undefined)
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(u32, undefined)
-// @as(u32, undefined)
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(u32, undefined)
-// @as(u32, undefined)
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(u32, undefined)
-// @as(u32, undefined)
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(u32, undefined)
-// @as(u32, undefined)
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(u32, undefined)
-// @as(u32, undefined)
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(u32, [runtime value])
-// @as(u32, [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), [runtime value])
-// @as(@Vector(2, u32), undefined)
-// @as(u32, undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(u32, undefined)
-// @as(u32, undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(u1, undefined)
-// @as(@Vector(2, u1), [runtime value])
-// @as(@Vector(2, u1), [runtime value])
-// @as(@Vector(2, u1), undefined)
-// @as(u32, undefined)
-// @as(@Vector(2, u32), undefined)
-// @as(i32, undefined)
-// @as(i32, undefined)
-// @as(@Vector(2, i32), .{ 6, undefined })
-// @as(@Vector(2, i32), .{ undefined, 6 })
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), .{ 6, undefined })
-// @as(@Vector(2, i32), .{ 6, undefined })
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), .{ undefined, 6 })
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), .{ undefined, 6 })
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(i32, undefined)
-// @as(i32, undefined)
-// @as(@Vector(2, i32), .{ 6, undefined })
-// @as(@Vector(2, i32), .{ undefined, 6 })
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), .{ 6, undefined })
-// @as(@Vector(2, i32), .{ 6, undefined })
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), .{ undefined, 6 })
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), .{ undefined, 6 })
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(i32, undefined)
-// @as(i32, undefined)
-// @as(@Vector(2, i32), .{ 0, undefined })
-// @as(@Vector(2, i32), .{ undefined, 0 })
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), .{ 0, undefined })
-// @as(@Vector(2, i32), .{ 0, undefined })
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), .{ undefined, 0 })
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), .{ undefined, 0 })
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(i32, undefined)
-// @as(i32, undefined)
-// @as(@Vector(2, i32), .{ 0, undefined })
-// @as(@Vector(2, i32), .{ undefined, 0 })
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), .{ 0, undefined })
-// @as(@Vector(2, i32), .{ 0, undefined })
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), .{ undefined, 0 })
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), .{ undefined, 0 })
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(i32, undefined)
-// @as(i32, undefined)
-// @as(@Vector(2, i32), .{ 9, undefined })
-// @as(@Vector(2, i32), .{ undefined, 9 })
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), .{ 9, undefined })
-// @as(@Vector(2, i32), .{ 9, undefined })
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), .{ undefined, 9 })
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), .{ undefined, 9 })
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(i32, undefined)
-// @as(i32, undefined)
-// @as(@Vector(2, i32), .{ 9, undefined })
-// @as(@Vector(2, i32), .{ undefined, 9 })
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), .{ 9, undefined })
-// @as(@Vector(2, i32), .{ 9, undefined })
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), .{ undefined, 9 })
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), .{ undefined, 9 })
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(i32, undefined)
-// @as(i32, undefined)
-// @as(@Vector(2, i32), .{ 0, undefined })
-// @as(@Vector(2, i32), .{ undefined, 0 })
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), .{ 0, undefined })
-// @as(@Vector(2, i32), .{ 0, undefined })
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), .{ undefined, 0 })
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), .{ undefined, 0 })
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(i32, undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(i32, undefined)
-// @as(i32, undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(i32, undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(i32, undefined)
-// @as(i32, undefined)
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(i32, undefined)
-// @as(i32, undefined)
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(i32, undefined)
-// @as(i32, undefined)
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(i32, undefined)
-// @as(i32, undefined)
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(i32, undefined)
-// @as(i32, undefined)
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(i32, undefined)
-// @as(i32, undefined)
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(i32, [runtime value])
-// @as(i32, [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), [runtime value])
-// @as(@Vector(2, i32), undefined)
-// @as(i32, undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(i32, undefined)
-// @as(i32, undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(@Vector(2, i32), undefined)
-// @as(i32, undefined)
-// @as(@Vector(2, i32), undefined)
+// @as(i500, undefined)
+// @as(i500, undefined)
+// @as(@Vector(2, i500), .{ 6, undefined })
+// @as(@Vector(2, i500), .{ undefined, 6 })
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), .{ 6, undefined })
+// @as(@Vector(2, i500), .{ 6, undefined })
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), .{ undefined, 6 })
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), .{ undefined, 6 })
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(i500, undefined)
+// @as(i500, undefined)
+// @as(@Vector(2, i500), .{ 6, undefined })
+// @as(@Vector(2, i500), .{ undefined, 6 })
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), .{ 6, undefined })
+// @as(@Vector(2, i500), .{ 6, undefined })
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), .{ undefined, 6 })
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), .{ undefined, 6 })
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(i500, undefined)
+// @as(i500, undefined)
+// @as(@Vector(2, i500), .{ 0, undefined })
+// @as(@Vector(2, i500), .{ undefined, 0 })
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), .{ 0, undefined })
+// @as(@Vector(2, i500), .{ 0, undefined })
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), .{ undefined, 0 })
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), .{ undefined, 0 })
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(i500, undefined)
+// @as(i500, undefined)
+// @as(@Vector(2, i500), .{ 0, undefined })
+// @as(@Vector(2, i500), .{ undefined, 0 })
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), .{ 0, undefined })
+// @as(@Vector(2, i500), .{ 0, undefined })
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), .{ undefined, 0 })
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), .{ undefined, 0 })
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(i500, undefined)
+// @as(i500, undefined)
+// @as(@Vector(2, i500), .{ 9, undefined })
+// @as(@Vector(2, i500), .{ undefined, 9 })
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), .{ 9, undefined })
+// @as(@Vector(2, i500), .{ 9, undefined })
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), .{ undefined, 9 })
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), .{ undefined, 9 })
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(i500, undefined)
+// @as(i500, undefined)
+// @as(@Vector(2, i500), .{ 9, undefined })
+// @as(@Vector(2, i500), .{ undefined, 9 })
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), .{ 9, undefined })
+// @as(@Vector(2, i500), .{ 9, undefined })
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), .{ undefined, 9 })
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), .{ undefined, 9 })
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(i500, undefined)
+// @as(i500, undefined)
+// @as(@Vector(2, i500), .{ 0, undefined })
+// @as(@Vector(2, i500), .{ undefined, 0 })
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), .{ 0, undefined })
+// @as(@Vector(2, i500), .{ 0, undefined })
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), .{ undefined, 0 })
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), .{ undefined, 0 })
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(i500, undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(i500, undefined)
+// @as(i500, undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(i500, undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(i500, undefined)
+// @as(i500, undefined)
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(i500, undefined)
+// @as(i500, undefined)
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(i500, undefined)
+// @as(i500, undefined)
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(i500, undefined)
+// @as(i500, undefined)
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(i500, undefined)
+// @as(i500, undefined)
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(i500, undefined)
+// @as(i500, undefined)
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(i500, [runtime value])
+// @as(i500, [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), [runtime value])
+// @as(@Vector(2, i500), undefined)
+// @as(i500, undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(i500, undefined)
+// @as(i500, undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(@Vector(2, i500), undefined)
+// @as(i500, undefined)
+// @as(@Vector(2, i500), undefined)
// @as(u500, undefined)
// @as(u500, undefined)
// @as(@Vector(2, u500), .{ 6, undefined })
@@ -1779,702 +1229,812 @@ inline fn testFloatWithValue(comptime Float: type, x: Float) void {
// @as(@Vector(2, u1), [runtime value])
// @as(@Vector(2, u1), [runtime value])
// @as(@Vector(2, u1), undefined)
-// @as(u500, undefined)
-// @as(@Vector(2, u500), undefined)
-// @as(i500, undefined)
-// @as(i500, undefined)
-// @as(@Vector(2, i500), .{ 6, undefined })
-// @as(@Vector(2, i500), .{ undefined, 6 })
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), .{ 6, undefined })
-// @as(@Vector(2, i500), .{ 6, undefined })
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), .{ undefined, 6 })
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), .{ undefined, 6 })
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(i500, undefined)
-// @as(i500, undefined)
-// @as(@Vector(2, i500), .{ 6, undefined })
-// @as(@Vector(2, i500), .{ undefined, 6 })
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), .{ 6, undefined })
-// @as(@Vector(2, i500), .{ 6, undefined })
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), .{ undefined, 6 })
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), .{ undefined, 6 })
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(i500, undefined)
-// @as(i500, undefined)
-// @as(@Vector(2, i500), .{ 0, undefined })
-// @as(@Vector(2, i500), .{ undefined, 0 })
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), .{ 0, undefined })
-// @as(@Vector(2, i500), .{ 0, undefined })
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), .{ undefined, 0 })
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), .{ undefined, 0 })
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(i500, undefined)
-// @as(i500, undefined)
-// @as(@Vector(2, i500), .{ 0, undefined })
-// @as(@Vector(2, i500), .{ undefined, 0 })
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), .{ 0, undefined })
-// @as(@Vector(2, i500), .{ 0, undefined })
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), .{ undefined, 0 })
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), .{ undefined, 0 })
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(i500, undefined)
-// @as(i500, undefined)
-// @as(@Vector(2, i500), .{ 9, undefined })
-// @as(@Vector(2, i500), .{ undefined, 9 })
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), .{ 9, undefined })
-// @as(@Vector(2, i500), .{ 9, undefined })
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), .{ undefined, 9 })
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), .{ undefined, 9 })
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(i500, undefined)
-// @as(i500, undefined)
-// @as(@Vector(2, i500), .{ 9, undefined })
-// @as(@Vector(2, i500), .{ undefined, 9 })
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), .{ 9, undefined })
-// @as(@Vector(2, i500), .{ 9, undefined })
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), .{ undefined, 9 })
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), .{ undefined, 9 })
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(i500, undefined)
-// @as(i500, undefined)
-// @as(@Vector(2, i500), .{ 0, undefined })
-// @as(@Vector(2, i500), .{ undefined, 0 })
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), .{ 0, undefined })
-// @as(@Vector(2, i500), .{ 0, undefined })
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), .{ undefined, 0 })
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), .{ undefined, 0 })
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(i500, undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(i500, undefined)
-// @as(i500, undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(i500, undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(i500, undefined)
-// @as(i500, undefined)
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(i500, undefined)
-// @as(i500, undefined)
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(i500, undefined)
-// @as(i500, undefined)
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(i500, undefined)
-// @as(i500, undefined)
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(i500, undefined)
-// @as(i500, undefined)
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(i500, undefined)
-// @as(i500, undefined)
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(i500, [runtime value])
-// @as(i500, [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), [runtime value])
-// @as(@Vector(2, i500), undefined)
-// @as(i500, undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(i500, undefined)
-// @as(i500, undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(i500, undefined)
-// @as(@Vector(2, i500), undefined)
-// @as(f16, undefined)
-// @as(f16, undefined)
-// @as(@Vector(2, f16), .{ 6, undefined })
-// @as(@Vector(2, f16), .{ undefined, 6 })
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), .{ 6, undefined })
-// @as(@Vector(2, f16), .{ 6, undefined })
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), .{ undefined, 6 })
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), .{ undefined, 6 })
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), undefined)
-// @as(f16, undefined)
-// @as(f16, undefined)
-// @as(@Vector(2, f16), .{ 0, undefined })
-// @as(@Vector(2, f16), .{ undefined, 0 })
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), .{ 0, undefined })
-// @as(@Vector(2, f16), .{ 0, undefined })
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), .{ undefined, 0 })
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), .{ undefined, 0 })
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), undefined)
-// @as(f16, undefined)
-// @as(f16, undefined)
-// @as(@Vector(2, f16), .{ 9, undefined })
-// @as(@Vector(2, f16), .{ undefined, 9 })
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), .{ 9, undefined })
-// @as(@Vector(2, f16), .{ 9, undefined })
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), .{ undefined, 9 })
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), .{ undefined, 9 })
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), undefined)
-// @as(f16, undefined)
-// @as(@Vector(2, f16), .{ -3, undefined })
-// @as(@Vector(2, f16), .{ undefined, -3 })
-// @as(@Vector(2, f16), undefined)
-// @as(f16, undefined)
-// @as(f16, undefined)
-// @as(@Vector(2, f16), [runtime value])
-// @as(@Vector(2, f16), [runtime value])
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), [runtime value])
-// @as(@Vector(2, f16), [runtime value])
-// @as(@Vector(2, f16), [runtime value])
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), [runtime value])
-// @as(@Vector(2, f16), [runtime value])
-// @as(@Vector(2, f16), [runtime value])
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), undefined)
-// @as(f16, undefined)
-// @as(f16, undefined)
-// @as(@Vector(2, f16), [runtime value])
-// @as(@Vector(2, f16), [runtime value])
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), [runtime value])
-// @as(@Vector(2, f16), [runtime value])
-// @as(@Vector(2, f16), [runtime value])
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), [runtime value])
-// @as(@Vector(2, f16), [runtime value])
-// @as(@Vector(2, f16), [runtime value])
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), undefined)
-// @as(f16, undefined)
-// @as(f16, undefined)
-// @as(@Vector(2, f16), [runtime value])
-// @as(@Vector(2, f16), [runtime value])
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), [runtime value])
-// @as(@Vector(2, f16), [runtime value])
-// @as(@Vector(2, f16), [runtime value])
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), [runtime value])
-// @as(@Vector(2, f16), [runtime value])
-// @as(@Vector(2, f16), [runtime value])
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), undefined)
-// @as(@Vector(2, f16), undefined)
-// @as(f16, undefined)
-// @as(@Vector(2, f16), [runtime value])
-// @as(@Vector(2, f16), [runtime value])
-// @as(@Vector(2, f16), undefined)
-// @as(f32, undefined)
-// @as(f32, undefined)
-// @as(@Vector(2, f32), .{ 6, undefined })
-// @as(@Vector(2, f32), .{ undefined, 6 })
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), .{ 6, undefined })
-// @as(@Vector(2, f32), .{ 6, undefined })
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), .{ undefined, 6 })
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), .{ undefined, 6 })
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), undefined)
-// @as(f32, undefined)
-// @as(f32, undefined)
-// @as(@Vector(2, f32), .{ 0, undefined })
-// @as(@Vector(2, f32), .{ undefined, 0 })
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), .{ 0, undefined })
-// @as(@Vector(2, f32), .{ 0, undefined })
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), .{ undefined, 0 })
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), .{ undefined, 0 })
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), undefined)
-// @as(f32, undefined)
-// @as(f32, undefined)
-// @as(@Vector(2, f32), .{ 9, undefined })
-// @as(@Vector(2, f32), .{ undefined, 9 })
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), .{ 9, undefined })
-// @as(@Vector(2, f32), .{ 9, undefined })
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), .{ undefined, 9 })
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), .{ undefined, 9 })
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), undefined)
-// @as(f32, undefined)
-// @as(@Vector(2, f32), .{ -3, undefined })
-// @as(@Vector(2, f32), .{ undefined, -3 })
-// @as(@Vector(2, f32), undefined)
-// @as(f32, undefined)
-// @as(f32, undefined)
-// @as(@Vector(2, f32), [runtime value])
-// @as(@Vector(2, f32), [runtime value])
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), [runtime value])
-// @as(@Vector(2, f32), [runtime value])
-// @as(@Vector(2, f32), [runtime value])
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), [runtime value])
-// @as(@Vector(2, f32), [runtime value])
-// @as(@Vector(2, f32), [runtime value])
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), undefined)
-// @as(f32, undefined)
-// @as(f32, undefined)
-// @as(@Vector(2, f32), [runtime value])
-// @as(@Vector(2, f32), [runtime value])
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), [runtime value])
-// @as(@Vector(2, f32), [runtime value])
-// @as(@Vector(2, f32), [runtime value])
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), [runtime value])
-// @as(@Vector(2, f32), [runtime value])
-// @as(@Vector(2, f32), [runtime value])
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), undefined)
-// @as(f32, undefined)
-// @as(f32, undefined)
-// @as(@Vector(2, f32), [runtime value])
-// @as(@Vector(2, f32), [runtime value])
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), [runtime value])
-// @as(@Vector(2, f32), [runtime value])
-// @as(@Vector(2, f32), [runtime value])
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), [runtime value])
-// @as(@Vector(2, f32), [runtime value])
-// @as(@Vector(2, f32), [runtime value])
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), undefined)
-// @as(@Vector(2, f32), undefined)
-// @as(f32, undefined)
-// @as(@Vector(2, f32), [runtime value])
-// @as(@Vector(2, f32), [runtime value])
-// @as(@Vector(2, f32), undefined)
-// @as(f64, undefined)
-// @as(f64, undefined)
-// @as(@Vector(2, f64), .{ 6, undefined })
-// @as(@Vector(2, f64), .{ undefined, 6 })
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), .{ 6, undefined })
-// @as(@Vector(2, f64), .{ 6, undefined })
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), .{ undefined, 6 })
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), .{ undefined, 6 })
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), undefined)
-// @as(f64, undefined)
-// @as(f64, undefined)
-// @as(@Vector(2, f64), .{ 0, undefined })
-// @as(@Vector(2, f64), .{ undefined, 0 })
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), .{ 0, undefined })
-// @as(@Vector(2, f64), .{ 0, undefined })
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), .{ undefined, 0 })
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), .{ undefined, 0 })
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), undefined)
-// @as(f64, undefined)
-// @as(f64, undefined)
-// @as(@Vector(2, f64), .{ 9, undefined })
-// @as(@Vector(2, f64), .{ undefined, 9 })
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), .{ 9, undefined })
-// @as(@Vector(2, f64), .{ 9, undefined })
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), .{ undefined, 9 })
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), .{ undefined, 9 })
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), undefined)
-// @as(f64, undefined)
-// @as(@Vector(2, f64), .{ -3, undefined })
-// @as(@Vector(2, f64), .{ undefined, -3 })
-// @as(@Vector(2, f64), undefined)
-// @as(f64, undefined)
-// @as(f64, undefined)
-// @as(@Vector(2, f64), [runtime value])
-// @as(@Vector(2, f64), [runtime value])
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), [runtime value])
-// @as(@Vector(2, f64), [runtime value])
-// @as(@Vector(2, f64), [runtime value])
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), [runtime value])
-// @as(@Vector(2, f64), [runtime value])
-// @as(@Vector(2, f64), [runtime value])
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), undefined)
-// @as(f64, undefined)
-// @as(f64, undefined)
-// @as(@Vector(2, f64), [runtime value])
-// @as(@Vector(2, f64), [runtime value])
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), [runtime value])
-// @as(@Vector(2, f64), [runtime value])
-// @as(@Vector(2, f64), [runtime value])
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), [runtime value])
-// @as(@Vector(2, f64), [runtime value])
-// @as(@Vector(2, f64), [runtime value])
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), undefined)
-// @as(f64, undefined)
-// @as(f64, undefined)
-// @as(@Vector(2, f64), [runtime value])
-// @as(@Vector(2, f64), [runtime value])
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), [runtime value])
-// @as(@Vector(2, f64), [runtime value])
-// @as(@Vector(2, f64), [runtime value])
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), [runtime value])
-// @as(@Vector(2, f64), [runtime value])
-// @as(@Vector(2, f64), [runtime value])
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), undefined)
-// @as(@Vector(2, f64), undefined)
-// @as(f64, undefined)
-// @as(@Vector(2, f64), [runtime value])
-// @as(@Vector(2, f64), [runtime value])
-// @as(@Vector(2, f64), undefined)
-// @as(f80, undefined)
-// @as(f80, undefined)
-// @as(@Vector(2, f80), .{ 6, undefined })
-// @as(@Vector(2, f80), .{ undefined, 6 })
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), .{ 6, undefined })
-// @as(@Vector(2, f80), .{ 6, undefined })
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), .{ undefined, 6 })
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), .{ undefined, 6 })
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), undefined)
-// @as(f80, undefined)
-// @as(f80, undefined)
-// @as(@Vector(2, f80), .{ 0, undefined })
-// @as(@Vector(2, f80), .{ undefined, 0 })
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), .{ 0, undefined })
-// @as(@Vector(2, f80), .{ 0, undefined })
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), .{ undefined, 0 })
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), .{ undefined, 0 })
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), undefined)
-// @as(f80, undefined)
-// @as(f80, undefined)
-// @as(@Vector(2, f80), .{ 9, undefined })
-// @as(@Vector(2, f80), .{ undefined, 9 })
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), .{ 9, undefined })
-// @as(@Vector(2, f80), .{ 9, undefined })
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), .{ undefined, 9 })
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), .{ undefined, 9 })
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), undefined)
-// @as(f80, undefined)
-// @as(@Vector(2, f80), .{ -3, undefined })
-// @as(@Vector(2, f80), .{ undefined, -3 })
-// @as(@Vector(2, f80), undefined)
-// @as(f80, undefined)
-// @as(f80, undefined)
-// @as(@Vector(2, f80), [runtime value])
-// @as(@Vector(2, f80), [runtime value])
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), [runtime value])
-// @as(@Vector(2, f80), [runtime value])
-// @as(@Vector(2, f80), [runtime value])
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), [runtime value])
-// @as(@Vector(2, f80), [runtime value])
-// @as(@Vector(2, f80), [runtime value])
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), undefined)
-// @as(f80, undefined)
-// @as(f80, undefined)
-// @as(@Vector(2, f80), [runtime value])
-// @as(@Vector(2, f80), [runtime value])
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), [runtime value])
-// @as(@Vector(2, f80), [runtime value])
-// @as(@Vector(2, f80), [runtime value])
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), [runtime value])
-// @as(@Vector(2, f80), [runtime value])
-// @as(@Vector(2, f80), [runtime value])
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), undefined)
-// @as(f80, undefined)
-// @as(f80, undefined)
-// @as(@Vector(2, f80), [runtime value])
-// @as(@Vector(2, f80), [runtime value])
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), [runtime value])
-// @as(@Vector(2, f80), [runtime value])
-// @as(@Vector(2, f80), [runtime value])
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), [runtime value])
-// @as(@Vector(2, f80), [runtime value])
-// @as(@Vector(2, f80), [runtime value])
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), undefined)
-// @as(@Vector(2, f80), undefined)
-// @as(f80, undefined)
-// @as(@Vector(2, f80), [runtime value])
-// @as(@Vector(2, f80), [runtime value])
-// @as(@Vector(2, f80), undefined)
+// @as(u500, undefined)
+// @as(@Vector(2, u500), undefined)
+// @as(i32, undefined)
+// @as(i32, undefined)
+// @as(@Vector(2, i32), .{ 6, undefined })
+// @as(@Vector(2, i32), .{ undefined, 6 })
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), .{ 6, undefined })
+// @as(@Vector(2, i32), .{ 6, undefined })
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), .{ undefined, 6 })
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), .{ undefined, 6 })
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(i32, undefined)
+// @as(i32, undefined)
+// @as(@Vector(2, i32), .{ 6, undefined })
+// @as(@Vector(2, i32), .{ undefined, 6 })
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), .{ 6, undefined })
+// @as(@Vector(2, i32), .{ 6, undefined })
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), .{ undefined, 6 })
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), .{ undefined, 6 })
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(i32, undefined)
+// @as(i32, undefined)
+// @as(@Vector(2, i32), .{ 0, undefined })
+// @as(@Vector(2, i32), .{ undefined, 0 })
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), .{ 0, undefined })
+// @as(@Vector(2, i32), .{ 0, undefined })
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), .{ undefined, 0 })
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), .{ undefined, 0 })
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(i32, undefined)
+// @as(i32, undefined)
+// @as(@Vector(2, i32), .{ 0, undefined })
+// @as(@Vector(2, i32), .{ undefined, 0 })
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), .{ 0, undefined })
+// @as(@Vector(2, i32), .{ 0, undefined })
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), .{ undefined, 0 })
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), .{ undefined, 0 })
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(i32, undefined)
+// @as(i32, undefined)
+// @as(@Vector(2, i32), .{ 9, undefined })
+// @as(@Vector(2, i32), .{ undefined, 9 })
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), .{ 9, undefined })
+// @as(@Vector(2, i32), .{ 9, undefined })
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), .{ undefined, 9 })
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), .{ undefined, 9 })
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(i32, undefined)
+// @as(i32, undefined)
+// @as(@Vector(2, i32), .{ 9, undefined })
+// @as(@Vector(2, i32), .{ undefined, 9 })
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), .{ 9, undefined })
+// @as(@Vector(2, i32), .{ 9, undefined })
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), .{ undefined, 9 })
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), .{ undefined, 9 })
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(i32, undefined)
+// @as(i32, undefined)
+// @as(@Vector(2, i32), .{ 0, undefined })
+// @as(@Vector(2, i32), .{ undefined, 0 })
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), .{ 0, undefined })
+// @as(@Vector(2, i32), .{ 0, undefined })
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), .{ undefined, 0 })
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), .{ undefined, 0 })
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(i32, undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(i32, undefined)
+// @as(i32, undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(i32, undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(i32, undefined)
+// @as(i32, undefined)
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(i32, undefined)
+// @as(i32, undefined)
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(i32, undefined)
+// @as(i32, undefined)
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(i32, undefined)
+// @as(i32, undefined)
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(i32, undefined)
+// @as(i32, undefined)
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(i32, undefined)
+// @as(i32, undefined)
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(i32, [runtime value])
+// @as(i32, [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), [runtime value])
+// @as(@Vector(2, i32), undefined)
+// @as(i32, undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(i32, undefined)
+// @as(i32, undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(i32, undefined)
+// @as(@Vector(2, i32), undefined)
+// @as(u32, undefined)
+// @as(u32, undefined)
+// @as(@Vector(2, u32), .{ 6, undefined })
+// @as(@Vector(2, u32), .{ undefined, 6 })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), .{ 6, undefined })
+// @as(@Vector(2, u32), .{ 6, undefined })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), .{ undefined, 6 })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), .{ undefined, 6 })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(u32, undefined)
+// @as(u32, undefined)
+// @as(@Vector(2, u32), .{ 6, undefined })
+// @as(@Vector(2, u32), .{ undefined, 6 })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), .{ 6, undefined })
+// @as(@Vector(2, u32), .{ 6, undefined })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), .{ undefined, 6 })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), .{ undefined, 6 })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(u32, undefined)
+// @as(u32, undefined)
+// @as(@Vector(2, u32), .{ 0, undefined })
+// @as(@Vector(2, u32), .{ undefined, 0 })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), .{ 0, undefined })
+// @as(@Vector(2, u32), .{ 0, undefined })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), .{ undefined, 0 })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), .{ undefined, 0 })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(u32, undefined)
+// @as(u32, undefined)
+// @as(@Vector(2, u32), .{ 0, undefined })
+// @as(@Vector(2, u32), .{ undefined, 0 })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), .{ 0, undefined })
+// @as(@Vector(2, u32), .{ 0, undefined })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), .{ undefined, 0 })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), .{ undefined, 0 })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(u32, undefined)
+// @as(u32, undefined)
+// @as(@Vector(2, u32), .{ 9, undefined })
+// @as(@Vector(2, u32), .{ undefined, 9 })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), .{ 9, undefined })
+// @as(@Vector(2, u32), .{ 9, undefined })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), .{ undefined, 9 })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), .{ undefined, 9 })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(u32, undefined)
+// @as(u32, undefined)
+// @as(@Vector(2, u32), .{ 9, undefined })
+// @as(@Vector(2, u32), .{ undefined, 9 })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), .{ 9, undefined })
+// @as(@Vector(2, u32), .{ 9, undefined })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), .{ undefined, 9 })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), .{ undefined, 9 })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(u32, undefined)
+// @as(u32, undefined)
+// @as(@Vector(2, u32), .{ 24, undefined })
+// @as(@Vector(2, u32), .{ undefined, 24 })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), .{ 24, undefined })
+// @as(@Vector(2, u32), .{ 24, undefined })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), .{ undefined, 24 })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), .{ undefined, 24 })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(u32, undefined)
+// @as(u32, undefined)
+// @as(@Vector(2, u32), .{ 0, undefined })
+// @as(@Vector(2, u32), .{ undefined, 0 })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), .{ 0, undefined })
+// @as(@Vector(2, u32), .{ 0, undefined })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), .{ undefined, 0 })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), .{ undefined, 0 })
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(u32, undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(u32, undefined)
+// @as(u32, undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(u1, undefined)
+// @as(@Vector(2, u1), .{ 1, undefined })
+// @as(@Vector(2, u1), .{ undefined, 1 })
+// @as(@Vector(2, u1), undefined)
+// @as(u32, undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(u32, undefined)
+// @as(u32, undefined)
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(u32, undefined)
+// @as(u32, undefined)
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(u32, undefined)
+// @as(u32, undefined)
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(u32, undefined)
+// @as(u32, undefined)
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(u32, undefined)
+// @as(u32, undefined)
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(u32, undefined)
+// @as(u32, undefined)
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(u32, undefined)
+// @as(u32, undefined)
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(u32, [runtime value])
+// @as(u32, [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), [runtime value])
+// @as(@Vector(2, u32), undefined)
+// @as(u32, undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(u32, undefined)
+// @as(u32, undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(u1, undefined)
+// @as(@Vector(2, u1), [runtime value])
+// @as(@Vector(2, u1), [runtime value])
+// @as(@Vector(2, u1), undefined)
+// @as(u32, undefined)
+// @as(@Vector(2, u32), undefined)
+// @as(i8, undefined)
+// @as(i8, undefined)
+// @as(@Vector(2, i8), .{ 6, undefined })
+// @as(@Vector(2, i8), .{ undefined, 6 })
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), .{ 6, undefined })
+// @as(@Vector(2, i8), .{ 6, undefined })
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), .{ undefined, 6 })
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), .{ undefined, 6 })
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(i8, undefined)
+// @as(i8, undefined)
+// @as(@Vector(2, i8), .{ 6, undefined })
+// @as(@Vector(2, i8), .{ undefined, 6 })
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), .{ 6, undefined })
+// @as(@Vector(2, i8), .{ 6, undefined })
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), .{ undefined, 6 })
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), .{ undefined, 6 })
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(i8, undefined)
+// @as(i8, undefined)
+// @as(@Vector(2, i8), .{ 0, undefined })
+// @as(@Vector(2, i8), .{ undefined, 0 })
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), .{ 0, undefined })
+// @as(@Vector(2, i8), .{ 0, undefined })
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), .{ undefined, 0 })
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), .{ undefined, 0 })
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(i8, undefined)
+// @as(i8, undefined)
+// @as(@Vector(2, i8), .{ 0, undefined })
+// @as(@Vector(2, i8), .{ undefined, 0 })
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), .{ 0, undefined })
+// @as(@Vector(2, i8), .{ 0, undefined })
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), .{ undefined, 0 })
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), .{ undefined, 0 })
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(i8, undefined)
+// @as(i8, undefined)
+// @as(@Vector(2, i8), .{ 9, undefined })
+// @as(@Vector(2, i8), .{ undefined, 9 })
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), .{ 9, undefined })
+// @as(@Vector(2, i8), .{ 9, undefined })
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), .{ undefined, 9 })
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), .{ undefined, 9 })
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(i8, undefined)
+// @as(i8, undefined)
+// @as(@Vector(2, i8), .{ 9, undefined })
+// @as(@Vector(2, i8), .{ undefined, 9 })
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), .{ 9, undefined })
+// @as(@Vector(2, i8), .{ 9, undefined })
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), .{ undefined, 9 })
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), .{ undefined, 9 })
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(i8, undefined)
+// @as(i8, undefined)
+// @as(@Vector(2, i8), .{ 0, undefined })
+// @as(@Vector(2, i8), .{ undefined, 0 })
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), .{ 0, undefined })
+// @as(@Vector(2, i8), .{ 0, undefined })
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), .{ undefined, 0 })
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), .{ undefined, 0 })
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(i8, undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(i8, undefined)
+// @as(i8, undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(i8, undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(i8, undefined)
+// @as(i8, undefined)
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(i8, undefined)
+// @as(i8, undefined)
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(i8, undefined)
+// @as(i8, undefined)
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(i8, undefined)
+// @as(i8, undefined)
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(i8, undefined)
+// @as(i8, undefined)
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(i8, undefined)
+// @as(i8, undefined)
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(i8, [runtime value])
+// @as(i8, [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), [runtime value])
+// @as(@Vector(2, i8), undefined)
+// @as(i8, undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(i8, undefined)
+// @as(i8, undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(@Vector(2, i8), undefined)
+// @as(i8, undefined)
+// @as(@Vector(2, i8), undefined)
// @as(f128, undefined)
// @as(f128, undefined)
// @as(@Vector(2, f128), .{ 6, undefined })
@@ -2585,3 +2145,443 @@ inline fn testFloatWithValue(comptime Float: type, x: Float) void {
// @as(@Vector(2, f128), [runtime value])
// @as(@Vector(2, f128), [runtime value])
// @as(@Vector(2, f128), undefined)
+// @as(f80, undefined)
+// @as(f80, undefined)
+// @as(@Vector(2, f80), .{ 6, undefined })
+// @as(@Vector(2, f80), .{ undefined, 6 })
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), .{ 6, undefined })
+// @as(@Vector(2, f80), .{ 6, undefined })
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), .{ undefined, 6 })
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), .{ undefined, 6 })
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), undefined)
+// @as(f80, undefined)
+// @as(f80, undefined)
+// @as(@Vector(2, f80), .{ 0, undefined })
+// @as(@Vector(2, f80), .{ undefined, 0 })
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), .{ 0, undefined })
+// @as(@Vector(2, f80), .{ 0, undefined })
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), .{ undefined, 0 })
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), .{ undefined, 0 })
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), undefined)
+// @as(f80, undefined)
+// @as(f80, undefined)
+// @as(@Vector(2, f80), .{ 9, undefined })
+// @as(@Vector(2, f80), .{ undefined, 9 })
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), .{ 9, undefined })
+// @as(@Vector(2, f80), .{ 9, undefined })
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), .{ undefined, 9 })
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), .{ undefined, 9 })
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), undefined)
+// @as(f80, undefined)
+// @as(@Vector(2, f80), .{ -3, undefined })
+// @as(@Vector(2, f80), .{ undefined, -3 })
+// @as(@Vector(2, f80), undefined)
+// @as(f80, undefined)
+// @as(f80, undefined)
+// @as(@Vector(2, f80), [runtime value])
+// @as(@Vector(2, f80), [runtime value])
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), [runtime value])
+// @as(@Vector(2, f80), [runtime value])
+// @as(@Vector(2, f80), [runtime value])
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), [runtime value])
+// @as(@Vector(2, f80), [runtime value])
+// @as(@Vector(2, f80), [runtime value])
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), undefined)
+// @as(f80, undefined)
+// @as(f80, undefined)
+// @as(@Vector(2, f80), [runtime value])
+// @as(@Vector(2, f80), [runtime value])
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), [runtime value])
+// @as(@Vector(2, f80), [runtime value])
+// @as(@Vector(2, f80), [runtime value])
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), [runtime value])
+// @as(@Vector(2, f80), [runtime value])
+// @as(@Vector(2, f80), [runtime value])
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), undefined)
+// @as(f80, undefined)
+// @as(f80, undefined)
+// @as(@Vector(2, f80), [runtime value])
+// @as(@Vector(2, f80), [runtime value])
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), [runtime value])
+// @as(@Vector(2, f80), [runtime value])
+// @as(@Vector(2, f80), [runtime value])
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), [runtime value])
+// @as(@Vector(2, f80), [runtime value])
+// @as(@Vector(2, f80), [runtime value])
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), undefined)
+// @as(@Vector(2, f80), undefined)
+// @as(f80, undefined)
+// @as(@Vector(2, f80), [runtime value])
+// @as(@Vector(2, f80), [runtime value])
+// @as(@Vector(2, f80), undefined)
+// @as(f64, undefined)
+// @as(f64, undefined)
+// @as(@Vector(2, f64), .{ 6, undefined })
+// @as(@Vector(2, f64), .{ undefined, 6 })
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), .{ 6, undefined })
+// @as(@Vector(2, f64), .{ 6, undefined })
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), .{ undefined, 6 })
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), .{ undefined, 6 })
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), undefined)
+// @as(f64, undefined)
+// @as(f64, undefined)
+// @as(@Vector(2, f64), .{ 0, undefined })
+// @as(@Vector(2, f64), .{ undefined, 0 })
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), .{ 0, undefined })
+// @as(@Vector(2, f64), .{ 0, undefined })
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), .{ undefined, 0 })
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), .{ undefined, 0 })
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), undefined)
+// @as(f64, undefined)
+// @as(f64, undefined)
+// @as(@Vector(2, f64), .{ 9, undefined })
+// @as(@Vector(2, f64), .{ undefined, 9 })
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), .{ 9, undefined })
+// @as(@Vector(2, f64), .{ 9, undefined })
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), .{ undefined, 9 })
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), .{ undefined, 9 })
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), undefined)
+// @as(f64, undefined)
+// @as(@Vector(2, f64), .{ -3, undefined })
+// @as(@Vector(2, f64), .{ undefined, -3 })
+// @as(@Vector(2, f64), undefined)
+// @as(f64, undefined)
+// @as(f64, undefined)
+// @as(@Vector(2, f64), [runtime value])
+// @as(@Vector(2, f64), [runtime value])
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), [runtime value])
+// @as(@Vector(2, f64), [runtime value])
+// @as(@Vector(2, f64), [runtime value])
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), [runtime value])
+// @as(@Vector(2, f64), [runtime value])
+// @as(@Vector(2, f64), [runtime value])
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), undefined)
+// @as(f64, undefined)
+// @as(f64, undefined)
+// @as(@Vector(2, f64), [runtime value])
+// @as(@Vector(2, f64), [runtime value])
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), [runtime value])
+// @as(@Vector(2, f64), [runtime value])
+// @as(@Vector(2, f64), [runtime value])
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), [runtime value])
+// @as(@Vector(2, f64), [runtime value])
+// @as(@Vector(2, f64), [runtime value])
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), undefined)
+// @as(f64, undefined)
+// @as(f64, undefined)
+// @as(@Vector(2, f64), [runtime value])
+// @as(@Vector(2, f64), [runtime value])
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), [runtime value])
+// @as(@Vector(2, f64), [runtime value])
+// @as(@Vector(2, f64), [runtime value])
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), [runtime value])
+// @as(@Vector(2, f64), [runtime value])
+// @as(@Vector(2, f64), [runtime value])
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), undefined)
+// @as(@Vector(2, f64), undefined)
+// @as(f64, undefined)
+// @as(@Vector(2, f64), [runtime value])
+// @as(@Vector(2, f64), [runtime value])
+// @as(@Vector(2, f64), undefined)
+// @as(f32, undefined)
+// @as(f32, undefined)
+// @as(@Vector(2, f32), .{ 6, undefined })
+// @as(@Vector(2, f32), .{ undefined, 6 })
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), .{ 6, undefined })
+// @as(@Vector(2, f32), .{ 6, undefined })
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), .{ undefined, 6 })
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), .{ undefined, 6 })
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), undefined)
+// @as(f32, undefined)
+// @as(f32, undefined)
+// @as(@Vector(2, f32), .{ 0, undefined })
+// @as(@Vector(2, f32), .{ undefined, 0 })
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), .{ 0, undefined })
+// @as(@Vector(2, f32), .{ 0, undefined })
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), .{ undefined, 0 })
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), .{ undefined, 0 })
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), undefined)
+// @as(f32, undefined)
+// @as(f32, undefined)
+// @as(@Vector(2, f32), .{ 9, undefined })
+// @as(@Vector(2, f32), .{ undefined, 9 })
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), .{ 9, undefined })
+// @as(@Vector(2, f32), .{ 9, undefined })
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), .{ undefined, 9 })
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), .{ undefined, 9 })
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), undefined)
+// @as(f32, undefined)
+// @as(@Vector(2, f32), .{ -3, undefined })
+// @as(@Vector(2, f32), .{ undefined, -3 })
+// @as(@Vector(2, f32), undefined)
+// @as(f32, undefined)
+// @as(f32, undefined)
+// @as(@Vector(2, f32), [runtime value])
+// @as(@Vector(2, f32), [runtime value])
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), [runtime value])
+// @as(@Vector(2, f32), [runtime value])
+// @as(@Vector(2, f32), [runtime value])
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), [runtime value])
+// @as(@Vector(2, f32), [runtime value])
+// @as(@Vector(2, f32), [runtime value])
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), undefined)
+// @as(f32, undefined)
+// @as(f32, undefined)
+// @as(@Vector(2, f32), [runtime value])
+// @as(@Vector(2, f32), [runtime value])
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), [runtime value])
+// @as(@Vector(2, f32), [runtime value])
+// @as(@Vector(2, f32), [runtime value])
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), [runtime value])
+// @as(@Vector(2, f32), [runtime value])
+// @as(@Vector(2, f32), [runtime value])
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), undefined)
+// @as(f32, undefined)
+// @as(f32, undefined)
+// @as(@Vector(2, f32), [runtime value])
+// @as(@Vector(2, f32), [runtime value])
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), [runtime value])
+// @as(@Vector(2, f32), [runtime value])
+// @as(@Vector(2, f32), [runtime value])
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), [runtime value])
+// @as(@Vector(2, f32), [runtime value])
+// @as(@Vector(2, f32), [runtime value])
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), undefined)
+// @as(@Vector(2, f32), undefined)
+// @as(f32, undefined)
+// @as(@Vector(2, f32), [runtime value])
+// @as(@Vector(2, f32), [runtime value])
+// @as(@Vector(2, f32), undefined)
+// @as(f16, undefined)
+// @as(f16, undefined)
+// @as(@Vector(2, f16), .{ 6, undefined })
+// @as(@Vector(2, f16), .{ undefined, 6 })
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), .{ 6, undefined })
+// @as(@Vector(2, f16), .{ 6, undefined })
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), .{ undefined, 6 })
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), .{ undefined, 6 })
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), undefined)
+// @as(f16, undefined)
+// @as(f16, undefined)
+// @as(@Vector(2, f16), .{ 0, undefined })
+// @as(@Vector(2, f16), .{ undefined, 0 })
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), .{ 0, undefined })
+// @as(@Vector(2, f16), .{ 0, undefined })
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), .{ undefined, 0 })
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), .{ undefined, 0 })
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), undefined)
+// @as(f16, undefined)
+// @as(f16, undefined)
+// @as(@Vector(2, f16), .{ 9, undefined })
+// @as(@Vector(2, f16), .{ undefined, 9 })
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), .{ 9, undefined })
+// @as(@Vector(2, f16), .{ 9, undefined })
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), .{ undefined, 9 })
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), .{ undefined, 9 })
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), undefined)
+// @as(f16, undefined)
+// @as(@Vector(2, f16), .{ -3, undefined })
+// @as(@Vector(2, f16), .{ undefined, -3 })
+// @as(@Vector(2, f16), undefined)
+// @as(f16, undefined)
+// @as(f16, undefined)
+// @as(@Vector(2, f16), [runtime value])
+// @as(@Vector(2, f16), [runtime value])
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), [runtime value])
+// @as(@Vector(2, f16), [runtime value])
+// @as(@Vector(2, f16), [runtime value])
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), [runtime value])
+// @as(@Vector(2, f16), [runtime value])
+// @as(@Vector(2, f16), [runtime value])
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), undefined)
+// @as(f16, undefined)
+// @as(f16, undefined)
+// @as(@Vector(2, f16), [runtime value])
+// @as(@Vector(2, f16), [runtime value])
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), [runtime value])
+// @as(@Vector(2, f16), [runtime value])
+// @as(@Vector(2, f16), [runtime value])
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), [runtime value])
+// @as(@Vector(2, f16), [runtime value])
+// @as(@Vector(2, f16), [runtime value])
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), undefined)
+// @as(f16, undefined)
+// @as(f16, undefined)
+// @as(@Vector(2, f16), [runtime value])
+// @as(@Vector(2, f16), [runtime value])
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), [runtime value])
+// @as(@Vector(2, f16), [runtime value])
+// @as(@Vector(2, f16), [runtime value])
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), [runtime value])
+// @as(@Vector(2, f16), [runtime value])
+// @as(@Vector(2, f16), [runtime value])
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), undefined)
+// @as(@Vector(2, f16), undefined)
+// @as(f16, undefined)
+// @as(@Vector(2, f16), [runtime value])
+// @as(@Vector(2, f16), [runtime value])
+// @as(@Vector(2, f16), undefined)
diff --git a/test/cases/compile_errors/undef_shifts_are_illegal.zig b/test/cases/compile_errors/undef_shifts_are_illegal.zig
index 20c4571408db755b1d38f99585342106b7a94d0c..518da69194e8c43a831a8745cf985780307ab5d9 100644
--- a/test/cases/compile_errors/undef_shifts_are_illegal.zig
+++ b/test/cases/compile_errors/undef_shifts_are_illegal.zig
@@ -125,27 +125,19 @@ const std = @import("std");
// :53:17: error: use of undefined value here causes illegal behavior
// :53:17: error: use of undefined value here causes illegal behavior
// :53:17: error: use of undefined value here causes illegal behavior
-// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
-// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
-// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
-// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
-// :53:17: note: when computing vector element at index '1'
// :53:17: error: use of undefined value here causes illegal behavior
-// :53:17: note: when computing vector element at index '1'
// :53:17: error: use of undefined value here causes illegal behavior
-// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
-// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
-// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
-// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
+// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
+// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
@@ -155,9 +147,9 @@ const std = @import("std");
// :53:17: error: use of undefined value here causes illegal behavior
// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
-// :53:17: note: when computing vector element at index '1'
+// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
-// :53:17: note: when computing vector element at index '1'
+// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
@@ -167,7 +159,9 @@ const std = @import("std");
// :53:17: error: use of undefined value here causes illegal behavior
// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
+// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
+// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
@@ -177,9 +171,9 @@ const std = @import("std");
// :53:17: error: use of undefined value here causes illegal behavior
// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
-// :53:17: note: when computing vector element at index '1'
+// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
-// :53:17: note: when computing vector element at index '1'
+// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
@@ -189,7 +183,9 @@ const std = @import("std");
// :53:17: error: use of undefined value here causes illegal behavior
// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
+// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
+// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
@@ -199,9 +195,9 @@ const std = @import("std");
// :53:17: error: use of undefined value here causes illegal behavior
// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
-// :53:17: note: when computing vector element at index '1'
+// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
-// :53:17: note: when computing vector element at index '1'
+// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
@@ -211,7 +207,9 @@ const std = @import("std");
// :53:17: error: use of undefined value here causes illegal behavior
// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
+// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
+// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
@@ -221,9 +219,9 @@ const std = @import("std");
// :53:17: error: use of undefined value here causes illegal behavior
// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
-// :53:17: note: when computing vector element at index '1'
+// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
-// :53:17: note: when computing vector element at index '1'
+// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
@@ -233,27 +231,29 @@ const std = @import("std");
// :53:17: error: use of undefined value here causes illegal behavior
// :53:17: note: when computing vector element at index '0'
// :53:17: error: use of undefined value here causes illegal behavior
+// :53:17: note: when computing vector element at index '1'
// :53:17: error: use of undefined value here causes illegal behavior
+// :53:17: note: when computing vector element at index '1'
// :53:17: error: use of undefined value here causes illegal behavior
-// :53:17: note: when computing vector element at index '0'
+// :53:17: note: when computing vector element at index '1'
// :53:17: error: use of undefined value here causes illegal behavior
-// :53:17: note: when computing vector element at index '0'
+// :53:17: note: when computing vector element at index '1'
// :53:17: error: use of undefined value here causes illegal behavior
-// :53:17: note: when computing vector element at index '0'
+// :53:17: note: when computing vector element at index '1'
// :53:17: error: use of undefined value here causes illegal behavior
-// :53:17: note: when computing vector element at index '0'
+// :53:17: note: when computing vector element at index '1'
// :53:17: error: use of undefined value here causes illegal behavior
// :53:17: note: when computing vector element at index '1'
// :53:17: error: use of undefined value here causes illegal behavior
// :53:17: note: when computing vector element at index '1'
// :53:17: error: use of undefined value here causes illegal behavior
-// :53:17: note: when computing vector element at index '0'
+// :53:17: note: when computing vector element at index '1'
// :53:17: error: use of undefined value here causes illegal behavior
-// :53:17: note: when computing vector element at index '0'
+// :53:17: note: when computing vector element at index '1'
// :53:17: error: use of undefined value here causes illegal behavior
-// :53:17: note: when computing vector element at index '0'
+// :53:17: note: when computing vector element at index '1'
// :53:17: error: use of undefined value here causes illegal behavior
-// :53:17: note: when computing vector element at index '0'
+// :53:17: note: when computing vector element at index '1'
// :53:22: error: use of undefined value here causes illegal behavior
// :53:22: note: when computing vector element at index '0'
// :53:22: error: use of undefined value here causes illegal behavior
@@ -281,27 +281,19 @@ const std = @import("std");
// :56:27: error: use of undefined value here causes illegal behavior
// :56:27: error: use of undefined value here causes illegal behavior
// :56:27: error: use of undefined value here causes illegal behavior
-// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
-// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
-// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
-// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
-// :56:27: note: when computing vector element at index '1'
// :56:27: error: use of undefined value here causes illegal behavior
-// :56:27: note: when computing vector element at index '1'
// :56:27: error: use of undefined value here causes illegal behavior
-// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
-// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
-// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
-// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
+// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
+// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
@@ -311,9 +303,9 @@ const std = @import("std");
// :56:27: error: use of undefined value here causes illegal behavior
// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
-// :56:27: note: when computing vector element at index '1'
+// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
-// :56:27: note: when computing vector element at index '1'
+// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
@@ -323,7 +315,9 @@ const std = @import("std");
// :56:27: error: use of undefined value here causes illegal behavior
// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
+// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
+// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
@@ -333,9 +327,9 @@ const std = @import("std");
// :56:27: error: use of undefined value here causes illegal behavior
// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
-// :56:27: note: when computing vector element at index '1'
+// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
-// :56:27: note: when computing vector element at index '1'
+// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
@@ -345,7 +339,9 @@ const std = @import("std");
// :56:27: error: use of undefined value here causes illegal behavior
// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
+// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
+// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
@@ -355,9 +351,9 @@ const std = @import("std");
// :56:27: error: use of undefined value here causes illegal behavior
// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
-// :56:27: note: when computing vector element at index '1'
+// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
-// :56:27: note: when computing vector element at index '1'
+// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
@@ -367,7 +363,9 @@ const std = @import("std");
// :56:27: error: use of undefined value here causes illegal behavior
// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
+// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
+// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
@@ -377,9 +375,9 @@ const std = @import("std");
// :56:27: error: use of undefined value here causes illegal behavior
// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
-// :56:27: note: when computing vector element at index '1'
+// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
-// :56:27: note: when computing vector element at index '1'
+// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
@@ -389,27 +387,29 @@ const std = @import("std");
// :56:27: error: use of undefined value here causes illegal behavior
// :56:27: note: when computing vector element at index '0'
// :56:27: error: use of undefined value here causes illegal behavior
+// :56:27: note: when computing vector element at index '1'
// :56:27: error: use of undefined value here causes illegal behavior
+// :56:27: note: when computing vector element at index '1'
// :56:27: error: use of undefined value here causes illegal behavior
-// :56:27: note: when computing vector element at index '0'
+// :56:27: note: when computing vector element at index '1'
// :56:27: error: use of undefined value here causes illegal behavior
-// :56:27: note: when computing vector element at index '0'
+// :56:27: note: when computing vector element at index '1'
// :56:27: error: use of undefined value here causes illegal behavior
-// :56:27: note: when computing vector element at index '0'
+// :56:27: note: when computing vector element at index '1'
// :56:27: error: use of undefined value here causes illegal behavior
-// :56:27: note: when computing vector element at index '0'
+// :56:27: note: when computing vector element at index '1'
// :56:27: error: use of undefined value here causes illegal behavior
// :56:27: note: when computing vector element at index '1'
// :56:27: error: use of undefined value here causes illegal behavior
// :56:27: note: when computing vector element at index '1'
// :56:27: error: use of undefined value here causes illegal behavior
-// :56:27: note: when computing vector element at index '0'
+// :56:27: note: when computing vector element at index '1'
// :56:27: error: use of undefined value here causes illegal behavior
-// :56:27: note: when computing vector element at index '0'
+// :56:27: note: when computing vector element at index '1'
// :56:27: error: use of undefined value here causes illegal behavior
-// :56:27: note: when computing vector element at index '0'
+// :56:27: note: when computing vector element at index '1'
// :56:27: error: use of undefined value here causes illegal behavior
-// :56:27: note: when computing vector element at index '0'
+// :56:27: note: when computing vector element at index '1'
// :56:30: error: use of undefined value here causes illegal behavior
// :56:30: note: when computing vector element at index '0'
// :56:30: error: use of undefined value here causes illegal behavior
@@ -437,27 +437,19 @@ const std = @import("std");
// :59:34: error: use of undefined value here causes illegal behavior
// :59:34: error: use of undefined value here causes illegal behavior
// :59:34: error: use of undefined value here causes illegal behavior
-// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
-// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
-// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
-// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
-// :59:34: note: when computing vector element at index '1'
// :59:34: error: use of undefined value here causes illegal behavior
-// :59:34: note: when computing vector element at index '1'
// :59:34: error: use of undefined value here causes illegal behavior
-// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
-// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
-// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
-// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
+// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
+// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
@@ -467,9 +459,9 @@ const std = @import("std");
// :59:34: error: use of undefined value here causes illegal behavior
// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
-// :59:34: note: when computing vector element at index '1'
+// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
-// :59:34: note: when computing vector element at index '1'
+// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
@@ -479,7 +471,9 @@ const std = @import("std");
// :59:34: error: use of undefined value here causes illegal behavior
// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
+// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
+// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
@@ -489,9 +483,9 @@ const std = @import("std");
// :59:34: error: use of undefined value here causes illegal behavior
// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
-// :59:34: note: when computing vector element at index '1'
+// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
-// :59:34: note: when computing vector element at index '1'
+// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
@@ -501,7 +495,9 @@ const std = @import("std");
// :59:34: error: use of undefined value here causes illegal behavior
// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
+// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
+// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
@@ -511,9 +507,9 @@ const std = @import("std");
// :59:34: error: use of undefined value here causes illegal behavior
// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
-// :59:34: note: when computing vector element at index '1'
+// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
-// :59:34: note: when computing vector element at index '1'
+// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
@@ -523,7 +519,9 @@ const std = @import("std");
// :59:34: error: use of undefined value here causes illegal behavior
// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
+// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
+// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
@@ -533,9 +531,9 @@ const std = @import("std");
// :59:34: error: use of undefined value here causes illegal behavior
// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
-// :59:34: note: when computing vector element at index '1'
+// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
-// :59:34: note: when computing vector element at index '1'
+// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
@@ -545,27 +543,29 @@ const std = @import("std");
// :59:34: error: use of undefined value here causes illegal behavior
// :59:34: note: when computing vector element at index '0'
// :59:34: error: use of undefined value here causes illegal behavior
+// :59:34: note: when computing vector element at index '1'
// :59:34: error: use of undefined value here causes illegal behavior
+// :59:34: note: when computing vector element at index '1'
// :59:34: error: use of undefined value here causes illegal behavior
-// :59:34: note: when computing vector element at index '0'
+// :59:34: note: when computing vector element at index '1'
// :59:34: error: use of undefined value here causes illegal behavior
-// :59:34: note: when computing vector element at index '0'
+// :59:34: note: when computing vector element at index '1'
// :59:34: error: use of undefined value here causes illegal behavior
-// :59:34: note: when computing vector element at index '0'
+// :59:34: note: when computing vector element at index '1'
// :59:34: error: use of undefined value here causes illegal behavior
-// :59:34: note: when computing vector element at index '0'
+// :59:34: note: when computing vector element at index '1'
// :59:34: error: use of undefined value here causes illegal behavior
// :59:34: note: when computing vector element at index '1'
// :59:34: error: use of undefined value here causes illegal behavior
// :59:34: note: when computing vector element at index '1'
// :59:34: error: use of undefined value here causes illegal behavior
-// :59:34: note: when computing vector element at index '0'
+// :59:34: note: when computing vector element at index '1'
// :59:34: error: use of undefined value here causes illegal behavior
-// :59:34: note: when computing vector element at index '0'
+// :59:34: note: when computing vector element at index '1'
// :59:34: error: use of undefined value here causes illegal behavior
-// :59:34: note: when computing vector element at index '0'
+// :59:34: note: when computing vector element at index '1'
// :59:34: error: use of undefined value here causes illegal behavior
-// :59:34: note: when computing vector element at index '0'
+// :59:34: note: when computing vector element at index '1'
// :59:37: error: use of undefined value here causes illegal behavior
// :59:37: note: when computing vector element at index '0'
// :59:37: error: use of undefined value here causes illegal behavior
@@ -593,27 +593,19 @@ const std = @import("std");
// :62:17: error: use of undefined value here causes illegal behavior
// :62:17: error: use of undefined value here causes illegal behavior
// :62:17: error: use of undefined value here causes illegal behavior
-// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
-// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
-// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
-// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
-// :62:17: note: when computing vector element at index '1'
// :62:17: error: use of undefined value here causes illegal behavior
-// :62:17: note: when computing vector element at index '1'
// :62:17: error: use of undefined value here causes illegal behavior
-// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
-// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
-// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
-// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
+// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
+// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
@@ -623,9 +615,9 @@ const std = @import("std");
// :62:17: error: use of undefined value here causes illegal behavior
// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
-// :62:17: note: when computing vector element at index '1'
+// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
-// :62:17: note: when computing vector element at index '1'
+// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
@@ -635,7 +627,9 @@ const std = @import("std");
// :62:17: error: use of undefined value here causes illegal behavior
// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
+// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
+// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
@@ -645,9 +639,9 @@ const std = @import("std");
// :62:17: error: use of undefined value here causes illegal behavior
// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
-// :62:17: note: when computing vector element at index '1'
+// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
-// :62:17: note: when computing vector element at index '1'
+// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
@@ -657,7 +651,9 @@ const std = @import("std");
// :62:17: error: use of undefined value here causes illegal behavior
// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
+// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
+// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
@@ -667,9 +663,9 @@ const std = @import("std");
// :62:17: error: use of undefined value here causes illegal behavior
// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
-// :62:17: note: when computing vector element at index '1'
+// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
-// :62:17: note: when computing vector element at index '1'
+// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
@@ -679,7 +675,9 @@ const std = @import("std");
// :62:17: error: use of undefined value here causes illegal behavior
// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
+// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
+// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
@@ -689,9 +687,9 @@ const std = @import("std");
// :62:17: error: use of undefined value here causes illegal behavior
// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
-// :62:17: note: when computing vector element at index '1'
+// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
-// :62:17: note: when computing vector element at index '1'
+// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
@@ -701,27 +699,29 @@ const std = @import("std");
// :62:17: error: use of undefined value here causes illegal behavior
// :62:17: note: when computing vector element at index '0'
// :62:17: error: use of undefined value here causes illegal behavior
+// :62:17: note: when computing vector element at index '1'
// :62:17: error: use of undefined value here causes illegal behavior
+// :62:17: note: when computing vector element at index '1'
// :62:17: error: use of undefined value here causes illegal behavior
-// :62:17: note: when computing vector element at index '0'
+// :62:17: note: when computing vector element at index '1'
// :62:17: error: use of undefined value here causes illegal behavior
-// :62:17: note: when computing vector element at index '0'
+// :62:17: note: when computing vector element at index '1'
// :62:17: error: use of undefined value here causes illegal behavior
-// :62:17: note: when computing vector element at index '0'
+// :62:17: note: when computing vector element at index '1'
// :62:17: error: use of undefined value here causes illegal behavior
-// :62:17: note: when computing vector element at index '0'
+// :62:17: note: when computing vector element at index '1'
// :62:17: error: use of undefined value here causes illegal behavior
// :62:17: note: when computing vector element at index '1'
// :62:17: error: use of undefined value here causes illegal behavior
// :62:17: note: when computing vector element at index '1'
// :62:17: error: use of undefined value here causes illegal behavior
-// :62:17: note: when computing vector element at index '0'
+// :62:17: note: when computing vector element at index '1'
// :62:17: error: use of undefined value here causes illegal behavior
-// :62:17: note: when computing vector element at index '0'
+// :62:17: note: when computing vector element at index '1'
// :62:17: error: use of undefined value here causes illegal behavior
-// :62:17: note: when computing vector element at index '0'
+// :62:17: note: when computing vector element at index '1'
// :62:17: error: use of undefined value here causes illegal behavior
-// :62:17: note: when computing vector element at index '0'
+// :62:17: note: when computing vector element at index '1'
// :62:22: error: use of undefined value here causes illegal behavior
// :62:22: note: when computing vector element at index '0'
// :62:22: error: use of undefined value here causes illegal behavior
@@ -749,27 +749,19 @@ const std = @import("std");
// :65:27: error: use of undefined value here causes illegal behavior
// :65:27: error: use of undefined value here causes illegal behavior
// :65:27: error: use of undefined value here causes illegal behavior
-// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
-// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
-// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
-// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
-// :65:27: note: when computing vector element at index '1'
// :65:27: error: use of undefined value here causes illegal behavior
-// :65:27: note: when computing vector element at index '1'
// :65:27: error: use of undefined value here causes illegal behavior
-// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
-// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
-// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
-// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
+// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
+// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
@@ -779,9 +771,9 @@ const std = @import("std");
// :65:27: error: use of undefined value here causes illegal behavior
// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
-// :65:27: note: when computing vector element at index '1'
+// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
-// :65:27: note: when computing vector element at index '1'
+// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
@@ -791,7 +783,9 @@ const std = @import("std");
// :65:27: error: use of undefined value here causes illegal behavior
// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
+// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
+// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
@@ -801,9 +795,9 @@ const std = @import("std");
// :65:27: error: use of undefined value here causes illegal behavior
// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
-// :65:27: note: when computing vector element at index '1'
+// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
-// :65:27: note: when computing vector element at index '1'
+// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
@@ -813,7 +807,9 @@ const std = @import("std");
// :65:27: error: use of undefined value here causes illegal behavior
// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
+// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
+// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
@@ -823,9 +819,9 @@ const std = @import("std");
// :65:27: error: use of undefined value here causes illegal behavior
// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
-// :65:27: note: when computing vector element at index '1'
+// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
-// :65:27: note: when computing vector element at index '1'
+// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
@@ -835,7 +831,9 @@ const std = @import("std");
// :65:27: error: use of undefined value here causes illegal behavior
// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
+// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
+// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
@@ -845,9 +843,9 @@ const std = @import("std");
// :65:27: error: use of undefined value here causes illegal behavior
// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
-// :65:27: note: when computing vector element at index '1'
+// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
-// :65:27: note: when computing vector element at index '1'
+// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
@@ -857,27 +855,29 @@ const std = @import("std");
// :65:27: error: use of undefined value here causes illegal behavior
// :65:27: note: when computing vector element at index '0'
// :65:27: error: use of undefined value here causes illegal behavior
+// :65:27: note: when computing vector element at index '1'
// :65:27: error: use of undefined value here causes illegal behavior
+// :65:27: note: when computing vector element at index '1'
// :65:27: error: use of undefined value here causes illegal behavior
-// :65:27: note: when computing vector element at index '0'
+// :65:27: note: when computing vector element at index '1'
// :65:27: error: use of undefined value here causes illegal behavior
-// :65:27: note: when computing vector element at index '0'
+// :65:27: note: when computing vector element at index '1'
// :65:27: error: use of undefined value here causes illegal behavior
-// :65:27: note: when computing vector element at index '0'
+// :65:27: note: when computing vector element at index '1'
// :65:27: error: use of undefined value here causes illegal behavior
-// :65:27: note: when computing vector element at index '0'
+// :65:27: note: when computing vector element at index '1'
// :65:27: error: use of undefined value here causes illegal behavior
// :65:27: note: when computing vector element at index '1'
// :65:27: error: use of undefined value here causes illegal behavior
// :65:27: note: when computing vector element at index '1'
// :65:27: error: use of undefined value here causes illegal behavior
-// :65:27: note: when computing vector element at index '0'
+// :65:27: note: when computing vector element at index '1'
// :65:27: error: use of undefined value here causes illegal behavior
-// :65:27: note: when computing vector element at index '0'
+// :65:27: note: when computing vector element at index '1'
// :65:27: error: use of undefined value here causes illegal behavior
-// :65:27: note: when computing vector element at index '0'
+// :65:27: note: when computing vector element at index '1'
// :65:27: error: use of undefined value here causes illegal behavior
-// :65:27: note: when computing vector element at index '0'
+// :65:27: note: when computing vector element at index '1'
// :65:30: error: use of undefined value here causes illegal behavior
// :65:30: note: when computing vector element at index '0'
// :65:30: error: use of undefined value here causes illegal behavior
@@ -909,21 +909,13 @@ const std = @import("std");
// :70:17: error: use of undefined value here causes illegal behavior
// :70:17: error: use of undefined value here causes illegal behavior
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '1'
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '1'
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '1'
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '1'
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '0'
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '0'
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '0'
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '0'
// :70:17: error: use of undefined value here causes illegal behavior
// :70:17: error: use of undefined value here causes illegal behavior
// :70:17: error: use of undefined value here causes illegal behavior
@@ -931,21 +923,13 @@ const std = @import("std");
// :70:17: error: use of undefined value here causes illegal behavior
// :70:17: error: use of undefined value here causes illegal behavior
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '1'
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '1'
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '1'
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '1'
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '0'
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '0'
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '0'
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '0'
// :70:17: error: use of undefined value here causes illegal behavior
// :70:17: error: use of undefined value here causes illegal behavior
// :70:17: error: use of undefined value here causes illegal behavior
@@ -953,13 +937,11 @@ const std = @import("std");
// :70:17: error: use of undefined value here causes illegal behavior
// :70:17: error: use of undefined value here causes illegal behavior
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '1'
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '1'
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '1'
+// :70:17: note: when computing vector element at index '0'
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '1'
+// :70:17: note: when computing vector element at index '0'
// :70:17: error: use of undefined value here causes illegal behavior
// :70:17: note: when computing vector element at index '0'
// :70:17: error: use of undefined value here causes illegal behavior
@@ -969,19 +951,25 @@ const std = @import("std");
// :70:17: error: use of undefined value here causes illegal behavior
// :70:17: note: when computing vector element at index '0'
// :70:17: error: use of undefined value here causes illegal behavior
+// :70:17: note: when computing vector element at index '0'
// :70:17: error: use of undefined value here causes illegal behavior
+// :70:17: note: when computing vector element at index '0'
// :70:17: error: use of undefined value here causes illegal behavior
+// :70:17: note: when computing vector element at index '0'
// :70:17: error: use of undefined value here causes illegal behavior
+// :70:17: note: when computing vector element at index '0'
// :70:17: error: use of undefined value here causes illegal behavior
+// :70:17: note: when computing vector element at index '0'
// :70:17: error: use of undefined value here causes illegal behavior
+// :70:17: note: when computing vector element at index '0'
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '1'
+// :70:17: note: when computing vector element at index '0'
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '1'
+// :70:17: note: when computing vector element at index '0'
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '1'
+// :70:17: note: when computing vector element at index '0'
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '1'
+// :70:17: note: when computing vector element at index '0'
// :70:17: error: use of undefined value here causes illegal behavior
// :70:17: note: when computing vector element at index '0'
// :70:17: error: use of undefined value here causes illegal behavior
@@ -991,11 +979,17 @@ const std = @import("std");
// :70:17: error: use of undefined value here causes illegal behavior
// :70:17: note: when computing vector element at index '0'
// :70:17: error: use of undefined value here causes illegal behavior
+// :70:17: note: when computing vector element at index '0'
// :70:17: error: use of undefined value here causes illegal behavior
+// :70:17: note: when computing vector element at index '0'
// :70:17: error: use of undefined value here causes illegal behavior
+// :70:17: note: when computing vector element at index '0'
// :70:17: error: use of undefined value here causes illegal behavior
+// :70:17: note: when computing vector element at index '0'
// :70:17: error: use of undefined value here causes illegal behavior
+// :70:17: note: when computing vector element at index '1'
// :70:17: error: use of undefined value here causes illegal behavior
+// :70:17: note: when computing vector element at index '1'
// :70:17: error: use of undefined value here causes illegal behavior
// :70:17: note: when computing vector element at index '1'
// :70:17: error: use of undefined value here causes illegal behavior
@@ -1005,19 +999,25 @@ const std = @import("std");
// :70:17: error: use of undefined value here causes illegal behavior
// :70:17: note: when computing vector element at index '1'
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '0'
+// :70:17: note: when computing vector element at index '1'
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '0'
+// :70:17: note: when computing vector element at index '1'
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '0'
+// :70:17: note: when computing vector element at index '1'
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '0'
+// :70:17: note: when computing vector element at index '1'
// :70:17: error: use of undefined value here causes illegal behavior
+// :70:17: note: when computing vector element at index '1'
// :70:17: error: use of undefined value here causes illegal behavior
+// :70:17: note: when computing vector element at index '1'
// :70:17: error: use of undefined value here causes illegal behavior
+// :70:17: note: when computing vector element at index '1'
// :70:17: error: use of undefined value here causes illegal behavior
+// :70:17: note: when computing vector element at index '1'
// :70:17: error: use of undefined value here causes illegal behavior
+// :70:17: note: when computing vector element at index '1'
// :70:17: error: use of undefined value here causes illegal behavior
+// :70:17: note: when computing vector element at index '1'
// :70:17: error: use of undefined value here causes illegal behavior
// :70:17: note: when computing vector element at index '1'
// :70:17: error: use of undefined value here causes illegal behavior
@@ -1027,13 +1027,13 @@ const std = @import("std");
// :70:17: error: use of undefined value here causes illegal behavior
// :70:17: note: when computing vector element at index '1'
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '0'
+// :70:17: note: when computing vector element at index '1'
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '0'
+// :70:17: note: when computing vector element at index '1'
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '0'
+// :70:17: note: when computing vector element at index '1'
// :70:17: error: use of undefined value here causes illegal behavior
-// :70:17: note: when computing vector element at index '0'
+// :70:17: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: error: use of undefined value here causes illegal behavior
@@ -1041,21 +1041,13 @@ const std = @import("std");
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: error: use of undefined value here causes illegal behavior
@@ -1063,21 +1055,13 @@ const std = @import("std");
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: error: use of undefined value here causes illegal behavior
@@ -1085,13 +1069,11 @@ const std = @import("std");
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
@@ -1101,19 +1083,25 @@ const std = @import("std");
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '1'
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
@@ -1123,11 +1111,17 @@ const std = @import("std");
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '0'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
@@ -1137,19 +1131,25 @@ const std = @import("std");
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
+// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
+// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
+// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
+// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
+// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
@@ -1159,13 +1159,13 @@ const std = @import("std");
// :73:27: error: use of undefined value here causes illegal behavior
// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
+// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
+// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
+// :73:27: note: when computing vector element at index '1'
// :73:27: error: use of undefined value here causes illegal behavior
-// :73:27: note: when computing vector element at index '0'
+// :73:27: note: when computing vector element at index '1'
// :76:34: error: use of undefined value here causes illegal behavior
// :76:34: error: use of undefined value here causes illegal behavior
// :76:34: error: use of undefined value here causes illegal behavior
@@ -1173,21 +1173,13 @@ const std = @import("std");
// :76:34: error: use of undefined value here causes illegal behavior
// :76:34: error: use of undefined value here causes illegal behavior
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '1'
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '1'
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '1'
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '1'
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '0'
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '0'
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '0'
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '0'
// :76:34: error: use of undefined value here causes illegal behavior
// :76:34: error: use of undefined value here causes illegal behavior
// :76:34: error: use of undefined value here causes illegal behavior
@@ -1195,21 +1187,13 @@ const std = @import("std");
// :76:34: error: use of undefined value here causes illegal behavior
// :76:34: error: use of undefined value here causes illegal behavior
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '1'
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '1'
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '1'
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '1'
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '0'
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '0'
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '0'
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '0'
// :76:34: error: use of undefined value here causes illegal behavior
// :76:34: error: use of undefined value here causes illegal behavior
// :76:34: error: use of undefined value here causes illegal behavior
@@ -1217,13 +1201,11 @@ const std = @import("std");
// :76:34: error: use of undefined value here causes illegal behavior
// :76:34: error: use of undefined value here causes illegal behavior
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '1'
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '1'
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '1'
+// :76:34: note: when computing vector element at index '0'
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '1'
+// :76:34: note: when computing vector element at index '0'
// :76:34: error: use of undefined value here causes illegal behavior
// :76:34: note: when computing vector element at index '0'
// :76:34: error: use of undefined value here causes illegal behavior
@@ -1233,19 +1215,25 @@ const std = @import("std");
// :76:34: error: use of undefined value here causes illegal behavior
// :76:34: note: when computing vector element at index '0'
// :76:34: error: use of undefined value here causes illegal behavior
+// :76:34: note: when computing vector element at index '0'
// :76:34: error: use of undefined value here causes illegal behavior
+// :76:34: note: when computing vector element at index '0'
// :76:34: error: use of undefined value here causes illegal behavior
+// :76:34: note: when computing vector element at index '0'
// :76:34: error: use of undefined value here causes illegal behavior
+// :76:34: note: when computing vector element at index '0'
// :76:34: error: use of undefined value here causes illegal behavior
+// :76:34: note: when computing vector element at index '0'
// :76:34: error: use of undefined value here causes illegal behavior
+// :76:34: note: when computing vector element at index '0'
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '1'
+// :76:34: note: when computing vector element at index '0'
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '1'
+// :76:34: note: when computing vector element at index '0'
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '1'
+// :76:34: note: when computing vector element at index '0'
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '1'
+// :76:34: note: when computing vector element at index '0'
// :76:34: error: use of undefined value here causes illegal behavior
// :76:34: note: when computing vector element at index '0'
// :76:34: error: use of undefined value here causes illegal behavior
@@ -1255,11 +1243,17 @@ const std = @import("std");
// :76:34: error: use of undefined value here causes illegal behavior
// :76:34: note: when computing vector element at index '0'
// :76:34: error: use of undefined value here causes illegal behavior
+// :76:34: note: when computing vector element at index '0'
// :76:34: error: use of undefined value here causes illegal behavior
+// :76:34: note: when computing vector element at index '0'
// :76:34: error: use of undefined value here causes illegal behavior
+// :76:34: note: when computing vector element at index '0'
// :76:34: error: use of undefined value here causes illegal behavior
+// :76:34: note: when computing vector element at index '0'
// :76:34: error: use of undefined value here causes illegal behavior
+// :76:34: note: when computing vector element at index '1'
// :76:34: error: use of undefined value here causes illegal behavior
+// :76:34: note: when computing vector element at index '1'
// :76:34: error: use of undefined value here causes illegal behavior
// :76:34: note: when computing vector element at index '1'
// :76:34: error: use of undefined value here causes illegal behavior
@@ -1269,19 +1263,25 @@ const std = @import("std");
// :76:34: error: use of undefined value here causes illegal behavior
// :76:34: note: when computing vector element at index '1'
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '0'
+// :76:34: note: when computing vector element at index '1'
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '0'
+// :76:34: note: when computing vector element at index '1'
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '0'
+// :76:34: note: when computing vector element at index '1'
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '0'
+// :76:34: note: when computing vector element at index '1'
// :76:34: error: use of undefined value here causes illegal behavior
+// :76:34: note: when computing vector element at index '1'
// :76:34: error: use of undefined value here causes illegal behavior
+// :76:34: note: when computing vector element at index '1'
// :76:34: error: use of undefined value here causes illegal behavior
+// :76:34: note: when computing vector element at index '1'
// :76:34: error: use of undefined value here causes illegal behavior
+// :76:34: note: when computing vector element at index '1'
// :76:34: error: use of undefined value here causes illegal behavior
+// :76:34: note: when computing vector element at index '1'
// :76:34: error: use of undefined value here causes illegal behavior
+// :76:34: note: when computing vector element at index '1'
// :76:34: error: use of undefined value here causes illegal behavior
// :76:34: note: when computing vector element at index '1'
// :76:34: error: use of undefined value here causes illegal behavior
@@ -1291,13 +1291,13 @@ const std = @import("std");
// :76:34: error: use of undefined value here causes illegal behavior
// :76:34: note: when computing vector element at index '1'
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '0'
+// :76:34: note: when computing vector element at index '1'
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '0'
+// :76:34: note: when computing vector element at index '1'
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '0'
+// :76:34: note: when computing vector element at index '1'
// :76:34: error: use of undefined value here causes illegal behavior
-// :76:34: note: when computing vector element at index '0'
+// :76:34: note: when computing vector element at index '1'
// :79:17: error: use of undefined value here causes illegal behavior
// :79:17: error: use of undefined value here causes illegal behavior
// :79:17: error: use of undefined value here causes illegal behavior
@@ -1305,21 +1305,13 @@ const std = @import("std");
// :79:17: error: use of undefined value here causes illegal behavior
// :79:17: error: use of undefined value here causes illegal behavior
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '1'
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '1'
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '1'
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '1'
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '0'
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '0'
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '0'
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '0'
// :79:17: error: use of undefined value here causes illegal behavior
// :79:17: error: use of undefined value here causes illegal behavior
// :79:17: error: use of undefined value here causes illegal behavior
@@ -1327,21 +1319,13 @@ const std = @import("std");
// :79:17: error: use of undefined value here causes illegal behavior
// :79:17: error: use of undefined value here causes illegal behavior
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '1'
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '1'
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '1'
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '1'
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '0'
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '0'
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '0'
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '0'
// :79:17: error: use of undefined value here causes illegal behavior
// :79:17: error: use of undefined value here causes illegal behavior
// :79:17: error: use of undefined value here causes illegal behavior
@@ -1349,13 +1333,11 @@ const std = @import("std");
// :79:17: error: use of undefined value here causes illegal behavior
// :79:17: error: use of undefined value here causes illegal behavior
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '1'
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '1'
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '1'
+// :79:17: note: when computing vector element at index '0'
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '1'
+// :79:17: note: when computing vector element at index '0'
// :79:17: error: use of undefined value here causes illegal behavior
// :79:17: note: when computing vector element at index '0'
// :79:17: error: use of undefined value here causes illegal behavior
@@ -1365,19 +1347,25 @@ const std = @import("std");
// :79:17: error: use of undefined value here causes illegal behavior
// :79:17: note: when computing vector element at index '0'
// :79:17: error: use of undefined value here causes illegal behavior
+// :79:17: note: when computing vector element at index '0'
// :79:17: error: use of undefined value here causes illegal behavior
+// :79:17: note: when computing vector element at index '0'
// :79:17: error: use of undefined value here causes illegal behavior
+// :79:17: note: when computing vector element at index '0'
// :79:17: error: use of undefined value here causes illegal behavior
+// :79:17: note: when computing vector element at index '0'
// :79:17: error: use of undefined value here causes illegal behavior
+// :79:17: note: when computing vector element at index '0'
// :79:17: error: use of undefined value here causes illegal behavior
+// :79:17: note: when computing vector element at index '0'
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '1'
+// :79:17: note: when computing vector element at index '0'
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '1'
+// :79:17: note: when computing vector element at index '0'
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '1'
+// :79:17: note: when computing vector element at index '0'
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '1'
+// :79:17: note: when computing vector element at index '0'
// :79:17: error: use of undefined value here causes illegal behavior
// :79:17: note: when computing vector element at index '0'
// :79:17: error: use of undefined value here causes illegal behavior
@@ -1387,11 +1375,17 @@ const std = @import("std");
// :79:17: error: use of undefined value here causes illegal behavior
// :79:17: note: when computing vector element at index '0'
// :79:17: error: use of undefined value here causes illegal behavior
+// :79:17: note: when computing vector element at index '0'
// :79:17: error: use of undefined value here causes illegal behavior
+// :79:17: note: when computing vector element at index '0'
// :79:17: error: use of undefined value here causes illegal behavior
+// :79:17: note: when computing vector element at index '0'
// :79:17: error: use of undefined value here causes illegal behavior
+// :79:17: note: when computing vector element at index '0'
// :79:17: error: use of undefined value here causes illegal behavior
+// :79:17: note: when computing vector element at index '1'
// :79:17: error: use of undefined value here causes illegal behavior
+// :79:17: note: when computing vector element at index '1'
// :79:17: error: use of undefined value here causes illegal behavior
// :79:17: note: when computing vector element at index '1'
// :79:17: error: use of undefined value here causes illegal behavior
@@ -1401,19 +1395,25 @@ const std = @import("std");
// :79:17: error: use of undefined value here causes illegal behavior
// :79:17: note: when computing vector element at index '1'
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '0'
+// :79:17: note: when computing vector element at index '1'
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '0'
+// :79:17: note: when computing vector element at index '1'
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '0'
+// :79:17: note: when computing vector element at index '1'
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '0'
+// :79:17: note: when computing vector element at index '1'
// :79:17: error: use of undefined value here causes illegal behavior
+// :79:17: note: when computing vector element at index '1'
// :79:17: error: use of undefined value here causes illegal behavior
+// :79:17: note: when computing vector element at index '1'
// :79:17: error: use of undefined value here causes illegal behavior
+// :79:17: note: when computing vector element at index '1'
// :79:17: error: use of undefined value here causes illegal behavior
+// :79:17: note: when computing vector element at index '1'
// :79:17: error: use of undefined value here causes illegal behavior
+// :79:17: note: when computing vector element at index '1'
// :79:17: error: use of undefined value here causes illegal behavior
+// :79:17: note: when computing vector element at index '1'
// :79:17: error: use of undefined value here causes illegal behavior
// :79:17: note: when computing vector element at index '1'
// :79:17: error: use of undefined value here causes illegal behavior
@@ -1423,13 +1423,13 @@ const std = @import("std");
// :79:17: error: use of undefined value here causes illegal behavior
// :79:17: note: when computing vector element at index '1'
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '0'
+// :79:17: note: when computing vector element at index '1'
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '0'
+// :79:17: note: when computing vector element at index '1'
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '0'
+// :79:17: note: when computing vector element at index '1'
// :79:17: error: use of undefined value here causes illegal behavior
-// :79:17: note: when computing vector element at index '0'
+// :79:17: note: when computing vector element at index '1'
// :82:27: error: use of undefined value here causes illegal behavior
// :82:27: error: use of undefined value here causes illegal behavior
// :82:27: error: use of undefined value here causes illegal behavior
@@ -1437,21 +1437,13 @@ const std = @import("std");
// :82:27: error: use of undefined value here causes illegal behavior
// :82:27: error: use of undefined value here causes illegal behavior
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '1'
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '1'
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '1'
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '1'
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '0'
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '0'
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '0'
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '0'
// :82:27: error: use of undefined value here causes illegal behavior
// :82:27: error: use of undefined value here causes illegal behavior
// :82:27: error: use of undefined value here causes illegal behavior
@@ -1459,21 +1451,13 @@ const std = @import("std");
// :82:27: error: use of undefined value here causes illegal behavior
// :82:27: error: use of undefined value here causes illegal behavior
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '1'
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '1'
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '1'
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '1'
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '0'
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '0'
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '0'
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '0'
// :82:27: error: use of undefined value here causes illegal behavior
// :82:27: error: use of undefined value here causes illegal behavior
// :82:27: error: use of undefined value here causes illegal behavior
@@ -1481,13 +1465,11 @@ const std = @import("std");
// :82:27: error: use of undefined value here causes illegal behavior
// :82:27: error: use of undefined value here causes illegal behavior
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '1'
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '1'
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '1'
+// :82:27: note: when computing vector element at index '0'
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '1'
+// :82:27: note: when computing vector element at index '0'
// :82:27: error: use of undefined value here causes illegal behavior
// :82:27: note: when computing vector element at index '0'
// :82:27: error: use of undefined value here causes illegal behavior
@@ -1497,19 +1479,25 @@ const std = @import("std");
// :82:27: error: use of undefined value here causes illegal behavior
// :82:27: note: when computing vector element at index '0'
// :82:27: error: use of undefined value here causes illegal behavior
+// :82:27: note: when computing vector element at index '0'
// :82:27: error: use of undefined value here causes illegal behavior
+// :82:27: note: when computing vector element at index '0'
// :82:27: error: use of undefined value here causes illegal behavior
+// :82:27: note: when computing vector element at index '0'
// :82:27: error: use of undefined value here causes illegal behavior
+// :82:27: note: when computing vector element at index '0'
// :82:27: error: use of undefined value here causes illegal behavior
+// :82:27: note: when computing vector element at index '0'
// :82:27: error: use of undefined value here causes illegal behavior
+// :82:27: note: when computing vector element at index '0'
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '1'
+// :82:27: note: when computing vector element at index '0'
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '1'
+// :82:27: note: when computing vector element at index '0'
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '1'
+// :82:27: note: when computing vector element at index '0'
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '1'
+// :82:27: note: when computing vector element at index '0'
// :82:27: error: use of undefined value here causes illegal behavior
// :82:27: note: when computing vector element at index '0'
// :82:27: error: use of undefined value here causes illegal behavior
@@ -1519,11 +1507,17 @@ const std = @import("std");
// :82:27: error: use of undefined value here causes illegal behavior
// :82:27: note: when computing vector element at index '0'
// :82:27: error: use of undefined value here causes illegal behavior
+// :82:27: note: when computing vector element at index '0'
// :82:27: error: use of undefined value here causes illegal behavior
+// :82:27: note: when computing vector element at index '0'
// :82:27: error: use of undefined value here causes illegal behavior
+// :82:27: note: when computing vector element at index '0'
// :82:27: error: use of undefined value here causes illegal behavior
+// :82:27: note: when computing vector element at index '0'
// :82:27: error: use of undefined value here causes illegal behavior
+// :82:27: note: when computing vector element at index '1'
// :82:27: error: use of undefined value here causes illegal behavior
+// :82:27: note: when computing vector element at index '1'
// :82:27: error: use of undefined value here causes illegal behavior
// :82:27: note: when computing vector element at index '1'
// :82:27: error: use of undefined value here causes illegal behavior
@@ -1533,19 +1527,25 @@ const std = @import("std");
// :82:27: error: use of undefined value here causes illegal behavior
// :82:27: note: when computing vector element at index '1'
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '0'
+// :82:27: note: when computing vector element at index '1'
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '0'
+// :82:27: note: when computing vector element at index '1'
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '0'
+// :82:27: note: when computing vector element at index '1'
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '0'
+// :82:27: note: when computing vector element at index '1'
// :82:27: error: use of undefined value here causes illegal behavior
+// :82:27: note: when computing vector element at index '1'
// :82:27: error: use of undefined value here causes illegal behavior
+// :82:27: note: when computing vector element at index '1'
// :82:27: error: use of undefined value here causes illegal behavior
+// :82:27: note: when computing vector element at index '1'
// :82:27: error: use of undefined value here causes illegal behavior
+// :82:27: note: when computing vector element at index '1'
// :82:27: error: use of undefined value here causes illegal behavior
+// :82:27: note: when computing vector element at index '1'
// :82:27: error: use of undefined value here causes illegal behavior
+// :82:27: note: when computing vector element at index '1'
// :82:27: error: use of undefined value here causes illegal behavior
// :82:27: note: when computing vector element at index '1'
// :82:27: error: use of undefined value here causes illegal behavior
@@ -1555,44 +1555,37 @@ const std = @import("std");
// :82:27: error: use of undefined value here causes illegal behavior
// :82:27: note: when computing vector element at index '1'
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '0'
+// :82:27: note: when computing vector element at index '1'
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '0'
+// :82:27: note: when computing vector element at index '1'
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '0'
+// :82:27: note: when computing vector element at index '1'
// :82:27: error: use of undefined value here causes illegal behavior
-// :82:27: note: when computing vector element at index '0'
+// :82:27: note: when computing vector element at index '1'
// :87:17: error: use of undefined value here causes illegal behavior
// :87:17: error: use of undefined value here causes illegal behavior
-// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
-// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
-// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
-// :87:17: note: when computing vector element at index '1'
// :87:17: error: use of undefined value here causes illegal behavior
-// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
-// :87:17: error: use of undefined value here causes illegal behavior
// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
-// :87:17: note: when computing vector element at index '1'
-// :87:17: error: use of undefined value here causes illegal behavior
// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
+// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
@@ -1600,7 +1593,7 @@ const std = @import("std");
// :87:17: error: use of undefined value here causes illegal behavior
// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
-// :87:17: note: when computing vector element at index '1'
+// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
@@ -1608,6 +1601,7 @@ const std = @import("std");
// :87:17: error: use of undefined value here causes illegal behavior
// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
+// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
@@ -1615,7 +1609,7 @@ const std = @import("std");
// :87:17: error: use of undefined value here causes illegal behavior
// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
-// :87:17: note: when computing vector element at index '1'
+// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
@@ -1623,6 +1617,7 @@ const std = @import("std");
// :87:17: error: use of undefined value here causes illegal behavior
// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
+// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
@@ -1630,7 +1625,7 @@ const std = @import("std");
// :87:17: error: use of undefined value here causes illegal behavior
// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
-// :87:17: note: when computing vector element at index '1'
+// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
@@ -1638,6 +1633,7 @@ const std = @import("std");
// :87:17: error: use of undefined value here causes illegal behavior
// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
+// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
// :87:17: note: when computing vector element at index '0'
// :87:17: error: use of undefined value here causes illegal behavior
@@ -1647,108 +1643,105 @@ const std = @import("std");
// :87:17: error: use of undefined value here causes illegal behavior
// :87:17: note: when computing vector element at index '1'
// :87:17: error: use of undefined value here causes illegal behavior
-// :87:17: note: when computing vector element at index '0'
+// :87:17: note: when computing vector element at index '1'
// :87:17: error: use of undefined value here causes illegal behavior
-// :87:17: note: when computing vector element at index '0'
+// :87:17: note: when computing vector element at index '1'
// :87:17: error: use of undefined value here causes illegal behavior
-// :87:17: note: when computing vector element at index '0'
+// :87:17: note: when computing vector element at index '1'
+// :87:17: error: use of undefined value here causes illegal behavior
+// :87:17: note: when computing vector element at index '1'
+// :87:17: error: use of undefined value here causes illegal behavior
+// :87:17: note: when computing vector element at index '1'
// :87:22: error: use of undefined value here causes illegal behavior
// :87:22: error: use of undefined value here causes illegal behavior
-// :87:22: note: when computing vector element at index '0'
// :87:22: error: use of undefined value here causes illegal behavior
-// :87:22: note: when computing vector element at index '0'
// :87:22: error: use of undefined value here causes illegal behavior
-// :87:22: note: when computing vector element at index '1'
// :87:22: error: use of undefined value here causes illegal behavior
-// :87:22: note: when computing vector element at index '0'
// :87:22: error: use of undefined value here causes illegal behavior
-// :87:22: note: when computing vector element at index '0'
// :87:22: error: use of undefined value here causes illegal behavior
+// :87:22: note: when computing vector element at index '0'
// :87:22: error: use of undefined value here causes illegal behavior
// :87:22: note: when computing vector element at index '0'
// :87:22: error: use of undefined value here causes illegal behavior
// :87:22: note: when computing vector element at index '0'
// :87:22: error: use of undefined value here causes illegal behavior
-// :87:22: note: when computing vector element at index '1'
+// :87:22: note: when computing vector element at index '0'
// :87:22: error: use of undefined value here causes illegal behavior
// :87:22: note: when computing vector element at index '0'
// :87:22: error: use of undefined value here causes illegal behavior
// :87:22: note: when computing vector element at index '0'
// :87:22: error: use of undefined value here causes illegal behavior
+// :87:22: note: when computing vector element at index '0'
// :87:22: error: use of undefined value here causes illegal behavior
// :87:22: note: when computing vector element at index '0'
// :87:22: error: use of undefined value here causes illegal behavior
// :87:22: note: when computing vector element at index '0'
// :87:22: error: use of undefined value here causes illegal behavior
-// :87:22: note: when computing vector element at index '1'
+// :87:22: note: when computing vector element at index '0'
// :87:22: error: use of undefined value here causes illegal behavior
// :87:22: note: when computing vector element at index '0'
// :87:22: error: use of undefined value here causes illegal behavior
// :87:22: note: when computing vector element at index '0'
// :87:22: error: use of undefined value here causes illegal behavior
+// :87:22: note: when computing vector element at index '0'
// :87:22: error: use of undefined value here causes illegal behavior
// :87:22: note: when computing vector element at index '0'
// :87:22: error: use of undefined value here causes illegal behavior
// :87:22: note: when computing vector element at index '0'
// :87:22: error: use of undefined value here causes illegal behavior
-// :87:22: note: when computing vector element at index '1'
+// :87:22: note: when computing vector element at index '0'
// :87:22: error: use of undefined value here causes illegal behavior
// :87:22: note: when computing vector element at index '0'
// :87:22: error: use of undefined value here causes illegal behavior
// :87:22: note: when computing vector element at index '0'
// :87:22: error: use of undefined value here causes illegal behavior
+// :87:22: note: when computing vector element at index '0'
// :87:22: error: use of undefined value here causes illegal behavior
// :87:22: note: when computing vector element at index '0'
// :87:22: error: use of undefined value here causes illegal behavior
// :87:22: note: when computing vector element at index '0'
// :87:22: error: use of undefined value here causes illegal behavior
-// :87:22: note: when computing vector element at index '1'
+// :87:22: note: when computing vector element at index '0'
// :87:22: error: use of undefined value here causes illegal behavior
// :87:22: note: when computing vector element at index '0'
// :87:22: error: use of undefined value here causes illegal behavior
// :87:22: note: when computing vector element at index '0'
// :87:22: error: use of undefined value here causes illegal behavior
+// :87:22: note: when computing vector element at index '1'
// :87:22: error: use of undefined value here causes illegal behavior
-// :87:22: note: when computing vector element at index '0'
+// :87:22: note: when computing vector element at index '1'
// :87:22: error: use of undefined value here causes illegal behavior
-// :87:22: note: when computing vector element at index '0'
+// :87:22: note: when computing vector element at index '1'
// :87:22: error: use of undefined value here causes illegal behavior
// :87:22: note: when computing vector element at index '1'
// :87:22: error: use of undefined value here causes illegal behavior
-// :87:22: note: when computing vector element at index '0'
+// :87:22: note: when computing vector element at index '1'
// :87:22: error: use of undefined value here causes illegal behavior
-// :87:22: note: when computing vector element at index '0'
+// :87:22: note: when computing vector element at index '1'
// :90:27: error: use of undefined value here causes illegal behavior
// :90:27: error: use of undefined value here causes illegal behavior
-// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
-// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
-// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
-// :90:27: note: when computing vector element at index '1'
// :90:27: error: use of undefined value here causes illegal behavior
-// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
-// :90:27: error: use of undefined value here causes illegal behavior
// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
-// :90:27: note: when computing vector element at index '1'
-// :90:27: error: use of undefined value here causes illegal behavior
// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
+// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
@@ -1756,7 +1749,7 @@ const std = @import("std");
// :90:27: error: use of undefined value here causes illegal behavior
// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
-// :90:27: note: when computing vector element at index '1'
+// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
@@ -1764,6 +1757,7 @@ const std = @import("std");
// :90:27: error: use of undefined value here causes illegal behavior
// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
+// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
@@ -1771,7 +1765,7 @@ const std = @import("std");
// :90:27: error: use of undefined value here causes illegal behavior
// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
-// :90:27: note: when computing vector element at index '1'
+// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
@@ -1779,6 +1773,7 @@ const std = @import("std");
// :90:27: error: use of undefined value here causes illegal behavior
// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
+// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
@@ -1786,7 +1781,7 @@ const std = @import("std");
// :90:27: error: use of undefined value here causes illegal behavior
// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
-// :90:27: note: when computing vector element at index '1'
+// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
@@ -1794,6 +1789,7 @@ const std = @import("std");
// :90:27: error: use of undefined value here causes illegal behavior
// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
+// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
// :90:27: note: when computing vector element at index '0'
// :90:27: error: use of undefined value here causes illegal behavior
@@ -1803,108 +1799,105 @@ const std = @import("std");
// :90:27: error: use of undefined value here causes illegal behavior
// :90:27: note: when computing vector element at index '1'
// :90:27: error: use of undefined value here causes illegal behavior
-// :90:27: note: when computing vector element at index '0'
+// :90:27: note: when computing vector element at index '1'
// :90:27: error: use of undefined value here causes illegal behavior
-// :90:27: note: when computing vector element at index '0'
+// :90:27: note: when computing vector element at index '1'
// :90:27: error: use of undefined value here causes illegal behavior
-// :90:27: note: when computing vector element at index '0'
+// :90:27: note: when computing vector element at index '1'
+// :90:27: error: use of undefined value here causes illegal behavior
+// :90:27: note: when computing vector element at index '1'
+// :90:27: error: use of undefined value here causes illegal behavior
+// :90:27: note: when computing vector element at index '1'
// :90:30: error: use of undefined value here causes illegal behavior
// :90:30: error: use of undefined value here causes illegal behavior
-// :90:30: note: when computing vector element at index '0'
// :90:30: error: use of undefined value here causes illegal behavior
-// :90:30: note: when computing vector element at index '0'
// :90:30: error: use of undefined value here causes illegal behavior
-// :90:30: note: when computing vector element at index '1'
// :90:30: error: use of undefined value here causes illegal behavior
-// :90:30: note: when computing vector element at index '0'
// :90:30: error: use of undefined value here causes illegal behavior
-// :90:30: note: when computing vector element at index '0'
// :90:30: error: use of undefined value here causes illegal behavior
+// :90:30: note: when computing vector element at index '0'
// :90:30: error: use of undefined value here causes illegal behavior
// :90:30: note: when computing vector element at index '0'
// :90:30: error: use of undefined value here causes illegal behavior
// :90:30: note: when computing vector element at index '0'
// :90:30: error: use of undefined value here causes illegal behavior
-// :90:30: note: when computing vector element at index '1'
+// :90:30: note: when computing vector element at index '0'
// :90:30: error: use of undefined value here causes illegal behavior
// :90:30: note: when computing vector element at index '0'
// :90:30: error: use of undefined value here causes illegal behavior
// :90:30: note: when computing vector element at index '0'
// :90:30: error: use of undefined value here causes illegal behavior
+// :90:30: note: when computing vector element at index '0'
// :90:30: error: use of undefined value here causes illegal behavior
// :90:30: note: when computing vector element at index '0'
// :90:30: error: use of undefined value here causes illegal behavior
// :90:30: note: when computing vector element at index '0'
// :90:30: error: use of undefined value here causes illegal behavior
-// :90:30: note: when computing vector element at index '1'
+// :90:30: note: when computing vector element at index '0'
// :90:30: error: use of undefined value here causes illegal behavior
// :90:30: note: when computing vector element at index '0'
// :90:30: error: use of undefined value here causes illegal behavior
// :90:30: note: when computing vector element at index '0'
// :90:30: error: use of undefined value here causes illegal behavior
+// :90:30: note: when computing vector element at index '0'
// :90:30: error: use of undefined value here causes illegal behavior
// :90:30: note: when computing vector element at index '0'
// :90:30: error: use of undefined value here causes illegal behavior
// :90:30: note: when computing vector element at index '0'
// :90:30: error: use of undefined value here causes illegal behavior
-// :90:30: note: when computing vector element at index '1'
+// :90:30: note: when computing vector element at index '0'
// :90:30: error: use of undefined value here causes illegal behavior
// :90:30: note: when computing vector element at index '0'
// :90:30: error: use of undefined value here causes illegal behavior
// :90:30: note: when computing vector element at index '0'
// :90:30: error: use of undefined value here causes illegal behavior
+// :90:30: note: when computing vector element at index '0'
// :90:30: error: use of undefined value here causes illegal behavior
// :90:30: note: when computing vector element at index '0'
// :90:30: error: use of undefined value here causes illegal behavior
// :90:30: note: when computing vector element at index '0'
// :90:30: error: use of undefined value here causes illegal behavior
-// :90:30: note: when computing vector element at index '1'
+// :90:30: note: when computing vector element at index '0'
// :90:30: error: use of undefined value here causes illegal behavior
// :90:30: note: when computing vector element at index '0'
// :90:30: error: use of undefined value here causes illegal behavior
// :90:30: note: when computing vector element at index '0'
// :90:30: error: use of undefined value here causes illegal behavior
+// :90:30: note: when computing vector element at index '1'
// :90:30: error: use of undefined value here causes illegal behavior
-// :90:30: note: when computing vector element at index '0'
+// :90:30: note: when computing vector element at index '1'
// :90:30: error: use of undefined value here causes illegal behavior
-// :90:30: note: when computing vector element at index '0'
+// :90:30: note: when computing vector element at index '1'
// :90:30: error: use of undefined value here causes illegal behavior
// :90:30: note: when computing vector element at index '1'
// :90:30: error: use of undefined value here causes illegal behavior
-// :90:30: note: when computing vector element at index '0'
+// :90:30: note: when computing vector element at index '1'
// :90:30: error: use of undefined value here causes illegal behavior
-// :90:30: note: when computing vector element at index '0'
+// :90:30: note: when computing vector element at index '1'
// :93:34: error: use of undefined value here causes illegal behavior
// :93:34: error: use of undefined value here causes illegal behavior
-// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
-// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
-// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
-// :93:34: note: when computing vector element at index '1'
// :93:34: error: use of undefined value here causes illegal behavior
-// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
-// :93:34: error: use of undefined value here causes illegal behavior
// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
-// :93:34: note: when computing vector element at index '1'
-// :93:34: error: use of undefined value here causes illegal behavior
// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
+// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
@@ -1912,7 +1905,7 @@ const std = @import("std");
// :93:34: error: use of undefined value here causes illegal behavior
// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
-// :93:34: note: when computing vector element at index '1'
+// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
@@ -1920,6 +1913,7 @@ const std = @import("std");
// :93:34: error: use of undefined value here causes illegal behavior
// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
+// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
@@ -1927,7 +1921,7 @@ const std = @import("std");
// :93:34: error: use of undefined value here causes illegal behavior
// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
-// :93:34: note: when computing vector element at index '1'
+// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
@@ -1935,6 +1929,7 @@ const std = @import("std");
// :93:34: error: use of undefined value here causes illegal behavior
// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
+// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
@@ -1942,7 +1937,7 @@ const std = @import("std");
// :93:34: error: use of undefined value here causes illegal behavior
// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
-// :93:34: note: when computing vector element at index '1'
+// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
@@ -1950,6 +1945,7 @@ const std = @import("std");
// :93:34: error: use of undefined value here causes illegal behavior
// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
+// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
// :93:34: note: when computing vector element at index '0'
// :93:34: error: use of undefined value here causes illegal behavior
@@ -1959,108 +1955,105 @@ const std = @import("std");
// :93:34: error: use of undefined value here causes illegal behavior
// :93:34: note: when computing vector element at index '1'
// :93:34: error: use of undefined value here causes illegal behavior
-// :93:34: note: when computing vector element at index '0'
+// :93:34: note: when computing vector element at index '1'
// :93:34: error: use of undefined value here causes illegal behavior
-// :93:34: note: when computing vector element at index '0'
+// :93:34: note: when computing vector element at index '1'
// :93:34: error: use of undefined value here causes illegal behavior
-// :93:34: note: when computing vector element at index '0'
+// :93:34: note: when computing vector element at index '1'
+// :93:34: error: use of undefined value here causes illegal behavior
+// :93:34: note: when computing vector element at index '1'
+// :93:34: error: use of undefined value here causes illegal behavior
+// :93:34: note: when computing vector element at index '1'
// :93:37: error: use of undefined value here causes illegal behavior
// :93:37: error: use of undefined value here causes illegal behavior
-// :93:37: note: when computing vector element at index '0'
// :93:37: error: use of undefined value here causes illegal behavior
-// :93:37: note: when computing vector element at index '0'
// :93:37: error: use of undefined value here causes illegal behavior
-// :93:37: note: when computing vector element at index '1'
// :93:37: error: use of undefined value here causes illegal behavior
-// :93:37: note: when computing vector element at index '0'
// :93:37: error: use of undefined value here causes illegal behavior
-// :93:37: note: when computing vector element at index '0'
// :93:37: error: use of undefined value here causes illegal behavior
+// :93:37: note: when computing vector element at index '0'
// :93:37: error: use of undefined value here causes illegal behavior
// :93:37: note: when computing vector element at index '0'
// :93:37: error: use of undefined value here causes illegal behavior
// :93:37: note: when computing vector element at index '0'
// :93:37: error: use of undefined value here causes illegal behavior
-// :93:37: note: when computing vector element at index '1'
+// :93:37: note: when computing vector element at index '0'
// :93:37: error: use of undefined value here causes illegal behavior
// :93:37: note: when computing vector element at index '0'
// :93:37: error: use of undefined value here causes illegal behavior
// :93:37: note: when computing vector element at index '0'
// :93:37: error: use of undefined value here causes illegal behavior
+// :93:37: note: when computing vector element at index '0'
// :93:37: error: use of undefined value here causes illegal behavior
// :93:37: note: when computing vector element at index '0'
// :93:37: error: use of undefined value here causes illegal behavior
// :93:37: note: when computing vector element at index '0'
// :93:37: error: use of undefined value here causes illegal behavior
-// :93:37: note: when computing vector element at index '1'
+// :93:37: note: when computing vector element at index '0'
// :93:37: error: use of undefined value here causes illegal behavior
// :93:37: note: when computing vector element at index '0'
// :93:37: error: use of undefined value here causes illegal behavior
// :93:37: note: when computing vector element at index '0'
// :93:37: error: use of undefined value here causes illegal behavior
+// :93:37: note: when computing vector element at index '0'
// :93:37: error: use of undefined value here causes illegal behavior
// :93:37: note: when computing vector element at index '0'
// :93:37: error: use of undefined value here causes illegal behavior
// :93:37: note: when computing vector element at index '0'
// :93:37: error: use of undefined value here causes illegal behavior
-// :93:37: note: when computing vector element at index '1'
+// :93:37: note: when computing vector element at index '0'
// :93:37: error: use of undefined value here causes illegal behavior
// :93:37: note: when computing vector element at index '0'
// :93:37: error: use of undefined value here causes illegal behavior
// :93:37: note: when computing vector element at index '0'
// :93:37: error: use of undefined value here causes illegal behavior
+// :93:37: note: when computing vector element at index '0'
// :93:37: error: use of undefined value here causes illegal behavior
// :93:37: note: when computing vector element at index '0'
// :93:37: error: use of undefined value here causes illegal behavior
// :93:37: note: when computing vector element at index '0'
// :93:37: error: use of undefined value here causes illegal behavior
-// :93:37: note: when computing vector element at index '1'
+// :93:37: note: when computing vector element at index '0'
// :93:37: error: use of undefined value here causes illegal behavior
// :93:37: note: when computing vector element at index '0'
// :93:37: error: use of undefined value here causes illegal behavior
// :93:37: note: when computing vector element at index '0'
// :93:37: error: use of undefined value here causes illegal behavior
+// :93:37: note: when computing vector element at index '1'
// :93:37: error: use of undefined value here causes illegal behavior
-// :93:37: note: when computing vector element at index '0'
+// :93:37: note: when computing vector element at index '1'
// :93:37: error: use of undefined value here causes illegal behavior
-// :93:37: note: when computing vector element at index '0'
+// :93:37: note: when computing vector element at index '1'
// :93:37: error: use of undefined value here causes illegal behavior
// :93:37: note: when computing vector element at index '1'
// :93:37: error: use of undefined value here causes illegal behavior
-// :93:37: note: when computing vector element at index '0'
+// :93:37: note: when computing vector element at index '1'
// :93:37: error: use of undefined value here causes illegal behavior
-// :93:37: note: when computing vector element at index '0'
+// :93:37: note: when computing vector element at index '1'
// :96:17: error: use of undefined value here causes illegal behavior
// :96:17: error: use of undefined value here causes illegal behavior
-// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
-// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
-// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
-// :96:17: note: when computing vector element at index '1'
// :96:17: error: use of undefined value here causes illegal behavior
-// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
-// :96:17: error: use of undefined value here causes illegal behavior
// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
-// :96:17: note: when computing vector element at index '1'
-// :96:17: error: use of undefined value here causes illegal behavior
// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
+// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
@@ -2068,7 +2061,7 @@ const std = @import("std");
// :96:17: error: use of undefined value here causes illegal behavior
// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
-// :96:17: note: when computing vector element at index '1'
+// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
@@ -2076,6 +2069,7 @@ const std = @import("std");
// :96:17: error: use of undefined value here causes illegal behavior
// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
+// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
@@ -2083,7 +2077,7 @@ const std = @import("std");
// :96:17: error: use of undefined value here causes illegal behavior
// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
-// :96:17: note: when computing vector element at index '1'
+// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
@@ -2091,6 +2085,7 @@ const std = @import("std");
// :96:17: error: use of undefined value here causes illegal behavior
// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
+// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
@@ -2098,7 +2093,7 @@ const std = @import("std");
// :96:17: error: use of undefined value here causes illegal behavior
// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
-// :96:17: note: when computing vector element at index '1'
+// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
@@ -2106,6 +2101,7 @@ const std = @import("std");
// :96:17: error: use of undefined value here causes illegal behavior
// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
+// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
// :96:17: note: when computing vector element at index '0'
// :96:17: error: use of undefined value here causes illegal behavior
@@ -2115,67 +2111,65 @@ const std = @import("std");
// :96:17: error: use of undefined value here causes illegal behavior
// :96:17: note: when computing vector element at index '1'
// :96:17: error: use of undefined value here causes illegal behavior
-// :96:17: note: when computing vector element at index '0'
+// :96:17: note: when computing vector element at index '1'
// :96:17: error: use of undefined value here causes illegal behavior
-// :96:17: note: when computing vector element at index '0'
+// :96:17: note: when computing vector element at index '1'
// :96:17: error: use of undefined value here causes illegal behavior
-// :96:17: note: when computing vector element at index '0'
-// :96:22: error: use of undefined value here causes illegal behavior
-// :96:22: error: use of undefined value here causes illegal behavior
-// :96:22: note: when computing vector element at index '0'
+// :96:17: note: when computing vector element at index '1'
+// :96:17: error: use of undefined value here causes illegal behavior
+// :96:17: note: when computing vector element at index '1'
+// :96:17: error: use of undefined value here causes illegal behavior
+// :96:17: note: when computing vector element at index '1'
// :96:22: error: use of undefined value here causes illegal behavior
-// :96:22: note: when computing vector element at index '0'
// :96:22: error: use of undefined value here causes illegal behavior
-// :96:22: note: when computing vector element at index '1'
// :96:22: error: use of undefined value here causes illegal behavior
-// :96:22: note: when computing vector element at index '0'
// :96:22: error: use of undefined value here causes illegal behavior
-// :96:22: note: when computing vector element at index '0'
// :96:22: error: use of undefined value here causes illegal behavior
// :96:22: error: use of undefined value here causes illegal behavior
-// :96:22: note: when computing vector element at index '0'
// :96:22: error: use of undefined value here causes illegal behavior
// :96:22: note: when computing vector element at index '0'
// :96:22: error: use of undefined value here causes illegal behavior
-// :96:22: note: when computing vector element at index '1'
-// :96:22: error: use of undefined value here causes illegal behavior
// :96:22: note: when computing vector element at index '0'
// :96:22: error: use of undefined value here causes illegal behavior
// :96:22: note: when computing vector element at index '0'
// :96:22: error: use of undefined value here causes illegal behavior
+// :96:22: note: when computing vector element at index '0'
// :96:22: error: use of undefined value here causes illegal behavior
// :96:22: note: when computing vector element at index '0'
// :96:22: error: use of undefined value here causes illegal behavior
// :96:22: note: when computing vector element at index '0'
// :96:22: error: use of undefined value here causes illegal behavior
-// :96:22: note: when computing vector element at index '1'
+// :96:22: note: when computing vector element at index '0'
// :96:22: error: use of undefined value here causes illegal behavior
// :96:22: note: when computing vector element at index '0'
// :96:22: error: use of undefined value here causes illegal behavior
// :96:22: note: when computing vector element at index '0'
// :96:22: error: use of undefined value here causes illegal behavior
+// :96:22: note: when computing vector element at index '0'
// :96:22: error: use of undefined value here causes illegal behavior
// :96:22: note: when computing vector element at index '0'
// :96:22: error: use of undefined value here causes illegal behavior
// :96:22: note: when computing vector element at index '0'
// :96:22: error: use of undefined value here causes illegal behavior
-// :96:22: note: when computing vector element at index '1'
+// :96:22: note: when computing vector element at index '0'
// :96:22: error: use of undefined value here causes illegal behavior
// :96:22: note: when computing vector element at index '0'
// :96:22: error: use of undefined value here causes illegal behavior
// :96:22: note: when computing vector element at index '0'
// :96:22: error: use of undefined value here causes illegal behavior
+// :96:22: note: when computing vector element at index '0'
// :96:22: error: use of undefined value here causes illegal behavior
// :96:22: note: when computing vector element at index '0'
// :96:22: error: use of undefined value here causes illegal behavior
// :96:22: note: when computing vector element at index '0'
// :96:22: error: use of undefined value here causes illegal behavior
-// :96:22: note: when computing vector element at index '1'
+// :96:22: note: when computing vector element at index '0'
// :96:22: error: use of undefined value here causes illegal behavior
// :96:22: note: when computing vector element at index '0'
// :96:22: error: use of undefined value here causes illegal behavior
// :96:22: note: when computing vector element at index '0'
// :96:22: error: use of undefined value here causes illegal behavior
+// :96:22: note: when computing vector element at index '0'
// :96:22: error: use of undefined value here causes illegal behavior
// :96:22: note: when computing vector element at index '0'
// :96:22: error: use of undefined value here causes illegal behavior
@@ -2183,40 +2177,39 @@ const std = @import("std");
// :96:22: error: use of undefined value here causes illegal behavior
// :96:22: note: when computing vector element at index '1'
// :96:22: error: use of undefined value here causes illegal behavior
-// :96:22: note: when computing vector element at index '0'
+// :96:22: note: when computing vector element at index '1'
// :96:22: error: use of undefined value here causes illegal behavior
-// :96:22: note: when computing vector element at index '0'
+// :96:22: note: when computing vector element at index '1'
+// :96:22: error: use of undefined value here causes illegal behavior
+// :96:22: note: when computing vector element at index '1'
+// :96:22: error: use of undefined value here causes illegal behavior
+// :96:22: note: when computing vector element at index '1'
+// :96:22: error: use of undefined value here causes illegal behavior
+// :96:22: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
-// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
@@ -2224,7 +2217,7 @@ const std = @import("std");
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
@@ -2232,6 +2225,7 @@ const std = @import("std");
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
@@ -2239,7 +2233,7 @@ const std = @import("std");
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
@@ -2247,6 +2241,7 @@ const std = @import("std");
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
@@ -2254,7 +2249,7 @@ const std = @import("std");
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '1'
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
@@ -2262,6 +2257,7 @@ const std = @import("std");
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '0'
// :99:27: error: use of undefined value here causes illegal behavior
@@ -2271,77 +2267,81 @@ const std = @import("std");
// :99:27: error: use of undefined value here causes illegal behavior
// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
+// :99:27: note: when computing vector element at index '1'
// :99:27: error: use of undefined value here causes illegal behavior
-// :99:27: note: when computing vector element at index '0'
+// :99:27: note: when computing vector element at index '1'
+// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '1'
+// :99:27: error: use of undefined value here causes illegal behavior
+// :99:27: note: when computing vector element at index '1'
// :99:30: error: use of undefined value here causes illegal behavior
// :99:30: error: use of undefined value here causes illegal behavior
-// :99:30: note: when computing vector element at index '0'
// :99:30: error: use of undefined value here causes illegal behavior
-// :99:30: note: when computing vector element at index '0'
// :99:30: error: use of undefined value here causes illegal behavior
-// :99:30: note: when computing vector element at index '1'
// :99:30: error: use of undefined value here causes illegal behavior
-// :99:30: note: when computing vector element at index '0'
// :99:30: error: use of undefined value here causes illegal behavior
-// :99:30: note: when computing vector element at index '0'
// :99:30: error: use of undefined value here causes illegal behavior
+// :99:30: note: when computing vector element at index '0'
// :99:30: error: use of undefined value here causes illegal behavior
// :99:30: note: when computing vector element at index '0'
// :99:30: error: use of undefined value here causes illegal behavior
// :99:30: note: when computing vector element at index '0'
// :99:30: error: use of undefined value here causes illegal behavior
-// :99:30: note: when computing vector element at index '1'
+// :99:30: note: when computing vector element at index '0'
// :99:30: error: use of undefined value here causes illegal behavior
// :99:30: note: when computing vector element at index '0'
// :99:30: error: use of undefined value here causes illegal behavior
// :99:30: note: when computing vector element at index '0'
// :99:30: error: use of undefined value here causes illegal behavior
+// :99:30: note: when computing vector element at index '0'
// :99:30: error: use of undefined value here causes illegal behavior
// :99:30: note: when computing vector element at index '0'
// :99:30: error: use of undefined value here causes illegal behavior
// :99:30: note: when computing vector element at index '0'
// :99:30: error: use of undefined value here causes illegal behavior
-// :99:30: note: when computing vector element at index '1'
+// :99:30: note: when computing vector element at index '0'
// :99:30: error: use of undefined value here causes illegal behavior
// :99:30: note: when computing vector element at index '0'
// :99:30: error: use of undefined value here causes illegal behavior
// :99:30: note: when computing vector element at index '0'
// :99:30: error: use of undefined value here causes illegal behavior
+// :99:30: note: when computing vector element at index '0'
// :99:30: error: use of undefined value here causes illegal behavior
// :99:30: note: when computing vector element at index '0'
// :99:30: error: use of undefined value here causes illegal behavior
// :99:30: note: when computing vector element at index '0'
// :99:30: error: use of undefined value here causes illegal behavior
-// :99:30: note: when computing vector element at index '1'
+// :99:30: note: when computing vector element at index '0'
// :99:30: error: use of undefined value here causes illegal behavior
// :99:30: note: when computing vector element at index '0'
// :99:30: error: use of undefined value here causes illegal behavior
// :99:30: note: when computing vector element at index '0'
// :99:30: error: use of undefined value here causes illegal behavior
+// :99:30: note: when computing vector element at index '0'
// :99:30: error: use of undefined value here causes illegal behavior
// :99:30: note: when computing vector element at index '0'
// :99:30: error: use of undefined value here causes illegal behavior
// :99:30: note: when computing vector element at index '0'
// :99:30: error: use of undefined value here causes illegal behavior
-// :99:30: note: when computing vector element at index '1'
+// :99:30: note: when computing vector element at index '0'
// :99:30: error: use of undefined value here causes illegal behavior
// :99:30: note: when computing vector element at index '0'
// :99:30: error: use of undefined value here causes illegal behavior
// :99:30: note: when computing vector element at index '0'
// :99:30: error: use of undefined value here causes illegal behavior
+// :99:30: note: when computing vector element at index '1'
// :99:30: error: use of undefined value here causes illegal behavior
-// :99:30: note: when computing vector element at index '0'
+// :99:30: note: when computing vector element at index '1'
// :99:30: error: use of undefined value here causes illegal behavior
-// :99:30: note: when computing vector element at index '0'
+// :99:30: note: when computing vector element at index '1'
// :99:30: error: use of undefined value here causes illegal behavior
// :99:30: note: when computing vector element at index '1'
// :99:30: error: use of undefined value here causes illegal behavior
-// :99:30: note: when computing vector element at index '0'
+// :99:30: note: when computing vector element at index '1'
// :99:30: error: use of undefined value here causes illegal behavior
-// :99:30: note: when computing vector element at index '0'
+// :99:30: note: when computing vector element at index '1'
// :104:22: error: use of undefined value here causes illegal behavior
// :104:22: error: use of undefined value here causes illegal behavior
// :104:22: error: use of undefined value here causes illegal behavior
@@ -2349,21 +2349,13 @@ const std = @import("std");
// :104:22: error: use of undefined value here causes illegal behavior
// :104:22: error: use of undefined value here causes illegal behavior
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '1'
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '1'
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '1'
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '1'
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '0'
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '0'
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '0'
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '0'
// :104:22: error: use of undefined value here causes illegal behavior
// :104:22: error: use of undefined value here causes illegal behavior
// :104:22: error: use of undefined value here causes illegal behavior
@@ -2371,21 +2363,13 @@ const std = @import("std");
// :104:22: error: use of undefined value here causes illegal behavior
// :104:22: error: use of undefined value here causes illegal behavior
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '1'
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '1'
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '1'
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '1'
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '0'
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '0'
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '0'
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '0'
// :104:22: error: use of undefined value here causes illegal behavior
// :104:22: error: use of undefined value here causes illegal behavior
// :104:22: error: use of undefined value here causes illegal behavior
@@ -2393,13 +2377,11 @@ const std = @import("std");
// :104:22: error: use of undefined value here causes illegal behavior
// :104:22: error: use of undefined value here causes illegal behavior
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '1'
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '1'
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '1'
+// :104:22: note: when computing vector element at index '0'
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '1'
+// :104:22: note: when computing vector element at index '0'
// :104:22: error: use of undefined value here causes illegal behavior
// :104:22: note: when computing vector element at index '0'
// :104:22: error: use of undefined value here causes illegal behavior
@@ -2409,19 +2391,25 @@ const std = @import("std");
// :104:22: error: use of undefined value here causes illegal behavior
// :104:22: note: when computing vector element at index '0'
// :104:22: error: use of undefined value here causes illegal behavior
+// :104:22: note: when computing vector element at index '0'
// :104:22: error: use of undefined value here causes illegal behavior
+// :104:22: note: when computing vector element at index '0'
// :104:22: error: use of undefined value here causes illegal behavior
+// :104:22: note: when computing vector element at index '0'
// :104:22: error: use of undefined value here causes illegal behavior
+// :104:22: note: when computing vector element at index '0'
// :104:22: error: use of undefined value here causes illegal behavior
+// :104:22: note: when computing vector element at index '0'
// :104:22: error: use of undefined value here causes illegal behavior
+// :104:22: note: when computing vector element at index '0'
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '1'
+// :104:22: note: when computing vector element at index '0'
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '1'
+// :104:22: note: when computing vector element at index '0'
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '1'
+// :104:22: note: when computing vector element at index '0'
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '1'
+// :104:22: note: when computing vector element at index '0'
// :104:22: error: use of undefined value here causes illegal behavior
// :104:22: note: when computing vector element at index '0'
// :104:22: error: use of undefined value here causes illegal behavior
@@ -2431,11 +2419,17 @@ const std = @import("std");
// :104:22: error: use of undefined value here causes illegal behavior
// :104:22: note: when computing vector element at index '0'
// :104:22: error: use of undefined value here causes illegal behavior
+// :104:22: note: when computing vector element at index '0'
// :104:22: error: use of undefined value here causes illegal behavior
+// :104:22: note: when computing vector element at index '0'
// :104:22: error: use of undefined value here causes illegal behavior
+// :104:22: note: when computing vector element at index '0'
// :104:22: error: use of undefined value here causes illegal behavior
+// :104:22: note: when computing vector element at index '0'
// :104:22: error: use of undefined value here causes illegal behavior
+// :104:22: note: when computing vector element at index '1'
// :104:22: error: use of undefined value here causes illegal behavior
+// :104:22: note: when computing vector element at index '1'
// :104:22: error: use of undefined value here causes illegal behavior
// :104:22: note: when computing vector element at index '1'
// :104:22: error: use of undefined value here causes illegal behavior
@@ -2445,19 +2439,25 @@ const std = @import("std");
// :104:22: error: use of undefined value here causes illegal behavior
// :104:22: note: when computing vector element at index '1'
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '0'
+// :104:22: note: when computing vector element at index '1'
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '0'
+// :104:22: note: when computing vector element at index '1'
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '0'
+// :104:22: note: when computing vector element at index '1'
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '0'
+// :104:22: note: when computing vector element at index '1'
// :104:22: error: use of undefined value here causes illegal behavior
+// :104:22: note: when computing vector element at index '1'
// :104:22: error: use of undefined value here causes illegal behavior
+// :104:22: note: when computing vector element at index '1'
// :104:22: error: use of undefined value here causes illegal behavior
+// :104:22: note: when computing vector element at index '1'
// :104:22: error: use of undefined value here causes illegal behavior
+// :104:22: note: when computing vector element at index '1'
// :104:22: error: use of undefined value here causes illegal behavior
+// :104:22: note: when computing vector element at index '1'
// :104:22: error: use of undefined value here causes illegal behavior
+// :104:22: note: when computing vector element at index '1'
// :104:22: error: use of undefined value here causes illegal behavior
// :104:22: note: when computing vector element at index '1'
// :104:22: error: use of undefined value here causes illegal behavior
@@ -2467,13 +2467,13 @@ const std = @import("std");
// :104:22: error: use of undefined value here causes illegal behavior
// :104:22: note: when computing vector element at index '1'
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '0'
+// :104:22: note: when computing vector element at index '1'
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '0'
+// :104:22: note: when computing vector element at index '1'
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '0'
+// :104:22: note: when computing vector element at index '1'
// :104:22: error: use of undefined value here causes illegal behavior
-// :104:22: note: when computing vector element at index '0'
+// :104:22: note: when computing vector element at index '1'
// :107:30: error: use of undefined value here causes illegal behavior
// :107:30: error: use of undefined value here causes illegal behavior
// :107:30: error: use of undefined value here causes illegal behavior
@@ -2481,21 +2481,13 @@ const std = @import("std");
// :107:30: error: use of undefined value here causes illegal behavior
// :107:30: error: use of undefined value here causes illegal behavior
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '1'
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '1'
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '1'
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '1'
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '0'
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '0'
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '0'
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '0'
// :107:30: error: use of undefined value here causes illegal behavior
// :107:30: error: use of undefined value here causes illegal behavior
// :107:30: error: use of undefined value here causes illegal behavior
@@ -2503,21 +2495,13 @@ const std = @import("std");
// :107:30: error: use of undefined value here causes illegal behavior
// :107:30: error: use of undefined value here causes illegal behavior
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '1'
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '1'
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '1'
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '1'
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '0'
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '0'
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '0'
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '0'
// :107:30: error: use of undefined value here causes illegal behavior
// :107:30: error: use of undefined value here causes illegal behavior
// :107:30: error: use of undefined value here causes illegal behavior
@@ -2525,13 +2509,11 @@ const std = @import("std");
// :107:30: error: use of undefined value here causes illegal behavior
// :107:30: error: use of undefined value here causes illegal behavior
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '1'
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '1'
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '1'
+// :107:30: note: when computing vector element at index '0'
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '1'
+// :107:30: note: when computing vector element at index '0'
// :107:30: error: use of undefined value here causes illegal behavior
// :107:30: note: when computing vector element at index '0'
// :107:30: error: use of undefined value here causes illegal behavior
@@ -2541,19 +2523,25 @@ const std = @import("std");
// :107:30: error: use of undefined value here causes illegal behavior
// :107:30: note: when computing vector element at index '0'
// :107:30: error: use of undefined value here causes illegal behavior
+// :107:30: note: when computing vector element at index '0'
// :107:30: error: use of undefined value here causes illegal behavior
+// :107:30: note: when computing vector element at index '0'
// :107:30: error: use of undefined value here causes illegal behavior
+// :107:30: note: when computing vector element at index '0'
// :107:30: error: use of undefined value here causes illegal behavior
+// :107:30: note: when computing vector element at index '0'
// :107:30: error: use of undefined value here causes illegal behavior
+// :107:30: note: when computing vector element at index '0'
// :107:30: error: use of undefined value here causes illegal behavior
+// :107:30: note: when computing vector element at index '0'
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '1'
+// :107:30: note: when computing vector element at index '0'
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '1'
+// :107:30: note: when computing vector element at index '0'
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '1'
+// :107:30: note: when computing vector element at index '0'
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '1'
+// :107:30: note: when computing vector element at index '0'
// :107:30: error: use of undefined value here causes illegal behavior
// :107:30: note: when computing vector element at index '0'
// :107:30: error: use of undefined value here causes illegal behavior
@@ -2563,11 +2551,17 @@ const std = @import("std");
// :107:30: error: use of undefined value here causes illegal behavior
// :107:30: note: when computing vector element at index '0'
// :107:30: error: use of undefined value here causes illegal behavior
+// :107:30: note: when computing vector element at index '0'
// :107:30: error: use of undefined value here causes illegal behavior
+// :107:30: note: when computing vector element at index '0'
// :107:30: error: use of undefined value here causes illegal behavior
+// :107:30: note: when computing vector element at index '0'
// :107:30: error: use of undefined value here causes illegal behavior
+// :107:30: note: when computing vector element at index '0'
// :107:30: error: use of undefined value here causes illegal behavior
+// :107:30: note: when computing vector element at index '1'
// :107:30: error: use of undefined value here causes illegal behavior
+// :107:30: note: when computing vector element at index '1'
// :107:30: error: use of undefined value here causes illegal behavior
// :107:30: note: when computing vector element at index '1'
// :107:30: error: use of undefined value here causes illegal behavior
@@ -2577,19 +2571,25 @@ const std = @import("std");
// :107:30: error: use of undefined value here causes illegal behavior
// :107:30: note: when computing vector element at index '1'
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '0'
+// :107:30: note: when computing vector element at index '1'
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '0'
+// :107:30: note: when computing vector element at index '1'
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '0'
+// :107:30: note: when computing vector element at index '1'
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '0'
+// :107:30: note: when computing vector element at index '1'
// :107:30: error: use of undefined value here causes illegal behavior
+// :107:30: note: when computing vector element at index '1'
// :107:30: error: use of undefined value here causes illegal behavior
+// :107:30: note: when computing vector element at index '1'
// :107:30: error: use of undefined value here causes illegal behavior
+// :107:30: note: when computing vector element at index '1'
// :107:30: error: use of undefined value here causes illegal behavior
+// :107:30: note: when computing vector element at index '1'
// :107:30: error: use of undefined value here causes illegal behavior
+// :107:30: note: when computing vector element at index '1'
// :107:30: error: use of undefined value here causes illegal behavior
+// :107:30: note: when computing vector element at index '1'
// :107:30: error: use of undefined value here causes illegal behavior
// :107:30: note: when computing vector element at index '1'
// :107:30: error: use of undefined value here causes illegal behavior
@@ -2599,13 +2599,13 @@ const std = @import("std");
// :107:30: error: use of undefined value here causes illegal behavior
// :107:30: note: when computing vector element at index '1'
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '0'
+// :107:30: note: when computing vector element at index '1'
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '0'
+// :107:30: note: when computing vector element at index '1'
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '0'
+// :107:30: note: when computing vector element at index '1'
// :107:30: error: use of undefined value here causes illegal behavior
-// :107:30: note: when computing vector element at index '0'
+// :107:30: note: when computing vector element at index '1'
// :110:37: error: use of undefined value here causes illegal behavior
// :110:37: error: use of undefined value here causes illegal behavior
// :110:37: error: use of undefined value here causes illegal behavior
@@ -2613,21 +2613,13 @@ const std = @import("std");
// :110:37: error: use of undefined value here causes illegal behavior
// :110:37: error: use of undefined value here causes illegal behavior
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '1'
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '1'
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '1'
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '1'
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '0'
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '0'
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '0'
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '0'
// :110:37: error: use of undefined value here causes illegal behavior
// :110:37: error: use of undefined value here causes illegal behavior
// :110:37: error: use of undefined value here causes illegal behavior
@@ -2635,21 +2627,13 @@ const std = @import("std");
// :110:37: error: use of undefined value here causes illegal behavior
// :110:37: error: use of undefined value here causes illegal behavior
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '1'
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '1'
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '1'
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '1'
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '0'
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '0'
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '0'
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '0'
// :110:37: error: use of undefined value here causes illegal behavior
// :110:37: error: use of undefined value here causes illegal behavior
// :110:37: error: use of undefined value here causes illegal behavior
@@ -2657,13 +2641,11 @@ const std = @import("std");
// :110:37: error: use of undefined value here causes illegal behavior
// :110:37: error: use of undefined value here causes illegal behavior
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '1'
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '1'
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '1'
+// :110:37: note: when computing vector element at index '0'
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '1'
+// :110:37: note: when computing vector element at index '0'
// :110:37: error: use of undefined value here causes illegal behavior
// :110:37: note: when computing vector element at index '0'
// :110:37: error: use of undefined value here causes illegal behavior
@@ -2673,19 +2655,25 @@ const std = @import("std");
// :110:37: error: use of undefined value here causes illegal behavior
// :110:37: note: when computing vector element at index '0'
// :110:37: error: use of undefined value here causes illegal behavior
+// :110:37: note: when computing vector element at index '0'
// :110:37: error: use of undefined value here causes illegal behavior
+// :110:37: note: when computing vector element at index '0'
// :110:37: error: use of undefined value here causes illegal behavior
+// :110:37: note: when computing vector element at index '0'
// :110:37: error: use of undefined value here causes illegal behavior
+// :110:37: note: when computing vector element at index '0'
// :110:37: error: use of undefined value here causes illegal behavior
+// :110:37: note: when computing vector element at index '0'
// :110:37: error: use of undefined value here causes illegal behavior
+// :110:37: note: when computing vector element at index '0'
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '1'
+// :110:37: note: when computing vector element at index '0'
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '1'
+// :110:37: note: when computing vector element at index '0'
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '1'
+// :110:37: note: when computing vector element at index '0'
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '1'
+// :110:37: note: when computing vector element at index '0'
// :110:37: error: use of undefined value here causes illegal behavior
// :110:37: note: when computing vector element at index '0'
// :110:37: error: use of undefined value here causes illegal behavior
@@ -2695,11 +2683,17 @@ const std = @import("std");
// :110:37: error: use of undefined value here causes illegal behavior
// :110:37: note: when computing vector element at index '0'
// :110:37: error: use of undefined value here causes illegal behavior
+// :110:37: note: when computing vector element at index '0'
// :110:37: error: use of undefined value here causes illegal behavior
+// :110:37: note: when computing vector element at index '0'
// :110:37: error: use of undefined value here causes illegal behavior
+// :110:37: note: when computing vector element at index '0'
// :110:37: error: use of undefined value here causes illegal behavior
+// :110:37: note: when computing vector element at index '0'
// :110:37: error: use of undefined value here causes illegal behavior
+// :110:37: note: when computing vector element at index '1'
// :110:37: error: use of undefined value here causes illegal behavior
+// :110:37: note: when computing vector element at index '1'
// :110:37: error: use of undefined value here causes illegal behavior
// :110:37: note: when computing vector element at index '1'
// :110:37: error: use of undefined value here causes illegal behavior
@@ -2709,19 +2703,25 @@ const std = @import("std");
// :110:37: error: use of undefined value here causes illegal behavior
// :110:37: note: when computing vector element at index '1'
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '0'
+// :110:37: note: when computing vector element at index '1'
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '0'
+// :110:37: note: when computing vector element at index '1'
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '0'
+// :110:37: note: when computing vector element at index '1'
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '0'
+// :110:37: note: when computing vector element at index '1'
// :110:37: error: use of undefined value here causes illegal behavior
+// :110:37: note: when computing vector element at index '1'
// :110:37: error: use of undefined value here causes illegal behavior
+// :110:37: note: when computing vector element at index '1'
// :110:37: error: use of undefined value here causes illegal behavior
+// :110:37: note: when computing vector element at index '1'
// :110:37: error: use of undefined value here causes illegal behavior
+// :110:37: note: when computing vector element at index '1'
// :110:37: error: use of undefined value here causes illegal behavior
+// :110:37: note: when computing vector element at index '1'
// :110:37: error: use of undefined value here causes illegal behavior
+// :110:37: note: when computing vector element at index '1'
// :110:37: error: use of undefined value here causes illegal behavior
// :110:37: note: when computing vector element at index '1'
// :110:37: error: use of undefined value here causes illegal behavior
@@ -2731,13 +2731,13 @@ const std = @import("std");
// :110:37: error: use of undefined value here causes illegal behavior
// :110:37: note: when computing vector element at index '1'
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '0'
+// :110:37: note: when computing vector element at index '1'
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '0'
+// :110:37: note: when computing vector element at index '1'
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '0'
+// :110:37: note: when computing vector element at index '1'
// :110:37: error: use of undefined value here causes illegal behavior
-// :110:37: note: when computing vector element at index '0'
+// :110:37: note: when computing vector element at index '1'
// :113:22: error: use of undefined value here causes illegal behavior
// :113:22: error: use of undefined value here causes illegal behavior
// :113:22: error: use of undefined value here causes illegal behavior
@@ -2745,21 +2745,13 @@ const std = @import("std");
// :113:22: error: use of undefined value here causes illegal behavior
// :113:22: error: use of undefined value here causes illegal behavior
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '1'
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '1'
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '1'
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '1'
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '0'
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '0'
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '0'
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '0'
// :113:22: error: use of undefined value here causes illegal behavior
// :113:22: error: use of undefined value here causes illegal behavior
// :113:22: error: use of undefined value here causes illegal behavior
@@ -2767,21 +2759,13 @@ const std = @import("std");
// :113:22: error: use of undefined value here causes illegal behavior
// :113:22: error: use of undefined value here causes illegal behavior
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '1'
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '1'
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '1'
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '1'
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '0'
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '0'
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '0'
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '0'
// :113:22: error: use of undefined value here causes illegal behavior
// :113:22: error: use of undefined value here causes illegal behavior
// :113:22: error: use of undefined value here causes illegal behavior
@@ -2789,13 +2773,11 @@ const std = @import("std");
// :113:22: error: use of undefined value here causes illegal behavior
// :113:22: error: use of undefined value here causes illegal behavior
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '1'
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '1'
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '1'
+// :113:22: note: when computing vector element at index '0'
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '1'
+// :113:22: note: when computing vector element at index '0'
// :113:22: error: use of undefined value here causes illegal behavior
// :113:22: note: when computing vector element at index '0'
// :113:22: error: use of undefined value here causes illegal behavior
@@ -2805,19 +2787,25 @@ const std = @import("std");
// :113:22: error: use of undefined value here causes illegal behavior
// :113:22: note: when computing vector element at index '0'
// :113:22: error: use of undefined value here causes illegal behavior
+// :113:22: note: when computing vector element at index '0'
// :113:22: error: use of undefined value here causes illegal behavior
+// :113:22: note: when computing vector element at index '0'
// :113:22: error: use of undefined value here causes illegal behavior
+// :113:22: note: when computing vector element at index '0'
// :113:22: error: use of undefined value here causes illegal behavior
+// :113:22: note: when computing vector element at index '0'
// :113:22: error: use of undefined value here causes illegal behavior
+// :113:22: note: when computing vector element at index '0'
// :113:22: error: use of undefined value here causes illegal behavior
+// :113:22: note: when computing vector element at index '0'
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '1'
+// :113:22: note: when computing vector element at index '0'
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '1'
+// :113:22: note: when computing vector element at index '0'
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '1'
+// :113:22: note: when computing vector element at index '0'
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '1'
+// :113:22: note: when computing vector element at index '0'
// :113:22: error: use of undefined value here causes illegal behavior
// :113:22: note: when computing vector element at index '0'
// :113:22: error: use of undefined value here causes illegal behavior
@@ -2827,11 +2815,17 @@ const std = @import("std");
// :113:22: error: use of undefined value here causes illegal behavior
// :113:22: note: when computing vector element at index '0'
// :113:22: error: use of undefined value here causes illegal behavior
+// :113:22: note: when computing vector element at index '0'
// :113:22: error: use of undefined value here causes illegal behavior
+// :113:22: note: when computing vector element at index '0'
// :113:22: error: use of undefined value here causes illegal behavior
+// :113:22: note: when computing vector element at index '0'
// :113:22: error: use of undefined value here causes illegal behavior
+// :113:22: note: when computing vector element at index '0'
// :113:22: error: use of undefined value here causes illegal behavior
+// :113:22: note: when computing vector element at index '1'
// :113:22: error: use of undefined value here causes illegal behavior
+// :113:22: note: when computing vector element at index '1'
// :113:22: error: use of undefined value here causes illegal behavior
// :113:22: note: when computing vector element at index '1'
// :113:22: error: use of undefined value here causes illegal behavior
@@ -2841,19 +2835,25 @@ const std = @import("std");
// :113:22: error: use of undefined value here causes illegal behavior
// :113:22: note: when computing vector element at index '1'
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '0'
+// :113:22: note: when computing vector element at index '1'
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '0'
+// :113:22: note: when computing vector element at index '1'
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '0'
+// :113:22: note: when computing vector element at index '1'
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '0'
+// :113:22: note: when computing vector element at index '1'
// :113:22: error: use of undefined value here causes illegal behavior
+// :113:22: note: when computing vector element at index '1'
// :113:22: error: use of undefined value here causes illegal behavior
+// :113:22: note: when computing vector element at index '1'
// :113:22: error: use of undefined value here causes illegal behavior
+// :113:22: note: when computing vector element at index '1'
// :113:22: error: use of undefined value here causes illegal behavior
+// :113:22: note: when computing vector element at index '1'
// :113:22: error: use of undefined value here causes illegal behavior
+// :113:22: note: when computing vector element at index '1'
// :113:22: error: use of undefined value here causes illegal behavior
+// :113:22: note: when computing vector element at index '1'
// :113:22: error: use of undefined value here causes illegal behavior
// :113:22: note: when computing vector element at index '1'
// :113:22: error: use of undefined value here causes illegal behavior
@@ -2863,13 +2863,13 @@ const std = @import("std");
// :113:22: error: use of undefined value here causes illegal behavior
// :113:22: note: when computing vector element at index '1'
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '0'
+// :113:22: note: when computing vector element at index '1'
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '0'
+// :113:22: note: when computing vector element at index '1'
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '0'
+// :113:22: note: when computing vector element at index '1'
// :113:22: error: use of undefined value here causes illegal behavior
-// :113:22: note: when computing vector element at index '0'
+// :113:22: note: when computing vector element at index '1'
// :116:30: error: use of undefined value here causes illegal behavior
// :116:30: error: use of undefined value here causes illegal behavior
// :116:30: error: use of undefined value here causes illegal behavior
@@ -2877,21 +2877,13 @@ const std = @import("std");
// :116:30: error: use of undefined value here causes illegal behavior
// :116:30: error: use of undefined value here causes illegal behavior
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '1'
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '1'
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '1'
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '1'
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '0'
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '0'
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '0'
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '0'
// :116:30: error: use of undefined value here causes illegal behavior
// :116:30: error: use of undefined value here causes illegal behavior
// :116:30: error: use of undefined value here causes illegal behavior
@@ -2899,21 +2891,13 @@ const std = @import("std");
// :116:30: error: use of undefined value here causes illegal behavior
// :116:30: error: use of undefined value here causes illegal behavior
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '1'
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '1'
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '1'
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '1'
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '0'
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '0'
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '0'
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '0'
// :116:30: error: use of undefined value here causes illegal behavior
// :116:30: error: use of undefined value here causes illegal behavior
// :116:30: error: use of undefined value here causes illegal behavior
@@ -2921,13 +2905,11 @@ const std = @import("std");
// :116:30: error: use of undefined value here causes illegal behavior
// :116:30: error: use of undefined value here causes illegal behavior
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '1'
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '1'
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '1'
+// :116:30: note: when computing vector element at index '0'
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '1'
+// :116:30: note: when computing vector element at index '0'
// :116:30: error: use of undefined value here causes illegal behavior
// :116:30: note: when computing vector element at index '0'
// :116:30: error: use of undefined value here causes illegal behavior
@@ -2937,19 +2919,25 @@ const std = @import("std");
// :116:30: error: use of undefined value here causes illegal behavior
// :116:30: note: when computing vector element at index '0'
// :116:30: error: use of undefined value here causes illegal behavior
+// :116:30: note: when computing vector element at index '0'
// :116:30: error: use of undefined value here causes illegal behavior
+// :116:30: note: when computing vector element at index '0'
// :116:30: error: use of undefined value here causes illegal behavior
+// :116:30: note: when computing vector element at index '0'
// :116:30: error: use of undefined value here causes illegal behavior
+// :116:30: note: when computing vector element at index '0'
// :116:30: error: use of undefined value here causes illegal behavior
+// :116:30: note: when computing vector element at index '0'
// :116:30: error: use of undefined value here causes illegal behavior
+// :116:30: note: when computing vector element at index '0'
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '1'
+// :116:30: note: when computing vector element at index '0'
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '1'
+// :116:30: note: when computing vector element at index '0'
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '1'
+// :116:30: note: when computing vector element at index '0'
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '1'
+// :116:30: note: when computing vector element at index '0'
// :116:30: error: use of undefined value here causes illegal behavior
// :116:30: note: when computing vector element at index '0'
// :116:30: error: use of undefined value here causes illegal behavior
@@ -2959,11 +2947,17 @@ const std = @import("std");
// :116:30: error: use of undefined value here causes illegal behavior
// :116:30: note: when computing vector element at index '0'
// :116:30: error: use of undefined value here causes illegal behavior
+// :116:30: note: when computing vector element at index '0'
// :116:30: error: use of undefined value here causes illegal behavior
+// :116:30: note: when computing vector element at index '0'
// :116:30: error: use of undefined value here causes illegal behavior
+// :116:30: note: when computing vector element at index '0'
// :116:30: error: use of undefined value here causes illegal behavior
+// :116:30: note: when computing vector element at index '0'
// :116:30: error: use of undefined value here causes illegal behavior
+// :116:30: note: when computing vector element at index '1'
// :116:30: error: use of undefined value here causes illegal behavior
+// :116:30: note: when computing vector element at index '1'
// :116:30: error: use of undefined value here causes illegal behavior
// :116:30: note: when computing vector element at index '1'
// :116:30: error: use of undefined value here causes illegal behavior
@@ -2973,19 +2967,25 @@ const std = @import("std");
// :116:30: error: use of undefined value here causes illegal behavior
// :116:30: note: when computing vector element at index '1'
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '0'
+// :116:30: note: when computing vector element at index '1'
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '0'
+// :116:30: note: when computing vector element at index '1'
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '0'
+// :116:30: note: when computing vector element at index '1'
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '0'
+// :116:30: note: when computing vector element at index '1'
// :116:30: error: use of undefined value here causes illegal behavior
+// :116:30: note: when computing vector element at index '1'
// :116:30: error: use of undefined value here causes illegal behavior
+// :116:30: note: when computing vector element at index '1'
// :116:30: error: use of undefined value here causes illegal behavior
+// :116:30: note: when computing vector element at index '1'
// :116:30: error: use of undefined value here causes illegal behavior
+// :116:30: note: when computing vector element at index '1'
// :116:30: error: use of undefined value here causes illegal behavior
+// :116:30: note: when computing vector element at index '1'
// :116:30: error: use of undefined value here causes illegal behavior
+// :116:30: note: when computing vector element at index '1'
// :116:30: error: use of undefined value here causes illegal behavior
// :116:30: note: when computing vector element at index '1'
// :116:30: error: use of undefined value here causes illegal behavior
@@ -2995,10 +2995,10 @@ const std = @import("std");
// :116:30: error: use of undefined value here causes illegal behavior
// :116:30: note: when computing vector element at index '1'
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '0'
+// :116:30: note: when computing vector element at index '1'
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '0'
+// :116:30: note: when computing vector element at index '1'
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '0'
+// :116:30: note: when computing vector element at index '1'
// :116:30: error: use of undefined value here causes illegal behavior
-// :116:30: note: when computing vector element at index '0'
+// :116:30: note: when computing vector element at index '1'
diff --git a/test/cases/compile_errors/union_auto-enum_value_already_taken.zig b/test/cases/compile_errors/union_auto-enum_value_already_taken.zig
index 214fd1bdacd8144e9323c7b451d050c4cec3844f..8756e8400ff263abc78db857a657fbc56bef419d 100644
--- a/test/cases/compile_errors/union_auto-enum_value_already_taken.zig
+++ b/test/cases/compile_errors/union_auto-enum_value_already_taken.zig
@@ -12,5 +12,5 @@ export fn entry() void {
// error
//
-// :6:9: error: enum tag value 60 already taken
-// :4:9: note: other occurrence here
+// :6:9: error: enum tag value '60' for field 'E' already taken
+// :4:9: note: previous occurrence in field 'C'
diff --git a/test/cases/compile_errors/union_backed_by_enum_backed_by_comptime_int.zig b/test/cases/compile_errors/union_backed_by_enum_backed_by_comptime_int.zig
new file mode 100644
index 0000000000000000000000000000000000000000..7217c65b59f2d96922705af883ccb0623aea98e0
--- /dev/null
+++ b/test/cases/compile_errors/union_backed_by_enum_backed_by_comptime_int.zig
@@ -0,0 +1,9 @@
+const U = union(enum(comptime_int)) { a: u32 };
+comptime {
+ const u: U = .{ .a = 123 };
+ _ = u;
+}
+
+// error
+//
+// :1:22: error: expected integer tag type, found 'comptime_int'
diff --git a/test/cases/compile_errors/union_depends_on_pointer_alignment.zig b/test/cases/compile_errors/union_depends_on_pointer_alignment.zig
deleted file mode 100644
index 2b97a3fb54207efde38a61c0fc505f7b0721b984..0000000000000000000000000000000000000000
--- a/test/cases/compile_errors/union_depends_on_pointer_alignment.zig
+++ /dev/null
@@ -1,11 +0,0 @@
-const U = union {
- next: ?*align(1) U align(128),
-};
-
-export fn entry() usize {
- return @alignOf(U);
-}
-
-// error
-//
-// :1:11: error: union layout depends on being pointer aligned
diff --git a/test/cases/compile_errors/union_enum_field_missing.zig b/test/cases/compile_errors/union_enum_field_missing.zig
index c376b72da18c895b2c6c565014f6cc38737f0147..6261d452960947b8ab9e8f8ff1ac17ca3abed35c 100644
--- a/test/cases/compile_errors/union_enum_field_missing.zig
+++ b/test/cases/compile_errors/union_enum_field_missing.zig
@@ -15,6 +15,5 @@ export fn entry() usize {
// error
//
-// :7:11: error: enum field(s) missing in union
-// :4:5: note: field 'c' missing, declared here
-// :1:11: note: enum declared here
+// :7:11: error: enum field 'c' missing from union
+// :4:5: note: enum field here
diff --git a/test/cases/compile_errors/union_field_ordered_differently_than_enum.zig b/test/cases/compile_errors/union_field_ordered_differently_than_enum.zig
index 5c86fb4080cd7f25cccb3a44c0f9b6415be07b4f..6c1e1ccea8608307964a43ac2347d120b4ed4926 100644
--- a/test/cases/compile_errors/union_field_ordered_differently_than_enum.zig
+++ b/test/cases/compile_errors/union_field_ordered_differently_than_enum.zig
@@ -21,7 +21,6 @@ export fn entry() usize {
// error
//
-// :4:5: error: union field 'b' ordered differently than corresponding enum field
-// :1:23: note: enum field here
-// :14:5: error: union field 'b' ordered differently than corresponding enum field
-// :10:5: note: enum field here
+// :3:15: error: union field order does not match tag enum field order
+// :5:5: note: union field 'a' is index 1
+// :1:20: note: enum field 'a' is index 0
diff --git a/test/cases/compile_errors/union_noreturn_field_initialized.zig b/test/cases/compile_errors/union_noreturn_field_initialized.zig
index 3fdc1958703ea9076a0399fac46b8bfdae50b822..da0bd8c5d89613e9e9a026d526491f65a1162055 100644
--- a/test/cases/compile_errors/union_noreturn_field_initialized.zig
+++ b/test/cases/compile_errors/union_noreturn_field_initialized.zig
@@ -15,8 +15,8 @@ pub export fn entry2() void {
const U = union(enum) {
a: noreturn,
};
- var u: U = undefined;
- u = .a;
+ const u: U = .a;
+ _ = u;
}
pub export fn entry3() void {
const U = union(enum) {
@@ -30,12 +30,12 @@ pub export fn entry3() void {
// error
//
-// :11:14: error: cannot initialize 'noreturn' field of union
+// :11:14: error: cannot initialize union field with uninstantiable type 'noreturn'
// :4:9: note: field 'b' declared here
// :2:15: note: union declared here
-// :19:10: error: cannot initialize 'noreturn' field of union
+// :18:19: error: cannot initialize union field with uninstantiable type 'noreturn'
// :16:9: note: field 'a' declared here
// :15:15: note: union declared here
-// :28:13: error: runtime coercion from enum '@typeInfo(tmp.entry3.U).@"union".tag_type.?' to union 'tmp.entry3.U' which has a 'noreturn' field
-// :23:9: note: 'noreturn' field here
+// :28:13: error: runtime coercion from enum '@typeInfo(tmp.entry3.U).@"union".tag_type.?' to union 'tmp.entry3.U' which has non-void fields
+// :23:9: note: field 'a' has uninstantiable type 'noreturn'
// :22:15: note: union declared here
diff --git a/test/cases/compile_errors/union_with_specified_enum_omits_field.zig b/test/cases/compile_errors/union_with_specified_enum_omits_field.zig
index bae2cf2957016281fced4d06bb6464e644851869..e90e60494558730285faa258fab24e8e5253b9a6 100644
--- a/test/cases/compile_errors/union_with_specified_enum_omits_field.zig
+++ b/test/cases/compile_errors/union_with_specified_enum_omits_field.zig
@@ -13,6 +13,5 @@ export fn entry() usize {
// error
//
-// :6:17: error: enum field(s) missing in union
-// :4:5: note: field 'C' missing, declared here
-// :1:16: note: enum declared here
+// :6:17: error: enum field 'C' missing from union
+// :4:5: note: enum field here
diff --git a/test/cases/compile_errors/union_with_too_small_explicit_signed_tag_type.zig b/test/cases/compile_errors/union_with_too_small_explicit_signed_tag_type.zig
index 6a6076e9465e594ea0403ad156d6c1fc8f45b6de..fb9e7091017241c16ce3bf8554102ddf7d6fe64b 100644
--- a/test/cases/compile_errors/union_with_too_small_explicit_signed_tag_type.zig
+++ b/test/cases/compile_errors/union_with_too_small_explicit_signed_tag_type.zig
@@ -10,5 +10,4 @@ export fn entry() void {
// error
//
-// :1:22: error: specified integer tag type cannot represent every field
-// :1:22: note: type 'i2' cannot fit values in range 0...3
+// :4:5: error: enum tag value '2' too large for type 'i2'
diff --git a/test/cases/compile_errors/union_with_too_small_explicit_unsigned_tag_type.zig b/test/cases/compile_errors/union_with_too_small_explicit_unsigned_tag_type.zig
index 830c5634a1281e73b8d1a453a5276503a0e88658..2df10ea0748171a74255c856e8072a2c2d7ab2b7 100644
--- a/test/cases/compile_errors/union_with_too_small_explicit_unsigned_tag_type.zig
+++ b/test/cases/compile_errors/union_with_too_small_explicit_unsigned_tag_type.zig
@@ -11,5 +11,4 @@ export fn entry() void {
// error
//
-// :1:22: error: specified integer tag type cannot represent every field
-// :1:22: note: type 'u2' cannot fit values in range 0...4
+// :6:5: error: enum tag value '4' too large for type 'u2'
diff --git a/test/cases/compile_errors/untagged_union_integer_conversion.zig b/test/cases/compile_errors/untagged_union_integer_conversion.zig
index e469cd125bc9a957cb9efe5a0e9922d45530cfdb..0a8fb54602598dfdc07f28c75ae06f8c3cd2b783 100644
--- a/test/cases/compile_errors/untagged_union_integer_conversion.zig
+++ b/test/cases/compile_errors/untagged_union_integer_conversion.zig
@@ -1,4 +1,4 @@
-const UntaggedUnion = union {};
+const UntaggedUnion = union { a: void };
comptime {
@intFromEnum(@as(UntaggedUnion, undefined));
}
diff --git a/test/cases/compile_errors/variadic_arg_validation.zig b/test/cases/compile_errors/variadic_arg_validation.zig
index c7a8219f2f54889aa132458828a989856709db90..f28622426f76e7757b4bfa253ae7aac86a3250c9 100644
--- a/test/cases/compile_errors/variadic_arg_validation.zig
+++ b/test/cases/compile_errors/variadic_arg_validation.zig
@@ -25,4 +25,4 @@ pub export fn entry3() void {
// :14:24: error: cannot pass 'u48' to variadic function
// :14:24: note: only integers with 0 or power of two bits are extern compatible
// :18:24: error: cannot pass 'void' to variadic function
-// :18:24: note: 'void' is a zero bit type; for C 'void' use 'anyopaque'
+// :18:24: note: 'void' is a zero bit type
diff --git a/test/cases/compile_errors/zero_width_nonexhaustive_enum.zig b/test/cases/compile_errors/zero_width_nonexhaustive_enum.zig
index a38c5f357adc794b0049473eea29e636bbad0203..4ec7297dce19ae33d988ffc96868f44552ff6752 100644
--- a/test/cases/compile_errors/zero_width_nonexhaustive_enum.zig
+++ b/test/cases/compile_errors/zero_width_nonexhaustive_enum.zig
@@ -1,17 +1,20 @@
comptime {
- _ = enum(i0) { a, _ };
+ const E = enum(i0) { a, _ };
+ _ = @as(E, undefined);
}
comptime {
- _ = enum(u0) { a, _ };
+ const E = enum(u0) { a, _ };
+ _ = @as(E, undefined);
}
comptime {
- _ = enum(u0) { a, b, _ };
+ const E = enum(u0) { a, b, _ };
+ _ = @as(E, undefined);
}
// error
//
-// :2:9: error: non-exhaustive enum specifies every value
-// :6:9: error: non-exhaustive enum specifies every value
-// :10:23: error: enumeration value '1' too large for type 'u0'
+// :2:15: error: non-exhaustive enum specifies every value
+// :7:15: error: non-exhaustive enum specifies every value
+// :12:29: error: enum tag value '1' too large for type 'u0'
diff --git a/test/incremental/change_enum_tag_type b/test/incremental/change_enum_tag_type
index 97103351995157bd82b99b96913ffaa6165d2f96..46681407cb6a259e44b1e6071281ecc302b14967 100644
--- a/test/incremental/change_enum_tag_type
+++ b/test/incremental/change_enum_tag_type
@@ -44,7 +44,7 @@ comptime {
}
const std = @import("std");
const io = std.Io.Threaded.global_single_threaded.io();
-#expect_error=main.zig:7:5: error: enumeration value '4' too large for type 'u2'
+#expect_error=main.zig:7:5: error: enum tag value '4' too large for type 'u2'
#update=increase tag size
#file=main.zig
const Tag = u3;
diff --git a/test/incremental/type_dependency_loop b/test/incremental/type_dependency_loop
new file mode 100644
index 0000000000000000000000000000000000000000..40f41bf19fe4bb4d7a19b5a4a40a0a10fb361ca9
--- /dev/null
+++ b/test/incremental/type_dependency_loop
@@ -0,0 +1,55 @@
+#target=x86_64-linux-selfhosted
+#target=x86_64-windows-selfhosted
+#target=x86_64-linux-cbe
+#target=x86_64-windows-cbe
+#target=wasm32-wasi-selfhosted
+#update=initial version
+#file=main.zig
+pub const A = struct { b: B };
+pub const B = struct { a: A };
+pub fn main() void {
+ _ = @as(B, undefined);
+}
+#expect_error=:error: dependency loop with length 2
+#expect_error=main.zig:2:27: note: type 'main.B' depends on type 'main.A' for field declared here
+#expect_error=main.zig:1:27: note: type 'main.A' depends on type 'main.B' for field declared here
+#expect_error=:note: eliminate any one of these dependencies to break the loop
+
+#update=remove reference to dependency loop
+#file=main.zig
+pub const A = struct { b: B };
+pub const B = struct { a: A };
+pub fn main() void {
+ _ = B;
+}
+#expect_stdout=""
+
+#update=change dependency loop without fixing it
+#file=main.zig
+pub const A = struct { b: B };
+pub const B = struct { a: *align(@alignOf(A)) A };
+pub fn main() void {
+ _ = B;
+}
+#expect_stdout=""
+
+#update=reference dependency loop again
+#file=main.zig
+pub const A = struct { b: B };
+pub const B = struct { a: *align(@alignOf(A)) A };
+pub fn main() void {
+ _ = @as(B, undefined);
+}
+#expect_error=:error: dependency loop with length 2
+#expect_error=main.zig:2:43: note: type 'main.B' depends on type 'main.A' for alignment query here
+#expect_error=main.zig:1:27: note: type 'main.A' depends on type 'main.B' for field declared here
+#expect_error=:note: eliminate any one of these dependencies to break the loop
+
+#update=fix dependency loop
+#file=main.zig
+pub const A = struct { b: B };
+pub const B = struct { a: *A };
+pub fn main() void {
+ _ = @as(B, undefined);
+}
+#expect_stdout=""
diff --git a/tools/incr-check.zig b/tools/incr-check.zig
index 171af570361c4986b3ddd75ac909d2ba6b1a7551..8eb985408e54ba63be587055d8c559f9852fe4c4 100644
--- a/tools/incr-check.zig
+++ b/tools/incr-check.zig
@@ -311,12 +311,12 @@ const Eval = struct {
.error_bundle => {
const result_error_bundle = try std.zig.Server.allocErrorBundle(arena, body);
if (stderr.bufferedLen() > 0) {
- const stderr_data = try mr.toOwnedSlice(1);
if (eval.allow_stderr) {
- std.log.info("error_bundle stderr:\n{s}", .{stderr_data});
+ std.log.info("error_bundle stderr:\n{s}", .{stderr.buffered()});
} else {
- eval.fatal("error_bundle unexpected stderr:\n{s}", .{stderr_data});
+ eval.fatal("error_bundle unexpected stderr:\n{s}", .{stderr.buffered()});
}
+ stderr.tossBuffered();
}
if (result_error_bundle.errorMessageCount() != 0) {
try eval.checkErrorOutcome(update, result_error_bundle);
@@ -327,18 +327,18 @@ const Eval = struct {
.emit_digest => {
var r: std.Io.Reader = .fixed(body);
_ = r.takeStruct(std.zig.Server.Message.EmitDigest, .little) catch unreachable;
+
if (stderr.bufferedLen() > 0) {
- const stderr_data = try mr.toOwnedSlice(1);
if (eval.allow_stderr) {
- std.log.info("emit_digest stderr:\n{s}", .{stderr_data});
+ std.log.info("emit_digest stderr:\n{s}", .{stderr.buffered()});
} else {
- eval.fatal("emit_digest unexpected stderr:\n{s}", .{stderr_data});
+ eval.fatal("emit_digest unexpected stderr:\n{s}", .{stderr.buffered()});
}
+ stderr.tossBuffered();
}
-
if (eval.target.backend == .sema) {
try eval.checkSuccessOutcome(update, null, prog_node);
- // This message indicates the end of the update.
+ continue;
}
const digest = r.takeArray(Cache.bin_digest_len) catch unreachable;
@@ -352,7 +352,6 @@ const Eval = struct {
const bin_path = try Dir.path.join(arena, &.{ result_dir, bin_name });
try eval.checkSuccessOutcome(update, bin_path, prog_node);
- // This message indicates the end of the update.
},
else => {
// Ignore other messages.
@@ -370,7 +369,7 @@ const Eval = struct {
}
waitChild(eval.child, eval);
- eval.fatal("compiler failed to send error_bundle or emit_bin_path", .{});
+ eval.fatal("compiler failed to send terminating error_bundle", .{});
}
fn checkErrorOutcome(eval: *Eval, update: Case.Update, error_bundle: std.zig.ErrorBundle) !void {
@@ -417,29 +416,32 @@ const Eval = struct {
is_note: bool,
err_idx: std.zig.ErrorBundle.MessageIndex,
) Allocator.Error!void {
+ const io = eval.io;
const err = eb.getErrorMessage(err_idx);
- if (err.src_loc == .none) @panic("TODO error message with no source location");
if (err.count != 1) @panic("TODO error message with count>1");
const msg = eb.nullTerminatedString(err.msg);
- const src = eb.getSourceLocation(err.src_loc);
- const raw_filename = eb.nullTerminatedString(src.src_path);
-
- const io = eval.io;
-
- // We need to replace backslashes for consistency between platforms.
- const filename = name: {
- if (std.mem.indexOfScalar(u8, raw_filename, '\\') == null) break :name raw_filename;
- const copied = try eval.arena.dupe(u8, raw_filename);
- std.mem.replaceScalar(u8, copied, '\\', '/');
- break :name copied;
+ const matches = matches: {
+ if (expected.is_note != is_note) break :matches false;
+ if (!std.mem.eql(u8, expected.msg, msg)) break :matches false;
+ if (err.src_loc == .none) {
+ break :matches expected.src == null;
+ }
+ const expected_src = expected.src orelse break :matches false;
+ const src = eb.getSourceLocation(err.src_loc);
+ const raw_filename = eb.nullTerminatedString(src.src_path);
+ // We need to replace backslashes for consistency between platforms.
+ const filename = name: {
+ if (std.mem.indexOfScalar(u8, raw_filename, '\\') == null) break :name raw_filename;
+ const copied = try eval.arena.dupe(u8, raw_filename);
+ std.mem.replaceScalar(u8, copied, '\\', '/');
+ break :name copied;
+ };
+ if (!std.mem.eql(u8, expected_src.filename, filename)) break :matches false;
+ if (expected_src.line != src.line + 1) break :matches false;
+ if (expected_src.column != src.column + 1) break :matches false;
+ break :matches true;
};
-
- if (expected.is_note != is_note or
- !std.mem.eql(u8, expected.filename, filename) or
- expected.line != src.line + 1 or
- expected.column != src.column + 1 or
- !std.mem.eql(u8, expected.msg, msg))
- {
+ if (!matches) {
eb.renderToStderr(io, .{}, .auto) catch {};
eval.fatal("compile error did not match expected error", .{});
}
@@ -714,10 +716,12 @@ const Case = struct {
const ExpectedError = struct {
is_note: bool,
- filename: []const u8,
- line: u32,
- column: u32,
msg: []const u8,
+ src: ?struct {
+ filename: []const u8,
+ line: u32,
+ column: u32,
+ },
};
fn parse(arena: Allocator, io: Io, bytes: []const u8) !Case {
@@ -930,16 +934,16 @@ fn parseExpectedError(str: []const u8, l: usize) Case.ExpectedError {
var it = std.mem.splitScalar(u8, str, ':');
const filename = it.first();
- const line_str = it.next() orelse fatal("line {d}: incomplete error specification", .{l});
- const column_str = it.next() orelse fatal("line {d}: incomplete error specification", .{l});
+ const line_str, const column_str = if (filename.len > 0) .{
+ it.next() orelse fatal("line {d}: incomplete error specification", .{l}),
+ it.next() orelse fatal("line {d}: incomplete error specification", .{l}),
+ } else .{ undefined, undefined };
const error_or_note_str = std.mem.trim(
u8,
it.next() orelse fatal("line {d}: incomplete error specification", .{l}),
" ",
);
- const message = std.mem.trim(u8, it.rest(), " ");
- if (filename.len == 0) fatal("line {d}: empty filename", .{l});
- if (message.len == 0) fatal("line {d}: empty error message", .{l});
+
const is_note = if (std.mem.eql(u8, error_or_note_str, "error"))
false
else if (std.mem.eql(u8, error_or_note_str, "note"))
@@ -947,18 +951,19 @@ fn parseExpectedError(str: []const u8, l: usize) Case.ExpectedError {
else
fatal("line {d}: expeted 'error' or 'note', found '{s}'", .{ l, error_or_note_str });
- const line = std.fmt.parseInt(u32, line_str, 10) catch
- fatal("line {d}: invalid line number '{s}'", .{ l, line_str });
-
- const column = std.fmt.parseInt(u32, column_str, 10) catch
- fatal("line {d}: invalid column number '{s}'", .{ l, column_str });
+ const message = std.mem.trim(u8, it.rest(), " ");
+ if (message.len == 0) fatal("line {d}: empty error message", .{l});
return .{
.is_note = is_note,
- .filename = filename,
- .line = line,
- .column = column,
.msg = message,
+ .src = if (filename.len == 0) null else .{
+ .filename = filename,
+ .line = std.fmt.parseInt(u32, line_str, 10) catch
+ fatal("line {d}: invalid line number '{s}'", .{ l, line_str }),
+ .column = std.fmt.parseInt(u32, column_str, 10) catch
+ fatal("line {d}: invalid column number '{s}'", .{ l, column_str }),
+ },
};
}