authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-08-29 14:10:59-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-08-29 14:10:59-07:00
logde7270028d2b70ceea74c43be943b1b788c797a6
tree0d9b545a2a9d36c86b79178f797adf5ebcd40d17
parent7c9a8ecc2aca7f925e59d282540ef8e2d1ae211e
parente69973beddcd8a42dbc7ebcfb96187e5a6f61b61

Merge remote-tracking branch 'origin/master' into llvm15


326 files changed, 14312 insertions(+), 8637 deletions(-)

CMakeLists.txt+76-66
...@@ -12,7 +12,7 @@ if(NOT CMAKE_BUILD_TYPE)...@@ -12,7 +12,7 @@ if(NOT CMAKE_BUILD_TYPE)
12endif()12endif()
1313
14if(NOT CMAKE_INSTALL_PREFIX)14if(NOT CMAKE_INSTALL_PREFIX)
15 set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/stage1" CACHE STRING15 set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/stage3" CACHE STRING
16 "Directory to install zig to" FORCE)16 "Directory to install zig to" FORCE)
17endif()17endif()
1818
...@@ -65,6 +65,9 @@ if("${ZIG_VERSION}" STREQUAL "")...@@ -65,6 +65,9 @@ if("${ZIG_VERSION}" STREQUAL "")
65endif()65endif()
66message(STATUS "Configuring zig version ${ZIG_VERSION}")66message(STATUS "Configuring zig version ${ZIG_VERSION}")
6767
68set(ZIG_SKIP_INSTALL_LIB_FILES off CACHE BOOL
69 "Disable copying lib/ files to install prefix during the build phase")
70
68set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)")71set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)")
69set(ZIG_SHARED_LLVM off CACHE BOOL "Prefer linking against shared LLVM libraries")72set(ZIG_SHARED_LLVM off CACHE BOOL "Prefer linking against shared LLVM libraries")
70set(ZIG_STATIC_LLVM off CACHE BOOL "Prefer linking against static LLVM libraries")73set(ZIG_STATIC_LLVM off CACHE BOOL "Prefer linking against static LLVM libraries")
...@@ -333,7 +336,7 @@ set(ZIG_CONFIG_H_OUT "${CMAKE_BINARY_DIR}/config.h")...@@ -333,7 +336,7 @@ set(ZIG_CONFIG_H_OUT "${CMAKE_BINARY_DIR}/config.h")
333set(ZIG_CONFIG_ZIG_OUT "${CMAKE_BINARY_DIR}/config.zig")336set(ZIG_CONFIG_ZIG_OUT "${CMAKE_BINARY_DIR}/config.zig")
334337
335# This is our shim which will be replaced by stage1.zig.338# This is our shim which will be replaced by stage1.zig.
336set(ZIG0_SOURCES339set(ZIG1_SOURCES
337 "${CMAKE_SOURCE_DIR}/src/stage1/zig0.cpp"340 "${CMAKE_SOURCE_DIR}/src/stage1/zig0.cpp"
338)341)
339342
...@@ -373,9 +376,9 @@ set(ZIG_CPP_SOURCES...@@ -373,9 +376,9 @@ set(ZIG_CPP_SOURCES
373 # https://github.com/ziglang/zig/issues/6363376 # https://github.com/ziglang/zig/issues/6363
374 "${CMAKE_SOURCE_DIR}/src/windows_sdk.cpp"377 "${CMAKE_SOURCE_DIR}/src/windows_sdk.cpp"
375)378)
376# Needed because we use cmake, not the zig build system, to build zig1.o.379# Needed because we use cmake, not the zig build system, to build zig2.o.
377# This list is generated by building zig and then clearing the zig-cache directory,380# This list is generated by building zig and then clearing the zig-cache directory,
378# then manually running the build-obj command (see BUILD_ZIG1_ARGS), and then looking381# then manually running the build-obj command (see BUILD_ZIG2_ARGS), and then looking
379# in the zig-cache directory for the compiler-generated list of zig file dependencies.382# in the zig-cache directory for the compiler-generated list of zig file dependencies.
380set(ZIG_STAGE2_SOURCES383set(ZIG_STAGE2_SOURCES
381 "${ZIG_CONFIG_ZIG_OUT}"384 "${ZIG_CONFIG_ZIG_OUT}"
...@@ -942,40 +945,51 @@ if(MSVC OR MINGW)...@@ -942,40 +945,51 @@ if(MSVC OR MINGW)
942endif()945endif()
943946
944if("${ZIG_EXECUTABLE}" STREQUAL "")947if("${ZIG_EXECUTABLE}" STREQUAL "")
945 add_executable(zig0 ${ZIG0_SOURCES})948 add_executable(zig1 ${ZIG1_SOURCES})
946 set_target_properties(zig0 PROPERTIES949 set_target_properties(zig1 PROPERTIES
947 COMPILE_FLAGS ${EXE_CFLAGS}950 COMPILE_FLAGS ${EXE_CFLAGS}
948 LINK_FLAGS ${EXE_LDFLAGS}951 LINK_FLAGS ${EXE_LDFLAGS}
949 )952 )
950 target_link_libraries(zig0 zigstage1)953 target_link_libraries(zig1 zigstage1)
951endif()954endif()
952955
953if(MSVC)956if(MSVC)
954 set(ZIG1_OBJECT "${CMAKE_BINARY_DIR}/zig1.obj")957 set(ZIG2_OBJECT "${CMAKE_BINARY_DIR}/zig2.obj")
955else()958else()
956 set(ZIG1_OBJECT "${CMAKE_BINARY_DIR}/zig1.o")959 set(ZIG2_OBJECT "${CMAKE_BINARY_DIR}/zig2.o")
957endif()960endif()
958if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")961if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
959 set(ZIG1_RELEASE_ARG "")962 set(ZIG_RELEASE_ARG "")
963elseif("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo")
964 set(ZIG_RELEASE_ARG -Drelease)
960else()965else()
961 set(ZIG1_RELEASE_ARG -OReleaseFast --strip)966 set(ZIG_RELEASE_ARG -Drelease -Dstrip)
967endif()
968if(ZIG_SKIP_INSTALL_LIB_FILES)
969 set(ZIG_SKIP_INSTALL_LIB_FILES_ARG "-Dskip-install-lib-files")
970else()
971 set(ZIG_SKIP_INSTALL_LIB_FILES_ARG "-Dskip-install-lib-files=false")
962endif()972endif()
963if(ZIG_SINGLE_THREADED)973if(ZIG_SINGLE_THREADED)
964 set(ZIG1_SINGLE_THREADED_ARG "-fsingle-threaded")974 set(ZIG_SINGLE_THREADED_ARG "-fsingle-threaded")
975else()
976 set(ZIG_SINGLE_THREADED_ARG "")
977endif()
978if(ZIG_STATIC)
979 set(ZIG_STATIC_ARG "-Duse-zig-libcxx")
965else()980else()
966 set(ZIG1_SINGLE_THREADED_ARG "")981 set(ZIG_STATIC_ARG "")
967endif()982endif()
968983
969set(BUILD_ZIG1_ARGS984set(BUILD_ZIG2_ARGS
970 "src/stage1.zig"985 "src/stage1.zig"
971 -target "${ZIG_TARGET_TRIPLE}"986 --name zig2
972 "-mcpu=${ZIG_TARGET_MCPU}"
973 --name zig1
974 --zig-lib-dir "${CMAKE_SOURCE_DIR}/lib"987 --zig-lib-dir "${CMAKE_SOURCE_DIR}/lib"
975 "-femit-bin=${ZIG1_OBJECT}"988 "-femit-bin=${ZIG2_OBJECT}"
976 -fcompiler-rt989 -fcompiler-rt
977 "${ZIG1_RELEASE_ARG}"990 ${ZIG_SINGLE_THREADED_ARG}
978 "${ZIG1_SINGLE_THREADED_ARG}"991 -target "${ZIG_TARGET_TRIPLE}"
992 -mcpu "${ZIG_TARGET_MCPU}"
979 -lc993 -lc
980 --pkg-begin build_options "${ZIG_CONFIG_ZIG_OUT}"994 --pkg-begin build_options "${ZIG_CONFIG_ZIG_OUT}"
981 --pkg-end995 --pkg-end
...@@ -985,68 +999,64 @@ set(BUILD_ZIG1_ARGS...@@ -985,68 +999,64 @@ set(BUILD_ZIG1_ARGS
985999
986if("${ZIG_EXECUTABLE}" STREQUAL "")1000if("${ZIG_EXECUTABLE}" STREQUAL "")
987 add_custom_command(1001 add_custom_command(
988 OUTPUT "${ZIG1_OBJECT}"1002 OUTPUT "${ZIG2_OBJECT}"
989 COMMAND zig0 ${BUILD_ZIG1_ARGS}1003 COMMAND zig1 ${BUILD_ZIG2_ARGS}
990 DEPENDS zig0 "${ZIG_STAGE2_SOURCES}"1004 DEPENDS zig1 "${ZIG_STAGE2_SOURCES}"
991 COMMENT STATUS "Building self-hosted component ${ZIG1_OBJECT}"1005 COMMENT STATUS "Building stage2 object ${ZIG2_OBJECT}"
992 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"1006 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
993 )1007 )
994 set(ZIG_EXECUTABLE "${zig_BINARY_DIR}/zig")
995 if (WIN32)1008 if (WIN32)
996 set(ZIG_EXECUTABLE "${ZIG_EXECUTABLE}.exe")1009 set(ZIG_EXECUTABLE "${zig2_BINARY_DIR}/zig2.exe")
1010 else()
1011 set(ZIG_EXECUTABLE "${zig2_BINARY_DIR}/zig2")
997 endif()1012 endif()
998else()1013else()
999 add_custom_command(1014 add_custom_command(
1000 OUTPUT "${ZIG1_OBJECT}"1015 OUTPUT "${ZIG2_OBJECT}"
1001 COMMAND "${ZIG_EXECUTABLE}" "build-obj" ${BUILD_ZIG1_ARGS}1016 COMMAND "${ZIG_EXECUTABLE}" "build-obj" ${BUILD_ZIG2_ARGS}
1002 DEPENDS ${ZIG_STAGE2_SOURCES}1017 DEPENDS ${ZIG_STAGE2_SOURCES}
1003 COMMENT STATUS "Building self-hosted component ${ZIG1_OBJECT}"1018 COMMENT STATUS "Building stage2 component ${ZIG2_OBJECT}"
1004 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"1019 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
1005 )1020 )
1006endif()1021endif()
10071022
1008# cmake won't let us configure an executable without C sources.1023# cmake won't let us configure an executable without C sources.
1009add_executable(zig "${CMAKE_SOURCE_DIR}/src/stage1/empty.cpp" "${ZIG1_OBJECT}")1024add_executable(zig2 "${CMAKE_SOURCE_DIR}/src/stage1/empty.cpp" "${ZIG2_OBJECT}")
10101025
1011set_target_properties(zig PROPERTIES1026set_target_properties(zig2 PROPERTIES
1012 COMPILE_FLAGS ${EXE_CFLAGS}1027 COMPILE_FLAGS ${EXE_CFLAGS}
1013 LINK_FLAGS ${EXE_LDFLAGS}1028 LINK_FLAGS ${EXE_LDFLAGS}
1014)1029)
1015target_link_libraries(zig zigstage1)1030target_link_libraries(zig2 zigstage1)
1016if(MSVC)1031if(MSVC)
1017 target_link_libraries(zig ntdll.lib)1032 target_link_libraries(zig2 ntdll.lib)
1018elseif(MINGW)1033elseif(MINGW)
1019 target_link_libraries(zig ntdll)1034 target_link_libraries(zig2 ntdll)
1020endif()1035endif()
10211036
1022install(TARGETS zig DESTINATION bin)1037# Dummy install command so that the "install" target is not missing.
10231038# This is redundant from the "stage3" custom target below.
1024set(ZIG_SKIP_INSTALL_LIB_FILES off CACHE BOOL
1025 "Disable copying lib/ files to install prefix during the build phase")
1026
1027if(NOT ZIG_SKIP_INSTALL_LIB_FILES)1039if(NOT ZIG_SKIP_INSTALL_LIB_FILES)
1028 set(ZIG_INSTALL_ARGS "build"1040 install(FILES "lib/compiler_rt.zig" DESTINATION "lib/zig")
1029 --zig-lib-dir "${CMAKE_SOURCE_DIR}/lib"
1030 "-Dlib-files-only"
1031 --prefix "${CMAKE_INSTALL_PREFIX}"
1032 "-Dconfig_h=${ZIG_CONFIG_H_OUT}"
1033 install
1034 )
1035
1036 # CODE has no effect with Visual Studio build system generator, therefore
1037 # when using Visual Studio build system generator we resort to running
1038 # `zig build install` during the build phase.
1039 if(MSVC)
1040 add_custom_target(zig_install_lib_files ALL
1041 COMMAND zig ${ZIG_INSTALL_ARGS}
1042 DEPENDS zig
1043 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
1044 )
1045 else()
1046 get_target_property(zig_BINARY_DIR zig BINARY_DIR)
1047 install(CODE "set(zig_EXE \"${ZIG_EXECUTABLE}\")")
1048 install(CODE "set(ZIG_INSTALL_ARGS \"${ZIG_INSTALL_ARGS}\")")
1049 install(CODE "set(CMAKE_SOURCE_DIR \"${CMAKE_SOURCE_DIR}\")")
1050 install(SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/cmake/install.cmake)
1051 endif()
1052endif()1041endif()
1042
1043set(ZIG_INSTALL_ARGS "build"
1044 --zig-lib-dir "${CMAKE_SOURCE_DIR}/lib"
1045 --prefix "${CMAKE_INSTALL_PREFIX}"
1046 "-Dconfig_h=${ZIG_CONFIG_H_OUT}"
1047 "-Denable-llvm"
1048 "-Denable-stage1"
1049 ${ZIG_RELEASE_ARG}
1050 ${ZIG_STATIC_ARG}
1051 ${ZIG_SKIP_INSTALL_LIB_FILES_ARG}
1052 ${ZIG_SINGLE_THREADED_ARG}
1053 "-Dtarget=${ZIG_TARGET_TRIPLE}"
1054 "-Dcpu=${ZIG_TARGET_MCPU}"
1055)
1056
1057add_custom_target(stage3 ALL
1058 COMMAND zig2 ${ZIG_INSTALL_ARGS}
1059 DEPENDS zig2
1060 COMMENT STATUS "Building stage3"
1061 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
1062)
build.zig+29-42
...@@ -15,6 +15,7 @@ const stack_size = 32 * 1024 * 1024;...@@ -15,6 +15,7 @@ const stack_size = 32 * 1024 * 1024;
1515
16pub fn build(b: *Builder) !void {16pub fn build(b: *Builder) !void {
17 b.setPreferredReleaseMode(.ReleaseFast);17 b.setPreferredReleaseMode(.ReleaseFast);
18 const test_step = b.step("test", "Run all the tests");
18 const mode = b.standardReleaseOptions();19 const mode = b.standardReleaseOptions();
19 const target = b.standardTargetOptions(.{});20 const target = b.standardTargetOptions(.{});
20 const single_threaded = b.option(bool, "single-threaded", "Build artifacts that run in single threaded mode");21 const single_threaded = b.option(bool, "single-threaded", "Build artifacts that run in single threaded mode");
...@@ -39,8 +40,6 @@ pub fn build(b: *Builder) !void {...@@ -39,8 +40,6 @@ pub fn build(b: *Builder) !void {
39 const docs_step = b.step("docs", "Build documentation");40 const docs_step = b.step("docs", "Build documentation");
40 docs_step.dependOn(&docgen_cmd.step);41 docs_step.dependOn(&docgen_cmd.step);
4142
42 const toolchain_step = b.step("test-toolchain", "Run the tests for the toolchain");
43
44 var test_cases = b.addTest("src/test.zig");43 var test_cases = b.addTest("src/test.zig");
45 test_cases.stack_size = stack_size;44 test_cases.stack_size = stack_size;
46 test_cases.setBuildMode(mode);45 test_cases.setBuildMode(mode);
...@@ -64,10 +63,9 @@ pub fn build(b: *Builder) !void {...@@ -64,10 +63,9 @@ pub fn build(b: *Builder) !void {
6463
65 const only_install_lib_files = b.option(bool, "lib-files-only", "Only install library files") orelse false;64 const only_install_lib_files = b.option(bool, "lib-files-only", "Only install library files") orelse false;
6665
67 const is_stage1 = b.option(bool, "stage1", "Build the stage1 compiler, put stage2 behind a feature flag") orelse false;66 const have_stage1 = b.option(bool, "enable-stage1", "Include the stage1 compiler behind a feature flag") orelse false;
68 const omit_stage2 = b.option(bool, "omit-stage2", "Do not include stage2 behind a feature flag inside stage1") orelse false;
69 const static_llvm = b.option(bool, "static-llvm", "Disable integration with system-installed LLVM, Clang, LLD, and libc++") orelse false;67 const static_llvm = b.option(bool, "static-llvm", "Disable integration with system-installed LLVM, Clang, LLD, and libc++") orelse false;
70 const enable_llvm = b.option(bool, "enable-llvm", "Build self-hosted compiler with LLVM backend enabled") orelse (is_stage1 or static_llvm);68 const enable_llvm = b.option(bool, "enable-llvm", "Build self-hosted compiler with LLVM backend enabled") orelse (have_stage1 or static_llvm);
71 const llvm_has_m68k = b.option(69 const llvm_has_m68k = b.option(
72 bool,70 bool,
73 "llvm-has-m68k",71 "llvm-has-m68k",
...@@ -137,7 +135,7 @@ pub fn build(b: *Builder) !void {...@@ -137,7 +135,7 @@ pub fn build(b: *Builder) !void {
137 };135 };
138136
139 const main_file: ?[]const u8 = mf: {137 const main_file: ?[]const u8 = mf: {
140 if (!is_stage1) break :mf "src/main.zig";138 if (!have_stage1) break :mf "src/main.zig";
141 if (use_zig0) break :mf null;139 if (use_zig0) break :mf null;
142 break :mf "src/stage1.zig";140 break :mf "src/stage1.zig";
143 };141 };
...@@ -150,7 +148,7 @@ pub fn build(b: *Builder) !void {...@@ -150,7 +148,7 @@ pub fn build(b: *Builder) !void {
150 exe.setBuildMode(mode);148 exe.setBuildMode(mode);
151 exe.setTarget(target);149 exe.setTarget(target);
152 if (!skip_stage2_tests) {150 if (!skip_stage2_tests) {
153 toolchain_step.dependOn(&exe.step);151 test_step.dependOn(&exe.step);
154 }152 }
155153
156 b.default_step.dependOn(&exe.step);154 b.default_step.dependOn(&exe.step);
...@@ -248,7 +246,7 @@ pub fn build(b: *Builder) !void {...@@ -248,7 +246,7 @@ pub fn build(b: *Builder) !void {
248 }246 }
249 };247 };
250248
251 if (is_stage1) {249 if (have_stage1) {
252 const softfloat = b.addStaticLibrary("softfloat", null);250 const softfloat = b.addStaticLibrary("softfloat", null);
253 softfloat.setBuildMode(.ReleaseFast);251 softfloat.setBuildMode(.ReleaseFast);
254 softfloat.setTarget(target);252 softfloat.setTarget(target);
...@@ -360,8 +358,7 @@ pub fn build(b: *Builder) !void {...@@ -360,8 +358,7 @@ pub fn build(b: *Builder) !void {
360 exe_options.addOption(bool, "enable_tracy_callstack", tracy_callstack);358 exe_options.addOption(bool, "enable_tracy_callstack", tracy_callstack);
361 exe_options.addOption(bool, "enable_tracy_allocation", tracy_allocation);359 exe_options.addOption(bool, "enable_tracy_allocation", tracy_allocation);
362 exe_options.addOption(bool, "value_tracing", value_tracing);360 exe_options.addOption(bool, "value_tracing", value_tracing);
363 exe_options.addOption(bool, "is_stage1", is_stage1);361 exe_options.addOption(bool, "have_stage1", have_stage1);
364 exe_options.addOption(bool, "omit_stage2", omit_stage2);
365 if (tracy) |tracy_path| {362 if (tracy) |tracy_path| {
366 const client_cpp = fs.path.join(363 const client_cpp = fs.path.join(
367 b.allocator,364 b.allocator,
...@@ -396,8 +393,7 @@ pub fn build(b: *Builder) !void {...@@ -396,8 +393,7 @@ pub fn build(b: *Builder) !void {
396 test_cases_options.addOption(bool, "enable_link_snapshots", enable_link_snapshots);393 test_cases_options.addOption(bool, "enable_link_snapshots", enable_link_snapshots);
397 test_cases_options.addOption(bool, "skip_non_native", skip_non_native);394 test_cases_options.addOption(bool, "skip_non_native", skip_non_native);
398 test_cases_options.addOption(bool, "skip_stage1", skip_stage1);395 test_cases_options.addOption(bool, "skip_stage1", skip_stage1);
399 test_cases_options.addOption(bool, "is_stage1", is_stage1);396 test_cases_options.addOption(bool, "have_stage1", have_stage1);
400 test_cases_options.addOption(bool, "omit_stage2", omit_stage2);
401 test_cases_options.addOption(bool, "have_llvm", enable_llvm);397 test_cases_options.addOption(bool, "have_llvm", enable_llvm);
402 test_cases_options.addOption(bool, "llvm_has_m68k", llvm_has_m68k);398 test_cases_options.addOption(bool, "llvm_has_m68k", llvm_has_m68k);
403 test_cases_options.addOption(bool, "llvm_has_csky", llvm_has_csky);399 test_cases_options.addOption(bool, "llvm_has_csky", llvm_has_csky);
...@@ -418,7 +414,7 @@ pub fn build(b: *Builder) !void {...@@ -418,7 +414,7 @@ pub fn build(b: *Builder) !void {
418 const test_cases_step = b.step("test-cases", "Run the main compiler test cases");414 const test_cases_step = b.step("test-cases", "Run the main compiler test cases");
419 test_cases_step.dependOn(&test_cases.step);415 test_cases_step.dependOn(&test_cases.step);
420 if (!skip_stage2_tests) {416 if (!skip_stage2_tests) {
421 toolchain_step.dependOn(test_cases_step);417 test_step.dependOn(test_cases_step);
422 }418 }
423419
424 var chosen_modes: [4]builtin.Mode = undefined;420 var chosen_modes: [4]builtin.Mode = undefined;
...@@ -442,11 +438,11 @@ pub fn build(b: *Builder) !void {...@@ -442,11 +438,11 @@ pub fn build(b: *Builder) !void {
442 const modes = chosen_modes[0..chosen_mode_index];438 const modes = chosen_modes[0..chosen_mode_index];
443439
444 // run stage1 `zig fmt` on this build.zig file just to make sure it works440 // run stage1 `zig fmt` on this build.zig file just to make sure it works
445 toolchain_step.dependOn(&fmt_build_zig.step);441 test_step.dependOn(&fmt_build_zig.step);
446 const fmt_step = b.step("test-fmt", "Run zig fmt against build.zig to make sure it works");442 const fmt_step = b.step("test-fmt", "Run zig fmt against build.zig to make sure it works");
447 fmt_step.dependOn(&fmt_build_zig.step);443 fmt_step.dependOn(&fmt_build_zig.step);
448444
449 toolchain_step.dependOn(tests.addPkgTests(445 test_step.dependOn(tests.addPkgTests(
450 b,446 b,
451 test_filter,447 test_filter,
452 "test/behavior.zig",448 "test/behavior.zig",
...@@ -457,11 +453,10 @@ pub fn build(b: *Builder) !void {...@@ -457,11 +453,10 @@ pub fn build(b: *Builder) !void {
457 skip_non_native,453 skip_non_native,
458 skip_libc,454 skip_libc,
459 skip_stage1,455 skip_stage1,
460 omit_stage2,456 skip_stage2_tests,
461 is_stage1,
462 ));457 ));
463458
464 toolchain_step.dependOn(tests.addPkgTests(459 test_step.dependOn(tests.addPkgTests(
465 b,460 b,
466 test_filter,461 test_filter,
467 "lib/compiler_rt.zig",462 "lib/compiler_rt.zig",
...@@ -472,11 +467,10 @@ pub fn build(b: *Builder) !void {...@@ -472,11 +467,10 @@ pub fn build(b: *Builder) !void {
472 skip_non_native,467 skip_non_native,
473 true, // skip_libc468 true, // skip_libc
474 skip_stage1,469 skip_stage1,
475 omit_stage2 or true, // TODO get these all passing470 skip_stage2_tests or true, // TODO get these all passing
476 is_stage1,
477 ));471 ));
478472
479 toolchain_step.dependOn(tests.addPkgTests(473 test_step.dependOn(tests.addPkgTests(
480 b,474 b,
481 test_filter,475 test_filter,
482 "lib/c.zig",476 "lib/c.zig",
...@@ -487,37 +481,36 @@ pub fn build(b: *Builder) !void {...@@ -487,37 +481,36 @@ pub fn build(b: *Builder) !void {
487 skip_non_native,481 skip_non_native,
488 true, // skip_libc482 true, // skip_libc
489 skip_stage1,483 skip_stage1,
490 omit_stage2 or true, // TODO get these all passing484 skip_stage2_tests or true, // TODO get these all passing
491 is_stage1,
492 ));485 ));
493486
494 toolchain_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes));487 test_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes));
495 toolchain_step.dependOn(tests.addStandaloneTests(488 test_step.dependOn(tests.addStandaloneTests(
496 b,489 b,
497 test_filter,490 test_filter,
498 modes,491 modes,
499 skip_non_native,492 skip_non_native,
500 enable_macos_sdk,493 enable_macos_sdk,
501 target,494 target,
502 omit_stage2,495 skip_stage2_tests,
503 b.enable_darling,496 b.enable_darling,
504 b.enable_qemu,497 b.enable_qemu,
505 b.enable_rosetta,498 b.enable_rosetta,
506 b.enable_wasmtime,499 b.enable_wasmtime,
507 b.enable_wine,500 b.enable_wine,
508 ));501 ));
509 toolchain_step.dependOn(tests.addLinkTests(b, test_filter, modes, enable_macos_sdk, omit_stage2));502 test_step.dependOn(tests.addLinkTests(b, test_filter, modes, enable_macos_sdk, skip_stage2_tests));
510 toolchain_step.dependOn(tests.addStackTraceTests(b, test_filter, modes));503 test_step.dependOn(tests.addStackTraceTests(b, test_filter, modes));
511 toolchain_step.dependOn(tests.addCliTests(b, test_filter, modes));504 test_step.dependOn(tests.addCliTests(b, test_filter, modes));
512 toolchain_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes));505 test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes));
513 toolchain_step.dependOn(tests.addTranslateCTests(b, test_filter));506 test_step.dependOn(tests.addTranslateCTests(b, test_filter));
514 if (!skip_run_translated_c) {507 if (!skip_run_translated_c) {
515 toolchain_step.dependOn(tests.addRunTranslatedCTests(b, test_filter, target));508 test_step.dependOn(tests.addRunTranslatedCTests(b, test_filter, target));
516 }509 }
517 // tests for this feature are disabled until we have the self-hosted compiler available510 // tests for this feature are disabled until we have the self-hosted compiler available
518 // toolchain_step.dependOn(tests.addGenHTests(b, test_filter));511 // test_step.dependOn(tests.addGenHTests(b, test_filter));
519512
520 const std_step = tests.addPkgTests(513 test_step.dependOn(tests.addPkgTests(
521 b,514 b,
522 test_filter,515 test_filter,
523 "lib/std/std.zig",516 "lib/std/std.zig",
...@@ -528,14 +521,8 @@ pub fn build(b: *Builder) !void {...@@ -528,14 +521,8 @@ pub fn build(b: *Builder) !void {
528 skip_non_native,521 skip_non_native,
529 skip_libc,522 skip_libc,
530 skip_stage1,523 skip_stage1,
531 omit_stage2 or true, // TODO get these all passing524 true, // TODO get these all passing
532 is_stage1,525 ));
533 );
534
535 const test_step = b.step("test", "Run all the tests");
536 test_step.dependOn(toolchain_step);
537 test_step.dependOn(std_step);
538 test_step.dependOn(docs_step);
539}526}
540527
541const exe_cflags = [_][]const u8{528const exe_cflags = [_][]const u8{
ci/azure/build.zig deleted-976
...@@ -1,976 +0,0 @@
1const std = @import("std");
2const builtin = std.builtin;
3const Builder = std.build.Builder;
4const BufMap = std.BufMap;
5const mem = std.mem;
6const ArrayList = std.ArrayList;
7const io = std.io;
8const fs = std.fs;
9const InstallDirectoryOptions = std.build.InstallDirectoryOptions;
10const assert = std.debug.assert;
11
12const zig_version = std.builtin.Version{ .major = 0, .minor = 10, .patch = 0 };
13
14pub fn build(b: *Builder) !void {
15 b.setPreferredReleaseMode(.ReleaseFast);
16 const mode = b.standardReleaseOptions();
17 const target = b.standardTargetOptions(.{});
18 const single_threaded = b.option(bool, "single-threaded", "Build artifacts that run in single threaded mode");
19 const use_zig_libcxx = b.option(bool, "use-zig-libcxx", "If libc++ is needed, use zig's bundled version, don't try to integrate with the system") orelse false;
20
21 const docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");
22 docgen_exe.single_threaded = single_threaded;
23
24 const rel_zig_exe = try fs.path.relative(b.allocator, b.build_root, b.zig_exe);
25 const langref_out_path = fs.path.join(
26 b.allocator,
27 &[_][]const u8{ b.cache_root, "langref.html" },
28 ) catch unreachable;
29 const docgen_cmd = docgen_exe.run();
30 docgen_cmd.addArgs(&[_][]const u8{
31 rel_zig_exe,
32 "doc" ++ fs.path.sep_str ++ "langref.html.in",
33 langref_out_path,
34 });
35 docgen_cmd.step.dependOn(&docgen_exe.step);
36
37 const docs_step = b.step("docs", "Build documentation");
38 docs_step.dependOn(&docgen_cmd.step);
39
40 const is_stage1 = b.option(bool, "stage1", "Build the stage1 compiler, put stage2 behind a feature flag") orelse false;
41 const omit_stage2 = b.option(bool, "omit-stage2", "Do not include stage2 behind a feature flag inside stage1") orelse false;
42 const static_llvm = b.option(bool, "static-llvm", "Disable integration with system-installed LLVM, Clang, LLD, and libc++") orelse false;
43 const enable_llvm = b.option(bool, "enable-llvm", "Build self-hosted compiler with LLVM backend enabled") orelse (is_stage1 or static_llvm);
44 const llvm_has_m68k = b.option(
45 bool,
46 "llvm-has-m68k",
47 "Whether LLVM has the experimental target m68k enabled",
48 ) orelse false;
49 const llvm_has_csky = b.option(
50 bool,
51 "llvm-has-csky",
52 "Whether LLVM has the experimental target csky enabled",
53 ) orelse false;
54 const llvm_has_arc = b.option(
55 bool,
56 "llvm-has-arc",
57 "Whether LLVM has the experimental target arc enabled",
58 ) orelse false;
59 const config_h_path_option = b.option([]const u8, "config_h", "Path to the generated config.h");
60
61 b.installDirectory(InstallDirectoryOptions{
62 .source_dir = "lib",
63 .install_dir = .lib,
64 .install_subdir = "zig",
65 .exclude_extensions = &[_][]const u8{
66 // exclude files from lib/std/compress/
67 ".gz",
68 ".z.0",
69 ".z.9",
70 "rfc1951.txt",
71 "rfc1952.txt",
72 // exclude files from lib/std/compress/deflate/testdata
73 ".expect",
74 ".expect-noinput",
75 ".golden",
76 ".input",
77 "compress-e.txt",
78 "compress-gettysburg.txt",
79 "compress-pi.txt",
80 "rfc1951.txt",
81 // exclude files from lib/std/tz/
82 ".tzif",
83 // others
84 "README.md",
85 },
86 .blank_extensions = &[_][]const u8{
87 "test.zig",
88 },
89 });
90
91 const tracy = b.option([]const u8, "tracy", "Enable Tracy integration. Supply path to Tracy source");
92 const tracy_callstack = b.option(bool, "tracy-callstack", "Include callstack information with Tracy data. Does nothing if -Dtracy is not provided") orelse false;
93 const tracy_allocation = b.option(bool, "tracy-allocation", "Include allocation information with Tracy data. Does nothing if -Dtracy is not provided") orelse false;
94 const force_gpa = b.option(bool, "force-gpa", "Force the compiler to use GeneralPurposeAllocator") orelse false;
95 const link_libc = b.option(bool, "force-link-libc", "Force self-hosted compiler to link libc") orelse enable_llvm;
96 const strip = b.option(bool, "strip", "Omit debug information") orelse false;
97 const value_tracing = b.option(bool, "value-tracing", "Enable extra state tracking to help troubleshoot bugs in the compiler (using the std.debug.Trace API)") orelse false;
98
99 const mem_leak_frames: u32 = b.option(u32, "mem-leak-frames", "How many stack frames to print when a memory leak occurs. Tests get 2x this amount.") orelse blk: {
100 if (strip) break :blk @as(u32, 0);
101 if (mode != .Debug) break :blk 0;
102 break :blk 4;
103 };
104
105 const main_file: ?[]const u8 = if (is_stage1) null else "src/main.zig";
106
107 const exe = b.addExecutable("zig", main_file);
108 exe.strip = strip;
109 exe.install();
110 exe.setBuildMode(mode);
111 exe.setTarget(target);
112
113 b.default_step.dependOn(&exe.step);
114 exe.single_threaded = single_threaded;
115
116 if (target.isWindows() and target.getAbi() == .gnu) {
117 // LTO is currently broken on mingw, this can be removed when it's fixed.
118 exe.want_lto = false;
119 }
120
121 const exe_options = b.addOptions();
122 exe.addOptions("build_options", exe_options);
123
124 exe_options.addOption(u32, "mem_leak_frames", mem_leak_frames);
125 exe_options.addOption(bool, "skip_non_native", false);
126 exe_options.addOption(bool, "have_llvm", enable_llvm);
127 exe_options.addOption(bool, "llvm_has_m68k", llvm_has_m68k);
128 exe_options.addOption(bool, "llvm_has_csky", llvm_has_csky);
129 exe_options.addOption(bool, "llvm_has_arc", llvm_has_arc);
130 exe_options.addOption(bool, "force_gpa", force_gpa);
131
132 if (link_libc) {
133 exe.linkLibC();
134 }
135
136 const is_debug = mode == .Debug;
137 const enable_logging = b.option(bool, "log", "Enable debug logging with --debug-log") orelse is_debug;
138 const enable_link_snapshots = b.option(bool, "link-snapshot", "Whether to enable linker state snapshots") orelse false;
139
140 const opt_version_string = b.option([]const u8, "version-string", "Override Zig version string. Default is to find out with git.");
141 const version = if (opt_version_string) |version| version else v: {
142 const version_string = b.fmt("{d}.{d}.{d}", .{ zig_version.major, zig_version.minor, zig_version.patch });
143
144 var code: u8 = undefined;
145 const git_describe_untrimmed = b.execAllowFail(&[_][]const u8{
146 "git", "-C", b.build_root, "describe", "--match", "*.*.*", "--tags",
147 }, &code, .Ignore) catch {
148 break :v version_string;
149 };
150 const git_describe = mem.trim(u8, git_describe_untrimmed, " \n\r");
151
152 switch (mem.count(u8, git_describe, "-")) {
153 0 => {
154 // Tagged release version (e.g. 0.9.0).
155 if (!mem.eql(u8, git_describe, version_string)) {
156 std.debug.print("Zig version '{s}' does not match Git tag '{s}'\n", .{ version_string, git_describe });
157 std.process.exit(1);
158 }
159 break :v version_string;
160 },
161 2 => {
162 // Untagged development build (e.g. 0.9.0-dev.2025+ecf0050a9).
163 var it = mem.split(u8, git_describe, "-");
164 const tagged_ancestor = it.next() orelse unreachable;
165 const commit_height = it.next() orelse unreachable;
166 const commit_id = it.next() orelse unreachable;
167
168 const ancestor_ver = try std.builtin.Version.parse(tagged_ancestor);
169 if (zig_version.order(ancestor_ver) != .gt) {
170 std.debug.print("Zig version '{}' must be greater than tagged ancestor '{}'\n", .{ zig_version, ancestor_ver });
171 std.process.exit(1);
172 }
173
174 // Check that the commit hash is prefixed with a 'g' (a Git convention).
175 if (commit_id.len < 1 or commit_id[0] != 'g') {
176 std.debug.print("Unexpected `git describe` output: {s}\n", .{git_describe});
177 break :v version_string;
178 }
179
180 // The version is reformatted in accordance with the https://semver.org specification.
181 break :v b.fmt("{s}-dev.{s}+{s}", .{ version_string, commit_height, commit_id[1..] });
182 },
183 else => {
184 std.debug.print("Unexpected `git describe` output: {s}\n", .{git_describe});
185 break :v version_string;
186 },
187 }
188 };
189 exe_options.addOption([:0]const u8, "version", try b.allocator.dupeZ(u8, version));
190
191 if (enable_llvm) {
192 const cmake_cfg = if (static_llvm) null else findAndParseConfigH(b, config_h_path_option);
193
194 if (is_stage1) {
195 const softfloat = b.addStaticLibrary("softfloat", null);
196 softfloat.setBuildMode(.ReleaseFast);
197 softfloat.setTarget(target);
198 softfloat.addIncludeDir("deps/SoftFloat-3e-prebuilt");
199 softfloat.addIncludeDir("deps/SoftFloat-3e/source/8086");
200 softfloat.addIncludeDir("deps/SoftFloat-3e/source/include");
201 softfloat.addCSourceFiles(&softfloat_sources, &[_][]const u8{ "-std=c99", "-O3" });
202 softfloat.single_threaded = single_threaded;
203
204 const zig0 = b.addExecutable("zig0", null);
205 zig0.addCSourceFiles(&.{"src/stage1/zig0.cpp"}, &exe_cflags);
206 zig0.addIncludeDir("zig-cache/tmp"); // for config.h
207 zig0.defineCMacro("ZIG_VERSION_MAJOR", b.fmt("{d}", .{zig_version.major}));
208 zig0.defineCMacro("ZIG_VERSION_MINOR", b.fmt("{d}", .{zig_version.minor}));
209 zig0.defineCMacro("ZIG_VERSION_PATCH", b.fmt("{d}", .{zig_version.patch}));
210 zig0.defineCMacro("ZIG_VERSION_STRING", b.fmt("\"{s}\"", .{version}));
211
212 for ([_]*std.build.LibExeObjStep{ zig0, exe }) |artifact| {
213 artifact.addIncludeDir("src");
214 artifact.addIncludeDir("deps/SoftFloat-3e/source/include");
215 artifact.addIncludeDir("deps/SoftFloat-3e-prebuilt");
216
217 artifact.defineCMacro("ZIG_LINK_MODE", "Static");
218
219 artifact.addCSourceFiles(&stage1_sources, &exe_cflags);
220 artifact.addCSourceFiles(&optimized_c_sources, &[_][]const u8{ "-std=c99", "-O3" });
221
222 artifact.linkLibrary(softfloat);
223 artifact.linkLibCpp();
224 }
225
226 try addStaticLlvmOptionsToExe(zig0);
227
228 const zig1_obj_ext = target.getObjectFormat().fileExt(target.getCpuArch());
229 const zig1_obj_path = b.pathJoin(&.{ "zig-cache", "tmp", b.fmt("zig1{s}", .{zig1_obj_ext}) });
230 const zig1_compiler_rt_path = b.pathJoin(&.{ b.pathFromRoot("lib"), "std", "special", "compiler_rt.zig" });
231
232 const zig1_obj = zig0.run();
233 zig1_obj.addArgs(&.{
234 "src/stage1.zig",
235 "-target",
236 try target.zigTriple(b.allocator),
237 "-mcpu=baseline",
238 "--name",
239 "zig1",
240 "--zig-lib-dir",
241 b.pathFromRoot("lib"),
242 b.fmt("-femit-bin={s}", .{b.pathFromRoot(zig1_obj_path)}),
243 "-fcompiler-rt",
244 "-lc",
245 });
246 {
247 zig1_obj.addArgs(&.{ "--pkg-begin", "build_options" });
248 zig1_obj.addFileSourceArg(exe_options.getSource());
249 zig1_obj.addArgs(&.{ "--pkg-end", "--pkg-begin", "compiler_rt", zig1_compiler_rt_path, "--pkg-end" });
250 }
251 switch (mode) {
252 .Debug => {},
253 .ReleaseFast => {
254 zig1_obj.addArg("-OReleaseFast");
255 zig1_obj.addArg("--strip");
256 },
257 .ReleaseSafe => {
258 zig1_obj.addArg("-OReleaseSafe");
259 zig1_obj.addArg("--strip");
260 },
261 .ReleaseSmall => {
262 zig1_obj.addArg("-OReleaseSmall");
263 zig1_obj.addArg("--strip");
264 },
265 }
266 if (single_threaded orelse false) {
267 zig1_obj.addArg("-fsingle-threaded");
268 }
269
270 exe.step.dependOn(&zig1_obj.step);
271 exe.addObjectFile(zig1_obj_path);
272
273 // This is intentionally a dummy path. stage1.zig tries to @import("compiler_rt") in case
274 // of being built by cmake. But when built by zig it's gonna get a compiler_rt so that
275 // is pointless.
276 exe.addPackagePath("compiler_rt", "src/empty.zig");
277 }
278 if (cmake_cfg) |cfg| {
279 // Inside this code path, we have to coordinate with system packaged LLVM, Clang, and LLD.
280 // That means we also have to rely on stage1 compiled c++ files. We parse config.h to find
281 // the information passed on to us from cmake.
282 if (cfg.cmake_prefix_path.len > 0) {
283 b.addSearchPrefix(cfg.cmake_prefix_path);
284 }
285
286 try addCmakeCfgOptionsToExe(b, cfg, exe, use_zig_libcxx);
287 } else {
288 // Here we are -Denable-llvm but no cmake integration.
289 try addStaticLlvmOptionsToExe(exe);
290 }
291 }
292
293 const semver = try std.SemanticVersion.parse(version);
294 exe_options.addOption(std.SemanticVersion, "semver", semver);
295
296 exe_options.addOption(bool, "enable_logging", enable_logging);
297 exe_options.addOption(bool, "enable_link_snapshots", enable_link_snapshots);
298 exe_options.addOption(bool, "enable_tracy", tracy != null);
299 exe_options.addOption(bool, "enable_tracy_callstack", tracy_callstack);
300 exe_options.addOption(bool, "enable_tracy_allocation", tracy_allocation);
301 exe_options.addOption(bool, "value_tracing", value_tracing);
302 exe_options.addOption(bool, "is_stage1", is_stage1);
303 exe_options.addOption(bool, "omit_stage2", omit_stage2);
304 if (tracy) |tracy_path| {
305 const client_cpp = fs.path.join(
306 b.allocator,
307 &[_][]const u8{ tracy_path, "TracyClient.cpp" },
308 ) catch unreachable;
309
310 // On mingw, we need to opt into windows 7+ to get some features required by tracy.
311 const tracy_c_flags: []const []const u8 = if (target.isWindows() and target.getAbi() == .gnu)
312 &[_][]const u8{ "-DTRACY_ENABLE=1", "-fno-sanitize=undefined", "-D_WIN32_WINNT=0x601" }
313 else
314 &[_][]const u8{ "-DTRACY_ENABLE=1", "-fno-sanitize=undefined" };
315
316 exe.addIncludeDir(tracy_path);
317 exe.addCSourceFile(client_cpp, tracy_c_flags);
318 if (!enable_llvm) {
319 exe.linkSystemLibraryName("c++");
320 }
321 exe.linkLibC();
322
323 if (target.isWindows()) {
324 exe.linkSystemLibrary("dbghelp");
325 exe.linkSystemLibrary("ws2_32");
326 }
327 }
328}
329
330const exe_cflags = [_][]const u8{
331 "-std=c++14",
332 "-D__STDC_CONSTANT_MACROS",
333 "-D__STDC_FORMAT_MACROS",
334 "-D__STDC_LIMIT_MACROS",
335 "-D_GNU_SOURCE",
336 "-fvisibility-inlines-hidden",
337 "-fno-exceptions",
338 "-fno-rtti",
339 "-Werror=type-limits",
340 "-Wno-missing-braces",
341 "-Wno-comment",
342};
343
344fn addCmakeCfgOptionsToExe(
345 b: *Builder,
346 cfg: CMakeConfig,
347 exe: *std.build.LibExeObjStep,
348 use_zig_libcxx: bool,
349) !void {
350 exe.addObjectFile(fs.path.join(b.allocator, &[_][]const u8{
351 cfg.cmake_binary_dir,
352 "zigcpp",
353 b.fmt("{s}{s}{s}", .{ exe.target.libPrefix(), "zigcpp", exe.target.staticLibSuffix() }),
354 }) catch unreachable);
355 assert(cfg.lld_include_dir.len != 0);
356 exe.addIncludeDir(cfg.lld_include_dir);
357 addCMakeLibraryList(exe, cfg.clang_libraries);
358 addCMakeLibraryList(exe, cfg.lld_libraries);
359 addCMakeLibraryList(exe, cfg.llvm_libraries);
360
361 if (use_zig_libcxx) {
362 exe.linkLibCpp();
363 } else {
364 const need_cpp_includes = true;
365
366 // System -lc++ must be used because in this code path we are attempting to link
367 // against system-provided LLVM, Clang, LLD.
368 if (exe.target.getOsTag() == .linux) {
369 // First we try to static link against gcc libstdc++. If that doesn't work,
370 // we fall back to -lc++ and cross our fingers.
371 addCxxKnownPath(b, cfg, exe, "libstdc++.a", "", need_cpp_includes) catch |err| switch (err) {
372 error.RequiredLibraryNotFound => {
373 exe.linkSystemLibrary("c++");
374 },
375 else => |e| return e,
376 };
377 exe.linkSystemLibrary("unwind");
378 } else if (exe.target.isFreeBSD()) {
379 try addCxxKnownPath(b, cfg, exe, "libc++.a", null, need_cpp_includes);
380 exe.linkSystemLibrary("pthread");
381 } else if (exe.target.getOsTag() == .openbsd) {
382 try addCxxKnownPath(b, cfg, exe, "libc++.a", null, need_cpp_includes);
383 try addCxxKnownPath(b, cfg, exe, "libc++abi.a", null, need_cpp_includes);
384 } else if (exe.target.isDarwin()) {
385 exe.linkSystemLibrary("c++");
386 }
387 }
388
389 if (cfg.dia_guids_lib.len != 0) {
390 exe.addObjectFile(cfg.dia_guids_lib);
391 }
392}
393
394fn addStaticLlvmOptionsToExe(
395 exe: *std.build.LibExeObjStep,
396) !void {
397 // Adds the Zig C++ sources which both stage1 and stage2 need.
398 //
399 // We need this because otherwise zig_clang_cc1_main.cpp ends up pulling
400 // in a dependency on llvm::cfg::Update<llvm::BasicBlock*>::dump() which is
401 // unavailable when LLVM is compiled in Release mode.
402 const zig_cpp_cflags = exe_cflags ++ [_][]const u8{"-DNDEBUG=1"};
403 exe.addCSourceFiles(&zig_cpp_sources, &zig_cpp_cflags);
404
405 for (clang_libs) |lib_name| {
406 exe.linkSystemLibrary(lib_name);
407 }
408
409 for (lld_libs) |lib_name| {
410 exe.linkSystemLibrary(lib_name);
411 }
412
413 for (llvm_libs) |lib_name| {
414 exe.linkSystemLibrary(lib_name);
415 }
416
417 exe.linkSystemLibrary("z");
418
419 // This means we rely on clang-or-zig-built LLVM, Clang, LLD libraries.
420 exe.linkSystemLibrary("c++");
421
422 if (exe.target.getOs().tag == .windows) {
423 exe.linkSystemLibrary("version");
424 exe.linkSystemLibrary("uuid");
425 exe.linkSystemLibrary("ole32");
426 }
427}
428
429fn addCxxKnownPath(
430 b: *Builder,
431 ctx: CMakeConfig,
432 exe: *std.build.LibExeObjStep,
433 objname: []const u8,
434 errtxt: ?[]const u8,
435 need_cpp_includes: bool,
436) !void {
437 const path_padded = try b.exec(&[_][]const u8{
438 ctx.cxx_compiler,
439 b.fmt("-print-file-name={s}", .{objname}),
440 });
441 const path_unpadded = mem.tokenize(u8, path_padded, "\r\n").next().?;
442 if (mem.eql(u8, path_unpadded, objname)) {
443 if (errtxt) |msg| {
444 std.debug.print("{s}", .{msg});
445 } else {
446 std.debug.print("Unable to determine path to {s}\n", .{objname});
447 }
448 return error.RequiredLibraryNotFound;
449 }
450 exe.addObjectFile(path_unpadded);
451
452 // TODO a way to integrate with system c++ include files here
453 // cc -E -Wp,-v -xc++ /dev/null
454 if (need_cpp_includes) {
455 // I used these temporarily for testing something but we obviously need a
456 // more general purpose solution here.
457 //exe.addIncludeDir("/nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/lib/gcc/x86_64-unknown-linux-gnu/9.3.0/../../../../include/c++/9.3.0");
458 //exe.addIncludeDir("/nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/lib/gcc/x86_64-unknown-linux-gnu/9.3.0/../../../../include/c++/9.3.0/x86_64-unknown-linux-gnu");
459 //exe.addIncludeDir("/nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/lib/gcc/x86_64-unknown-linux-gnu/9.3.0/../../../../include/c++/9.3.0/backward");
460 }
461}
462
463fn addCMakeLibraryList(exe: *std.build.LibExeObjStep, list: []const u8) void {
464 var it = mem.tokenize(u8, list, ";");
465 while (it.next()) |lib| {
466 if (mem.startsWith(u8, lib, "-l")) {
467 exe.linkSystemLibrary(lib["-l".len..]);
468 } else {
469 exe.addObjectFile(lib);
470 }
471 }
472}
473
474const CMakeConfig = struct {
475 cmake_binary_dir: []const u8,
476 cmake_prefix_path: []const u8,
477 cxx_compiler: []const u8,
478 lld_include_dir: []const u8,
479 lld_libraries: []const u8,
480 clang_libraries: []const u8,
481 llvm_libraries: []const u8,
482 dia_guids_lib: []const u8,
483};
484
485const max_config_h_bytes = 1 * 1024 * 1024;
486
487fn findAndParseConfigH(b: *Builder, config_h_path_option: ?[]const u8) ?CMakeConfig {
488 const config_h_text: []const u8 = if (config_h_path_option) |config_h_path| blk: {
489 break :blk fs.cwd().readFileAlloc(b.allocator, config_h_path, max_config_h_bytes) catch unreachable;
490 } else blk: {
491 // TODO this should stop looking for config.h once it detects we hit the
492 // zig source root directory.
493 var check_dir = fs.path.dirname(b.zig_exe).?;
494 while (true) {
495 var dir = fs.cwd().openDir(check_dir, .{}) catch unreachable;
496 defer dir.close();
497
498 break :blk dir.readFileAlloc(b.allocator, "config.h", max_config_h_bytes) catch |err| switch (err) {
499 error.FileNotFound => {
500 const new_check_dir = fs.path.dirname(check_dir);
501 if (new_check_dir == null or mem.eql(u8, new_check_dir.?, check_dir)) {
502 return null;
503 }
504 check_dir = new_check_dir.?;
505 continue;
506 },
507 else => unreachable,
508 };
509 } else unreachable; // TODO should not need `else unreachable`.
510 };
511
512 var ctx: CMakeConfig = .{
513 .cmake_binary_dir = undefined,
514 .cmake_prefix_path = undefined,
515 .cxx_compiler = undefined,
516 .lld_include_dir = undefined,
517 .lld_libraries = undefined,
518 .clang_libraries = undefined,
519 .llvm_libraries = undefined,
520 .dia_guids_lib = undefined,
521 };
522
523 const mappings = [_]struct { prefix: []const u8, field: []const u8 }{
524 .{
525 .prefix = "#define ZIG_CMAKE_BINARY_DIR ",
526 .field = "cmake_binary_dir",
527 },
528 .{
529 .prefix = "#define ZIG_CMAKE_PREFIX_PATH ",
530 .field = "cmake_prefix_path",
531 },
532 .{
533 .prefix = "#define ZIG_CXX_COMPILER ",
534 .field = "cxx_compiler",
535 },
536 .{
537 .prefix = "#define ZIG_LLD_INCLUDE_PATH ",
538 .field = "lld_include_dir",
539 },
540 .{
541 .prefix = "#define ZIG_LLD_LIBRARIES ",
542 .field = "lld_libraries",
543 },
544 .{
545 .prefix = "#define ZIG_CLANG_LIBRARIES ",
546 .field = "clang_libraries",
547 },
548 .{
549 .prefix = "#define ZIG_LLVM_LIBRARIES ",
550 .field = "llvm_libraries",
551 },
552 .{
553 .prefix = "#define ZIG_DIA_GUIDS_LIB ",
554 .field = "dia_guids_lib",
555 },
556 };
557
558 var lines_it = mem.tokenize(u8, config_h_text, "\r\n");
559 while (lines_it.next()) |line| {
560 inline for (mappings) |mapping| {
561 if (mem.startsWith(u8, line, mapping.prefix)) {
562 var it = mem.split(u8, line, "\"");
563 _ = it.next().?; // skip the stuff before the quote
564 const quoted = it.next().?; // the stuff inside the quote
565 @field(ctx, mapping.field) = toNativePathSep(b, quoted);
566 }
567 }
568 }
569 return ctx;
570}
571
572fn toNativePathSep(b: *Builder, s: []const u8) []u8 {
573 const duplicated = b.allocator.dupe(u8, s) catch unreachable;
574 for (duplicated) |*byte| switch (byte.*) {
575 '/' => byte.* = fs.path.sep,
576 else => {},
577 };
578 return duplicated;
579}
580
581const softfloat_sources = [_][]const u8{
582 "deps/SoftFloat-3e/source/8086/f128M_isSignalingNaN.c",
583 "deps/SoftFloat-3e/source/8086/extF80M_isSignalingNaN.c",
584 "deps/SoftFloat-3e/source/8086/s_commonNaNToF128M.c",
585 "deps/SoftFloat-3e/source/8086/s_commonNaNToExtF80M.c",
586 "deps/SoftFloat-3e/source/8086/s_commonNaNToF16UI.c",
587 "deps/SoftFloat-3e/source/8086/s_commonNaNToF32UI.c",
588 "deps/SoftFloat-3e/source/8086/s_commonNaNToF64UI.c",
589 "deps/SoftFloat-3e/source/8086/s_f128MToCommonNaN.c",
590 "deps/SoftFloat-3e/source/8086/s_extF80MToCommonNaN.c",
591 "deps/SoftFloat-3e/source/8086/s_f16UIToCommonNaN.c",
592 "deps/SoftFloat-3e/source/8086/s_f32UIToCommonNaN.c",
593 "deps/SoftFloat-3e/source/8086/s_f64UIToCommonNaN.c",
594 "deps/SoftFloat-3e/source/8086/s_propagateNaNF128M.c",
595 "deps/SoftFloat-3e/source/8086/s_propagateNaNExtF80M.c",
596 "deps/SoftFloat-3e/source/8086/s_propagateNaNF16UI.c",
597 "deps/SoftFloat-3e/source/8086/softfloat_raiseFlags.c",
598 "deps/SoftFloat-3e/source/f128M_add.c",
599 "deps/SoftFloat-3e/source/f128M_div.c",
600 "deps/SoftFloat-3e/source/f128M_eq.c",
601 "deps/SoftFloat-3e/source/f128M_eq_signaling.c",
602 "deps/SoftFloat-3e/source/f128M_le.c",
603 "deps/SoftFloat-3e/source/f128M_le_quiet.c",
604 "deps/SoftFloat-3e/source/f128M_lt.c",
605 "deps/SoftFloat-3e/source/f128M_lt_quiet.c",
606 "deps/SoftFloat-3e/source/f128M_mul.c",
607 "deps/SoftFloat-3e/source/f128M_mulAdd.c",
608 "deps/SoftFloat-3e/source/f128M_rem.c",
609 "deps/SoftFloat-3e/source/f128M_roundToInt.c",
610 "deps/SoftFloat-3e/source/f128M_sqrt.c",
611 "deps/SoftFloat-3e/source/f128M_sub.c",
612 "deps/SoftFloat-3e/source/f128M_to_f16.c",
613 "deps/SoftFloat-3e/source/f128M_to_f32.c",
614 "deps/SoftFloat-3e/source/f128M_to_f64.c",
615 "deps/SoftFloat-3e/source/f128M_to_extF80M.c",
616 "deps/SoftFloat-3e/source/f128M_to_i32.c",
617 "deps/SoftFloat-3e/source/f128M_to_i32_r_minMag.c",
618 "deps/SoftFloat-3e/source/f128M_to_i64.c",
619 "deps/SoftFloat-3e/source/f128M_to_i64_r_minMag.c",
620 "deps/SoftFloat-3e/source/f128M_to_ui32.c",
621 "deps/SoftFloat-3e/source/f128M_to_ui32_r_minMag.c",
622 "deps/SoftFloat-3e/source/f128M_to_ui64.c",
623 "deps/SoftFloat-3e/source/f128M_to_ui64_r_minMag.c",
624 "deps/SoftFloat-3e/source/extF80M_add.c",
625 "deps/SoftFloat-3e/source/extF80M_div.c",
626 "deps/SoftFloat-3e/source/extF80M_eq.c",
627 "deps/SoftFloat-3e/source/extF80M_le.c",
628 "deps/SoftFloat-3e/source/extF80M_lt.c",
629 "deps/SoftFloat-3e/source/extF80M_mul.c",
630 "deps/SoftFloat-3e/source/extF80M_rem.c",
631 "deps/SoftFloat-3e/source/extF80M_roundToInt.c",
632 "deps/SoftFloat-3e/source/extF80M_sqrt.c",
633 "deps/SoftFloat-3e/source/extF80M_sub.c",
634 "deps/SoftFloat-3e/source/extF80M_to_f16.c",
635 "deps/SoftFloat-3e/source/extF80M_to_f32.c",
636 "deps/SoftFloat-3e/source/extF80M_to_f64.c",
637 "deps/SoftFloat-3e/source/extF80M_to_f128M.c",
638 "deps/SoftFloat-3e/source/f16_add.c",
639 "deps/SoftFloat-3e/source/f16_div.c",
640 "deps/SoftFloat-3e/source/f16_eq.c",
641 "deps/SoftFloat-3e/source/f16_isSignalingNaN.c",
642 "deps/SoftFloat-3e/source/f16_lt.c",
643 "deps/SoftFloat-3e/source/f16_mul.c",
644 "deps/SoftFloat-3e/source/f16_mulAdd.c",
645 "deps/SoftFloat-3e/source/f16_rem.c",
646 "deps/SoftFloat-3e/source/f16_roundToInt.c",
647 "deps/SoftFloat-3e/source/f16_sqrt.c",
648 "deps/SoftFloat-3e/source/f16_sub.c",
649 "deps/SoftFloat-3e/source/f16_to_extF80M.c",
650 "deps/SoftFloat-3e/source/f16_to_f128M.c",
651 "deps/SoftFloat-3e/source/f16_to_f64.c",
652 "deps/SoftFloat-3e/source/f32_to_extF80M.c",
653 "deps/SoftFloat-3e/source/f32_to_f128M.c",
654 "deps/SoftFloat-3e/source/f64_to_extF80M.c",
655 "deps/SoftFloat-3e/source/f64_to_f128M.c",
656 "deps/SoftFloat-3e/source/f64_to_f16.c",
657 "deps/SoftFloat-3e/source/i32_to_f128M.c",
658 "deps/SoftFloat-3e/source/s_add256M.c",
659 "deps/SoftFloat-3e/source/s_addCarryM.c",
660 "deps/SoftFloat-3e/source/s_addComplCarryM.c",
661 "deps/SoftFloat-3e/source/s_addF128M.c",
662 "deps/SoftFloat-3e/source/s_addExtF80M.c",
663 "deps/SoftFloat-3e/source/s_addM.c",
664 "deps/SoftFloat-3e/source/s_addMagsF16.c",
665 "deps/SoftFloat-3e/source/s_addMagsF32.c",
666 "deps/SoftFloat-3e/source/s_addMagsF64.c",
667 "deps/SoftFloat-3e/source/s_approxRecip32_1.c",
668 "deps/SoftFloat-3e/source/s_approxRecipSqrt32_1.c",
669 "deps/SoftFloat-3e/source/s_approxRecipSqrt_1Ks.c",
670 "deps/SoftFloat-3e/source/s_approxRecip_1Ks.c",
671 "deps/SoftFloat-3e/source/s_compare128M.c",
672 "deps/SoftFloat-3e/source/s_compare96M.c",
673 "deps/SoftFloat-3e/source/s_compareNonnormExtF80M.c",
674 "deps/SoftFloat-3e/source/s_countLeadingZeros16.c",
675 "deps/SoftFloat-3e/source/s_countLeadingZeros32.c",
676 "deps/SoftFloat-3e/source/s_countLeadingZeros64.c",
677 "deps/SoftFloat-3e/source/s_countLeadingZeros8.c",
678 "deps/SoftFloat-3e/source/s_eq128.c",
679 "deps/SoftFloat-3e/source/s_invalidF128M.c",
680 "deps/SoftFloat-3e/source/s_invalidExtF80M.c",
681 "deps/SoftFloat-3e/source/s_isNaNF128M.c",
682 "deps/SoftFloat-3e/source/s_le128.c",
683 "deps/SoftFloat-3e/source/s_lt128.c",
684 "deps/SoftFloat-3e/source/s_mul128MTo256M.c",
685 "deps/SoftFloat-3e/source/s_mul64To128M.c",
686 "deps/SoftFloat-3e/source/s_mulAddF128M.c",
687 "deps/SoftFloat-3e/source/s_mulAddF16.c",
688 "deps/SoftFloat-3e/source/s_mulAddF32.c",
689 "deps/SoftFloat-3e/source/s_mulAddF64.c",
690 "deps/SoftFloat-3e/source/s_negXM.c",
691 "deps/SoftFloat-3e/source/s_normExtF80SigM.c",
692 "deps/SoftFloat-3e/source/s_normRoundPackMToF128M.c",
693 "deps/SoftFloat-3e/source/s_normRoundPackMToExtF80M.c",
694 "deps/SoftFloat-3e/source/s_normRoundPackToF16.c",
695 "deps/SoftFloat-3e/source/s_normRoundPackToF32.c",
696 "deps/SoftFloat-3e/source/s_normRoundPackToF64.c",
697 "deps/SoftFloat-3e/source/s_normSubnormalF128SigM.c",
698 "deps/SoftFloat-3e/source/s_normSubnormalF16Sig.c",
699 "deps/SoftFloat-3e/source/s_normSubnormalF32Sig.c",
700 "deps/SoftFloat-3e/source/s_normSubnormalF64Sig.c",
701 "deps/SoftFloat-3e/source/s_remStepMBy32.c",
702 "deps/SoftFloat-3e/source/s_roundMToI64.c",
703 "deps/SoftFloat-3e/source/s_roundMToUI64.c",
704 "deps/SoftFloat-3e/source/s_roundPackMToExtF80M.c",
705 "deps/SoftFloat-3e/source/s_roundPackMToF128M.c",
706 "deps/SoftFloat-3e/source/s_roundPackToF16.c",
707 "deps/SoftFloat-3e/source/s_roundPackToF32.c",
708 "deps/SoftFloat-3e/source/s_roundPackToF64.c",
709 "deps/SoftFloat-3e/source/s_roundToI32.c",
710 "deps/SoftFloat-3e/source/s_roundToI64.c",
711 "deps/SoftFloat-3e/source/s_roundToUI32.c",
712 "deps/SoftFloat-3e/source/s_roundToUI64.c",
713 "deps/SoftFloat-3e/source/s_shiftLeftM.c",
714 "deps/SoftFloat-3e/source/s_shiftNormSigF128M.c",
715 "deps/SoftFloat-3e/source/s_shiftRightJam256M.c",
716 "deps/SoftFloat-3e/source/s_shiftRightJam32.c",
717 "deps/SoftFloat-3e/source/s_shiftRightJam64.c",
718 "deps/SoftFloat-3e/source/s_shiftRightJamM.c",
719 "deps/SoftFloat-3e/source/s_shiftRightM.c",
720 "deps/SoftFloat-3e/source/s_shortShiftLeft64To96M.c",
721 "deps/SoftFloat-3e/source/s_shortShiftLeftM.c",
722 "deps/SoftFloat-3e/source/s_shortShiftRightExtendM.c",
723 "deps/SoftFloat-3e/source/s_shortShiftRightJam64.c",
724 "deps/SoftFloat-3e/source/s_shortShiftRightJamM.c",
725 "deps/SoftFloat-3e/source/s_shortShiftRightM.c",
726 "deps/SoftFloat-3e/source/s_sub1XM.c",
727 "deps/SoftFloat-3e/source/s_sub256M.c",
728 "deps/SoftFloat-3e/source/s_subM.c",
729 "deps/SoftFloat-3e/source/s_subMagsF16.c",
730 "deps/SoftFloat-3e/source/s_subMagsF32.c",
731 "deps/SoftFloat-3e/source/s_subMagsF64.c",
732 "deps/SoftFloat-3e/source/s_tryPropagateNaNF128M.c",
733 "deps/SoftFloat-3e/source/s_tryPropagateNaNExtF80M.c",
734 "deps/SoftFloat-3e/source/softfloat_state.c",
735 "deps/SoftFloat-3e/source/ui32_to_f128M.c",
736 "deps/SoftFloat-3e/source/ui64_to_f128M.c",
737 "deps/SoftFloat-3e/source/ui32_to_extF80M.c",
738 "deps/SoftFloat-3e/source/ui64_to_extF80M.c",
739};
740
741const stage1_sources = [_][]const u8{
742 "src/stage1/analyze.cpp",
743 "src/stage1/astgen.cpp",
744 "src/stage1/bigfloat.cpp",
745 "src/stage1/bigint.cpp",
746 "src/stage1/buffer.cpp",
747 "src/stage1/codegen.cpp",
748 "src/stage1/errmsg.cpp",
749 "src/stage1/error.cpp",
750 "src/stage1/heap.cpp",
751 "src/stage1/ir.cpp",
752 "src/stage1/ir_print.cpp",
753 "src/stage1/mem.cpp",
754 "src/stage1/os.cpp",
755 "src/stage1/parser.cpp",
756 "src/stage1/range_set.cpp",
757 "src/stage1/stage1.cpp",
758 "src/stage1/target.cpp",
759 "src/stage1/tokenizer.cpp",
760 "src/stage1/util.cpp",
761 "src/stage1/softfloat_ext.cpp",
762};
763const optimized_c_sources = [_][]const u8{
764 "src/stage1/parse_f128.c",
765};
766const zig_cpp_sources = [_][]const u8{
767 // These are planned to stay even when we are self-hosted.
768 "src/zig_llvm.cpp",
769 "src/zig_clang.cpp",
770 "src/zig_llvm-ar.cpp",
771 "src/zig_clang_driver.cpp",
772 "src/zig_clang_cc1_main.cpp",
773 "src/zig_clang_cc1as_main.cpp",
774 // https://github.com/ziglang/zig/issues/6363
775 "src/windows_sdk.cpp",
776};
777
778const clang_libs = [_][]const u8{
779 "clangFrontendTool",
780 "clangCodeGen",
781 "clangFrontend",
782 "clangDriver",
783 "clangSerialization",
784 "clangSema",
785 "clangStaticAnalyzerFrontend",
786 "clangStaticAnalyzerCheckers",
787 "clangStaticAnalyzerCore",
788 "clangAnalysis",
789 "clangASTMatchers",
790 "clangAST",
791 "clangParse",
792 "clangSema",
793 "clangBasic",
794 "clangEdit",
795 "clangLex",
796 "clangARCMigrate",
797 "clangRewriteFrontend",
798 "clangRewrite",
799 "clangCrossTU",
800 "clangIndex",
801 "clangToolingCore",
802};
803const lld_libs = [_][]const u8{
804 "lldMinGW",
805 "lldELF",
806 "lldCOFF",
807 "lldWasm",
808 "lldMachO",
809 "lldCommon",
810};
811// This list can be re-generated with `llvm-config --libfiles` and then
812// reformatting using your favorite text editor. Note we do not execute
813// `llvm-config` here because we are cross compiling. Also omit LLVMTableGen
814// from these libs.
815const llvm_libs = [_][]const u8{
816 "LLVMWindowsManifest",
817 "LLVMXRay",
818 "LLVMLibDriver",
819 "LLVMDlltoolDriver",
820 "LLVMCoverage",
821 "LLVMLineEditor",
822 "LLVMXCoreDisassembler",
823 "LLVMXCoreCodeGen",
824 "LLVMXCoreDesc",
825 "LLVMXCoreInfo",
826 "LLVMX86TargetMCA",
827 "LLVMX86Disassembler",
828 "LLVMX86AsmParser",
829 "LLVMX86CodeGen",
830 "LLVMX86Desc",
831 "LLVMX86Info",
832 "LLVMWebAssemblyDisassembler",
833 "LLVMWebAssemblyAsmParser",
834 "LLVMWebAssemblyCodeGen",
835 "LLVMWebAssemblyDesc",
836 "LLVMWebAssemblyUtils",
837 "LLVMWebAssemblyInfo",
838 "LLVMVEDisassembler",
839 "LLVMVEAsmParser",
840 "LLVMVECodeGen",
841 "LLVMVEDesc",
842 "LLVMVEInfo",
843 "LLVMSystemZDisassembler",
844 "LLVMSystemZAsmParser",
845 "LLVMSystemZCodeGen",
846 "LLVMSystemZDesc",
847 "LLVMSystemZInfo",
848 "LLVMSparcDisassembler",
849 "LLVMSparcAsmParser",
850 "LLVMSparcCodeGen",
851 "LLVMSparcDesc",
852 "LLVMSparcInfo",
853 "LLVMRISCVDisassembler",
854 "LLVMRISCVAsmParser",
855 "LLVMRISCVCodeGen",
856 "LLVMRISCVDesc",
857 "LLVMRISCVInfo",
858 "LLVMPowerPCDisassembler",
859 "LLVMPowerPCAsmParser",
860 "LLVMPowerPCCodeGen",
861 "LLVMPowerPCDesc",
862 "LLVMPowerPCInfo",
863 "LLVMNVPTXCodeGen",
864 "LLVMNVPTXDesc",
865 "LLVMNVPTXInfo",
866 "LLVMMSP430Disassembler",
867 "LLVMMSP430AsmParser",
868 "LLVMMSP430CodeGen",
869 "LLVMMSP430Desc",
870 "LLVMMSP430Info",
871 "LLVMMipsDisassembler",
872 "LLVMMipsAsmParser",
873 "LLVMMipsCodeGen",
874 "LLVMMipsDesc",
875 "LLVMMipsInfo",
876 "LLVMLanaiDisassembler",
877 "LLVMLanaiCodeGen",
878 "LLVMLanaiAsmParser",
879 "LLVMLanaiDesc",
880 "LLVMLanaiInfo",
881 "LLVMHexagonDisassembler",
882 "LLVMHexagonCodeGen",
883 "LLVMHexagonAsmParser",
884 "LLVMHexagonDesc",
885 "LLVMHexagonInfo",
886 "LLVMBPFDisassembler",
887 "LLVMBPFAsmParser",
888 "LLVMBPFCodeGen",
889 "LLVMBPFDesc",
890 "LLVMBPFInfo",
891 "LLVMAVRDisassembler",
892 "LLVMAVRAsmParser",
893 "LLVMAVRCodeGen",
894 "LLVMAVRDesc",
895 "LLVMAVRInfo",
896 "LLVMARMDisassembler",
897 "LLVMARMAsmParser",
898 "LLVMARMCodeGen",
899 "LLVMARMDesc",
900 "LLVMARMUtils",
901 "LLVMARMInfo",
902 "LLVMAMDGPUTargetMCA",
903 "LLVMAMDGPUDisassembler",
904 "LLVMAMDGPUAsmParser",
905 "LLVMAMDGPUCodeGen",
906 "LLVMAMDGPUDesc",
907 "LLVMAMDGPUUtils",
908 "LLVMAMDGPUInfo",
909 "LLVMAArch64Disassembler",
910 "LLVMAArch64AsmParser",
911 "LLVMAArch64CodeGen",
912 "LLVMAArch64Desc",
913 "LLVMAArch64Utils",
914 "LLVMAArch64Info",
915 "LLVMOrcJIT",
916 "LLVMMCJIT",
917 "LLVMJITLink",
918 "LLVMInterpreter",
919 "LLVMExecutionEngine",
920 "LLVMRuntimeDyld",
921 "LLVMOrcTargetProcess",
922 "LLVMOrcShared",
923 "LLVMDWP",
924 "LLVMSymbolize",
925 "LLVMDebugInfoPDB",
926 "LLVMDebugInfoGSYM",
927 "LLVMOption",
928 "LLVMObjectYAML",
929 "LLVMMCA",
930 "LLVMMCDisassembler",
931 "LLVMLTO",
932 "LLVMPasses",
933 "LLVMCFGuard",
934 "LLVMCoroutines",
935 "LLVMObjCARCOpts",
936 "LLVMipo",
937 "LLVMVectorize",
938 "LLVMLinker",
939 "LLVMInstrumentation",
940 "LLVMFrontendOpenMP",
941 "LLVMFrontendOpenACC",
942 "LLVMExtensions",
943 "LLVMDWARFLinker",
944 "LLVMGlobalISel",
945 "LLVMMIRParser",
946 "LLVMAsmPrinter",
947 "LLVMDebugInfoMSF",
948 "LLVMSelectionDAG",
949 "LLVMCodeGen",
950 "LLVMIRReader",
951 "LLVMAsmParser",
952 "LLVMInterfaceStub",
953 "LLVMFileCheck",
954 "LLVMFuzzMutate",
955 "LLVMTarget",
956 "LLVMScalarOpts",
957 "LLVMInstCombine",
958 "LLVMAggressiveInstCombine",
959 "LLVMTransformUtils",
960 "LLVMBitWriter",
961 "LLVMAnalysis",
962 "LLVMProfileData",
963 "LLVMDebugInfoDWARF",
964 "LLVMObject",
965 "LLVMTextAPI",
966 "LLVMMCParser",
967 "LLVMMC",
968 "LLVMDebugInfoCodeView",
969 "LLVMBitReader",
970 "LLVMCore",
971 "LLVMRemarks",
972 "LLVMBitstreamReader",
973 "LLVMBinaryFormat",
974 "LLVMSupport",
975 "LLVMDemangle",
976};
ci/azure/macos_arm64_script deleted-132
...@@ -1,132 +0,0 @@
1#!/bin/sh
2
3set -x
4set -e
5
6brew update && brew install ncurses s3cmd
7
8ZIGDIR="$(pwd)"
9
10HOST_ARCH="x86_64"
11HOST_TARGET="$HOST_ARCH-macos-none"
12HOST_MCPU="baseline"
13HOST_CACHE_BASENAME="zig+llvm+lld+clang-$HOST_TARGET-0.10.0-dev.2931+bdf3fa12f"
14HOST_PREFIX="$HOME/$HOST_CACHE_BASENAME"
15
16ARCH="aarch64"
17TARGET="$ARCH-macos-none"
18MCPU="apple_a14"
19CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.10.0-dev.2931+bdf3fa12f"
20PREFIX="$HOME/$CACHE_BASENAME"
21
22JOBS="-j2"
23
24rm -rf $HOST_PREFIX $PREFIX
25cd $HOME
26
27wget -nv "https://ziglang.org/deps/$HOST_CACHE_BASENAME.tar.xz"
28wget -nv "https://ziglang.org/deps/$CACHE_BASENAME.tar.xz"
29tar xf "$HOST_CACHE_BASENAME.tar.xz"
30tar xf "$CACHE_BASENAME.tar.xz"
31
32cd $ZIGDIR
33
34# Make the `zig version` number consistent.
35# This will affect the cmake command below.
36git config core.abbrev 9
37git fetch --unshallow || true
38git fetch --tags
39
40# Build host zig compiler in debug so that we can get the
41# current version when packaging
42
43ZIG="$HOST_PREFIX/bin/zig"
44
45export CC="$ZIG cc -target $HOST_TARGET -mcpu=$HOST_MCPU"
46export CXX="$ZIG c++ -target $HOST_TARGET -mcpu=$HOST_MCPU"
47
48mkdir build.host
49cd build.host
50cmake .. \
51 -DCMAKE_INSTALL_PREFIX="$(pwd)/release" \
52 -DCMAKE_PREFIX_PATH="$HOST_PREFIX" \
53 -DCMAKE_BUILD_TYPE=Release \
54 -DZIG_TARGET_TRIPLE="$HOST_TARGET" \
55 -DZIG_TARGET_MCPU="$HOST_MCPU" \
56 -DZIG_STATIC=ON \
57 -DZIG_OMIT_STAGE2=ON
58
59unset CC
60unset CXX
61
62make $JOBS install
63
64# Build zig compiler cross-compiled for arm64
65cd $ZIGDIR
66
67ZIG="$ZIGDIR/build.host/release/bin/zig"
68
69export CC="$ZIG cc -target $TARGET -mcpu=$MCPU"
70export CXX="$ZIG c++ -target $TARGET -mcpu=$MCPU"
71
72mkdir build
73cd build
74cmake .. \
75 -DCMAKE_INSTALL_PREFIX="$(pwd)/release" \
76 -DCMAKE_PREFIX_PATH="$PREFIX" \
77 -DCMAKE_BUILD_TYPE=Release \
78 -DZIG_TARGET_TRIPLE="$TARGET" \
79 -DZIG_TARGET_MCPU="$MCPU" \
80 -DZIG_EXECUTABLE="$ZIG" \
81 -DZIG_STATIC=ON
82
83unset CC
84unset CXX
85
86make $JOBS install
87
88if [ "${BUILD_REASON}" != "PullRequest" ]; then
89 mv ../LICENSE release/
90
91 # We do not run test suite but still need langref.
92 mkdir -p release/docs
93 $ZIG run ../doc/docgen.zig -- $ZIG ../doc/langref.html.in release/docs/langref.html
94
95 # Produce the experimental std lib documentation.
96 mkdir -p release/docs/std
97 $ZIG test ../lib/std/std.zig \
98 --zig-lib-dir ../lib \
99 -femit-docs=release/docs/std \
100 -fno-emit-bin
101
102 mv release/bin/zig release/
103 rmdir release/bin
104
105 VERSION=$(../build.host/release/bin/zig version)
106 DIRNAME="zig-macos-$ARCH-$VERSION"
107 TARBALL="$DIRNAME.tar.xz"
108 mv release "$DIRNAME"
109 tar cfJ "$TARBALL" "$DIRNAME"
110
111 mv "$DOWNLOADSECUREFILE_SECUREFILEPATH" "$HOME/.s3cfg"
112 s3cmd put -P --add-header="cache-control: public, max-age=31536000, immutable" "$TARBALL" s3://ziglang.org/builds/
113
114 SHASUM=$(shasum -a 256 $TARBALL | cut '-d ' -f1)
115 BYTESIZE=$(wc -c < $TARBALL)
116
117 JSONFILE="macos-$GITBRANCH.json"
118 touch $JSONFILE
119 echo "{\"tarball\": \"$TARBALL\"," >>$JSONFILE
120 echo "\"shasum\": \"$SHASUM\"," >>$JSONFILE
121 echo "\"size\": \"$BYTESIZE\"}" >>$JSONFILE
122
123 s3cmd put -P --add-header="Cache-Control: max-age=0, must-revalidate" "$JSONFILE" "s3://ziglang.org/builds/$JSONFILE"
124 s3cmd put -P "$JSONFILE" "s3://ziglang.org/builds/$ARCH-macos-$VERSION.json"
125
126 # `set -x` causes these variables to be mangled.
127 # See https://developercommunity.visualstudio.com/content/problem/375679/pipeline-variable-incorrectly-inserts-single-quote.html
128 set +x
129 echo "##vso[task.setvariable variable=tarball;isOutput=true]$TARBALL"
130 echo "##vso[task.setvariable variable=shasum;isOutput=true]$SHASUM"
131 echo "##vso[task.setvariable variable=bytesize;isOutput=true]$BYTESIZE"
132fi
ci/azure/macos_script+12-37
...@@ -34,13 +34,12 @@ git fetch --tags...@@ -34,13 +34,12 @@ git fetch --tags
34mkdir build34mkdir build
35cd build35cd build
36cmake .. \36cmake .. \
37 -DCMAKE_INSTALL_PREFIX="$(pwd)/release" \37 -DCMAKE_INSTALL_PREFIX="stage3-release" \
38 -DCMAKE_PREFIX_PATH="$PREFIX" \38 -DCMAKE_PREFIX_PATH="$PREFIX" \
39 -DCMAKE_BUILD_TYPE=Release \39 -DCMAKE_BUILD_TYPE=Release \
40 -DZIG_TARGET_TRIPLE="$TARGET" \40 -DZIG_TARGET_TRIPLE="$TARGET" \
41 -DZIG_TARGET_MCPU="$MCPU" \41 -DZIG_TARGET_MCPU="$MCPU" \
42 -DZIG_STATIC=ON \42 -DZIG_STATIC=ON
43 -DZIG_OMIT_STAGE2=ON
4443
45# Now cmake will use zig as the C/C++ compiler. We reset the environment variables44# Now cmake will use zig as the C/C++ compiler. We reset the environment variables
46# so that installation and testing do not get affected by them.45# so that installation and testing do not get affected by them.
...@@ -49,45 +48,21 @@ unset CXX...@@ -49,45 +48,21 @@ unset CXX
4948
50make $JOBS install49make $JOBS install
5150
52# Here we rebuild zig but this time using the Zig binary we just now produced to51stage3-release/bin/zig build test docs \
53# build zig1.o rather than relying on the one built with stage0. See52 -Denable-macos-sdk \
54# https://github.com/ziglang/zig/issues/6830 for more details.53 -Dstatic-llvm \
55cmake .. -DZIG_EXECUTABLE="$(pwd)/release/bin/zig"54 --search-prefix "$PREFIX"
56make $JOBS install
57
58# Build stage2 standalone so that we can test stage2 against stage2 compiler-rt.
59release/bin/zig build -p stage2 -Denable-llvm
60
61stage2/bin/zig build test-behavior
62
63# TODO: upgrade these to test stage2 instead of stage1
64# TODO: upgrade these to test stage3 instead of stage2
65release/bin/zig build test-behavior -Denable-macos-sdk -Domit-stage2
66release/bin/zig build test-compiler-rt -Denable-macos-sdk
67release/bin/zig build test-std -Denable-macos-sdk
68release/bin/zig build test-universal-libc -Denable-macos-sdk
69release/bin/zig build test-compare-output -Denable-macos-sdk
70release/bin/zig build test-standalone -Denable-macos-sdk
71release/bin/zig build test-stack-traces -Denable-macos-sdk
72release/bin/zig build test-cli -Denable-macos-sdk
73release/bin/zig build test-asm-link -Denable-macos-sdk
74release/bin/zig build test-translate-c -Denable-macos-sdk
75release/bin/zig build test-run-translated-c -Denable-macos-sdk
76release/bin/zig build docs -Denable-macos-sdk
77release/bin/zig build test-fmt -Denable-macos-sdk
78release/bin/zig build test-cases -Denable-macos-sdk -Dsingle-threaded
79release/bin/zig build test-link -Denable-macos-sdk -Domit-stage2
8055
81if [ "${BUILD_REASON}" != "PullRequest" ]; then56if [ "${BUILD_REASON}" != "PullRequest" ]; then
82 mv ../LICENSE release/57 mv ../LICENSE stage3-release/
83 mv ../zig-cache/langref.html release/58 mv ../zig-cache/langref.html stage3-release/
84 mv release/bin/zig release/59 mv stage3-release/bin/zig stage3-release/
85 rmdir release/bin60 rmdir stage3-release/bin
8661
87 VERSION=$(release/zig version)62 VERSION=$(stage3-release/zig version)
88 DIRNAME="zig-macos-$ARCH-$VERSION"63 DIRNAME="zig-macos-$ARCH-$VERSION"
89 TARBALL="$DIRNAME.tar.xz"64 TARBALL="$DIRNAME.tar.xz"
90 mv release "$DIRNAME"65 mv stage3-release "$DIRNAME"
91 tar cfJ "$TARBALL" "$DIRNAME"66 tar cfJ "$TARBALL" "$DIRNAME"
9267
93 mv "$DOWNLOADSECUREFILE_SECUREFILEPATH" "$HOME/.s3cfg"68 mv "$DOWNLOADSECUREFILE_SECUREFILEPATH" "$HOME/.s3cfg"
ci/azure/pipelines.yml+36-61
...@@ -10,24 +10,13 @@ jobs:...@@ -10,24 +10,13 @@ jobs:
10 - script: ci/azure/macos_script10 - script: ci/azure/macos_script
11 name: main11 name: main
12 displayName: 'Build and test'12 displayName: 'Build and test'
13- job: BuildMacOS_arm64
14 pool:
15 vmImage: 'macOS-11'
16 timeoutInMinutes: 180
17 steps:
18 - task: DownloadSecureFile@1
19 inputs:
20 secureFile: s3cfg
21 - script: ci/azure/macos_arm64_script
22 name: main
23 displayName: 'Build'
24- job: BuildWindows13- job: BuildWindows
25 timeoutInMinutes: 36014 timeoutInMinutes: 360
26 pool:15 pool:
27 vmImage: 'windows-2019'16 vmImage: 'windows-2019'
28 variables:17 variables:
29 TARGET: 'x86_64-windows-gnu'18 TARGET: 'x86_64-windows-gnu'
30 ZIG_LLVM_CLANG_LLD_NAME: 'zig+llvm+lld+clang-${{ variables.TARGET }}-0.10.0-dev.2931+bdf3fa12f'19 ZIG_LLVM_CLANG_LLD_NAME: 'zig+llvm+lld+clang-${{ variables.TARGET }}-0.10.0-dev.3733+a9af47272'
31 ZIG_LLVM_CLANG_LLD_URL: 'https://ziglang.org/deps/${{ variables.ZIG_LLVM_CLANG_LLD_NAME }}.zip'20 ZIG_LLVM_CLANG_LLD_URL: 'https://ziglang.org/deps/${{ variables.ZIG_LLVM_CLANG_LLD_NAME }}.zip'
32 steps:21 steps:
33 - pwsh: |22 - pwsh: |
...@@ -37,10 +26,17 @@ jobs:...@@ -37,10 +26,17 @@ jobs:
37 displayName: 'Install ZIG/LLVM/CLANG/LLD'26 displayName: 'Install ZIG/LLVM/CLANG/LLD'
3827
39 - pwsh: |28 - pwsh: |
40 Set-Variable -Name ZIGBUILDDIR -Value "$(Get-Location)\build"29 Set-Variable -Name ZIGLIBDIR -Value "$(Get-Location)\lib"
41 Set-Variable -Name ZIGINSTALLDIR -Value "${ZIGBUILDDIR}\dist"30 Set-Variable -Name ZIGINSTALLDIR -Value "$(Get-Location)\stage3-release"
42 Set-Variable -Name ZIGPREFIXPATH -Value "$(Get-Location)\$(ZIG_LLVM_CLANG_LLD_NAME)"31 Set-Variable -Name ZIGPREFIXPATH -Value "$(Get-Location)\$(ZIG_LLVM_CLANG_LLD_NAME)"
4332
33 function CheckLastExitCode {
34 if (!$?) {
35 exit 1
36 }
37 return 0
38 }
39
44 # Make the `zig version` number consistent.40 # Make the `zig version` number consistent.
45 # This will affect the `zig build` command below which uses `git describe`.41 # This will affect the `zig build` command below which uses `git describe`.
46 git config core.abbrev 942 git config core.abbrev 9
...@@ -49,64 +45,45 @@ jobs:...@@ -49,64 +45,45 @@ jobs:
49 git fetch --unshallow # `git describe` won't work on a shallow repo45 git fetch --unshallow # `git describe` won't work on a shallow repo
50 }46 }
5147
52 # The dev kit zip file that we have here is old, and may be incompatible with48 & "$ZIGPREFIXPATH\bin\zig.exe" build `
53 # the build.zig script of master branch. So we keep an old version of build.zig
54 # here in the CI directory.
55 mv build.zig build.zig.master
56 mv ci/azure/build.zig build.zig
57
58 mkdir $ZIGBUILDDIR
59 cd $ZIGBUILDDIR
60
61 & "${ZIGPREFIXPATH}/bin/zig.exe" build `
62 --prefix "$ZIGINSTALLDIR" `49 --prefix "$ZIGINSTALLDIR" `
63 --search-prefix "$ZIGPREFIXPATH" `50 --search-prefix "$ZIGPREFIXPATH" `
64 -Dstage1 `51 --zig-lib-dir "$ZIGLIBDIR" `
65 <# stage2 is omitted until we resolve https://github.com/ziglang/zig/issues/6485 #> `52 -Denable-stage1 `
66 -Domit-stage2 `
67 -Dstatic-llvm `53 -Dstatic-llvm `
68 -Drelease `54 -Drelease `
69 -Dstrip `55 -Dstrip `
70 -Duse-zig-libcxx `56 -Duse-zig-libcxx `
71 -Dtarget=$(TARGET)57 -Dtarget=$(TARGET)
7258 CheckLastExitCode
73 cd -
74
75 # Now that we have built an up-to-date zig.exe, we restore the original
76 # build script from master branch.
77 rm build.zig
78 mv build.zig.master build.zig
79
80 name: build59 name: build
81 displayName: 'Build'60 displayName: 'Build'
8261
83 - pwsh: |62 - pwsh: |
84 Set-Variable -Name ZIGINSTALLDIR -Value "$(Get-Location)\build\dist"63 Set-Variable -Name ZIGINSTALLDIR -Value "$(Get-Location)\stage3-release"
8564
86 # Sadly, stage2 is omitted from this build to save memory on the CI server. Once self-hosted is65 function CheckLastExitCode {
87 # built with itself and does not gobble as much memory, we can enable these tests.66 if (!$?) {
88 #& "$ZIGINSTALLDIR\bin\zig.exe" test "..\test\behavior.zig" -fno-stage1 -fLLVM -I "..\test" 2>&167 exit 1
68 }
69 return 0
70 }
8971
90 & "$ZIGINSTALLDIR\bin\zig.exe" build test-toolchain -Dskip-non-native -Dskip-stage2-tests 2>&172 & "$ZIGINSTALLDIR\bin\zig.exe" build test docs `
91 & "$ZIGINSTALLDIR\bin\zig.exe" build test-std -Dskip-non-native 2>&173 --search-prefix "$ZIGPREFIXPATH" `
74 -Dstatic-llvm `
75 -Dskip-non-native `
76 -Dskip-stage2-tests
77 CheckLastExitCode
92 name: test78 name: test
93 displayName: 'Test'79 displayName: 'Test'
9480
95 - pwsh: |
96 Set-Variable -Name ZIGINSTALLDIR -Value "$(Get-Location)\build\dist"
97
98 & "$ZIGINSTALLDIR\bin\zig.exe" build docs
99 timeoutInMinutes: 60
100 name: doc
101 displayName: 'Documentation'
102
103 - task: DownloadSecureFile@181 - task: DownloadSecureFile@1
104 inputs:82 inputs:
105 name: aws_credentials83 name: aws_credentials
106 secureFile: aws_credentials84 secureFile: aws_credentials
10785
108 - pwsh: |86 - pwsh: |
109 Set-Variable -Name ZIGBUILDDIR -Value "$(Get-Location)\build"
110 $Env:AWS_SHARED_CREDENTIALS_FILE = "$Env:DOWNLOADSECUREFILE_SECUREFILEPATH"87 $Env:AWS_SHARED_CREDENTIALS_FILE = "$Env:DOWNLOADSECUREFILE_SECUREFILEPATH"
11188
112 # Workaround Azure networking issue89 # Workaround Azure networking issue
...@@ -114,21 +91,20 @@ jobs:...@@ -114,21 +91,20 @@ jobs:
114 $Env:AWS_EC2_METADATA_DISABLED = "true"91 $Env:AWS_EC2_METADATA_DISABLED = "true"
115 $Env:AWS_REGION = "us-west-2"92 $Env:AWS_REGION = "us-west-2"
11693
117 cd "$ZIGBUILDDIR"94 mv LICENSE stage3-release/
118 mv ../LICENSE dist/95 mv zig-cache/langref.html stage3-release/
119 mv ../zig-cache/langref.html dist/96 mv stage3-release/bin/zig.exe stage3-release/
120 mv dist/bin/zig.exe dist/97 rmdir stage3-release/bin
121 rmdir dist/bin
12298
123 # Remove the unnecessary zig dir in $prefix/lib/zig/std/std.zig99 # Remove the unnecessary zig dir in $prefix/lib/zig/std/std.zig
124 mv dist/lib/zig dist/lib2100 mv stage3-release/lib/zig stage3-release/lib2
125 rmdir dist/lib101 rmdir stage3-release/lib
126 mv dist/lib2 dist/lib102 mv stage3-release/lib2 stage3-release/lib
127103
128 Set-Variable -Name VERSION -Value $(./dist/zig.exe version)104 Set-Variable -Name VERSION -Value $(./stage3-release/zig.exe version)
129 Set-Variable -Name DIRNAME -Value "zig-windows-x86_64-$VERSION"105 Set-Variable -Name DIRNAME -Value "zig-windows-x86_64-$VERSION"
130 Set-Variable -Name TARBALL -Value "$DIRNAME.zip"106 Set-Variable -Name TARBALL -Value "$DIRNAME.zip"
131 mv dist "$DIRNAME"107 mv stage3-release "$DIRNAME"
132 7z a "$TARBALL" "$DIRNAME"108 7z a "$TARBALL" "$DIRNAME"
133109
134 aws s3 cp `110 aws s3 cp `
...@@ -168,7 +144,6 @@ jobs:...@@ -168,7 +144,6 @@ jobs:
168- job: OnMasterSuccess144- job: OnMasterSuccess
169 dependsOn:145 dependsOn:
170 - BuildMacOS146 - BuildMacOS
171 - BuildMacOS_arm64
172 - BuildWindows147 - BuildWindows
173 condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))148 condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
174 strategy:149 strategy:
ci/drone/drone.yml+21-21
...@@ -13,65 +13,65 @@ steps:...@@ -13,65 +13,65 @@ steps:
13 commands:13 commands:
14 - ./ci/drone/linux_script_build14 - ./ci/drone/linux_script_build
1515
16- name: test-116- name: behavior
17 depends_on:17 depends_on:
18 - build18 - build
19 image: ziglang/static-base:llvm14-aarch64-319 image: ziglang/static-base:llvm14-aarch64-3
20 commands:20 commands:
21 - ./ci/drone/linux_script_test 121 - ./ci/drone/test_linux_behavior
2222
23- name: test-223- name: std_Debug
24 depends_on:24 depends_on:
25 - build25 - build
26 image: ziglang/static-base:llvm14-aarch64-326 image: ziglang/static-base:llvm14-aarch64-3
27 commands:27 commands:
28 - ./ci/drone/linux_script_test 228 - ./ci/drone/test_linux_std_Debug
2929
30- name: test-330- name: std_ReleaseSafe
31 depends_on:31 depends_on:
32 - build32 - build
33 image: ziglang/static-base:llvm14-aarch64-333 image: ziglang/static-base:llvm14-aarch64-3
34 commands:34 commands:
35 - ./ci/drone/linux_script_test 335 - ./ci/drone/test_linux_std_ReleaseSafe
3636
37- name: test-437- name: std_ReleaseFast
38 depends_on:38 depends_on:
39 - build39 - build
40 image: ziglang/static-base:llvm14-aarch64-340 image: ziglang/static-base:llvm14-aarch64-3
41 commands:41 commands:
42 - ./ci/drone/linux_script_test 442 - ./ci/drone/test_linux_std_ReleaseFast
4343
44- name: test-544- name: std_ReleaseSmall
45 depends_on:45 depends_on:
46 - build46 - build
47 image: ziglang/static-base:llvm14-aarch64-347 image: ziglang/static-base:llvm14-aarch64-3
48 commands:48 commands:
49 - ./ci/drone/linux_script_test 549 - ./ci/drone/test_linux_std_ReleaseSmall
5050
51- name: test-651- name: misc
52 depends_on:52 depends_on:
53 - build53 - build
54 image: ziglang/static-base:llvm14-aarch64-354 image: ziglang/static-base:llvm14-aarch64-3
55 commands:55 commands:
56 - ./ci/drone/linux_script_test 656 - ./ci/drone/test_linux_misc
5757
58- name: test-758- name: cases
59 depends_on:59 depends_on:
60 - build60 - build
61 image: ziglang/static-base:llvm14-aarch64-361 image: ziglang/static-base:llvm14-aarch64-3
62 commands:62 commands:
63 - ./ci/drone/linux_script_test 763 - ./ci/drone/test_linux_cases
6464
65- name: finalize65- name: finalize
66 depends_on:66 depends_on:
67 - build67 - build
68 - test-168 - behavior
69 - test-269 - std_Debug
70 - test-370 - std_ReleaseSafe
71 - test-471 - std_ReleaseFast
72 - test-572 - std_ReleaseSmall
73 - test-673 - misc
74 - test-774 - cases
75 image: ziglang/static-base:llvm14-aarch64-375 image: ziglang/static-base:llvm14-aarch64-3
76 environment:76 environment:
77 SRHT_OAUTH_TOKEN:77 SRHT_OAUTH_TOKEN:
ci/drone/linux_script_base deleted-22
...@@ -1,22 +0,0 @@
1#!/bin/sh
2
3# https://docs.drone.io/pipeline/docker/syntax/workspace/
4#
5# Drone automatically creates a temporary volume, known as your workspace,
6# where it clones your repository. The workspace is the current working
7# directory for each step in your pipeline.
8#
9# Because the workspace is a volume, filesystem changes are persisted between
10# pipeline steps. In other words, individual steps can communicate and share
11# state using the filesystem.
12#
13# Workspace volumes are ephemeral. They are created when the pipeline starts
14# and destroyed after the pipeline completes.
15
16set -x
17set -e
18
19TRIPLEARCH="$(uname -m)"
20DISTDIR="$DRONE_WORKSPACE/dist"
21
22export ZIG_GLOBAL_CACHE_DIR="$DRONE_WORKSPACE/zig-cache"
ci/drone/linux_script_build+10-17
...@@ -1,17 +1,16 @@...@@ -1,17 +1,16 @@
1#!/bin/sh1#!/bin/sh
22
3. ./ci/drone/linux_script_base3set -x
4set -e
45
5# Probe CPU/brand details.6ARCH="$(uname -m)"
6# TODO: `lscpu` is changing package names in EDGE to `util-linux-misc`7INSTALL_PREFIX="$DRONE_WORKSPACE/stage3-release"
7apk update8
8apk add util-linux9export ZIG_GLOBAL_CACHE_DIR="$DRONE_WORKSPACE/zig-cache"
9echo "lscpu:"
10lscpu | sed 's,^, : ,'
1110
12PREFIX="/deps/local"11PREFIX="/deps/local"
13ZIG="$PREFIX/bin/zig"12ZIG="$PREFIX/bin/zig"
14TARGET="$TRIPLEARCH-linux-musl"13TARGET="$ARCH-linux-musl"
15MCPU="baseline"14MCPU="baseline"
1615
17export CC="$ZIG cc -target $TARGET -mcpu=$MCPU"16export CC="$ZIG cc -target $TARGET -mcpu=$MCPU"
...@@ -30,8 +29,8 @@ cat <<'ENDFILE' >$PREFIX/bin/ranlib...@@ -30,8 +29,8 @@ cat <<'ENDFILE' >$PREFIX/bin/ranlib
30/deps/local/bin/zig ranlib $@29/deps/local/bin/zig ranlib $@
31ENDFILE30ENDFILE
3231
33chmod +x $PREFIX/bin/ar32chmod +x "$PREFIX/bin/ar"
34chmod +x $PREFIX/bin/ranlib33chmod +x "$PREFIX/bin/ranlib"
3534
36# Make the `zig version` number consistent.35# Make the `zig version` number consistent.
37# This will affect the cmake command below.36# This will affect the cmake command below.
...@@ -42,8 +41,8 @@ git fetch --tags...@@ -42,8 +41,8 @@ git fetch --tags
42mkdir build41mkdir build
43cd build42cd build
44cmake .. \43cmake .. \
45 -DCMAKE_INSTALL_PREFIX="$DISTDIR" \
46 -DCMAKE_PREFIX_PATH="$PREFIX" \44 -DCMAKE_PREFIX_PATH="$PREFIX" \
45 -DCMAKE_INSTALL_PREFIX="$INSTALL_PREFIX" \
47 -DCMAKE_BUILD_TYPE=Release \46 -DCMAKE_BUILD_TYPE=Release \
48 -DCMAKE_AR="$PREFIX/bin/ar" \47 -DCMAKE_AR="$PREFIX/bin/ar" \
49 -DCMAKE_RANLIB="$PREFIX/bin/ranlib" \48 -DCMAKE_RANLIB="$PREFIX/bin/ranlib" \
...@@ -57,9 +56,3 @@ cmake .. \...@@ -57,9 +56,3 @@ cmake .. \
57unset CC56unset CC
58unset CXX57unset CXX
59samu install58samu install
60
61# Here we rebuild Zig but this time using the Zig binary we just now produced to
62# build zig1.o rather than relying on the one built with stage0. See
63# https://github.com/ziglang/zig/issues/6830 for more details.
64cmake .. -DZIG_EXECUTABLE="$DISTDIR/bin/zig"
65samu install
ci/drone/linux_script_finalize+15-9
...@@ -1,6 +1,12 @@...@@ -1,6 +1,12 @@
1#!/bin/sh1#!/bin/sh
22
3. ./ci/drone/linux_script_base3set -x
4set -e
5
6ARCH="$(uname -m)"
7INSTALL_PREFIX="$DRONE_WORKSPACE/stage3-release"
8
9export ZIG_GLOBAL_CACHE_DIR="$DRONE_WORKSPACE/zig-cache"
410
5if [ -n "$DRONE_PULL_REQUEST" ]; then11if [ -n "$DRONE_PULL_REQUEST" ]; then
6 exit 012 exit 0
...@@ -12,16 +18,16 @@ pip3 install s3cmd...@@ -12,16 +18,16 @@ pip3 install s3cmd
1218
13cd build19cd build
1420
15mv ../LICENSE "$DISTDIR/"21mv ../LICENSE "$INSTALL_PREFIX/"
16mv ../zig-cache/langref.html "$DISTDIR/"22mv ../zig-cache/langref.html "$INSTALL_PREFIX/"
17mv "$DISTDIR/bin/zig" "$DISTDIR/"23mv "$INSTALL_PREFIX/bin/zig" "$INSTALL_PREFIX/"
18rmdir "$DISTDIR/bin"24rmdir "$INSTALL_PREFIX/bin"
1925
20GITBRANCH="$DRONE_BRANCH"26GITBRANCH="$DRONE_BRANCH"
21VERSION="$("$DISTDIR/zig" version)"27VERSION="$("$INSTALL_PREFIX/zig" version)"
22DIRNAME="zig-linux-$TRIPLEARCH-$VERSION"28DIRNAME="zig-linux-$ARCH-$VERSION"
23TARBALL="$DIRNAME.tar.xz"29TARBALL="$DIRNAME.tar.xz"
24mv "$DISTDIR" "$DIRNAME"30mv "$INSTALL_PREFIX" "$DIRNAME"
25tar cfJ "$TARBALL" "$DIRNAME"31tar cfJ "$TARBALL" "$DIRNAME"
2632
27s3cmd put -P --add-header="cache-control: public, max-age=31536000, immutable" "$TARBALL" s3://ziglang.org/builds/33s3cmd put -P --add-header="cache-control: public, max-age=31536000, immutable" "$TARBALL" s3://ziglang.org/builds/
...@@ -35,7 +41,7 @@ echo "{\"tarball\": \"$TARBALL\"," >>$JSONFILE...@@ -35,7 +41,7 @@ echo "{\"tarball\": \"$TARBALL\"," >>$JSONFILE
35echo "\"shasum\": \"$SHASUM\"," >>$JSONFILE41echo "\"shasum\": \"$SHASUM\"," >>$JSONFILE
36echo "\"size\": \"$BYTESIZE\"}" >>$JSONFILE42echo "\"size\": \"$BYTESIZE\"}" >>$JSONFILE
3743
38s3cmd put -P "$JSONFILE" "s3://ziglang.org/builds/$TRIPLEARCH-linux-$VERSION.json"44s3cmd put -P "$JSONFILE" "s3://ziglang.org/builds/$ARCH-linux-$VERSION.json"
39if [ "$GITBRANCH" = "master" ]; then45if [ "$GITBRANCH" = "master" ]; then
40 # avoid leaking oauth token46 # avoid leaking oauth token
41 set +x47 set +x
ci/drone/linux_script_test deleted-51
...@@ -1,51 +0,0 @@
1#!/bin/sh
2
3. ./ci/drone/linux_script_base
4
5BUILD_FLAGS="-Dskip-non-native"
6
7case "$1" in
8 1)
9 ./build/zig build $BUILD_FLAGS test-behavior
10 ./build/zig build $BUILD_FLAGS test-compiler-rt
11 ./build/zig build $BUILD_FLAGS test-fmt
12 ./build/zig build $BUILD_FLAGS docs
13 ;;
14 2)
15 # Debug
16 ./build/zig build $BUILD_FLAGS test-std -Dskip-release-safe -Dskip-release-fast -Dskip-release-small
17 ;;
18 3)
19 # ReleaseSafe
20 ./build/zig build $BUILD_FLAGS test-std -Dskip-debug -Dskip-release-fast -Dskip-release-small -Dskip-non-native -Dskip-single-threaded
21 ;;
22 4)
23 # ReleaseFast
24 ./build/zig build $BUILD_FLAGS test-std -Dskip-debug -Dskip-release-safe -Dskip-release-small -Dskip-non-native -Dskip-single-threaded
25 ;;
26 5)
27 # ReleaseSmall
28 ./build/zig build $BUILD_FLAGS test-std -Dskip-debug -Dskip-release-safe -Dskip-release-fast
29 ;;
30 6)
31 ./build/zig build $BUILD_FLAGS test-universal-libc
32 ./build/zig build $BUILD_FLAGS test-compare-output
33 ./build/zig build $BUILD_FLAGS test-standalone -Dskip-release-safe
34 ./build/zig build $BUILD_FLAGS test-stack-traces
35 ./build/zig build $BUILD_FLAGS test-cli
36 ./build/zig build $BUILD_FLAGS test-asm-link
37 ./build/zig build $BUILD_FLAGS test-translate-c
38 ;;
39 7)
40 ./build/zig build $BUILD_FLAGS # test building self-hosted without LLVM
41 ./build/zig build $BUILD_FLAGS test-cases
42 ;;
43 '')
44 echo "error: expecting test group argument"
45 exit 1
46 ;;
47 *)
48 echo "error: unknown test group: $1"
49 exit 1
50 ;;
51esac
ci/drone/test_linux_behavior created+13
...@@ -0,0 +1,13 @@
1#!/bin/sh
2
3set -x
4set -e
5
6INSTALL_PREFIX="$DRONE_WORKSPACE/stage3-release"
7ZIG="$INSTALL_PREFIX/bin/zig"
8export ZIG_GLOBAL_CACHE_DIR="$DRONE_WORKSPACE/zig-cache"
9
10$ZIG build test-behavior -Dskip-non-native
11$ZIG build test-compiler-rt -Dskip-non-native
12$ZIG build test-fmt
13$ZIG build docs
ci/drone/test_linux_cases created+11
...@@ -0,0 +1,11 @@
1#!/bin/sh
2
3set -x
4set -e
5
6INSTALL_PREFIX="$DRONE_WORKSPACE/stage3-release"
7ZIG="$INSTALL_PREFIX/bin/zig"
8export ZIG_GLOBAL_CACHE_DIR="$DRONE_WORKSPACE/zig-cache"
9
10$ZIG build -Dskip-non-native # test building self-hosted without LLVM
11$ZIG build -Dskip-non-native test-cases
ci/drone/test_linux_misc created+16
...@@ -0,0 +1,16 @@
1#!/bin/sh
2
3set -x
4set -e
5
6INSTALL_PREFIX="$DRONE_WORKSPACE/stage3-release"
7ZIG="$INSTALL_PREFIX/bin/zig"
8export ZIG_GLOBAL_CACHE_DIR="$DRONE_WORKSPACE/zig-cache"
9
10$ZIG build test-universal-libc -Dskip-non-native
11$ZIG build test-compare-output -Dskip-non-native
12$ZIG build test-standalone -Dskip-non-native -Dskip-release-safe
13$ZIG build test-stack-traces -Dskip-non-native
14$ZIG build test-cli -Dskip-non-native
15$ZIG build test-asm-link -Dskip-non-native
16$ZIG build test-translate-c -Dskip-non-native
ci/drone/test_linux_std_Debug created+10
...@@ -0,0 +1,10 @@
1#!/bin/sh
2
3set -x
4set -e
5
6INSTALL_PREFIX="$DRONE_WORKSPACE/stage3-release"
7ZIG="$INSTALL_PREFIX/bin/zig"
8export ZIG_GLOBAL_CACHE_DIR="$DRONE_WORKSPACE/zig-cache"
9
10$ZIG build test-std -Dskip-release-safe -Dskip-release-fast -Dskip-release-small -Dskip-non-native
ci/drone/test_linux_std_ReleaseFast created+10
...@@ -0,0 +1,10 @@
1#!/bin/sh
2
3set -x
4set -e
5
6INSTALL_PREFIX="$DRONE_WORKSPACE/stage3-release"
7ZIG="$INSTALL_PREFIX/bin/zig"
8export ZIG_GLOBAL_CACHE_DIR="$DRONE_WORKSPACE/zig-cache"
9
10$ZIG build test-std -Dskip-debug -Dskip-release-safe -Dskip-release-small -Dskip-non-native -Dskip-single-threaded
ci/drone/test_linux_std_ReleaseSafe created+10
...@@ -0,0 +1,10 @@
1#!/bin/sh
2
3set -x
4set -e
5
6INSTALL_PREFIX="$DRONE_WORKSPACE/stage3-release"
7ZIG="$INSTALL_PREFIX/bin/zig"
8export ZIG_GLOBAL_CACHE_DIR="$DRONE_WORKSPACE/zig-cache"
9
10$ZIG build test-std -Dskip-debug -Dskip-release-fast -Dskip-release-small -Dskip-non-native -Dskip-single-threaded
ci/drone/test_linux_std_ReleaseSmall created+16
...@@ -0,0 +1,16 @@
1#!/bin/sh
2
3set -x
4set -e
5
6INSTALL_PREFIX="$DRONE_WORKSPACE/stage3-release"
7ZIG="$INSTALL_PREFIX/bin/zig"
8export ZIG_GLOBAL_CACHE_DIR="$DRONE_WORKSPACE/zig-cache"
9
10# Empirically, this takes about 55 minutes on the CI, and is the bottleneck
11# causing timeouts. So this is disabled in favor of running a smaller set
12# of ReleaseSmall std lib tests.
13# $ZIG build test-std -Dskip-debug -Dskip-release-safe -Dskip-release-fast -Dskip-non-native
14
15$ZIG test lib/std/std.zig -OReleaseSmall
16$ZIG test lib/std/std.zig -OReleaseSmall -lc
ci/srht/freebsd_script+35-20
...@@ -7,7 +7,9 @@ sudo pkg update -fq...@@ -7,7 +7,9 @@ sudo pkg update -fq
7sudo pkg install -y cmake py39-s3cmd wget curl jq samurai7sudo pkg install -y cmake py39-s3cmd wget curl jq samurai
88
9ZIGDIR="$(pwd)"9ZIGDIR="$(pwd)"
10CACHE_BASENAME="zig+llvm+lld+clang-x86_64-freebsd-gnu-0.10.0-dev.2931+bdf3fa12f"10TARGET="x86_64-freebsd-gnu"
11MCPU="baseline"
12CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.10.0-dev.3524+74673b7f6"
11PREFIX="$HOME/$CACHE_BASENAME"13PREFIX="$HOME/$CACHE_BASENAME"
1214
13cd $HOME15cd $HOME
...@@ -29,34 +31,47 @@ export TERM=dumb...@@ -29,34 +31,47 @@ export TERM=dumb
2931
30mkdir build32mkdir build
31cd build33cd build
34
35
32cmake .. \36cmake .. \
33 -DCMAKE_BUILD_TYPE=Release \37 -DCMAKE_BUILD_TYPE=Release \
34 -DCMAKE_PREFIX_PATH=$PREFIX \38 -DCMAKE_PREFIX_PATH=$PREFIX \
35 "-DCMAKE_INSTALL_PREFIX=$(pwd)/release" \39 -DZIG_TARGET_TRIPLE="$TARGET" \
36 -DZIG_STATIC=ON \40 -DZIG_TARGET_MCPU="$MCPU" \
37 -DZIG_TARGET_TRIPLE=x86_64-freebsd-gnu \41 -DZIG_STATIC=ON \
38 -GNinja42 -GNinja
39samu install43
4044# TODO: eliminate this workaround. Without this, zig does not end up passing
41# TODO ld.lld: error: undefined symbol: main45# -isystem /usr/include when building libc++, resulting in #include <sys/endian.h>
42# >>> referenced by crt1_c.c:75 (/usr/src/lib/csu/amd64/crt1_c.c:75)46# "file not found" errors.
43# >>> /usr/lib/crt1.o:(_start)47echo "include_dir=/usr/include" >>libc.txt
44#release/bin/zig test ../test/behavior.zig -fno-stage1 -fLLVM -I ../test48echo "sys_include_dir=/usr/include" >>libc.txt
49echo "crt_dir=/usr/lib" >>libc.txt
50echo "msvc_lib_dir=" >>libc.txt
51echo "kernel32_lib_dir=" >>libc.txt
52echo "gcc_dir=" >>libc.txt
53ZIG_LIBC_TXT="$(pwd)/libc.txt"
54
55ZIG_LIBC="$ZIG_LIBC_TXT" samu install
4556
46# Here we skip some tests to save time.57# Here we skip some tests to save time.
47release/bin/zig build test -Dskip-stage1 -Dskip-non-native58stage3/bin/zig build test docs \
59 -Dstatic-llvm \
60 --search-prefix "$PREFIX" \
61 -Dskip-stage1 \
62 -Dskip-non-native
4863
49if [ -f ~/.s3cfg ]; then64if [ -f ~/.s3cfg ]; then
50 mv ../LICENSE release/65 mv ../LICENSE stage3/
51 mv ../zig-cache/langref.html release/66 mv ../zig-cache/langref.html stage3/
52 mv release/bin/zig release/67 mv stage3/bin/zig stage3/
53 rmdir release/bin68 rmdir stage3/bin
5469
55 GITBRANCH=$(basename $GITHUB_REF)70 GITBRANCH=$(basename $GITHUB_REF)
56 VERSION=$(release/zig version)71 VERSION=$(stage3/zig version)
57 DIRNAME="zig-freebsd-x86_64-$VERSION"72 DIRNAME="zig-freebsd-x86_64-$VERSION"
58 TARBALL="$DIRNAME.tar.xz"73 TARBALL="$DIRNAME.tar.xz"
59 mv release "$DIRNAME"74 mv stage3 "$DIRNAME"
60 tar cfJ "$TARBALL" "$DIRNAME"75 tar cfJ "$TARBALL" "$DIRNAME"
6176
62 s3cmd put -P --add-header="cache-control: public, max-age=31536000, immutable" "$TARBALL" s3://ziglang.org/builds/77 s3cmd put -P --add-header="cache-control: public, max-age=31536000, immutable" "$TARBALL" s3://ziglang.org/builds/
ci/srht/update_download_page+22-7
...@@ -100,6 +100,27 @@ cd "$SRCTARBALLDIR/ci/srht"...@@ -100,6 +100,27 @@ cd "$SRCTARBALLDIR/ci/srht"
100CIDIR="$(pwd)"100CIDIR="$(pwd)"
101101
102cd "$HOME"102cd "$HOME"
103
104# Upload new stdlib autodocs
105mkdir -p docs_to_upload/documentation/master/std/
106gzip -c -9 "$ZIGDIR/docs/std/index.html" > docs_to_upload/documentation/master/std/index.html
107gzip -c -9 "$ZIGDIR/docs/std/data.js" > docs_to_upload/documentation/master/std/data.js
108gzip -c -9 "$ZIGDIR/docs/std/main.js" > docs_to_upload/documentation/master/std/main.js
109gzip -c -9 "$LANGREF" > docs_to_upload/documentation/master/index.html
110$S3CMD put -P --no-mime-magic --recursive --add-header="Content-Encoding:gzip" --add-header="Cache-Control: max-age=0, must-revalidate" "docs_to_upload/" s3://ziglang.org/
111
112mkdir -p docs_src_to_upload/documentation/master/std/
113cp -r "$ZIGDIR/docs/std/src" docs_src_to_upload/documentation/master/std/
114$S3CMD put -P --no-mime-magic --recursive --add-header:"Content-Type:text/html" --add-header="Cache-Control: max-age=0, must-revalidate" "docs_src_to_upload/" s3://ziglang.org/
115
116## Copy without compression:
117# mkdir -p docs_to_upload/documentation/master/std/
118# cp "$ZIGDIR/docs/std/index.html" docs_to_upload/documentation/master/std/index.html
119# cp "$ZIGDIR/docs/std/data.js" docs_to_upload/documentation/master/std/data.js
120# cp "$ZIGDIR/docs/std/main.js" docs_to_upload/documentation/master/std/main.js
121# cp "$LANGREF" docs_to_upload/documentation/master/index.html
122# $S3CMD put -P --no-mime-magic --recursive --add-header="Cache-Control: max-age=0, must-revalidate" "docs_to_upload/" s3://ziglang.org/
123
103git clone --depth 1 git@github.com:ziglang/www.ziglang.org.git124git clone --depth 1 git@github.com:ziglang/www.ziglang.org.git
104cd www.ziglang.org125cd www.ziglang.org
105WWWDIR="$(pwd)"126WWWDIR="$(pwd)"
...@@ -108,12 +129,6 @@ $S3CMD put -P --no-mime-magic --add-header="cache-control: public, max-age=31536...@@ -108,12 +129,6 @@ $S3CMD put -P --no-mime-magic --add-header="cache-control: public, max-age=31536
108129
109cd "$WWWDIR"130cd "$WWWDIR"
110cp "$CIDIR/out/index.json" data/releases.json131cp "$CIDIR/out/index.json" data/releases.json
111mkdir -p content/documentation/master/std
112cp "$LANGREF" content/documentation/master/index.html
113cp "$ZIGDIR/docs/std/index.html" content/documentation/master/std/index.html
114cp "$ZIGDIR/docs/std/data.js" content/documentation/master/std/data.js
115cp "$ZIGDIR/docs/std/main.js" content/documentation/master/std/main.js
116git add data/releases.json132git add data/releases.json
117git add content/133git commit -m "CI: update releases"
118git commit -m "CI: update releases and docs"
119git push origin master134git push origin master
ci/zinc/build_aarch64_macos created+20
...@@ -0,0 +1,20 @@
1#!/bin/sh
2
3set -x
4set -e
5
6RELEASE_STAGING="$DRONE_WORKSPACE/_release/staging"
7TARGET="aarch64-macos-none"
8MCPU="apple_a14"
9INSTALL_PREFIX="$DRONE_WORKSPACE/$TARGET"
10SEARCH_PREFIX="/deps/$TARGET"
11
12"$RELEASE_STAGING/bin/zig" build \
13 --prefix "$INSTALL_PREFIX" \
14 --search-prefix "$SEARCH_PREFIX" \
15 -Dstatic-llvm \
16 -Drelease \
17 -Dstrip \
18 -Dtarget="$TARGET" \
19 -Dmcpu="$MCPU" \
20 -Denable-stage1
ci/zinc/configure_git created+10
...@@ -0,0 +1,10 @@
1#!/bin/sh
2
3set -x
4set -e
5
6# Make the `zig version` number consistent.
7# This will affect the cmake commands that follow.
8# This is in its own script because git does not support this command
9# being run concurrently with itself.
10git config core.abbrev 9
ci/zinc/drone.yml+56-7
...@@ -9,26 +9,75 @@ workspace:...@@ -9,26 +9,75 @@ workspace:
9 path: /workspace9 path: /workspace
1010
11steps:11steps:
12- name: test12- name: configure_git
13 image: ci/debian-amd64:11.1-613 image: ci/debian-amd64:11.1-9
14 commands:14 commands:
15 - ./ci/zinc/linux_test.sh15 - ./ci/zinc/configure_git
1616
17- name: package17- name: test_stage3_debug
18 depends_on:18 depends_on:
19 - test19 - configure_git
20 image: ci/debian-amd64:11.1-9
21 commands:
22 - ./ci/zinc/linux_test_stage3_debug
23
24- name: test_stage3_release
25 depends_on:
26 - configure_git
27 image: ci/debian-amd64:11.1-9
28 commands:
29 - ./ci/zinc/linux_test_stage3_release
30
31- name: build_aarch64_macos
32 depends_on:
33 - test_stage3_release
34 image: ci/debian-amd64:11.1-9
35 commands:
36 - ./ci/zinc/build_aarch64_macos
37
38- name: linux_package
39 depends_on:
40 - test_stage3_debug
41 - test_stage3_release
42 when:
43 branch:
44 - master
45 event:
46 - push
47 image: ci/debian-amd64:11.1-9
48 environment:
49 AWS_ACCESS_KEY_ID:
50 from_secret: AWS_ACCESS_KEY_ID
51 AWS_SECRET_ACCESS_KEY:
52 from_secret: AWS_SECRET_ACCESS_KEY
53 commands:
54 - ./ci/zinc/linux_package
55
56- name: macos_package
57 depends_on:
58 - test_stage3_debug
59 - build_aarch64_macos
20 when:60 when:
21 branch:61 branch:
22 - master62 - master
23 event:63 event:
24 - push64 - push
25 image: ci/debian-amd64:11.1-665 image: ci/debian-amd64:11.1-9
26 environment:66 environment:
27 AWS_ACCESS_KEY_ID:67 AWS_ACCESS_KEY_ID:
28 from_secret: AWS_ACCESS_KEY_ID68 from_secret: AWS_ACCESS_KEY_ID
29 AWS_SECRET_ACCESS_KEY:69 AWS_SECRET_ACCESS_KEY:
30 from_secret: AWS_SECRET_ACCESS_KEY70 from_secret: AWS_SECRET_ACCESS_KEY
71 commands:
72 - ./ci/zinc/macos_package
73
74- name: notify_lavahut
75 depends_on:
76 - macos_package
77 - linux_package
78 image: ci/debian-amd64:11.1-9
79 environment:
31 SRHT_OAUTH_TOKEN:80 SRHT_OAUTH_TOKEN:
32 from_secret: SRHT_OAUTH_TOKEN81 from_secret: SRHT_OAUTH_TOKEN
33 commands:82 commands:
34 - ./ci/zinc/linux_package.sh83 - ./ci/zinc/notify_lavahut
ci/zinc/linux_base.sh deleted-27
...@@ -1,27 +0,0 @@
1#!/bin/sh
2
3# https://docs.drone.io/pipeline/docker/syntax/workspace/
4#
5# Drone automatically creates a temporary volume, known as your workspace,
6# where it clones your repository. The workspace is the current working
7# directory for each step in your pipeline.
8#
9# Because the workspace is a volume, filesystem changes are persisted between
10# pipeline steps. In other words, individual steps can communicate and share
11# state using the filesystem.
12#
13# Workspace volumes are ephemeral. They are created when the pipeline starts
14# and destroyed after the pipeline completes.
15
16set -x
17set -e
18
19ARCH="$(uname -m)"
20
21DEPS_LOCAL="/deps/local"
22WORKSPACE="$DRONE_WORKSPACE"
23
24DEBUG_STAGING="$WORKSPACE/_debug/staging"
25RELEASE_STAGING="$WORKSPACE/_release/staging"
26
27export PATH=$DEPS_LOCAL/bin:$PATH
ci/zinc/linux_package created+45
...@@ -0,0 +1,45 @@
1#!/bin/sh
2
3set -x
4set -e
5
6ARCH="$(uname -m)"
7OS="linux"
8RELEASE_STAGING="$DRONE_WORKSPACE/_release/staging"
9VERSION=$($RELEASE_STAGING/bin/zig version)
10BASENAME="zig-$OS-$ARCH-$VERSION"
11TARBALL="$BASENAME.tar.xz"
12
13# This runs concurrently with the macos_package script, so it should not make
14# any changes to the filesystem that will cause problems for the other script.
15
16cp -r "$RELEASE_STAGING" "$BASENAME"
17
18# Remove the unnecessary bin dir in $prefix/bin/zig
19mv $BASENAME/bin/zig $BASENAME/
20rmdir $BASENAME/bin
21
22# Remove the unnecessary zig dir in $prefix/lib/zig/std/std.zig
23mv $BASENAME/lib/zig $BASENAME/lib2
24rmdir $BASENAME/lib
25mv $BASENAME/lib2 $BASENAME/lib
26
27tar cfJ "$TARBALL" "$BASENAME"
28
29SHASUM=$(sha256sum $TARBALL | cut '-d ' -f1)
30BYTESIZE=$(wc -c < $TARBALL)
31
32MANIFEST="manifest.json"
33touch $MANIFEST
34echo "{\"tarball\": \"$TARBALL\"," >>$MANIFEST
35echo "\"shasum\": \"$SHASUM\"," >>$MANIFEST
36echo "\"size\": \"$BYTESIZE\"}" >>$MANIFEST
37
38# Publish artifact.
39s3cmd put -P --add-header="cache-control: public, max-age=31536000, immutable" "$TARBALL" s3://ziglang.org/builds/
40
41# Publish manifest.
42s3cmd put -P --add-header="cache-control: max-age=0, must-revalidate" "$MANIFEST" "s3://ziglang.org/builds/$ARCH-$OS-$VERSION.json"
43
44# Explicit exit helps show last command duration.
45exit
ci/zinc/linux_package.sh deleted-48
...@@ -1,48 +0,0 @@
1#!/bin/sh
2
3. ./ci/zinc/linux_base.sh
4
5cp LICENSE $RELEASE_STAGING/
6cp zig-cache/langref.html $RELEASE_STAGING/docs/
7
8# Remove the unnecessary bin dir in $prefix/bin/zig
9mv $RELEASE_STAGING/bin/zig $RELEASE_STAGING/
10rmdir $RELEASE_STAGING/bin
11
12# Remove the unnecessary zig dir in $prefix/lib/zig/std/std.zig
13mv $RELEASE_STAGING/lib/zig $RELEASE_STAGING/lib2
14rmdir $RELEASE_STAGING/lib
15mv $RELEASE_STAGING/lib2 $RELEASE_STAGING/lib
16
17VERSION=$($RELEASE_STAGING/zig version)
18BASENAME="zig-linux-$ARCH-$VERSION"
19TARBALL="$BASENAME.tar.xz"
20mv "$RELEASE_STAGING" "$BASENAME"
21tar cfJ "$TARBALL" "$BASENAME"
22ls -l "$TARBALL"
23
24SHASUM=$(sha256sum $TARBALL | cut '-d ' -f1)
25BYTESIZE=$(wc -c < $TARBALL)
26
27MANIFEST="manifest.json"
28touch $MANIFEST
29echo "{\"tarball\": \"$TARBALL\"," >>$MANIFEST
30echo "\"shasum\": \"$SHASUM\"," >>$MANIFEST
31echo "\"size\": \"$BYTESIZE\"}" >>$MANIFEST
32
33# Publish artifact.
34s3cmd put -P --add-header="cache-control: public, max-age=31536000, immutable" "$TARBALL" s3://ziglang.org/builds/
35
36# Publish manifest.
37s3cmd put -P --add-header="cache-control: max-age=0, must-revalidate" "$MANIFEST" "s3://ziglang.org/builds/$ARCH-linux-$VERSION.json"
38
39# Avoid leaking oauth token.
40set +x
41
42cd $WORKSPACE
43./ci/srht/on_master_success "$VERSION" "$SRHT_OAUTH_TOKEN"
44
45set -x
46
47# Explicit exit helps show last command duration.
48exit
ci/zinc/linux_test.sh deleted-93
...@@ -1,93 +0,0 @@
1#!/bin/sh
2
3. ./ci/zinc/linux_base.sh
4
5OLD_ZIG="$DEPS_LOCAL/bin/zig"
6TARGET="${ARCH}-linux-musl"
7MCPU="baseline"
8
9# Make the `zig version` number consistent.
10# This will affect the cmake command below.
11git config core.abbrev 9
12
13echo "building debug zig with zig version $($OLD_ZIG version)"
14
15export CC="$OLD_ZIG cc -target $TARGET -mcpu=$MCPU"
16export CXX="$OLD_ZIG c++ -target $TARGET -mcpu=$MCPU"
17
18mkdir _debug
19cd _debug
20cmake .. \
21 -DCMAKE_INSTALL_PREFIX="$DEBUG_STAGING" \
22 -DCMAKE_PREFIX_PATH="$DEPS_LOCAL" \
23 -DCMAKE_BUILD_TYPE=Debug \
24 -DZIG_TARGET_TRIPLE="$TARGET" \
25 -DZIG_TARGET_MCPU="$MCPU" \
26 -DZIG_STATIC=ON \
27 -GNinja
28
29# Now cmake will use zig as the C/C++ compiler. We reset the environment variables
30# so that installation and testing do not get affected by them.
31unset CC
32unset CXX
33
34ninja install
35
36STAGE1_ZIG="$DEBUG_STAGING/bin/zig"
37
38# Here we rebuild zig but this time using the Zig binary we just now produced to
39# build zig1.o rather than relying on the one built with stage0. See
40# https://github.com/ziglang/zig/issues/6830 for more details.
41cmake .. -DZIG_EXECUTABLE="$STAGE1_ZIG"
42ninja install
43
44cd $WORKSPACE
45
46echo "Looking for non-conforming code formatting..."
47echo "Formatting errors can be fixed by running 'zig fmt' on the files printed here."
48$STAGE1_ZIG fmt --check . --exclude test/cases/
49
50$STAGE1_ZIG build -p stage2 -Dstatic-llvm -Dtarget=native-native-musl --search-prefix "$DEPS_LOCAL"
51stage2/bin/zig build -p stage3 -Dstatic-llvm -Dtarget=native-native-musl --search-prefix "$DEPS_LOCAL"
52stage3/bin/zig build # test building self-hosted without LLVM
53stage3/bin/zig build -Dtarget=arm-linux-musleabihf # test building self-hosted for 32-bit arm
54
55stage3/bin/zig build test-compiler-rt -fqemu -fwasmtime -Denable-llvm
56stage3/bin/zig build test-behavior -fqemu -fwasmtime -Denable-llvm
57stage3/bin/zig build test-std -fqemu -fwasmtime -Denable-llvm
58stage3/bin/zig build test-universal-libc -fqemu -fwasmtime -Denable-llvm
59stage3/bin/zig build test-compare-output -fqemu -fwasmtime -Denable-llvm
60stage3/bin/zig build test-asm-link -fqemu -fwasmtime -Denable-llvm
61stage3/bin/zig build test-fmt -fqemu -fwasmtime -Denable-llvm
62stage3/bin/zig build test-translate-c -fqemu -fwasmtime -Denable-llvm
63stage3/bin/zig build test-run-translated-c -fqemu -fwasmtime -Denable-llvm
64stage3/bin/zig build test-standalone -fqemu -fwasmtime -Denable-llvm
65stage3/bin/zig build test-cli -fqemu -fwasmtime -Denable-llvm
66stage3/bin/zig build test-cases -fqemu -fwasmtime -Dstatic-llvm -Dtarget=native-native-musl --search-prefix "$DEPS_LOCAL"
67stage3/bin/zig build test-link -fqemu -fwasmtime -Denable-llvm
68
69$STAGE1_ZIG build test-stack-traces -fqemu -fwasmtime
70$STAGE1_ZIG build docs -fqemu -fwasmtime
71
72# Produce the experimental std lib documentation.
73mkdir -p "$RELEASE_STAGING/docs/std"
74stage3/bin/zig test lib/std/std.zig \
75 --zig-lib-dir lib \
76 -femit-docs=$RELEASE_STAGING/docs/std \
77 -fno-emit-bin
78
79# Look for HTML errors.
80tidy --drop-empty-elements no -qe zig-cache/langref.html
81
82# Build release zig.
83stage3/bin/zig build \
84 --prefix "$RELEASE_STAGING" \
85 --search-prefix "$DEPS_LOCAL" \
86 -Dstatic-llvm \
87 -Drelease \
88 -Dstrip \
89 -Dtarget="$TARGET" \
90 -Dstage1
91
92# Explicit exit helps show last command duration.
93exit
ci/zinc/linux_test_stage3_debug created+61
...@@ -0,0 +1,61 @@
1#!/bin/sh
2
3set -x
4set -e
5
6ARCH="$(uname -m)"
7DEPS_LOCAL="/deps/local"
8OLD_ZIG="$DEPS_LOCAL/bin/zig"
9TARGET="${ARCH}-linux-musl"
10MCPU="baseline"
11
12export PATH=$DEPS_LOCAL/bin:$PATH
13
14echo "building stage3-debug with zig version $($OLD_ZIG version)"
15
16# Override the cache directories so that we don't clobber with the release
17# testing script which is running concurrently and in the same directory.
18# Normally we want processes to cooperate, but in this case we want them isolated.
19export ZIG_LOCAL_CACHE_DIR="$(pwd)/zig-cache-local-debug"
20export ZIG_GLOBAL_CACHE_DIR="$(pwd)/zig-cache-global-debug"
21
22export CC="$OLD_ZIG cc -target $TARGET -mcpu=$MCPU"
23export CXX="$OLD_ZIG c++ -target $TARGET -mcpu=$MCPU"
24
25mkdir build-debug
26cd build-debug
27cmake .. \
28 -DCMAKE_INSTALL_PREFIX="$(pwd)/stage3" \
29 -DCMAKE_PREFIX_PATH="$DEPS_LOCAL" \
30 -DCMAKE_BUILD_TYPE=Debug \
31 -DZIG_STATIC=ON \
32 -DZIG_USE_LLVM_CONFIG=OFF \
33 -GNinja
34
35# Now cmake will use zig as the C/C++ compiler. We reset the environment variables
36# so that installation and testing do not get affected by them.
37unset CC
38unset CXX
39
40ninja install
41
42echo "Looking for non-conforming code formatting..."
43stage3/bin/zig fmt --check .. \
44 --exclude ../test/cases/ \
45 --exclude ../build-debug \
46 --exclude ../build-release \
47 --exclude "$ZIG_LOCAL_CACHE_DIR" \
48 --exclude "$ZIG_GLOBAL_CACHE_DIR"
49
50# simultaneously test building self-hosted without LLVM and with 32-bit arm
51stage3/bin/zig build -Dtarget=arm-linux-musleabihf
52
53stage3/bin/zig build test \
54 -fqemu \
55 -fwasmtime \
56 -Dstatic-llvm \
57 -Dtarget=native-native-musl \
58 --search-prefix "$DEPS_LOCAL"
59
60# Explicit exit helps show last command duration.
61exit
ci/zinc/linux_test_stage3_release created+58
...@@ -0,0 +1,58 @@
1#!/bin/sh
2
3set -x
4set -e
5
6ARCH="$(uname -m)"
7DEPS_LOCAL="/deps/local"
8RELEASE_STAGING="$DRONE_WORKSPACE/_release/staging"
9OLD_ZIG="$DEPS_LOCAL/bin/zig"
10TARGET="${ARCH}-linux-musl"
11MCPU="baseline"
12
13export PATH=$DEPS_LOCAL/bin:$PATH
14
15echo "building stage3-release with zig version $($OLD_ZIG version)"
16
17export CC="$OLD_ZIG cc -target $TARGET -mcpu=$MCPU"
18export CXX="$OLD_ZIG c++ -target $TARGET -mcpu=$MCPU"
19
20mkdir build-release
21cd build-release
22cmake .. \
23 -DCMAKE_INSTALL_PREFIX="$RELEASE_STAGING" \
24 -DCMAKE_PREFIX_PATH="$DEPS_LOCAL" \
25 -DCMAKE_BUILD_TYPE=Release \
26 -DZIG_TARGET_TRIPLE="$TARGET" \
27 -DZIG_TARGET_MCPU="$MCPU" \
28 -DZIG_STATIC=ON \
29 -GNinja
30
31# Now cmake will use zig as the C/C++ compiler. We reset the environment variables
32# so that installation and testing do not get affected by them.
33unset CC
34unset CXX
35
36ninja install
37
38"$RELEASE_STAGING/bin/zig" build test docs \
39 -fqemu \
40 -fwasmtime \
41 -Dstatic-llvm \
42 -Dtarget=native-native-musl \
43 --search-prefix "$DEPS_LOCAL"
44
45# Produce the experimental std lib documentation.
46mkdir -p "$RELEASE_STAGING/docs/std"
47"$RELEASE_STAGING/bin/zig" test ../lib/std/std.zig \
48 -femit-docs=$RELEASE_STAGING/docs/std \
49 -fno-emit-bin
50
51cp ../LICENSE $RELEASE_STAGING/
52cp ../zig-cache/langref.html $RELEASE_STAGING/docs/
53
54# Look for HTML errors.
55tidy --drop-empty-elements no -qe $RELEASE_STAGING/docs/langref.html
56
57# Explicit exit helps show last command duration.
58exit
ci/zinc/macos_package created+49
...@@ -0,0 +1,49 @@
1#!/bin/sh
2
3set -x
4set -e
5
6ARCH="aarch64"
7OS=macos
8ZIG_PREFIX="$DRONE_WORKSPACE/_release/staging"
9VERSION=$($ZIG_PREFIX/bin/zig version)
10TARGET="$ARCH-$OS-none"
11INSTALL_PREFIX="$DRONE_WORKSPACE/$TARGET"
12BASENAME="zig-$OS-$ARCH-$VERSION"
13TARBALL="$BASENAME.tar.xz"
14
15# This runs concurrently with the linux_package script, so it should not make
16# any changes to the filesystem that will cause problems for the other script.
17
18# Remove the unnecessary bin dir in $prefix/bin/zig
19mv $INSTALL_PREFIX/bin/zig $INSTALL_PREFIX/
20rmdir $INSTALL_PREFIX/bin
21
22# Remove the unnecessary zig dir in $prefix/lib/zig/std/std.zig
23mv $INSTALL_PREFIX/lib/zig $INSTALL_PREFIX/lib2
24rmdir $INSTALL_PREFIX/lib
25mv $INSTALL_PREFIX/lib2 $INSTALL_PREFIX/lib
26
27cp -r "$ZIG_PREFIX/docs" "$INSTALL_PREFIX/"
28cp "$ZIG_PREFIX/LICENSE" "$INSTALL_PREFIX/"
29
30mv "$INSTALL_PREFIX" "$BASENAME"
31tar cfJ "$TARBALL" "$BASENAME"
32
33SHASUM=$(sha256sum $TARBALL | cut '-d ' -f1)
34BYTESIZE=$(wc -c < $TARBALL)
35
36MANIFEST="manifest.json"
37touch $MANIFEST
38echo "{\"tarball\": \"$TARBALL\"," >>$MANIFEST
39echo "\"shasum\": \"$SHASUM\"," >>$MANIFEST
40echo "\"size\": \"$BYTESIZE\"}" >>$MANIFEST
41
42# Publish artifact.
43s3cmd put -P --add-header="cache-control: public, max-age=31536000, immutable" "$TARBALL" s3://ziglang.org/builds/
44
45# Publish manifest.
46s3cmd put -P --add-header="cache-control: max-age=0, must-revalidate" "$MANIFEST" "s3://ziglang.org/builds/$ARCH-$OS-$VERSION.json"
47
48# Explicit exit helps show last command duration.
49exit
ci/zinc/notify_lavahut created+9
...@@ -0,0 +1,9 @@
1#!/bin/sh
2
3set +x # Avoid leaking oauth token.
4set -e
5
6ZIG_PREFIX="$DRONE_WORKSPACE/_release/staging"
7VERSION=$($ZIG_PREFIX/bin/zig version)
8cd $DRONE_WORKSPACE
9./ci/srht/on_master_success "$VERSION" "$SRHT_OAUTH_TOKEN"
cmake/install.cmake deleted-37
...@@ -1,37 +0,0 @@
1message("-- Installing: ${CMAKE_INSTALL_PREFIX}/lib")
2
3if(NOT EXISTS ${zig_EXE})
4 message("::")
5 message(":: ERROR: Executable not found")
6 message(":: (execute_process)")
7 message("::")
8 message(":: executable: ${zig_EXE}")
9 message("::")
10 message(FATAL_ERROR)
11endif()
12
13execute_process(COMMAND ${zig_EXE} ${ZIG_INSTALL_ARGS}
14 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
15 RESULT_VARIABLE _result
16)
17if(_result)
18 message("::")
19 message(":: ERROR: ${_result}")
20 message(":: (execute_process)")
21
22 string(REPLACE ";" " " s_INSTALL_LIBSTAGE2_ARGS "${ZIG_INSTALL_ARGS}")
23 message("::")
24 message(":: argv: ${zig_EXE} ${s_INSTALL_LIBSTAGE2_ARGS}")
25
26 set(_args ${zig_EXE} ${ZIG_INSTALL_ARGS})
27 list(LENGTH _args _len)
28 math(EXPR _len "${_len} - 1")
29 message("::")
30 foreach(_i RANGE 0 ${_len})
31 list(GET _args ${_i} _arg)
32 message(":: argv[${_i}]: ${_arg}")
33 endforeach()
34
35 message("::")
36 message(FATAL_ERROR)
37endif()
doc/docgen.zig+31
...@@ -285,6 +285,7 @@ const Code = struct {...@@ -285,6 +285,7 @@ const Code = struct {
285 link_objects: []const []const u8,285 link_objects: []const []const u8,
286 target_str: ?[]const u8,286 target_str: ?[]const u8,
287 link_libc: bool,287 link_libc: bool,
288 backend_stage1: bool,
288 link_mode: ?std.builtin.LinkMode,289 link_mode: ?std.builtin.LinkMode,
289 disable_cache: bool,290 disable_cache: bool,
290 verbose_cimport: bool,291 verbose_cimport: bool,
...@@ -554,6 +555,7 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {...@@ -554,6 +555,7 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {
554 var link_mode: ?std.builtin.LinkMode = null;555 var link_mode: ?std.builtin.LinkMode = null;
555 var disable_cache = false;556 var disable_cache = false;
556 var verbose_cimport = false;557 var verbose_cimport = false;
558 var backend_stage1 = false;
557559
558 const source_token = while (true) {560 const source_token = while (true) {
559 const content_tok = try eatToken(tokenizer, Token.Id.Content);561 const content_tok = try eatToken(tokenizer, Token.Id.Content);
...@@ -586,6 +588,8 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {...@@ -586,6 +588,8 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {
586 link_libc = true;588 link_libc = true;
587 } else if (mem.eql(u8, end_tag_name, "link_mode_dynamic")) {589 } else if (mem.eql(u8, end_tag_name, "link_mode_dynamic")) {
588 link_mode = .Dynamic;590 link_mode = .Dynamic;
591 } else if (mem.eql(u8, end_tag_name, "backend_stage1")) {
592 backend_stage1 = true;
589 } else if (mem.eql(u8, end_tag_name, "code_end")) {593 } else if (mem.eql(u8, end_tag_name, "code_end")) {
590 _ = try eatToken(tokenizer, Token.Id.BracketClose);594 _ = try eatToken(tokenizer, Token.Id.BracketClose);
591 break content_tok;595 break content_tok;
...@@ -609,6 +613,7 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {...@@ -609,6 +613,7 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {
609 .link_objects = link_objects.toOwnedSlice(),613 .link_objects = link_objects.toOwnedSlice(),
610 .target_str = target_str,614 .target_str = target_str,
611 .link_libc = link_libc,615 .link_libc = link_libc,
616 .backend_stage1 = backend_stage1,
612 .link_mode = link_mode,617 .link_mode = link_mode,
613 .disable_cache = disable_cache,618 .disable_cache = disable_cache,
614 .verbose_cimport = verbose_cimport,619 .verbose_cimport = verbose_cimport,
...@@ -1187,6 +1192,9 @@ fn printShell(out: anytype, shell_content: []const u8) !void {...@@ -1187,6 +1192,9 @@ fn printShell(out: anytype, shell_content: []const u8) !void {
1187 try out.writeAll("</samp></pre></figure>");1192 try out.writeAll("</samp></pre></figure>");
1188}1193}
11891194
1195// Override this to skip to later tests
1196const debug_start_line = 0;
1197
1190fn genHtml(1198fn genHtml(
1191 allocator: Allocator,1199 allocator: Allocator,
1192 tokenizer: *Tokenizer,1200 tokenizer: *Tokenizer,
...@@ -1266,6 +1274,13 @@ fn genHtml(...@@ -1266,6 +1274,13 @@ fn genHtml(
1266 continue;1274 continue;
1267 }1275 }
12681276
1277 if (debug_start_line > 0) {
1278 const loc = tokenizer.getTokenLocation(code.source_token);
1279 if (debug_start_line > loc.line) {
1280 continue;
1281 }
1282 }
1283
1269 const raw_source = tokenizer.buffer[code.source_token.start..code.source_token.end];1284 const raw_source = tokenizer.buffer[code.source_token.start..code.source_token.end];
1270 const trimmed_raw_source = mem.trim(u8, raw_source, " \n");1285 const trimmed_raw_source = mem.trim(u8, raw_source, " \n");
1271 const tmp_source_file_name = try fs.path.join(1286 const tmp_source_file_name = try fs.path.join(
...@@ -1311,6 +1326,10 @@ fn genHtml(...@@ -1311,6 +1326,10 @@ fn genHtml(
1311 try build_args.append("-lc");1326 try build_args.append("-lc");
1312 try shell_out.print("-lc ", .{});1327 try shell_out.print("-lc ", .{});
1313 }1328 }
1329 if (code.backend_stage1) {
1330 try build_args.append("-fstage1");
1331 try shell_out.print("-fstage1", .{});
1332 }
1314 const target = try std.zig.CrossTarget.parse(.{1333 const target = try std.zig.CrossTarget.parse(.{
1315 .arch_os_abi = code.target_str orelse "native",1334 .arch_os_abi = code.target_str orelse "native",
1316 });1335 });
...@@ -1443,6 +1462,10 @@ fn genHtml(...@@ -1443,6 +1462,10 @@ fn genHtml(
1443 try test_args.append("-lc");1462 try test_args.append("-lc");
1444 try shell_out.print("-lc ", .{});1463 try shell_out.print("-lc ", .{});
1445 }1464 }
1465 if (code.backend_stage1) {
1466 try test_args.append("-fstage1");
1467 try shell_out.print("-fstage1", .{});
1468 }
1446 if (code.target_str) |triple| {1469 if (code.target_str) |triple| {
1447 try test_args.appendSlice(&[_][]const u8{ "-target", triple });1470 try test_args.appendSlice(&[_][]const u8{ "-target", triple });
1448 try shell_out.print("-target {s} ", .{triple});1471 try shell_out.print("-target {s} ", .{triple});
...@@ -1490,6 +1513,14 @@ fn genHtml(...@@ -1490,6 +1513,14 @@ fn genHtml(
1490 try shell_out.print("-O {s} ", .{@tagName(code.mode)});1513 try shell_out.print("-O {s} ", .{@tagName(code.mode)});
1491 },1514 },
1492 }1515 }
1516 if (code.link_libc) {
1517 try test_args.append("-lc");
1518 try shell_out.print("-lc ", .{});
1519 }
1520 if (code.backend_stage1) {
1521 try test_args.append("-fstage1");
1522 try shell_out.print("-fstage1", .{});
1523 }
1493 const result = try ChildProcess.exec(.{1524 const result = try ChildProcess.exec(.{
1494 .allocator = allocator,1525 .allocator = allocator,
1495 .argv = test_args.items,1526 .argv = test_args.items,
doc/langref.html.in+87-126
...@@ -535,8 +535,8 @@ const Timestamp = struct {...@@ -535,8 +535,8 @@ const Timestamp = struct {
535 {#header_close#}535 {#header_close#}
536 {#header_open|Top-Level Doc Comments#}536 {#header_open|Top-Level Doc Comments#}
537 <p>User documentation that doesn't belong to whatever537 <p>User documentation that doesn't belong to whatever
538 immediately follows it, like container level documentation, goes538 immediately follows it, like container-level documentation, goes
539 in top level doc comments. A top level doc comment is one that539 in top-level doc comments. A top-level doc comment is one that
540 begins with two slashes and an exclamation point:540 begins with two slashes and an exclamation point:
541 {#syntax#}//!{#endsyntax#}.</p>541 {#syntax#}//!{#endsyntax#}.</p>
542 {#code_begin|syntax|tldoc_comments#}542 {#code_begin|syntax|tldoc_comments#}
...@@ -1188,6 +1188,7 @@ test "this will be skipped" {...@@ -1188,6 +1188,7 @@ test "this will be skipped" {
1188 (The evented IO mode is enabled using the <kbd>--test-evented-io</kbd> command line parameter.)1188 (The evented IO mode is enabled using the <kbd>--test-evented-io</kbd> command line parameter.)
1189 </p>1189 </p>
1190 {#code_begin|test|async_skip#}1190 {#code_begin|test|async_skip#}
1191 {#backend_stage1#}
1191const std = @import("std");1192const std = @import("std");
11921193
1193test "async skip test" {1194test "async skip test" {
...@@ -1520,7 +1521,8 @@ fn divide(a: i32, b: i32) i32 {...@@ -1520,7 +1521,8 @@ fn divide(a: i32, b: i32) i32 {
1520 Zig supports arbitrary bit-width integers, referenced by using1521 Zig supports arbitrary bit-width integers, referenced by using
1521 an identifier of <code>i</code> or <code>u</code> followed by digits. For example, the identifier1522 an identifier of <code>i</code> or <code>u</code> followed by digits. For example, the identifier
1522 {#syntax#}i7{#endsyntax#} refers to a signed 7-bit integer. The maximum allowed bit-width of an1523 {#syntax#}i7{#endsyntax#} refers to a signed 7-bit integer. The maximum allowed bit-width of an
1523 integer type is {#syntax#}65535{#endsyntax#}.1524 integer type is {#syntax#}65535{#endsyntax#}. For signed integer types, Zig uses a
1525 <a href="https://en.wikipedia.org/wiki/Two's_complement">two's complement</a> representation.
1524 </p>1526 </p>
1525 {#see_also|Wrapping Operations#}1527 {#see_also|Wrapping Operations#}
1526 {#header_close#}1528 {#header_close#}
...@@ -2768,7 +2770,7 @@ test "comptime @intToPtr" {...@@ -2768,7 +2770,7 @@ test "comptime @intToPtr" {
2768 }2770 }
2769}2771}
2770 {#code_end#}2772 {#code_end#}
2771 {#see_also|Optional Pointers|@intToPtr|@ptrToInt|C Pointers|Pointers to Zero Bit Types#}2773 {#see_also|Optional Pointers|@intToPtr|@ptrToInt|C Pointers#}
2772 {#header_open|volatile#}2774 {#header_open|volatile#}
2773 <p>Loads and stores are assumed to not have side effects. If a given load or store2775 <p>Loads and stores are assumed to not have side effects. If a given load or store
2774 should have side effects, such as Memory Mapped Input/Output (MMIO), use {#syntax#}volatile{#endsyntax#}.2776 should have side effects, such as Memory Mapped Input/Output (MMIO), use {#syntax#}volatile{#endsyntax#}.
...@@ -2862,19 +2864,22 @@ var foo: u8 align(4) = 100;...@@ -2862,19 +2864,22 @@ var foo: u8 align(4) = 100;
2862test "global variable alignment" {2864test "global variable alignment" {
2863 try expect(@typeInfo(@TypeOf(&foo)).Pointer.alignment == 4);2865 try expect(@typeInfo(@TypeOf(&foo)).Pointer.alignment == 4);
2864 try expect(@TypeOf(&foo) == *align(4) u8);2866 try expect(@TypeOf(&foo) == *align(4) u8);
2865 const as_pointer_to_array: *[1]u8 = &foo;2867 const as_pointer_to_array: *align(4) [1]u8 = &foo;
2866 const as_slice: []u8 = as_pointer_to_array;2868 const as_slice: []align(4) u8 = as_pointer_to_array;
2867 try expect(@TypeOf(as_slice) == []align(4) u8);2869 const as_unaligned_slice: []u8 = as_slice;
2870 try expect(as_unaligned_slice[0] == 100);
2868}2871}
28692872
2870fn derp() align(@sizeOf(usize) * 2) i32 { return 1234; }2873fn derp() align(@sizeOf(usize) * 2) i32 {
2874 return 1234;
2875}
2871fn noop1() align(1) void {}2876fn noop1() align(1) void {}
2872fn noop4() align(4) void {}2877fn noop4() align(4) void {}
28732878
2874test "function alignment" {2879test "function alignment" {
2875 try expect(derp() == 1234);2880 try expect(derp() == 1234);
2876 try expect(@TypeOf(noop1) == fn() align(1) void);2881 try expect(@TypeOf(noop1) == fn () align(1) void);
2877 try expect(@TypeOf(noop4) == fn() align(4) void);2882 try expect(@TypeOf(noop4) == fn () align(4) void);
2878 noop1();2883 noop1();
2879 noop4();2884 noop4();
2880}2885}
...@@ -3336,6 +3341,7 @@ fn doTheTest() !void {...@@ -3336,6 +3341,7 @@ fn doTheTest() !void {
3336 Zig allows the address to be taken of a non-byte-aligned field:3341 Zig allows the address to be taken of a non-byte-aligned field:
3337 </p>3342 </p>
3338 {#code_begin|test|pointer_to_non-byte_aligned_field#}3343 {#code_begin|test|pointer_to_non-byte_aligned_field#}
3344 {#backend_stage1#}
3339const std = @import("std");3345const std = @import("std");
3340const expect = std.testing.expect;3346const expect = std.testing.expect;
33413347
...@@ -3391,7 +3397,8 @@ fn bar(x: *const u3) u3 {...@@ -3391,7 +3397,8 @@ fn bar(x: *const u3) u3 {
3391 <p>3397 <p>
3392 Pointers to non-ABI-aligned fields share the same address as the other fields within their host integer:3398 Pointers to non-ABI-aligned fields share the same address as the other fields within their host integer:
3393 </p>3399 </p>
3394 {#code_begin|test|pointer_to_non-bit_aligned_field#}3400 {#code_begin|test|packed_struct_field_addrs#}
3401 {#backend_stage1#}
3395const std = @import("std");3402const std = @import("std");
3396const expect = std.testing.expect;3403const expect = std.testing.expect;
33973404
...@@ -3407,7 +3414,7 @@ var bit_field = BitField{...@@ -3407,7 +3414,7 @@ var bit_field = BitField{
3407 .c = 3,3414 .c = 3,
3408};3415};
34093416
3410test "pointer to non-bit-aligned field" {3417test "pointers of sub-byte-aligned fields share addresses" {
3411 try expect(@ptrToInt(&bit_field.a) == @ptrToInt(&bit_field.b));3418 try expect(@ptrToInt(&bit_field.a) == @ptrToInt(&bit_field.b));
3412 try expect(@ptrToInt(&bit_field.a) == @ptrToInt(&bit_field.c));3419 try expect(@ptrToInt(&bit_field.a) == @ptrToInt(&bit_field.c));
3413}3420}
...@@ -3438,20 +3445,22 @@ test "pointer to non-bit-aligned field" {...@@ -3438,20 +3445,22 @@ test "pointer to non-bit-aligned field" {
3438}3445}
3439 {#code_end#}3446 {#code_end#}
3440 <p>3447 <p>
3441 Packed structs have 1-byte alignment. However if you have an overaligned pointer to a packed struct,3448 Packed structs have the same alignment as their backing integer, however, overaligned
3442 Zig should correctly understand the alignment of fields. However there is3449 pointers to packed structs can override this:
3443 <a href="https://github.com/ziglang/zig/issues/1994">a bug</a>:
3444 </p>3450 </p>
3445 {#code_begin|test_err|expected type '*u32', found '*align(1) u32'#}3451 {#code_begin|test|overaligned_packed_struct#}
3452const std = @import("std");
3453const expect = std.testing.expect;
3454
3446const S = packed struct {3455const S = packed struct {
3447 a: u32,3456 a: u32,
3448 b: u32,3457 b: u32,
3449};3458};
3450test "overaligned pointer to packed struct" {3459test "overaligned pointer to packed struct" {
3451 var foo: S align(4) = undefined;3460 var foo: S align(4) = .{ .a = 1, .b = 2 };
3452 const ptr: *align(4) S = &foo;3461 const ptr: *align(4) S = &foo;
3453 const ptr_to_b: *u32 = &ptr.b;3462 const ptr_to_b: *u32 = &ptr.b;
3454 _ = ptr_to_b;3463 try expect(ptr_to_b.* == 2);
3455}3464}
3456 {#code_end#}3465 {#code_end#}
3457 <p>When this bug is fixed, the above test in the documentation will unexpectedly pass, which will3466 <p>When this bug is fixed, the above test in the documentation will unexpectedly pass, which will
...@@ -3698,7 +3707,7 @@ test "@tagName" {...@@ -3698,7 +3707,7 @@ test "@tagName" {
3698 <p>3707 <p>
3699 By default, enums are not guaranteed to be compatible with the C ABI:3708 By default, enums are not guaranteed to be compatible with the C ABI:
3700 </p>3709 </p>
3701 {#code_begin|obj_err|parameter of type 'Foo' not allowed in function with calling convention 'C'#}3710 {#code_begin|obj_err|parameter of type 'test.Foo' not allowed in function with calling convention 'C'#}
3702const Foo = enum { a, b, c };3711const Foo = enum { a, b, c };
3703export fn entry(foo: Foo) void { _ = foo; }3712export fn entry(foo: Foo) void { _ = foo; }
3704 {#code_end#}3713 {#code_end#}
...@@ -4004,7 +4013,7 @@ fn makeNumber() Number {...@@ -4004,7 +4013,7 @@ fn makeNumber() Number {
4004 This is typically used for type safety when interacting with C code that does not expose struct details.4013 This is typically used for type safety when interacting with C code that does not expose struct details.
4005 Example:4014 Example:
4006 </p>4015 </p>
4007 {#code_begin|test_err|expected type '*Derp', found '*Wat'#}4016 {#code_begin|test_err|expected type '*test.Derp', found '*test.Wat'#}
4008const Derp = opaque {};4017const Derp = opaque {};
4009const Wat = opaque {};4018const Wat = opaque {};
40104019
...@@ -4203,7 +4212,7 @@ test "switch on tagged union" {...@@ -4203,7 +4212,7 @@ test "switch on tagged union" {
4203 When a {#syntax#}switch{#endsyntax#} expression does not have an {#syntax#}else{#endsyntax#} clause,4212 When a {#syntax#}switch{#endsyntax#} expression does not have an {#syntax#}else{#endsyntax#} clause,
4204 it must exhaustively list all the possible values. Failure to do so is a compile error:4213 it must exhaustively list all the possible values. Failure to do so is a compile error:
4205 </p>4214 </p>
4206 {#code_begin|test_err|not handled in switch#}4215 {#code_begin|test_err|unhandled enumeration value#}
4207const Color = enum {4216const Color = enum {
4208 auto,4217 auto,
4209 off,4218 off,
...@@ -5015,8 +5024,8 @@ fn shiftLeftOne(a: u32) callconv(.Inline) u32 {...@@ -5015,8 +5024,8 @@ fn shiftLeftOne(a: u32) callconv(.Inline) u32 {
5015// Another file can use @import and call sub25024// Another file can use @import and call sub2
5016pub fn sub2(a: i8, b: i8) i8 { return a - b; }5025pub fn sub2(a: i8, b: i8) i8 { return a - b; }
50175026
5018// Functions can be used as values and are equivalent to pointers.5027// Function pointers are prefixed with `*const `.
5019const call2_op = fn (a: i8, b: i8) i8;5028const call2_op = *const fn (a: i8, b: i8) i8;
5020fn do_op(fn_call: call2_op, op1: i8, op2: i8) i8 {5029fn do_op(fn_call: call2_op, op1: i8, op2: i8) i8 {
5021 return fn_call(op1, op2);5030 return fn_call(op1, op2);
5022}5031}
...@@ -5026,17 +5035,9 @@ test "function" {...@@ -5026,17 +5035,9 @@ test "function" {
5026 try expect(do_op(sub2, 5, 6) == -1);5035 try expect(do_op(sub2, 5, 6) == -1);
5027}5036}
5028 {#code_end#}5037 {#code_end#}
5029 <p>Function values are like pointers:</p>5038 <p>There is a difference between a function <em>body</em> and a function <em>pointer</em>.
5030 {#code_begin|obj#}5039 Function bodies are {#link|comptime#}-only types while function {#link|Pointers#} may be
5031const assert = @import("std").debug.assert;5040 runtime-known.</p>
5032
5033comptime {
5034 assert(@TypeOf(foo) == fn()void);
5035 assert(@sizeOf(fn()void) == @sizeOf(?fn()void));
5036}
5037
5038fn foo() void { }
5039 {#code_end#}
5040 {#header_open|Pass-by-value Parameters#}5041 {#header_open|Pass-by-value Parameters#}
5041 <p>5042 <p>
5042 Primitive types such as {#link|Integers#} and {#link|Floats#} passed as parameters5043 Primitive types such as {#link|Integers#} and {#link|Floats#} passed as parameters
...@@ -6123,10 +6124,11 @@ test "float widening" {...@@ -6123,10 +6124,11 @@ test "float widening" {
6123 two choices about the coercion.6124 two choices about the coercion.
6124 </p>6125 </p>
6125 <ul>6126 <ul>
6126 <li> Cast {#syntax#}54.0{#endsyntax#} to {#syntax#}comptime_int{#endsyntax#} resulting in {#syntax#}@as(comptime_int, 10){#endsyntax#}, which is casted to {#syntax#}@as(f32, 10){#endsyntax#}</li>6127 <li>Cast {#syntax#}54.0{#endsyntax#} to {#syntax#}comptime_int{#endsyntax#} resulting in {#syntax#}@as(comptime_int, 10){#endsyntax#}, which is casted to {#syntax#}@as(f32, 10){#endsyntax#}</li>
6127 <li> Cast {#syntax#}5{#endsyntax#} to {#syntax#}comptime_float{#endsyntax#} resulting in {#syntax#}@as(comptime_float, 10.8){#endsyntax#}, which is casted to {#syntax#}@as(f32, 10.8){#endsyntax#}</li>6128 <li>Cast {#syntax#}5{#endsyntax#} to {#syntax#}comptime_float{#endsyntax#} resulting in {#syntax#}@as(comptime_float, 10.8){#endsyntax#}, which is casted to {#syntax#}@as(f32, 10.8){#endsyntax#}</li>
6128 </ul>6129 </ul>
6129 {#code_begin|test_err#}6130 {#code_begin|test_err#}
6131 {#backend_stage1#}
6130// Compile time coercion of float to int6132// Compile time coercion of float to int
6131test "implicit cast to comptime_int" {6133test "implicit cast to comptime_int" {
6132 var f: f32 = 54.0 / 5;6134 var f: f32 = 54.0 / 5;
...@@ -6302,19 +6304,6 @@ test "coercion between unions and enums" {...@@ -6302,19 +6304,6 @@ test "coercion between unions and enums" {
6302 {#code_end#}6304 {#code_end#}
6303 {#see_also|union|enum#}6305 {#see_also|union|enum#}
6304 {#header_close#}6306 {#header_close#}
6305 {#header_open|Type Coercion: Zero Bit Types#}
6306 <p>{#link|Zero Bit Types#} may be coerced to single-item {#link|Pointers#},
6307 regardless of const.</p>
6308 <p>TODO document the reasoning for this</p>
6309 <p>TODO document whether vice versa should work and why</p>
6310 {#code_begin|test|coerce_zero_bit_types#}
6311test "coercion of zero bit types" {
6312 var x: void = {};
6313 var y: *void = x;
6314 _ = y;
6315}
6316 {#code_end#}
6317 {#header_close#}
6318 {#header_open|Type Coercion: undefined#}6307 {#header_open|Type Coercion: undefined#}
6319 <p>{#link|undefined#} can be cast to any type.</p>6308 <p>{#link|undefined#} can be cast to any type.</p>
6320 {#header_close#}6309 {#header_close#}
...@@ -6467,7 +6456,6 @@ test "peer type resolution: *const T and ?*T" {...@@ -6467,7 +6456,6 @@ test "peer type resolution: *const T and ?*T" {
6467 <li>An {#link|enum#} with only 1 tag.</li>6456 <li>An {#link|enum#} with only 1 tag.</li>
6468 <li>A {#link|struct#} with all fields being zero bit types.</li>6457 <li>A {#link|struct#} with all fields being zero bit types.</li>
6469 <li>A {#link|union#} with only 1 field which is a zero bit type.</li>6458 <li>A {#link|union#} with only 1 field which is a zero bit type.</li>
6470 <li>{#link|Pointers to Zero Bit Types#} are themselves zero bit types.</li>
6471 </ul>6459 </ul>
6472 <p>6460 <p>
6473 These types can only ever have one possible value, and thus6461 These types can only ever have one possible value, and thus
...@@ -6527,7 +6515,7 @@ test "turn HashMap into a set with void" {...@@ -6527,7 +6515,7 @@ test "turn HashMap into a set with void" {
6527 <p>6515 <p>
6528 Expressions of type {#syntax#}void{#endsyntax#} are the only ones whose value can be ignored. For example:6516 Expressions of type {#syntax#}void{#endsyntax#} are the only ones whose value can be ignored. For example:
6529 </p>6517 </p>
6530 {#code_begin|test_err|expression value is ignored#}6518 {#code_begin|test_err|ignored#}
6531test "ignoring expression value" {6519test "ignoring expression value" {
6532 foo();6520 foo();
6533}6521}
...@@ -6553,37 +6541,6 @@ fn foo() i32 {...@@ -6553,37 +6541,6 @@ fn foo() i32 {
6553}6541}
6554 {#code_end#}6542 {#code_end#}
6555 {#header_close#}6543 {#header_close#}
6556
6557 {#header_open|Pointers to Zero Bit Types#}
6558 <p>Pointers to zero bit types also have zero bits. They always compare equal to each other:</p>
6559 {#code_begin|test|pointers_to_zero_bits#}
6560const std = @import("std");
6561const expect = std.testing.expect;
6562
6563test "pointer to empty struct" {
6564 const Empty = struct {};
6565 var a = Empty{};
6566 var b = Empty{};
6567 var ptr_a = &a;
6568 var ptr_b = &b;
6569 comptime try expect(ptr_a == ptr_b);
6570}
6571 {#code_end#}
6572 <p>The type being pointed to can only ever be one value; therefore loads and stores are
6573 never generated. {#link|ptrToInt#} and {#link|intToPtr#} are not allowed:</p>
6574 {#code_begin|test_err#}
6575const Empty = struct {};
6576
6577test "@ptrToInt for pointer to zero bit type" {
6578 var a = Empty{};
6579 _ = @ptrToInt(&a);
6580}
6581
6582test "@intToPtr for pointer to zero bit type" {
6583 _ = @intToPtr(*Empty, 0x1);
6584}
6585 {#code_end#}
6586 {#header_close#}
6587 {#header_close#}6544 {#header_close#}
65886545
6589 {#header_open|Result Location Semantics#}6546 {#header_open|Result Location Semantics#}
...@@ -6666,7 +6623,7 @@ fn gimmeTheBiggerInteger(a: u64, b: u64) u64 {...@@ -6666,7 +6623,7 @@ fn gimmeTheBiggerInteger(a: u64, b: u64) u64 {
6666 <p>6623 <p>
6667 For example, if we were to introduce another function to the above snippet:6624 For example, if we were to introduce another function to the above snippet:
6668 </p>6625 </p>
6669 {#code_begin|test_err|values of type 'type' must be comptime known#}6626 {#code_begin|test_err|unable to resolve comptime value#}
6670fn max(comptime T: type, a: T, b: T) T {6627fn max(comptime T: type, a: T, b: T) T {
6671 return if (a > b) a else b;6628 return if (a > b) a else b;
6672}6629}
...@@ -6692,7 +6649,7 @@ fn foo(condition: bool) void {...@@ -6692,7 +6649,7 @@ fn foo(condition: bool) void {
6692 <p>6649 <p>
6693 For example:6650 For example:
6694 </p>6651 </p>
6695 {#code_begin|test_err|operator not allowed for type 'bool'#}6652 {#code_begin|test_err|operator > not allowed for type 'bool'#}
6696fn max(comptime T: type, a: T, b: T) T {6653fn max(comptime T: type, a: T, b: T) T {
6697 return if (a > b) a else b;6654 return if (a > b) a else b;
6698}6655}
...@@ -6837,7 +6794,7 @@ fn performFn(start_value: i32) i32 {...@@ -6837,7 +6794,7 @@ fn performFn(start_value: i32) i32 {
6837 use a {#syntax#}comptime{#endsyntax#} expression to guarantee that the expression will be evaluated at compile-time.6794 use a {#syntax#}comptime{#endsyntax#} expression to guarantee that the expression will be evaluated at compile-time.
6838 If this cannot be accomplished, the compiler will emit an error. For example:6795 If this cannot be accomplished, the compiler will emit an error. For example:
6839 </p>6796 </p>
6840 {#code_begin|test_err|unable to evaluate constant expression#}6797 {#code_begin|test_err|comptime call of extern function#}
6841extern fn exit() noreturn;6798extern fn exit() noreturn;
68426799
6843test "foo" {6800test "foo" {
...@@ -6889,7 +6846,7 @@ test "fibonacci" {...@@ -6889,7 +6846,7 @@ test "fibonacci" {
6889 <p>6846 <p>
6890 Imagine if we had forgotten the base case of the recursive function and tried to run the tests:6847 Imagine if we had forgotten the base case of the recursive function and tried to run the tests:
6891 </p>6848 </p>
6892 {#code_begin|test_err|operation caused overflow#}6849 {#code_begin|test_err|overflow of integer type#}
6893const expect = @import("std").testing.expect;6850const expect = @import("std").testing.expect;
68946851
6895fn fibonacci(index: u32) u32 {6852fn fibonacci(index: u32) u32 {
...@@ -6913,7 +6870,8 @@ test "fibonacci" {...@@ -6913,7 +6870,8 @@ test "fibonacci" {
6913 But what would have happened if we used a signed integer?6870 But what would have happened if we used a signed integer?
6914 </p>6871 </p>
6915 {#code_begin|test_err|evaluation exceeded 1000 backwards branches#}6872 {#code_begin|test_err|evaluation exceeded 1000 backwards branches#}
6916const expect = @import("std").testing.expect;6873 {#backend_stage1#}
6874const assert = @import("std").debug.assert;
69176875
6918fn fibonacci(index: i32) i32 {6876fn fibonacci(index: i32) i32 {
6919 //if (index < 2) return index;6877 //if (index < 2) return index;
...@@ -6922,7 +6880,7 @@ fn fibonacci(index: i32) i32 {...@@ -6922,7 +6880,7 @@ fn fibonacci(index: i32) i32 {
69226880
6923test "fibonacci" {6881test "fibonacci" {
6924 comptime {6882 comptime {
6925 try expect(fibonacci(7) == 13);6883 try assert(fibonacci(7) == 13);
6926 }6884 }
6927}6885}
6928 {#code_end#}6886 {#code_end#}
...@@ -6935,8 +6893,8 @@ test "fibonacci" {...@@ -6935,8 +6893,8 @@ test "fibonacci" {
6935 <p>6893 <p>
6936 What if we fix the base case, but put the wrong value in the {#syntax#}expect{#endsyntax#} line?6894 What if we fix the base case, but put the wrong value in the {#syntax#}expect{#endsyntax#} line?
6937 </p>6895 </p>
6938 {#code_begin|test_err|test "fibonacci"... FAIL (TestUnexpectedResult)#}6896 {#code_begin|test_err|reached unreachable#}
6939const expect = @import("std").testing.expect;6897const assert = @import("std").debug.assert;
69406898
6941fn fibonacci(index: i32) i32 {6899fn fibonacci(index: i32) i32 {
6942 if (index < 2) return index;6900 if (index < 2) return index;
...@@ -6945,16 +6903,10 @@ fn fibonacci(index: i32) i32 {...@@ -6945,16 +6903,10 @@ fn fibonacci(index: i32) i32 {
69456903
6946test "fibonacci" {6904test "fibonacci" {
6947 comptime {6905 comptime {
6948 try expect(fibonacci(7) == 99999);6906 try assert(fibonacci(7) == 99999);
6949 }6907 }
6950}6908}
6951 {#code_end#}6909 {#code_end#}
6952 <p>
6953 What happened is Zig started interpreting the {#syntax#}expect{#endsyntax#} function with the
6954 parameter {#syntax#}ok{#endsyntax#} set to {#syntax#}false{#endsyntax#}. When the interpreter hit
6955 {#syntax#}@panic{#endsyntax#} it emitted a compile error because a panic during compile
6956 causes a compile error if it is detected at compile-time.
6957 </p>
69586910
6959 <p>6911 <p>
6960 At container level (outside of any function), all expressions are implicitly6912 At container level (outside of any function), all expressions are implicitly
...@@ -7280,6 +7232,7 @@ pub fn main() void {...@@ -7280,6 +7232,7 @@ pub fn main() void {
7280 </p>7232 </p>
7281 {#code_begin|exe#}7233 {#code_begin|exe#}
7282 {#target_linux_x86_64#}7234 {#target_linux_x86_64#}
7235 {#backend_stage1#}
7283pub fn main() noreturn {7236pub fn main() noreturn {
7284 const msg = "hello world\n";7237 const msg = "hello world\n";
7285 _ = syscall3(SYS_write, STDOUT_FILENO, @ptrToInt(msg), msg.len);7238 _ = syscall3(SYS_write, STDOUT_FILENO, @ptrToInt(msg), msg.len);
...@@ -7497,6 +7450,7 @@ test "global assembly" {...@@ -7497,6 +7450,7 @@ test "global assembly" {
7497 or resumer (in the case of subsequent suspensions).7450 or resumer (in the case of subsequent suspensions).
7498 </p>7451 </p>
7499 {#code_begin|test|suspend_no_resume#}7452 {#code_begin|test|suspend_no_resume#}
7453 {#backend_stage1#}
7500const std = @import("std");7454const std = @import("std");
7501const expect = std.testing.expect;7455const expect = std.testing.expect;
75027456
...@@ -7524,6 +7478,7 @@ fn func() void {...@@ -7524,6 +7478,7 @@ fn func() void {
7524 {#link|@frame#} provides access to the async function frame pointer.7478 {#link|@frame#} provides access to the async function frame pointer.
7525 </p>7479 </p>
7526 {#code_begin|test|async_suspend_block#}7480 {#code_begin|test|async_suspend_block#}
7481 {#backend_stage1#}
7527const std = @import("std");7482const std = @import("std");
7528const expect = std.testing.expect;7483const expect = std.testing.expect;
75297484
...@@ -7562,6 +7517,7 @@ fn testSuspendBlock() void {...@@ -7562,6 +7517,7 @@ fn testSuspendBlock() void {
7562 never returns to its resumer and continues executing.7517 never returns to its resumer and continues executing.
7563 </p>7518 </p>
7564 {#code_begin|test|resume_from_suspend#}7519 {#code_begin|test|resume_from_suspend#}
7520 {#backend_stage1#}
7565const std = @import("std");7521const std = @import("std");
7566const expect = std.testing.expect;7522const expect = std.testing.expect;
75677523
...@@ -7598,6 +7554,7 @@ fn testResumeFromSuspend(my_result: *i32) void {...@@ -7598,6 +7554,7 @@ fn testResumeFromSuspend(my_result: *i32) void {
7598 and the return value of the async function would be lost.7554 and the return value of the async function would be lost.
7599 </p>7555 </p>
7600 {#code_begin|test|async_await#}7556 {#code_begin|test|async_await#}
7557 {#backend_stage1#}
7601const std = @import("std");7558const std = @import("std");
7602const expect = std.testing.expect;7559const expect = std.testing.expect;
76037560
...@@ -7642,6 +7599,7 @@ fn func() void {...@@ -7642,6 +7599,7 @@ fn func() void {
7642 return value directly from the target function's frame.7599 return value directly from the target function's frame.
7643 </p>7600 </p>
7644 {#code_begin|test|async_await_sequence#}7601 {#code_begin|test|async_await_sequence#}
7602 {#backend_stage1#}
7645const std = @import("std");7603const std = @import("std");
7646const expect = std.testing.expect;7604const expect = std.testing.expect;
76477605
...@@ -7695,6 +7653,7 @@ fn seq(c: u8) void {...@@ -7695,6 +7653,7 @@ fn seq(c: u8) void {
7695 {#syntax#}async{#endsyntax#}/{#syntax#}await{#endsyntax#} usage:7653 {#syntax#}async{#endsyntax#}/{#syntax#}await{#endsyntax#} usage:
7696 </p>7654 </p>
7697 {#code_begin|exe|async#}7655 {#code_begin|exe|async#}
7656 {#backend_stage1#}
7698const std = @import("std");7657const std = @import("std");
7699const Allocator = std.mem.Allocator;7658const Allocator = std.mem.Allocator;
77007659
...@@ -7773,6 +7732,7 @@ fn readFile(allocator: Allocator, filename: []const u8) ![]u8 {...@@ -7773,6 +7732,7 @@ fn readFile(allocator: Allocator, filename: []const u8) ![]u8 {
7773 observe the same behavior, with one tiny difference:7732 observe the same behavior, with one tiny difference:
7774 </p>7733 </p>
7775 {#code_begin|exe|blocking#}7734 {#code_begin|exe|blocking#}
7735 {#backend_stage1#}
7776const std = @import("std");7736const std = @import("std");
7777const Allocator = std.mem.Allocator;7737const Allocator = std.mem.Allocator;
77787738
...@@ -7910,6 +7870,7 @@ comptime {...@@ -7910,6 +7870,7 @@ comptime {
7910 {#syntax#}await{#endsyntax#} will copy the result from {#syntax#}result_ptr{#endsyntax#}.7870 {#syntax#}await{#endsyntax#} will copy the result from {#syntax#}result_ptr{#endsyntax#}.
7911 </p>7871 </p>
7912 {#code_begin|test|async_struct_field_fn_pointer#}7872 {#code_begin|test|async_struct_field_fn_pointer#}
7873 {#backend_stage1#}
7913const std = @import("std");7874const std = @import("std");
7914const expect = std.testing.expect;7875const expect = std.testing.expect;
79157876
...@@ -8071,8 +8032,8 @@ fn func(y: *i32) void {...@@ -8071,8 +8032,8 @@ fn func(y: *i32) void {
8071 {#header_close#}8032 {#header_close#}
80728033
8073 {#header_open|@byteSwap#}8034 {#header_open|@byteSwap#}
8074 <pre>{#syntax#}@byteSwap(comptime T: type, operand: T) T{#endsyntax#}</pre>8035 <pre>{#syntax#}@byteSwap(operand: anytype) T{#endsyntax#}</pre>
8075 <p>{#syntax#}T{#endsyntax#} must be an integer type with bit count evenly divisible by 8.</p>8036 <p>{#syntax#}@TypeOf(operand){#endsyntax#} must be an integer type or an integer vector type with bit count evenly divisible by 8.</p>
8076 <p>{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.</p>8037 <p>{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.</p>
8077 <p>8038 <p>
8078 Swaps the byte order of the integer. This converts a big endian integer to a little endian integer,8039 Swaps the byte order of the integer. This converts a big endian integer to a little endian integer,
...@@ -8089,8 +8050,8 @@ fn func(y: *i32) void {...@@ -8089,8 +8050,8 @@ fn func(y: *i32) void {
8089 {#header_close#}8050 {#header_close#}
80908051
8091 {#header_open|@bitReverse#}8052 {#header_open|@bitReverse#}
8092 <pre>{#syntax#}@bitReverse(comptime T: type, integer: T) T{#endsyntax#}</pre>8053 <pre>{#syntax#}@bitReverse(integer: anytype) T{#endsyntax#}</pre>
8093 <p>{#syntax#}T{#endsyntax#} accepts any integer type.</p>8054 <p>{#syntax#}@TypeOf(anytype){#endsyntax#} accepts any integer type or integer vector type.</p>
8094 <p>8055 <p>
8095 Reverses the bitpattern of an integer value, including the sign bit if applicable.8056 Reverses the bitpattern of an integer value, including the sign bit if applicable.
8096 </p>8057 </p>
...@@ -8229,8 +8190,8 @@ pub const CallOptions = struct {...@@ -8229,8 +8190,8 @@ pub const CallOptions = struct {
8229 {#header_close#}8190 {#header_close#}
82308191
8231 {#header_open|@clz#}8192 {#header_open|@clz#}
8232 <pre>{#syntax#}@clz(comptime T: type, operand: T){#endsyntax#}</pre>8193 <pre>{#syntax#}@clz(operand: anytype){#endsyntax#}</pre>
8233 <p>{#syntax#}T{#endsyntax#} must be an integer type.</p>8194 <p>{#syntax#}@TypeOf(operand){#endsyntax#} must be an integer type or an integer vector type.</p>
8234 <p>{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.</p>8195 <p>{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.</p>
8235 <p>8196 <p>
8236 This function counts the number of most-significant (leading in a big-Endian sense) zeroes in an integer.8197 This function counts the number of most-significant (leading in a big-Endian sense) zeroes in an integer.
...@@ -8375,8 +8336,8 @@ test "main" {...@@ -8375,8 +8336,8 @@ test "main" {
8375 {#header_close#}8336 {#header_close#}
83768337
8377 {#header_open|@ctz#}8338 {#header_open|@ctz#}
8378 <pre>{#syntax#}@ctz(comptime T: type, operand: T){#endsyntax#}</pre>8339 <pre>{#syntax#}@ctz(operand: anytype){#endsyntax#}</pre>
8379 <p>{#syntax#}T{#endsyntax#} must be an integer type.</p>8340 <p>{#syntax#}@TypeOf(operand){#endsyntax#} must be an integer type or an integer vector type.</p>
8380 <p>{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.</p>8341 <p>{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.</p>
8381 <p>8342 <p>
8382 This function counts the number of least-significant (trailing in a big-Endian sense) zeroes in an integer.8343 This function counts the number of least-significant (trailing in a big-Endian sense) zeroes in an integer.
...@@ -8677,6 +8638,7 @@ test "decl access by string" {...@@ -8677,6 +8638,7 @@ test "decl access by string" {
8677 allows one to, for example, heap-allocate an async function frame:8638 allows one to, for example, heap-allocate an async function frame:
8678 </p>8639 </p>
8679 {#code_begin|test|heap_allocated_frame#}8640 {#code_begin|test|heap_allocated_frame#}
8641 {#backend_stage1#}
8680const std = @import("std");8642const std = @import("std");
86818643
8682test "heap allocated frame" {8644test "heap allocated frame" {
...@@ -9011,8 +8973,8 @@ test "@wasmMemoryGrow" {...@@ -9011,8 +8973,8 @@ test "@wasmMemoryGrow" {
9011 {#header_close#}8973 {#header_close#}
90128974
9013 {#header_open|@popCount#}8975 {#header_open|@popCount#}
9014 <pre>{#syntax#}@popCount(comptime T: type, operand: T){#endsyntax#}</pre>8976 <pre>{#syntax#}@popCount(operand: anytype){#endsyntax#}</pre>
9015 <p>{#syntax#}T{#endsyntax#} must be an integer type.</p>8977 <p>{#syntax#}@TypeOf(operand){#endsyntax#} must be an integer type.</p>
9016 <p>{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.</p>8978 <p>{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.</p>
9017 <p>Counts the number of bits set in an integer.</p>8979 <p>Counts the number of bits set in an integer.</p>
9018 <p>8980 <p>
...@@ -9423,12 +9385,6 @@ const std = @import("std");...@@ -9423,12 +9385,6 @@ const std = @import("std");
9423const expect = std.testing.expect;9385const expect = std.testing.expect;
94249386
9425test "vector @reduce" {9387test "vector @reduce" {
9426 // This test regressed with LLVM 14:
9427 // https://github.com/llvm/llvm-project/issues/55522
9428 // We'll skip this test unless the self-hosted compiler is being used.
9429 // After LLVM 15 is released we can delete this line.
9430 if (@import("builtin").zig_backend == .stage1) return;
9431
9432 const value = @Vector(4, i32){ 1, -1, 1, -1 };9388 const value = @Vector(4, i32){ 1, -1, 1, -1 };
9433 const result = value > @splat(4, @as(i32, 0));9389 const result = value > @splat(4, @as(i32, 0));
9434 // result is { true, false, true, false };9390 // result is { true, false, true, false };
...@@ -9938,7 +9894,7 @@ pub fn main() void {...@@ -9938,7 +9894,7 @@ pub fn main() void {
9938 {#header_close#}9894 {#header_close#}
9939 {#header_open|Index out of Bounds#}9895 {#header_open|Index out of Bounds#}
9940 <p>At compile-time:</p>9896 <p>At compile-time:</p>
9941 {#code_begin|test_err|index 5 outside array of size 5#}9897 {#code_begin|test_err|index 5 outside array of length 5#}
9942comptime {9898comptime {
9943 const array: [5]u8 = "hello".*;9899 const array: [5]u8 = "hello".*;
9944 const garbage = array[5];9900 const garbage = array[5];
...@@ -9959,9 +9915,9 @@ fn foo(x: []const u8) u8 {...@@ -9959,9 +9915,9 @@ fn foo(x: []const u8) u8 {
9959 {#header_close#}9915 {#header_close#}
9960 {#header_open|Cast Negative Number to Unsigned Integer#}9916 {#header_open|Cast Negative Number to Unsigned Integer#}
9961 <p>At compile-time:</p>9917 <p>At compile-time:</p>
9962 {#code_begin|test_err|attempt to cast negative value to unsigned integer#}9918 {#code_begin|test_err|type 'u32' cannot represent integer value '-1'#}
9963comptime {9919comptime {
9964 const value: i32 = -1;9920 var value: i32 = -1;
9965 const unsigned = @intCast(u32, value);9921 const unsigned = @intCast(u32, value);
9966 _ = unsigned;9922 _ = unsigned;
9967}9923}
...@@ -9982,7 +9938,7 @@ pub fn main() void {...@@ -9982,7 +9938,7 @@ pub fn main() void {
9982 {#header_close#}9938 {#header_close#}
9983 {#header_open|Cast Truncates Data#}9939 {#header_open|Cast Truncates Data#}
9984 <p>At compile-time:</p>9940 <p>At compile-time:</p>
9985 {#code_begin|test_err|cast from 'u16' to 'u8' truncates bits#}9941 {#code_begin|test_err|type 'u8' cannot represent integer value '300'#}
9986comptime {9942comptime {
9987 const spartan_count: u16 = 300;9943 const spartan_count: u16 = 300;
9988 const byte = @intCast(u8, spartan_count);9944 const byte = @intCast(u8, spartan_count);
...@@ -10017,7 +9973,7 @@ pub fn main() void {...@@ -10017,7 +9973,7 @@ pub fn main() void {
10017 <li>{#link|@divExact#} (division)</li>9973 <li>{#link|@divExact#} (division)</li>
10018 </ul>9974 </ul>
10019 <p>Example with addition at compile-time:</p>9975 <p>Example with addition at compile-time:</p>
10020 {#code_begin|test_err|operation caused overflow#}9976 {#code_begin|test_err|overflow of integer type 'u8' with value '256'#}
10021comptime {9977comptime {
10022 var byte: u8 = 255;9978 var byte: u8 = 255;
10023 byte += 1;9979 byte += 1;
...@@ -10118,6 +10074,7 @@ test "wraparound addition and subtraction" {...@@ -10118,6 +10074,7 @@ test "wraparound addition and subtraction" {
10118 {#header_open|Exact Left Shift Overflow#}10074 {#header_open|Exact Left Shift Overflow#}
10119 <p>At compile-time:</p>10075 <p>At compile-time:</p>
10120 {#code_begin|test_err|operation caused overflow#}10076 {#code_begin|test_err|operation caused overflow#}
10077 {#backend_stage1#}
10121comptime {10078comptime {
10122 const x = @shlExact(@as(u8, 0b01010101), 2);10079 const x = @shlExact(@as(u8, 0b01010101), 2);
10123 _ = x;10080 _ = x;
...@@ -10137,6 +10094,7 @@ pub fn main() void {...@@ -10137,6 +10094,7 @@ pub fn main() void {
10137 {#header_open|Exact Right Shift Overflow#}10094 {#header_open|Exact Right Shift Overflow#}
10138 <p>At compile-time:</p>10095 <p>At compile-time:</p>
10139 {#code_begin|test_err|exact shift shifted out 1 bits#}10096 {#code_begin|test_err|exact shift shifted out 1 bits#}
10097 {#backend_stage1#}
10140comptime {10098comptime {
10141 const x = @shrExact(@as(u8, 0b10101010), 2);10099 const x = @shrExact(@as(u8, 0b10101010), 2);
10142 _ = x;10100 _ = x;
...@@ -10200,6 +10158,7 @@ pub fn main() void {...@@ -10200,6 +10158,7 @@ pub fn main() void {
10200 {#header_open|Exact Division Remainder#}10158 {#header_open|Exact Division Remainder#}
10201 <p>At compile-time:</p>10159 <p>At compile-time:</p>
10202 {#code_begin|test_err|exact division had a remainder#}10160 {#code_begin|test_err|exact division had a remainder#}
10161 {#backend_stage1#}
10203comptime {10162comptime {
10204 const a: u32 = 10;10163 const a: u32 = 10;
10205 const b: u32 = 3;10164 const b: u32 = 3;
...@@ -10302,7 +10261,7 @@ fn getNumberOrFail() !i32 {...@@ -10302,7 +10261,7 @@ fn getNumberOrFail() !i32 {
10302 {#header_close#}10261 {#header_close#}
10303 {#header_open|Invalid Error Code#}10262 {#header_open|Invalid Error Code#}
10304 <p>At compile-time:</p>10263 <p>At compile-time:</p>
10305 {#code_begin|test_err|integer value 11 represents no error#}10264 {#code_begin|test_err|integer value '11' represents no error#}
10306comptime {10265comptime {
10307 const err = error.AnError;10266 const err = error.AnError;
10308 const number = @errorToInt(err) + 10;10267 const number = @errorToInt(err) + 10;
...@@ -10324,7 +10283,7 @@ pub fn main() void {...@@ -10324,7 +10283,7 @@ pub fn main() void {
10324 {#header_close#}10283 {#header_close#}
10325 {#header_open|Invalid Enum Cast#}10284 {#header_open|Invalid Enum Cast#}
10326 <p>At compile-time:</p>10285 <p>At compile-time:</p>
10327 {#code_begin|test_err|has no tag matching integer value 3#}10286 {#code_begin|test_err|enum 'test.Foo' has no tag with value '3'#}
10328const Foo = enum {10287const Foo = enum {
10329 a,10288 a,
10330 b,10289 b,
...@@ -10356,7 +10315,7 @@ pub fn main() void {...@@ -10356,7 +10315,7 @@ pub fn main() void {
1035610315
10357 {#header_open|Invalid Error Set Cast#}10316 {#header_open|Invalid Error Set Cast#}
10358 <p>At compile-time:</p>10317 <p>At compile-time:</p>
10359 {#code_begin|test_err|error.B not a member of error set 'Set2'#}10318 {#code_begin|test_err|'error.B' not a member of error set 'error{A,C}'#}
10360const Set1 = error{10319const Set1 = error{
10361 A,10320 A,
10362 B,10321 B,
...@@ -10417,7 +10376,7 @@ fn foo(bytes: []u8) u32 {...@@ -10417,7 +10376,7 @@ fn foo(bytes: []u8) u32 {
10417 {#header_close#}10376 {#header_close#}
10418 {#header_open|Wrong Union Field Access#}10377 {#header_open|Wrong Union Field Access#}
10419 <p>At compile-time:</p>10378 <p>At compile-time:</p>
10420 {#code_begin|test_err|accessing union field 'float' while field 'int' is set#}10379 {#code_begin|test_err|access of union field 'float' while field 'int' is active#}
10421comptime {10380comptime {
10422 var f = Foo{ .int = 42 };10381 var f = Foo{ .int = 42 };
10423 f.float = 12.34;10382 f.float = 12.34;
...@@ -10509,6 +10468,7 @@ fn bar(f: *Foo) void {...@@ -10509,6 +10468,7 @@ fn bar(f: *Foo) void {
10509 </p>10468 </p>
10510 <p>At compile-time:</p>10469 <p>At compile-time:</p>
10511 {#code_begin|test_err|null pointer casted to type#}10470 {#code_begin|test_err|null pointer casted to type#}
10471 {#backend_stage1#}
10512comptime {10472comptime {
10513 const opt_ptr: ?*i32 = null;10473 const opt_ptr: ?*i32 = null;
10514 const ptr = @ptrCast(*i32, opt_ptr);10474 const ptr = @ptrCast(*i32, opt_ptr);
...@@ -10551,7 +10511,8 @@ const expect = std.testing.expect;...@@ -10551,7 +10511,8 @@ const expect = std.testing.expect;
1055110511
10552test "using an allocator" {10512test "using an allocator" {
10553 var buffer: [100]u8 = undefined;10513 var buffer: [100]u8 = undefined;
10554 const allocator = std.heap.FixedBufferAllocator.init(&buffer).allocator();10514 var fba = std.heap.FixedBufferAllocator.init(&buffer);
10515 const allocator = fba.allocator();
10555 const result = try concat(allocator, "foo", "bar");10516 const result = try concat(allocator, "foo", "bar");
10556 try expect(std.mem.eql(u8, "foobar", result));10517 try expect(std.mem.eql(u8, "foobar", result));
10557}10518}
...@@ -10647,7 +10608,7 @@ pub fn main() !void {...@@ -10647,7 +10608,7 @@ pub fn main() !void {
10647 <p>String literals such as {#syntax#}"foo"{#endsyntax#} are in the global constant data section.10608 <p>String literals such as {#syntax#}"foo"{#endsyntax#} are in the global constant data section.
10648 This is why it is an error to pass a string literal to a mutable slice, like this:10609 This is why it is an error to pass a string literal to a mutable slice, like this:
10649 </p>10610 </p>
10650 {#code_begin|test_err|cannot cast pointer to array literal to slice type '[]u8'#}10611 {#code_begin|test_err|expected type '[]u8', found '*const [5:0]u8'#}
10651fn foo(s: []u8) void {10612fn foo(s: []u8) void {
10652 _ = s;10613 _ = s;
10653}10614}
...@@ -11832,8 +11793,8 @@ fn readU32Be() u32 {}...@@ -11832,8 +11793,8 @@ fn readU32Be() u32 {}
11832 <pre>{#syntax#}anytype{#endsyntax#}</pre>11793 <pre>{#syntax#}anytype{#endsyntax#}</pre>
11833 </th>11794 </th>
11834 <td>11795 <td>
11835 Function parameters and struct fields can be declared with {#syntax#}anytype{#endsyntax#} in place of the type.11796 Function parameters can be declared with {#syntax#}anytype{#endsyntax#} in place of the type.
11836 The type will be inferred where the function is called or the struct is instantiated.11797 The type will be inferred where the function is called.
11837 <ul>11798 <ul>
11838 <li>See also {#link|Function Parameter Type Inference#}</li>11799 <li>See also {#link|Function Parameter Type Inference#}</li>
11839 </ul>11800 </ul>
lib/compiler_rt/addf3.zig+2-2
...@@ -9,7 +9,7 @@ const normalize = common.normalize;...@@ -9,7 +9,7 @@ const normalize = common.normalize;
9pub inline fn addf3(comptime T: type, a: T, b: T) T {9pub inline fn addf3(comptime T: type, a: T, b: T) T {
10 const bits = @typeInfo(T).Float.bits;10 const bits = @typeInfo(T).Float.bits;
11 const Z = std.meta.Int(.unsigned, bits);11 const Z = std.meta.Int(.unsigned, bits);
12 const S = std.meta.Int(.unsigned, bits - @clz(Z, @as(Z, bits) - 1));12 const S = std.meta.Int(.unsigned, bits - @clz(@as(Z, bits) - 1));
1313
14 const typeWidth = bits;14 const typeWidth = bits;
15 const significandBits = math.floatMantissaBits(T);15 const significandBits = math.floatMantissaBits(T);
...@@ -118,7 +118,7 @@ pub inline fn addf3(comptime T: type, a: T, b: T) T {...@@ -118,7 +118,7 @@ pub inline fn addf3(comptime T: type, a: T, b: T) T {
118 // If partial cancellation occured, we need to left-shift the result118 // If partial cancellation occured, we need to left-shift the result
119 // and adjust the exponent:119 // and adjust the exponent:
120 if (aSignificand < integerBit << 3) {120 if (aSignificand < integerBit << 3) {
121 const shift = @intCast(i32, @clz(Z, aSignificand)) - @intCast(i32, @clz(std.meta.Int(.unsigned, bits), integerBit << 3));121 const shift = @intCast(i32, @clz(aSignificand)) - @intCast(i32, @clz(integerBit << 3));
122 aSignificand <<= @intCast(S, shift);122 aSignificand <<= @intCast(S, shift);
123 aExponent -= shift;123 aExponent -= shift;
124 }124 }
lib/compiler_rt/common.zig+1-1
...@@ -199,7 +199,7 @@ pub fn normalize(comptime T: type, significand: *std.meta.Int(.unsigned, @typeIn...@@ -199,7 +199,7 @@ pub fn normalize(comptime T: type, significand: *std.meta.Int(.unsigned, @typeIn
199 const Z = std.meta.Int(.unsigned, @typeInfo(T).Float.bits);199 const Z = std.meta.Int(.unsigned, @typeInfo(T).Float.bits);
200 const integerBit = @as(Z, 1) << std.math.floatFractionalBits(T);200 const integerBit = @as(Z, 1) << std.math.floatFractionalBits(T);
201201
202 const shift = @clz(Z, significand.*) - @clz(Z, integerBit);202 const shift = @clz(significand.*) - @clz(integerBit);
203 significand.* <<= @intCast(std.math.Log2Int(Z), shift);203 significand.* <<= @intCast(std.math.Log2Int(Z), shift);
204 return @as(i32, 1) - shift;204 return @as(i32, 1) - shift;
205}205}
lib/compiler_rt/divxf3.zig+2
...@@ -206,5 +206,7 @@ pub fn __divxf3(a: f80, b: f80) callconv(.C) f80 {...@@ -206,5 +206,7 @@ pub fn __divxf3(a: f80, b: f80) callconv(.C) f80 {
206}206}
207207
208test {208test {
209 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/12603
210
209 _ = @import("divxf3_test.zig");211 _ = @import("divxf3_test.zig");
210}212}
lib/compiler_rt/extendf.zig+4-4
...@@ -56,8 +56,8 @@ pub inline fn extendf(...@@ -56,8 +56,8 @@ pub inline fn extendf(
56 // a is denormal.56 // a is denormal.
57 // renormalize the significand and clear the leading bit, then insert57 // renormalize the significand and clear the leading bit, then insert
58 // the correct adjusted exponent in the destination type.58 // the correct adjusted exponent in the destination type.
59 const scale: u32 = @clz(src_rep_t, aAbs) -59 const scale: u32 = @clz(aAbs) -
60 @clz(src_rep_t, @as(src_rep_t, srcMinNormal));60 @clz(@as(src_rep_t, srcMinNormal));
61 absResult = @as(dst_rep_t, aAbs) << @intCast(DstShift, dstSigBits - srcSigBits + scale);61 absResult = @as(dst_rep_t, aAbs) << @intCast(DstShift, dstSigBits - srcSigBits + scale);
62 absResult ^= dstMinNormal;62 absResult ^= dstMinNormal;
63 const resultExponent: u32 = dstExpBias - srcExpBias - scale + 1;63 const resultExponent: u32 = dstExpBias - srcExpBias - scale + 1;
...@@ -119,8 +119,8 @@ pub inline fn extend_f80(comptime src_t: type, a: std.meta.Int(.unsigned, @typeI...@@ -119,8 +119,8 @@ pub inline fn extend_f80(comptime src_t: type, a: std.meta.Int(.unsigned, @typeI
119 // a is denormal.119 // a is denormal.
120 // renormalize the significand and clear the leading bit, then insert120 // renormalize the significand and clear the leading bit, then insert
121 // the correct adjusted exponent in the destination type.121 // the correct adjusted exponent in the destination type.
122 const scale: u16 = @clz(src_rep_t, a_abs) -122 const scale: u16 = @clz(a_abs) -
123 @clz(src_rep_t, @as(src_rep_t, src_min_normal));123 @clz(@as(src_rep_t, src_min_normal));
124124
125 dst.fraction = @as(u64, a_abs) << @intCast(u6, dst_sig_bits - src_sig_bits + scale);125 dst.fraction = @as(u64, a_abs) << @intCast(u6, dst_sig_bits - src_sig_bits + scale);
126 dst.fraction |= dst_int_bit; // bit 64 is always set for normal numbers126 dst.fraction |= dst_int_bit; // bit 64 is always set for normal numbers
lib/compiler_rt/extendxftf2.zig+1-1
...@@ -38,7 +38,7 @@ fn __extendxftf2(a: f80) callconv(.C) f128 {...@@ -38,7 +38,7 @@ fn __extendxftf2(a: f80) callconv(.C) f128 {
38 // a is denormal38 // a is denormal
39 // renormalize the significand and clear the leading bit and integer part,39 // renormalize the significand and clear the leading bit and integer part,
40 // then insert the correct adjusted exponent in the destination type.40 // then insert the correct adjusted exponent in the destination type.
41 const scale: u32 = @clz(u64, a_rep.fraction);41 const scale: u32 = @clz(a_rep.fraction);
42 abs_result = @as(u128, a_rep.fraction) << @intCast(u7, dst_sig_bits - src_sig_bits + scale + 1);42 abs_result = @as(u128, a_rep.fraction) << @intCast(u7, dst_sig_bits - src_sig_bits + scale + 1);
43 abs_result ^= dst_min_normal;43 abs_result ^= dst_min_normal;
44 abs_result |= @as(u128, scale + 1) << dst_sig_bits;44 abs_result |= @as(u128, scale + 1) << dst_sig_bits;
lib/compiler_rt/int.zig+1-1
...@@ -243,7 +243,7 @@ inline fn div_u32(n: u32, d: u32) u32 {...@@ -243,7 +243,7 @@ inline fn div_u32(n: u32, d: u32) u32 {
243 // special cases243 // special cases
244 if (d == 0) return 0; // ?!244 if (d == 0) return 0; // ?!
245 if (n == 0) return 0;245 if (n == 0) return 0;
246 var sr = @bitCast(c_uint, @as(c_int, @clz(u32, d)) - @as(c_int, @clz(u32, n)));246 var sr = @bitCast(c_uint, @as(c_int, @clz(d)) - @as(c_int, @clz(n)));
247 // 0 <= sr <= n_uword_bits - 1 or sr large247 // 0 <= sr <= n_uword_bits - 1 or sr large
248 if (sr > n_uword_bits - 1) {248 if (sr > n_uword_bits - 1) {
249 // d > r249 // d > r
lib/compiler_rt/int_to_float.zig+2-2
...@@ -23,7 +23,7 @@ pub fn intToFloat(comptime T: type, x: anytype) T {...@@ -23,7 +23,7 @@ pub fn intToFloat(comptime T: type, x: anytype) T {
23 var result: uT = sign_bit;23 var result: uT = sign_bit;
2424
25 // Compute significand25 // Compute significand
26 var exp = int_bits - @clz(Z, abs_val) - 1;26 var exp = int_bits - @clz(abs_val) - 1;
27 if (int_bits <= fractional_bits or exp <= fractional_bits) {27 if (int_bits <= fractional_bits or exp <= fractional_bits) {
28 const shift_amt = fractional_bits - @intCast(math.Log2Int(uT), exp);28 const shift_amt = fractional_bits - @intCast(math.Log2Int(uT), exp);
2929
...@@ -32,7 +32,7 @@ pub fn intToFloat(comptime T: type, x: anytype) T {...@@ -32,7 +32,7 @@ pub fn intToFloat(comptime T: type, x: anytype) T {
32 result ^= implicit_bit; // Remove implicit integer bit32 result ^= implicit_bit; // Remove implicit integer bit
33 } else {33 } else {
34 var shift_amt = @intCast(math.Log2Int(Z), exp - fractional_bits);34 var shift_amt = @intCast(math.Log2Int(Z), exp - fractional_bits);
35 const exact_tie: bool = @ctz(Z, abs_val) == shift_amt - 1;35 const exact_tie: bool = @ctz(abs_val) == shift_amt - 1;
3636
37 // Shift down result and remove implicit integer bit37 // Shift down result and remove implicit integer bit
38 result = @intCast(uT, (abs_val >> (shift_amt - 1))) ^ (implicit_bit << 1);38 result = @intCast(uT, (abs_val >> (shift_amt - 1))) ^ (implicit_bit << 1);
lib/compiler_rt/mulf3.zig+1-1
...@@ -186,7 +186,7 @@ fn normalize(comptime T: type, significand: *PowerOfTwoSignificandZ(T)) i32 {...@@ -186,7 +186,7 @@ fn normalize(comptime T: type, significand: *PowerOfTwoSignificandZ(T)) i32 {
186 const Z = PowerOfTwoSignificandZ(T);186 const Z = PowerOfTwoSignificandZ(T);
187 const integerBit = @as(Z, 1) << math.floatFractionalBits(T);187 const integerBit = @as(Z, 1) << math.floatFractionalBits(T);
188188
189 const shift = @clz(Z, significand.*) - @clz(Z, integerBit);189 const shift = @clz(significand.*) - @clz(integerBit);
190 significand.* <<= @intCast(math.Log2Int(Z), shift);190 significand.* <<= @intCast(math.Log2Int(Z), shift);
191 return @as(i32, 1) - shift;191 return @as(i32, 1) - shift;
192}192}
lib/compiler_rt/udivmod.zig+5-5
...@@ -75,12 +75,12 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:...@@ -75,12 +75,12 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
75 r[high] = n[high] & (d[high] - 1);75 r[high] = n[high] & (d[high] - 1);
76 rem.* = @ptrCast(*align(@alignOf(SingleInt)) DoubleInt, &r[0]).*; // TODO issue #42176 rem.* = @ptrCast(*align(@alignOf(SingleInt)) DoubleInt, &r[0]).*; // TODO issue #421
77 }77 }
78 return n[high] >> @intCast(Log2SingleInt, @ctz(SingleInt, d[high]));78 return n[high] >> @intCast(Log2SingleInt, @ctz(d[high]));
79 }79 }
80 // K K80 // K K
81 // ---81 // ---
82 // K 082 // K 0
83 sr = @bitCast(c_uint, @as(c_int, @clz(SingleInt, d[high])) - @as(c_int, @clz(SingleInt, n[high])));83 sr = @bitCast(c_uint, @as(c_int, @clz(d[high])) - @as(c_int, @clz(n[high])));
84 // 0 <= sr <= single_int_bits - 2 or sr large84 // 0 <= sr <= single_int_bits - 2 or sr large
85 if (sr > single_int_bits - 2) {85 if (sr > single_int_bits - 2) {
86 if (maybe_rem) |rem| {86 if (maybe_rem) |rem| {
...@@ -110,7 +110,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:...@@ -110,7 +110,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
110 if (d[low] == 1) {110 if (d[low] == 1) {
111 return a;111 return a;
112 }112 }
113 sr = @ctz(SingleInt, d[low]);113 sr = @ctz(d[low]);
114 q[high] = n[high] >> @intCast(Log2SingleInt, sr);114 q[high] = n[high] >> @intCast(Log2SingleInt, sr);
115 q[low] = (n[high] << @intCast(Log2SingleInt, single_int_bits - sr)) | (n[low] >> @intCast(Log2SingleInt, sr));115 q[low] = (n[high] << @intCast(Log2SingleInt, single_int_bits - sr)) | (n[low] >> @intCast(Log2SingleInt, sr));
116 return @ptrCast(*align(@alignOf(SingleInt)) DoubleInt, &q[0]).*; // TODO issue #421116 return @ptrCast(*align(@alignOf(SingleInt)) DoubleInt, &q[0]).*; // TODO issue #421
...@@ -118,7 +118,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:...@@ -118,7 +118,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
118 // K X118 // K X
119 // ---119 // ---
120 // 0 K120 // 0 K
121 sr = 1 + single_int_bits + @as(c_uint, @clz(SingleInt, d[low])) - @as(c_uint, @clz(SingleInt, n[high]));121 sr = 1 + single_int_bits + @as(c_uint, @clz(d[low])) - @as(c_uint, @clz(n[high]));
122 // 2 <= sr <= double_int_bits - 1122 // 2 <= sr <= double_int_bits - 1
123 // q.all = a << (double_int_bits - sr);123 // q.all = a << (double_int_bits - sr);
124 // r.all = a >> sr;124 // r.all = a >> sr;
...@@ -144,7 +144,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:...@@ -144,7 +144,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
144 // K X144 // K X
145 // ---145 // ---
146 // K K146 // K K
147 sr = @bitCast(c_uint, @as(c_int, @clz(SingleInt, d[high])) - @as(c_int, @clz(SingleInt, n[high])));147 sr = @bitCast(c_uint, @as(c_int, @clz(d[high])) - @as(c_int, @clz(n[high])));
148 // 0 <= sr <= single_int_bits - 1 or sr large148 // 0 <= sr <= single_int_bits - 1 or sr large
149 if (sr > single_int_bits - 1) {149 if (sr > single_int_bits - 1) {
150 if (maybe_rem) |rem| {150 if (maybe_rem) |rem| {
lib/docs/index.html+91-72
...@@ -25,9 +25,10 @@...@@ -25,9 +25,10 @@
25 --search-bg-color-focus: #ffffff;25 --search-bg-color-focus: #ffffff;
26 --search-sh-color: rgba(0, 0, 0, 0.18);26 --search-sh-color: rgba(0, 0, 0, 0.18);
27 --help-sh-color: rgba(0, 0, 0, 0.75);27 --help-sh-color: rgba(0, 0, 0, 0.75);
28 --help-bg-color: #aaa;
28 }29 }
2930
30 html, body { margin: 0; padding:0; height: 100%; }31 html, body { margin: 0; padding: 0; height: 100%; }
3132
32 a {33 a {
33 text-decoration: none;34 text-decoration: none;
...@@ -168,8 +169,8 @@...@@ -168,8 +169,8 @@
168 width: 100%;169 width: 100%;
169 margin-bottom: 0.8rem;170 margin-bottom: 0.8rem;
170 padding: 0.5rem;171 padding: 0.5rem;
171 font-size: 1rem;
172 font-family: var(--ui);172 font-family: var(--ui);
173 font-size: 1rem;
173 color: var(--tx-color);174 color: var(--tx-color);
174 background-color: var(--search-bg-color);175 background-color: var(--search-bg-color);
175 border-top: 0;176 border-top: 0;
...@@ -190,11 +191,11 @@...@@ -190,11 +191,11 @@
190 box-shadow: 0 0.3em 1em 0.125em var(--search-sh-color);191 box-shadow: 0 0.3em 1em 0.125em var(--search-sh-color);
191 }192 }
192193
193 .docs .search::placeholder {194 #searchPlaceholder {
194 font-size: 1rem;195 position: absolute;
195 font-family: var(--ui);196 pointer-events: none;
196 color: var(--tx-color);197 top: 5px;
197 opacity: 0.5;198 left: 5px;
198 }199 }
199200
200 .docs a {201 .docs a {
...@@ -207,9 +208,9 @@...@@ -207,9 +208,9 @@
207208
208 .docs pre {209 .docs pre {
209 font-family: var(--mono);210 font-family: var(--mono);
210 font-size:1em;211 font-size: 1em;
211 background-color:#F5F5F5;212 background-color: #F5F5F5;
212 padding:1em;213 padding: 1em;
213 overflow-x: auto;214 overflow-x: auto;
214 }215 }
215216
...@@ -225,7 +226,7 @@...@@ -225,7 +226,7 @@
225 border-bottom: 0.0625rem dashed;226 border-bottom: 0.0625rem dashed;
226 }227 }
227228
228 .docs h2 {229 .docs h2 {
229 font-size: 1.3em;230 font-size: 1.3em;
230 margin: 0.5em 0;231 margin: 0.5em 0;
231 padding: 0;232 padding: 0;
...@@ -289,12 +290,12 @@...@@ -289,12 +290,12 @@
289 }290 }
290291
291 .fieldDocs {292 .fieldDocs {
292 border: 1px solid #2A2A2A;293 border: 1px solid #F5F5F5;
293 border-top: 0px;294 border-top: 0px;
294 padding: 1px 1em;295 padding: 1px 1em;
295 }296 }
296297
297 /* help dialog */298 /* help modal */
298 .help-modal {299 .help-modal {
299 display: flex;300 display: flex;
300 width: 100%;301 width: 100%;
...@@ -308,13 +309,13 @@...@@ -308,13 +309,13 @@
308 backdrop-filter: blur(0.3em);309 backdrop-filter: blur(0.3em);
309 }310 }
310311
311 .help-modal > .dialog {312 .help-modal > .modal {
312 max-width: 97vw;313 max-width: 97vw;
313 max-height: 97vh;314 max-height: 97vh;
314 overflow: auto;315 overflow: auto;
315 font-size: 1rem;316 font-size: 1rem;
316 color: #fff;317 color: #fff;
317 background-color: #333;318 background-color: var(--help-bg-color);
318 border: 0.125rem solid #000;319 border: 0.125rem solid #000;
319 box-shadow: 0 0.5rem 2.5rem 0.3rem var(--help-sh-color);320 box-shadow: 0 0.5rem 2.5rem 0.3rem var(--help-sh-color);
320 }321 }
...@@ -335,11 +336,11 @@...@@ -335,11 +336,11 @@
335 margin-right: 0.5em;336 margin-right: 0.5em;
336 }337 }
337338
338 .help-modal kbd {339 kbd {
339 display: inline-block;340 display: inline-block;
340 padding: 0.3em 0.2em;341 padding: 0.3em 0.2em;
341 font-size: 1.2em;342 font-family: var(--mono);
342 font-size: var(--mono);343 font-size: 1em;
343 line-height: 0.8em;344 line-height: 0.8em;
344 vertical-align: middle;345 vertical-align: middle;
345 color: #000;346 color: #000;
...@@ -348,16 +349,20 @@...@@ -348,16 +349,20 @@
348 border-bottom-color: #c6cbd1;349 border-bottom-color: #c6cbd1;
349 border: solid 0.0625em;350 border: solid 0.0625em;
350 border-radius: 0.1875em;351 border-radius: 0.1875em;
351 box-shadow: inset 0 -0.0625em 0 #c6cbd1;352 box-shadow: inset 0 -0.2em 0 #c6cbd1;
352 cursor: default;353 cursor: default;
353 }354 }
355
356 #listFns > div {
357 padding-bottom: 10px;
358 }
354359
355 #listFns dt {360 #listFns dt {
356 font-family: var(--mono);361 font-family: var(--mono);
357 }362 }
358 .argBreaker {363 .argBreaker {
359 display: none;364 display: none;
360 }365 }
361366
362 /* tokens */367 /* tokens */
363 .tok-kw {368 .tok-kw {
...@@ -391,7 +396,6 @@...@@ -391,7 +396,6 @@
391396
392 /* dark mode */397 /* dark mode */
393 @media (prefers-color-scheme: dark) {398 @media (prefers-color-scheme: dark) {
394
395 :root {399 :root {
396 --tx-color: #bbb;400 --tx-color: #bbb;
397 --bg-color: #111;401 --bg-color: #111;
...@@ -408,11 +412,15 @@...@@ -408,11 +412,15 @@
408 --search-bg-color-focus: #000;412 --search-bg-color-focus: #000;
409 --search-sh-color: rgba(255, 255, 255, 0.28);413 --search-sh-color: rgba(255, 255, 255, 0.28);
410 --help-sh-color: rgba(142, 142, 142, 0.5);414 --help-sh-color: rgba(142, 142, 142, 0.5);
415 --help-bg-color: #333;
411 }416 }
412417
413 .docs pre {418 .docs pre {
414 background-color:#2A2A2A;419 background-color:#2A2A2A;
415 }420 }
421 .fieldDocs {
422 border-color:#2A2A2A;
423 }
416 #listNav {424 #listNav {
417 background-color: #333;425 background-color: #333;
418 }426 }
...@@ -457,7 +465,6 @@...@@ -457,7 +465,6 @@
457 .tok-type {465 .tok-type {
458 color: #68f;466 color: #68f;
459 }467 }
460
461 }468 }
462469
463 @media only screen and (max-width: 750px) {470 @media only screen and (max-width: 750px) {
...@@ -544,7 +551,7 @@...@@ -544,7 +551,7 @@
544 <body class="canvas">551 <body class="canvas">
545 <div class="banner">552 <div class="banner">
546 This is a beta autodoc build; expect bugs and missing information.553 This is a beta autodoc build; expect bugs and missing information.
547 <a href="https://github.com/ziglang/zig/wiki/How-to-contribute-to-Autodoc">Report an Issue</a>, 554 <a href="https://github.com/ziglang/zig/wiki/How-to-contribute-to-Autodoc">Report an Issue</a>,
548 <a href="https://github.com/ziglang/zig/wiki/How-to-contribute-to-Autodoc">Contribute</a>,555 <a href="https://github.com/ziglang/zig/wiki/How-to-contribute-to-Autodoc">Contribute</a>,
549 <a href="https://github.com/ziglang/zig/wiki/How-to-read-the-standard-library-source-code">Learn more about stdlib source code</a>.556 <a href="https://github.com/ziglang/zig/wiki/How-to-read-the-standard-library-source-code">Learn more about stdlib source code</a>.
550 </div>557 </div>
...@@ -555,43 +562,43 @@...@@ -555,43 +562,43 @@
555 <div class="logo">562 <div class="logo">
556 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 140">563 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 140">
557 <g fill="#F7A41D">564 <g fill="#F7A41D">
558 <g>565 <g>
559 <polygon points="46,22 28,44 19,30"/>566 <polygon points="46,22 28,44 19,30"/>
560 <polygon points="46,22 33,33 28,44 22,44 22,95 31,95 20,100 12,117 0,117 0,22" shape-rendering="crispEdges"/>567 <polygon points="46,22 33,33 28,44 22,44 22,95 31,95 20,100 12,117 0,117 0,22" shape-rendering="crispEdges"/>
561 <polygon points="31,95 12,117 4,106"/>568 <polygon points="31,95 12,117 4,106"/>
562 </g>569 </g>
563 <g>570 <g>
564 <polygon points="56,22 62,36 37,44"/>571 <polygon points="56,22 62,36 37,44"/>
565 <polygon points="56,22 111,22 111,44 37,44 56,32" shape-rendering="crispEdges"/>572 <polygon points="56,22 111,22 111,44 37,44 56,32" shape-rendering="crispEdges"/>
566 <polygon points="116,95 97,117 90,104"/>573 <polygon points="116,95 97,117 90,104"/>
567 <polygon points="116,95 100,104 97,117 42,117 42,95" shape-rendering="crispEdges"/>574 <polygon points="116,95 100,104 97,117 42,117 42,95" shape-rendering="crispEdges"/>
568 <polygon points="150,0 52,117 3,140 101,22"/>575 <polygon points="150,0 52,117 3,140 101,22"/>
569 </g>576 </g>
570 <g>577 <g>
571 <polygon points="141,22 140,40 122,45"/>578 <polygon points="141,22 140,40 122,45"/>
572 <polygon points="153,22 153,117 106,117 120,105 125,95 131,95 131,45 122,45 132,36 141,22" shape-rendering="crispEdges"/>579 <polygon points="153,22 153,117 106,117 120,105 125,95 131,95 131,45 122,45 132,36 141,22" shape-rendering="crispEdges"/>
573 <polygon points="125,95 130,110 106,117"/>580 <polygon points="125,95 130,110 106,117"/>
574 </g>581 </g>
575 </g>582 </g>
576 <style>583 <style>
577 #text { fill: #121212 }584 #text { fill: #121212 }
578 @media (prefers-color-scheme: dark) { #text { fill: #f2f2f2 } }585 @media (prefers-color-scheme: dark) { #text { fill: #f2f2f2 } }
579 </style>586 </style>
580 <g id="text">587 <g id="text">
581 <g>588 <g>
582 <polygon points="260,22 260,37 229,40 177,40 177,22" shape-rendering="crispEdges"/>589 <polygon points="260,22 260,37 229,40 177,40 177,22" shape-rendering="crispEdges"/>
583 <polygon points="260,37 207,99 207,103 176,103 229,40 229,37"/>590 <polygon points="260,37 207,99 207,103 176,103 229,40 229,37"/>
584 <polygon points="261,99 261,117 176,117 176,103 206,99" shape-rendering="crispEdges"/>591 <polygon points="261,99 261,117 176,117 176,103 206,99" shape-rendering="crispEdges"/>
585 </g>592 </g>
586 <rect x="272" y="22" shape-rendering="crispEdges" width="22" height="95"/>593 <rect x="272" y="22" shape-rendering="crispEdges" width="22" height="95"/>
587 <g>594 <g>
588 <polygon points="394,67 394,106 376,106 376,81 360,70 346,67" shape-rendering="crispEdges"/>595 <polygon points="394,67 394,106 376,106 376,81 360,70 346,67" shape-rendering="crispEdges"/>
589 <polygon points="360,68 376,81 346,67"/>596 <polygon points="360,68 376,81 346,67"/>
590 <path d="M394,106c-10.2,7.3-24,12-37.7,12c-29,0-51.1-20.8-51.1-48.3c0-27.3,22.5-48.1,52-48.1 c14.3,0,29.2,5.5,38.9,14l-13,15c-7.1-6.3-16.8-10-25.9-10c-17,0-30.2,12.9-30.2,29.5c0,16.8,13.3,29.6,30.3,29.6 c5.7,0,12.8-2.3,19-5.5L394,106z"/>597 <path d="M394,106c-10.2,7.3-24,12-37.7,12c-29,0-51.1-20.8-51.1-48.3c0-27.3,22.5-48.1,52-48.1 c14.3,0,29.2,5.5,38.9,14l-13,15c-7.1-6.3-16.8-10-25.9-10c-17,0-30.2,12.9-30.2,29.5c0,16.8,13.3,29.6,30.3,29.6 c5.7,0,12.8-2.3,19-5.5L394,106z"/>
591 </g>598 </g>
592 </g>599 </g>
593 </svg>600 </svg>
594 </div>601 </div>
595 <div id="sectMainPkg" class="hidden">602 <div id="sectMainPkg" class="hidden">
596 <h2><span>Main Package</span></h2>603 <h2><span>Main Package</span></h2>
597 <ul class="packages">604 <ul class="packages">
...@@ -606,16 +613,19 @@...@@ -606,16 +613,19 @@
606 <h2><span>Zig Version</span></h2>613 <h2><span>Zig Version</span></h2>
607 <p class="str" id="tdZigVer"></p>614 <p class="str" id="tdZigVer"></p>
608 </div>615 </div>
609 <div>616 <div>
610 <input id="privDeclsBox" type="checkbox"/>617 <input id="privDeclsBox" type="checkbox"/>
611 <label for="privDeclsBox">Internal Doc Mode</label>618 <label for="privDeclsBox">Internal Doc Mode</label>
612 </div>619 </div>
613 </nav>620 </nav>
614 </div>621 </div>
615 <div class="flex-right">622 <div id="docs" class="flex-right">
616 <div class="wrap">623 <div class="wrap">
617 <section class="docs">624 <section class="docs">
618 <input type="search" class="search" id="search" autocomplete="off" spellcheck="false" placeholder="`s` to search, `?` to see more options">625 <div style="position: relative">
626 <span id="searchPlaceholder"><kbd>S</kbd> to search, <kbd>?</kbd> for more options</span>
627 <input type="search" class="search" id="search" autocomplete="off" spellcheck="false" disabled>
628 </div>
619 <p id="status">Loading...</p>629 <p id="status">Loading...</p>
620 <div id="sectNav" class="hidden"><ul id="listNav"></ul></div>630 <div id="sectNav" class="hidden"><ul id="listNav"></ul></div>
621 <div id="fnProto" class="hidden">631 <div id="fnProto" class="hidden">
...@@ -647,10 +657,17 @@...@@ -647,10 +657,17 @@
647 <div id="sectSearchResults" class="hidden">657 <div id="sectSearchResults" class="hidden">
648 <h2>Search Results</h2>658 <h2>Search Results</h2>
649 <ul id="listSearchResults"></ul>659 <ul id="listSearchResults"></ul>
660 <p id="sectSearchAllResultsLink" class="hidden"><a href="">show all results</a></p>
650 </div>661 </div>
651 <div id="sectSearchNoResults" class="hidden">662 <div id="sectSearchNoResults" class="hidden">
652 <h2>No Results Found</h2>663 <h2>No Results Found</h2>
653 <p>Press escape to exit search and then '?' to see more options.</p>664 <p>Here are some things you can try:</p>
665 <ul>
666 <li>Check out the <a id="langRefLink">Language Reference</a> for the language itself.</li>
667 <li>Check out the <a href="https://ziglang.org/learn/">Learn page</a> for other helpful resources for learning Zig.</li>
668 <li>Use your search engine.</li>
669 </ul>
670 <p>Press <kbd>?</kbd> to see keyboard shortcuts and <kbd>Esc</kbd> to return.</p>
654 </div>671 </div>
655 <div id="sectFields" class="hidden">672 <div id="sectFields" class="hidden">
656 <h2>Fields</h2>673 <h2>Fields</h2>
...@@ -702,21 +719,23 @@...@@ -702,21 +719,23 @@
702 </table>719 </table>
703 </div>720 </div>
704 </div>721 </div>
705 </section>722 </section>
706 </div>723 </div>
707 <div class="flex-filler"></div>724 <div class="flex-filler"></div>
708 </div>725 </div>
709 </div>726 </div>
710 <div id="helpDialog" class="hidden">727 <div id="helpModal" class="hidden">
711 <div class="help-modal">728 <div class="help-modal">
712 <div class="dialog">729 <div class="modal">
713 <h1>Keyboard Shortcuts</h1>730 <h1>Keyboard Shortcuts</h1>
714 <dl><dt><kbd>?</kbd></dt><dd>Show this help dialog</dd></dl>731 <dl><dt><kbd>?</kbd></dt><dd>Show this help modal</dd></dl>
715 <dl><dt><kbd>Esc</kbd></dt><dd>Clear focus; close this dialog</dd></dl>
716 <dl><dt><kbd>s</kbd></dt><dd>Focus the search field</dd></dl>732 <dl><dt><kbd>s</kbd></dt><dd>Focus the search field</dd></dl>
717 <dl><dt><kbd>↑</kbd></dt><dd>Move up in search results</dd></dl>733 <div style="margin-left: 1em">
718 <dl><dt><kbd>↓</kbd></dt><dd>Move down in search results</dd></dl>734 <dl><dt><kbd>↑</kbd></dt><dd>Move up in search results</dd></dl>
719 <dl><dt><kbd>⏎</kbd></dt><dd>Go to active search result</dd></dl>735 <dl><dt><kbd>↓</kbd></dt><dd>Move down in search results</dd></dl>
736 <dl><dt><kbd>⏎</kbd></dt><dd>Go to active search result</dd></dl>
737 </div>
738 <dl><dt><kbd>Esc</kbd></dt><dd>Clear focus; close this modal</dd></dl>
720 </div>739 </div>
721 </div>740 </div>
722 </div>741 </div>
lib/docs/main.js+3178-2966
...@@ -1,3259 +1,3471 @@...@@ -1,3259 +1,3471 @@
1'use strict';1"use strict";
22
3var zigAnalysis;3var zigAnalysis;
44
5(function() {5(function () {
6 let domStatus = (document.getElementById("status"));6 const domStatus = document.getElementById("status");
7 let domSectNav = (document.getElementById("sectNav"));7 const domSectNav = document.getElementById("sectNav");
8 let domListNav = (document.getElementById("listNav"));8 const domListNav = document.getElementById("listNav");
9 let domSectMainPkg = (document.getElementById("sectMainPkg"));9 const domSectMainPkg = document.getElementById("sectMainPkg");
10 let domSectPkgs = (document.getElementById("sectPkgs"));10 const domSectPkgs = document.getElementById("sectPkgs");
11 let domListPkgs = (document.getElementById("listPkgs"));11 const domListPkgs = document.getElementById("listPkgs");
12 let domSectTypes = (document.getElementById("sectTypes"));12 const domSectTypes = document.getElementById("sectTypes");
13 let domListTypes = (document.getElementById("listTypes"));13 const domListTypes = document.getElementById("listTypes");
14 let domSectTests = (document.getElementById("sectTests"));14 const domSectTests = document.getElementById("sectTests");
15 let domListTests = (document.getElementById("listTests"));15 const domListTests = document.getElementById("listTests");
16 let domSectNamespaces = (document.getElementById("sectNamespaces"));16 const domSectNamespaces = document.getElementById("sectNamespaces");
17 let domListNamespaces = (document.getElementById("listNamespaces"));17 const domListNamespaces = document.getElementById("listNamespaces");
18 let domSectErrSets = (document.getElementById("sectErrSets"));18 const domSectErrSets = document.getElementById("sectErrSets");
19 let domListErrSets = (document.getElementById("listErrSets"));19 const domListErrSets = document.getElementById("listErrSets");
20 let domSectFns = (document.getElementById("sectFns"));20 const domSectFns = document.getElementById("sectFns");
21 let domListFns = (document.getElementById("listFns"));21 const domListFns = document.getElementById("listFns");
22 let domSectFields = (document.getElementById("sectFields"));22 const domSectFields = document.getElementById("sectFields");
23 let domListFields = (document.getElementById("listFields"));23 const domListFields = document.getElementById("listFields");
24 let domSectGlobalVars = (document.getElementById("sectGlobalVars"));24 const domSectGlobalVars = document.getElementById("sectGlobalVars");
25 let domListGlobalVars = (document.getElementById("listGlobalVars"));25 const domListGlobalVars = document.getElementById("listGlobalVars");
26 let domSectValues = (document.getElementById("sectValues"));26 const domSectValues = document.getElementById("sectValues");
27 let domListValues = (document.getElementById("listValues"));27 const domListValues = document.getElementById("listValues");
28 let domFnProto = (document.getElementById("fnProto"));28 const domFnProto = document.getElementById("fnProto");
29 let domFnProtoCode = (document.getElementById("fnProtoCode"));29 const domFnProtoCode = document.getElementById("fnProtoCode");
30 let domSectParams = (document.getElementById("sectParams"));30 const domSectParams = document.getElementById("sectParams");
31 let domListParams = (document.getElementById("listParams"));31 const domListParams = document.getElementById("listParams");
32 let domTldDocs = (document.getElementById("tldDocs"));32 const domTldDocs = document.getElementById("tldDocs");
33 let domSectFnErrors = (document.getElementById("sectFnErrors"));33 const domSectFnErrors = document.getElementById("sectFnErrors");
34 let domListFnErrors = (document.getElementById("listFnErrors"));34 const domListFnErrors = document.getElementById("listFnErrors");
35 let domTableFnErrors =(document.getElementById("tableFnErrors"));35 const domTableFnErrors = document.getElementById("tableFnErrors");
36 let domFnErrorsAnyError = (document.getElementById("fnErrorsAnyError"));36 const domFnErrorsAnyError = document.getElementById("fnErrorsAnyError");
37 let domFnExamples = (document.getElementById("fnExamples"));37 const domFnExamples = document.getElementById("fnExamples");
38 // let domListFnExamples = (document.getElementById("listFnExamples"));38 // const domListFnExamples = (document.getElementById("listFnExamples"));
39 let domFnNoExamples = (document.getElementById("fnNoExamples"));39 const domFnNoExamples = document.getElementById("fnNoExamples");
40 let domDeclNoRef = (document.getElementById("declNoRef"));40 const domDeclNoRef = document.getElementById("declNoRef");
41 let domSearch = (document.getElementById("search"));41 const domSearch = document.getElementById("search");
42 let domSectSearchResults = (document.getElementById("sectSearchResults"));42 const domSectSearchResults = document.getElementById("sectSearchResults");
4343 const domSectSearchAllResultsLink = document.getElementById("sectSearchAllResultsLink");
44 let domListSearchResults = (document.getElementById("listSearchResults"));44 const domDocs = document.getElementById("docs");
45 let domSectSearchNoResults = (document.getElementById("sectSearchNoResults"));45 const domListSearchResults = document.getElementById("listSearchResults");
46 let domSectInfo = (document.getElementById("sectInfo"));46 const domSectSearchNoResults = document.getElementById("sectSearchNoResults");
47 // let domTdTarget = (document.getElementById("tdTarget"));47 const domSectInfo = document.getElementById("sectInfo");
48 let domPrivDeclsBox = (document.getElementById("privDeclsBox"));48 // const domTdTarget = (document.getElementById("tdTarget"));
49 let domTdZigVer = (document.getElementById("tdZigVer"));49 const domPrivDeclsBox = document.getElementById("privDeclsBox");
50 let domHdrName = (document.getElementById("hdrName"));50 const domTdZigVer = document.getElementById("tdZigVer");
51 let domHelpModal = (document.getElementById("helpDialog"));51 const domHdrName = document.getElementById("hdrName");
5252 const domHelpModal = document.getElementById("helpModal");
53 53 const domSearchPlaceholder = document.getElementById("searchPlaceholder");
54 let searchTimer = null;54 const sourceFileUrlTemplate = "src/{{file}}#L{{line}}"
5555 const domLangRefLink = document.getElementById("langRefLink");
56 56
57 let escapeHtmlReplacements = { "&": "&amp;", '"': "&quot;", "<": "&lt;", ">": "&gt;" };57 let searchTimer = null;
5858 let searchTrimResults = true;
59 let typeKinds = (indexTypeKinds());59
60 let typeTypeId = (findTypeTypeId());60 let escapeHtmlReplacements = {
61 let pointerSizeEnum = { One: 0, Many: 1, Slice: 2, C: 3 };61 "&": "&amp;",
6262 '"': "&quot;",
63 // for each package, is an array with packages to get to this one63 "<": "&lt;",
64 let canonPkgPaths = computeCanonicalPackagePaths();64 ">": "&gt;",
6565 };
66 66
6767 let typeKinds = indexTypeKinds();
68 // for each decl, is an array with {declNames, pkgNames} to get to this one68 let typeTypeId = findTypeTypeId();
69 69 let pointerSizeEnum = { One: 0, Many: 1, Slice: 2, C: 3 };
70 let canonDeclPaths = null; // lazy; use getCanonDeclPath70
7171 // for each package, is an array with packages to get to this one
72 // for each type, is an array with {declNames, pkgNames} to get to this one72 let canonPkgPaths = computeCanonicalPackagePaths();
73 73
74 let canonTypeDecls = null; // lazy; use getCanonTypeDecl74 // for each decl, is an array with {declNames, pkgNames} to get to this one
7575
76 76 let canonDeclPaths = null; // lazy; use getCanonDeclPath
7777
78 78 // for each type, is an array with {declNames, pkgNames} to get to this one
79 let curNav = {79
80 showPrivDecls: false,80 let canonTypeDecls = null; // lazy; use getCanonTypeDecl
81 // each element is a package name, e.g. @import("a") then within there @import("b")81
82 // starting implicitly from root package82 let curNav = {
83 pkgNames: [],83 showPrivDecls: false,
84 // same as above except actual packages, not names84 // each element is a package name, e.g. @import("a") then within there @import("b")
85 pkgObjs: [],85 // starting implicitly from root package
86 // Each element is a decl name, `a.b.c`, a is 0, b is 1, c is 2, etc.86 pkgNames: [],
87 // empty array means refers to the package itself87 // same as above except actual packages, not names
88 declNames: [],88 pkgObjs: [],
89 // these will be all types, except the last one may be a type or a decl89 // Each element is a decl name, `a.b.c`, a is 0, b is 1, c is 2, etc.
90 declObjs: [],90 // empty array means refers to the package itself
9191 declNames: [],
92 // (a, b, c, d) comptime call; result is the value the docs refer to92 // these will be all types, except the last one may be a type or a decl
93 callName: null,93 declObjs: [],
94 };94
9595 // (a, b, c, d) comptime call; result is the value the docs refer to
96 let curNavSearch = "";96 callName: null,
97 let curSearchIndex = -1;97 };
98 let imFeelingLucky = false;98
9999 let curNavSearch = "";
100 let rootIsStd = detectRootIsStd();100 let curSearchIndex = -1;
101101 let imFeelingLucky = false;
102 // map of decl index to list of non-generic fn indexes102
103 // let nodesToFnsMap = indexNodesToFns();103 let rootIsStd = detectRootIsStd();
104 // map of decl index to list of comptime fn calls104
105 // let nodesToCallsMap = indexNodesToCalls();105 // map of decl index to list of non-generic fn indexes
106106 // let nodesToFnsMap = indexNodesToFns();
107 domSearch.addEventListener('keydown', onSearchKeyDown, false);107 // map of decl index to list of comptime fn calls
108 domPrivDeclsBox.addEventListener('change', function() {108 // let nodesToCallsMap = indexNodesToCalls();
109 if (this.checked != curNav.showPrivDecls) {109
110 if (this.checked && location.hash.length > 1 && location.hash[1] != '*'){110 domSearch.disabled = false;
111 location.hash = "#*" + location.hash.substring(1);111 domSearch.addEventListener("keydown", onSearchKeyDown, false);
112 return;112 domSearch.addEventListener("focus", ev => {
113 }113 domSearchPlaceholder.classList.add("hidden");
114 if (!this.checked && location.hash.length > 1 && location.hash[1] == '*') {114 });
115 location.hash = "#" + location.hash.substring(2);115 domSearch.addEventListener("blur", ev => {
116 return;116 if (domSearch.value.length == 0)
117 }117 domSearchPlaceholder.classList.remove("hidden");
118 }118 });
119 }, false);119 domSectSearchAllResultsLink.addEventListener('click', onClickSearchShowAllResults, false);
120 120 function onClickSearchShowAllResults(ev) {
121 if (location.hash == "") {121 ev.preventDefault();
122 location.hash = "#root";122 ev.stopPropagation();
123 }123 searchTrimResults = false;
124
125 window.addEventListener('hashchange', onHashChange, false);
126 window.addEventListener('keydown', onWindowKeyDown, false);
127 onHashChange();124 onHashChange();
128125 }
129 function renderTitle() {126
130 let list = curNav.pkgNames.concat(curNav.declNames);127 domPrivDeclsBox.addEventListener(
131 let suffix = " - Zig";128 "change",
132 if (list.length === 0) {129 function () {
133 if (rootIsStd) {130 if (this.checked != curNav.showPrivDecls) {
134 document.title = "std" + suffix;131 if (
135 } else {132 this.checked &&
136 document.title = zigAnalysis.params.rootName + suffix;133 location.hash.length > 1 &&
137 }134 location.hash[1] != "*"
138 } else {135 ) {
139 document.title = list.join('.') + suffix;136 location.hash = "#*" + location.hash.substring(1);
137 return;
138 }
139 if (
140 !this.checked &&
141 location.hash.length > 1 &&
142 location.hash[1] == "*"
143 ) {
144 location.hash = "#" + location.hash.substring(2);
145 return;
140 }146 }
147 }
148 },
149 false
150 );
151
152 if (location.hash == "") {
153 location.hash = "#root";
154 }
155
156 // make the modal disappear if you click outside it
157 domHelpModal.addEventListener("click", ev => {
158 if (ev.target.className == "help-modal")
159 domHelpModal.classList.add("hidden");
160 });
161
162 window.addEventListener("hashchange", onHashChange, false);
163 window.addEventListener("keydown", onWindowKeyDown, false);
164 onHashChange();
165
166 let langRefVersion = zigAnalysis.params.zigVersion;
167 if (!/^\d+\.\d+\.\d+$/.test(langRefVersion)) {
168 // the version is probably not released yet
169 langRefVersion = "master";
170 }
171 domLangRefLink.href = `https://ziglang.org/documentation/${langRefVersion}/`;
172
173 function renderTitle() {
174 let list = curNav.pkgNames.concat(curNav.declNames);
175 let suffix = " - Zig";
176 if (list.length === 0) {
177 if (rootIsStd) {
178 document.title = "std" + suffix;
179 } else {
180 document.title = zigAnalysis.params.rootName + suffix;
181 }
182 } else {
183 document.title = list.join(".") + suffix;
141 }184 }
185 }
142186
143 187 function isDecl(x) {
144 function isDecl(x) {188 return "value" in x;
145 return "value" in x;189 }
146 }
147
148
149 function isType(x) {
150 return "kind" in x && !("value" in x);
151 }
152
153
154 function isContainerType(x) {
155 return isType(x) && typeKindIsContainer((x).kind) ;
156 }
157
158
159 function typeShorthandName(expr) {
160 let resolvedExpr = resolveValue({expr: expr});
161 if (!("type" in resolvedExpr)) {
162 return null;
163 }
164 let type = (zigAnalysis.types[resolvedExpr.type]);
165
166 outer: for (let i = 0; i < 10000; i += 1) {
167 switch (type.kind) {
168 case typeKinds.Optional:
169 case typeKinds.Pointer:
170 let child = (type).child;
171 let resolvedChild = resolveValue(child);
172 if ("type" in resolvedChild) {
173 type = zigAnalysis.types[resolvedChild.type];
174 continue;
175 } else {
176 return null;
177 }
178 default:
179 break outer;
180 }
181
182 if (i == 9999) throw "Exhausted typeShorthandName quota";
183 }
184
185190
191 function isType(x) {
192 return "kind" in x && !("value" in x);
193 }
186194
187 let name = undefined;195 function isContainerType(x) {
188 if (type.kind === typeKinds.Struct) {196 return isType(x) && typeKindIsContainer(x.kind);
189 name = "struct";197 }
190 } else if (type.kind === typeKinds.Enum) {
191 name = "enum";
192 } else if (type.kind === typeKinds.Union) {
193 name = "union";
194 } else {
195 console.log("TODO: unhalndled case in typeShortName");
196 return null;
197 }
198198
199 return escapeHtml(name);199 function typeShorthandName(expr) {
200 let resolvedExpr = resolveValue({ expr: expr });
201 if (!("type" in resolvedExpr)) {
202 return null;
200 }203 }
204 let type = zigAnalysis.types[resolvedExpr.type];
205
206 outer: for (let i = 0; i < 10000; i += 1) {
207 switch (type.kind) {
208 case typeKinds.Optional:
209 case typeKinds.Pointer:
210 let child = type.child;
211 let resolvedChild = resolveValue(child);
212 if ("type" in resolvedChild) {
213 type = zigAnalysis.types[resolvedChild.type];
214 continue;
215 } else {
216 return null;
217 }
218 default:
219 break outer;
220 }
201221
202 222 if (i == 9999) throw "Exhausted typeShorthandName quota";
203 function typeKindIsContainer(typeKind) {
204 return typeKind === typeKinds.Struct ||
205 typeKind === typeKinds.Union ||
206 typeKind === typeKinds.Enum;
207 }223 }
208224
209 225 let name = undefined;
210 function declCanRepresentTypeKind(typeKind) {226 if (type.kind === typeKinds.Struct) {
211 return typeKind === typeKinds.ErrorSet || typeKindIsContainer(typeKind);227 name = "struct";
228 } else if (type.kind === typeKinds.Enum) {
229 name = "enum";
230 } else if (type.kind === typeKinds.Union) {
231 name = "union";
232 } else {
233 console.log("TODO: unhalndled case in typeShortName");
234 return null;
212 }235 }
213236
214 // 237 return escapeHtml(name);
215 // function findCteInRefPath(path) {238 }
216 // for (let i = path.length - 1; i >= 0; i -= 1) {239
217 // const ref = path[i];240 function typeKindIsContainer(typeKind) {
218 // if ("string" in ref) continue;241 return (
219 // if ("comptimeExpr" in ref) return ref;242 typeKind === typeKinds.Struct ||
220 // if ("refPath" in ref) return findCteInRefPath(ref.refPath);243 typeKind === typeKinds.Union ||
221 // return null;244 typeKind === typeKinds.Enum
222 // }245 );
223246 }
224 // return null;247
225 // }248 function declCanRepresentTypeKind(typeKind) {
226249 return typeKind === typeKinds.ErrorSet || typeKindIsContainer(typeKind);
227 250 }
228 function resolveValue(value) {251
229 let i = 0;252 //
230 while(i < 1000) {253 // function findCteInRefPath(path) {
231 i += 1;254 // for (let i = path.length - 1; i >= 0; i -= 1) {
232255 // const ref = path[i];
233 if ("refPath" in value.expr) {256 // if ("string" in ref) continue;
234 value = {expr: value.expr.refPath[value.expr.refPath.length -1]};257 // if ("comptimeExpr" in ref) return ref;
235 continue;258 // if ("refPath" in ref) return findCteInRefPath(ref.refPath);
236 }259 // return null;
237260 // }
238 if ("declRef" in value.expr) {261
239 value = zigAnalysis.decls[value.expr.declRef].value;262 // return null;
240 continue;263 // }
241 }264
242265 function resolveValue(value) {
243 if ("as" in value.expr) {266 let i = 0;
244 value = {267 while (i < 1000) {
245 typeRef: zigAnalysis.exprs[value.expr.as.typeRefArg],268 i += 1;
246 expr: zigAnalysis.exprs[value.expr.as.exprArg],269
247 };270 if ("refPath" in value.expr) {
248 continue;271 value = { expr: value.expr.refPath[value.expr.refPath.length - 1] };
249 }272 continue;
250273 }
251 return value;
252
253 }
254 console.assert(false);
255 return ({});
256 }
257
258
259// function typeOfDecl(decl){
260// return decl.value.typeRef;
261//
262// let i = 0;
263// while(i < 1000) {
264// i += 1;
265// console.assert(isDecl(decl));
266// if ("type" in decl.value) {
267// return ({ type: typeTypeId });
268// }
269//
270//// if ("string" in decl.value) {
271//// return ({ type: {
272//// kind: typeKinds.Pointer,
273//// size: pointerSizeEnum.One,
274//// child: });
275//// }
276//
277// if ("refPath" in decl.value) {
278// decl = ({
279// value: decl.value.refPath[decl.value.refPath.length -1]
280// });
281// continue;
282// }
283//
284// if ("declRef" in decl.value) {
285// decl = zigAnalysis.decls[decl.value.declRef];
286// continue;
287// }
288//
289// if ("int" in decl.value) {
290// return decl.value.int.typeRef;
291// }
292//
293// if ("float" in decl.value) {
294// return decl.value.float.typeRef;
295// }
296//
297// if ("array" in decl.value) {
298// return decl.value.array.typeRef;
299// }
300//
301// if ("struct" in decl.value) {
302// return decl.value.struct.typeRef;
303// }
304//
305// if ("comptimeExpr" in decl.value) {
306// const cte = zigAnalysis.comptimeExprs[decl.value.comptimeExpr];
307// return cte.typeRef;
308// }
309//
310// if ("call" in decl.value) {
311// const fn_call = zigAnalysis.calls[decl.value.call];
312// let fn_decl = undefined;
313// if ("declRef" in fn_call.func) {
314// fn_decl = zigAnalysis.decls[fn_call.func.declRef];
315// } else if ("refPath" in fn_call.func) {
316// console.assert("declRef" in fn_call.func.refPath[fn_call.func.refPath.length -1]);
317// fn_decl = zigAnalysis.decls[fn_call.func.refPath[fn_call.func.refPath.length -1].declRef];
318// } else throw {};
319//
320// const fn_decl_value = resolveValue(fn_decl.value);
321// console.assert("type" in fn_decl_value); //TODO handle comptimeExpr
322// const fn_type = (zigAnalysis.types[fn_decl_value.type]);
323// console.assert(fn_type.kind === typeKinds.Fn);
324// return fn_type.ret;
325// }
326//
327// if ("void" in decl.value) {
328// return ({ type: typeTypeId });
329// }
330//
331// if ("bool" in decl.value) {
332// return ({ type: typeKinds.Bool });
333// }
334//
335// console.log("TODO: handle in `typeOfDecl` more cases: ", decl);
336// console.assert(false);
337// throw {};
338// }
339// console.assert(false);
340// return ({});
341// }
342
343 function render() {
344 domStatus.classList.add("hidden");
345 domFnProto.classList.add("hidden");
346 domSectParams.classList.add("hidden");
347 domTldDocs.classList.add("hidden");
348 domSectMainPkg.classList.add("hidden");
349 domSectPkgs.classList.add("hidden");
350 domSectTypes.classList.add("hidden");
351 domSectTests.classList.add("hidden");
352 domSectNamespaces.classList.add("hidden");
353 domSectErrSets.classList.add("hidden");
354 domSectFns.classList.add("hidden");
355 domSectFields.classList.add("hidden");
356 domSectSearchResults.classList.add("hidden");
357 domSectSearchNoResults.classList.add("hidden");
358 domSectInfo.classList.add("hidden");
359 domHdrName.classList.add("hidden");
360 domSectNav.classList.add("hidden");
361 domSectFnErrors.classList.add("hidden");
362 domFnExamples.classList.add("hidden");
363 domFnNoExamples.classList.add("hidden");
364 domDeclNoRef.classList.add("hidden");
365 domFnErrorsAnyError.classList.add("hidden");
366 domTableFnErrors.classList.add("hidden");
367 domSectGlobalVars.classList.add("hidden");
368 domSectValues.classList.add("hidden");
369
370 renderTitle();
371 renderInfo();
372 renderPkgList();
373
374 domPrivDeclsBox.checked = curNav.showPrivDecls;
375
376 if (curNavSearch !== "") {
377 return renderSearch();
378 }
379
380 let rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg];
381 let pkg = rootPkg;
382 curNav.pkgObjs = [pkg];
383 for (let i = 0; i < curNav.pkgNames.length; i += 1) {
384 let childPkg = zigAnalysis.packages[pkg.table[curNav.pkgNames[i]]];
385 if (childPkg == null) {
386 return render404();
387 }
388 pkg = childPkg;
389 curNav.pkgObjs.push(pkg);
390 }
391
392
393 let currentType = zigAnalysis.types[pkg.main];
394 curNav.declObjs = [currentType];
395 for (let i = 0; i < curNav.declNames.length; i += 1) {
396
397
398 let childDecl = findSubDecl((currentType), curNav.declNames[i]);
399 if (childDecl == null) {
400 return render404();
401 }
402
403 let childDeclValue = resolveValue((childDecl).value).expr;
404 if ("type" in childDeclValue) {
405
406 const t = zigAnalysis.types[childDeclValue.type];
407 if (t.kind != typeKinds.Fn) {
408 childDecl = t;
409 }
410 }
411274
412 currentType = (childDecl);275 if ("declRef" in value.expr) {
413 curNav.declObjs.push(currentType);276 value = zigAnalysis.decls[value.expr.declRef].value;
414 }277 continue;
278 }
415279
416 renderNav();280 if ("as" in value.expr) {
281 value = {
282 typeRef: zigAnalysis.exprs[value.expr.as.typeRefArg],
283 expr: zigAnalysis.exprs[value.expr.as.exprArg],
284 };
285 continue;
286 }
417287
418 let last = curNav.declObjs[curNav.declObjs.length - 1];288 return value;
419 let lastIsDecl = isDecl(last);289 }
420 let lastIsType = isType(last);290 console.assert(false);
421 let lastIsContainerType = isContainerType(last);291 return {};
292 }
293
294 // function typeOfDecl(decl){
295 // return decl.value.typeRef;
296 //
297 // let i = 0;
298 // while(i < 1000) {
299 // i += 1;
300 // console.assert(isDecl(decl));
301 // if ("type" in decl.value) {
302 // return ({ type: typeTypeId });
303 // }
304 //
305 //// if ("string" in decl.value) {
306 //// return ({ type: {
307 //// kind: typeKinds.Pointer,
308 //// size: pointerSizeEnum.One,
309 //// child: });
310 //// }
311 //
312 // if ("refPath" in decl.value) {
313 // decl = ({
314 // value: decl.value.refPath[decl.value.refPath.length -1]
315 // });
316 // continue;
317 // }
318 //
319 // if ("declRef" in decl.value) {
320 // decl = zigAnalysis.decls[decl.value.declRef];
321 // continue;
322 // }
323 //
324 // if ("int" in decl.value) {
325 // return decl.value.int.typeRef;
326 // }
327 //
328 // if ("float" in decl.value) {
329 // return decl.value.float.typeRef;
330 // }
331 //
332 // if ("array" in decl.value) {
333 // return decl.value.array.typeRef;
334 // }
335 //
336 // if ("struct" in decl.value) {
337 // return decl.value.struct.typeRef;
338 // }
339 //
340 // if ("comptimeExpr" in decl.value) {
341 // const cte = zigAnalysis.comptimeExprs[decl.value.comptimeExpr];
342 // return cte.typeRef;
343 // }
344 //
345 // if ("call" in decl.value) {
346 // const fn_call = zigAnalysis.calls[decl.value.call];
347 // let fn_decl = undefined;
348 // if ("declRef" in fn_call.func) {
349 // fn_decl = zigAnalysis.decls[fn_call.func.declRef];
350 // } else if ("refPath" in fn_call.func) {
351 // console.assert("declRef" in fn_call.func.refPath[fn_call.func.refPath.length -1]);
352 // fn_decl = zigAnalysis.decls[fn_call.func.refPath[fn_call.func.refPath.length -1].declRef];
353 // } else throw {};
354 //
355 // const fn_decl_value = resolveValue(fn_decl.value);
356 // console.assert("type" in fn_decl_value); //TODO handle comptimeExpr
357 // const fn_type = (zigAnalysis.types[fn_decl_value.type]);
358 // console.assert(fn_type.kind === typeKinds.Fn);
359 // return fn_type.ret;
360 // }
361 //
362 // if ("void" in decl.value) {
363 // return ({ type: typeTypeId });
364 // }
365 //
366 // if ("bool" in decl.value) {
367 // return ({ type: typeKinds.Bool });
368 // }
369 //
370 // console.log("TODO: handle in `typeOfDecl` more cases: ", decl);
371 // console.assert(false);
372 // throw {};
373 // }
374 // console.assert(false);
375 // return ({});
376 // }
377
378 function render() {
379 domStatus.classList.add("hidden");
380 domFnProto.classList.add("hidden");
381 domSectParams.classList.add("hidden");
382 domTldDocs.classList.add("hidden");
383 domSectMainPkg.classList.add("hidden");
384 domSectPkgs.classList.add("hidden");
385 domSectTypes.classList.add("hidden");
386 domSectTests.classList.add("hidden");
387 domSectNamespaces.classList.add("hidden");
388 domSectErrSets.classList.add("hidden");
389 domSectFns.classList.add("hidden");
390 domSectFields.classList.add("hidden");
391 domSectSearchResults.classList.add("hidden");
392 domSectSearchAllResultsLink.classList.add("hidden");
393 domSectSearchNoResults.classList.add("hidden");
394 domSectInfo.classList.add("hidden");
395 domHdrName.classList.add("hidden");
396 domSectNav.classList.add("hidden");
397 domSectFnErrors.classList.add("hidden");
398 domFnExamples.classList.add("hidden");
399 domFnNoExamples.classList.add("hidden");
400 domDeclNoRef.classList.add("hidden");
401 domFnErrorsAnyError.classList.add("hidden");
402 domTableFnErrors.classList.add("hidden");
403 domSectGlobalVars.classList.add("hidden");
404 domSectValues.classList.add("hidden");
405
406 renderTitle();
407 renderInfo();
408 renderPkgList();
409
410 domPrivDeclsBox.checked = curNav.showPrivDecls;
411
412 if (curNavSearch !== "") {
413 return renderSearch();
414 }
422415
423 if (lastIsContainerType) {
424 return renderContainer((last));
425 }
426416
427 if (!lastIsDecl && !lastIsType) {417 let rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg];
428 return renderUnknownDecl((last));418 let pkg = rootPkg;
429 }419 curNav.pkgObjs = [pkg];
420 for (let i = 0; i < curNav.pkgNames.length; i += 1) {
421 let childPkg = zigAnalysis.packages[pkg.table[curNav.pkgNames[i]]];
422 if (childPkg == null) {
423 return render404();
424 }
425 pkg = childPkg;
426 curNav.pkgObjs.push(pkg);
427 }
430428
431 if (lastIsType) {429 let currentType = zigAnalysis.types[pkg.main];
432 return renderType((last));430 curNav.declObjs = [currentType];
433 }431 for (let i = 0; i < curNav.declNames.length; i += 1) {
432 let childDecl = findSubDecl(currentType, curNav.declNames[i]);
433 if (childDecl == null) {
434 return render404();
435 }
434436
435 if (lastIsDecl && last.kind === 'var') {437 let childDeclValue = resolveValue(childDecl.value).expr;
436 return renderVar((last));438 if ("type" in childDeclValue) {
439 const t = zigAnalysis.types[childDeclValue.type];
440 if (t.kind != typeKinds.Fn) {
441 childDecl = t;
437 }442 }
443 }
438444
439 if (lastIsDecl && last.kind === 'const') {445 currentType = childDecl;
440 let typeObj = zigAnalysis.types[resolveValue((last).value).expr.type];446 curNav.declObjs.push(currentType);
441 if (typeObj && typeObj.kind === typeKinds.Fn) {
442 return renderFn((last));
443 }
444
445 return renderValue((last));
446 }
447 }447 }
448448
449 449 renderNav();
450 function renderUnknownDecl(decl) {
451 domDeclNoRef.classList.remove("hidden");
452450
453 let docs = zigAnalysis.astNodes[decl.src].docs;451 let last = curNav.declObjs[curNav.declObjs.length - 1];
454 if (docs != null) {452 let lastIsDecl = isDecl(last);
455 domTldDocs.innerHTML = markdown(docs);453 let lastIsType = isType(last);
456 } else {454 let lastIsContainerType = isContainerType(last);
457 domTldDocs.innerHTML = '<p>There are no doc comments for this declaration.</p>';
458 }
459 domTldDocs.classList.remove("hidden");
460 }
461455
462 456 if (lastIsContainerType) {
463 function typeIsErrSet(typeIndex) {457 return renderContainer(last);
464 let typeObj = zigAnalysis.types[typeIndex];
465 return typeObj.kind === typeKinds.ErrorSet;
466 }458 }
467459
468 460 if (!lastIsDecl && !lastIsType) {
469 function typeIsStructWithNoFields(typeIndex) {461 return renderUnknownDecl(last);
470 let typeObj = zigAnalysis.types[typeIndex];
471 if (typeObj.kind !== typeKinds.Struct)
472 return false;
473 return (typeObj).fields.length == 0;
474 }462 }
475463
476 464 if (lastIsType) {
477 function typeIsGenericFn(typeIndex) {465 return renderType(last);
478 let typeObj = zigAnalysis.types[typeIndex];
479 if (typeObj.kind !== typeKinds.Fn) {
480 return false;
481 }
482 return (typeObj).generic_ret != null;
483 }466 }
484467
485 468 if (lastIsDecl && last.kind === "var") {
486 function renderFn(fnDecl) {469 return renderVar(last);
487 if ("refPath" in fnDecl.value.expr) {470 }
488 let last = fnDecl.value.expr.refPath.length - 1;
489 let lastExpr = fnDecl.value.expr.refPath[last];
490 console.assert("declRef" in lastExpr);
491 fnDecl = zigAnalysis.decls[lastExpr.declRef];
492 }
493
494 let value = resolveValue(fnDecl.value);
495 console.assert("type" in value.expr);
496 let typeObj = (zigAnalysis.types[value.expr.type]);
497
498 domFnProtoCode.innerHTML = exprName(value.expr, {
499 wantHtml: true,
500 wantLink: true,
501 fnDecl,
502 });
503
504 let docsSource = null;
505 let srcNode = zigAnalysis.astNodes[fnDecl.src];
506 if (srcNode.docs != null) {
507 docsSource = srcNode.docs;
508 }
509
510 renderFnParamDocs(fnDecl, typeObj);
511
512 let retExpr = resolveValue({expr:typeObj.ret}).expr;
513 if ("type" in retExpr) {
514 let retIndex = retExpr.type;
515 let errSetTypeIndex = (null);
516 let retType = zigAnalysis.types[retIndex];
517 if (retType.kind === typeKinds.ErrorSet) {
518 errSetTypeIndex = retIndex;
519 } else if (retType.kind === typeKinds.ErrorUnion) {
520 errSetTypeIndex = (retType).err.type;
521 }
522 if (errSetTypeIndex != null) {
523 let errSetType = (zigAnalysis.types[errSetTypeIndex]);
524 renderErrorSet(errSetType);
525 }
526 }
527
528 let protoSrcIndex = fnDecl.src;
529 if (typeIsGenericFn(value.expr.type)) {
530 // does the generic_ret contain a container?
531 var resolvedGenericRet = resolveValue({expr: typeObj.generic_ret});
532
533 if ("call" in resolvedGenericRet.expr){
534 let call = zigAnalysis.calls[resolvedGenericRet.expr.call];
535 let resolvedFunc = resolveValue({expr: call.func});
536 if (!("type" in resolvedFunc.expr)) return;
537 let callee = zigAnalysis.types[resolvedFunc.expr.type];
538 if (!callee.generic_ret) return;
539 resolvedGenericRet = resolveValue({expr: callee.generic_ret});
540 }
541471
542 // TODO: see if unwrapping the `as` here is a good idea or not.472 if (lastIsDecl && last.kind === "const") {
543 if ("as" in resolvedGenericRet.expr) {473 let typeObj = zigAnalysis.types[resolveValue(last.value).expr.type];
544 resolvedGenericRet = {474 if (typeObj && typeObj.kind === typeKinds.Fn) {
545 expr: zigAnalysis.exprs[resolvedGenericRet.expr.as.exprArg]475 return renderFn(last);
546 };476 }
547 }
548477
549 if (!("type" in resolvedGenericRet.expr)) return;478 return renderValue(last);
550 const genericType = zigAnalysis.types[resolvedGenericRet.expr.type];479 }
551 if (isContainerType(genericType)) {480 }
552 renderContainer(genericType)
553 }
554481
482 function renderUnknownDecl(decl) {
483 domDeclNoRef.classList.remove("hidden");
555484
485 let docs = zigAnalysis.astNodes[decl.src].docs;
486 if (docs != null) {
487 domTldDocs.innerHTML = markdown(docs);
488 } else {
489 domTldDocs.innerHTML =
490 "<p>There are no doc comments for this declaration.</p>";
491 }
492 domTldDocs.classList.remove("hidden");
493 }
494
495 function typeIsErrSet(typeIndex) {
496 let typeObj = zigAnalysis.types[typeIndex];
497 return typeObj.kind === typeKinds.ErrorSet;
498 }
499
500 function typeIsStructWithNoFields(typeIndex) {
501 let typeObj = zigAnalysis.types[typeIndex];
502 if (typeObj.kind !== typeKinds.Struct) return false;
503 return typeObj.fields.length == 0;
504 }
505
506 function typeIsGenericFn(typeIndex) {
507 let typeObj = zigAnalysis.types[typeIndex];
508 if (typeObj.kind !== typeKinds.Fn) {
509 return false;
510 }
511 return typeObj.generic_ret != null;
512 }
513
514 function renderFn(fnDecl) {
515 if ("refPath" in fnDecl.value.expr) {
516 let last = fnDecl.value.expr.refPath.length - 1;
517 let lastExpr = fnDecl.value.expr.refPath[last];
518 console.assert("declRef" in lastExpr);
519 fnDecl = zigAnalysis.decls[lastExpr.declRef];
520 }
556521
522 let value = resolveValue(fnDecl.value);
523 console.assert("type" in value.expr);
524 let typeObj = zigAnalysis.types[value.expr.type];
557525
526 domFnProtoCode.innerHTML = exprName(value.expr, {
527 wantHtml: true,
528 wantLink: true,
529 fnDecl,
530 });
558531
559 // old code532 let docsSource = null;
560 // let instantiations = nodesToFnsMap[protoSrcIndex];533 let srcNode = zigAnalysis.astNodes[fnDecl.src];
561 // let calls = nodesToCallsMap[protoSrcIndex];534 if (srcNode.docs != null) {
562 // if (instantiations == null && calls == null) {535 docsSource = srcNode.docs;
563 // domFnNoExamples.classList.remove("hidden");536 }
564 // } else if (calls != null) {
565 // // if (fnObj.combined === undefined) fnObj.combined = allCompTimeFnCallsResult(calls);
566 // if (fnObj.combined != null) renderContainer(fnObj.combined);
567537
568 // resizeDomList(domListFnExamples, calls.length, '<li></li>');538 renderFnParamDocs(fnDecl, typeObj);
539
540 let retExpr = resolveValue({ expr: typeObj.ret }).expr;
541 if ("type" in retExpr) {
542 let retIndex = retExpr.type;
543 let errSetTypeIndex = null;
544 let retType = zigAnalysis.types[retIndex];
545 if (retType.kind === typeKinds.ErrorSet) {
546 errSetTypeIndex = retIndex;
547 } else if (retType.kind === typeKinds.ErrorUnion) {
548 errSetTypeIndex = retType.err.type;
549 }
550 if (errSetTypeIndex != null) {
551 let errSetType = zigAnalysis.types[errSetTypeIndex];
552 renderErrorSet(errSetType);
553 }
554 }
569555
570 // for (let callI = 0; callI < calls.length; callI += 1) {556 let protoSrcIndex = fnDecl.src;
571 // let liDom = domListFnExamples.children[callI];557 if (typeIsGenericFn(value.expr.type)) {
572 // liDom.innerHTML = getCallHtml(fnDecl, calls[callI]);558 // does the generic_ret contain a container?
573 // }559 var resolvedGenericRet = resolveValue({ expr: typeObj.generic_ret });
560
561 if ("call" in resolvedGenericRet.expr) {
562 let call = zigAnalysis.calls[resolvedGenericRet.expr.call];
563 let resolvedFunc = resolveValue({ expr: call.func });
564 if (!("type" in resolvedFunc.expr)) return;
565 let callee = zigAnalysis.types[resolvedFunc.expr.type];
566 if (!callee.generic_ret) return;
567 resolvedGenericRet = resolveValue({ expr: callee.generic_ret });
568 }
574569
575 // domFnExamples.classList.remove("hidden");570 // TODO: see if unwrapping the `as` here is a good idea or not.
576 // } else if (instantiations != null) {571 if ("as" in resolvedGenericRet.expr) {
577 // // TODO572 resolvedGenericRet = {
578 // }573 expr: zigAnalysis.exprs[resolvedGenericRet.expr.as.exprArg],
579 } else {574 };
575 }
580576
581 domFnExamples.classList.add("hidden");577 if (!("type" in resolvedGenericRet.expr)) return;
582 domFnNoExamples.classList.add("hidden");578 const genericType = zigAnalysis.types[resolvedGenericRet.expr.type];
583 }579 if (isContainerType(genericType)) {
580 renderContainer(genericType);
581 }
584582
585 let protoSrcNode = zigAnalysis.astNodes[protoSrcIndex];583 // old code
586 if (docsSource == null && protoSrcNode != null && protoSrcNode.docs != null) {584 // let instantiations = nodesToFnsMap[protoSrcIndex];
587 docsSource = protoSrcNode.docs;585 // let calls = nodesToCallsMap[protoSrcIndex];
588 }586 // if (instantiations == null && calls == null) {
589 if (docsSource != null) {587 // domFnNoExamples.classList.remove("hidden");
590 domTldDocs.innerHTML = markdown(docsSource);588 // } else if (calls != null) {
591 domTldDocs.classList.remove("hidden");589 // // if (fnObj.combined === undefined) fnObj.combined = allCompTimeFnCallsResult(calls);
592 }590 // if (fnObj.combined != null) renderContainer(fnObj.combined);
593 domFnProto.classList.remove("hidden");591
592 // resizeDomList(domListFnExamples, calls.length, '<li></li>');
593
594 // for (let callI = 0; callI < calls.length; callI += 1) {
595 // let liDom = domListFnExamples.children[callI];
596 // liDom.innerHTML = getCallHtml(fnDecl, calls[callI]);
597 // }
598
599 // domFnExamples.classList.remove("hidden");
600 // } else if (instantiations != null) {
601 // // TODO
602 // }
603 } else {
604 domFnExamples.classList.add("hidden");
605 domFnNoExamples.classList.add("hidden");
594 }606 }
595607
596 608 let protoSrcNode = zigAnalysis.astNodes[protoSrcIndex];
597 function renderFnParamDocs(fnDecl, typeObj) {609 if (
598 let docCount = 0;610 docsSource == null &&
599611 protoSrcNode != null &&
600 let fnNode = zigAnalysis.astNodes[fnDecl.src];612 protoSrcNode.docs != null
601 let fields = (fnNode.fields);613 ) {
602 let isVarArgs = fnNode.varArgs;614 docsSource = protoSrcNode.docs;
603615 }
604 for (let i = 0; i < fields.length; i += 1) {616 if (docsSource != null) {
605 let field = fields[i];617 domTldDocs.innerHTML = markdown(docsSource);
606 let fieldNode = zigAnalysis.astNodes[field];618 domTldDocs.classList.remove("hidden");
607 if (fieldNode.docs != null) {619 }
608 docCount += 1;620 domFnProto.classList.remove("hidden");
609 }621 }
610 }
611 if (docCount == 0) {
612 return;
613 }
614
615 resizeDomList(domListParams, docCount, '<div></div>');
616 let domIndex = 0;
617622
618 for (let i = 0; i < fields.length; i += 1) {623 function renderFnParamDocs(fnDecl, typeObj) {
619 let field = fields[i];624 let docCount = 0;
620 let fieldNode = zigAnalysis.astNodes[field];
621 let docs = fieldNode.docs;
622 if (fieldNode.docs == null) {
623 continue;
624 }
625 let docsNonEmpty = docs !== "";
626 let divDom = domListParams.children[domIndex];
627 domIndex += 1;
628625
626 let fnNode = zigAnalysis.astNodes[fnDecl.src];
627 let fields = fnNode.fields;
628 let isVarArgs = fnNode.varArgs;
629629
630 let value = typeObj.params[i];630 for (let i = 0; i < fields.length; i += 1) {
631 let preClass = docsNonEmpty ? ' class="fieldHasDocs"' : "";631 let field = fields[i];
632 let html = '<pre' + preClass + '>' + escapeHtml((fieldNode.name)) + ": ";632 let fieldNode = zigAnalysis.astNodes[field];
633 if (isVarArgs && i === typeObj.params.length - 1) {633 if (fieldNode.docs != null) {
634 html += '...';634 docCount += 1;
635 } else {635 }
636 let name = exprName(value, {wantHtml: false, wantLink: false});636 }
637 html += '<span class="tok-kw">' + name + '</span>';637 if (docCount == 0) {
638 }638 return;
639 }
639640
640 html += ',</pre>';641 resizeDomList(domListParams, docCount, "<div></div>");
642 let domIndex = 0;
641643
642 if (docsNonEmpty) {644 for (let i = 0; i < fields.length; i += 1) {
643 html += '<div class="fieldDocs">' + markdown(docs) + '</div>';645 let field = fields[i];
644 }646 let fieldNode = zigAnalysis.astNodes[field];
645 divDom.innerHTML = html;647 let docs = fieldNode.docs;
646 }648 if (fieldNode.docs == null) {
647 domSectParams.classList.remove("hidden");649 continue;
648 }650 }
649651 let docsNonEmpty = docs !== "";
650 function renderNav() {652 let divDom = domListParams.children[domIndex];
651 let len = curNav.pkgNames.length + curNav.declNames.length;653 domIndex += 1;
652 resizeDomList(domListNav, len, '<li><a href="#"></a></li>');654
653 let list = [];655 let value = typeObj.params[i];
654 let hrefPkgNames = [];656 let preClass = docsNonEmpty ? ' class="fieldHasDocs"' : "";
655 let hrefDeclNames = ([]);657 let html = "<pre" + preClass + ">" + escapeHtml(fieldNode.name) + ": ";
656 for (let i = 0; i < curNav.pkgNames.length; i += 1) {658 if (isVarArgs && i === typeObj.params.length - 1) {
657 hrefPkgNames.push(curNav.pkgNames[i]);659 html += "...";
658 let name = curNav.pkgNames[i];660 } else {
659 if (name == "root") name = zigAnalysis.rootPkgName;661 let name = exprName(value, { wantHtml: false, wantLink: false });
660 list.push({662 html += '<span class="tok-kw">' + name + "</span>";
661 name: name,663 }
662 link: navLink(hrefPkgNames, hrefDeclNames),
663 });
664 }
665 for (let i = 0; i < curNav.declNames.length; i += 1) {
666 hrefDeclNames.push(curNav.declNames[i]);
667 list.push({
668 name: curNav.declNames[i],
669 link: navLink(hrefPkgNames, hrefDeclNames),
670 });
671 }
672664
673 for (let i = 0; i < list.length; i += 1) {665 html += ",</pre>";
674 let liDom = domListNav.children[i];
675 let aDom = liDom.children[0];
676 aDom.textContent = list[i].name;
677 aDom.setAttribute('href', list[i].link);
678 if (i + 1 == list.length) {
679 aDom.classList.add("active");
680 } else {
681 aDom.classList.remove("active");
682 }
683 }
684666
685 domSectNav.classList.remove("hidden");667 if (docsNonEmpty) {
668 html += '<div class="fieldDocs">' + markdown(docs) + "</div>";
669 }
670 divDom.innerHTML = html;
686 }671 }
687672 domSectParams.classList.remove("hidden");
688 function renderInfo() {673 }
689 domTdZigVer.textContent = zigAnalysis.params.zigVersion;674
690 //domTdTarget.textContent = zigAnalysis.params.builds[0].target;675 function renderNav() {
691676 let len = curNav.pkgNames.length + curNav.declNames.length;
692 domSectInfo.classList.remove("hidden");677 resizeDomList(domListNav, len, '<li><a href="#"></a></li>');
678 let list = [];
679 let hrefPkgNames = [];
680 let hrefDeclNames = [];
681 for (let i = 0; i < curNav.pkgNames.length; i += 1) {
682 hrefPkgNames.push(curNav.pkgNames[i]);
683 let name = curNav.pkgNames[i];
684 if (name == "root") name = zigAnalysis.rootPkgName;
685 list.push({
686 name: name,
687 link: navLink(hrefPkgNames, hrefDeclNames),
688 });
693 }689 }
694690 for (let i = 0; i < curNav.declNames.length; i += 1) {
695 function render404() {691 hrefDeclNames.push(curNav.declNames[i]);
696 domStatus.textContent = "404 Not Found";692 list.push({
697 domStatus.classList.remove("hidden");693 name: curNav.declNames[i],
694 link: navLink(hrefPkgNames, hrefDeclNames),
695 });
698 }696 }
699697
700 function renderPkgList() {698 for (let i = 0; i < list.length; i += 1) {
701 let rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg];699 let liDom = domListNav.children[i];
702 let list = [];700 let aDom = liDom.children[0];
703 for (let key in rootPkg.table) {701 aDom.textContent = list[i].name;
704 let pkgIndex = rootPkg.table[key];702 aDom.setAttribute("href", list[i].link);
705 if (zigAnalysis.packages[pkgIndex] == null) continue;703 if (i + 1 == list.length) {
706 if (key == zigAnalysis.params.rootName) continue;704 aDom.classList.add("active");
707 list.push({705 } else {
708 name: key,706 aDom.classList.remove("active");
709 pkg: pkgIndex,707 }
710 });
711 }
712
713 {
714 let aDom = domSectMainPkg.children[1].children[0].children[0];
715 aDom.textContent = zigAnalysis.rootPkgName;
716 aDom.setAttribute('href', navLinkPkg(zigAnalysis.rootPkg));
717 if (zigAnalysis.params.rootName === curNav.pkgNames[0]) {
718 aDom.classList.add("active");
719 } else {
720 aDom.classList.remove("active");
721 }
722 domSectMainPkg.classList.remove("hidden");
723 }
724
725 list.sort(function(a, b) {
726 return operatorCompare(a.name.toLowerCase(), b.name.toLowerCase());
727 });
728
729 if (list.length !== 0) {
730 resizeDomList(domListPkgs, list.length, '<li><a href="#"></a></li>');
731 for (let i = 0; i < list.length; i += 1) {
732 let liDom = domListPkgs.children[i];
733 let aDom = liDom.children[0];
734 aDom.textContent = list[i].name;
735 aDom.setAttribute('href', navLinkPkg(list[i].pkg));
736 if (list[i].name === curNav.pkgNames[0]) {
737 aDom.classList.add("active");
738 } else {
739 aDom.classList.remove("active");
740 }
741 }
742
743 domSectPkgs.classList.remove("hidden");
744 }
745 }708 }
746709
747 710 domSectNav.classList.remove("hidden");
711 }
712
713 function renderInfo() {
714 domTdZigVer.textContent = zigAnalysis.params.zigVersion;
715 //domTdTarget.textContent = zigAnalysis.params.builds[0].target;
716
717 domSectInfo.classList.remove("hidden");
718 }
719
720 function render404() {
721 domStatus.textContent = "404 Not Found";
722 domStatus.classList.remove("hidden");
723 }
724
725 function renderPkgList() {
726 let rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg];
727 let list = [];
728 for (let key in rootPkg.table) {
729 let pkgIndex = rootPkg.table[key];
730 if (zigAnalysis.packages[pkgIndex] == null) continue;
731 if (key == zigAnalysis.params.rootName) continue;
732 list.push({
733 name: key,
734 pkg: pkgIndex,
735 });
736 }
748737
749 function navLink(pkgNames, declNames, callName) {738 {
750 let base = '#';739 let aDom = domSectMainPkg.children[1].children[0].children[0];
751 if (curNav.showPrivDecls) {740 aDom.textContent = zigAnalysis.rootPkgName;
752 base += "*";741 aDom.setAttribute("href", navLinkPkg(zigAnalysis.rootPkg));
753 }742 if (zigAnalysis.params.rootName === curNav.pkgNames[0]) {
743 aDom.classList.add("active");
744 } else {
745 aDom.classList.remove("active");
746 }
747 domSectMainPkg.classList.remove("hidden");
748 }
754749
755 if (pkgNames.length === 0 && declNames.length === 0) {750 list.sort(function (a, b) {
756 return base;751 return operatorCompare(a.name.toLowerCase(), b.name.toLowerCase());
757 } else if (declNames.length === 0 && callName == null) {752 });
758 return base + pkgNames.join('.');753
759 } else if (callName == null) {754 if (list.length !== 0) {
760 return base + pkgNames.join('.') + ';' + declNames.join('.');755 resizeDomList(domListPkgs, list.length, '<li><a href="#"></a></li>');
756 for (let i = 0; i < list.length; i += 1) {
757 let liDom = domListPkgs.children[i];
758 let aDom = liDom.children[0];
759 aDom.textContent = list[i].name;
760 aDom.setAttribute("href", navLinkPkg(list[i].pkg));
761 if (list[i].name === curNav.pkgNames[0]) {
762 aDom.classList.add("active");
761 } else {763 } else {
762 return base + pkgNames.join('.') + ';' + declNames.join('.') + ';' + callName;764 aDom.classList.remove("active");
763 }765 }
764 }766 }
765767
766 768 domSectPkgs.classList.remove("hidden");
767 function navLinkPkg(pkgIndex) {
768 return navLink(canonPkgPaths[pkgIndex], []);
769 }769 }
770 }
770771
771 772 function navLink(pkgNames, declNames, callName) {
772 function navLinkDecl(childName) {773 let base = "#";
773 return navLink(curNav.pkgNames, curNav.declNames.concat([childName]));774 if (curNav.showPrivDecls) {
775 base += "*";
774 }776 }
775777
776 // 778 if (pkgNames.length === 0 && declNames.length === 0) {
777 // function navLinkCall(callObj) {779 return base;
778 // let declNamesCopy = curNav.declNames.concat([]);780 } else if (declNames.length === 0 && callName == null) {
779 // let callName = (declNamesCopy.pop());781 return base + pkgNames.join(".");
780782 } else if (callName == null) {
781 // callName += '(';783 return base + pkgNames.join(".") + ";" + declNames.join(".");
782 // for (let arg_i = 0; arg_i < callObj.args.length; arg_i += 1) {784 } else {
783 // if (arg_i !== 0) callName += ',';785 return (
784 // let argObj = callObj.args[arg_i];786 base + pkgNames.join(".") + ";" + declNames.join(".") + ";" + callName
785 // callName += getValueText(argObj, argObj, false, false);787 );
786 // }788 }
787 // callName += ')';789 }
788790
789 // declNamesCopy.push(callName);791 function navLinkPkg(pkgIndex) {
790 // return navLink(curNav.pkgNames, declNamesCopy);792 return navLink(canonPkgPaths[pkgIndex], []);
791 // }793 }
794
795 function navLinkDecl(childName) {
796 return navLink(curNav.pkgNames, curNav.declNames.concat([childName]));
797 }
798
799 //
800 // function navLinkCall(callObj) {
801 // let declNamesCopy = curNav.declNames.concat([]);
802 // let callName = (declNamesCopy.pop());
803
804 // callName += '(';
805 // for (let arg_i = 0; arg_i < callObj.args.length; arg_i += 1) {
806 // if (arg_i !== 0) callName += ',';
807 // let argObj = callObj.args[arg_i];
808 // callName += getValueText(argObj, argObj, false, false);
809 // }
810 // callName += ')';
811
812 // declNamesCopy.push(callName);
813 // return navLink(curNav.pkgNames, declNamesCopy);
814 // }
815
816 function resizeDomListDl(dlDom, desiredLen) {
817 // add the missing dom entries
818 for (let i = dlDom.childElementCount / 2; i < desiredLen; i += 1) {
819 dlDom.insertAdjacentHTML("beforeend", "<dt></dt><dd></dd>");
820 }
821 // remove extra dom entries
822 while (desiredLen < dlDom.childElementCount / 2) {
823 dlDom.removeChild(dlDom.lastChild);
824 dlDom.removeChild(dlDom.lastChild);
825 }
826 }
792827
793 828 function resizeDomList(listDom, desiredLen, templateHtml) {
794 function resizeDomListDl(dlDom, desiredLen) {829 // add the missing dom entries
795 // add the missing dom entries830 for (let i = listDom.childElementCount; i < desiredLen; i += 1) {
796 for (let i = dlDom.childElementCount / 2; i < desiredLen; i += 1) {831 listDom.insertAdjacentHTML("beforeend", templateHtml);
797 dlDom.insertAdjacentHTML('beforeend', '<dt></dt><dd></dd>');832 }
798 }833 // remove extra dom entries
799 // remove extra dom entries834 while (desiredLen < listDom.childElementCount) {
800 while (desiredLen < dlDom.childElementCount / 2) {835 listDom.removeChild(listDom.lastChild);
801 dlDom.removeChild(dlDom.lastChild);
802 dlDom.removeChild(dlDom.lastChild);
803 }
804 }836 }
837 }
805838
806 839 function walkResultTypeRef(wr) {
807 function resizeDomList(listDom, desiredLen, templateHtml) {840 if (wr.typeRef) return wr.typeRef;
808 // add the missing dom entries841 let resolved = resolveValue(wr);
809 for (let i = listDom.childElementCount; i < desiredLen; i += 1) {842 if (wr === resolved) {
810 listDom.insertAdjacentHTML('beforeend', templateHtml);843 return { type: 0 };
844 }
845 return walkResultTypeRef(resolved);
846 }
847
848 function exprName(expr, opts) {
849 switch (Object.keys(expr)[0]) {
850 default:
851 throw "this expression is not implemented yet";
852 case "bool": {
853 if (expr.bool) {
854 return "true";
855 }
856 return "false";
857 }
858 case "&": {
859 return "&" + exprName(zigAnalysis.exprs[expr["&"]]);
860 }
861 case "compileError": {
862 let compileError = expr.compileError;
863 return "@compileError(" + exprName(zigAnalysis.exprs[compileError], opts) + ")";
864 }
865 case "enumLiteral": {
866 let literal = expr.enumLiteral;
867 return "." + literal;
868 }
869 case "void": {
870 return "void";
871 }
872 case "slice": {
873 let payloadHtml = "";
874 const lhsExpr = zigAnalysis.exprs[expr.slice.lhs];
875 const startExpr = zigAnalysis.exprs[expr.slice.start];
876 let decl = exprName(lhsExpr);
877 let start = exprName(startExpr);
878 let end = "";
879 let sentinel = "";
880 if (expr.slice["end"]) {
881 const endExpr = zigAnalysis.exprs[expr.slice.end];
882 let end_ = exprName(endExpr);
883 end += end_;
884 }
885 if (expr.slice["sentinel"]) {
886 const sentinelExpr = zigAnalysis.exprs[expr.slice.sentinel];
887 let sentinel_ = exprName(sentinelExpr);
888 sentinel += " :" + sentinel_;
889 }
890 payloadHtml += decl + "[" + start + ".." + end + sentinel + "]";
891 return payloadHtml;
892 }
893 case "sliceIndex": {
894 const sliceIndex = zigAnalysis.exprs[expr.sliceIndex];
895 return exprName(sliceIndex, opts);
896 }
897 case "cmpxchg": {
898 const typeIndex = zigAnalysis.exprs[expr.cmpxchg.type];
899 const ptrIndex = zigAnalysis.exprs[expr.cmpxchg.ptr];
900 const expectedValueIndex =
901 zigAnalysis.exprs[expr.cmpxchg.expected_value];
902 const newValueIndex = zigAnalysis.exprs[expr.cmpxchg.new_value];
903 const successOrderIndex = zigAnalysis.exprs[expr.cmpxchg.success_order];
904 const failureOrderIndex = zigAnalysis.exprs[expr.cmpxchg.failure_order];
905
906 const type = exprName(typeIndex, opts);
907 const ptr = exprName(ptrIndex, opts);
908 const expectedValue = exprName(expectedValueIndex, opts);
909 const newValue = exprName(newValueIndex, opts);
910 const successOrder = exprName(successOrderIndex, opts);
911 const failureOrder = exprName(failureOrderIndex, opts);
912
913 let fnName = "@";
914
915 switch (expr.cmpxchg.name) {
916 case "cmpxchg_strong": {
917 fnName += "cmpxchgStrong";
918 break;
919 }
920 case "cmpxchg_weak": {
921 fnName += "cmpxchgWeak";
922 break;
923 }
924 default: {
925 console.log("There's only cmpxchg_strong and cmpxchg_weak");
926 }
811 }927 }
812 // remove extra dom entries928
813 while (desiredLen < listDom.childElementCount) {929 return (
814 listDom.removeChild(listDom.lastChild);930 fnName +
931 "(" +
932 type +
933 ", " +
934 ptr +
935 ", " +
936 expectedValue +
937 ", " +
938 newValue +
939 ", " +
940 "." +
941 successOrder +
942 ", " +
943 "." +
944 failureOrder +
945 ")"
946 );
947 }
948 case "cmpxchgIndex": {
949 const cmpxchgIndex = zigAnalysis.exprs[expr.cmpxchgIndex];
950 return exprName(cmpxchgIndex, opts);
951 }
952 case "switchOp": {
953 let condExpr = zigAnalysis.exprs[expr.switchOp.cond_index];
954 let ast = zigAnalysis.astNodes[expr.switchOp.ast];
955 let file_name = expr.switchOp.file_name;
956 let outer_decl_index = expr.switchOp.outer_decl;
957 let outer_decl = zigAnalysis.types[outer_decl_index];
958 let line = 0;
959 // console.log(expr.switchOp)
960 // console.log(outer_decl)
961 while (outer_decl_index !== 0 && outer_decl.line_number > 0) {
962 line += outer_decl.line_number;
963 outer_decl_index = outer_decl.outer_decl;
964 outer_decl = zigAnalysis.types[outer_decl_index];
965 // console.log(outer_decl)
966 }
967 line += ast.line + 1;
968 let payloadHtml = "";
969 let cond = exprName(condExpr, opts);
970
971 payloadHtml +=
972 "</br>" +
973 "node_name: " +
974 ast.name +
975 "</br>" +
976 "file: " +
977 file_name +
978 "</br>" +
979 "line: " +
980 line +
981 "</br>";
982 payloadHtml +=
983 "switch(" +
984 cond +
985 ") {" +
986 '<a href="/src/' +
987 file_name +
988 "#L" +
989 line +
990 '">' +
991 "..." +
992 "</a>}";
993 return payloadHtml;
994 }
995 case "switchIndex": {
996 const switchIndex = zigAnalysis.exprs[expr.switchIndex];
997 return exprName(switchIndex, opts);
998 }
999 case "refPath": {
1000 let name = exprName(expr.refPath[0]);
1001 for (let i = 1; i < expr.refPath.length; i++) {
1002 let component = undefined;
1003 if ("string" in expr.refPath[i]) {
1004 component = expr.refPath[i].string;
1005 } else {
1006 component = exprName(expr.refPath[i]);
1007 }
1008 name += "." + component;
815 }1009 }
816 }1010 return name;
817 1011 }
818 function walkResultTypeRef(wr) {1012 case "fieldRef": {
819 if (wr.typeRef) return wr.typeRef;1013 const enumObj = exprName({ type: expr.fieldRef.type }, opts);
820 let resolved = resolveValue(wr);1014 const field =
821 if (wr === resolved) {1015 zigAnalysis.astNodes[enumObj.ast].fields[expr.fieldRef.index];
822 return {type: 0};1016 const name = zigAnalysis.astNodes[field].name;
823 }1017 return name;
824 return walkResultTypeRef(resolved);1018 }
825 }1019 case "enumToInt": {
826 1020 const enumToInt = zigAnalysis.exprs[expr.enumToInt];
827 function exprName(expr, opts) {1021 return "@enumToInt(" + exprName(enumToInt, opts) + ")";
828 switch (Object.keys(expr)[0]) {1022 }
829 default: throw "this expression is not implemented yet";1023 case "bitSizeOf": {
830 case "bool": {1024 const bitSizeOf = zigAnalysis.exprs[expr.bitSizeOf];
831 if (expr.bool) {1025 return "@bitSizeOf(" + exprName(bitSizeOf, opts) + ")";
832 return "true";1026 }
833 }1027 case "sizeOf": {
834 return "false";1028 const sizeOf = zigAnalysis.exprs[expr.sizeOf];
1029 return "@sizeOf(" + exprName(sizeOf, opts) + ")";
1030 }
1031 case "builtinIndex": {
1032 const builtinIndex = zigAnalysis.exprs[expr.builtinIndex];
1033 return exprName(builtinIndex, opts);
1034 }
1035 case "builtin": {
1036 const param_expr = zigAnalysis.exprs[expr.builtin.param];
1037 let param = exprName(param_expr, opts);
1038
1039 let payloadHtml = "@";
1040 switch (expr.builtin.name) {
1041 case "align_of": {
1042 payloadHtml += "alignOf";
1043 break;
835 }1044 }
836 case "&": {1045 case "bool_to_int": {
837 return "&" + exprName(zigAnalysis.exprs[expr["&"]]);1046 payloadHtml += "boolToInt";
1047 break;
838 }1048 }
839 case "compileError": {1049 case "embed_file": {
840 let compileError = expr.compileError;1050 payloadHtml += "embedFile";
841 return compileError;1051 break;
842 }1052 }
843 case "enumLiteral": {1053 case "error_name": {
844 let literal = expr.enumLiteral;1054 payloadHtml += "errorName";
845 return "." + literal;1055 break;
846 }1056 }
847 case "void": {1057 case "panic": {
848 return "void";1058 payloadHtml += "panic";
1059 break;
849 }1060 }
850 case "slice":{1061 case "set_cold": {
851 let payloadHtml = "";1062 payloadHtml += "setCold";
852 const lhsExpr = zigAnalysis.exprs[expr.slice.lhs];1063 break;
853 const startExpr = zigAnalysis.exprs[expr.slice.start];
854 let decl = exprName(lhsExpr);
855 let start = exprName(startExpr);
856 let end = "";
857 let sentinel = "";
858 if (expr.slice['end']) {
859 const endExpr = zigAnalysis.exprs[expr.slice.end];
860 let end_ = exprName(endExpr);
861 end += end_;
862 }
863 if (expr.slice['sentinel']) {
864 const sentinelExpr = zigAnalysis.exprs[expr.slice.sentinel];
865 let sentinel_ = exprName(sentinelExpr);
866 sentinel += " :" + sentinel_;
867 }
868 payloadHtml += decl + "["+ start + ".." + end + sentinel + "]";
869 return payloadHtml;
870 }1064 }
871 case "sliceIndex": {1065 case "set_runtime_safety": {
872 const sliceIndex = zigAnalysis.exprs[expr.sliceIndex];1066 payloadHtml += "setRuntimeSafety";
873 return exprName(sliceIndex, opts);1067 break;
874 }
875 case "cmpxchg":{
876 const typeIndex = zigAnalysis.exprs[expr.cmpxchg.type];
877 const ptrIndex = zigAnalysis.exprs[expr.cmpxchg.ptr];
878 const expectedValueIndex = zigAnalysis.exprs[expr.cmpxchg.expected_value];
879 const newValueIndex = zigAnalysis.exprs[expr.cmpxchg.new_value];
880 const successOrderIndex = zigAnalysis.exprs[expr.cmpxchg.success_order];
881 const failureOrderIndex = zigAnalysis.exprs[expr.cmpxchg.failure_order];
882
883 const type = exprName(typeIndex, opts);
884 const ptr = exprName(ptrIndex, opts);
885 const expectedValue = exprName(expectedValueIndex, opts);
886 const newValue = exprName(newValueIndex, opts);
887 const successOrder = exprName(successOrderIndex, opts);
888 const failureOrder = exprName(failureOrderIndex, opts);
889
890 let fnName = "@";
891
892 switch (expr.cmpxchg.name) {
893 case "cmpxchg_strong": {
894 fnName += "cmpxchgStrong"
895 break;
896 }
897 case "cmpxchg_weak": {
898 fnName += "cmpxchgWeak"
899 break;
900 }
901 default: {
902 console.log("There's only cmpxchg_strong and cmpxchg_weak");
903 }
904 }
905
906 return fnName + "(" + type + ", " + ptr + ", " + expectedValue + ", "+ newValue + ", "+"." +successOrder + ", "+ "." +failureOrder + ")";
907 }
908 case "cmpxchgIndex": {
909 const cmpxchgIndex = zigAnalysis.exprs[expr.cmpxchgIndex];
910 return exprName(cmpxchgIndex, opts);
911 }
912 case "switchOp":{
913 let condExpr = zigAnalysis.exprs[expr.switchOp.cond_index];
914 let ast = zigAnalysis.astNodes[expr.switchOp.ast];
915 let file_name = expr.switchOp.file_name;
916 let outer_decl_index = expr.switchOp.outer_decl;
917 let outer_decl = zigAnalysis.types[outer_decl_index];
918 let line = 0;
919 // console.log(expr.switchOp)
920 // console.log(outer_decl)
921 while (outer_decl_index !== 0 && outer_decl.line_number > 0) {
922 line += outer_decl.line_number;
923 outer_decl_index = outer_decl.outer_decl;
924 outer_decl = zigAnalysis.types[outer_decl_index];
925 // console.log(outer_decl)
926 }
927 line += ast.line + 1;
928 let payloadHtml = "";
929 let cond = exprName(condExpr, opts);
930
931 payloadHtml += "</br>" + "node_name: " + ast.name + "</br>" + "file: " + file_name + "</br>" + "line: " + line + "</br>";
932 payloadHtml += "switch(" + cond + ") {" + "<a href=\"https://github.com/ziglang/zig/tree/master/lib/std/" + file_name + "#L" + line + "\">" +"..." + "</a>}";
933 return payloadHtml;
934 }1068 }
935 case "switchIndex": {1069 case "sqrt": {
936 const switchIndex = zigAnalysis.exprs[expr.switchIndex];1070 payloadHtml += "sqrt";
937 return exprName(switchIndex, opts);1071 break;
938 }1072 }
939 case "refPath" : {1073 case "sin": {
940 let name = exprName(expr.refPath[0]);1074 payloadHtml += "sin";
941 for (let i = 1; i < expr.refPath.length; i++) {1075 break;
942 let component = undefined;
943 if ("string" in expr.refPath[i]) {
944 component = expr.refPath[i].string;
945 } else {
946 component = exprName(expr.refPath[i]);
947 }
948 name += "." + component;
949 }
950 return name;
951 }1076 }
952 case "fieldRef" : {1077 case "cos": {
953 const enumObj = exprName({"type":expr.fieldRef.type} ,opts);1078 payloadHtml += "cos";
954 const field = zigAnalysis.astNodes[enumObj.ast].fields[expr.fieldRef.index];1079 break;
955 const name = zigAnalysis.astNodes[field].name;
956 return name
957 }1080 }
958 case "enumToInt" : {1081 case "tan": {
959 const enumToInt = zigAnalysis.exprs[expr.enumToInt];1082 payloadHtml += "tan";
960 return "@enumToInt(" + exprName(enumToInt, opts) + ")";1083 break;
961 }1084 }
962 case "bitSizeOf" : {1085 case "exp": {
963 const bitSizeOf = zigAnalysis.exprs[expr.bitSizeOf];1086 payloadHtml += "exp";
964 return "@bitSizeOf(" + exprName(bitSizeOf, opts) + ")";1087 break;
965 }1088 }
966 case "sizeOf" : {1089 case "exp2": {
967 const sizeOf = zigAnalysis.exprs[expr.sizeOf];1090 payloadHtml += "exp2";
968 return "@sizeOf(" + exprName(sizeOf, opts) + ")";1091 break;
969 }1092 }
970 case "builtinIndex" : {1093 case "log": {
971 const builtinIndex = zigAnalysis.exprs[expr.builtinIndex];1094 payloadHtml += "log";
972 return exprName(builtinIndex, opts);1095 break;
973 }1096 }
974 case "builtin": {1097 case "log2": {
975 const param_expr = zigAnalysis.exprs[expr.builtin.param];1098 payloadHtml += "log2";
976 let param = exprName(param_expr, opts);1099 break;
977
978
979 let payloadHtml = "@";
980 switch (expr.builtin.name) {
981 case "align_of": {
982 payloadHtml += "alignOf";
983 break;
984 }
985 case "bool_to_int": {
986 payloadHtml += "boolToInt";
987 break;
988 }
989 case "embed_file": {
990 payloadHtml += "embedFile";
991 break;
992 }
993 case "error_name": {
994 payloadHtml += "errorName";
995 break;
996 }
997 case "panic": {
998 payloadHtml += "panic";
999 break;
1000 }
1001 case "set_cold": {
1002 payloadHtml += "setCold";
1003 break;
1004 }
1005 case "set_runtime_safety": {
1006 payloadHtml += "setRuntimeSafety";
1007 break;
1008 }
1009 case "sqrt": {
1010 payloadHtml += "sqrt";
1011 break;
1012 }
1013 case "sin": {
1014 payloadHtml += "sin";
1015 break;
1016 }
1017 case "cos": {
1018 payloadHtml += "cos";
1019 break;
1020 }
1021 case "tan": {
1022 payloadHtml += "tan";
1023 break;
1024 }
1025 case "exp": {
1026 payloadHtml += "exp";
1027 break;
1028 }
1029 case "exp2": {
1030 payloadHtml += "exp2";
1031 break;
1032 }
1033 case "log": {
1034 payloadHtml += "log";
1035 break;
1036 }
1037 case "log2": {
1038 payloadHtml += "log2";
1039 break;
1040 }
1041 case "log10": {
1042 payloadHtml += "log10";
1043 break;
1044 }
1045 case "fabs": {
1046 payloadHtml += "fabs";
1047 break;
1048 }
1049 case "floor": {
1050 payloadHtml += "floor";
1051 break;
1052 }
1053 case "ceil": {
1054 payloadHtml += "ceil";
1055 break;
1056 }
1057 case "trunc": {
1058 payloadHtml += "trunc";
1059 break;
1060 }
1061 case "round": {
1062 payloadHtml += "round";
1063 break;
1064 }
1065 case "tag_name": {
1066 payloadHtml += "tagName";
1067 break;
1068 }
1069 case "reify": {
1070 payloadHtml += "Type";
1071 break;
1072 }
1073 case "type_name": {
1074 payloadHtml += "typeName";
1075 break;
1076 }
1077 case "frame_type": {
1078 payloadHtml += "Frame";
1079 break;
1080 }
1081 case "frame_size": {
1082 payloadHtml += "frameSize";
1083 break;
1084 }
1085 case "ptr_to_int": {
1086 payloadHtml += "ptrToInt";
1087 break;
1088 }
1089 case "error_to_int": {
1090 payloadHtml += "errorToInt";
1091 break;
1092 }
1093 case "int_to_error": {
1094 payloadHtml += "intToError";
1095 break;
1096 }
1097 case "maximum": {
1098 payloadHtml += "maximum";
1099 break;
1100 }
1101 case "minimum": {
1102 payloadHtml += "minimum";
1103 break;
1104 }
1105 case "bit_not": {
1106 return "~" + param;
1107 }
1108 case "clz": {
1109 return "@clz(T" + ", " + param + ")";
1110 }
1111 case "ctz": {
1112 return "@ctz(T" + ", " + param + ")";
1113 }
1114 case "pop_count": {
1115 return "@popCount(T" + ", " + param + ")";
1116 }
1117 case "byte_swap": {
1118 return "@byteSwap(T" + ", " + param + ")";
1119 }
1120 case "bit_reverse": {
1121 return "@bitReverse(T" + ", " + param + ")";
1122 }
1123 default: console.log("builtin function not handled yet or doesn't exist!");
1124 };
1125 return payloadHtml + "(" + param + ")";
1126
1127 }1100 }
1128 case "builtinBinIndex" : {1101 case "log10": {
1129 const builtinBinIndex = zigAnalysis.exprs[expr.builtinBinIndex];1102 payloadHtml += "log10";
1130 return exprName(builtinBinIndex, opts);1103 break;
1131 }1104 }
1132 case "builtinBin": {1105 case "fabs": {
1133 const lhsOp = zigAnalysis.exprs[expr.builtinBin.lhs];1106 payloadHtml += "fabs";
1134 const rhsOp = zigAnalysis.exprs[expr.builtinBin.rhs];1107 break;
1135 let lhs = exprName(lhsOp, opts);
1136 let rhs = exprName(rhsOp, opts);
1137
1138 let payloadHtml = "@";
1139 switch (expr.builtinBin.name) {
1140 case "float_to_int": {
1141 payloadHtml += "floatToInt";
1142 break;
1143 }
1144 case "int_to_float": {
1145 payloadHtml += "intToFloat";
1146 break;
1147 }
1148 case "int_to_ptr": {
1149 payloadHtml += "intToPtr";
1150 break;
1151 }
1152 case "int_to_enum": {
1153 payloadHtml += "intToEnum";
1154 break;
1155 }
1156 case "float_cast": {
1157 payloadHtml += "floatCast";
1158 break;
1159 }
1160 case "int_cast": {
1161 payloadHtml += "intCast";
1162 break;
1163 }
1164 case "ptr_cast": {
1165 payloadHtml += "ptrCast";
1166 break;
1167 }
1168 case "truncate": {
1169 payloadHtml += "truncate";
1170 break;
1171 }
1172 case "align_cast": {
1173 payloadHtml += "alignCast";
1174 break;
1175 }
1176 case "has_decl": {
1177 payloadHtml += "hasDecl";
1178 break;
1179 }
1180 case "has_field": {
1181 payloadHtml += "hasField";
1182 break;
1183 }
1184 case "bit_reverse": {
1185 payloadHtml += "bitReverse";
1186 break;
1187 }
1188 case "div_exact": {
1189 payloadHtml += "divExact";
1190 break;
1191 }
1192 case "div_floor": {
1193 payloadHtml += "divFloor";
1194 break;
1195 }
1196 case "div_trunc": {
1197 payloadHtml += "divTrunc";
1198 break;
1199 }
1200 case "mod": {
1201 payloadHtml += "mod";
1202 break;
1203 }
1204 case "rem": {
1205 payloadHtml += "rem";
1206 break;
1207 }
1208 case "mod_rem": {
1209 payloadHtml += "rem";
1210 break;
1211 }
1212 case "shl_exact": {
1213 payloadHtml += "shlExact";
1214 break;
1215 }
1216 case "shr_exact": {
1217 payloadHtml += "shrExact";
1218 break;
1219 }
1220 case "bitcast" : {
1221 payloadHtml += "bitCast";
1222 break;
1223 }
1224 case "align_cast" : {
1225 payloadHtml += "alignCast";
1226 break;
1227 }
1228 case "vector_type" : {
1229 payloadHtml += "Vector";
1230 break;
1231 }
1232 case "reduce": {
1233 payloadHtml += "reduce";
1234 break;
1235 }
1236 case "splat": {
1237 payloadHtml += "splat";
1238 break;
1239 }
1240 case "offset_of": {
1241 payloadHtml += "offsetOf";
1242 break;
1243 }
1244 case "bit_offset_of": {
1245 payloadHtml += "bitOffsetOf";
1246 break;
1247 }
1248 default: console.log("builtin function not handled yet or doesn't exist!");
1249 };
1250 return payloadHtml + "(" + lhs + ", " + rhs + ")";
1251
1252 }1108 }
1253 case "binOpIndex" : {1109 case "floor": {
1254 const binOpIndex = zigAnalysis.exprs[expr.binOpIndex];1110 payloadHtml += "floor";
1255 return exprName(binOpIndex, opts);1111 break;
1256 }1112 }
1257 case "binOp": {1113 case "ceil": {
1258 const lhsOp = zigAnalysis.exprs[expr.binOp.lhs];1114 payloadHtml += "ceil";
1259 const rhsOp = zigAnalysis.exprs[expr.binOp.rhs];1115 break;
1260 let lhs = exprName(lhsOp, opts);1116 }
1261 let rhs = exprName(rhsOp, opts);1117 case "trunc": {
12621118 payloadHtml += "trunc";
1263 let print_lhs = "";1119 break;
1264 let print_rhs = "";1120 }
12651121 case "round": {
1266 if (lhsOp['binOpIndex']) {1122 payloadHtml += "round";
1267 print_lhs = "(" + lhs + ")";1123 break;
1268 } else {1124 }
1269 print_lhs = lhs;1125 case "tag_name": {
1270 }1126 payloadHtml += "tagName";
1271 if (rhsOp['binOpIndex']) {1127 break;
1272 print_rhs = "(" + rhs + ")";1128 }
1273 } else {1129 case "reify": {
1274 print_rhs = rhs;1130 payloadHtml += "Type";
1275 }1131 break;
1132 }
1133 case "type_name": {
1134 payloadHtml += "typeName";
1135 break;
1136 }
1137 case "frame_type": {
1138 payloadHtml += "Frame";
1139 break;
1140 }
1141 case "frame_size": {
1142 payloadHtml += "frameSize";
1143 break;
1144 }
1145 case "ptr_to_int": {
1146 payloadHtml += "ptrToInt";
1147 break;
1148 }
1149 case "error_to_int": {
1150 payloadHtml += "errorToInt";
1151 break;
1152 }
1153 case "int_to_error": {
1154 payloadHtml += "intToError";
1155 break;
1156 }
1157 case "maximum": {
1158 payloadHtml += "maximum";
1159 break;
1160 }
1161 case "minimum": {
1162 payloadHtml += "minimum";
1163 break;
1164 }
1165 case "bit_not": {
1166 return "~" + param;
1167 }
1168 case "clz": {
1169 return "@clz(T" + ", " + param + ")";
1170 }
1171 case "ctz": {
1172 return "@ctz(T" + ", " + param + ")";
1173 }
1174 case "pop_count": {
1175 return "@popCount(T" + ", " + param + ")";
1176 }
1177 case "byte_swap": {
1178 return "@byteSwap(T" + ", " + param + ")";
1179 }
1180 case "bit_reverse": {
1181 return "@bitReverse(T" + ", " + param + ")";
1182 }
1183 default:
1184 console.log("builtin function not handled yet or doesn't exist!");
1185 }
1186 return payloadHtml + "(" + param + ")";
1187 }
1188 case "builtinBinIndex": {
1189 const builtinBinIndex = zigAnalysis.exprs[expr.builtinBinIndex];
1190 return exprName(builtinBinIndex, opts);
1191 }
1192 case "builtinBin": {
1193 const lhsOp = zigAnalysis.exprs[expr.builtinBin.lhs];
1194 const rhsOp = zigAnalysis.exprs[expr.builtinBin.rhs];
1195 let lhs = exprName(lhsOp, opts);
1196 let rhs = exprName(rhsOp, opts);
1197
1198 let payloadHtml = "@";
1199 switch (expr.builtinBin.name) {
1200 case "float_to_int": {
1201 payloadHtml += "floatToInt";
1202 break;
1203 }
1204 case "int_to_float": {
1205 payloadHtml += "intToFloat";
1206 break;
1207 }
1208 case "int_to_ptr": {
1209 payloadHtml += "intToPtr";
1210 break;
1211 }
1212 case "int_to_enum": {
1213 payloadHtml += "intToEnum";
1214 break;
1215 }
1216 case "float_cast": {
1217 payloadHtml += "floatCast";
1218 break;
1219 }
1220 case "int_cast": {
1221 payloadHtml += "intCast";
1222 break;
1223 }
1224 case "ptr_cast": {
1225 payloadHtml += "ptrCast";
1226 break;
1227 }
1228 case "truncate": {
1229 payloadHtml += "truncate";
1230 break;
1231 }
1232 case "align_cast": {
1233 payloadHtml += "alignCast";
1234 break;
1235 }
1236 case "has_decl": {
1237 payloadHtml += "hasDecl";
1238 break;
1239 }
1240 case "has_field": {
1241 payloadHtml += "hasField";
1242 break;
1243 }
1244 case "bit_reverse": {
1245 payloadHtml += "bitReverse";
1246 break;
1247 }
1248 case "div_exact": {
1249 payloadHtml += "divExact";
1250 break;
1251 }
1252 case "div_floor": {
1253 payloadHtml += "divFloor";
1254 break;
1255 }
1256 case "div_trunc": {
1257 payloadHtml += "divTrunc";
1258 break;
1259 }
1260 case "mod": {
1261 payloadHtml += "mod";
1262 break;
1263 }
1264 case "rem": {
1265 payloadHtml += "rem";
1266 break;
1267 }
1268 case "mod_rem": {
1269 payloadHtml += "rem";
1270 break;
1271 }
1272 case "shl_exact": {
1273 payloadHtml += "shlExact";
1274 break;
1275 }
1276 case "shr_exact": {
1277 payloadHtml += "shrExact";
1278 break;
1279 }
1280 case "bitcast": {
1281 payloadHtml += "bitCast";
1282 break;
1283 }
1284 case "align_cast": {
1285 payloadHtml += "alignCast";
1286 break;
1287 }
1288 case "vector_type": {
1289 payloadHtml += "Vector";
1290 break;
1291 }
1292 case "reduce": {
1293 payloadHtml += "reduce";
1294 break;
1295 }
1296 case "splat": {
1297 payloadHtml += "splat";
1298 break;
1299 }
1300 case "offset_of": {
1301 payloadHtml += "offsetOf";
1302 break;
1303 }
1304 case "bit_offset_of": {
1305 payloadHtml += "bitOffsetOf";
1306 break;
1307 }
1308 default:
1309 console.log("builtin function not handled yet or doesn't exist!");
1310 }
1311 return payloadHtml + "(" + lhs + ", " + rhs + ")";
1312 }
1313 case "binOpIndex": {
1314 const binOpIndex = zigAnalysis.exprs[expr.binOpIndex];
1315 return exprName(binOpIndex, opts);
1316 }
1317 case "binOp": {
1318 const lhsOp = zigAnalysis.exprs[expr.binOp.lhs];
1319 const rhsOp = zigAnalysis.exprs[expr.binOp.rhs];
1320 let lhs = exprName(lhsOp, opts);
1321 let rhs = exprName(rhsOp, opts);
12761322
1277 let operator = "";1323 let print_lhs = "";
1324 let print_rhs = "";
12781325
1279 switch (expr.binOp.name) {1326 if (lhsOp["binOpIndex"]) {
1280 case "add": {1327 print_lhs = "(" + lhs + ")";
1281 operator += "+";1328 } else {
1282 break;1329 print_lhs = lhs;
1283 }1330 }
1284 case "addwrap": {1331 if (rhsOp["binOpIndex"]) {
1285 operator += "+%";1332 print_rhs = "(" + rhs + ")";
1286 break;1333 } else {
1287 }1334 print_rhs = rhs;
1288 case "add_sat": {1335 }
1289 operator += "+|";
1290 break;
1291 }
1292 case "sub": {
1293 operator += "-";
1294 break;
1295 }
1296 case "subwrap": {
1297 operator += "-%";
1298 break;
1299 }
1300 case "sub_sat": {
1301 operator += "-|";
1302 break;
1303 }
1304 case "mul": {
1305 operator += "*";
1306 break;
1307 }
1308 case "mulwrap": {
1309 operator += "*%";
1310 break;
1311 }
1312 case "mul_sat": {
1313 operator += "*|";
1314 break;
1315 }
1316 case "div": {
1317 operator += "/";
1318 break;
1319 }
1320 case "shl": {
1321 operator += "<<";
1322 break;
1323 }
1324 case "shl_sat": {
1325 operator += "<<|";
1326 break;
1327 }
1328 case "shr": {
1329 operator += ">>";
1330 break;
1331 }
1332 case "bit_or" : {
1333 operator += "|";
1334 break;
1335 }
1336 case "bit_and" : {
1337 operator += "&";
1338 break;
1339 }
1340 case "array_cat" : {
1341 operator += "++";
1342 break;
1343 }
1344 case "array_mul" : {
1345 operator += "**";
1346 break;
1347 }
1348 default: console.log("operator not handled yet or doesn't exist!");
1349 };
13501336
1351 return print_lhs + " " + operator + " " + print_rhs;1337 let operator = "";
13521338
1339 switch (expr.binOp.name) {
1340 case "add": {
1341 operator += "+";
1342 break;
1353 }1343 }
1354 case "errorSets": {1344 case "addwrap": {
1355 const errUnionObj = zigAnalysis.types[expr.errorSets];1345 operator += "+%";
1356 let lhs = exprName(errUnionObj.lhs, opts);1346 break;
1357 let rhs = exprName(errUnionObj.rhs, opts);
1358 return lhs + " || " + rhs;
1359
1360 }1347 }
1361 case "errorUnion": {1348 case "add_sat": {
1362 const errUnionObj = zigAnalysis.types[expr.errorUnion];1349 operator += "+|";
1363 let lhs = exprName(errUnionObj.lhs, opts);1350 break;
1364 let rhs = exprName(errUnionObj.rhs, opts);
1365 return lhs + "!" + rhs;
1366
1367 }1351 }
1368 case "struct": {1352 case "sub": {
1369 const struct_name = zigAnalysis.decls[expr.struct[0].val.typeRef.refPath[0].declRef].name;1353 operator += "-";
1370 let struct_body = "";1354 break;
1371 struct_body += struct_name + "{ ";
1372 for (let i = 0; i < expr.struct.length; i++) {
1373 const val = expr.struct[i].name
1374 const exprArg = zigAnalysis.exprs[expr.struct[i].val.expr.as.exprArg];
1375 let value_field = exprArg[Object.keys(exprArg)[0]];
1376 if (value_field instanceof Object) {
1377 value_field = zigAnalysis.decls[value_field[0].val.typeRef.refPath[0].declRef].name;
1378 };
1379 struct_body += "." + val + " = " + value_field;
1380 if (i !== expr.struct.length - 1) {
1381 struct_body += ", ";
1382 } else {
1383 struct_body += " ";
1384 }
1385 }
1386 struct_body += "}";
1387 return struct_body;
1388 }
1389 case "typeOf_peer": {
1390 let payloadHtml = "@TypeOf("
1391 for (let i = 0; i < expr.typeOf_peer.length; i++) {
1392 let elem = zigAnalysis.exprs[expr.typeOf_peer[i]];
1393 payloadHtml += exprName(elem, {wantHtml: true, wantLink:true});
1394 if (i !== expr.typeOf_peer.length - 1) {
1395 payloadHtml += ", ";
1396 }
1397 }
1398 payloadHtml += ")";
1399 return payloadHtml;
1400
1401 }1355 }
1402 case "alignOf": {1356 case "subwrap": {
1403 const alignRefArg = zigAnalysis.exprs[expr.alignOf];1357 operator += "-%";
1404 let payloadHtml = "@alignOf(" + exprName(alignRefArg, {wantHtml: true, wantLink:true}) + ")";1358 break;
1405 return payloadHtml;
1406 }1359 }
1407 case "typeOf": {1360 case "sub_sat": {
1408 const typeRefArg = zigAnalysis.exprs[expr.typeOf];1361 operator += "-|";
1409 let payloadHtml = "@TypeOf(" + exprName(typeRefArg, {wantHtml: true, wantLink:true}) + ")";1362 break;
1410 return payloadHtml;
1411 }1363 }
1412 case "typeInfo": {1364 case "mul": {
1413 const typeRefArg = zigAnalysis.exprs[expr.typeInfo];1365 operator += "*";
1414 let payloadHtml = "@typeInfo(" + exprName(typeRefArg, {wantHtml: true, wantLink:true}) + ")";1366 break;
1415 return payloadHtml;
1416 }1367 }
1417 case "null": {1368 case "mulwrap": {
1418 return "null";1369 operator += "*%";
1370 break;
1419 }1371 }
1420 case "array": {1372 case "mul_sat": {
1421 let payloadHtml = ".{";1373 operator += "*|";
1422 for (let i = 0; i < expr.array.length; i++) {1374 break;
1423 if (i != 0) payloadHtml += ", ";1375 }
1424 let elem = zigAnalysis.exprs[expr.array[i]];1376 case "div": {
1425 payloadHtml += exprName(elem, opts);1377 operator += "/";
1426 }1378 break;
1427 return payloadHtml + "}";1379 }
1380 case "shl": {
1381 operator += "<<";
1382 break;
1383 }
1384 case "shl_sat": {
1385 operator += "<<|";
1386 break;
1387 }
1388 case "shr": {
1389 operator += ">>";
1390 break;
1391 }
1392 case "bit_or": {
1393 operator += "|";
1394 break;
1395 }
1396 case "bit_and": {
1397 operator += "&";
1398 break;
1399 }
1400 case "array_cat": {
1401 operator += "++";
1402 break;
1403 }
1404 case "array_mul": {
1405 operator += "**";
1406 break;
1428 }1407 }
1429 case "comptimeExpr": {1408 default:
1430 return zigAnalysis.comptimeExprs[expr.comptimeExpr].code;1409 console.log("operator not handled yet or doesn't exist!");
1410 }
1411
1412 return print_lhs + " " + operator + " " + print_rhs;
1413 }
1414 case "errorSets": {
1415 const errUnionObj = zigAnalysis.types[expr.errorSets];
1416 let lhs = exprName(errUnionObj.lhs, opts);
1417 let rhs = exprName(errUnionObj.rhs, opts);
1418 return lhs + " || " + rhs;
1419 }
1420 case "errorUnion": {
1421 const errUnionObj = zigAnalysis.types[expr.errorUnion];
1422 let lhs = exprName(errUnionObj.lhs, opts);
1423 let rhs = exprName(errUnionObj.rhs, opts);
1424 return lhs + "!" + rhs;
1425 }
1426 case "struct": {
1427 // const struct_name =
1428 // zigAnalysis.decls[expr.struct[0].val.typeRef.refPath[0].declRef].name;
1429 const struct_name = ".";
1430 let struct_body = "";
1431 struct_body += struct_name + "{ ";
1432 for (let i = 0; i < expr.struct.length; i++) {
1433 const fv = expr.struct[i];
1434 const field_name = fv.name;
1435 const field_value = exprName(fv.val.expr, opts);
1436 // TODO: commented out because it seems not needed. if it deals
1437 // with a corner case, please add a comment when re-enabling it.
1438 // let field_value = exprArg[Object.keys(exprArg)[0]];
1439 // if (field_value instanceof Object) {
1440 // value_field = exprName(value_field)
1441 // zigAnalysis.decls[value_field[0].val.typeRef.refPath[0].declRef]
1442 // .name;
1443 // }
1444 struct_body += "." + field_name + " = " + field_value;
1445 if (i !== expr.struct.length - 1) {
1446 struct_body += ", ";
1447 } else {
1448 struct_body += " ";
1449 }
1450 }
1451 struct_body += "}";
1452 return struct_body;
1453 }
1454 case "typeOf_peer": {
1455 let payloadHtml = "@TypeOf(";
1456 for (let i = 0; i < expr.typeOf_peer.length; i++) {
1457 let elem = zigAnalysis.exprs[expr.typeOf_peer[i]];
1458 payloadHtml += exprName(elem, { wantHtml: true, wantLink: true });
1459 if (i !== expr.typeOf_peer.length - 1) {
1460 payloadHtml += ", ";
1461 }
1462 }
1463 payloadHtml += ")";
1464 return payloadHtml;
1465 }
1466 case "alignOf": {
1467 const alignRefArg = zigAnalysis.exprs[expr.alignOf];
1468 let payloadHtml =
1469 "@alignOf(" +
1470 exprName(alignRefArg, { wantHtml: true, wantLink: true }) +
1471 ")";
1472 return payloadHtml;
1473 }
1474 case "typeOf": {
1475 const typeRefArg = zigAnalysis.exprs[expr.typeOf];
1476 let payloadHtml =
1477 "@TypeOf(" +
1478 exprName(typeRefArg, { wantHtml: true, wantLink: true }) +
1479 ")";
1480 return payloadHtml;
1481 }
1482 case "typeInfo": {
1483 const typeRefArg = zigAnalysis.exprs[expr.typeInfo];
1484 let payloadHtml =
1485 "@typeInfo(" +
1486 exprName(typeRefArg, { wantHtml: true, wantLink: true }) +
1487 ")";
1488 return payloadHtml;
1489 }
1490 case "null": {
1491 return "null";
1492 }
1493 case "array": {
1494 let payloadHtml = ".{";
1495 for (let i = 0; i < expr.array.length; i++) {
1496 if (i != 0) payloadHtml += ", ";
1497 let elem = zigAnalysis.exprs[expr.array[i]];
1498 payloadHtml += exprName(elem, opts);
1499 }
1500 return payloadHtml + "}";
1501 }
1502 case "comptimeExpr": {
1503 return zigAnalysis.comptimeExprs[expr.comptimeExpr].code;
1504 }
1505 case "call": {
1506 let call = zigAnalysis.calls[expr.call];
1507 let payloadHtml = "";
1508
1509 switch (Object.keys(call.func)[0]) {
1510 default:
1511 throw "TODO";
1512 case "declRef":
1513 case "refPath": {
1514 payloadHtml += exprName(call.func, opts);
1515 break;
1431 }1516 }
1432 case "call": {1517 }
1433 let call = zigAnalysis.calls[expr.call];1518 payloadHtml += "(";
1434 let payloadHtml = "";
14351519
1520 for (let i = 0; i < call.args.length; i++) {
1521 if (i != 0) payloadHtml += ", ";
1522 payloadHtml += exprName(call.args[i], opts);
1523 }
14361524
1437 switch(Object.keys(call.func)[0]){1525 payloadHtml += ")";
1438 default: throw "TODO";1526 return payloadHtml;
1439 case "declRef":1527 }
1440 case "refPath": {1528 case "as": {
1441 payloadHtml += exprName(call.func, opts);1529 // @Check : this should be done in backend because there are legit @as() calls
1442 break;1530 // const typeRefArg = zigAnalysis.exprs[expr.as.typeRefArg];
1443 }1531 const exprArg = zigAnalysis.exprs[expr.as.exprArg];
1444 }1532 // return "@as(" + exprName(typeRefArg, opts) +
1445 payloadHtml += "(";1533 // ", " + exprName(exprArg, opts) + ")";
1534 return exprName(exprArg, opts);
1535 }
1536 case "declRef": {
1537 return zigAnalysis.decls[expr.declRef].name;
1538 }
1539 case "refPath": {
1540 return expr.refPath.map((x) => exprName(x, opts)).join(".");
1541 }
1542 case "int": {
1543 return "" + expr.int;
1544 }
1545 case "float": {
1546 return "" + expr.float.toFixed(2);
1547 }
1548 case "float128": {
1549 return "" + expr.float128.toFixed(2);
1550 }
1551 case "undefined": {
1552 return "undefined";
1553 }
1554 case "string": {
1555 return '"' + escapeHtml(expr.string) + '"';
1556 }
14461557
1447 for (let i = 0; i < call.args.length; i++) {1558 case "anytype": {
1448 if (i != 0) payloadHtml += ", ";1559 return "anytype";
1449 payloadHtml += exprName(call.args[i], opts);1560 }
1450 }1561
1562 case "this": {
1563 return "@This()";
1564 }
14511565
1452 payloadHtml += ")";1566 case "type": {
1453 return payloadHtml;1567 let name = "";
1568
1569 let typeObj = expr.type;
1570 if (typeof typeObj === "number") typeObj = zigAnalysis.types[typeObj];
1571 switch (typeObj.kind) {
1572 default:
1573 throw "TODO";
1574 case typeKinds.Struct: {
1575 let structObj = typeObj;
1576 return structObj;
1454 }1577 }
1455 case "as": {1578 case typeKinds.Enum: {
1456 // @Check : this should be done in backend because there are legit @as() calls1579 let enumObj = typeObj;
1457 // const typeRefArg = zigAnalysis.exprs[expr.as.typeRefArg];1580 return enumObj;
1458 const exprArg = zigAnalysis.exprs[expr.as.exprArg];
1459 // return "@as(" + exprName(typeRefArg, opts) +
1460 // ", " + exprName(exprArg, opts) + ")";
1461 return exprName(exprArg, opts);
1462 }1581 }
1463 case "declRef": {1582 case typeKinds.Opaque: {
1464 return zigAnalysis.decls[expr.declRef].name;1583 let opaqueObj = typeObj;
1584
1585 return opaqueObj.name;
1465 }1586 }
1466 case "refPath": {1587 case typeKinds.ComptimeExpr: {
1467 return expr.refPath.map(x => exprName(x, opts)).join(".");1588 return "anyopaque";
1468 }1589 }
1469 case "int": {1590 case typeKinds.Array: {
1470 return "" + expr.int;1591 let arrayObj = typeObj;
1592 let name = "[";
1593 let lenName = exprName(arrayObj.len, opts);
1594 let sentinel = arrayObj.sentinel
1595 ? ":" + exprName(arrayObj.sentinel, opts)
1596 : "";
1597 // let is_mutable = arrayObj.is_multable ? "const " : "";
1598
1599 if (opts.wantHtml) {
1600 name +=
1601 '<span class="tok-number">' + lenName + sentinel + "</span>";
1602 } else {
1603 name += lenName + sentinel;
1604 }
1605 name += "]";
1606 // name += is_mutable;
1607 name += exprName(arrayObj.child, opts);
1608 return name;
1471 }1609 }
1472 case "float": {1610 case typeKinds.Optional:
1473 return "" + expr.float.toFixed(2);1611 return "?" + exprName(typeObj.child, opts);
1612 case typeKinds.Pointer: {
1613 let ptrObj = typeObj;
1614 let sentinel = ptrObj.sentinel
1615 ? ":" + exprName(ptrObj.sentinel, opts)
1616 : "";
1617 let is_mutable = !ptrObj.is_mutable ? "const " : "";
1618 let name = "";
1619 switch (ptrObj.size) {
1620 default:
1621 console.log("TODO: implement unhandled pointer size case");
1622 case pointerSizeEnum.One:
1623 name += "*";
1624 name += is_mutable;
1625 break;
1626 case pointerSizeEnum.Many:
1627 name += "[*";
1628 name += sentinel;
1629 name += "]";
1630 name += is_mutable;
1631 break;
1632 case pointerSizeEnum.Slice:
1633 if (ptrObj.is_ref) {
1634 name += "*";
1635 }
1636 name += "[";
1637 name += sentinel;
1638 name += "]";
1639 name += is_mutable;
1640 break;
1641 case pointerSizeEnum.C:
1642 name += "[*c";
1643 name += sentinel;
1644 name += "]";
1645 name += is_mutable;
1646 break;
1647 }
1648 // @check: after the major changes in arrays the consts are came from switch above
1649 // if (!ptrObj.is_mutable) {
1650 // if (opts.wantHtml) {
1651 // name += '<span class="tok-kw">const</span> ';
1652 // } else {
1653 // name += "const ";
1654 // }
1655 // }
1656 if (ptrObj.is_allowzero) {
1657 name += "allowzero ";
1658 }
1659 if (ptrObj.is_volatile) {
1660 name += "volatile ";
1661 }
1662 if (ptrObj.has_addrspace) {
1663 name += "addrspace(";
1664 name += "." + "";
1665 name += ") ";
1666 }
1667 if (ptrObj.has_align) {
1668 let align = exprName(ptrObj.align, opts);
1669 if (opts.wantHtml) {
1670 name += '<span class="tok-kw">align</span>(';
1671 } else {
1672 name += "align(";
1673 }
1674 if (opts.wantHtml) {
1675 name += '<span class="tok-number">' + align + "</span>";
1676 } else {
1677 name += align;
1678 }
1679 if (ptrObj.hostIntBytes != null) {
1680 name += ":";
1681 if (opts.wantHtml) {
1682 name +=
1683 '<span class="tok-number">' +
1684 ptrObj.bitOffsetInHost +
1685 "</span>";
1686 } else {
1687 name += ptrObj.bitOffsetInHost;
1688 }
1689 name += ":";
1690 if (opts.wantHtml) {
1691 name +=
1692 '<span class="tok-number">' +
1693 ptrObj.hostIntBytes +
1694 "</span>";
1695 } else {
1696 name += ptrObj.hostIntBytes;
1697 }
1698 }
1699 name += ") ";
1700 }
1701 //name += typeValueName(ptrObj.child, wantHtml, wantSubLink, null);
1702 name += exprName(ptrObj.child, opts);
1703 return name;
1474 }1704 }
1475 case "float128": {1705 case typeKinds.Float: {
1476 return "" + expr.float128.toFixed(2);1706 let floatObj = typeObj;
1707
1708 if (opts.wantHtml) {
1709 return '<span class="tok-type">' + floatObj.name + "</span>";
1710 } else {
1711 return floatObj.name;
1712 }
1477 }1713 }
1478 case "undefined": {1714 case typeKinds.Int: {
1479 return "undefined";1715 let intObj = typeObj;
1716 let name = intObj.name;
1717 if (opts.wantHtml) {
1718 return '<span class="tok-type">' + name + "</span>";
1719 } else {
1720 return name;
1721 }
1480 }1722 }
1481 case "string": {1723 case typeKinds.ComptimeInt:
1482 return "\"" + escapeHtml(expr.string) + "\"";1724 if (opts.wantHtml) {
1725 return '<span class="tok-type">comptime_int</span>';
1726 } else {
1727 return "comptime_int";
1728 }
1729 case typeKinds.ComptimeFloat:
1730 if (opts.wantHtml) {
1731 return '<span class="tok-type">comptime_float</span>';
1732 } else {
1733 return "comptime_float";
1734 }
1735 case typeKinds.Type:
1736 if (opts.wantHtml) {
1737 return '<span class="tok-type">type</span>';
1738 } else {
1739 return "type";
1740 }
1741 case typeKinds.Bool:
1742 if (opts.wantHtml) {
1743 return '<span class="tok-type">bool</span>';
1744 } else {
1745 return "bool";
1746 }
1747 case typeKinds.Void:
1748 if (opts.wantHtml) {
1749 return '<span class="tok-type">void</span>';
1750 } else {
1751 return "void";
1752 }
1753 case typeKinds.EnumLiteral:
1754 if (opts.wantHtml) {
1755 return '<span class="tok-type">(enum literal)</span>';
1756 } else {
1757 return "(enum literal)";
1758 }
1759 case typeKinds.NoReturn:
1760 if (opts.wantHtml) {
1761 return '<span class="tok-type">noreturn</span>';
1762 } else {
1763 return "noreturn";
1764 }
1765 case typeKinds.ErrorSet: {
1766 let errSetObj = typeObj;
1767 if (errSetObj.fields == null) {
1768 return '<span class="tok-type">anyerror</span>';
1769 } else if (errSetObj.fields.length == 0) {
1770 return "error{}";
1771 } else if (errSetObj.fields.length == 1) {
1772 return "error{" + errSetObj.fields[0].name + "}";
1773 } else {
1774 // throw "TODO";
1775 let html = "error{ " + errSetObj.fields[0].name;
1776 for (let i = 1; i < errSetObj.fields.length; i++) html += ", " + errSetObj.fields[i].name;
1777 html += " }";
1778 return html;
1779 }
1483 }1780 }
14841781
1485 case "anytype": {1782 case typeKinds.ErrorUnion: {
1486 return "anytype";1783 let errUnionObj = typeObj;
1784 let lhs = exprName(errUnionObj.lhs, opts);
1785 let rhs = exprName(errUnionObj.rhs, opts);
1786 return lhs + "!" + rhs;
1487 }1787 }
14881788 case typeKinds.InferredErrorUnion: {
1489 case "this":{1789 let errUnionObj = typeObj;
1490 return "@This()";1790 let payload = exprName(errUnionObj.payload, opts);
1791 return "!" + payload;
1491 }1792 }
1793 case typeKinds.Fn: {
1794 let fnObj = typeObj;
1795 let payloadHtml = "";
1796 if (opts.wantHtml) {
1797 if (fnObj.is_extern) {
1798 payloadHtml += "pub extern ";
1799 }
1800 if (fnObj.has_lib_name) {
1801 payloadHtml += '"' + fnObj.lib_name + '" ';
1802 }
1803 payloadHtml += '<span class="tok-kw">fn</span>';
1804 if (opts.fnDecl) {
1805 payloadHtml += ' <span class="tok-fn">';
1806 if (opts.linkFnNameDecl) {
1807 payloadHtml +=
1808 '<a href="' +
1809 opts.linkFnNameDecl +
1810 '">' +
1811 escapeHtml(opts.fnDecl.name) +
1812 "</a>";
1813 } else {
1814 payloadHtml += escapeHtml(opts.fnDecl.name);
1815 }
1816 payloadHtml += "</span>";
1817 }
1818 } else {
1819 payloadHtml += "fn ";
1820 }
1821 payloadHtml += "(";
1822 if (fnObj.params) {
1823 let fields = null;
1824 let isVarArgs = false;
1825 let fnNode = zigAnalysis.astNodes[fnObj.src];
1826 fields = fnNode.fields;
1827 isVarArgs = fnNode.varArgs;
1828
1829 for (let i = 0; i < fnObj.params.length; i += 1) {
1830 if (i != 0) {
1831 payloadHtml += ", ";
1832 }
14921833
1493 case "type": {1834 payloadHtml +=
1494 let name = "";1835 "<span class='argBreaker'><br>&nbsp;&nbsp;&nbsp;&nbsp;</span>";
1836 let value = fnObj.params[i];
1837 let paramValue = resolveValue({ expr: value });
14951838
1496 let typeObj = expr.type;1839 if (fields != null) {
1497 if (typeof typeObj === 'number') typeObj = zigAnalysis.types[typeObj];1840 let paramNode = zigAnalysis.astNodes[fields[i]];
1498 switch (typeObj.kind) {
1499 default: throw "TODO";
1500 case typeKinds.Struct:
1501 {
1502 let structObj = (typeObj);
1503 return structObj;
1504 }
1505 case typeKinds.Enum:
1506 {
1507 let enumObj = (typeObj);
1508 return enumObj;
1509 }
1510 case typeKinds.Opaque:
1511 {
1512 let opaqueObj = (typeObj);
15131841
1514 return opaqueObj.name;1842 if (paramNode.varArgs) {
1843 payloadHtml += "...";
1844 continue;
1515 }1845 }
1516 case typeKinds.ComptimeExpr:1846
1517 {1847 if (paramNode.noalias) {
1518 return "anyopaque";1848 if (opts.wantHtml) {
1849 payloadHtml += '<span class="tok-kw">noalias</span> ';
1850 } else {
1851 payloadHtml += "noalias ";
1852 }
1519 }1853 }
1520 case typeKinds.Array:
1521 {
1522 let arrayObj = typeObj;
1523 let name = "[";
1524 let lenName = exprName(arrayObj.len, opts);
1525 let sentinel = arrayObj.sentinel ? ":"+exprName(arrayObj.sentinel, opts) : "";
1526 // let is_mutable = arrayObj.is_multable ? "const " : "";
15271854
1855 if (paramNode.comptime) {
1528 if (opts.wantHtml) {1856 if (opts.wantHtml) {
1529 name +=1857 payloadHtml += '<span class="tok-kw">comptime</span> ';
1530 '<span class="tok-number">' + lenName + sentinel + "</span>";
1531 } else {1858 } else {
1532 name += lenName + sentinel;1859 payloadHtml += "comptime ";
1533 }1860 }
1534 name += "]";
1535 // name += is_mutable;
1536 name += exprName(arrayObj.child, opts);
1537 return name;
1538 }1861 }
1539 case typeKinds.Optional:1862
1540 return "?" + exprName((typeObj).child, opts);1863 let paramName = paramNode.name;
1541 case typeKinds.Pointer:1864 if (paramName != null) {
1542 {1865 // skip if it matches the type name
1543 let ptrObj = (typeObj);1866 if (!shouldSkipParamName(paramValue, paramName)) {
1544 let sentinel = ptrObj.sentinel ? ":"+exprName(ptrObj.sentinel, opts) : "";1867 payloadHtml += paramName + ": ";
1545 let is_mutable = !ptrObj.is_mutable ? "const " : "";1868 }
1546 let name = "";
1547 switch (ptrObj.size) {
1548 default:
1549 console.log("TODO: implement unhandled pointer size case");
1550 case pointerSizeEnum.One:
1551 name += "*";
1552 name += is_mutable;
1553 break;
1554 case pointerSizeEnum.Many:
1555 name += "[*";
1556 name += sentinel;
1557 name += "]";
1558 name += is_mutable;
1559 break;
1560 case pointerSizeEnum.Slice:
1561 if (ptrObj.is_ref) {
1562 name += "*";
1563 }
1564 name += "[";
1565 name += sentinel;
1566 name += "]";
1567 name += is_mutable;
1568 break;
1569 case pointerSizeEnum.C:
1570 name += "[*c";
1571 name += sentinel;
1572 name += "]";
1573 name += is_mutable;
1574 break;
1575 }
1576 // @check: after the major changes in arrays the consts are came from switch above
1577 // if (!ptrObj.is_mutable) {
1578 // if (opts.wantHtml) {
1579 // name += '<span class="tok-kw">const</span> ';
1580 // } else {
1581 // name += "const ";
1582 // }
1583 // }
1584 if (ptrObj.is_allowzero) {
1585 name += "allowzero ";
1586 }
1587 if (ptrObj.is_volatile) {
1588 name += "volatile ";
1589 }
1590 if (ptrObj.has_addrspace) {
1591 name += "addrspace(";
1592 name += "." + "";
1593 name += ") ";
1594 }
1595 if (ptrObj.has_align) {
1596 let align = exprName(ptrObj.align, opts);
1597 if (opts.wantHtml) {
1598 name += '<span class="tok-kw">align</span>(';
1599 } else {
1600 name += "align(";
1601 }
1602 if (opts.wantHtml) {
1603 name += '<span class="tok-number">' + align + '</span>';
1604 } else {
1605 name += align;
1606 }
1607 if (ptrObj.hostIntBytes != null) {
1608 name += ":";
1609 if (opts.wantHtml) {
1610 name += '<span class="tok-number">' + ptrObj.bitOffsetInHost + '</span>';
1611 } else {
1612 name += ptrObj.bitOffsetInHost;
1613 }
1614 name += ":";
1615 if (opts.wantHtml) {
1616 name += '<span class="tok-number">' + ptrObj.hostIntBytes + '</span>';
1617 } else {
1618 name += ptrObj.hostIntBytes;
1619 }
1620 }
1621 name += ") ";
1622 }
1623 //name += typeValueName(ptrObj.child, wantHtml, wantSubLink, null);
1624 name += exprName(ptrObj.child, opts);
1625 return name;
1626 }1869 }
1627 case typeKinds.Float:1870 }
1628 {1871
1629 let floatObj = (typeObj);1872 if (isVarArgs && i === fnObj.params.length - 1) {
16301873 payloadHtml += "...";
1631 if (opts.wantHtml) {1874 } else if ("alignOf" in value) {
1632 return '<span class="tok-type">' + floatObj.name + '</span>';1875 if (opts.wantHtml) {
1633 } else {1876 payloadHtml += '<a href="">';
1634 return floatObj.name;1877 payloadHtml +=
1635 }1878 '<span class="tok-kw" style="color:lightblue;">' +
1879 exprName(value, opts) +
1880 "</span>";
1881 payloadHtml += "</a>";
1882 } else {
1883 payloadHtml += exprName(value, opts);
1636 }1884 }
1637 case typeKinds.Int:1885 } else if ("typeOf" in value) {
1638 {1886 if (opts.wantHtml) {
1639 let intObj = (typeObj);1887 payloadHtml += '<a href="">';
1640 let name = intObj.name;1888 payloadHtml +=
1641 if (opts.wantHtml) {1889 '<span class="tok-kw" style="color:lightblue;">' +
1642 return '<span class="tok-type">' + name + '</span>';1890 exprName(value, opts) +
1643 } else {1891 "</span>";
1644 return name;1892 payloadHtml += "</a>";
1645 }1893 } else {
1894 payloadHtml += exprName(value, opts);
1646 }1895 }
1647 case typeKinds.ComptimeInt:1896 } else if ("typeOf_peer" in value) {
1648 if (opts.wantHtml) {1897 if (opts.wantHtml) {
1649 return '<span class="tok-type">comptime_int</span>';1898 payloadHtml += '<a href="">';
1650 } else {1899 payloadHtml +=
1651 return "comptime_int";1900 '<span class="tok-kw" style="color:lightblue;">' +
1652 }1901 exprName(value, opts) +
1653 case typeKinds.ComptimeFloat:1902 "</span>";
1654 if (opts.wantHtml) {1903 payloadHtml += "</a>";
1655 return '<span class="tok-type">comptime_float</span>';1904 } else {
1656 } else {1905 payloadHtml += exprName(value, opts);
1657 return "comptime_float";
1658 }
1659 case typeKinds.Type:
1660 if (opts.wantHtml) {
1661 return '<span class="tok-type">type</span>';
1662 } else {
1663 return "type";
1664 }
1665 case typeKinds.Bool:
1666 if (opts.wantHtml) {
1667 return '<span class="tok-type">bool</span>';
1668 } else {
1669 return "bool";
1670 }
1671 case typeKinds.Void:
1672 if (opts.wantHtml) {
1673 return '<span class="tok-type">void</span>';
1674 } else {
1675 return "void";
1676 }
1677 case typeKinds.EnumLiteral:
1678 if (opts.wantHtml) {
1679 return '<span class="tok-type">(enum literal)</span>';
1680 } else {
1681 return "(enum literal)";
1682 }
1683 case typeKinds.NoReturn:
1684 if (opts.wantHtml) {
1685 return '<span class="tok-type">noreturn</span>';
1686 } else {
1687 return "noreturn";
1688 }
1689 case typeKinds.ErrorSet:
1690 {
1691 let errSetObj = (typeObj);
1692 if (errSetObj.fields == null) {
1693 return '<span class="tok-type">anyerror</span>';
1694 } else {
1695 // throw "TODO";
1696 let html = "error{" + errSetObj.fields[0].name + "}";
1697 return html;
1698 }
1699 }1906 }
17001907 } else if ("declRef" in value) {
1701 case typeKinds.ErrorUnion:1908 if (opts.wantHtml) {
1702 {1909 payloadHtml += '<a href="">';
1703 let errUnionObj = (typeObj);1910 payloadHtml +=
1704 let lhs = exprName(errUnionObj.lhs, opts);1911 '<span class="tok-kw" style="color:lightblue;">' +
1705 let rhs = exprName(errUnionObj.rhs, opts);1912 exprName(value, opts) +
1706 return lhs + "!" + rhs;1913 "</span>";
1914 payloadHtml += "</a>";
1915 } else {
1916 payloadHtml += exprName(value, opts);
1707 }1917 }
1708 case typeKinds.InferredErrorUnion:1918 } else if ("call" in value) {
1709 {1919 if (opts.wantHtml) {
1710 let errUnionObj = (typeObj);1920 payloadHtml += '<a href="">';
1711 let payload = exprName(errUnionObj.payload, opts);1921 payloadHtml +=
1712 return "!" + payload;1922 '<span class="tok-kw" style="color:lightblue;">' +
1923 exprName(value, opts) +
1924 "</span>";
1925 payloadHtml += "</a>";
1926 } else {
1927 payloadHtml += exprName(value, opts);
1713 }1928 }
1714 case typeKinds.Fn:1929 } else if ("refPath" in value) {
1715 {1930 if (opts.wantHtml) {
1716 let fnObj = (typeObj);1931 payloadHtml += '<a href="">';
1717 let payloadHtml = "";1932 payloadHtml +=
1718 if (opts.wantHtml) {1933 '<span class="tok-kw" style="color:lightblue;">' +
1719 if (fnObj.is_extern) {1934 exprName(value, opts) +
1720 payloadHtml += "pub extern ";1935 "</span>";
1721 }1936 payloadHtml += "</a>";
1722 if (fnObj.has_lib_name) {1937 } else {
1723 payloadHtml += "\"" + fnObj.lib_name +"\" ";1938 payloadHtml += exprName(value, opts);
1724 }
1725 payloadHtml += '<span class="tok-kw">fn</span>';
1726 if (opts.fnDecl) {
1727 payloadHtml += ' <span class="tok-fn">';
1728 if (opts.linkFnNameDecl) {
1729 payloadHtml += '<a href="' + opts.linkFnNameDecl + '">' +
1730 escapeHtml(opts.fnDecl.name) + '</a>';
1731 } else {
1732 payloadHtml += escapeHtml(opts.fnDecl.name);
1733 }
1734 payloadHtml += '</span>';
1735 }
1736 } else {
1737 payloadHtml += 'fn ';
1738 }
1739 payloadHtml += '(';
1740 if (fnObj.params) {
1741 let fields = null;
1742 let isVarArgs = false;
1743 let fnNode = zigAnalysis.astNodes[fnObj.src];
1744 fields = fnNode.fields;
1745 isVarArgs = fnNode.varArgs;
1746
1747 for (let i = 0; i < fnObj.params.length; i += 1) {
1748 if (i != 0) {
1749 payloadHtml += ', ';
1750 }
1751
1752 payloadHtml += "<span class='argBreaker'><br>&nbsp;&nbsp;&nbsp;&nbsp;</span>"
1753 let value = fnObj.params[i];
1754 let paramValue = resolveValue({expr: value});
1755
1756 if (fields != null) {
1757 let paramNode = zigAnalysis.astNodes[fields[i]];
1758
1759 if (paramNode.varArgs) {
1760 payloadHtml += '...';
1761 continue;
1762 }
1763
1764 if (paramNode.noalias) {
1765 if (opts.wantHtml) {
1766 payloadHtml += '<span class="tok-kw">noalias</span> ';
1767 } else {
1768 payloadHtml += 'noalias ';
1769 }
1770 }
1771
1772 if (paramNode.comptime) {
1773 if (opts.wantHtml) {
1774 payloadHtml += '<span class="tok-kw">comptime</span> ';
1775 } else {
1776 payloadHtml += 'comptime ';
1777 }
1778 }
1779
1780 let paramName = paramNode.name;
1781 if (paramName != null) {
1782 // skip if it matches the type name
1783 if (!shouldSkipParamName(paramValue, paramName)) {
1784 payloadHtml += paramName + ': ';
1785 }
1786 }
1787 }
1788
1789 if (isVarArgs && i === fnObj.params.length - 1) {
1790 payloadHtml += '...';
1791 }
1792 else if ("alignOf" in value) {
1793 if (opts.wantHtml) {
1794 payloadHtml += '<a href="">';
1795 payloadHtml +=
1796 '<span class="tok-kw" style="color:lightblue;">'
1797 + exprName(value, opts) + '</span>';
1798 payloadHtml += '</a>';
1799 } else {
1800 payloadHtml += exprName(value, opts);
1801 }
1802
1803 }
1804 else if ("typeOf" in value) {
1805 if (opts.wantHtml) {
1806 payloadHtml += '<a href="">';
1807 payloadHtml +=
1808 '<span class="tok-kw" style="color:lightblue;">'
1809 + exprName(value, opts) + '</span>';
1810 payloadHtml += '</a>';
1811 } else {
1812 payloadHtml += exprName(value, opts);
1813 }
1814
1815 }
1816 else if ("typeOf_peer" in value) {
1817 if (opts.wantHtml) {
1818 payloadHtml += '<a href="">';
1819 payloadHtml +=
1820 '<span class="tok-kw" style="color:lightblue;">'
1821 + exprName(value, opts) + '</span>';
1822 payloadHtml += '</a>';
1823 } else {
1824 payloadHtml += exprName(value, opts);
1825 }
1826
1827 }
1828 else if ("declRef" in value) {
1829 if (opts.wantHtml) {
1830 payloadHtml += '<a href="">';
1831 payloadHtml +=
1832 '<span class="tok-kw" style="color:lightblue;">'
1833 + exprName(value, opts) + '</span>';
1834 payloadHtml += '</a>';
1835 } else {
1836 payloadHtml += exprName(value, opts);
1837 }
1838
1839 }
1840 else if ("call" in value) {
1841 if (opts.wantHtml) {
1842 payloadHtml += '<a href="">';
1843 payloadHtml +=
1844 '<span class="tok-kw" style="color:lightblue;">'
1845 + exprName(value, opts) + '</span>';
1846 payloadHtml += '</a>';
1847 } else {
1848 payloadHtml += exprName(value, opts);
1849 }
1850 }
1851 else if ("refPath" in value) {
1852 if (opts.wantHtml) {
1853 payloadHtml += '<a href="">';
1854 payloadHtml +=
1855 '<span class="tok-kw" style="color:lightblue;">'
1856 + exprName(value, opts) + '</span>';
1857 payloadHtml += '</a>';
1858 } else {
1859 payloadHtml += exprName(value, opts);
1860 }
1861 } else if ("type" in value) {
1862 let name = exprName(value, {
1863 wantHtml: false,
1864 wantLink: false,
1865 fnDecl: opts.fnDecl,
1866 linkFnNameDecl: opts.linkFnNameDecl,
1867 });
1868 payloadHtml += '<span class="tok-kw">' + name + '</span>';
1869 } else if ("binOpIndex" in value) {
1870 payloadHtml += exprName(value, opts);
1871 }else if ("comptimeExpr" in value) {
1872 let comptimeExpr = zigAnalysis.comptimeExprs[value.comptimeExpr].code;
1873 if (opts.wantHtml) {
1874 payloadHtml += '<span class="tok-kw">' + comptimeExpr + '</span>';
1875 } else {
1876 payloadHtml += comptimeExpr;
1877 }
1878 } else if (opts.wantHtml) {
1879 payloadHtml += '<span class="tok-kw">anytype</span>';
1880 } else {
1881 payloadHtml += 'anytype';
1882 }
1883 }
1884 }
1885
1886 payloadHtml += "<span class='argBreaker'>,<br></span>"
1887 payloadHtml += ') ';
1888
1889 if (fnObj.has_align) {
1890 let align = zigAnalysis.exprs[fnObj.align]
1891 payloadHtml += "align(" + exprName(align, opts) + ") ";
1892 }
1893 if (fnObj.has_cc) {
1894 let cc = zigAnalysis.exprs[fnObj.cc]
1895 if (cc) {
1896 payloadHtml += "callconv(." + cc.enumLiteral + ") ";
1897 }
1898 }
1899
1900 if (fnObj.is_inferred_error) {
1901 payloadHtml += "!";
1902 }
1903 if (fnObj.ret != null) {
1904 payloadHtml += exprName(fnObj.ret, opts);
1905 } else if (opts.wantHtml) {
1906 payloadHtml += '<span class="tok-kw">anytype</span>';
1907 } else {
1908 payloadHtml += 'anytype';
1909 }
1910 return payloadHtml;
1911 }1939 }
1912 // if (wantHtml) {1940 } else if ("type" in value) {
1913 // return escapeHtml(typeObj.name);1941 let name = exprName(value, {
1914 // } else {1942 wantHtml: false,
1915 // return typeObj.name;1943 wantLink: false,
1916 // }1944 fnDecl: opts.fnDecl,
1917 }1945 linkFnNameDecl: opts.linkFnNameDecl,
1918 }1946 });
19191947 payloadHtml += '<span class="tok-kw">' + name + "</span>";
1920 }1948 } else if ("binOpIndex" in value) {
1921 }1949 payloadHtml += exprName(value, opts);
19221950 } else if ("comptimeExpr" in value) {
19231951 let comptimeExpr =
1924 1952 zigAnalysis.comptimeExprs[value.comptimeExpr].code;
1925 function shouldSkipParamName(typeRef, paramName) {1953 if (opts.wantHtml) {
1926 let resolvedTypeRef = resolveValue({expr: typeRef});1954 payloadHtml +=
1927 if ("type" in resolvedTypeRef) {1955 '<span class="tok-kw">' + comptimeExpr + "</span>";
1928 let typeObj = zigAnalysis.types[resolvedTypeRef.type];1956 } else {
1929 if (typeObj.kind === typeKinds.Pointer){1957 payloadHtml += comptimeExpr;
1930 let ptrObj = (typeObj);1958 }
1931 if (getPtrSize(ptrObj) === pointerSizeEnum.One) {1959 } else if (opts.wantHtml) {
1932 const value = resolveValue(ptrObj.child);1960 payloadHtml += '<span class="tok-kw">anytype</span>';
1933 return typeValueName(value, false, true).toLowerCase() === paramName;1961 } else {
1962 payloadHtml += "anytype";
1934 }1963 }
1964 }
1935 }1965 }
1936 }
1937 return false;
1938 }
1939
1940
1941 function getPtrSize(typeObj) {
1942 return (typeObj.size == null) ? pointerSizeEnum.One : typeObj.size;
1943 }
19441966
1945 1967 payloadHtml += "<span class='argBreaker'>,<br></span>";
1946 function renderType(typeObj) {1968 payloadHtml += ") ";
1947 let name;
1948 if (rootIsStd && typeObj === zigAnalysis.types[zigAnalysis.packages[zigAnalysis.rootPkg].main]) {
1949 name = "std";
1950 } else {
1951 name = exprName({type:typeObj}, false, false);
1952 }
1953 if (name != null && name != "") {
1954 domHdrName.innerText = name + " (" + zigAnalysis.typeKinds[typeObj.kind] + ")";
1955 domHdrName.classList.remove("hidden");
1956 }
1957 if (typeObj.kind == typeKinds.ErrorSet) {
1958 renderErrorSet((typeObj));
1959 }
1960 }
19611969
1962 1970 if (fnObj.has_align) {
1963 function renderErrorSet(errSetType) {1971 let align = zigAnalysis.exprs[fnObj.align];
1964 if (errSetType.fields == null) {1972 payloadHtml += "align(" + exprName(align, opts) + ") ";
1965 domFnErrorsAnyError.classList.remove("hidden");1973 }
1966 } else {1974 if (fnObj.has_cc) {
1967 let errorList = [];1975 let cc = zigAnalysis.exprs[fnObj.cc];
1968 for (let i = 0; i < errSetType.fields.length; i += 1) {1976 if (cc) {
1969 let errObj = errSetType.fields[i];1977 payloadHtml += "callconv(." + cc.enumLiteral + ") ";
1970 //let srcObj = zigAnalysis.astNodes[errObj.src];1978 }
1971 errorList.push(errObj);
1972 }1979 }
1973 errorList.sort(function(a, b) {
1974 return operatorCompare(a.name.toLowerCase(), b.name.toLowerCase());
1975 });
19761980
1977 resizeDomListDl(domListFnErrors, errorList.length);1981 if (fnObj.is_inferred_error) {
1978 for (let i = 0; i < errorList.length; i += 1) {1982 payloadHtml += "!";
1979 let nameTdDom = domListFnErrors.children[i * 2 + 0];
1980 let descTdDom = domListFnErrors.children[i * 2 + 1];
1981 nameTdDom.textContent = errorList[i].name;
1982 let docs = errorList[i].docs;
1983 if (docs != null) {
1984 descTdDom.innerHTML = markdown(docs);
1985 } else {
1986 descTdDom.textContent = "";
1987 }
1988 }1983 }
1989 domTableFnErrors.classList.remove("hidden");1984 if (fnObj.ret != null) {
1985 payloadHtml += exprName(fnObj.ret, opts);
1986 } else if (opts.wantHtml) {
1987 payloadHtml += '<span class="tok-kw">anytype</span>';
1988 } else {
1989 payloadHtml += "anytype";
1990 }
1991 return payloadHtml;
1992 }
1993 // if (wantHtml) {
1994 // return escapeHtml(typeObj.name);
1995 // } else {
1996 // return typeObj.name;
1997 // }
1990 }1998 }
1991 domSectFnErrors.classList.remove("hidden");
1992 }
1993
1994// function allCompTimeFnCallsHaveTypeResult(typeIndex, value) {
1995// let srcIndex = zigAnalysis.fns[value].src;
1996// let calls = nodesToCallsMap[srcIndex];
1997// if (calls == null) return false;
1998// for (let i = 0; i < calls.length; i += 1) {
1999// let call = zigAnalysis.calls[calls[i]];
2000// if (call.result.type !== typeTypeId) return false;
2001// }
2002// return true;
2003// }
2004//
2005// function allCompTimeFnCallsResult(calls) {
2006// let firstTypeObj = null;
2007// let containerObj = {
2008// privDecls: [],
2009// };
2010// for (let callI = 0; callI < calls.length; callI += 1) {
2011// let call = zigAnalysis.calls[calls[callI]];
2012// if (call.result.type !== typeTypeId) return null;
2013// let typeObj = zigAnalysis.types[call.result.value];
2014// if (!typeKindIsContainer(typeObj.kind)) return null;
2015// if (firstTypeObj == null) {
2016// firstTypeObj = typeObj;
2017// containerObj.src = typeObj.src;
2018// } else if (firstTypeObj.src !== typeObj.src) {
2019// return null;
2020// }
2021//
2022// if (containerObj.fields == null) {
2023// containerObj.fields = (typeObj.fields || []).concat([]);
2024// } else for (let fieldI = 0; fieldI < typeObj.fields.length; fieldI += 1) {
2025// let prev = containerObj.fields[fieldI];
2026// let next = typeObj.fields[fieldI];
2027// if (prev === next) continue;
2028// if (typeof(prev) === 'object') {
2029// if (prev[next] == null) prev[next] = typeObj;
2030// } else {
2031// containerObj.fields[fieldI] = {};
2032// containerObj.fields[fieldI][prev] = firstTypeObj;
2033// containerObj.fields[fieldI][next] = typeObj;
2034// }
2035// }
2036//
2037// if (containerObj.pubDecls == null) {
2038// containerObj.pubDecls = (typeObj.pubDecls || []).concat([]);
2039// } else for (let declI = 0; declI < typeObj.pubDecls.length; declI += 1) {
2040// let prev = containerObj.pubDecls[declI];
2041// let next = typeObj.pubDecls[declI];
2042// if (prev === next) continue;
2043// // TODO instead of showing "examples" as the public declarations,
2044// // do logic like this:
2045// //if (typeof(prev) !== 'object') {
2046// // let newDeclId = zigAnalysis.decls.length;
2047// // prev = clone(zigAnalysis.decls[prev]);
2048// // prev.id = newDeclId;
2049// // zigAnalysis.decls.push(prev);
2050// // containerObj.pubDecls[declI] = prev;
2051// //}
2052// //mergeDecls(prev, next, firstTypeObj, typeObj);
2053// }
2054// }
2055// for (let declI = 0; declI < containerObj.pubDecls.length; declI += 1) {
2056// let decl = containerObj.pubDecls[declI];
2057// if (typeof(decl) === 'object') {
2058// containerObj.pubDecls[declI] = containerObj.pubDecls[declI].id;
2059// }
2060// }
2061// return containerObj;
2062// }
2063
2064
2065
2066
2067 function renderValue(decl) {
2068 let resolvedValue = resolveValue(decl.value)
2069
2070 if (resolvedValue.expr.fieldRef) {
2071 const declRef = decl.value.expr.refPath[0].declRef;
2072 const type = zigAnalysis.decls[declRef];
2073 domFnProtoCode.innerHTML = '<span class="tok-kw">const</span> ' +
2074 escapeHtml(decl.name) + ': ' + type.name +
2075 " = " + exprName(decl.value.expr, {wantHtml: true, wantLink:true}) + ";";
2076 } else if (resolvedValue.expr.string !== undefined || resolvedValue.expr.call !== undefined || resolvedValue.expr.comptimeExpr) {
2077 domFnProtoCode.innerHTML = '<span class="tok-kw">const</span> ' +
2078 escapeHtml(decl.name) + ': ' + exprName(resolvedValue.expr, {wantHtml: true, wantLink:true}) +
2079 " = " + exprName(decl.value.expr, {wantHtml: true, wantLink:true}) + ";";
2080 } else if (resolvedValue.expr.compileError) {
2081 domFnProtoCode.innerHTML = '<span class="tok-kw">const</span> ' +
2082 escapeHtml(decl.name) + " = " + exprName(decl.value.expr, {wantHtml: true, wantLink:true}) + ";";
2083 }
2084 else {
2085 domFnProtoCode.innerHTML = '<span class="tok-kw">const</span> ' +
2086 escapeHtml(decl.name) + ': ' + exprName(resolvedValue.typeRef, {wantHtml: true, wantLink:true}) +
2087 " = " + exprName(decl.value.expr, {wantHtml: true, wantLink:true}) + ";";
2088 }1999 }
20892000 }
2090 let docs = zigAnalysis.astNodes[decl.src].docs;2001 }
2091 if (docs != null) {2002
2092 domTldDocs.innerHTML = markdown(docs);2003 function shouldSkipParamName(typeRef, paramName) {
2093 domTldDocs.classList.remove("hidden");2004 let resolvedTypeRef = resolveValue({ expr: typeRef });
2005 if ("type" in resolvedTypeRef) {
2006 let typeObj = zigAnalysis.types[resolvedTypeRef.type];
2007 if (typeObj.kind === typeKinds.Pointer) {
2008 let ptrObj = typeObj;
2009 if (getPtrSize(ptrObj) === pointerSizeEnum.One) {
2010 const value = resolveValue(ptrObj.child);
2011 return typeValueName(value, false, true).toLowerCase() === paramName;
2094 }2012 }
20952013 }
2096 domFnProto.classList.remove("hidden");
2097 }2014 }
2015 return false;
2016 }
2017
2018 function getPtrSize(typeObj) {
2019 return typeObj.size == null ? pointerSizeEnum.One : typeObj.size;
2020 }
2021
2022 function renderType(typeObj) {
2023 let name;
2024 if (
2025 rootIsStd &&
2026 typeObj ===
2027 zigAnalysis.types[zigAnalysis.packages[zigAnalysis.rootPkg].main]
2028 ) {
2029 name = "std";
2030 } else {
2031 name = exprName({ type: typeObj }, false, false);
2032 }
2033 if (name != null && name != "") {
2034 domHdrName.innerText =
2035 name + " (" + zigAnalysis.typeKinds[typeObj.kind] + ")";
2036 domHdrName.classList.remove("hidden");
2037 }
2038 if (typeObj.kind == typeKinds.ErrorSet) {
2039 renderErrorSet(typeObj);
2040 }
2041 }
20982042
2099 2043 function renderErrorSet(errSetType) {
2100 function renderVar(decl) {2044 if (errSetType.fields == null) {
2101 let declTypeRef = typeOfDecl(decl);2045 domFnErrorsAnyError.classList.remove("hidden");
2102 domFnProtoCode.innerHTML = '<span class="tok-kw">var</span> ' +2046 } else {
2103 escapeHtml(decl.name) + ': ' + typeValueName(declTypeRef, true, true);2047 let errorList = [];
21042048 for (let i = 0; i < errSetType.fields.length; i += 1) {
2105 let docs = zigAnalysis.astNodes[decl.src].docs;2049 let errObj = errSetType.fields[i];
2050 //let srcObj = zigAnalysis.astNodes[errObj.src];
2051 errorList.push(errObj);
2052 }
2053 errorList.sort(function (a, b) {
2054 return operatorCompare(a.name.toLowerCase(), b.name.toLowerCase());
2055 });
2056
2057 resizeDomListDl(domListFnErrors, errorList.length);
2058 for (let i = 0; i < errorList.length; i += 1) {
2059 let nameTdDom = domListFnErrors.children[i * 2 + 0];
2060 let descTdDom = domListFnErrors.children[i * 2 + 1];
2061 nameTdDom.textContent = errorList[i].name;
2062 let docs = errorList[i].docs;
2106 if (docs != null) {2063 if (docs != null) {
2107 domTldDocs.innerHTML = markdown(docs);2064 descTdDom.innerHTML = markdown(docs);
2108 domTldDocs.classList.remove("hidden");2065 } else {
2066 descTdDom.textContent = "";
2109 }2067 }
21102068 }
2111 domFnProto.classList.remove("hidden");2069 domTableFnErrors.classList.remove("hidden");
2070 }
2071 domSectFnErrors.classList.remove("hidden");
2072 }
2073
2074 // function allCompTimeFnCallsHaveTypeResult(typeIndex, value) {
2075 // let srcIndex = zigAnalysis.fns[value].src;
2076 // let calls = nodesToCallsMap[srcIndex];
2077 // if (calls == null) return false;
2078 // for (let i = 0; i < calls.length; i += 1) {
2079 // let call = zigAnalysis.calls[calls[i]];
2080 // if (call.result.type !== typeTypeId) return false;
2081 // }
2082 // return true;
2083 // }
2084 //
2085 // function allCompTimeFnCallsResult(calls) {
2086 // let firstTypeObj = null;
2087 // let containerObj = {
2088 // privDecls: [],
2089 // };
2090 // for (let callI = 0; callI < calls.length; callI += 1) {
2091 // let call = zigAnalysis.calls[calls[callI]];
2092 // if (call.result.type !== typeTypeId) return null;
2093 // let typeObj = zigAnalysis.types[call.result.value];
2094 // if (!typeKindIsContainer(typeObj.kind)) return null;
2095 // if (firstTypeObj == null) {
2096 // firstTypeObj = typeObj;
2097 // containerObj.src = typeObj.src;
2098 // } else if (firstTypeObj.src !== typeObj.src) {
2099 // return null;
2100 // }
2101 //
2102 // if (containerObj.fields == null) {
2103 // containerObj.fields = (typeObj.fields || []).concat([]);
2104 // } else for (let fieldI = 0; fieldI < typeObj.fields.length; fieldI += 1) {
2105 // let prev = containerObj.fields[fieldI];
2106 // let next = typeObj.fields[fieldI];
2107 // if (prev === next) continue;
2108 // if (typeof(prev) === 'object') {
2109 // if (prev[next] == null) prev[next] = typeObj;
2110 // } else {
2111 // containerObj.fields[fieldI] = {};
2112 // containerObj.fields[fieldI][prev] = firstTypeObj;
2113 // containerObj.fields[fieldI][next] = typeObj;
2114 // }
2115 // }
2116 //
2117 // if (containerObj.pubDecls == null) {
2118 // containerObj.pubDecls = (typeObj.pubDecls || []).concat([]);
2119 // } else for (let declI = 0; declI < typeObj.pubDecls.length; declI += 1) {
2120 // let prev = containerObj.pubDecls[declI];
2121 // let next = typeObj.pubDecls[declI];
2122 // if (prev === next) continue;
2123 // // TODO instead of showing "examples" as the public declarations,
2124 // // do logic like this:
2125 // //if (typeof(prev) !== 'object') {
2126 // // let newDeclId = zigAnalysis.decls.length;
2127 // // prev = clone(zigAnalysis.decls[prev]);
2128 // // prev.id = newDeclId;
2129 // // zigAnalysis.decls.push(prev);
2130 // // containerObj.pubDecls[declI] = prev;
2131 // //}
2132 // //mergeDecls(prev, next, firstTypeObj, typeObj);
2133 // }
2134 // }
2135 // for (let declI = 0; declI < containerObj.pubDecls.length; declI += 1) {
2136 // let decl = containerObj.pubDecls[declI];
2137 // if (typeof(decl) === 'object') {
2138 // containerObj.pubDecls[declI] = containerObj.pubDecls[declI].id;
2139 // }
2140 // }
2141 // return containerObj;
2142 // }
2143
2144 function renderValue(decl) {
2145 let resolvedValue = resolveValue(decl.value);
2146
2147 if (resolvedValue.expr.fieldRef) {
2148 const declRef = decl.value.expr.refPath[0].declRef;
2149 const type = zigAnalysis.decls[declRef];
2150 domFnProtoCode.innerHTML =
2151 '<span class="tok-kw">const</span> ' +
2152 escapeHtml(decl.name) +
2153 ": " +
2154 type.name +
2155 " = " +
2156 exprName(decl.value.expr, { wantHtml: true, wantLink: true }) +
2157 ";";
2158 } else if (
2159 resolvedValue.expr.string !== undefined ||
2160 resolvedValue.expr.call !== undefined ||
2161 resolvedValue.expr.comptimeExpr
2162 ) {
2163 domFnProtoCode.innerHTML =
2164 '<span class="tok-kw">const</span> ' +
2165 escapeHtml(decl.name) +
2166 ": " +
2167 exprName(resolvedValue.expr, { wantHtml: true, wantLink: true }) +
2168 " = " +
2169 exprName(decl.value.expr, { wantHtml: true, wantLink: true }) +
2170 ";";
2171 } else if (resolvedValue.expr.compileError) {
2172 domFnProtoCode.innerHTML =
2173 '<span class="tok-kw">const</span> ' +
2174 escapeHtml(decl.name) +
2175 " = " +
2176 exprName(decl.value.expr, { wantHtml: true, wantLink: true }) +
2177 ";";
2178 } else {
2179 domFnProtoCode.innerHTML =
2180 '<span class="tok-kw">const</span> ' +
2181 escapeHtml(decl.name) +
2182 ": " +
2183 exprName(resolvedValue.typeRef, { wantHtml: true, wantLink: true }) +
2184 " = " +
2185 exprName(decl.value.expr, { wantHtml: true, wantLink: true }) +
2186 ";";
2112 }2187 }
21132188
2189 let docs = zigAnalysis.astNodes[decl.src].docs;
2190 if (docs != null) {
2191 domTldDocs.innerHTML = markdown(docs);
2192 domTldDocs.classList.remove("hidden");
2193 }
21142194
2115 2195 domFnProto.classList.remove("hidden");
2116 function categorizeDecls(decls,2196 }
2117 typesList, namespacesList, errSetsList,2197
2118 fnsList, varsList, valsList, testsList) {2198 function renderVar(decl) {
21192199 let declTypeRef = typeOfDecl(decl);
2120 for (let i = 0; i < decls.length; i += 1) {2200 domFnProtoCode.innerHTML =
2121 let decl = zigAnalysis.decls[decls[i]];2201 '<span class="tok-kw">var</span> ' +
2122 let declValue = resolveValue(decl.value);2202 escapeHtml(decl.name) +
21232203 ": " +
2124 if (decl.isTest) {2204 typeValueName(declTypeRef, true, true);
2125 testsList.push(decl);2205
2126 continue;2206 let docs = zigAnalysis.astNodes[decl.src].docs;
2127 }2207 if (docs != null) {
21282208 domTldDocs.innerHTML = markdown(docs);
2129 if (decl.kind === 'var') {2209 domTldDocs.classList.remove("hidden");
2130 varsList.push(decl);
2131 continue;
2132 }
2133
2134 if (decl.kind === 'const') {
2135 if ("type" in declValue.expr) {
2136 // We have the actual type expression at hand.
2137 const typeExpr = zigAnalysis.types[declValue.expr.type];
2138 if (typeExpr.kind == typeKinds.Fn) {
2139 const funcRetExpr = resolveValue({
2140 expr: (typeExpr).ret
2141 });
2142 if ("type" in funcRetExpr.expr && funcRetExpr.expr.type == typeTypeId) {
2143 if (typeIsErrSet(declValue.expr.type)) {
2144 errSetsList.push(decl);
2145 } else if (typeIsStructWithNoFields(declValue.expr.type)) {
2146 namespacesList.push(decl);
2147 } else {
2148 typesList.push(decl);
2149 }
2150 } else {
2151 fnsList.push(decl);
2152 }
2153 } else {
2154 if (typeIsErrSet(declValue.expr.type)) {
2155 errSetsList.push(decl);
2156 } else if (typeIsStructWithNoFields(declValue.expr.type)) {
2157 namespacesList.push(decl);
2158 } else {
2159 typesList.push(decl);
2160 }
2161 }
2162 } else if ("typeRef" in declValue) {
2163 if ("type" in declValue.typeRef && declValue.typeRef == typeTypeId) {
2164 // We don't know what the type expression is, but we know it's a type.
2165 typesList.push(decl);
2166 } else {
2167 valsList.push(decl);
2168 }
2169 } else {
2170 valsList.push(decl);
2171 }
2172 }
2173 }
2174 }2210 }
21752211
2176 2212 domFnProto.classList.remove("hidden");
2177 function renderContainer(container) {2213 }
2178 2214
2179 let typesList = [];2215 function categorizeDecls(
2180 2216 decls,
2181 let namespacesList = [];2217 typesList,
2182 2218 namespacesList,
2183 let errSetsList = [];2219 errSetsList,
2184 2220 fnsList,
2185 let fnsList = [];2221 varsList,
2186 2222 valsList,
2187 let varsList = [];2223 testsList
2188 2224 ) {
2189 let valsList = [];2225 for (let i = 0; i < decls.length; i += 1) {
2190 2226 let decl = zigAnalysis.decls[decls[i]];
2191 let testsList = [];2227 let declValue = resolveValue(decl.value);
21922228
2193 categorizeDecls(container.pubDecls,2229 if (decl.isTest) {
2194 typesList, namespacesList, errSetsList,2230 testsList.push(decl);
2195 fnsList, varsList, valsList, testsList);2231 continue;
2196 if (curNav.showPrivDecls) categorizeDecls(container.privDecls,2232 }
2197 typesList, namespacesList, errSetsList,
2198 fnsList, varsList, valsList, testsList);
2199
2200
2201 typesList.sort(byNameProperty);
2202 namespacesList.sort(byNameProperty);
2203 errSetsList.sort(byNameProperty);
2204 fnsList.sort(byNameProperty);
2205 varsList.sort(byNameProperty);
2206 valsList.sort(byNameProperty);
2207 testsList.sort(byNameProperty);
2208
2209 if (container.src != null) {
2210 let docs = zigAnalysis.astNodes[container.src].docs;
2211 if (docs != null) {
2212 domTldDocs.innerHTML = markdown(docs);
2213 domTldDocs.classList.remove("hidden");
2214 }
2215 }
22162233
2217 if (typesList.length !== 0) {2234 if (decl.kind === "var") {
2218 window.x = typesList;2235 varsList.push(decl);
2219 resizeDomList(domListTypes, typesList.length, '<li><a href="#"></a></li>');2236 continue;
2220 for (let i = 0; i < typesList.length; i += 1) {2237 }
2221 let liDom = domListTypes.children[i];
2222 let aDom = liDom.children[0];
2223 let decl = typesList[i];
2224 aDom.textContent = decl.name;
2225 aDom.setAttribute('href', navLinkDecl(decl.name));
2226 }
2227 domSectTypes.classList.remove("hidden");
2228 }
2229 if (namespacesList.length !== 0) {
2230 resizeDomList(domListNamespaces, namespacesList.length, '<li><a href="#"></a></li>');
2231 for (let i = 0; i < namespacesList.length; i += 1) {
2232 let liDom = domListNamespaces.children[i];
2233 let aDom = liDom.children[0];
2234 let decl = namespacesList[i];
2235 aDom.textContent = decl.name;
2236 aDom.setAttribute('href', navLinkDecl(decl.name));
2237 }
2238 domSectNamespaces.classList.remove("hidden");
2239 }
22402238
2241 if (errSetsList.length !== 0) {2239 if (decl.kind === "const") {
2242 resizeDomList(domListErrSets, errSetsList.length, '<li><a href="#"></a></li>');2240 if ("type" in declValue.expr) {
2243 for (let i = 0; i < errSetsList.length; i += 1) {2241 // We have the actual type expression at hand.
2244 let liDom = domListErrSets.children[i];2242 const typeExpr = zigAnalysis.types[declValue.expr.type];
2245 let aDom = liDom.children[0];2243 if (typeExpr.kind == typeKinds.Fn) {
2246 let decl = errSetsList[i];2244 const funcRetExpr = resolveValue({
2247 aDom.textContent = decl.name;2245 expr: typeExpr.ret,
2248 aDom.setAttribute('href', navLinkDecl(decl.name));2246 });
2247 if (
2248 "type" in funcRetExpr.expr &&
2249 funcRetExpr.expr.type == typeTypeId
2250 ) {
2251 if (typeIsErrSet(declValue.expr.type)) {
2252 errSetsList.push(decl);
2253 } else if (typeIsStructWithNoFields(declValue.expr.type)) {
2254 namespacesList.push(decl);
2255 } else {
2256 typesList.push(decl);
2257 }
2258 } else {
2259 fnsList.push(decl);
2249 }2260 }
2250 domSectErrSets.classList.remove("hidden");2261 } else {
2251 }2262 if (typeIsErrSet(declValue.expr.type)) {
22522263 errSetsList.push(decl);
2253 if (fnsList.length !== 0) {2264 } else if (typeIsStructWithNoFields(declValue.expr.type)) {
2254 resizeDomList(domListFns, fnsList.length, '<div><dt></dt><dd></dd></div>');2265 namespacesList.push(decl);
22552266 } else {
2256 for (let i = 0; i < fnsList.length; i += 1) {2267 typesList.push(decl);
2257 let decl = fnsList[i];
2258 let trDom = domListFns.children[i];
2259
2260 let tdFnCode = trDom.children[0];
2261 let tdDesc = trDom.children[1];
2262
2263 let declType = resolveValue(decl.value);
2264 console.assert("type" in declType.expr);
2265
2266 tdFnCode.innerHTML = exprName(declType.expr,{
2267 wantHtml: true,
2268 wantLink: true,
2269 fnDecl: decl,
2270 linkFnNameDecl: navLinkDecl(decl.name),
2271 });
2272
2273 let docs = zigAnalysis.astNodes[decl.src].docs;
2274 if (docs != null) {
2275 tdDesc.innerHTML = shortDescMarkdown(docs);
2276 } else {
2277 tdDesc.textContent = "";
2278 }
2279 }2268 }
2280 domSectFns.classList.remove("hidden");2269 }
2270 } else if ("typeRef" in declValue) {
2271 if ("type" in declValue.typeRef && declValue.typeRef == typeTypeId) {
2272 // We don't know what the type expression is, but we know it's a type.
2273 typesList.push(decl);
2274 } else {
2275 valsList.push(decl);
2276 }
2277 } else {
2278 valsList.push(decl);
2281 }2279 }
2280 }
2281 }
2282 }
2283 function renderSourceFileLink(decl) {
2284 let srcNode = zigAnalysis.astNodes[decl.src];
2285
2286 return "<a style=\"float: right;\" href=\"" +
2287 sourceFileUrlTemplate.replace("{{file}}",
2288 zigAnalysis.files[srcNode.file]).replace("{{line}}", srcNode.line) + "\">[src]</a>";
2289 }
2290
2291 function renderContainer(container) {
2292 let typesList = [];
2293
2294 let namespacesList = [];
2295
2296 let errSetsList = [];
2297
2298 let fnsList = [];
2299
2300 let varsList = [];
2301
2302 let valsList = [];
2303
2304 let testsList = [];
2305
2306 categorizeDecls(
2307 container.pubDecls,
2308 typesList,
2309 namespacesList,
2310 errSetsList,
2311 fnsList,
2312 varsList,
2313 valsList,
2314 testsList
2315 );
2316 if (curNav.showPrivDecls)
2317 categorizeDecls(
2318 container.privDecls,
2319 typesList,
2320 namespacesList,
2321 errSetsList,
2322 fnsList,
2323 varsList,
2324 valsList,
2325 testsList
2326 );
2327
2328 typesList.sort(byNameProperty);
2329 namespacesList.sort(byNameProperty);
2330 errSetsList.sort(byNameProperty);
2331 fnsList.sort(byNameProperty);
2332 varsList.sort(byNameProperty);
2333 valsList.sort(byNameProperty);
2334 testsList.sort(byNameProperty);
2335
2336 if (container.src != null) {
2337 let docs = zigAnalysis.astNodes[container.src].docs;
2338 if (docs != null) {
2339 domTldDocs.innerHTML = markdown(docs);
2340 domTldDocs.classList.remove("hidden");
2341 }
2342 }
22822343
2283 let containerNode = zigAnalysis.astNodes[container.src];2344 if (typesList.length !== 0) {
2284 if (containerNode.fields && containerNode.fields.length > 0) {2345 window.x = typesList;
2285 resizeDomList(domListFields, containerNode.fields.length, '<div></div>');2346 resizeDomList(
2347 domListTypes,
2348 typesList.length,
2349 '<li><a href="#"></a></li>'
2350 );
2351 for (let i = 0; i < typesList.length; i += 1) {
2352 let liDom = domListTypes.children[i];
2353 let aDom = liDom.children[0];
2354 let decl = typesList[i];
2355 aDom.textContent = decl.name;
2356 aDom.setAttribute("href", navLinkDecl(decl.name));
2357 }
2358 domSectTypes.classList.remove("hidden");
2359 }
2360 if (namespacesList.length !== 0) {
2361 resizeDomList(
2362 domListNamespaces,
2363 namespacesList.length,
2364 '<li><a href="#"></a></li>'
2365 );
2366 for (let i = 0; i < namespacesList.length; i += 1) {
2367 let liDom = domListNamespaces.children[i];
2368 let aDom = liDom.children[0];
2369 let decl = namespacesList[i];
2370 aDom.textContent = decl.name;
2371 aDom.setAttribute("href", navLinkDecl(decl.name));
2372 }
2373 domSectNamespaces.classList.remove("hidden");
2374 }
22862375
2287 for (let i = 0; i < containerNode.fields.length; i += 1) {2376 if (errSetsList.length !== 0) {
2288 let fieldNode = zigAnalysis.astNodes[containerNode.fields[i]];2377 resizeDomList(
2289 let divDom = domListFields.children[i];2378 domListErrSets,
2290 let fieldName = (fieldNode.name);2379 errSetsList.length,
2291 let docs = fieldNode.docs;2380 '<li><a href="#"></a></li>'
2292 let docsNonEmpty = docs != null && docs !== "";2381 );
2293 let extraPreClass = docsNonEmpty ? " fieldHasDocs" : "";2382 for (let i = 0; i < errSetsList.length; i += 1) {
2383 let liDom = domListErrSets.children[i];
2384 let aDom = liDom.children[0];
2385 let decl = errSetsList[i];
2386 aDom.textContent = decl.name;
2387 aDom.setAttribute("href", navLinkDecl(decl.name));
2388 }
2389 domSectErrSets.classList.remove("hidden");
2390 }
22942391
2295 let html = '<div class="mobile-scroll-container"><pre class="scroll-item' + extraPreClass + '">' + escapeHtml(fieldName);2392 if (fnsList.length !== 0) {
2393 resizeDomList(
2394 domListFns,
2395 fnsList.length,
2396 "<div><dt></dt><dd></dd></div>"
2397 );
22962398
2297 if (container.kind === typeKinds.Enum) {2399 for (let i = 0; i < fnsList.length; i += 1) {
2298 html += ' = <span class="tok-number">' + fieldName + '</span>';2400 let decl = fnsList[i];
2299 } else {2401 let trDom = domListFns.children[i];
2300 let fieldTypeExpr = container.fields[i];
2301 html += ": ";
2302 let name = exprName(fieldTypeExpr, false, false);
2303 html += '<span class="tok-kw">'+ name +'</span>';
2304 let tsn = typeShorthandName(fieldTypeExpr);
2305 if (tsn) {
2306 html += '<span> ('+ tsn +')</span>';
23072402
2308 }2403 let tdFnCode = trDom.children[0];
2309 }2404 let tdDesc = trDom.children[1];
23102405
2311 html += ',</pre></div>';2406 let declType = resolveValue(decl.value);
2407 console.assert("type" in declType.expr);
2408 tdFnCode.innerHTML = exprName(declType.expr, {
2409 wantHtml: true,
2410 wantLink: true,
2411 fnDecl: decl,
2412 linkFnNameDecl: navLinkDecl(decl.name),
2413 }) + renderSourceFileLink(decl);
23122414
2313 if (docsNonEmpty) {2415 let docs = zigAnalysis.astNodes[decl.src].docs;
2314 html += '<div class="fieldDocs">' + markdown(docs) + '</div>';2416 if (docs != null) {
2315 }2417 tdDesc.innerHTML = shortDescMarkdown(docs);
2316 divDom.innerHTML = html;2418 } else {
2317 }2419 tdDesc.textContent = "";
2318 domSectFields.classList.remove("hidden");
2319 }2420 }
2421 }
2422 domSectFns.classList.remove("hidden");
2423 }
23202424
2321 if (varsList.length !== 0) {2425 let containerNode = zigAnalysis.astNodes[container.src];
2322 resizeDomList(domListGlobalVars, varsList.length,2426 if (containerNode.fields && containerNode.fields.length > 0) {
2323 '<tr><td><a href="#"></a></td><td></td><td></td></tr>');2427 resizeDomList(domListFields, containerNode.fields.length, "<div></div>");
2324 for (let i = 0; i < varsList.length; i += 1) {2428
2325 let decl = varsList[i];2429 for (let i = 0; i < containerNode.fields.length; i += 1) {
2326 let trDom = domListGlobalVars.children[i];2430 let fieldNode = zigAnalysis.astNodes[containerNode.fields[i]];
23272431 let divDom = domListFields.children[i];
2328 let tdName = trDom.children[0];2432 let fieldName = fieldNode.name;
2329 let tdNameA = tdName.children[0];2433 let docs = fieldNode.docs;
2330 let tdType = trDom.children[1];2434 let docsNonEmpty = docs != null && docs !== "";
2331 let tdDesc = trDom.children[2];2435 let extraPreClass = docsNonEmpty ? " fieldHasDocs" : "";
23322436
2333 tdNameA.setAttribute('href', navLinkDecl(decl.name));2437 let html =
2334 tdNameA.textContent = decl.name;2438 '<div class="mobile-scroll-container"><pre class="scroll-item' +
23352439 extraPreClass +
2336 tdType.innerHTML = typeValueName(typeOfDecl(decl), true, true);2440 '">' +
23372441 escapeHtml(fieldName);
2338 let docs = zigAnalysis.astNodes[decl.src].docs;2442
2339 if (docs != null) {2443 if (container.kind === typeKinds.Enum) {
2340 tdDesc.innerHTML = shortDescMarkdown(docs);2444 html += ' = <span class="tok-number">' + fieldName + "</span>";
2341 } else {2445 } else {
2342 tdDesc.textContent = "";2446 let fieldTypeExpr = container.fields[i];
2343 }2447 html += ": ";
2344 }2448 let name = exprName(fieldTypeExpr, false, false);
2345 domSectGlobalVars.classList.remove("hidden");2449 html += '<span class="tok-kw">' + name + "</span>";
2450 let tsn = typeShorthandName(fieldTypeExpr);
2451 if (tsn) {
2452 html += "<span> (" + tsn + ")</span>";
2453 }
2346 }2454 }
23472455
2348 if (valsList.length !== 0) {2456 html += ",</pre></div>";
2349 resizeDomList(domListValues, valsList.length,
2350 '<tr><td><a href="#"></a></td><td></td><td></td></tr>');
2351 for (let i = 0; i < valsList.length; i += 1) {
2352 let decl = valsList[i];
2353 let trDom = domListValues.children[i];
23542457
2355 let tdName = trDom.children[0];2458 if (docsNonEmpty) {
2356 let tdNameA = tdName.children[0];2459 html += '<div class="fieldDocs">' + markdown(docs) + "</div>";
2357 let tdType = trDom.children[1];
2358 let tdDesc = trDom.children[2];
2359
2360 tdNameA.setAttribute('href', navLinkDecl(decl.name));
2361 tdNameA.textContent = decl.name;
2362
2363 tdType.innerHTML = exprName(walkResultTypeRef(decl.value),
2364 {wantHtml:true, wantLink:true});
2365
2366 let docs = zigAnalysis.astNodes[decl.src].docs;
2367 if (docs != null) {
2368 tdDesc.innerHTML = shortDescMarkdown(docs);
2369 } else {
2370 tdDesc.textContent = "";
2371 }
2372 }
2373 domSectValues.classList.remove("hidden");
2374 }2460 }
2461 divDom.innerHTML = html;
2462 }
2463 domSectFields.classList.remove("hidden");
2464 }
23752465
2376 if (testsList.length !== 0) {2466 if (varsList.length !== 0) {
2377 resizeDomList(domListTests, testsList.length,2467 resizeDomList(
2378 '<tr><td><a href="#"></a></td><td></td><td></td></tr>');2468 domListGlobalVars,
2379 for (let i = 0; i < testsList.length; i += 1) {2469 varsList.length,
2380 let decl = testsList[i];2470 '<tr><td><a href="#"></a></td><td></td><td></td></tr>'
2381 let trDom = domListTests.children[i];2471 );
2472 for (let i = 0; i < varsList.length; i += 1) {
2473 let decl = varsList[i];
2474 let trDom = domListGlobalVars.children[i];
23822475
2383 let tdName = trDom.children[0];2476 let tdName = trDom.children[0];
2384 let tdNameA = tdName.children[0];2477 let tdNameA = tdName.children[0];
2385 let tdType = trDom.children[1];2478 let tdType = trDom.children[1];
2386 let tdDesc = trDom.children[2];2479 let tdDesc = trDom.children[2];
23872480
2388 tdNameA.setAttribute('href', navLinkDecl(decl.name));2481 tdNameA.setAttribute("href", navLinkDecl(decl.name));
2389 tdNameA.textContent = decl.name;2482 tdNameA.textContent = decl.name;
23902483
2391 tdType.innerHTML = exprName(walkResultTypeRef(decl.value),2484 tdType.innerHTML = typeValueName(typeOfDecl(decl), true, true);
2392 {wantHtml:true, wantLink:true});
23932485
2394 let docs = zigAnalysis.astNodes[decl.src].docs;2486 let docs = zigAnalysis.astNodes[decl.src].docs;
2395 if (docs != null) {2487 if (docs != null) {
2396 tdDesc.innerHTML = shortDescMarkdown(docs);2488 tdDesc.innerHTML = shortDescMarkdown(docs);
2397 } else {2489 } else {
2398 tdDesc.textContent = "";2490 tdDesc.textContent = "";
2399 }
2400 }
2401 domSectTests.classList.remove("hidden");
2402 }2491 }
2492 }
2493 domSectGlobalVars.classList.remove("hidden");
2403 }2494 }
24042495
2496 if (valsList.length !== 0) {
2497 resizeDomList(
2498 domListValues,
2499 valsList.length,
2500 '<tr><td><a href="#"></a></td><td></td><td></td></tr>'
2501 );
2502 for (let i = 0; i < valsList.length; i += 1) {
2503 let decl = valsList[i];
2504 let trDom = domListValues.children[i];
2505
2506 let tdName = trDom.children[0];
2507 let tdNameA = tdName.children[0];
2508 let tdType = trDom.children[1];
2509 let tdDesc = trDom.children[2];
2510
2511 tdNameA.setAttribute("href", navLinkDecl(decl.name));
2512 tdNameA.textContent = decl.name;
2513
2514 tdType.innerHTML = exprName(walkResultTypeRef(decl.value), {
2515 wantHtml: true,
2516 wantLink: true,
2517 });
24052518
2406 2519 let docs = zigAnalysis.astNodes[decl.src].docs;
2407 function operatorCompare(a, b) {2520 if (docs != null) {
2408 if (a === b) {2521 tdDesc.innerHTML = shortDescMarkdown(docs);
2409 return 0;
2410 } else if (a < b) {
2411 return -1;
2412 } else {2522 } else {
2413 return 1;2523 tdDesc.textContent = "";
2414 }2524 }
2525 }
2526 domSectValues.classList.remove("hidden");
2415 }2527 }
24162528
2417 function detectRootIsStd() {2529 if (testsList.length !== 0) {
2418 let rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg];2530 resizeDomList(
2419 if (rootPkg.table["std"] == null) {2531 domListTests,
2420 // no std mapped into the root package2532 testsList.length,
2421 return false;2533 '<tr><td><a href="#"></a></td><td></td><td></td></tr>'
2422 }2534 );
2423 let stdPkg = zigAnalysis.packages[rootPkg.table["std"]];2535 for (let i = 0; i < testsList.length; i += 1) {
2424 if (stdPkg == null) return false;2536 let decl = testsList[i];
2425 return rootPkg.file === stdPkg.file;2537 let trDom = domListTests.children[i];
2426 }2538
2539 let tdName = trDom.children[0];
2540 let tdNameA = tdName.children[0];
2541 let tdType = trDom.children[1];
2542 let tdDesc = trDom.children[2];
2543
2544 tdNameA.setAttribute("href", navLinkDecl(decl.name));
2545 tdNameA.textContent = decl.name;
2546
2547 tdType.innerHTML = exprName(walkResultTypeRef(decl.value), {
2548 wantHtml: true,
2549 wantLink: true,
2550 });
24272551
2428 function indexTypeKinds() {2552 let docs = zigAnalysis.astNodes[decl.src].docs;
2429 let map = ({});2553 if (docs != null) {
2430 for (let i = 0; i < zigAnalysis.typeKinds.length; i += 1) {2554 tdDesc.innerHTML = shortDescMarkdown(docs);
2431 map[zigAnalysis.typeKinds[i]] = i;2555 } else {
2432 }2556 tdDesc.textContent = "";
2433 // This is just for debugging purposes, not needed to function
2434 let assertList = ["Type","Void","Bool","NoReturn","Int","Float","Pointer","Array","Struct",
2435 "ComptimeFloat","ComptimeInt","Undefined","Null","Optional","ErrorUnion","ErrorSet","Enum",
2436 "Union","Fn","BoundFn","Opaque","Frame","AnyFrame","Vector","EnumLiteral"];
2437 for (let i = 0; i < assertList.length; i += 1) {
2438 if (map[assertList[i]] == null) throw new Error("No type kind '" + assertList[i] + "' found");
2439 }2557 }
2440 return map;2558 }
2559 domSectTests.classList.remove("hidden");
2441 }2560 }
2561 }
24422562
2443 function findTypeTypeId() {2563 function operatorCompare(a, b) {
2444 for (let i = 0; i < zigAnalysis.types.length; i += 1) {2564 if (a === b) {
2445 if (zigAnalysis.types[i].kind == typeKinds.Type) {2565 return 0;
2446 return i;2566 } else if (a < b) {
2447 }2567 return -1;
2448 }2568 } else {
2449 throw new Error("No type 'type' found");2569 return 1;
2450 }2570 }
2571 }
24512572
2452 function updateCurNav() {2573 function detectRootIsStd() {
24532574 let rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg];
2454 curNav = {2575 if (rootPkg.table["std"] == null) {
2455 showPrivDecls: false,2576 // no std mapped into the root package
2456 pkgNames: [],2577 return false;
2457 pkgObjs: [],2578 }
2458 declNames: [],2579 let stdPkg = zigAnalysis.packages[rootPkg.table["std"]];
2459 declObjs: [],2580 if (stdPkg == null) return false;
2460 callName: null,2581 return rootPkg.file === stdPkg.file;
2461 };2582 }
2462 curNavSearch = "";2583
24632584 function indexTypeKinds() {
2464 if (location.hash[0] === '#' && location.hash.length > 1) {2585 let map = {};
2465 let query = location.hash.substring(1);2586 for (let i = 0; i < zigAnalysis.typeKinds.length; i += 1) {
2466 if (query[0] === '*') {2587 map[zigAnalysis.typeKinds[i]] = i;
2467 curNav.showPrivDecls = true;2588 }
2468 query = query.substring(1);2589 // This is just for debugging purposes, not needed to function
2469 }2590 let assertList = [
24702591 "Type",
2471 let qpos = query.indexOf("?");2592 "Void",
2472 let nonSearchPart;2593 "Bool",
2473 if (qpos === -1) {2594 "NoReturn",
2474 nonSearchPart = query;2595 "Int",
2475 } else {2596 "Float",
2476 nonSearchPart = query.substring(0, qpos);2597 "Pointer",
2477 curNavSearch = decodeURIComponent(query.substring(qpos + 1));2598 "Array",
2478 }2599 "Struct",
24792600 "ComptimeFloat",
2480 let parts = nonSearchPart.split(";");2601 "ComptimeInt",
2481 curNav.pkgNames = decodeURIComponent(parts[0]).split(".");2602 "Undefined",
2482 if (parts[1] != null) {2603 "Null",
2483 curNav.declNames = decodeURIComponent(parts[1]).split(".");2604 "Optional",
2484 }2605 "ErrorUnion",
2485 }2606 "ErrorSet",
2607 "Enum",
2608 "Union",
2609 "Fn",
2610 "BoundFn",
2611 "Opaque",
2612 "Frame",
2613 "AnyFrame",
2614 "Vector",
2615 "EnumLiteral",
2616 ];
2617 for (let i = 0; i < assertList.length; i += 1) {
2618 if (map[assertList[i]] == null)
2619 throw new Error("No type kind '" + assertList[i] + "' found");
2486 }2620 }
2621 return map;
2622 }
24872623
2488 function onHashChange() {2624 function findTypeTypeId() {
2489 updateCurNav();2625 for (let i = 0; i < zigAnalysis.types.length; i += 1) {
2490 if (domSearch.value !== curNavSearch) {2626 if (zigAnalysis.types[i].kind == typeKinds.Type) {
2491 domSearch.value = curNavSearch;2627 return i;
2492 }2628 }
2493 render();
2494 if (imFeelingLucky) {
2495 imFeelingLucky = false;
2496 activateSelectedResult();
2497 }
2498 }2629 }
2630 throw new Error("No type 'type' found");
2631 }
2632
2633 function updateCurNav() {
2634 curNav = {
2635 showPrivDecls: false,
2636 pkgNames: [],
2637 pkgObjs: [],
2638 declNames: [],
2639 declObjs: [],
2640 callName: null,
2641 };
2642 curNavSearch = "";
24992643
2500 2644 if (location.hash[0] === "#" && location.hash.length > 1) {
2501 function findSubDecl(parentType, childName) {2645 let query = location.hash.substring(1);
2502 {2646 if (query[0] === "*") {
2503 // Generic functions2647 curNav.showPrivDecls = true;
2504 if ("value" in parentType) {2648 query = query.substring(1);
2505 const rv = resolveValue(parentType.value);2649 }
2506 if ("type" in rv.expr) {
2507 const t = zigAnalysis.types[rv.expr.type];
2508 if (t.kind == typeKinds.Fn && t.generic_ret != null) {
2509 const rgr = resolveValue({expr: t.generic_ret});
2510 if ("type" in rgr.expr) {
2511 parentType = zigAnalysis.types[rgr.expr.type];
2512 }
2513 }
2514 }
2515 }
2516 }
25172650
2651 let qpos = query.indexOf("?");
2652 let nonSearchPart;
2653 if (qpos === -1) {
2654 nonSearchPart = query;
2655 } else {
2656 nonSearchPart = query.substring(0, qpos);
2657 curNavSearch = decodeURIComponent(query.substring(qpos + 1));
2658 }
25182659
2519 if (!parentType.pubDecls) return null;2660 let parts = nonSearchPart.split(";");
2520 for (let i = 0; i < parentType.pubDecls.length; i += 1) {2661 curNav.pkgNames = decodeURIComponent(parts[0]).split(".");
2521 let declIndex = parentType.pubDecls[i];2662 if (parts[1] != null) {
2522 let childDecl = zigAnalysis.decls[declIndex];2663 curNav.declNames = decodeURIComponent(parts[1]).split(".");
2523 if (childDecl.name === childName) {2664 }
2524 return childDecl;2665 }
2525 }2666 }
2526 }2667
2527 if (!parentType.privDecls) return null;2668 function onHashChange() {
2528 for (let i = 0; i < parentType.privDecls.length; i += 1) {2669 updateCurNav();
2529 let declIndex = parentType.privDecls[i];2670 if (domSearch.value !== curNavSearch) {
2530 let childDecl = zigAnalysis.decls[declIndex];2671 domSearch.value = curNavSearch;
2531 if (childDecl.name === childName) {2672 if (domSearch.value.length == 0)
2532 return childDecl;2673 domSearchPlaceholder.classList.remove("hidden");
2674 else
2675 domSearchPlaceholder.classList.add("hidden");
2676 }
2677 render();
2678 if (imFeelingLucky) {
2679 imFeelingLucky = false;
2680 activateSelectedResult();
2681 }
2682 }
2683
2684 function findSubDecl(parentType, childName) {
2685 {
2686 // Generic functions
2687 if ("value" in parentType) {
2688 const rv = resolveValue(parentType.value);
2689 if ("type" in rv.expr) {
2690 const t = zigAnalysis.types[rv.expr.type];
2691 if (t.kind == typeKinds.Fn && t.generic_ret != null) {
2692 const rgr = resolveValue({ expr: t.generic_ret });
2693 if ("type" in rgr.expr) {
2694 parentType = zigAnalysis.types[rgr.expr.type];
2533 }2695 }
2696 }
2534 }2697 }
2535 return null;2698 }
2536 }2699 }
25372700
2701 if (!parentType.pubDecls) return null;
2702 for (let i = 0; i < parentType.pubDecls.length; i += 1) {
2703 let declIndex = parentType.pubDecls[i];
2704 let childDecl = zigAnalysis.decls[declIndex];
2705 if (childDecl.name === childName) {
2706 return childDecl;
2707 }
2708 }
2709 if (!parentType.privDecls) return null;
2710 for (let i = 0; i < parentType.privDecls.length; i += 1) {
2711 let declIndex = parentType.privDecls[i];
2712 let childDecl = zigAnalysis.decls[declIndex];
2713 if (childDecl.name === childName) {
2714 return childDecl;
2715 }
2716 }
2717 return null;
2718 }
2719
2720 function computeCanonicalPackagePaths() {
2721 let list = new Array(zigAnalysis.packages.length);
2722 // Now we try to find all the packages from root.
2723 let rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg];
2724 // Breadth-first to keep the path shortest possible.
2725 let stack = [
2726 {
2727 path: [],
2728 pkg: rootPkg,
2729 },
2730 ];
2731 while (stack.length !== 0) {
2732 let item = stack.shift();
2733 for (let key in item.pkg.table) {
2734 let childPkgIndex = item.pkg.table[key];
2735 if (list[childPkgIndex] != null) continue;
2736 let childPkg = zigAnalysis.packages[childPkgIndex];
2737 if (childPkg == null) continue;
2738
2739 let newPath = item.path.concat([key]);
2740 list[childPkgIndex] = newPath;
2741 stack.push({
2742 path: newPath,
2743 pkg: childPkg,
2744 });
2745 }
2746 }
2747 return list;
2748 }
25382749
2750 function computeCanonDeclPaths() {
2751 let list = new Array(zigAnalysis.decls.length);
2752 canonTypeDecls = new Array(zigAnalysis.types.length);
25392753
2754 for (let pkgI = 0; pkgI < zigAnalysis.packages.length; pkgI += 1) {
2755 if (pkgI === zigAnalysis.rootPkg && rootIsStd) continue;
2756 let pkg = zigAnalysis.packages[pkgI];
2757 let pkgNames = canonPkgPaths[pkgI];
2758 if (pkgNames === undefined) continue;
25402759
2541 function computeCanonicalPackagePaths() {2760 let stack = [
2542 let list = new Array(zigAnalysis.packages.length);2761 {
2543 // Now we try to find all the packages from root.2762 declNames: [],
2544 let rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg];2763 type: zigAnalysis.types[pkg.main],
2545 // Breadth-first to keep the path shortest possible.2764 },
2546 let stack = [{2765 ];
2547 path: ([]),2766 while (stack.length !== 0) {
2548 pkg: rootPkg,2767 let item = stack.shift();
2549 }];2768
2550 while (stack.length !== 0) {2769 if (isContainerType(item.type)) {
2551 let item = (stack.shift());2770 let t = item.type;
2552 for (let key in item.pkg.table) {2771
2553 let childPkgIndex = item.pkg.table[key];2772 let len = t.pubDecls ? t.pubDecls.length : 0;
2554 if (list[childPkgIndex] != null) continue;2773 for (let declI = 0; declI < len; declI += 1) {
2555 let childPkg = zigAnalysis.packages[childPkgIndex];2774 let mainDeclIndex = t.pubDecls[declI];
2556 if (childPkg == null) continue;2775 if (list[mainDeclIndex] != null) continue;
2776
2777 let decl = zigAnalysis.decls[mainDeclIndex];
2778 let declVal = resolveValue(decl.value);
2779 let declNames = item.declNames.concat([decl.name]);
2780 list[mainDeclIndex] = {
2781 pkgNames: pkgNames,
2782 declNames: declNames,
2783 };
2784 if ("type" in declVal.expr) {
2785 let value = zigAnalysis.types[declVal.expr.type];
2786 if (declCanRepresentTypeKind(value.kind)) {
2787 canonTypeDecls[declVal.type] = mainDeclIndex;
2788 }
25572789
2558 let newPath = item.path.concat([key])2790 if (isContainerType(value)) {
2559 list[childPkgIndex] = newPath;
2560 stack.push({2791 stack.push({
2561 path: newPath,2792 declNames: declNames,
2562 pkg: childPkg,2793 type: value,
2563 });2794 });
2564 }2795 }
2565 }2796
2566 return list;2797 // Generic function
2567 }2798 if (value.kind == typeKinds.Fn && value.generic_ret != null) {
25682799 let resolvedVal = resolveValue({ expr: value.generic_ret });
25692800 if ("type" in resolvedVal.expr) {
2570 2801 let generic_type = zigAnalysis.types[resolvedVal.expr.type];
2571 function computeCanonDeclPaths() {2802 if (isContainerType(generic_type)) {
2572 let list = new Array(zigAnalysis.decls.length);2803 stack.push({
2573 canonTypeDecls = new Array(zigAnalysis.types.length);2804 declNames: declNames,
25742805 type: generic_type,
2575 for (let pkgI = 0; pkgI < zigAnalysis.packages.length; pkgI += 1) {2806 });
2576 if (pkgI === zigAnalysis.rootPkg && rootIsStd) continue;2807 }
2577 let pkg = zigAnalysis.packages[pkgI];
2578 let pkgNames = canonPkgPaths[pkgI];
2579 if (pkgNames === undefined) continue;
2580
2581 let stack = [{
2582 declNames: ([]),
2583 type: zigAnalysis.types[pkg.main],
2584 }];
2585 while (stack.length !== 0) {
2586 let item = (stack.shift());
2587
2588 if (isContainerType(item.type)) {
2589 let t = (item.type);
2590
2591 let len = t.pubDecls ? t.pubDecls.length : 0;
2592 for (let declI = 0; declI < len; declI += 1) {
2593 let mainDeclIndex = t.pubDecls[declI];
2594 if (list[mainDeclIndex] != null) continue;
2595
2596 let decl = zigAnalysis.decls[mainDeclIndex];
2597 let declVal = resolveValue(decl.value);
2598 let declNames = item.declNames.concat([decl.name]);
2599 list[mainDeclIndex] = {
2600 pkgNames: pkgNames,
2601 declNames: declNames,
2602 };
2603 if ("type" in declVal.expr) {
2604 let value = zigAnalysis.types[declVal.expr.type];
2605 if (declCanRepresentTypeKind(value.kind))
2606 {
2607 canonTypeDecls[declVal.type] = mainDeclIndex;
2608 }
2609
2610 if (isContainerType(value)) {
2611 stack.push({
2612 declNames: declNames,
2613 type:value,
2614 });
2615 }
2616
2617
2618 // Generic fun/ction
2619 if (value.kind == typeKinds.Fn && value.generic_ret != null) {
2620 let resolvedVal = resolveValue({ expr: value.generic_ret});
2621 if ("type" in resolvedVal.expr) {
2622 let generic_type = zigAnalysis.types[resolvedVal.expr.type];
2623 if (isContainerType(generic_type)){
2624 stack.push({
2625 declNames: declNames,
2626 type: generic_type,
2627 });
2628 }
2629 }
2630 }
2631 }
2632 }
2633 }2808 }
2809 }
2634 }2810 }
2811 }
2635 }2812 }
2636 return list;2813 }
2637 }
2638
2639
2640 function getCanonDeclPath(index) {
2641 if (canonDeclPaths == null) {
2642 canonDeclPaths = computeCanonDeclPaths();
2643 }
2644 //let cd = (canonDeclPaths);
2645 return canonDeclPaths[index];
2646 }
2647
2648
2649 function getCanonTypeDecl(index) {
2650 getCanonDeclPath(0);
2651 //let ct = (canonTypeDecls);
2652 return canonTypeDecls[index];
2653 }2814 }
2815 return list;
2816 }
26542817
2655 2818 function getCanonDeclPath(index) {
2656 function escapeHtml(text) {2819 if (canonDeclPaths == null) {
2657 return text.replace(/[&"<>]/g, function (m) {2820 canonDeclPaths = computeCanonDeclPaths();
2658 return escapeHtmlReplacements[m];
2659 });
2660 }2821 }
26612822 //let cd = (canonDeclPaths);
26622823 return canonDeclPaths[index];
2663 function shortDescMarkdown(docs) {2824 }
2664 const trimmed_docs = docs.trim();2825
2665 let index = trimmed_docs.indexOf('.');2826 function getCanonTypeDecl(index) {
2666 if (index < 0) {2827 getCanonDeclPath(0);
2667 index = trimmed_docs.indexOf('\n');2828 //let ct = (canonTypeDecls);
2668 if (index < 0) {2829 return canonTypeDecls[index];
2669 index = trimmed_docs.length;2830 }
2670 }2831
2832 function escapeHtml(text) {
2833 return text.replace(/[&"<>]/g, function (m) {
2834 return escapeHtmlReplacements[m];
2835 });
2836 }
2837
2838 function shortDescMarkdown(docs) {
2839 const trimmed_docs = docs.trim();
2840 let index = trimmed_docs.indexOf("\n\n");
2841 let cut = false;
2842
2843 if (index < 0 || index > 80) {
2844 if (trimmed_docs.length > 80) {
2845 index = 80;
2846 cut = true;
2671 } else {2847 } else {
2672 index += 1; // include the period2848 index = trimmed_docs.length;
2673 }2849 }
2674 const slice = trimmed_docs.slice(0, index);
2675 return markdown(slice);
2676 }2850 }
26772851
26782852 let slice = trimmed_docs.slice(0, index);
2679 function markdown(input) {2853 if (cut) slice += "...";
2680 const raw_lines = input.split('\n'); // zig allows no '\r', so we don't need to split on CR2854 return markdown(slice);
2681 2855 }
2682 const lines = [];2856
26832857 function markdown(input) {
2684 // PHASE 1:2858 const raw_lines = input.split("\n"); // zig allows no '\r', so we don't need to split on CR
2685 // Dissect lines and determine the type for each line.2859
2686 // Also computes indentation level and removes unnecessary whitespace2860 const lines = [];
26872861
2688 let is_reading_code = false;2862 // PHASE 1:
2689 let code_indent = 0;2863 // Dissect lines and determine the type for each line.
2690 for (let line_no = 0; line_no < raw_lines.length; line_no++) {2864 // Also computes indentation level and removes unnecessary whitespace
2691 const raw_line = raw_lines[line_no];2865
26922866 let is_reading_code = false;
2693 const line = {2867 let code_indent = 0;
2694 indent: 0,2868 for (let line_no = 0; line_no < raw_lines.length; line_no++) {
2695 raw_text: raw_line,2869 const raw_line = raw_lines[line_no];
2696 text: raw_line.trim(),2870
2697 type: "p", // p, h1 … h6, code, ul, ol, blockquote, skip, empty2871 const line = {
2698 ordered_number: -1, // NOTE: hack to make the type checker happy2872 indent: 0,
2699 };2873 raw_text: raw_line,
27002874 text: raw_line.trim(),
2701 if (!is_reading_code) {2875 type: "p", // p, h1 … h6, code, ul, ol, blockquote, skip, empty
2702 while ((line.indent < line.raw_text.length) && line.raw_text[line.indent] == ' ') {2876 ordered_number: -1, // NOTE: hack to make the type checker happy
2703 line.indent += 1;2877 };
2704 }2878
27052879 if (!is_reading_code) {
2706 if (line.text.startsWith("######")) {2880 while (
2707 line.type = "h6";2881 line.indent < line.raw_text.length &&
2708 line.text = line.text.substr(6);2882 line.raw_text[line.indent] == " "
2709 }2883 ) {
2710 else if (line.text.startsWith("#####")) {2884 line.indent += 1;
2711 line.type = "h5";2885 }
2712 line.text = line.text.substr(5);2886
2713 }2887 if (line.text.startsWith("######")) {
2714 else if (line.text.startsWith("####")) {2888 line.type = "h6";
2715 line.type = "h4";2889 line.text = line.text.substr(6);
2716 line.text = line.text.substr(4);2890 } else if (line.text.startsWith("#####")) {
2717 }2891 line.type = "h5";
2718 else if (line.text.startsWith("###")) {2892 line.text = line.text.substr(5);
2719 line.type = "h3";2893 } else if (line.text.startsWith("####")) {
2720 line.text = line.text.substr(3);2894 line.type = "h4";
2721 }2895 line.text = line.text.substr(4);
2722 else if (line.text.startsWith("##")) {2896 } else if (line.text.startsWith("###")) {
2723 line.type = "h2";2897 line.type = "h3";
2724 line.text = line.text.substr(2);2898 line.text = line.text.substr(3);
2725 }2899 } else if (line.text.startsWith("##")) {
2726 else if (line.text.startsWith("#")) {2900 line.type = "h2";
2727 line.type = "h1";2901 line.text = line.text.substr(2);
2728 line.text = line.text.substr(1);2902 } else if (line.text.startsWith("#")) {
2729 }2903 line.type = "h1";
2730 else if (line.text.startsWith("-")) {2904 line.text = line.text.substr(1);
2731 line.type = "ul";2905 } else if (line.text.startsWith("-")) {
2732 line.text = line.text.substr(1);2906 line.type = "ul";
2733 }2907 line.text = line.text.substr(1);
2734 else if (line.text.match(/^\d+\..*$/)) { // if line starts with {number}{dot}2908 } else if (line.text.match(/^\d+\..*$/)) {
2735 const match = (line.text.match(/(\d+)\./));2909 // if line starts with {number}{dot}
2736 line.type = "ul";2910 const match = line.text.match(/(\d+)\./);
2737 line.text = line.text.substr(match[0].length);2911 line.type = "ul";
2738 line.ordered_number = Number(match[1].length);2912 line.text = line.text.substr(match[0].length);
2739 }2913 line.ordered_number = Number(match[1].length);
2740 else if (line.text == "```") {2914 } else if (line.text == "```") {
2741 line.type = "skip";2915 line.type = "skip";
2742 is_reading_code = true;2916 is_reading_code = true;
2743 code_indent = line.indent;2917 code_indent = line.indent;
2744 }2918 } else if (line.text == "") {
2745 else if (line.text == "") {2919 line.type = "empty";
2746 line.type = "empty";2920 }
2747 }2921 } else {
2748 }2922 if (line.text == "```") {
2749 else {2923 is_reading_code = false;
2750 if (line.text == "```") {2924 line.type = "skip";
2751 is_reading_code = false;2925 } else {
2752 line.type = "skip";2926 line.type = "code";
2753 } else {2927 line.text = line.raw_text.substr(code_indent); // remove the indent of the ``` from all the code block
2754 line.type = "code";
2755 line.text = line.raw_text.substr(code_indent); // remove the indent of the ``` from all the code block
2756 }
2757 }
2758
2759 if (line.type != "skip") {
2760 lines.push(line);
2761 }
2762 }2928 }
2929 }
27632930
2764 // PHASE 2:2931 if (line.type != "skip") {
2765 // Render HTML from markdown lines.2932 lines.push(line);
2766 // Look at each line and emit fitting HTML code2933 }
27672934 }
2768
2769 function markdownInlines(innerText) {
2770
2771 // inline types:
2772 // **{INLINE}** : <strong>
2773 // __{INLINE}__ : <u>
2774 // ~~{INLINE}~~ : <s>
2775 // *{INLINE}* : <emph>
2776 // _{INLINE}_ : <emph>
2777 // `{TEXT}` : <code>
2778 // [{INLINE}]({URL}) : <a>
2779 // ![{TEXT}]({URL}) : <img>
2780 // [[std;format.fmt]] : <a> (inner link)
2781
2782
2783
2784 const formats = [
2785 {
2786 marker: "**",
2787 tag: "strong",
2788 },
2789 {
2790 marker: "~~",
2791 tag: "s",
2792 },
2793 {
2794 marker: "__",
2795 tag: "u",
2796 },
2797 {
2798 marker: "*",
2799 tag: "em",
2800 }
2801 ];
28022935
2803 2936 // PHASE 2:
2804 const stack = [];2937 // Render HTML from markdown lines.
2938 // Look at each line and emit fitting HTML code
2939
2940 function markdownInlines(innerText) {
2941 // inline types:
2942 // **{INLINE}** : <strong>
2943 // __{INLINE}__ : <u>
2944 // ~~{INLINE}~~ : <s>
2945 // *{INLINE}* : <emph>
2946 // _{INLINE}_ : <emph>
2947 // `{TEXT}` : <code>
2948 // [{INLINE}]({URL}) : <a>
2949 // ![{TEXT}]({URL}) : <img>
2950 // [[std;format.fmt]] : <a> (inner link)
2951
2952 const formats = [
2953 {
2954 marker: "**",
2955 tag: "strong",
2956 },
2957 {
2958 marker: "~~",
2959 tag: "s",
2960 },
2961 {
2962 marker: "__",
2963 tag: "u",
2964 },
2965 {
2966 marker: "*",
2967 tag: "em",
2968 },
2969 ];
28052970
2806 let innerHTML = "";2971 const stack = [];
2807 let currentRun = "";
28082972
2809 function flushRun() {2973 let innerHTML = "";
2810 if (currentRun != "") {2974 let currentRun = "";
2811 innerHTML += escapeHtml(currentRun);
2812 }
2813 currentRun = "";
2814 }
28152975
2816 let parsing_code = false;2976 function flushRun() {
2817 let codetag = "";2977 if (currentRun != "") {
2818 let in_code = false;2978 innerHTML += escapeHtml(currentRun);
28192979 }
2820 for (let i = 0; i < innerText.length; i++) {2980 currentRun = "";
28212981 }
2822 if (parsing_code && in_code) {
2823 if (innerText.substr(i, codetag.length) == codetag) {
2824 // remove leading and trailing whitespace if string both starts and ends with one.
2825 if (currentRun[0] == " " && currentRun[currentRun.length - 1] == " ") {
2826 currentRun = currentRun.substr(1, currentRun.length - 2);
2827 }
2828 flushRun();
2829 i += codetag.length - 1;
2830 in_code = false;
2831 parsing_code = false;
2832 innerHTML += "</code>";
2833 codetag = "";
2834 } else {
2835 currentRun += innerText[i];
2836 }
2837 continue;
2838 }
28392982
2840 if (innerText[i] == "`") {2983 let parsing_code = false;
2841 flushRun();2984 let codetag = "";
2842 if (!parsing_code) {2985 let in_code = false;
2843 innerHTML += "<code>";
2844 }
2845 parsing_code = true;
2846 codetag += "`";
2847 continue;
2848 }
28492986
2850 if (parsing_code) {2987 for (let i = 0; i < innerText.length; i++) {
2851 currentRun += innerText[i];2988 if (parsing_code && in_code) {
2852 in_code = true;2989 if (innerText.substr(i, codetag.length) == codetag) {
2853 } else {2990 // remove leading and trailing whitespace if string both starts and ends with one.
2854 let any = false;2991 if (
2855 for (let idx = (stack.length > 0 ? -1 : 0); idx < formats.length; idx++) {2992 currentRun[0] == " " &&
2856 const fmt = idx >= 0 ? formats[idx] : stack[stack.length - 1];2993 currentRun[currentRun.length - 1] == " "
2857 if (innerText.substr(i, fmt.marker.length) == fmt.marker) {2994 ) {
2858 flushRun();2995 currentRun = currentRun.substr(1, currentRun.length - 2);
2859 if (stack[stack.length - 1] == fmt) {
2860 stack.pop();
2861 innerHTML += "</" + fmt.tag + ">";
2862 } else {
2863 stack.push(fmt);
2864 innerHTML += "<" + fmt.tag + ">";
2865 }
2866 i += fmt.marker.length - 1;
2867 any = true;
2868 break;
2869 }
2870 }
2871 if (!any) {
2872 currentRun += innerText[i];
2873 }
2874 }
2875 }2996 }
2876 flushRun();2997 flushRun();
28772998 i += codetag.length - 1;
2878 while (stack.length > 0) {2999 in_code = false;
2879 const fmt = (stack.pop());3000 parsing_code = false;
2880 innerHTML += "</" + fmt.tag + ">";3001 innerHTML += "</code>";
2881 }3002 codetag = "";
28823003 } else {
2883 return innerHTML;3004 currentRun += innerText[i];
2884 }3005 }
28853006 continue;
2886
2887 function previousLineIs(type, line_no) {
2888 if (line_no > 0) {
2889 return (lines[line_no - 1].type == type);
2890 } else {
2891 return false;
2892 }
2893 }3007 }
28943008
2895 3009 if (innerText[i] == "`") {
2896 function nextLineIs(type, line_no) {3010 flushRun();
2897 if (line_no < (lines.length - 1)) {3011 if (!parsing_code) {
2898 return (lines[line_no + 1].type == type);3012 innerHTML += "<code>";
2899 } else {3013 }
2900 return false;3014 parsing_code = true;
2901 }3015 codetag += "`";
3016 continue;
2902 }3017 }
29033018
2904 3019 if (parsing_code) {
2905 function getPreviousLineIndent(line_no) {3020 currentRun += innerText[i];
2906 if (line_no > 0) {3021 in_code = true;
2907 return lines[line_no - 1].indent;3022 } else {
2908 } else {3023 let any = false;
2909 return 0;3024 for (
3025 let idx = stack.length > 0 ? -1 : 0;
3026 idx < formats.length;
3027 idx++
3028 ) {
3029 const fmt = idx >= 0 ? formats[idx] : stack[stack.length - 1];
3030 if (innerText.substr(i, fmt.marker.length) == fmt.marker) {
3031 flushRun();
3032 if (stack[stack.length - 1] == fmt) {
3033 stack.pop();
3034 innerHTML += "</" + fmt.tag + ">";
3035 } else {
3036 stack.push(fmt);
3037 innerHTML += "<" + fmt.tag + ">";
3038 }
3039 i += fmt.marker.length - 1;
3040 any = true;
3041 break;
2910 }3042 }
3043 }
3044 if (!any) {
3045 currentRun += innerText[i];
3046 }
2911 }3047 }
3048 }
3049 flushRun();
29123050
2913 3051 while (stack.length > 0) {
2914 function getNextLineIndent(line_no) {3052 const fmt = stack.pop();
2915 if (line_no < (lines.length - 1)) {3053 innerHTML += "</" + fmt.tag + ">";
2916 return lines[line_no + 1].indent;3054 }
2917 } else {
2918 return 0;
2919 }
2920 }
29213055
2922 let html = "";3056 return innerHTML;
2923 for (let line_no = 0; line_no < lines.length; line_no++) {3057 }
2924 const line = lines[line_no];
29253058
3059 function previousLineIs(type, line_no) {
3060 if (line_no > 0) {
3061 return lines[line_no - 1].type == type;
3062 } else {
3063 return false;
3064 }
3065 }
29263066
3067 function nextLineIs(type, line_no) {
3068 if (line_no < lines.length - 1) {
3069 return lines[line_no + 1].type == type;
3070 } else {
3071 return false;
3072 }
3073 }
29273074
2928 switch (line.type) {3075 function getPreviousLineIndent(line_no) {
2929 case "h1":3076 if (line_no > 0) {
2930 case "h2":3077 return lines[line_no - 1].indent;
2931 case "h3":3078 } else {
2932 case "h4":3079 return 0;
2933 case "h5":3080 }
2934 case "h6":3081 }
2935 html += "<" + line.type + ">" + markdownInlines(line.text) + "</" + line.type + ">\n";
2936 break;
29373082
2938 case "ul":3083 function getNextLineIndent(line_no) {
2939 case "ol":3084 if (line_no < lines.length - 1) {
2940 if (!previousLineIs("ul", line_no) || getPreviousLineIndent(line_no) < line.indent) {3085 return lines[line_no + 1].indent;
2941 html += "<" + line.type + ">\n";3086 } else {
2942 }3087 return 0;
3088 }
3089 }
29433090
2944 html += "<li>" + markdownInlines(line.text) + "</li>\n";3091 let html = "";
3092 for (let line_no = 0; line_no < lines.length; line_no++) {
3093 const line = lines[line_no];
3094
3095 switch (line.type) {
3096 case "h1":
3097 case "h2":
3098 case "h3":
3099 case "h4":
3100 case "h5":
3101 case "h6":
3102 html +=
3103 "<" +
3104 line.type +
3105 ">" +
3106 markdownInlines(line.text) +
3107 "</" +
3108 line.type +
3109 ">\n";
3110 break;
3111
3112 case "ul":
3113 case "ol":
3114 if (
3115 !previousLineIs("ul", line_no) ||
3116 getPreviousLineIndent(line_no) < line.indent
3117 ) {
3118 html += "<" + line.type + ">\n";
3119 }
29453120
2946 if (!nextLineIs("ul", line_no) || getNextLineIndent(line_no) < line.indent) {3121 html += "<li>" + markdownInlines(line.text) + "</li>\n";
2947 html += "</" + line.type + ">\n";
2948 }
2949 break;
29503122
2951 case "p":3123 if (
2952 if (!previousLineIs("p", line_no)) {3124 !nextLineIs("ul", line_no) ||
2953 html += "<p>\n";3125 getNextLineIndent(line_no) < line.indent
2954 }3126 ) {
2955 html += markdownInlines(line.text) + "\n";3127 html += "</" + line.type + ">\n";
2956 if (!nextLineIs("p", line_no)) {3128 }
2957 html += "</p>\n";3129 break;
2958 }
2959 break;
29603130
2961 case "code":3131 case "p":
2962 if (!previousLineIs("code", line_no)) {3132 if (!previousLineIs("p", line_no)) {
2963 html += "<pre><code>";3133 html += "<p>\n";
2964 }3134 }
2965 html += escapeHtml(line.text) + "\n";3135 html += markdownInlines(line.text) + "\n";
2966 if (!nextLineIs("code", line_no)) {3136 if (!nextLineIs("p", line_no)) {
2967 html += "</code></pre>\n";3137 html += "</p>\n";
2968 }3138 }
2969 break;3139 break;
2970 }
2971 }
29723140
2973 return html;3141 case "code":
3142 if (!previousLineIs("code", line_no)) {
3143 html += "<pre><code>";
3144 }
3145 html += escapeHtml(line.text) + "\n";
3146 if (!nextLineIs("code", line_no)) {
3147 html += "</code></pre>\n";
3148 }
3149 break;
3150 }
2974 }3151 }
29753152
2976 function activateSelectedResult() {3153 return html;
2977 if (domSectSearchResults.classList.contains("hidden")) {3154 }
2978 return;
2979 }
29803155
2981 let liDom = domListSearchResults.children[curSearchIndex];3156 function activateSelectedResult() {
2982 if (liDom == null && domListSearchResults.children.length !== 0) {3157 if (domSectSearchResults.classList.contains("hidden")) {
2983 liDom = domListSearchResults.children[0];3158 return;
2984 }
2985 if (liDom != null) {
2986 let aDom = liDom.children[0];
2987 location.href = (aDom.getAttribute("href"));
2988 curSearchIndex = -1;
2989 }
2990 domSearch.blur();
2991 }
2992
2993
2994 function onSearchKeyDown(ev) {
2995 switch (getKeyString(ev)) {
2996 case "Enter":
2997 // detect if this search changes anything
2998 let terms1 = getSearchTerms();
2999 startSearch();
3000 updateCurNav();
3001 let terms2 = getSearchTerms();
3002 // we might have to wait for onHashChange to trigger
3003 imFeelingLucky = (terms1.join(' ') !== terms2.join(' '));
3004 if (!imFeelingLucky) activateSelectedResult();
3005
3006 ev.preventDefault();
3007 ev.stopPropagation();
3008 return;
3009 case "Esc":
3010 domSearch.value = "";
3011 domSearch.blur();
3012 curSearchIndex = -1;
3013 ev.preventDefault();
3014 ev.stopPropagation();
3015 startSearch();
3016 return;
3017 case "Up":
3018 moveSearchCursor(-1);
3019 ev.preventDefault();
3020 ev.stopPropagation();
3021 return;
3022 case "Down":
3023 moveSearchCursor(1);
3024 ev.preventDefault();
3025 ev.stopPropagation();
3026 return;
3027 default:
3028 if (ev.shiftKey || ev.ctrlKey || ev.altKey) return;
3029
3030 curSearchIndex = -1;
3031 ev.stopPropagation();
3032 startAsyncSearch();
3033 return;
3034 }
3035 }3159 }
30363160
30373161 let liDom = domListSearchResults.children[curSearchIndex];
3038 3162 if (liDom == null && domListSearchResults.children.length !== 0) {
3039 function moveSearchCursor(dir) {3163 liDom = domListSearchResults.children[0];
3040 if (curSearchIndex < 0 || curSearchIndex >= domListSearchResults.children.length) {
3041 if (dir > 0) {
3042 curSearchIndex = -1 + dir;
3043 } else if (dir < 0) {
3044 curSearchIndex = domListSearchResults.children.length + dir;
3045 }
3046 } else {
3047 curSearchIndex += dir;
3048 }
3049 if (curSearchIndex < 0) {
3050 curSearchIndex = 0;
3051 }
3052 if (curSearchIndex >= domListSearchResults.children.length) {
3053 curSearchIndex = domListSearchResults.children.length - 1;
3054 }
3055 renderSearchCursor();
3056 }3164 }
30573165 if (liDom != null) {
3058 3166 let aDom = liDom.children[0];
3059 function getKeyString(ev) {3167 location.href = aDom.getAttribute("href");
3060 let name;3168 curSearchIndex = -1;
3061 let ignoreShift = false;
3062 switch (ev.which) {
3063 case 13:
3064 name = "Enter";
3065 break;
3066 case 27:
3067 name = "Esc";
3068 break;
3069 case 38:
3070 name = "Up";
3071 break;
3072 case 40:
3073 name = "Down";
3074 break;
3075 default:
3076 ignoreShift = true;
3077 name = (ev.key != null) ? ev.key : String.fromCharCode(ev.charCode || ev.keyCode);
3078 }
3079 if (!ignoreShift && ev.shiftKey) name = "Shift+" + name;
3080 if (ev.altKey) name = "Alt+" + name;
3081 if (ev.ctrlKey) name = "Ctrl+" + name;
3082 return name;
3083 }3169 }
30843170 domSearch.blur();
3085 3171 }
3086 function onWindowKeyDown(ev) {3172
3087 switch (getKeyString(ev)) {3173 // hide the modal if it's visible or return to the previous result page and unfocus the search
3088 case "Esc":3174 function onEscape(ev) {
3089 if (!domHelpModal.classList.contains("hidden")) {3175 if (!domHelpModal.classList.contains("hidden")) {
3090 domHelpModal.classList.add("hidden");3176 domHelpModal.classList.add("hidden");
3091 ev.preventDefault();3177 ev.preventDefault();
3092 ev.stopPropagation();3178 ev.stopPropagation();
3093 }3179 } else {
3094 break;3180 domSearch.value = "";
3095 case "s":3181 domSearch.blur();
3096 domSearch.focus();3182 domSearchPlaceholder.classList.remove("hidden");
3097 domSearch.select();3183 curSearchIndex = -1;
3098 ev.preventDefault();3184 ev.preventDefault();
3099 ev.stopPropagation();3185 ev.stopPropagation();
3100 startAsyncSearch();3186 startSearch();
3101 break;3187 }
3102 case "?":3188 }
3103 ev.preventDefault();3189
3104 ev.stopPropagation();3190 function onSearchKeyDown(ev) {
3105 showHelpModal();3191 switch (getKeyString(ev)) {
3106 break;3192 case "Enter":
3107 }3193 // detect if this search changes anything
3194 let terms1 = getSearchTerms();
3195 startSearch();
3196 updateCurNav();
3197 let terms2 = getSearchTerms();
3198 // we might have to wait for onHashChange to trigger
3199 imFeelingLucky = terms1.join(" ") !== terms2.join(" ");
3200 if (!imFeelingLucky) activateSelectedResult();
3201
3202 ev.preventDefault();
3203 ev.stopPropagation();
3204 return;
3205 case "Esc":
3206 onEscape(ev);
3207 return
3208 case "Up":
3209 moveSearchCursor(-1);
3210 ev.preventDefault();
3211 ev.stopPropagation();
3212 return;
3213 case "Down":
3214 // TODO: make the page scroll down if the search cursor is out of the screen
3215 moveSearchCursor(1);
3216 ev.preventDefault();
3217 ev.stopPropagation();
3218 return;
3219 default:
3220 if (ev.shiftKey || ev.ctrlKey || ev.altKey) return;
3221
3222 curSearchIndex = -1;
3223 ev.stopPropagation();
3224 startAsyncSearch();
3225 return;
3226 }
3227 }
3228
3229 function moveSearchCursor(dir) {
3230 if (
3231 curSearchIndex < 0 ||
3232 curSearchIndex >= domListSearchResults.children.length
3233 ) {
3234 if (dir > 0) {
3235 curSearchIndex = -1 + dir;
3236 } else if (dir < 0) {
3237 curSearchIndex = domListSearchResults.children.length + dir;
3238 }
3239 } else {
3240 curSearchIndex += dir;
3108 }3241 }
3242 if (curSearchIndex < 0) {
3243 curSearchIndex = 0;
3244 }
3245 if (curSearchIndex >= domListSearchResults.children.length) {
3246 curSearchIndex = domListSearchResults.children.length - 1;
3247 }
3248 renderSearchCursor();
3249 }
3250
3251 function getKeyString(ev) {
3252 let name;
3253 let ignoreShift = false;
3254 switch (ev.which) {
3255 case 13:
3256 name = "Enter";
3257 break;
3258 case 27:
3259 name = "Esc";
3260 break;
3261 case 38:
3262 name = "Up";
3263 break;
3264 case 40:
3265 name = "Down";
3266 break;
3267 default:
3268 ignoreShift = true;
3269 name =
3270 ev.key != null
3271 ? ev.key
3272 : String.fromCharCode(ev.charCode || ev.keyCode);
3273 }
3274 if (!ignoreShift && ev.shiftKey) name = "Shift+" + name;
3275 if (ev.altKey) name = "Alt+" + name;
3276 if (ev.ctrlKey) name = "Ctrl+" + name;
3277 return name;
3278 }
3279
3280 function onWindowKeyDown(ev) {
3281 switch (getKeyString(ev)) {
3282 case "Esc":
3283 onEscape(ev);
3284 break;
3285 case "s":
3286 if (domHelpModal.classList.contains("hidden")) {
3287 if (ev.target == domSearch) break;
3288
3289 domSearch.focus();
3290 domSearch.select();
3291 domDocs.scrollTo(0, 0);
3292 ev.preventDefault();
3293 ev.stopPropagation();
3294 startAsyncSearch();
3295 }
3296 break;
3297 case "?":
3298 ev.preventDefault();
3299 ev.stopPropagation();
3300 showHelpModal();
3301 break;
3302 }
3303 }
31093304
3110function showHelpModal() {3305 function showHelpModal() {
3111 domHelpModal.classList.remove("hidden");3306 domHelpModal.classList.remove("hidden");
3112 domHelpModal.style.left = (window.innerWidth / 2 - domHelpModal.clientWidth / 2) + "px";3307 domHelpModal.style.left =
3113 domHelpModal.style.top = (window.innerHeight / 2 - domHelpModal.clientHeight / 2) + "px";3308 window.innerWidth / 2 - domHelpModal.clientWidth / 2 + "px";
3309 domHelpModal.style.top =
3310 window.innerHeight / 2 - domHelpModal.clientHeight / 2 + "px";
3114 domHelpModal.focus();3311 domHelpModal.focus();
3115}3312 domSearch.blur();
3313 }
31163314
3117function clearAsyncSearch() {3315 function clearAsyncSearch() {
3118 if (searchTimer != null) {3316 if (searchTimer != null) {
3119 clearTimeout(searchTimer);3317 clearTimeout(searchTimer);
3120 searchTimer = null;3318 searchTimer = null;
3121 }3319 }
3122}3320 }
31233321
3124function startAsyncSearch() {3322 function startAsyncSearch() {
3125 clearAsyncSearch();3323 clearAsyncSearch();
3126 searchTimer = setTimeout(startSearch, 100);3324 searchTimer = setTimeout(startSearch, 100);
3127}3325 }
3128function startSearch() {3326 function startSearch() {
3129 clearAsyncSearch();3327 clearAsyncSearch();
3130 let oldHash = location.hash;3328 let oldHash = location.hash;
3131 let parts = oldHash.split("?");3329 let parts = oldHash.split("?");
3132 let newPart2 = (domSearch.value === "") ? "" : ("?" + domSearch.value);3330 let newPart2 = domSearch.value === "" ? "" : "?" + domSearch.value;
3133 location.hash = (parts.length === 1) ? (oldHash + newPart2) : (parts[0] + newPart2);3331 location.replace(parts.length === 1 ? oldHash + newPart2 : parts[0] + newPart2);
3134}3332 }
3135function getSearchTerms() {3333 function getSearchTerms() {
3136 let list = curNavSearch.trim().split(/[ \r\n\t]+/);3334 let list = curNavSearch.trim().split(/[ \r\n\t]+/);
3137 list.sort();3335 list.sort();
3138 return list;3336 return list;
3139}3337 }
3140function renderSearch() {3338
3339 function renderSearch() {
3141 let matchedItems = [];3340 let matchedItems = [];
3142 let ignoreCase = (curNavSearch.toLowerCase() === curNavSearch);3341 let ignoreCase = curNavSearch.toLowerCase() === curNavSearch;
3143 let terms = getSearchTerms();3342 let terms = getSearchTerms();
31443343
3145 decl_loop: for (let declIndex = 0; declIndex < zigAnalysis.decls.length; declIndex += 1) {3344 decl_loop: for (
3146 let canonPath = getCanonDeclPath(declIndex);3345 let declIndex = 0;
3147 if (canonPath == null) continue;3346 declIndex < zigAnalysis.decls.length;
31483347 declIndex += 1
3149 let decl = zigAnalysis.decls[declIndex];3348 ) {
3150 let lastPkgName = canonPath.pkgNames[canonPath.pkgNames.length - 1];3349 let canonPath = getCanonDeclPath(declIndex);
3151 let fullPathSearchText = lastPkgName + "." + canonPath.declNames.join('.');3350 if (canonPath == null) continue;
3152 let astNode = zigAnalysis.astNodes[decl.src];3351
3153 let fileAndDocs = "" //zigAnalysis.files[astNode.file];3352 let decl = zigAnalysis.decls[declIndex];
3154 // TODO: understand what this piece of code is trying to achieve3353 let lastPkgName = canonPath.pkgNames[canonPath.pkgNames.length - 1];
3155 // also right now `files` are expressed as a hashmap.3354 let fullPathSearchText =
3156 if (astNode.docs != null) {3355 lastPkgName + "." + canonPath.declNames.join(".");
3157 fileAndDocs += "\n" + astNode.docs;3356 let astNode = zigAnalysis.astNodes[decl.src];
3158 }3357 let fileAndDocs = ""; //zigAnalysis.files[astNode.file];
3159 let fullPathSearchTextLower = fullPathSearchText;3358 // TODO: understand what this piece of code is trying to achieve
3160 if (ignoreCase) {3359 // also right now `files` are expressed as a hashmap.
3161 fullPathSearchTextLower = fullPathSearchTextLower.toLowerCase();3360 if (astNode.docs != null) {
3162 fileAndDocs = fileAndDocs.toLowerCase();3361 fileAndDocs += "\n" + astNode.docs;
3163 }3362 }
31643363 let fullPathSearchTextLower = fullPathSearchText;
3165 let points = 0;3364 if (ignoreCase) {
3166 for (let termIndex = 0; termIndex < terms.length; termIndex += 1) {3365 fullPathSearchTextLower = fullPathSearchTextLower.toLowerCase();
3167 let term = terms[termIndex];3366 fileAndDocs = fileAndDocs.toLowerCase();
3367 }
31683368
3169 // exact, case sensitive match of full decl path3369 let points = 0;
3170 if (fullPathSearchText === term) {3370 for (let termIndex = 0; termIndex < terms.length; termIndex += 1) {
3171 points += 4;3371 let term = terms[termIndex];
3172 continue;
3173 }
3174 // exact, case sensitive match of just decl name
3175 if (decl.name == term) {
3176 points += 3;
3177 continue;
3178 }
3179 // substring, case insensitive match of full decl path
3180 if (fullPathSearchTextLower.indexOf(term) >= 0) {
3181 points += 2;
3182 continue;
3183 }
3184 if (fileAndDocs.indexOf(term) >= 0) {
3185 points += 1;
3186 continue;
3187 }
31883372
3189 continue decl_loop;3373 // exact, case sensitive match of full decl path
3374 if (fullPathSearchText === term) {
3375 points += 4;
3376 continue;
3377 }
3378 // exact, case sensitive match of just decl name
3379 if (decl.name == term) {
3380 points += 3;
3381 continue;
3382 }
3383 // substring, case insensitive match of full decl path
3384 if (fullPathSearchTextLower.indexOf(term) >= 0) {
3385 points += 2;
3386 continue;
3387 }
3388 if (fileAndDocs.indexOf(term) >= 0) {
3389 points += 1;
3390 continue;
3190 }3391 }
31913392
3192 matchedItems.push({3393 continue decl_loop;
3193 decl: decl,3394 }
3194 path: canonPath,3395
3195 points: points,3396 matchedItems.push({
3196 });3397 decl: decl,
3398 path: canonPath,
3399 points: points,
3400 });
3197 }3401 }
31983402
3199 if (matchedItems.length !== 0) {3403 if (matchedItems.length !== 0) {
3200 resizeDomList(domListSearchResults, matchedItems.length, '<li><a href="#"></a></li>');3404 matchedItems.sort(function (a, b) {
3405 let cmp = operatorCompare(b.points, a.points);
3406 if (cmp != 0) return cmp;
3407 return operatorCompare(a.decl.name, b.decl.name);
3408 });
3409
3410 let searchTrimmed = false;
3411 const searchTrimResultsMaxItems = 200;
3412 if (searchTrimResults && matchedItems.length > searchTrimResultsMaxItems) {
3413 matchedItems = matchedItems.slice(0, searchTrimResultsMaxItems);
3414 searchTrimmed = true;
3415 }
32013416
3202 matchedItems.sort(function(a, b) {3417 // Build up the list of search results
3203 let cmp = operatorCompare(b.points, a.points);3418 let matchedItemsHTML = "";
3204 if (cmp != 0) return cmp;
3205 return operatorCompare(a.decl.name, b.decl.name);
3206 });
32073419
3208 for (let i = 0; i < matchedItems.length; i += 1) {3420 for (let i = 0; i < matchedItems.length; i += 1) {
3209 let liDom = domListSearchResults.children[i];3421 const match = matchedItems[i];
3210 let aDom = liDom.children[0];3422 const lastPkgName = match.path.pkgNames[match.path.pkgNames.length - 1];
3211 let match = matchedItems[i];3423
3212 let lastPkgName = match.path.pkgNames[match.path.pkgNames.length - 1];3424 const text = lastPkgName + "." + match.path.declNames.join(".");
3213 aDom.textContent = lastPkgName + "." + match.path.declNames.join('.');3425 const href = navLink(match.path.pkgNames, match.path.declNames);
3214 aDom.setAttribute('href', navLink(match.path.pkgNames, match.path.declNames));
3215 }
3216 renderSearchCursor();
32173426
3218 domSectSearchResults.classList.remove("hidden");3427 matchedItemsHTML += "<li><a href=\"" + href + "\">" + text + "</a></li>";
3428 }
3429
3430 // Replace the search results using our newly constructed HTML string
3431 domListSearchResults.innerHTML = matchedItemsHTML;
3432 if (searchTrimmed) {
3433 domSectSearchAllResultsLink.classList.remove("hidden");
3434 }
3435 renderSearchCursor();
3436
3437 domSectSearchResults.classList.remove("hidden");
3219 } else {3438 } else {
3220 domSectSearchNoResults.classList.remove("hidden");3439 domSectSearchNoResults.classList.remove("hidden");
3221 }3440 }
3222}3441 }
32233442
3224function renderSearchCursor() {3443 function renderSearchCursor() {
3225 for (let i = 0; i < domListSearchResults.children.length; i += 1) {3444 for (let i = 0; i < domListSearchResults.children.length; i += 1) {
3226 let liDom = (domListSearchResults.children[i]);3445 let liDom = domListSearchResults.children[i];
3227 if (curSearchIndex === i) {3446 if (curSearchIndex === i) {
3228 liDom.classList.add("selected");3447 liDom.classList.add("selected");
3229 } else {3448 } else {
3230 liDom.classList.remove("selected");3449 liDom.classList.remove("selected");
3231 }3450 }
3232 }3451 }
3233}3452 }
32343453
32353454 // function indexNodesToCalls() {
32363455 // let map = {};
3237// function indexNodesToCalls() {3456 // for (let i = 0; i < zigAnalysis.calls.length; i += 1) {
3238// let map = {};3457 // let call = zigAnalysis.calls[i];
3239// for (let i = 0; i < zigAnalysis.calls.length; i += 1) {3458 // let fn = zigAnalysis.fns[call.fn];
3240// let call = zigAnalysis.calls[i];3459 // if (map[fn.src] == null) {
3241// let fn = zigAnalysis.fns[call.fn];3460 // map[fn.src] = [i];
3242// if (map[fn.src] == null) {3461 // } else {
3243// map[fn.src] = [i];3462 // map[fn.src].push(i);
3244// } else {3463 // }
3245// map[fn.src].push(i);3464 // }
3246// }3465 // return map;
3247// }3466 // }
3248// return map;3467
3249// }3468 function byNameProperty(a, b) {
3250
3251
3252
3253function byNameProperty(a, b) {
3254 return operatorCompare(a.name, b.name);3469 return operatorCompare(a.name, b.name);
3255}3470 }
3256
3257
3258
3259})();3471})();
lib/libc/glibc/abilists
Binary files a/lib/libc/glibc/abilists and b/lib/libc/glibc/abilists differ
lib/std/Thread/Futex.zig+2-2
...@@ -703,7 +703,7 @@ const PosixImpl = struct {...@@ -703,7 +703,7 @@ const PosixImpl = struct {
703 const max_multiplier_bits = @bitSizeOf(usize);703 const max_multiplier_bits = @bitSizeOf(usize);
704 const fibonacci_multiplier = 0x9E3779B97F4A7C15 >> (64 - max_multiplier_bits);704 const fibonacci_multiplier = 0x9E3779B97F4A7C15 >> (64 - max_multiplier_bits);
705705
706 const max_bucket_bits = @ctz(usize, buckets.len);706 const max_bucket_bits = @ctz(buckets.len);
707 comptime assert(std.math.isPowerOfTwo(buckets.len));707 comptime assert(std.math.isPowerOfTwo(buckets.len));
708708
709 const index = (address *% fibonacci_multiplier) >> (max_multiplier_bits - max_bucket_bits);709 const index = (address *% fibonacci_multiplier) >> (max_multiplier_bits - max_bucket_bits);
...@@ -721,7 +721,7 @@ const PosixImpl = struct {...@@ -721,7 +721,7 @@ const PosixImpl = struct {
721 // then cut off the zero bits from the alignment to get the unique address.721 // then cut off the zero bits from the alignment to get the unique address.
722 const addr = @ptrToInt(ptr);722 const addr = @ptrToInt(ptr);
723 assert(addr & (alignment - 1) == 0);723 assert(addr & (alignment - 1) == 0);
724 return addr >> @ctz(usize, alignment);724 return addr >> @ctz(alignment);
725 }725 }
726 };726 };
727727
lib/std/Thread/Mutex.zig+1-1
...@@ -140,7 +140,7 @@ const FutexImpl = struct {...@@ -140,7 +140,7 @@ const FutexImpl = struct {
140 // - they both seem to mark the cache-line as modified regardless: https://stackoverflow.com/a/63350048140 // - they both seem to mark the cache-line as modified regardless: https://stackoverflow.com/a/63350048
141 // - `lock bts` is smaller instruction-wise which makes it better for inlining141 // - `lock bts` is smaller instruction-wise which makes it better for inlining
142 if (comptime builtin.target.cpu.arch.isX86()) {142 if (comptime builtin.target.cpu.arch.isX86()) {
143 const locked_bit = @ctz(u32, @as(u32, locked));143 const locked_bit = @ctz(@as(u32, locked));
144 return self.state.bitSet(locked_bit, .Acquire) == 0;144 return self.state.bitSet(locked_bit, .Acquire) == 0;
145 }145 }
146146
lib/std/Thread/RwLock.zig+2-2
...@@ -168,8 +168,8 @@ pub const DefaultRwLock = struct {...@@ -168,8 +168,8 @@ pub const DefaultRwLock = struct {
168 const IS_WRITING: usize = 1;168 const IS_WRITING: usize = 1;
169 const WRITER: usize = 1 << 1;169 const WRITER: usize = 1 << 1;
170 const READER: usize = 1 << (1 + @bitSizeOf(Count));170 const READER: usize = 1 << (1 + @bitSizeOf(Count));
171 const WRITER_MASK: usize = std.math.maxInt(Count) << @ctz(usize, WRITER);171 const WRITER_MASK: usize = std.math.maxInt(Count) << @ctz(WRITER);
172 const READER_MASK: usize = std.math.maxInt(Count) << @ctz(usize, READER);172 const READER_MASK: usize = std.math.maxInt(Count) << @ctz(READER);
173 const Count = std.meta.Int(.unsigned, @divFloor(@bitSizeOf(usize) - 1, 2));173 const Count = std.meta.Int(.unsigned, @divFloor(@bitSizeOf(usize) - 1, 2));
174174
175 pub fn tryLock(rwl: *DefaultRwLock) bool {175 pub fn tryLock(rwl: *DefaultRwLock) bool {
lib/std/array_list.zig+63
...@@ -221,6 +221,30 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -221,6 +221,30 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
221 mem.copy(T, self.items[old_len..], items);221 mem.copy(T, self.items[old_len..], items);
222 }222 }
223223
224 /// Append an unaligned slice of items to the list. Allocates more
225 /// memory as necessary. Only call this function if calling
226 /// `appendSlice` instead would be a compile error.
227 pub fn appendUnalignedSlice(self: *Self, items: []align(1) const T) Allocator.Error!void {
228 try self.ensureUnusedCapacity(items.len);
229 self.appendUnalignedSliceAssumeCapacity(items);
230 }
231
232 /// Append the slice of items to the list, asserting the capacity is already
233 /// enough to store the new items. **Does not** invalidate pointers.
234 /// Only call this function if calling `appendSliceAssumeCapacity` instead
235 /// would be a compile error.
236 pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void {
237 const old_len = self.items.len;
238 const new_len = old_len + items.len;
239 assert(new_len <= self.capacity);
240 self.items.len = new_len;
241 @memcpy(
242 @ptrCast([*]align(@alignOf(T)) u8, self.items.ptr + old_len),
243 @ptrCast([*]const u8, items.ptr),
244 items.len * @sizeOf(T),
245 );
246 }
247
224 pub const Writer = if (T != u8)248 pub const Writer = if (T != u8)
225 @compileError("The Writer interface is only defined for ArrayList(u8) " ++249 @compileError("The Writer interface is only defined for ArrayList(u8) " ++
226 "but the given type is ArrayList(" ++ @typeName(T) ++ ")")250 "but the given type is ArrayList(" ++ @typeName(T) ++ ")")
...@@ -592,6 +616,29 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -592,6 +616,29 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
592 mem.copy(T, self.items[old_len..], items);616 mem.copy(T, self.items[old_len..], items);
593 }617 }
594618
619 /// Append the slice of items to the list. Allocates more
620 /// memory as necessary. Only call this function if a call to `appendSlice` instead would
621 /// be a compile error.
622 pub fn appendUnalignedSlice(self: *Self, allocator: Allocator, items: []align(1) const T) Allocator.Error!void {
623 try self.ensureUnusedCapacity(allocator, items.len);
624 self.appendUnalignedSliceAssumeCapacity(items);
625 }
626
627 /// Append an unaligned slice of items to the list, asserting the capacity is enough
628 /// to store the new items. Only call this function if a call to `appendSliceAssumeCapacity`
629 /// instead would be a compile error.
630 pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void {
631 const old_len = self.items.len;
632 const new_len = old_len + items.len;
633 assert(new_len <= self.capacity);
634 self.items.len = new_len;
635 @memcpy(
636 @ptrCast([*]align(@alignOf(T)) u8, self.items.ptr + old_len),
637 @ptrCast([*]const u8, items.ptr),
638 items.len * @sizeOf(T),
639 );
640 }
641
595 pub const WriterContext = struct {642 pub const WriterContext = struct {
596 self: *Self,643 self: *Self,
597 allocator: Allocator,644 allocator: Allocator,
...@@ -899,6 +946,14 @@ test "std.ArrayList/ArrayListUnmanaged.basic" {...@@ -899,6 +946,14 @@ test "std.ArrayList/ArrayListUnmanaged.basic" {
899 try testing.expect(list.pop() == 1);946 try testing.expect(list.pop() == 1);
900 try testing.expect(list.items.len == 9);947 try testing.expect(list.items.len == 9);
901948
949 var unaligned: [3]i32 align(1) = [_]i32{ 4, 5, 6 };
950 list.appendUnalignedSlice(&unaligned) catch unreachable;
951 try testing.expect(list.items.len == 12);
952 try testing.expect(list.pop() == 6);
953 try testing.expect(list.pop() == 5);
954 try testing.expect(list.pop() == 4);
955 try testing.expect(list.items.len == 9);
956
902 list.appendSlice(&[_]i32{}) catch unreachable;957 list.appendSlice(&[_]i32{}) catch unreachable;
903 try testing.expect(list.items.len == 9);958 try testing.expect(list.items.len == 9);
904959
...@@ -941,6 +996,14 @@ test "std.ArrayList/ArrayListUnmanaged.basic" {...@@ -941,6 +996,14 @@ test "std.ArrayList/ArrayListUnmanaged.basic" {
941 try testing.expect(list.pop() == 1);996 try testing.expect(list.pop() == 1);
942 try testing.expect(list.items.len == 9);997 try testing.expect(list.items.len == 9);
943998
999 var unaligned: [3]i32 align(1) = [_]i32{ 4, 5, 6 };
1000 list.appendUnalignedSlice(a, &unaligned) catch unreachable;
1001 try testing.expect(list.items.len == 12);
1002 try testing.expect(list.pop() == 6);
1003 try testing.expect(list.pop() == 5);
1004 try testing.expect(list.pop() == 4);
1005 try testing.expect(list.items.len == 9);
1006
944 list.appendSlice(a, &[_]i32{}) catch unreachable;1007 list.appendSlice(a, &[_]i32{}) catch unreachable;
945 try testing.expect(list.items.len == 9);1008 try testing.expect(list.items.len == 9);
9461009
lib/std/bit_set.zig+13-13
...@@ -91,7 +91,7 @@ pub fn IntegerBitSet(comptime size: u16) type {...@@ -91,7 +91,7 @@ pub fn IntegerBitSet(comptime size: u16) type {
9191
92 /// Returns the total number of set bits in this bit set.92 /// Returns the total number of set bits in this bit set.
93 pub fn count(self: Self) usize {93 pub fn count(self: Self) usize {
94 return @popCount(MaskInt, self.mask);94 return @popCount(self.mask);
95 }95 }
9696
97 /// Changes the value of the specified bit of the bit97 /// Changes the value of the specified bit of the bit
...@@ -179,7 +179,7 @@ pub fn IntegerBitSet(comptime size: u16) type {...@@ -179,7 +179,7 @@ pub fn IntegerBitSet(comptime size: u16) type {
179 pub fn findFirstSet(self: Self) ?usize {179 pub fn findFirstSet(self: Self) ?usize {
180 const mask = self.mask;180 const mask = self.mask;
181 if (mask == 0) return null;181 if (mask == 0) return null;
182 return @ctz(MaskInt, mask);182 return @ctz(mask);
183 }183 }
184184
185 /// Finds the index of the first set bit, and unsets it.185 /// Finds the index of the first set bit, and unsets it.
...@@ -187,7 +187,7 @@ pub fn IntegerBitSet(comptime size: u16) type {...@@ -187,7 +187,7 @@ pub fn IntegerBitSet(comptime size: u16) type {
187 pub fn toggleFirstSet(self: *Self) ?usize {187 pub fn toggleFirstSet(self: *Self) ?usize {
188 const mask = self.mask;188 const mask = self.mask;
189 if (mask == 0) return null;189 if (mask == 0) return null;
190 const index = @ctz(MaskInt, mask);190 const index = @ctz(mask);
191 self.mask = mask & (mask - 1);191 self.mask = mask & (mask - 1);
192 return index;192 return index;
193 }193 }
...@@ -222,12 +222,12 @@ pub fn IntegerBitSet(comptime size: u16) type {...@@ -222,12 +222,12 @@ pub fn IntegerBitSet(comptime size: u16) type {
222222
223 switch (direction) {223 switch (direction) {
224 .forward => {224 .forward => {
225 const next_index = @ctz(MaskInt, self.bits_remain);225 const next_index = @ctz(self.bits_remain);
226 self.bits_remain &= self.bits_remain - 1;226 self.bits_remain &= self.bits_remain - 1;
227 return next_index;227 return next_index;
228 },228 },
229 .reverse => {229 .reverse => {
230 const leading_zeroes = @clz(MaskInt, self.bits_remain);230 const leading_zeroes = @clz(self.bits_remain);
231 const top_bit = (@bitSizeOf(MaskInt) - 1) - leading_zeroes;231 const top_bit = (@bitSizeOf(MaskInt) - 1) - leading_zeroes;
232 self.bits_remain &= (@as(MaskInt, 1) << @intCast(ShiftInt, top_bit)) - 1;232 self.bits_remain &= (@as(MaskInt, 1) << @intCast(ShiftInt, top_bit)) - 1;
233 return top_bit;233 return top_bit;
...@@ -347,7 +347,7 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type {...@@ -347,7 +347,7 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type {
347 pub fn count(self: Self) usize {347 pub fn count(self: Self) usize {
348 var total: usize = 0;348 var total: usize = 0;
349 for (self.masks) |mask| {349 for (self.masks) |mask| {
350 total += @popCount(MaskInt, mask);350 total += @popCount(mask);
351 }351 }
352 return total;352 return total;
353 }353 }
...@@ -475,7 +475,7 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type {...@@ -475,7 +475,7 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type {
475 if (mask != 0) break mask;475 if (mask != 0) break mask;
476 offset += @bitSizeOf(MaskInt);476 offset += @bitSizeOf(MaskInt);
477 } else return null;477 } else return null;
478 return offset + @ctz(MaskInt, mask);478 return offset + @ctz(mask);
479 }479 }
480480
481 /// Finds the index of the first set bit, and unsets it.481 /// Finds the index of the first set bit, and unsets it.
...@@ -486,7 +486,7 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type {...@@ -486,7 +486,7 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type {
486 if (mask.* != 0) break mask;486 if (mask.* != 0) break mask;
487 offset += @bitSizeOf(MaskInt);487 offset += @bitSizeOf(MaskInt);
488 } else return null;488 } else return null;
489 const index = @ctz(MaskInt, mask.*);489 const index = @ctz(mask.*);
490 mask.* &= (mask.* - 1);490 mask.* &= (mask.* - 1);
491 return offset + index;491 return offset + index;
492 }492 }
...@@ -657,7 +657,7 @@ pub const DynamicBitSetUnmanaged = struct {...@@ -657,7 +657,7 @@ pub const DynamicBitSetUnmanaged = struct {
657 var total: usize = 0;657 var total: usize = 0;
658 for (self.masks[0..num_masks]) |mask| {658 for (self.masks[0..num_masks]) |mask| {
659 // Note: This is where we depend on padding bits being zero659 // Note: This is where we depend on padding bits being zero
660 total += @popCount(MaskInt, mask);660 total += @popCount(mask);
661 }661 }
662 return total;662 return total;
663 }663 }
...@@ -795,7 +795,7 @@ pub const DynamicBitSetUnmanaged = struct {...@@ -795,7 +795,7 @@ pub const DynamicBitSetUnmanaged = struct {
795 mask += 1;795 mask += 1;
796 offset += @bitSizeOf(MaskInt);796 offset += @bitSizeOf(MaskInt);
797 } else return null;797 } else return null;
798 return offset + @ctz(MaskInt, mask[0]);798 return offset + @ctz(mask[0]);
799 }799 }
800800
801 /// Finds the index of the first set bit, and unsets it.801 /// Finds the index of the first set bit, and unsets it.
...@@ -808,7 +808,7 @@ pub const DynamicBitSetUnmanaged = struct {...@@ -808,7 +808,7 @@ pub const DynamicBitSetUnmanaged = struct {
808 mask += 1;808 mask += 1;
809 offset += @bitSizeOf(MaskInt);809 offset += @bitSizeOf(MaskInt);
810 } else return null;810 } else return null;
811 const index = @ctz(MaskInt, mask[0]);811 const index = @ctz(mask[0]);
812 mask[0] &= (mask[0] - 1);812 mask[0] &= (mask[0] - 1);
813 return offset + index;813 return offset + index;
814 }814 }
...@@ -1067,12 +1067,12 @@ fn BitSetIterator(comptime MaskInt: type, comptime options: IteratorOptions) typ...@@ -1067,12 +1067,12 @@ fn BitSetIterator(comptime MaskInt: type, comptime options: IteratorOptions) typ
10671067
1068 switch (direction) {1068 switch (direction) {
1069 .forward => {1069 .forward => {
1070 const next_index = @ctz(MaskInt, self.bits_remain) + self.bit_offset;1070 const next_index = @ctz(self.bits_remain) + self.bit_offset;
1071 self.bits_remain &= self.bits_remain - 1;1071 self.bits_remain &= self.bits_remain - 1;
1072 return next_index;1072 return next_index;
1073 },1073 },
1074 .reverse => {1074 .reverse => {
1075 const leading_zeroes = @clz(MaskInt, self.bits_remain);1075 const leading_zeroes = @clz(self.bits_remain);
1076 const top_bit = (@bitSizeOf(MaskInt) - 1) - leading_zeroes;1076 const top_bit = (@bitSizeOf(MaskInt) - 1) - leading_zeroes;
1077 const no_top_bit_mask = (@as(MaskInt, 1) << @intCast(ShiftInt, top_bit)) - 1;1077 const no_top_bit_mask = (@as(MaskInt, 1) << @intCast(ShiftInt, top_bit)) - 1;
1078 self.bits_remain &= no_top_bit_mask;1078 self.bits_remain &= no_top_bit_mask;
lib/std/bounded_array.zig+8-8
...@@ -15,16 +15,16 @@ const testing = std.testing;...@@ -15,16 +15,16 @@ const testing = std.testing;
15/// var slice = a.slice(); // a slice of the 64-byte array15/// var slice = a.slice(); // a slice of the 64-byte array
16/// var a_clone = a; // creates a copy - the structure doesn't use any internal pointers16/// var a_clone = a; // creates a copy - the structure doesn't use any internal pointers
17/// ```17/// ```
18pub fn BoundedArray(comptime T: type, comptime capacity: usize) type {18pub fn BoundedArray(comptime T: type, comptime buffer_capacity: usize) type {
19 return struct {19 return struct {
20 const Self = @This();20 const Self = @This();
21 buffer: [capacity]T = undefined,21 buffer: [buffer_capacity]T = undefined,
22 len: usize = 0,22 len: usize = 0,
2323
24 /// Set the actual length of the slice.24 /// Set the actual length of the slice.
25 /// Returns error.Overflow if it exceeds the length of the backing array.25 /// Returns error.Overflow if it exceeds the length of the backing array.
26 pub fn init(len: usize) error{Overflow}!Self {26 pub fn init(len: usize) error{Overflow}!Self {
27 if (len > capacity) return error.Overflow;27 if (len > buffer_capacity) return error.Overflow;
28 return Self{ .len = len };28 return Self{ .len = len };
29 }29 }
3030
...@@ -41,7 +41,7 @@ pub fn BoundedArray(comptime T: type, comptime capacity: usize) type {...@@ -41,7 +41,7 @@ pub fn BoundedArray(comptime T: type, comptime capacity: usize) type {
41 /// Adjust the slice's length to `len`.41 /// Adjust the slice's length to `len`.
42 /// Does not initialize added items if any.42 /// Does not initialize added items if any.
43 pub fn resize(self: *Self, len: usize) error{Overflow}!void {43 pub fn resize(self: *Self, len: usize) error{Overflow}!void {
44 if (len > capacity) return error.Overflow;44 if (len > buffer_capacity) return error.Overflow;
45 self.len = len;45 self.len = len;
46 }46 }
4747
...@@ -69,7 +69,7 @@ pub fn BoundedArray(comptime T: type, comptime capacity: usize) type {...@@ -69,7 +69,7 @@ pub fn BoundedArray(comptime T: type, comptime capacity: usize) type {
6969
70 /// Check that the slice can hold at least `additional_count` items.70 /// Check that the slice can hold at least `additional_count` items.
71 pub fn ensureUnusedCapacity(self: Self, additional_count: usize) error{Overflow}!void {71 pub fn ensureUnusedCapacity(self: Self, additional_count: usize) error{Overflow}!void {
72 if (self.len + additional_count > capacity) {72 if (self.len + additional_count > buffer_capacity) {
73 return error.Overflow;73 return error.Overflow;
74 }74 }
75 }75 }
...@@ -83,7 +83,7 @@ pub fn BoundedArray(comptime T: type, comptime capacity: usize) type {...@@ -83,7 +83,7 @@ pub fn BoundedArray(comptime T: type, comptime capacity: usize) type {
83 /// Increase length by 1, returning pointer to the new item.83 /// Increase length by 1, returning pointer to the new item.
84 /// Asserts that there is space for the new item.84 /// Asserts that there is space for the new item.
85 pub fn addOneAssumeCapacity(self: *Self) *T {85 pub fn addOneAssumeCapacity(self: *Self) *T {
86 assert(self.len < capacity);86 assert(self.len < buffer_capacity);
87 self.len += 1;87 self.len += 1;
88 return &self.slice()[self.len - 1];88 return &self.slice()[self.len - 1];
89 }89 }
...@@ -236,7 +236,7 @@ pub fn BoundedArray(comptime T: type, comptime capacity: usize) type {...@@ -236,7 +236,7 @@ pub fn BoundedArray(comptime T: type, comptime capacity: usize) type {
236 pub fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void {236 pub fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void {
237 const old_len = self.len;237 const old_len = self.len;
238 self.len += n;238 self.len += n;
239 assert(self.len <= capacity);239 assert(self.len <= buffer_capacity);
240 mem.set(T, self.slice()[old_len..self.len], value);240 mem.set(T, self.slice()[old_len..self.len], value);
241 }241 }
242242
...@@ -275,7 +275,7 @@ test "BoundedArray" {...@@ -275,7 +275,7 @@ test "BoundedArray" {
275 try testing.expectEqualSlices(u8, &x, a.constSlice());275 try testing.expectEqualSlices(u8, &x, a.constSlice());
276276
277 var a2 = a;277 var a2 = a;
278 try testing.expectEqualSlices(u8, a.constSlice(), a.constSlice());278 try testing.expectEqualSlices(u8, a.constSlice(), a2.constSlice());
279 a2.set(0, 0);279 a2.set(0, 0);
280 try testing.expect(a.get(0) != a2.get(0));280 try testing.expect(a.get(0) != a2.get(0));
281281
lib/std/build.zig+11-4
...@@ -1495,6 +1495,7 @@ pub const LibExeObjStep = struct {...@@ -1495,6 +1495,7 @@ pub const LibExeObjStep = struct {
1495 emit_h: bool = false,1495 emit_h: bool = false,
1496 bundle_compiler_rt: ?bool = null,1496 bundle_compiler_rt: ?bool = null,
1497 single_threaded: ?bool = null,1497 single_threaded: ?bool = null,
1498 stack_protector: ?bool = null,
1498 disable_stack_probing: bool,1499 disable_stack_probing: bool,
1499 disable_sanitize_c: bool,1500 disable_sanitize_c: bool,
1500 sanitize_thread: bool,1501 sanitize_thread: bool,
...@@ -1896,13 +1897,12 @@ pub const LibExeObjStep = struct {...@@ -1896,13 +1897,12 @@ pub const LibExeObjStep = struct {
1896 /// When a binary cannot be ran through emulation or the option is disabled, a warning1897 /// When a binary cannot be ran through emulation or the option is disabled, a warning
1897 /// will be printed and the binary will *NOT* be ran.1898 /// will be printed and the binary will *NOT* be ran.
1898 pub fn runEmulatable(exe: *LibExeObjStep) *EmulatableRunStep {1899 pub fn runEmulatable(exe: *LibExeObjStep) *EmulatableRunStep {
1899 assert(exe.kind == .exe or exe.kind == .text_exe);1900 assert(exe.kind == .exe or exe.kind == .test_exe);
19001901
1901 const run_step = EmulatableRunStep.create(exe.builder.fmt("run {s}", .{exe.step.name}), exe);1902 const run_step = EmulatableRunStep.create(exe.builder, exe.builder.fmt("run {s}", .{exe.step.name}), exe);
1902 if (exe.vcpkg_bin_path) |path| {1903 if (exe.vcpkg_bin_path) |path| {
1903 run_step.addPathDir(path);1904 RunStep.addPathDirInternal(&run_step.step, exe.builder, path);
1904 }1905 }
1905
1906 return run_step;1906 return run_step;
1907 }1907 }
19081908
...@@ -2826,6 +2826,13 @@ pub const LibExeObjStep = struct {...@@ -2826,6 +2826,13 @@ pub const LibExeObjStep = struct {
2826 if (self.disable_stack_probing) {2826 if (self.disable_stack_probing) {
2827 try zig_args.append("-fno-stack-check");2827 try zig_args.append("-fno-stack-check");
2828 }2828 }
2829 if (self.stack_protector) |stack_protector| {
2830 if (stack_protector) {
2831 try zig_args.append("-fstack-protector");
2832 } else {
2833 try zig_args.append("-fno-stack-protector");
2834 }
2835 }
2829 if (self.red_zone) |red_zone| {2836 if (self.red_zone) |red_zone| {
2830 if (red_zone) {2837 if (red_zone) {
2831 try zig_args.append("-mred-zone");2838 try zig_args.append("-mred-zone");
lib/std/build/OptionsStep.zig+3
...@@ -171,6 +171,7 @@ fn printLiteral(out: anytype, val: anytype, indent: u8) !void {...@@ -171,6 +171,7 @@ fn printLiteral(out: anytype, val: anytype, indent: u8) !void {
171 .Void,171 .Void,
172 .Bool,172 .Bool,
173 .Int,173 .Int,
174 .ComptimeInt,
174 .Float,175 .Float,
175 .Null,176 .Null,
176 => try out.print("{any}", .{val}),177 => try out.print("{any}", .{val}),
...@@ -302,6 +303,7 @@ test "OptionsStep" {...@@ -302,6 +303,7 @@ test "OptionsStep" {
302 options.addOption(usize, "option1", 1);303 options.addOption(usize, "option1", 1);
303 options.addOption(?usize, "option2", null);304 options.addOption(?usize, "option2", null);
304 options.addOption(?usize, "option3", 3);305 options.addOption(?usize, "option3", 3);
306 options.addOption(comptime_int, "option4", 4);
305 options.addOption([]const u8, "string", "zigisthebest");307 options.addOption([]const u8, "string", "zigisthebest");
306 options.addOption(?[]const u8, "optional_string", null);308 options.addOption(?[]const u8, "optional_string", null);
307 options.addOption([2][2]u16, "nested_array", nested_array);309 options.addOption([2][2]u16, "nested_array", nested_array);
...@@ -314,6 +316,7 @@ test "OptionsStep" {...@@ -314,6 +316,7 @@ test "OptionsStep" {
314 \\pub const option1: usize = 1;316 \\pub const option1: usize = 1;
315 \\pub const option2: ?usize = null;317 \\pub const option2: ?usize = null;
316 \\pub const option3: ?usize = 3;318 \\pub const option3: ?usize = 3;
319 \\pub const option4: comptime_int = 4;
317 \\pub const string: []const u8 = "zigisthebest";320 \\pub const string: []const u8 = "zigisthebest";
318 \\pub const optional_string: ?[]const u8 = null;321 \\pub const optional_string: ?[]const u8 = null;
319 \\pub const nested_array: [2][2]u16 = [2][2]u16 {322 \\pub const nested_array: [2][2]u16 = [2][2]u16 {
lib/std/build/RunStep.zig+1-1
...@@ -101,7 +101,7 @@ pub fn addPathDir(self: *RunStep, search_path: []const u8) void {...@@ -101,7 +101,7 @@ pub fn addPathDir(self: *RunStep, search_path: []const u8) void {
101}101}
102102
103/// For internal use only, users of `RunStep` should use `addPathDir` directly.103/// For internal use only, users of `RunStep` should use `addPathDir` directly.
104fn addPathDirInternal(step: *Step, builder: *Builder, search_path: []const u8) void {104pub fn addPathDirInternal(step: *Step, builder: *Builder, search_path: []const u8) void {
105 const env_map = getEnvMapInternal(step, builder.allocator);105 const env_map = getEnvMapInternal(step, builder.allocator);
106106
107 const key = "PATH";107 const key = "PATH";
lib/std/build/TranslateCStep.zig+14
...@@ -21,6 +21,7 @@ output_dir: ?[]const u8,...@@ -21,6 +21,7 @@ output_dir: ?[]const u8,
21out_basename: []const u8,21out_basename: []const u8,
22target: CrossTarget = CrossTarget{},22target: CrossTarget = CrossTarget{},
23output_file: build.GeneratedFile,23output_file: build.GeneratedFile,
24use_stage1: ?bool = null,
2425
25pub fn create(builder: *Builder, source: build.FileSource) *TranslateCStep {26pub fn create(builder: *Builder, source: build.FileSource) *TranslateCStep {
26 const self = builder.allocator.create(TranslateCStep) catch unreachable;27 const self = builder.allocator.create(TranslateCStep) catch unreachable;
...@@ -91,6 +92,19 @@ fn make(step: *Step) !void {...@@ -91,6 +92,19 @@ fn make(step: *Step) !void {
91 try argv_list.append("-D");92 try argv_list.append("-D");
92 try argv_list.append(c_macro);93 try argv_list.append(c_macro);
93 }94 }
95 if (self.use_stage1) |stage1| {
96 if (stage1) {
97 try argv_list.append("-fstage1");
98 } else {
99 try argv_list.append("-fno-stage1");
100 }
101 } else if (self.builder.use_stage1) |stage1| {
102 if (stage1) {
103 try argv_list.append("-fstage1");
104 } else {
105 try argv_list.append("-fno-stage1");
106 }
107 }
94108
95 try argv_list.append(self.source.getPath(self.builder));109 try argv_list.append(self.source.getPath(self.builder));
96110
lib/std/builtin.zig+4-3
...@@ -294,6 +294,8 @@ pub const Type = union(enum) {...@@ -294,6 +294,8 @@ pub const Type = union(enum) {
294 /// therefore must be kept in sync with the compiler implementation.294 /// therefore must be kept in sync with the compiler implementation.
295 pub const Struct = struct {295 pub const Struct = struct {
296 layout: ContainerLayout,296 layout: ContainerLayout,
297 /// Only valid if layout is .Packed
298 backing_integer: ?type = null,
297 fields: []const StructField,299 fields: []const StructField,
298 decls: []const Declaration,300 decls: []const Declaration,
299 is_tuple: bool,301 is_tuple: bool,
...@@ -864,13 +866,12 @@ pub fn panicUnwrapError(st: ?*StackTrace, err: anyerror) noreturn {...@@ -864,13 +866,12 @@ pub fn panicUnwrapError(st: ?*StackTrace, err: anyerror) noreturn {
864866
865pub fn panicOutOfBounds(index: usize, len: usize) noreturn {867pub fn panicOutOfBounds(index: usize, len: usize) noreturn {
866 @setCold(true);868 @setCold(true);
867 std.debug.panic("attempt to index out of bound: index {d}, len {d}", .{ index, len });869 std.debug.panic("index out of bounds: index {d}, len {d}", .{ index, len });
868}870}
869871
870pub noinline fn returnError(maybe_st: ?*StackTrace) void {872pub noinline fn returnError(st: *StackTrace) void {
871 @setCold(true);873 @setCold(true);
872 @setRuntimeSafety(false);874 @setRuntimeSafety(false);
873 const st = maybe_st orelse return;
874 addErrRetTraceAddr(st, @returnAddress());875 addErrRetTraceAddr(st, @returnAddress());
875}876}
876877
lib/std/c.zig+6-2
...@@ -20,7 +20,7 @@ pub const Tokenizer = tokenizer.Tokenizer;...@@ -20,7 +20,7 @@ pub const Tokenizer = tokenizer.Tokenizer;
20/// If linking gnu libc (glibc), the `ok` value will be true if the target20/// If linking gnu libc (glibc), the `ok` value will be true if the target
21/// version is greater than or equal to `glibc_version`.21/// version is greater than or equal to `glibc_version`.
22/// If linking a libc other than these, returns `false`.22/// If linking a libc other than these, returns `false`.
23pub fn versionCheck(glibc_version: std.builtin.Version) type {23pub fn versionCheck(comptime glibc_version: std.builtin.Version) type {
24 return struct {24 return struct {
25 pub const ok = blk: {25 pub const ok = blk: {
26 if (!builtin.link_libc) break :blk false;26 if (!builtin.link_libc) break :blk false;
...@@ -263,7 +263,11 @@ const PThreadForkFn = if (builtin.zig_backend == .stage1)...@@ -263,7 +263,11 @@ const PThreadForkFn = if (builtin.zig_backend == .stage1)
263 fn () callconv(.C) void263 fn () callconv(.C) void
264else264else
265 *const fn () callconv(.C) void;265 *const fn () callconv(.C) void;
266pub extern "c" fn pthread_key_create(key: *c.pthread_key_t, destructor: ?fn (value: *anyopaque) callconv(.C) void) c.E;266pub extern "c" fn pthread_key_create(key: *c.pthread_key_t, destructor: ?PThreadKeyCreateFn) c.E;
267const PThreadKeyCreateFn = if (builtin.zig_backend == .stage1)
268 fn (value: *anyopaque) callconv(.C) void
269else
270 *const fn (value: *anyopaque) callconv(.C) void;
267pub extern "c" fn pthread_key_delete(key: c.pthread_key_t) c.E;271pub extern "c" fn pthread_key_delete(key: c.pthread_key_t) c.E;
268pub extern "c" fn pthread_getspecific(key: c.pthread_key_t) ?*anyopaque;272pub extern "c" fn pthread_getspecific(key: c.pthread_key_t) ?*anyopaque;
269pub extern "c" fn pthread_setspecific(key: c.pthread_key_t, value: ?*anyopaque) c_int;273pub extern "c" fn pthread_setspecific(key: c.pthread_key_t, value: ?*anyopaque) c_int;
lib/std/c/darwin.zig+4-4
...@@ -814,10 +814,10 @@ pub const sigset_t = u32;...@@ -814,10 +814,10 @@ pub const sigset_t = u32;
814pub const empty_sigset: sigset_t = 0;814pub const empty_sigset: sigset_t = 0;
815815
816pub const SIG = struct {816pub const SIG = struct {
817 pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));817 pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
818 pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0);818 pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
819 pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1);819 pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
820 pub const HOLD = @intToPtr(?Sigaction.sigaction_fn, 5);820 pub const HOLD = @intToPtr(?Sigaction.handler_fn, 5);
821821
822 /// block specified signal set822 /// block specified signal set
823 pub const _BLOCK = 1;823 pub const _BLOCK = 1;
lib/std/c/dragonfly.zig+3-3
...@@ -609,9 +609,9 @@ pub const S = struct {...@@ -609,9 +609,9 @@ pub const S = struct {
609pub const BADSIG = SIG.ERR;609pub const BADSIG = SIG.ERR;
610610
611pub const SIG = struct {611pub const SIG = struct {
612 pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0);612 pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
613 pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1);613 pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
614 pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));614 pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
615615
616 pub const BLOCK = 1;616 pub const BLOCK = 1;
617 pub const UNBLOCK = 2;617 pub const UNBLOCK = 2;
lib/std/c/freebsd.zig+3-3
...@@ -670,9 +670,9 @@ pub const SIG = struct {...@@ -670,9 +670,9 @@ pub const SIG = struct {
670 pub const UNBLOCK = 2;670 pub const UNBLOCK = 2;
671 pub const SETMASK = 3;671 pub const SETMASK = 3;
672672
673 pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0);673 pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
674 pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1);674 pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
675 pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));675 pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
676676
677 pub const WORDS = 4;677 pub const WORDS = 4;
678 pub const MAXSIG = 128;678 pub const MAXSIG = 128;
lib/std/c/haiku.zig+2-2
...@@ -702,7 +702,7 @@ pub const T = struct {...@@ -702,7 +702,7 @@ pub const T = struct {
702 pub const CSETAF = 0x8002;702 pub const CSETAF = 0x8002;
703 pub const CSETAW = 0x8003;703 pub const CSETAW = 0x8003;
704 pub const CWAITEVENT = 0x8004;704 pub const CWAITEVENT = 0x8004;
705 pub const CSBRK = 08005;705 pub const CSBRK = 0x8005;
706 pub const CFLSH = 0x8006;706 pub const CFLSH = 0x8006;
707 pub const CXONC = 0x8007;707 pub const CXONC = 0x8007;
708 pub const CQUERYCONNECTED = 0x8008;708 pub const CQUERYCONNECTED = 0x8008;
...@@ -874,7 +874,7 @@ pub const S = struct {...@@ -874,7 +874,7 @@ pub const S = struct {
874 pub const IFDIR = 0o040000;874 pub const IFDIR = 0o040000;
875 pub const IFCHR = 0o020000;875 pub const IFCHR = 0o020000;
876 pub const IFIFO = 0o010000;876 pub const IFIFO = 0o010000;
877 pub const INDEX_DIR = 04000000000;877 pub const INDEX_DIR = 0o4000000000;
878878
879 pub const IUMSK = 0o7777;879 pub const IUMSK = 0o7777;
880 pub const ISUID = 0o4000;880 pub const ISUID = 0o4000;
lib/std/c/netbsd.zig+3-3
...@@ -910,9 +910,9 @@ pub const winsize = extern struct {...@@ -910,9 +910,9 @@ pub const winsize = extern struct {
910const NSIG = 32;910const NSIG = 32;
911911
912pub const SIG = struct {912pub const SIG = struct {
913 pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0);913 pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
914 pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1);914 pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
915 pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));915 pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
916916
917 pub const WORDS = 4;917 pub const WORDS = 4;
918 pub const MAXSIG = 128;918 pub const MAXSIG = 128;
lib/std/c/openbsd.zig+6-21
...@@ -982,11 +982,11 @@ pub const winsize = extern struct {...@@ -982,11 +982,11 @@ pub const winsize = extern struct {
982const NSIG = 33;982const NSIG = 33;
983983
984pub const SIG = struct {984pub const SIG = struct {
985 pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0);985 pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
986 pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1);986 pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
987 pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));987 pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
988 pub const CATCH = @intToPtr(?Sigaction.sigaction_fn, 2);988 pub const CATCH = @intToPtr(?Sigaction.handler_fn, 2);
989 pub const HOLD = @intToPtr(?Sigaction.sigaction_fn, 3);989 pub const HOLD = @intToPtr(?Sigaction.handler_fn, 3);
990990
991 pub const HUP = 1;991 pub const HUP = 1;
992 pub const INT = 2;992 pub const INT = 2;
...@@ -1119,26 +1119,11 @@ pub usingnamespace switch (builtin.cpu.arch) {...@@ -1119,26 +1119,11 @@ pub usingnamespace switch (builtin.cpu.arch) {
1119 sc_rsp: c_long,1119 sc_rsp: c_long,
1120 sc_ss: c_long,1120 sc_ss: c_long,
11211121
1122 sc_fpstate: fxsave64,1122 sc_fpstate: *anyopaque, // struct fxsave64 *
1123 __sc_unused: c_int,1123 __sc_unused: c_int,
1124 sc_mask: c_int,1124 sc_mask: c_int,
1125 sc_cookie: c_long,1125 sc_cookie: c_long,
1126 };1126 };
1127
1128 pub const fxsave64 = packed struct {
1129 fx_fcw: u16,
1130 fx_fsw: u16,
1131 fx_ftw: u8,
1132 fx_unused1: u8,
1133 fx_fop: u16,
1134 fx_rip: u64,
1135 fx_rdp: u64,
1136 fx_mxcsr: u32,
1137 fx_mxcsr_mask: u32,
1138 fx_st: [8][2]u64,
1139 fx_xmm: [16][2]u64,
1140 fx_unused3: [96]u8,
1141 };
1142 },1127 },
1143 else => struct {},1128 else => struct {},
1144};1129};
lib/std/c/solaris.zig+4-4
...@@ -879,10 +879,10 @@ pub const winsize = extern struct {...@@ -879,10 +879,10 @@ pub const winsize = extern struct {
879const NSIG = 75;879const NSIG = 75;
880880
881pub const SIG = struct {881pub const SIG = struct {
882 pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0);882 pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
883 pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));883 pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
884 pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1);884 pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
885 pub const HOLD = @intToPtr(?Sigaction.sigaction_fn, 2);885 pub const HOLD = @intToPtr(?Sigaction.handler_fn, 2);
886886
887 pub const WORDS = 4;887 pub const WORDS = 4;
888 pub const MAXSIG = 75;888 pub const MAXSIG = 75;
lib/std/coff.zig+973-248
...@@ -1,14 +1,731 @@...@@ -1,14 +1,731 @@
1const std = @import("std.zig");1const std = @import("std.zig");
2const assert = std.debug.assert;
2const io = std.io;3const io = std.io;
3const mem = std.mem;4const mem = std.mem;
4const os = std.os;5const os = std.os;
5const File = std.fs.File;6const fs = std.fs;
67
7// CoffHeader.machine values8pub const CoffHeaderFlags = packed struct {
8// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms680313(v=vs.85).aspx9 /// Image only, Windows CE, and Microsoft Windows NT and later.
9const IMAGE_FILE_MACHINE_I386 = 0x014c;10 /// This indicates that the file does not contain base relocations
10const IMAGE_FILE_MACHINE_IA64 = 0x0200;11 /// and must therefore be loaded at its preferred base address.
11const IMAGE_FILE_MACHINE_AMD64 = 0x8664;12 /// If the base address is not available, the loader reports an error.
13 /// The default behavior of the linker is to strip base relocations
14 /// from executable (EXE) files.
15 RELOCS_STRIPPED: u1 = 0,
16
17 /// Image only. This indicates that the image file is valid and can be run.
18 /// If this flag is not set, it indicates a linker error.
19 EXECUTABLE_IMAGE: u1 = 0,
20
21 /// COFF line numbers have been removed. This flag is deprecated and should be zero.
22 LINE_NUMS_STRIPPED: u1 = 0,
23
24 /// COFF symbol table entries for local symbols have been removed.
25 /// This flag is deprecated and should be zero.
26 LOCAL_SYMS_STRIPPED: u1 = 0,
27
28 /// Obsolete. Aggressively trim working set.
29 /// This flag is deprecated for Windows 2000 and later and must be zero.
30 AGGRESSIVE_WS_TRIM: u1 = 0,
31
32 /// Application can handle > 2-GB addresses.
33 LARGE_ADDRESS_AWARE: u1 = 0,
34
35 /// This flag is reserved for future use.
36 RESERVED: u1 = 0,
37
38 /// Little endian: the least significant bit (LSB) precedes the
39 /// most significant bit (MSB) in memory. This flag is deprecated and should be zero.
40 BYTES_REVERSED_LO: u1 = 0,
41
42 /// Machine is based on a 32-bit-word architecture.
43 @"32BIT_MACHINE": u1 = 0,
44
45 /// Debugging information is removed from the image file.
46 DEBUG_STRIPPED: u1 = 0,
47
48 /// If the image is on removable media, fully load it and copy it to the swap file.
49 REMOVABLE_RUN_FROM_SWAP: u1 = 0,
50
51 /// If the image is on network media, fully load it and copy it to the swap file.
52 NET_RUN_FROM_SWAP: u1 = 0,
53
54 /// The image file is a system file, not a user program.
55 SYSTEM: u1 = 0,
56
57 /// The image file is a dynamic-link library (DLL).
58 /// Such files are considered executable files for almost all purposes,
59 /// although they cannot be directly run.
60 DLL: u1 = 0,
61
62 /// The file should be run only on a uniprocessor machine.
63 UP_SYSTEM_ONLY: u1 = 0,
64
65 /// Big endian: the MSB precedes the LSB in memory. This flag is deprecated and should be zero.
66 BYTES_REVERSED_HI: u1 = 0,
67};
68
69pub const CoffHeader = extern struct {
70 /// The number that identifies the type of target machine.
71 machine: MachineType,
72
73 /// The number of sections. This indicates the size of the section table, which immediately follows the headers.
74 number_of_sections: u16,
75
76 /// The low 32 bits of the number of seconds since 00:00 January 1, 1970 (a C run-time time_t value),
77 /// which indicates when the file was created.
78 time_date_stamp: u32,
79
80 /// The file offset of the COFF symbol table, or zero if no COFF symbol table is present.
81 /// This value should be zero for an image because COFF debugging information is deprecated.
82 pointer_to_symbol_table: u32,
83
84 /// The number of entries in the symbol table.
85 /// This data can be used to locate the string table, which immediately follows the symbol table.
86 /// This value should be zero for an image because COFF debugging information is deprecated.
87 number_of_symbols: u32,
88
89 /// The size of the optional header, which is required for executable files but not for object files.
90 /// This value should be zero for an object file. For a description of the header format, see Optional Header (Image Only).
91 size_of_optional_header: u16,
92
93 /// The flags that indicate the attributes of the file.
94 flags: CoffHeaderFlags,
95};
96
97// OptionalHeader.magic values
98// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms680339(v=vs.85).aspx
99pub const IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b;
100pub const IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b;
101
102pub const DllFlags = packed struct {
103 _reserved_0: u5 = 0,
104
105 /// Image can handle a high entropy 64-bit virtual address space.
106 HIGH_ENTROPY_VA: u1 = 0,
107
108 /// DLL can be relocated at load time.
109 DYNAMIC_BASE: u1 = 0,
110
111 /// Code Integrity checks are enforced.
112 FORCE_INTEGRITY: u1 = 0,
113
114 /// Image is NX compatible.
115 NX_COMPAT: u1 = 0,
116
117 /// Isolation aware, but do not isolate the image.
118 NO_ISOLATION: u1 = 0,
119
120 /// Does not use structured exception (SE) handling. No SE handler may be called in this image.
121 NO_SEH: u1 = 0,
122
123 /// Do not bind the image.
124 NO_BIND: u1 = 0,
125
126 /// Image must execute in an AppContainer.
127 APPCONTAINER: u1 = 0,
128
129 /// A WDM driver.
130 WDM_DRIVER: u1 = 0,
131
132 /// Image supports Control Flow Guard.
133 GUARD_CF: u1 = 0,
134
135 /// Terminal Server aware.
136 TERMINAL_SERVER_AWARE: u1 = 0,
137};
138
139pub const Subsystem = enum(u16) {
140 /// An unknown subsystem
141 UNKNOWN = 0,
142
143 /// Device drivers and native Windows processes
144 NATIVE = 1,
145
146 /// The Windows graphical user interface (GUI) subsystem
147 WINDOWS_GUI = 2,
148
149 /// The Windows character subsystem
150 WINDOWS_CUI = 3,
151
152 /// The OS/2 character subsystem
153 OS2_CUI = 5,
154
155 /// The Posix character subsystem
156 POSIX_CUI = 7,
157
158 /// Native Win9x driver
159 NATIVE_WINDOWS = 8,
160
161 /// Windows CE
162 WINDOWS_CE_GUI = 9,
163
164 /// An Extensible Firmware Interface (EFI) application
165 EFI_APPLICATION = 10,
166
167 /// An EFI driver with boot services
168 EFI_BOOT_SERVICE_DRIVER = 11,
169
170 /// An EFI driver with run-time services
171 EFI_RUNTIME_DRIVER = 12,
172
173 /// An EFI ROM image
174 EFI_ROM = 13,
175
176 /// XBOX
177 XBOX = 14,
178
179 /// Windows boot application
180 WINDOWS_BOOT_APPLICATION = 16,
181};
182
183pub const OptionalHeader = extern struct {
184 magic: u16,
185 major_linker_version: u8,
186 minor_linker_version: u8,
187 size_of_code: u32,
188 size_of_initialized_data: u32,
189 size_of_uninitialized_data: u32,
190 address_of_entry_point: u32,
191 base_of_code: u32,
192};
193
194pub const OptionalHeaderPE32 = extern struct {
195 magic: u16,
196 major_linker_version: u8,
197 minor_linker_version: u8,
198 size_of_code: u32,
199 size_of_initialized_data: u32,
200 size_of_uninitialized_data: u32,
201 address_of_entry_point: u32,
202 base_of_code: u32,
203 base_of_data: u32,
204 image_base: u32,
205 section_alignment: u32,
206 file_alignment: u32,
207 major_operating_system_version: u16,
208 minor_operating_system_version: u16,
209 major_image_version: u16,
210 minor_image_version: u16,
211 major_subsystem_version: u16,
212 minor_subsystem_version: u16,
213 win32_version_value: u32,
214 size_of_image: u32,
215 size_of_headers: u32,
216 checksum: u32,
217 subsystem: Subsystem,
218 dll_flags: DllFlags,
219 size_of_stack_reserve: u32,
220 size_of_stack_commit: u32,
221 size_of_heap_reserve: u32,
222 size_of_heap_commit: u32,
223 loader_flags: u32,
224 number_of_rva_and_sizes: u32,
225};
226
227pub const OptionalHeaderPE64 = extern struct {
228 magic: u16,
229 major_linker_version: u8,
230 minor_linker_version: u8,
231 size_of_code: u32,
232 size_of_initialized_data: u32,
233 size_of_uninitialized_data: u32,
234 address_of_entry_point: u32,
235 base_of_code: u32,
236 image_base: u64,
237 section_alignment: u32,
238 file_alignment: u32,
239 major_operating_system_version: u16,
240 minor_operating_system_version: u16,
241 major_image_version: u16,
242 minor_image_version: u16,
243 major_subsystem_version: u16,
244 minor_subsystem_version: u16,
245 win32_version_value: u32,
246 size_of_image: u32,
247 size_of_headers: u32,
248 checksum: u32,
249 subsystem: Subsystem,
250 dll_flags: DllFlags,
251 size_of_stack_reserve: u64,
252 size_of_stack_commit: u64,
253 size_of_heap_reserve: u64,
254 size_of_heap_commit: u64,
255 loader_flags: u32,
256 number_of_rva_and_sizes: u32,
257};
258
259pub const DebugDirectoryEntry = extern struct {
260 characteristiccs: u32,
261 time_date_stamp: u32,
262 major_version: u16,
263 minor_version: u16,
264 @"type": u32,
265 size_of_data: u32,
266 address_of_raw_data: u32,
267 pointer_to_raw_data: u32,
268};
269
270pub const ImageDataDirectory = extern struct {
271 virtual_address: u32,
272 size: u32,
273};
274
275pub const SectionHeader = extern struct {
276 name: [8]u8,
277 virtual_size: u32,
278 virtual_address: u32,
279 size_of_raw_data: u32,
280 pointer_to_raw_data: u32,
281 pointer_to_relocations: u32,
282 pointer_to_linenumbers: u32,
283 number_of_relocations: u16,
284 number_of_linenumbers: u16,
285 flags: SectionHeaderFlags,
286
287 pub fn getName(self: *align(1) const SectionHeader) ?[]const u8 {
288 if (self.name[0] == '/') return null;
289 const len = std.mem.indexOfScalar(u8, &self.name, @as(u8, 0)) orelse self.name.len;
290 return self.name[0..len];
291 }
292
293 pub fn getNameOffset(self: SectionHeader) ?u32 {
294 if (self.name[0] != '/') return null;
295 const len = std.mem.indexOfScalar(u8, &self.name, @as(u8, 0)) orelse self.name.len;
296 const offset = std.fmt.parseInt(u32, self.name[1..len], 10) catch unreachable;
297 return offset;
298 }
299
300 /// Applicable only to section headers in COFF objects.
301 pub fn getAlignment(self: SectionHeader) ?u16 {
302 if (self.flags.ALIGN == 0) return null;
303 return std.math.powi(u16, 2, self.flags.ALIGN - 1) catch unreachable;
304 }
305
306 pub fn isComdat(self: SectionHeader) bool {
307 return self.flags.LNK_COMDAT == 0b1;
308 }
309};
310
311pub const SectionHeaderFlags = packed struct {
312 _reserved_0: u3 = 0,
313
314 /// The section should not be padded to the next boundary.
315 /// This flag is obsolete and is replaced by IMAGE_SCN_ALIGN_1BYTES.
316 /// This is valid only for object files.
317 TYPE_NO_PAD: u1 = 0,
318
319 _reserved_1: u1 = 0,
320
321 /// The section contains executable code.
322 CNT_CODE: u1 = 0,
323
324 /// The section contains initialized data.
325 CNT_INITIALIZED_DATA: u1 = 0,
326
327 /// The section contains uninitialized data.
328 CNT_UNINITIALIZED_DATA: u1 = 0,
329
330 /// Reserved for future use.
331 LNK_OTHER: u1 = 0,
332
333 /// The section contains comments or other information.
334 /// The .drectve section has this type.
335 /// This is valid for object files only.
336 LNK_INFO: u1 = 0,
337
338 _reserverd_2: u1 = 0,
339
340 /// The section will not become part of the image.
341 /// This is valid only for object files.
342 LNK_REMOVE: u1 = 0,
343
344 /// The section contains COMDAT data.
345 /// For more information, see COMDAT Sections (Object Only).
346 /// This is valid only for object files.
347 LNK_COMDAT: u1 = 0,
348
349 _reserved_3: u2 = 0,
350
351 /// The section contains data referenced through the global pointer (GP).
352 GPREL: u1 = 0,
353
354 /// Reserved for future use.
355 MEM_PURGEABLE: u1 = 0,
356
357 /// Reserved for future use.
358 MEM_16BIT: u1 = 0,
359
360 /// Reserved for future use.
361 MEM_LOCKED: u1 = 0,
362
363 /// Reserved for future use.
364 MEM_PRELOAD: u1 = 0,
365
366 /// Takes on multiple values according to flags:
367 /// pub const IMAGE_SCN_ALIGN_1BYTES: u32 = 0x100000;
368 /// pub const IMAGE_SCN_ALIGN_2BYTES: u32 = 0x200000;
369 /// pub const IMAGE_SCN_ALIGN_4BYTES: u32 = 0x300000;
370 /// pub const IMAGE_SCN_ALIGN_8BYTES: u32 = 0x400000;
371 /// pub const IMAGE_SCN_ALIGN_16BYTES: u32 = 0x500000;
372 /// pub const IMAGE_SCN_ALIGN_32BYTES: u32 = 0x600000;
373 /// pub const IMAGE_SCN_ALIGN_64BYTES: u32 = 0x700000;
374 /// pub const IMAGE_SCN_ALIGN_128BYTES: u32 = 0x800000;
375 /// pub const IMAGE_SCN_ALIGN_256BYTES: u32 = 0x900000;
376 /// pub const IMAGE_SCN_ALIGN_512BYTES: u32 = 0xA00000;
377 /// pub const IMAGE_SCN_ALIGN_1024BYTES: u32 = 0xB00000;
378 /// pub const IMAGE_SCN_ALIGN_2048BYTES: u32 = 0xC00000;
379 /// pub const IMAGE_SCN_ALIGN_4096BYTES: u32 = 0xD00000;
380 /// pub const IMAGE_SCN_ALIGN_8192BYTES: u32 = 0xE00000;
381 ALIGN: u4 = 0,
382
383 /// The section contains extended relocations.
384 LNK_NRELOC_OVFL: u1 = 0,
385
386 /// The section can be discarded as needed.
387 MEM_DISCARDABLE: u1 = 0,
388
389 /// The section cannot be cached.
390 MEM_NOT_CACHED: u1 = 0,
391
392 /// The section is not pageable.
393 MEM_NOT_PAGED: u1 = 0,
394
395 /// The section can be shared in memory.
396 MEM_SHARED: u1 = 0,
397
398 /// The section can be executed as code.
399 MEM_EXECUTE: u1 = 0,
400
401 /// The section can be read.
402 MEM_READ: u1 = 0,
403
404 /// The section can be written to.
405 MEM_WRITE: u1 = 0,
406};
407
408pub const Symbol = struct {
409 name: [8]u8,
410 value: u32,
411 section_number: SectionNumber,
412 @"type": SymType,
413 storage_class: StorageClass,
414 number_of_aux_symbols: u8,
415
416 pub fn sizeOf() usize {
417 return 18;
418 }
419
420 pub fn getName(self: *const Symbol) ?[]const u8 {
421 if (std.mem.eql(u8, self.name[0..4], "\x00\x00\x00\x00")) return null;
422 const len = std.mem.indexOfScalar(u8, &self.name, @as(u8, 0)) orelse self.name.len;
423 return self.name[0..len];
424 }
425
426 pub fn getNameOffset(self: Symbol) ?u32 {
427 if (!std.mem.eql(u8, self.name[0..4], "\x00\x00\x00\x00")) return null;
428 const offset = std.mem.readIntLittle(u32, self.name[4..8]);
429 return offset;
430 }
431};
432
433pub const SectionNumber = enum(u16) {
434 /// The symbol record is not yet assigned a section.
435 /// A value of zero indicates that a reference to an external symbol is defined elsewhere.
436 /// A value of non-zero is a common symbol with a size that is specified by the value.
437 UNDEFINED = 0,
438
439 /// The symbol has an absolute (non-relocatable) value and is not an address.
440 ABSOLUTE = 0xffff,
441
442 /// The symbol provides general type or debugging information but does not correspond to a section.
443 /// Microsoft tools use this setting along with .file records (storage class FILE).
444 DEBUG = 0xfffe,
445 _,
446};
447
448pub const SymType = packed struct {
449 complex_type: ComplexType,
450 base_type: BaseType,
451};
452
453pub const BaseType = enum(u8) {
454 /// No type information or unknown base type. Microsoft tools use this setting
455 NULL = 0,
456
457 /// No valid type; used with void pointers and functions
458 VOID = 1,
459
460 /// A character (signed byte)
461 CHAR = 2,
462
463 /// A 2-byte signed integer
464 SHORT = 3,
465
466 /// A natural integer type (normally 4 bytes in Windows)
467 INT = 4,
468
469 /// A 4-byte signed integer
470 LONG = 5,
471
472 /// A 4-byte floating-point number
473 FLOAT = 6,
474
475 /// An 8-byte floating-point number
476 DOUBLE = 7,
477
478 /// A structure
479 STRUCT = 8,
480
481 /// A union
482 UNION = 9,
483
484 /// An enumerated type
485 ENUM = 10,
486
487 /// A member of enumeration (a specified value)
488 MOE = 11,
489
490 /// A byte; unsigned 1-byte integer
491 BYTE = 12,
492
493 /// A word; unsigned 2-byte integer
494 WORD = 13,
495
496 /// An unsigned integer of natural size (normally, 4 bytes)
497 UINT = 14,
498
499 /// An unsigned 4-byte integer
500 DWORD = 15,
501};
502
503pub const ComplexType = enum(u8) {
504 /// No derived type; the symbol is a simple scalar variable.
505 NULL = 0,
506
507 /// The symbol is a pointer to base type.
508 POINTER = 16,
509
510 /// The symbol is a function that returns a base type.
511 FUNCTION = 32,
512
513 /// The symbol is an array of base type.
514 ARRAY = 48,
515};
516
517pub const StorageClass = enum(u8) {
518 /// A special symbol that represents the end of function, for debugging purposes.
519 END_OF_FUNCTION = 0xff,
520
521 /// No assigned storage class.
522 NULL = 0,
523
524 /// The automatic (stack) variable. The Value field specifies the stack frame offset.
525 AUTOMATIC = 1,
526
527 /// A value that Microsoft tools use for external symbols.
528 /// The Value field indicates the size if the section number is IMAGE_SYM_UNDEFINED (0).
529 /// If the section number is not zero, then the Value field specifies the offset within the section.
530 EXTERNAL = 2,
531
532 /// The offset of the symbol within the section.
533 /// If the Value field is zero, then the symbol represents a section name.
534 STATIC = 3,
535
536 /// A register variable.
537 /// The Value field specifies the register number.
538 REGISTER = 4,
539
540 /// A symbol that is defined externally.
541 EXTERNAL_DEF = 5,
542
543 /// A code label that is defined within the module.
544 /// The Value field specifies the offset of the symbol within the section.
545 LABEL = 6,
546
547 /// A reference to a code label that is not defined.
548 UNDEFINED_LABEL = 7,
549
550 /// The structure member. The Value field specifies the n th member.
551 MEMBER_OF_STRUCT = 8,
552
553 /// A formal argument (parameter) of a function. The Value field specifies the n th argument.
554 ARGUMENT = 9,
555
556 /// The structure tag-name entry.
557 STRUCT_TAG = 10,
558
559 /// A union member. The Value field specifies the n th member.
560 MEMBER_OF_UNION = 11,
561
562 /// The Union tag-name entry.
563 UNION_TAG = 12,
564
565 /// A Typedef entry.
566 TYPE_DEFINITION = 13,
567
568 /// A static data declaration.
569 UNDEFINED_STATIC = 14,
570
571 /// An enumerated type tagname entry.
572 ENUM_TAG = 15,
573
574 /// A member of an enumeration. The Value field specifies the n th member.
575 MEMBER_OF_ENUM = 16,
576
577 /// A register parameter.
578 REGISTER_PARAM = 17,
579
580 /// A bit-field reference. The Value field specifies the n th bit in the bit field.
581 BIT_FIELD = 18,
582
583 /// A .bb (beginning of block) or .eb (end of block) record.
584 /// The Value field is the relocatable address of the code location.
585 BLOCK = 100,
586
587 /// A value that Microsoft tools use for symbol records that define the extent of a function: begin function (.bf ), end function ( .ef ), and lines in function ( .lf ).
588 /// For .lf records, the Value field gives the number of source lines in the function.
589 /// For .ef records, the Value field gives the size of the function code.
590 FUNCTION = 101,
591
592 /// An end-of-structure entry.
593 END_OF_STRUCT = 102,
594
595 /// A value that Microsoft tools, as well as traditional COFF format, use for the source-file symbol record.
596 /// The symbol is followed by auxiliary records that name the file.
597 FILE = 103,
598
599 /// A definition of a section (Microsoft tools use STATIC storage class instead).
600 SECTION = 104,
601
602 /// A weak external. For more information, see Auxiliary Format 3: Weak Externals.
603 WEAK_EXTERNAL = 105,
604
605 /// A CLR token symbol. The name is an ASCII string that consists of the hexadecimal value of the token.
606 /// For more information, see CLR Token Definition (Object Only).
607 CLR_TOKEN = 107,
608};
609
610pub const FunctionDefinition = struct {
611 /// The symbol-table index of the corresponding .bf (begin function) symbol record.
612 tag_index: u32,
613
614 /// The size of the executable code for the function itself.
615 /// If the function is in its own section, the SizeOfRawData in the section header is greater or equal to this field,
616 /// depending on alignment considerations.
617 total_size: u32,
618
619 /// The file offset of the first COFF line-number entry for the function, or zero if none exists.
620 pointer_to_linenumber: u32,
621
622 /// The symbol-table index of the record for the next function.
623 /// If the function is the last in the symbol table, this field is set to zero.
624 pointer_to_next_function: u32,
625
626 unused: [2]u8,
627};
628
629pub const SectionDefinition = struct {
630 /// The size of section data; the same as SizeOfRawData in the section header.
631 length: u32,
632
633 /// The number of relocation entries for the section.
634 number_of_relocations: u16,
635
636 /// The number of line-number entries for the section.
637 number_of_linenumbers: u16,
638
639 /// The checksum for communal data. It is applicable if the IMAGE_SCN_LNK_COMDAT flag is set in the section header.
640 checksum: u32,
641
642 /// One-based index into the section table for the associated section. This is used when the COMDAT selection setting is 5.
643 number: u16,
644
645 /// The COMDAT selection number. This is applicable if the section is a COMDAT section.
646 selection: ComdatSelection,
647
648 unused: [3]u8,
649};
650
651pub const FileDefinition = struct {
652 /// An ANSI string that gives the name of the source file.
653 /// This is padded with nulls if it is less than the maximum length.
654 file_name: [18]u8,
655
656 pub fn getFileName(self: *const FileDefinition) []const u8 {
657 const len = std.mem.indexOfScalar(u8, &self.file_name, @as(u8, 0)) orelse self.file_name.len;
658 return self.file_name[0..len];
659 }
660};
661
662pub const WeakExternalDefinition = struct {
663 /// The symbol-table index of sym2, the symbol to be linked if sym1 is not found.
664 tag_index: u32,
665
666 /// A value of IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY indicates that no library search for sym1 should be performed.
667 /// A value of IMAGE_WEAK_EXTERN_SEARCH_LIBRARY indicates that a library search for sym1 should be performed.
668 /// A value of IMAGE_WEAK_EXTERN_SEARCH_ALIAS indicates that sym1 is an alias for sym2.
669 flag: WeakExternalFlag,
670
671 unused: [10]u8,
672};
673
674// https://github.com/tpn/winsdk-10/blob/master/Include/10.0.16299.0/km/ntimage.h
675pub const WeakExternalFlag = enum(u32) {
676 SEARCH_NOLIBRARY = 1,
677 SEARCH_LIBRARY = 2,
678 SEARCH_ALIAS = 3,
679 ANTI_DEPENDENCY = 4,
680};
681
682pub const ComdatSelection = enum(u8) {
683 /// Not a COMDAT section.
684 NONE = 0,
685
686 /// If this symbol is already defined, the linker issues a "multiply defined symbol" error.
687 NODUPLICATES = 1,
688
689 /// Any section that defines the same COMDAT symbol can be linked; the rest are removed.
690 ANY = 2,
691
692 /// The linker chooses an arbitrary section among the definitions for this symbol.
693 /// If all definitions are not the same size, a "multiply defined symbol" error is issued.
694 SAME_SIZE = 3,
695
696 /// The linker chooses an arbitrary section among the definitions for this symbol.
697 /// If all definitions do not match exactly, a "multiply defined symbol" error is issued.
698 EXACT_MATCH = 4,
699
700 /// The section is linked if a certain other COMDAT section is linked.
701 /// This other section is indicated by the Number field of the auxiliary symbol record for the section definition.
702 /// This setting is useful for definitions that have components in multiple sections
703 /// (for example, code in one and data in another), but where all must be linked or discarded as a set.
704 /// The other section this section is associated with must be a COMDAT section, which can be another
705 /// associative COMDAT section. An associative COMDAT section's section association chain can't form a loop.
706 /// The section association chain must eventually come to a COMDAT section that doesn't have IMAGE_COMDAT_SELECT_ASSOCIATIVE set.
707 ASSOCIATIVE = 5,
708
709 /// The linker chooses the largest definition from among all of the definitions for this symbol.
710 /// If multiple definitions have this size, the choice between them is arbitrary.
711 LARGEST = 6,
712};
713
714pub const DebugInfoDefinition = struct {
715 unused_1: [4]u8,
716
717 /// The actual ordinal line number (1, 2, 3, and so on) within the source file, corresponding to the .bf or .ef record.
718 linenumber: u16,
719
720 unused_2: [6]u8,
721
722 /// The symbol-table index of the next .bf symbol record.
723 /// If the function is the last in the symbol table, this field is set to zero.
724 /// It is not used for .ef records.
725 pointer_to_next_function: u32,
726
727 unused_3: [2]u8,
728};
12729
13pub const MachineType = enum(u16) {730pub const MachineType = enum(u16) {
14 Unknown = 0x0,731 Unknown = 0x0,
...@@ -77,25 +794,6 @@ pub const MachineType = enum(u16) {...@@ -77,25 +794,6 @@ pub const MachineType = enum(u16) {
77 }794 }
78};795};
79796
80// OptionalHeader.magic values
81// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms680339(v=vs.85).aspx
82const IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b;
83const IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b;
84
85// Image Characteristics
86pub const IMAGE_FILE_RELOCS_STRIPPED = 0x1;
87pub const IMAGE_FILE_DEBUG_STRIPPED = 0x200;
88pub const IMAGE_FILE_EXECUTABLE_IMAGE = 0x2;
89pub const IMAGE_FILE_32BIT_MACHINE = 0x100;
90pub const IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x20;
91
92// Section flags
93pub const IMAGE_SCN_CNT_INITIALIZED_DATA = 0x40;
94pub const IMAGE_SCN_MEM_READ = 0x40000000;
95pub const IMAGE_SCN_CNT_CODE = 0x20;
96pub const IMAGE_SCN_MEM_EXECUTE = 0x20000000;
97pub const IMAGE_SCN_MEM_WRITE = 0x80000000;
98
99const IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;797const IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;
100const IMAGE_DEBUG_TYPE_CODEVIEW = 2;798const IMAGE_DEBUG_TYPE_CODEVIEW = 2;
101const DEBUG_DIRECTORY = 6;799const DEBUG_DIRECTORY = 6;
...@@ -104,166 +802,87 @@ pub const CoffError = error{...@@ -104,166 +802,87 @@ pub const CoffError = error{
104 InvalidPEMagic,802 InvalidPEMagic,
105 InvalidPEHeader,803 InvalidPEHeader,
106 InvalidMachine,804 InvalidMachine,
805 MissingPEHeader,
107 MissingCoffSection,806 MissingCoffSection,
108 MissingStringTable,807 MissingStringTable,
109};808};
110809
111// Official documentation of the format: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format810// Official documentation of the format: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
112pub const Coff = struct {811pub const Coff = struct {
113 in_file: File,
114 allocator: mem.Allocator,812 allocator: mem.Allocator,
813 data: []const u8 = undefined,
814 is_image: bool = false,
815 coff_header_offset: usize = 0,
115816
116 coff_header: CoffHeader,817 guid: [16]u8 = undefined,
117 pe_header: OptionalHeader,818 age: u32 = undefined,
118 sections: std.ArrayListUnmanaged(Section) = .{},
119
120 guid: [16]u8,
121 age: u32,
122
123 pub fn init(allocator: mem.Allocator, in_file: File) Coff {
124 return Coff{
125 .in_file = in_file,
126 .allocator = allocator,
127 .coff_header = undefined,
128 .pe_header = undefined,
129 .guid = undefined,
130 .age = undefined,
131 };
132 }
133819
134 pub fn deinit(self: *Coff) void {820 pub fn deinit(self: *Coff) void {
135 self.sections.deinit(self.allocator);821 self.allocator.free(self.data);
136 }822 }
137823
138 pub fn loadHeader(self: *Coff) !void {824 /// Takes ownership of `data`.
139 const pe_pointer_offset = 0x3C;825 pub fn parse(self: *Coff, data: []const u8) !void {
140826 self.data = data;
141 const in = self.in_file.reader();
142
143 var magic: [2]u8 = undefined;
144 try in.readNoEof(magic[0..]);
145 if (!mem.eql(u8, &magic, "MZ"))
146 return error.InvalidPEMagic;
147
148 // Seek to PE File Header (coff header)
149 try self.in_file.seekTo(pe_pointer_offset);
150 const pe_magic_offset = try in.readIntLittle(u32);
151 try self.in_file.seekTo(pe_magic_offset);
152
153 var pe_header_magic: [4]u8 = undefined;
154 try in.readNoEof(pe_header_magic[0..]);
155 if (!mem.eql(u8, &pe_header_magic, &[_]u8{ 'P', 'E', 0, 0 }))
156 return error.InvalidPEHeader;
157
158 self.coff_header = CoffHeader{
159 .machine = try in.readIntLittle(u16),
160 .number_of_sections = try in.readIntLittle(u16),
161 .timedate_stamp = try in.readIntLittle(u32),
162 .pointer_to_symbol_table = try in.readIntLittle(u32),
163 .number_of_symbols = try in.readIntLittle(u32),
164 .size_of_optional_header = try in.readIntLittle(u16),
165 .characteristics = try in.readIntLittle(u16),
166 };
167827
168 switch (self.coff_header.machine) {828 const pe_pointer_offset = 0x3C;
169 IMAGE_FILE_MACHINE_I386, IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_IA64 => {},829 const pe_magic = "PE\x00\x00";
170 else => return error.InvalidMachine,
171 }
172830
173 try self.loadOptionalHeader();831 var stream = std.io.fixedBufferStream(self.data);
174 }832 const reader = stream.reader();
833 try stream.seekTo(pe_pointer_offset);
834 const coff_header_offset = try reader.readByte();
835 try stream.seekTo(coff_header_offset);
836 var buf: [4]u8 = undefined;
837 try reader.readNoEof(&buf);
838 self.is_image = mem.eql(u8, pe_magic, &buf);
175839
176 fn readStringFromTable(self: *Coff, offset: usize, buf: []u8) ![]const u8 {840 // Do some basic validation upfront
177 if (self.coff_header.pointer_to_symbol_table == 0) {841 if (self.is_image) {
178 // No symbol table therefore no string table842 self.coff_header_offset = coff_header_offset + 4;
179 return error.MissingStringTable;843 const coff_header = self.getCoffHeader();
180 }844 if (coff_header.size_of_optional_header == 0) return error.MissingPEHeader;
181 // The string table is at the end of the symbol table and symbols are 18 bytes long
182 const string_table_offset = self.coff_header.pointer_to_symbol_table + (self.coff_header.number_of_symbols * 18) + offset;
183 const in = self.in_file.reader();
184 const old_pos = try self.in_file.getPos();
185
186 try self.in_file.seekTo(string_table_offset);
187 defer {
188 self.in_file.seekTo(old_pos) catch unreachable;
189 }845 }
190846
191 const str = try in.readUntilDelimiterOrEof(buf, 0);847 // JK: we used to check for architecture here and throw an error if not x86 or derivative.
192 return str orelse "";848 // However I am willing to take a leap of faith and let aarch64 have a shot also.
193 }
194
195 fn loadOptionalHeader(self: *Coff) !void {
196 const in = self.in_file.reader();
197 const opt_header_pos = try self.in_file.getPos();
198
199 self.pe_header.magic = try in.readIntLittle(u16);
200 try self.in_file.seekTo(opt_header_pos + 16);
201 self.pe_header.entry_addr = try in.readIntLittle(u32);
202 try self.in_file.seekTo(opt_header_pos + 20);
203 self.pe_header.code_base = try in.readIntLittle(u32);
204
205 // The header structure is different for 32 or 64 bit
206 var num_rva_pos: u64 = undefined;
207 if (self.pe_header.magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
208 num_rva_pos = opt_header_pos + 92;
209
210 try self.in_file.seekTo(opt_header_pos + 28);
211 const image_base32 = try in.readIntLittle(u32);
212 self.pe_header.image_base = image_base32;
213 } else if (self.pe_header.magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
214 num_rva_pos = opt_header_pos + 108;
215
216 try self.in_file.seekTo(opt_header_pos + 24);
217 self.pe_header.image_base = try in.readIntLittle(u64);
218 } else return error.InvalidPEMagic;
219
220 try self.in_file.seekTo(num_rva_pos);
221
222 const number_of_rva_and_sizes = try in.readIntLittle(u32);
223 if (number_of_rva_and_sizes != IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
224 return error.InvalidPEHeader;
225
226 for (self.pe_header.data_directory) |*data_dir| {
227 data_dir.* = OptionalHeader.DataDirectory{
228 .virtual_address = try in.readIntLittle(u32),
229 .size = try in.readIntLittle(u32),
230 };
231 }
232 }849 }
233850
234 pub fn getPdbPath(self: *Coff, buffer: []u8) !usize {851 pub fn getPdbPath(self: *Coff, buffer: []u8) !usize {
235 try self.loadSections();852 assert(self.is_image);
236853
237 const header = blk: {854 const header = blk: {
238 if (self.getSection(".buildid")) |section| {855 if (self.getSectionByName(".buildid")) |hdr| {
239 break :blk section.header;856 break :blk hdr;
240 } else if (self.getSection(".rdata")) |section| {857 } else if (self.getSectionByName(".rdata")) |hdr| {
241 break :blk section.header;858 break :blk hdr;
242 } else {859 } else {
243 return error.MissingCoffSection;860 return error.MissingCoffSection;
244 }861 }
245 };862 };
246863
247 const debug_dir = &self.pe_header.data_directory[DEBUG_DIRECTORY];864 const data_dirs = self.getDataDirectories();
865 const debug_dir = data_dirs[DEBUG_DIRECTORY];
248 const file_offset = debug_dir.virtual_address - header.virtual_address + header.pointer_to_raw_data;866 const file_offset = debug_dir.virtual_address - header.virtual_address + header.pointer_to_raw_data;
249867
250 const in = self.in_file.reader();868 var stream = std.io.fixedBufferStream(self.data);
251 try self.in_file.seekTo(file_offset);869 const reader = stream.reader();
870 try stream.seekTo(file_offset);
252871
253 // Find the correct DebugDirectoryEntry, and where its data is stored.872 // Find the correct DebugDirectoryEntry, and where its data is stored.
254 // It can be in any section.873 // It can be in any section.
255 const debug_dir_entry_count = debug_dir.size / @sizeOf(DebugDirectoryEntry);874 const debug_dir_entry_count = debug_dir.size / @sizeOf(DebugDirectoryEntry);
256 var i: u32 = 0;875 var i: u32 = 0;
257 blk: while (i < debug_dir_entry_count) : (i += 1) {876 blk: while (i < debug_dir_entry_count) : (i += 1) {
258 const debug_dir_entry = try in.readStruct(DebugDirectoryEntry);877 const debug_dir_entry = try reader.readStruct(DebugDirectoryEntry);
259 if (debug_dir_entry.type == IMAGE_DEBUG_TYPE_CODEVIEW) {878 if (debug_dir_entry.type == IMAGE_DEBUG_TYPE_CODEVIEW) {
260 for (self.sections.items) |*section| {879 for (self.getSectionHeaders()) |*section| {
261 const section_start = section.header.virtual_address;880 const section_start = section.virtual_address;
262 const section_size = section.header.misc.virtual_size;881 const section_size = section.virtual_size;
263 const rva = debug_dir_entry.address_of_raw_data;882 const rva = debug_dir_entry.address_of_raw_data;
264 const offset = rva - section_start;883 const offset = rva - section_start;
265 if (section_start <= rva and offset < section_size and debug_dir_entry.size_of_data <= section_size - offset) {884 if (section_start <= rva and offset < section_size and debug_dir_entry.size_of_data <= section_size - offset) {
266 try self.in_file.seekTo(section.header.pointer_to_raw_data + offset);885 try stream.seekTo(section.pointer_to_raw_data + offset);
267 break :blk;886 break :blk;
268 }887 }
269 }888 }
...@@ -271,19 +890,19 @@ pub const Coff = struct {...@@ -271,19 +890,19 @@ pub const Coff = struct {
271 }890 }
272891
273 var cv_signature: [4]u8 = undefined; // CodeView signature892 var cv_signature: [4]u8 = undefined; // CodeView signature
274 try in.readNoEof(cv_signature[0..]);893 try reader.readNoEof(cv_signature[0..]);
275 // 'RSDS' indicates PDB70 format, used by lld.894 // 'RSDS' indicates PDB70 format, used by lld.
276 if (!mem.eql(u8, &cv_signature, "RSDS"))895 if (!mem.eql(u8, &cv_signature, "RSDS"))
277 return error.InvalidPEMagic;896 return error.InvalidPEMagic;
278 try in.readNoEof(self.guid[0..]);897 try reader.readNoEof(self.guid[0..]);
279 self.age = try in.readIntLittle(u32);898 self.age = try reader.readIntLittle(u32);
280899
281 // Finally read the null-terminated string.900 // Finally read the null-terminated string.
282 var byte = try in.readByte();901 var byte = try reader.readByte();
283 i = 0;902 i = 0;
284 while (byte != 0 and i < buffer.len) : (i += 1) {903 while (byte != 0 and i < buffer.len) : (i += 1) {
285 buffer[i] = byte;904 buffer[i] = byte;
286 byte = try in.readByte();905 byte = try reader.readByte();
287 }906 }
288907
289 if (byte != 0 and i == buffer.len)908 if (byte != 0 and i == buffer.len)
...@@ -292,126 +911,232 @@ pub const Coff = struct {...@@ -292,126 +911,232 @@ pub const Coff = struct {
292 return @as(usize, i);911 return @as(usize, i);
293 }912 }
294913
295 pub fn loadSections(self: *Coff) !void {914 pub fn getCoffHeader(self: Coff) CoffHeader {
296 if (self.sections.items.len == self.coff_header.number_of_sections)915 return @ptrCast(*align(1) const CoffHeader, self.data[self.coff_header_offset..][0..@sizeOf(CoffHeader)]).*;
297 return;916 }
298917
299 try self.sections.ensureTotalCapacityPrecise(self.allocator, self.coff_header.number_of_sections);918 pub fn getOptionalHeader(self: Coff) OptionalHeader {
919 assert(self.is_image);
920 const offset = self.coff_header_offset + @sizeOf(CoffHeader);
921 return @ptrCast(*align(1) const OptionalHeader, self.data[offset..][0..@sizeOf(OptionalHeader)]).*;
922 }
300923
301 const in = self.in_file.reader();924 pub fn getOptionalHeader32(self: Coff) OptionalHeaderPE32 {
925 assert(self.is_image);
926 const offset = self.coff_header_offset + @sizeOf(CoffHeader);
927 return @ptrCast(*align(1) const OptionalHeaderPE32, self.data[offset..][0..@sizeOf(OptionalHeaderPE32)]).*;
928 }
302929
303 var name: [32]u8 = undefined;930 pub fn getOptionalHeader64(self: Coff) OptionalHeaderPE64 {
931 assert(self.is_image);
932 const offset = self.coff_header_offset + @sizeOf(CoffHeader);
933 return @ptrCast(*align(1) const OptionalHeaderPE64, self.data[offset..][0..@sizeOf(OptionalHeaderPE64)]).*;
934 }
304935
305 var i: u16 = 0;936 pub fn getImageBase(self: Coff) u64 {
306 while (i < self.coff_header.number_of_sections) : (i += 1) {937 const hdr = self.getOptionalHeader();
307 try in.readNoEof(name[0..8]);938 return switch (hdr.magic) {
939 IMAGE_NT_OPTIONAL_HDR32_MAGIC => self.getOptionalHeader32().image_base,
940 IMAGE_NT_OPTIONAL_HDR64_MAGIC => self.getOptionalHeader64().image_base,
941 else => unreachable, // We assume we have validated the header already
942 };
943 }
308944
309 if (name[0] == '/') {945 pub fn getNumberOfDataDirectories(self: Coff) u32 {
310 // This is a long name and stored in the string table946 const hdr = self.getOptionalHeader();
311 const offset_len = mem.indexOfScalar(u8, name[1..], 0) orelse 7;947 return switch (hdr.magic) {
948 IMAGE_NT_OPTIONAL_HDR32_MAGIC => self.getOptionalHeader32().number_of_rva_and_sizes,
949 IMAGE_NT_OPTIONAL_HDR64_MAGIC => self.getOptionalHeader64().number_of_rva_and_sizes,
950 else => unreachable, // We assume we have validated the header already
951 };
952 }
312953
313 const str_offset = try std.fmt.parseInt(u32, name[1 .. offset_len + 1], 10);954 pub fn getDataDirectories(self: *const Coff) []align(1) const ImageDataDirectory {
314 const str = try self.readStringFromTable(str_offset, &name);955 const hdr = self.getOptionalHeader();
315 std.mem.set(u8, name[str.len..], 0);956 const size: usize = switch (hdr.magic) {
316 } else {957 IMAGE_NT_OPTIONAL_HDR32_MAGIC => @sizeOf(OptionalHeaderPE32),
317 std.mem.set(u8, name[8..], 0);958 IMAGE_NT_OPTIONAL_HDR64_MAGIC => @sizeOf(OptionalHeaderPE64),
318 }959 else => unreachable, // We assume we have validated the header already
960 };
961 const offset = self.coff_header_offset + @sizeOf(CoffHeader) + size;
962 return @ptrCast([*]align(1) const ImageDataDirectory, self.data[offset..])[0..self.getNumberOfDataDirectories()];
963 }
319964
320 self.sections.appendAssumeCapacity(Section{965 pub fn getSymtab(self: *const Coff) ?Symtab {
321 .header = SectionHeader{966 const coff_header = self.getCoffHeader();
322 .name = name,967 if (coff_header.pointer_to_symbol_table == 0) return null;
323 .misc = SectionHeader.Misc{ .virtual_size = try in.readIntLittle(u32) },968
324 .virtual_address = try in.readIntLittle(u32),969 const offset = coff_header.pointer_to_symbol_table;
325 .size_of_raw_data = try in.readIntLittle(u32),970 const size = coff_header.number_of_symbols * Symbol.sizeOf();
326 .pointer_to_raw_data = try in.readIntLittle(u32),971 return .{ .buffer = self.data[offset..][0..size] };
327 .pointer_to_relocations = try in.readIntLittle(u32),972 }
328 .pointer_to_line_numbers = try in.readIntLittle(u32),973
329 .number_of_relocations = try in.readIntLittle(u16),974 pub fn getStrtab(self: *const Coff) ?Strtab {
330 .number_of_line_numbers = try in.readIntLittle(u16),975 const coff_header = self.getCoffHeader();
331 .characteristics = try in.readIntLittle(u32),976 if (coff_header.pointer_to_symbol_table == 0) return null;
332 },977
333 });978 const offset = coff_header.pointer_to_symbol_table + Symbol.sizeOf() * coff_header.number_of_symbols;
334 }979 const size = mem.readIntLittle(u32, self.data[offset..][0..4]);
980 return Strtab{ .buffer = self.data[offset..][0..size] };
335 }981 }
336982
337 pub fn getSection(self: *Coff, comptime name: []const u8) ?*Section {983 pub fn getSectionHeaders(self: *const Coff) []align(1) const SectionHeader {
338 for (self.sections.items) |*sec| {984 const coff_header = self.getCoffHeader();
339 if (mem.eql(u8, sec.header.name[0..name.len], name)) {985 const offset = self.coff_header_offset + @sizeOf(CoffHeader) + coff_header.size_of_optional_header;
340 return sec;986 return @ptrCast([*]align(1) const SectionHeader, self.data.ptr + offset)[0..coff_header.number_of_sections];
987 }
988
989 pub fn getSectionName(self: *const Coff, sect_hdr: *align(1) const SectionHeader) []const u8 {
990 const name = sect_hdr.getName() orelse blk: {
991 const strtab = self.getStrtab().?;
992 const name_offset = sect_hdr.getNameOffset().?;
993 break :blk strtab.get(name_offset);
994 };
995 return name;
996 }
997
998 pub fn getSectionByName(self: *const Coff, comptime name: []const u8) ?*align(1) const SectionHeader {
999 for (self.getSectionHeaders()) |*sect| {
1000 if (mem.eql(u8, self.getSectionName(sect), name)) {
1001 return sect;
341 }1002 }
342 }1003 }
343 return null;1004 return null;
344 }1005 }
3451006
346 // Return an owned slice full of the section data1007 // Return an owned slice full of the section data
347 pub fn getSectionData(self: *Coff, comptime name: []const u8, allocator: mem.Allocator) ![]u8 {1008 pub fn getSectionDataAlloc(self: *const Coff, comptime name: []const u8, allocator: mem.Allocator) ![]u8 {
348 const sec = for (self.sections.items) |*sec| {1009 const sec = self.getSectionByName(name) orelse return error.MissingCoffSection;
349 if (mem.eql(u8, sec.header.name[0..name.len], name)) {1010 const out_buff = try allocator.alloc(u8, sec.virtual_size);
350 break sec;1011 mem.copy(u8, out_buff, self.data[sec.pointer_to_raw_data..][0..sec.virtual_size]);
351 }
352 } else {
353 return error.MissingCoffSection;
354 };
355 const in = self.in_file.reader();
356 try self.in_file.seekTo(sec.header.pointer_to_raw_data);
357 const out_buff = try allocator.alloc(u8, sec.header.misc.virtual_size);
358 try in.readNoEof(out_buff);
359 return out_buff;1012 return out_buff;
360 }1013 }
361};
3621014
363const CoffHeader = struct {1015 pub const Symtab = struct {
364 machine: u16,1016 buffer: []const u8,
365 number_of_sections: u16,
366 timedate_stamp: u32,
367 pointer_to_symbol_table: u32,
368 number_of_symbols: u32,
369 size_of_optional_header: u16,
370 characteristics: u16,
371};
3721017
373const OptionalHeader = struct {1018 fn len(self: Symtab) usize {
374 const DataDirectory = struct {1019 return @divExact(self.buffer.len, Symbol.sizeOf());
375 virtual_address: u32,1020 }
376 size: u32,
377 };
3781021
379 magic: u16,1022 const Tag = enum {
380 data_directory: [IMAGE_NUMBEROF_DIRECTORY_ENTRIES]DataDirectory,1023 symbol,
381 entry_addr: u32,1024 func_def,
382 code_base: u32,1025 debug_info,
383 image_base: u64,1026 weak_ext,
384};1027 file_def,
1028 sect_def,
1029 };
3851030
386const DebugDirectoryEntry = packed struct {1031 const Record = union(Tag) {
387 characteristiccs: u32,1032 symbol: Symbol,
388 time_date_stamp: u32,1033 debug_info: DebugInfoDefinition,
389 major_version: u16,1034 func_def: FunctionDefinition,
390 minor_version: u16,1035 weak_ext: WeakExternalDefinition,
391 @"type": u32,1036 file_def: FileDefinition,
392 size_of_data: u32,1037 sect_def: SectionDefinition,
393 address_of_raw_data: u32,1038 };
394 pointer_to_raw_data: u32,
395};
3961039
397pub const Section = struct {1040 /// Lives as long as Symtab instance.
398 header: SectionHeader,1041 fn at(self: Symtab, index: usize, tag: Tag) Record {
399};1042 const offset = index * Symbol.sizeOf();
1043 const raw = self.buffer[offset..][0..Symbol.sizeOf()];
1044 return switch (tag) {
1045 .symbol => .{ .symbol = asSymbol(raw) },
1046 .debug_info => .{ .debug_info = asDebugInfo(raw) },
1047 .func_def => .{ .func_def = asFuncDef(raw) },
1048 .weak_ext => .{ .weak_ext = asWeakExtDef(raw) },
1049 .file_def => .{ .file_def = asFileDef(raw) },
1050 .sect_def => .{ .sect_def = asSectDef(raw) },
1051 };
1052 }
1053
1054 fn asSymbol(raw: []const u8) Symbol {
1055 return .{
1056 .name = raw[0..8].*,
1057 .value = mem.readIntLittle(u32, raw[8..12]),
1058 .section_number = @intToEnum(SectionNumber, mem.readIntLittle(u16, raw[12..14])),
1059 .@"type" = @bitCast(SymType, mem.readIntLittle(u16, raw[14..16])),
1060 .storage_class = @intToEnum(StorageClass, raw[16]),
1061 .number_of_aux_symbols = raw[17],
1062 };
1063 }
1064
1065 fn asDebugInfo(raw: []const u8) DebugInfoDefinition {
1066 return .{
1067 .unused_1 = raw[0..4].*,
1068 .linenumber = mem.readIntLittle(u16, raw[4..6]),
1069 .unused_2 = raw[6..12].*,
1070 .pointer_to_next_function = mem.readIntLittle(u32, raw[12..16]),
1071 .unused_3 = raw[16..18].*,
1072 };
1073 }
1074
1075 fn asFuncDef(raw: []const u8) FunctionDefinition {
1076 return .{
1077 .tag_index = mem.readIntLittle(u32, raw[0..4]),
1078 .total_size = mem.readIntLittle(u32, raw[4..8]),
1079 .pointer_to_linenumber = mem.readIntLittle(u32, raw[8..12]),
1080 .pointer_to_next_function = mem.readIntLittle(u32, raw[12..16]),
1081 .unused = raw[16..18].*,
1082 };
1083 }
1084
1085 fn asWeakExtDef(raw: []const u8) WeakExternalDefinition {
1086 return .{
1087 .tag_index = mem.readIntLittle(u32, raw[0..4]),
1088 .flag = @intToEnum(WeakExternalFlag, mem.readIntLittle(u32, raw[4..8])),
1089 .unused = raw[8..18].*,
1090 };
1091 }
1092
1093 fn asFileDef(raw: []const u8) FileDefinition {
1094 return .{
1095 .file_name = raw[0..18].*,
1096 };
1097 }
1098
1099 fn asSectDef(raw: []const u8) SectionDefinition {
1100 return .{
1101 .length = mem.readIntLittle(u32, raw[0..4]),
1102 .number_of_relocations = mem.readIntLittle(u16, raw[4..6]),
1103 .number_of_linenumbers = mem.readIntLittle(u16, raw[6..8]),
1104 .checksum = mem.readIntLittle(u32, raw[8..12]),
1105 .number = mem.readIntLittle(u16, raw[12..14]),
1106 .selection = @intToEnum(ComdatSelection, raw[14]),
1107 .unused = raw[15..18].*,
1108 };
1109 }
1110
1111 const Slice = struct {
1112 buffer: []const u8,
1113 num: usize,
1114 count: usize = 0,
1115
1116 /// Lives as long as Symtab instance.
1117 fn next(self: *Slice) ?Symbol {
1118 if (self.count >= self.num) return null;
1119 const sym = asSymbol(self.buffer[0..Symbol.sizeOf()]);
1120 self.count += 1;
1121 self.buffer = self.buffer[Symbol.sizeOf()..];
1122 return sym;
1123 }
1124 };
4001125
401const SectionHeader = struct {1126 fn slice(self: Symtab, start: usize, end: ?usize) Slice {
402 const Misc = union {1127 const offset = start * Symbol.sizeOf();
403 physical_address: u32,1128 const llen = if (end) |e| e * Symbol.sizeOf() else self.buffer.len;
404 virtual_size: u32,1129 const num = @divExact(llen - offset, Symbol.sizeOf());
1130 return Slice{ .buffer = self.buffer[offset..][0..llen], .num = num };
1131 }
405 };1132 };
4061133
407 name: [32]u8,1134 pub const Strtab = struct {
408 misc: Misc,1135 buffer: []const u8,
409 virtual_address: u32,1136
410 size_of_raw_data: u32,1137 fn get(self: Strtab, off: u32) []const u8 {
411 pointer_to_raw_data: u32,1138 assert(off < self.buffer.len);
412 pointer_to_relocations: u32,1139 return mem.sliceTo(@ptrCast([*:0]const u8, self.buffer.ptr + off), 0);
413 pointer_to_line_numbers: u32,1140 }
414 number_of_relocations: u16,1141 };
415 number_of_line_numbers: u16,
416 characteristics: u32,
417};1142};
lib/std/compress/deflate/bits_utils.zig+1-1
...@@ -2,7 +2,7 @@ const math = @import("std").math;...@@ -2,7 +2,7 @@ const math = @import("std").math;
22
3// Reverse bit-by-bit a N-bit code.3// Reverse bit-by-bit a N-bit code.
4pub fn bitReverse(comptime T: type, value: T, N: usize) T {4pub fn bitReverse(comptime T: type, value: T, N: usize) T {
5 const r = @bitReverse(T, value);5 const r = @bitReverse(value);
6 return r >> @intCast(math.Log2Int(T), @typeInfo(T).Int.bits - N);6 return r >> @intCast(math.Log2Int(T), @typeInfo(T).Int.bits - N);
7}7}
88
lib/std/crypto/25519/ed25519.zig+3-1
...@@ -355,7 +355,9 @@ test "ed25519 batch verification" {...@@ -355,7 +355,9 @@ test "ed25519 batch verification" {
355 try Ed25519.verifyBatch(2, signature_batch);355 try Ed25519.verifyBatch(2, signature_batch);
356356
357 signature_batch[1].sig = sig1;357 signature_batch[1].sig = sig1;
358 try std.testing.expectError(error.SignatureVerificationFailed, Ed25519.verifyBatch(signature_batch.len, signature_batch));358 // TODO https://github.com/ziglang/zig/issues/12240
359 const sig_len = signature_batch.len;
360 try std.testing.expectError(error.SignatureVerificationFailed, Ed25519.verifyBatch(sig_len, signature_batch));
359 }361 }
360}362}
361363
lib/std/crypto/aes_ocb.zig+5-5
...@@ -66,7 +66,7 @@ fn AesOcb(comptime Aes: anytype) type {...@@ -66,7 +66,7 @@ fn AesOcb(comptime Aes: anytype) type {
66 var offset = [_]u8{0} ** 16;66 var offset = [_]u8{0} ** 16;
67 var i: usize = 0;67 var i: usize = 0;
68 while (i < full_blocks) : (i += 1) {68 while (i < full_blocks) : (i += 1) {
69 xorWith(&offset, lt[@ctz(usize, i + 1)]);69 xorWith(&offset, lt[@ctz(i + 1)]);
70 var e = xorBlocks(offset, a[i * 16 ..][0..16].*);70 var e = xorBlocks(offset, a[i * 16 ..][0..16].*);
71 aes_enc_ctx.encrypt(&e, &e);71 aes_enc_ctx.encrypt(&e, &e);
72 xorWith(&sum, e);72 xorWith(&sum, e);
...@@ -129,7 +129,7 @@ fn AesOcb(comptime Aes: anytype) type {...@@ -129,7 +129,7 @@ fn AesOcb(comptime Aes: anytype) type {
129 var es: [16 * wb]u8 align(16) = undefined;129 var es: [16 * wb]u8 align(16) = undefined;
130 var j: usize = 0;130 var j: usize = 0;
131 while (j < wb) : (j += 1) {131 while (j < wb) : (j += 1) {
132 xorWith(&offset, lt[@ctz(usize, i + 1 + j)]);132 xorWith(&offset, lt[@ctz(i + 1 + j)]);
133 offsets[j] = offset;133 offsets[j] = offset;
134 const p = m[(i + j) * 16 ..][0..16].*;134 const p = m[(i + j) * 16 ..][0..16].*;
135 mem.copy(u8, es[j * 16 ..][0..16], &xorBlocks(p, offsets[j]));135 mem.copy(u8, es[j * 16 ..][0..16], &xorBlocks(p, offsets[j]));
...@@ -143,7 +143,7 @@ fn AesOcb(comptime Aes: anytype) type {...@@ -143,7 +143,7 @@ fn AesOcb(comptime Aes: anytype) type {
143 }143 }
144 }144 }
145 while (i < full_blocks) : (i += 1) {145 while (i < full_blocks) : (i += 1) {
146 xorWith(&offset, lt[@ctz(usize, i + 1)]);146 xorWith(&offset, lt[@ctz(i + 1)]);
147 const p = m[i * 16 ..][0..16].*;147 const p = m[i * 16 ..][0..16].*;
148 var e = xorBlocks(p, offset);148 var e = xorBlocks(p, offset);
149 aes_enc_ctx.encrypt(&e, &e);149 aes_enc_ctx.encrypt(&e, &e);
...@@ -193,7 +193,7 @@ fn AesOcb(comptime Aes: anytype) type {...@@ -193,7 +193,7 @@ fn AesOcb(comptime Aes: anytype) type {
193 var es: [16 * wb]u8 align(16) = undefined;193 var es: [16 * wb]u8 align(16) = undefined;
194 var j: usize = 0;194 var j: usize = 0;
195 while (j < wb) : (j += 1) {195 while (j < wb) : (j += 1) {
196 xorWith(&offset, lt[@ctz(usize, i + 1 + j)]);196 xorWith(&offset, lt[@ctz(i + 1 + j)]);
197 offsets[j] = offset;197 offsets[j] = offset;
198 const q = c[(i + j) * 16 ..][0..16].*;198 const q = c[(i + j) * 16 ..][0..16].*;
199 mem.copy(u8, es[j * 16 ..][0..16], &xorBlocks(q, offsets[j]));199 mem.copy(u8, es[j * 16 ..][0..16], &xorBlocks(q, offsets[j]));
...@@ -207,7 +207,7 @@ fn AesOcb(comptime Aes: anytype) type {...@@ -207,7 +207,7 @@ fn AesOcb(comptime Aes: anytype) type {
207 }207 }
208 }208 }
209 while (i < full_blocks) : (i += 1) {209 while (i < full_blocks) : (i += 1) {
210 xorWith(&offset, lt[@ctz(usize, i + 1)]);210 xorWith(&offset, lt[@ctz(i + 1)]);
211 const q = c[i * 16 ..][0..16].*;211 const q = c[i * 16 ..][0..16].*;
212 var e = xorBlocks(q, offset);212 var e = xorBlocks(q, offset);
213 aes_dec_ctx.decrypt(&e, &e);213 aes_dec_ctx.decrypt(&e, &e);
lib/std/crypto/ghash.zig+16-16
...@@ -41,8 +41,8 @@ pub const Ghash = struct {...@@ -41,8 +41,8 @@ pub const Ghash = struct {
41 pub fn init(key: *const [key_length]u8) Ghash {41 pub fn init(key: *const [key_length]u8) Ghash {
42 const h1 = mem.readIntBig(u64, key[0..8]);42 const h1 = mem.readIntBig(u64, key[0..8]);
43 const h0 = mem.readIntBig(u64, key[8..16]);43 const h0 = mem.readIntBig(u64, key[8..16]);
44 const h1r = @bitReverse(u64, h1);44 const h1r = @bitReverse(h1);
45 const h0r = @bitReverse(u64, h0);45 const h0r = @bitReverse(h0);
46 const h2 = h0 ^ h1;46 const h2 = h0 ^ h1;
47 const h2r = h0r ^ h1r;47 const h2r = h0r ^ h1r;
4848
...@@ -68,8 +68,8 @@ pub const Ghash = struct {...@@ -68,8 +68,8 @@ pub const Ghash = struct {
68 hh.update(key);68 hh.update(key);
69 const hh1 = hh.y1;69 const hh1 = hh.y1;
70 const hh0 = hh.y0;70 const hh0 = hh.y0;
71 const hh1r = @bitReverse(u64, hh1);71 const hh1r = @bitReverse(hh1);
72 const hh0r = @bitReverse(u64, hh0);72 const hh0r = @bitReverse(hh0);
73 const hh2 = hh0 ^ hh1;73 const hh2 = hh0 ^ hh1;
74 const hh2r = hh0r ^ hh1r;74 const hh2r = hh0r ^ hh1r;
7575
...@@ -156,8 +156,8 @@ pub const Ghash = struct {...@@ -156,8 +156,8 @@ pub const Ghash = struct {
156 y1 ^= mem.readIntBig(u64, msg[i..][0..8]);156 y1 ^= mem.readIntBig(u64, msg[i..][0..8]);
157 y0 ^= mem.readIntBig(u64, msg[i..][8..16]);157 y0 ^= mem.readIntBig(u64, msg[i..][8..16]);
158158
159 const y1r = @bitReverse(u64, y1);159 const y1r = @bitReverse(y1);
160 const y0r = @bitReverse(u64, y0);160 const y0r = @bitReverse(y0);
161 const y2 = y0 ^ y1;161 const y2 = y0 ^ y1;
162 const y2r = y0r ^ y1r;162 const y2r = y0r ^ y1r;
163163
...@@ -172,8 +172,8 @@ pub const Ghash = struct {...@@ -172,8 +172,8 @@ pub const Ghash = struct {
172 const sy1 = mem.readIntBig(u64, msg[i..][16..24]);172 const sy1 = mem.readIntBig(u64, msg[i..][16..24]);
173 const sy0 = mem.readIntBig(u64, msg[i..][24..32]);173 const sy0 = mem.readIntBig(u64, msg[i..][24..32]);
174174
175 const sy1r = @bitReverse(u64, sy1);175 const sy1r = @bitReverse(sy1);
176 const sy0r = @bitReverse(u64, sy0);176 const sy0r = @bitReverse(sy0);
177 const sy2 = sy0 ^ sy1;177 const sy2 = sy0 ^ sy1;
178 const sy2r = sy0r ^ sy1r;178 const sy2r = sy0r ^ sy1r;
179179
...@@ -191,9 +191,9 @@ pub const Ghash = struct {...@@ -191,9 +191,9 @@ pub const Ghash = struct {
191 z0h ^= sz0h;191 z0h ^= sz0h;
192 z1h ^= sz1h;192 z1h ^= sz1h;
193 z2h ^= sz2h;193 z2h ^= sz2h;
194 z0h = @bitReverse(u64, z0h) >> 1;194 z0h = @bitReverse(z0h) >> 1;
195 z1h = @bitReverse(u64, z1h) >> 1;195 z1h = @bitReverse(z1h) >> 1;
196 z2h = @bitReverse(u64, z2h) >> 1;196 z2h = @bitReverse(z2h) >> 1;
197197
198 var v3 = z1h;198 var v3 = z1h;
199 var v2 = z1 ^ z2h;199 var v2 = z1 ^ z2h;
...@@ -217,8 +217,8 @@ pub const Ghash = struct {...@@ -217,8 +217,8 @@ pub const Ghash = struct {
217 y1 ^= mem.readIntBig(u64, msg[i..][0..8]);217 y1 ^= mem.readIntBig(u64, msg[i..][0..8]);
218 y0 ^= mem.readIntBig(u64, msg[i..][8..16]);218 y0 ^= mem.readIntBig(u64, msg[i..][8..16]);
219219
220 const y1r = @bitReverse(u64, y1);220 const y1r = @bitReverse(y1);
221 const y0r = @bitReverse(u64, y0);221 const y0r = @bitReverse(y0);
222 const y2 = y0 ^ y1;222 const y2 = y0 ^ y1;
223 const y2r = y0r ^ y1r;223 const y2r = y0r ^ y1r;
224224
...@@ -228,9 +228,9 @@ pub const Ghash = struct {...@@ -228,9 +228,9 @@ pub const Ghash = struct {
228 var z0h = clmul(y0r, st.h0r);228 var z0h = clmul(y0r, st.h0r);
229 var z1h = clmul(y1r, st.h1r);229 var z1h = clmul(y1r, st.h1r);
230 var z2h = clmul(y2r, st.h2r) ^ z0h ^ z1h;230 var z2h = clmul(y2r, st.h2r) ^ z0h ^ z1h;
231 z0h = @bitReverse(u64, z0h) >> 1;231 z0h = @bitReverse(z0h) >> 1;
232 z1h = @bitReverse(u64, z1h) >> 1;232 z1h = @bitReverse(z1h) >> 1;
233 z2h = @bitReverse(u64, z2h) >> 1;233 z2h = @bitReverse(z2h) >> 1;
234234
235 // shift & reduce235 // shift & reduce
236 var v3 = z1h;236 var v3 = z1h;
lib/std/debug.zig+186-128
...@@ -816,11 +816,11 @@ pub fn openSelfDebugInfo(allocator: mem.Allocator) anyerror!DebugInfo {...@@ -816,11 +816,11 @@ pub fn openSelfDebugInfo(allocator: mem.Allocator) anyerror!DebugInfo {
816/// TODO it's weird to take ownership even on error, rework this code.816/// TODO it's weird to take ownership even on error, rework this code.
817fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo {817fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo {
818 nosuspend {818 nosuspend {
819 errdefer coff_file.close();819 defer coff_file.close();
820820
821 const coff_obj = try allocator.create(coff.Coff);821 const coff_obj = try allocator.create(coff.Coff);
822 errdefer allocator.destroy(coff_obj);822 errdefer allocator.destroy(coff_obj);
823 coff_obj.* = coff.Coff.init(allocator, coff_file);823 coff_obj.* = .{ .allocator = allocator };
824824
825 var di = ModuleDebugInfo{825 var di = ModuleDebugInfo{
826 .base_address = undefined,826 .base_address = undefined,
...@@ -828,27 +828,42 @@ fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo...@@ -828,27 +828,42 @@ fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo
828 .debug_data = undefined,828 .debug_data = undefined,
829 };829 };
830830
831 try di.coff.loadHeader();831 // TODO convert to Windows' memory-mapped file API
832 try di.coff.loadSections();832 const file_len = math.cast(usize, try coff_file.getEndPos()) orelse math.maxInt(usize);
833 if (di.coff.getSection(".debug_info")) |sec| {833 const data = try coff_file.readToEndAlloc(allocator, file_len);
834 try di.coff.parse(data);
835
836 if (di.coff.getSectionByName(".debug_info")) |sec| {
834 // This coff file has embedded DWARF debug info837 // This coff file has embedded DWARF debug info
835 _ = sec;838 _ = sec;
836 // TODO: free the section data slices839 // TODO: free the section data slices
837 const debug_info_data = di.coff.getSectionData(".debug_info", allocator) catch null;840 const debug_info = di.coff.getSectionDataAlloc(".debug_info", allocator) catch null;
838 const debug_abbrev_data = di.coff.getSectionData(".debug_abbrev", allocator) catch null;841 const debug_abbrev = di.coff.getSectionDataAlloc(".debug_abbrev", allocator) catch null;
839 const debug_str_data = di.coff.getSectionData(".debug_str", allocator) catch null;842 const debug_str = di.coff.getSectionDataAlloc(".debug_str", allocator) catch null;
840 const debug_line_data = di.coff.getSectionData(".debug_line", allocator) catch null;843 const debug_str_offsets = di.coff.getSectionDataAlloc(".debug_str_offsets", allocator) catch null;
841 const debug_line_str_data = di.coff.getSectionData(".debug_line_str", allocator) catch null;844 const debug_line = di.coff.getSectionDataAlloc(".debug_line", allocator) catch null;
842 const debug_ranges_data = di.coff.getSectionData(".debug_ranges", allocator) catch null;845 const debug_line_str = di.coff.getSectionDataAlloc(".debug_line_str", allocator) catch null;
846 const debug_ranges = di.coff.getSectionDataAlloc(".debug_ranges", allocator) catch null;
847 const debug_loclists = di.coff.getSectionDataAlloc(".debug_loclists", allocator) catch null;
848 const debug_rnglists = di.coff.getSectionDataAlloc(".debug_rnglists", allocator) catch null;
849 const debug_addr = di.coff.getSectionDataAlloc(".debug_addr", allocator) catch null;
850 const debug_names = di.coff.getSectionDataAlloc(".debug_names", allocator) catch null;
851 const debug_frame = di.coff.getSectionDataAlloc(".debug_frame", allocator) catch null;
843852
844 var dwarf = DW.DwarfInfo{853 var dwarf = DW.DwarfInfo{
845 .endian = native_endian,854 .endian = native_endian,
846 .debug_info = debug_info_data orelse return error.MissingDebugInfo,855 .debug_info = debug_info orelse return error.MissingDebugInfo,
847 .debug_abbrev = debug_abbrev_data orelse return error.MissingDebugInfo,856 .debug_abbrev = debug_abbrev orelse return error.MissingDebugInfo,
848 .debug_str = debug_str_data orelse return error.MissingDebugInfo,857 .debug_str = debug_str orelse return error.MissingDebugInfo,
849 .debug_line = debug_line_data orelse return error.MissingDebugInfo,858 .debug_str_offsets = debug_str_offsets,
850 .debug_line_str = debug_line_str_data,859 .debug_line = debug_line orelse return error.MissingDebugInfo,
851 .debug_ranges = debug_ranges_data,860 .debug_line_str = debug_line_str,
861 .debug_ranges = debug_ranges,
862 .debug_loclists = debug_loclists,
863 .debug_rnglists = debug_rnglists,
864 .debug_addr = debug_addr,
865 .debug_names = debug_names,
866 .debug_frame = debug_frame,
852 };867 };
853 try DW.openDwarfDebugInfo(&dwarf, allocator);868 try DW.openDwarfDebugInfo(&dwarf, allocator);
854 di.debug_data = PdbOrDwarf{ .dwarf = dwarf };869 di.debug_data = PdbOrDwarf{ .dwarf = dwarf };
...@@ -863,7 +878,10 @@ fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo...@@ -863,7 +878,10 @@ fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo
863 defer allocator.free(path);878 defer allocator.free(path);
864879
865 di.debug_data = PdbOrDwarf{ .pdb = undefined };880 di.debug_data = PdbOrDwarf{ .pdb = undefined };
866 di.debug_data.pdb = try pdb.Pdb.init(allocator, path);881 di.debug_data.pdb = pdb.Pdb.init(allocator, path) catch |err| switch (err) {
882 error.FileNotFound, error.IsDir => return error.MissingDebugInfo,
883 else => return err,
884 };
867 try di.debug_data.pdb.parseInfoStream();885 try di.debug_data.pdb.parseInfoStream();
868 try di.debug_data.pdb.parseDbiStream();886 try di.debug_data.pdb.parseDbiStream();
869887
...@@ -912,9 +930,15 @@ pub fn readElfDebugInfo(allocator: mem.Allocator, elf_file: File) !ModuleDebugIn...@@ -912,9 +930,15 @@ pub fn readElfDebugInfo(allocator: mem.Allocator, elf_file: File) !ModuleDebugIn
912 var opt_debug_info: ?[]const u8 = null;930 var opt_debug_info: ?[]const u8 = null;
913 var opt_debug_abbrev: ?[]const u8 = null;931 var opt_debug_abbrev: ?[]const u8 = null;
914 var opt_debug_str: ?[]const u8 = null;932 var opt_debug_str: ?[]const u8 = null;
933 var opt_debug_str_offsets: ?[]const u8 = null;
915 var opt_debug_line: ?[]const u8 = null;934 var opt_debug_line: ?[]const u8 = null;
916 var opt_debug_line_str: ?[]const u8 = null;935 var opt_debug_line_str: ?[]const u8 = null;
917 var opt_debug_ranges: ?[]const u8 = null;936 var opt_debug_ranges: ?[]const u8 = null;
937 var opt_debug_loclists: ?[]const u8 = null;
938 var opt_debug_rnglists: ?[]const u8 = null;
939 var opt_debug_addr: ?[]const u8 = null;
940 var opt_debug_names: ?[]const u8 = null;
941 var opt_debug_frame: ?[]const u8 = null;
918942
919 for (shdrs) |*shdr| {943 for (shdrs) |*shdr| {
920 if (shdr.sh_type == elf.SHT_NULL) continue;944 if (shdr.sh_type == elf.SHT_NULL) continue;
...@@ -926,12 +950,24 @@ pub fn readElfDebugInfo(allocator: mem.Allocator, elf_file: File) !ModuleDebugIn...@@ -926,12 +950,24 @@ pub fn readElfDebugInfo(allocator: mem.Allocator, elf_file: File) !ModuleDebugIn
926 opt_debug_abbrev = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);950 opt_debug_abbrev = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
927 } else if (mem.eql(u8, name, ".debug_str")) {951 } else if (mem.eql(u8, name, ".debug_str")) {
928 opt_debug_str = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);952 opt_debug_str = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
953 } else if (mem.eql(u8, name, ".debug_str_offsets")) {
954 opt_debug_str_offsets = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
929 } else if (mem.eql(u8, name, ".debug_line")) {955 } else if (mem.eql(u8, name, ".debug_line")) {
930 opt_debug_line = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);956 opt_debug_line = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
931 } else if (mem.eql(u8, name, ".debug_line_str")) {957 } else if (mem.eql(u8, name, ".debug_line_str")) {
932 opt_debug_line_str = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);958 opt_debug_line_str = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
933 } else if (mem.eql(u8, name, ".debug_ranges")) {959 } else if (mem.eql(u8, name, ".debug_ranges")) {
934 opt_debug_ranges = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);960 opt_debug_ranges = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
961 } else if (mem.eql(u8, name, ".debug_loclists")) {
962 opt_debug_loclists = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
963 } else if (mem.eql(u8, name, ".debug_rnglists")) {
964 opt_debug_rnglists = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
965 } else if (mem.eql(u8, name, ".debug_addr")) {
966 opt_debug_addr = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
967 } else if (mem.eql(u8, name, ".debug_names")) {
968 opt_debug_names = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
969 } else if (mem.eql(u8, name, ".debug_frame")) {
970 opt_debug_frame = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
935 }971 }
936 }972 }
937973
...@@ -940,9 +976,15 @@ pub fn readElfDebugInfo(allocator: mem.Allocator, elf_file: File) !ModuleDebugIn...@@ -940,9 +976,15 @@ pub fn readElfDebugInfo(allocator: mem.Allocator, elf_file: File) !ModuleDebugIn
940 .debug_info = opt_debug_info orelse return error.MissingDebugInfo,976 .debug_info = opt_debug_info orelse return error.MissingDebugInfo,
941 .debug_abbrev = opt_debug_abbrev orelse return error.MissingDebugInfo,977 .debug_abbrev = opt_debug_abbrev orelse return error.MissingDebugInfo,
942 .debug_str = opt_debug_str orelse return error.MissingDebugInfo,978 .debug_str = opt_debug_str orelse return error.MissingDebugInfo,
979 .debug_str_offsets = opt_debug_str_offsets,
943 .debug_line = opt_debug_line orelse return error.MissingDebugInfo,980 .debug_line = opt_debug_line orelse return error.MissingDebugInfo,
944 .debug_line_str = opt_debug_line_str,981 .debug_line_str = opt_debug_line_str,
945 .debug_ranges = opt_debug_ranges,982 .debug_ranges = opt_debug_ranges,
983 .debug_loclists = opt_debug_loclists,
984 .debug_rnglists = opt_debug_rnglists,
985 .debug_addr = opt_debug_addr,
986 .debug_names = opt_debug_names,
987 .debug_frame = opt_debug_frame,
946 };988 };
947989
948 try DW.openDwarfDebugInfo(&di, allocator);990 try DW.openDwarfDebugInfo(&di, allocator);
...@@ -968,24 +1010,20 @@ fn readMachODebugInfo(allocator: mem.Allocator, macho_file: File) !ModuleDebugIn...@@ -968,24 +1010,20 @@ fn readMachODebugInfo(allocator: mem.Allocator, macho_file: File) !ModuleDebugIn
968 if (hdr.magic != macho.MH_MAGIC_64)1010 if (hdr.magic != macho.MH_MAGIC_64)
969 return error.InvalidDebugInfo;1011 return error.InvalidDebugInfo;
9701012
971 const hdr_base = @ptrCast([*]const u8, hdr);1013 var it = macho.LoadCommandIterator{
972 var ptr = hdr_base + @sizeOf(macho.mach_header_64);1014 .ncmds = hdr.ncmds,
973 var ncmd: u32 = hdr.ncmds;1015 .buffer = mapped_mem[@sizeOf(macho.mach_header_64)..][0..hdr.sizeofcmds],
974 const symtab = while (ncmd != 0) : (ncmd -= 1) {
975 const lc = @ptrCast(*const std.macho.load_command, ptr);
976 switch (lc.cmd) {
977 .SYMTAB => break @ptrCast(*const std.macho.symtab_command, ptr),
978 else => {},
979 }
980 ptr = @alignCast(@alignOf(std.macho.load_command), ptr + lc.cmdsize);
981 } else {
982 return error.MissingDebugInfo;
983 };1016 };
1017 const symtab = while (it.next()) |cmd| switch (cmd.cmd()) {
1018 .SYMTAB => break cmd.cast(macho.symtab_command).?,
1019 else => {},
1020 } else return error.MissingDebugInfo;
1021
984 const syms = @ptrCast(1022 const syms = @ptrCast(
985 [*]const macho.nlist_64,1023 [*]const macho.nlist_64,
986 @alignCast(@alignOf(macho.nlist_64), hdr_base + symtab.symoff),1024 @alignCast(@alignOf(macho.nlist_64), &mapped_mem[symtab.symoff]),
987 )[0..symtab.nsyms];1025 )[0..symtab.nsyms];
988 const strings = @ptrCast([*]const u8, hdr_base + symtab.stroff)[0 .. symtab.strsize - 1 :0];1026 const strings = mapped_mem[symtab.stroff..][0 .. symtab.strsize - 1 :0];
9891027
990 const symbols_buf = try allocator.alloc(MachoSymbol, syms.len);1028 const symbols_buf = try allocator.alloc(MachoSymbol, syms.len);
9911029
...@@ -1200,48 +1238,46 @@ pub const DebugInfo = struct {...@@ -1200,48 +1238,46 @@ pub const DebugInfo = struct {
1200 if (address < base_address) continue;1238 if (address < base_address) continue;
12011239
1202 const header = std.c._dyld_get_image_header(i) orelse continue;1240 const header = std.c._dyld_get_image_header(i) orelse continue;
1203 // The array of load commands is right after the header
1204 var cmd_ptr = @intToPtr([*]u8, @ptrToInt(header) + @sizeOf(macho.mach_header_64));
1205
1206 var cmds = header.ncmds;
1207 while (cmds != 0) : (cmds -= 1) {
1208 const lc = @ptrCast(
1209 *macho.load_command,
1210 @alignCast(@alignOf(macho.load_command), cmd_ptr),
1211 );
1212 cmd_ptr += lc.cmdsize;
1213 if (lc.cmd != .SEGMENT_64) continue;
12141241
1215 const segment_cmd = @ptrCast(1242 var it = macho.LoadCommandIterator{
1216 *const std.macho.segment_command_64,1243 .ncmds = header.ncmds,
1217 @alignCast(@alignOf(std.macho.segment_command_64), lc),1244 .buffer = @alignCast(@alignOf(u64), @intToPtr(
1218 );1245 [*]u8,
1246 @ptrToInt(header) + @sizeOf(macho.mach_header_64),
1247 ))[0..header.sizeofcmds],
1248 };
1249 while (it.next()) |cmd| switch (cmd.cmd()) {
1250 .SEGMENT_64 => {
1251 const segment_cmd = cmd.cast(macho.segment_command_64).?;
1252 const rebased_address = address - base_address;
1253 const seg_start = segment_cmd.vmaddr;
1254 const seg_end = seg_start + segment_cmd.vmsize;
1255
1256 if (rebased_address >= seg_start and rebased_address < seg_end) {
1257 if (self.address_map.get(base_address)) |obj_di| {
1258 return obj_di;
1259 }
1260
1261 const obj_di = try self.allocator.create(ModuleDebugInfo);
1262 errdefer self.allocator.destroy(obj_di);
1263
1264 const macho_path = mem.sliceTo(std.c._dyld_get_image_name(i), 0);
1265 const macho_file = fs.cwd().openFile(macho_path, .{
1266 .intended_io_mode = .blocking,
1267 }) catch |err| switch (err) {
1268 error.FileNotFound => return error.MissingDebugInfo,
1269 else => return err,
1270 };
1271 obj_di.* = try readMachODebugInfo(self.allocator, macho_file);
1272 obj_di.base_address = base_address;
12191273
1220 const rebased_address = address - base_address;1274 try self.address_map.putNoClobber(base_address, obj_di);
1221 const seg_start = segment_cmd.vmaddr;
1222 const seg_end = seg_start + segment_cmd.vmsize;
12231275
1224 if (rebased_address >= seg_start and rebased_address < seg_end) {
1225 if (self.address_map.get(base_address)) |obj_di| {
1226 return obj_di;1276 return obj_di;
1227 }1277 }
12281278 },
1229 const obj_di = try self.allocator.create(ModuleDebugInfo);1279 else => {},
1230 errdefer self.allocator.destroy(obj_di);1280 };
1231
1232 const macho_path = mem.sliceTo(std.c._dyld_get_image_name(i), 0);
1233 const macho_file = fs.cwd().openFile(macho_path, .{ .intended_io_mode = .blocking }) catch |err| switch (err) {
1234 error.FileNotFound => return error.MissingDebugInfo,
1235 else => return err,
1236 };
1237 obj_di.* = try readMachODebugInfo(self.allocator, macho_file);
1238 obj_di.base_address = base_address;
1239
1240 try self.address_map.putNoClobber(base_address, obj_di);
1241
1242 return obj_di;
1243 }
1244 }
1245 }1281 }
12461282
1247 return error.MissingDebugInfo;1283 return error.MissingDebugInfo;
...@@ -1445,44 +1481,31 @@ pub const ModuleDebugInfo = switch (native_os) {...@@ -1445,44 +1481,31 @@ pub const ModuleDebugInfo = switch (native_os) {
1445 if (hdr.magic != std.macho.MH_MAGIC_64)1481 if (hdr.magic != std.macho.MH_MAGIC_64)
1446 return error.InvalidDebugInfo;1482 return error.InvalidDebugInfo;
14471483
1448 const hdr_base = @ptrCast([*]const u8, hdr);1484 var segcmd: ?macho.LoadCommandIterator.LoadCommand = null;
1449 var ptr = hdr_base + @sizeOf(macho.mach_header_64);1485 var symtabcmd: ?macho.symtab_command = null;
1450 var segptr = ptr;1486 var it = macho.LoadCommandIterator{
1451 var ncmd: u32 = hdr.ncmds;1487 .ncmds = hdr.ncmds,
1452 var segcmd: ?*const macho.segment_command_64 = null;1488 .buffer = mapped_mem[@sizeOf(macho.mach_header_64)..][0..hdr.sizeofcmds],
1453 var symtabcmd: ?*const macho.symtab_command = null;1489 };
14541490 while (it.next()) |cmd| switch (cmd.cmd()) {
1455 while (ncmd != 0) : (ncmd -= 1) {1491 .SEGMENT_64 => segcmd = cmd,
1456 const lc = @ptrCast(*const std.macho.load_command, ptr);1492 .SYMTAB => symtabcmd = cmd.cast(macho.symtab_command).?,
1457 switch (lc.cmd) {1493 else => {},
1458 .SEGMENT_64 => {1494 };
1459 segcmd = @ptrCast(
1460 *const std.macho.segment_command_64,
1461 @alignCast(@alignOf(std.macho.segment_command_64), ptr),
1462 );
1463 segptr = ptr;
1464 },
1465 .SYMTAB => {
1466 symtabcmd = @ptrCast(
1467 *const std.macho.symtab_command,
1468 @alignCast(@alignOf(std.macho.symtab_command), ptr),
1469 );
1470 },
1471 else => {},
1472 }
1473 ptr = @alignCast(@alignOf(std.macho.load_command), ptr + lc.cmdsize);
1474 }
14751495
1476 if (segcmd == null or symtabcmd == null) return error.MissingDebugInfo;1496 if (segcmd == null or symtabcmd == null) return error.MissingDebugInfo;
14771497
1478 // Parse symbols1498 // Parse symbols
1479 const strtab = @ptrCast(1499 const strtab = @ptrCast(
1480 [*]const u8,1500 [*]const u8,
1481 hdr_base + symtabcmd.?.stroff,1501 &mapped_mem[symtabcmd.?.stroff],
1482 )[0 .. symtabcmd.?.strsize - 1 :0];1502 )[0 .. symtabcmd.?.strsize - 1 :0];
1483 const symtab = @ptrCast(1503 const symtab = @ptrCast(
1484 [*]const macho.nlist_64,1504 [*]const macho.nlist_64,
1485 @alignCast(@alignOf(macho.nlist_64), hdr_base + symtabcmd.?.symoff),1505 @alignCast(
1506 @alignOf(macho.nlist_64),
1507 &mapped_mem[symtabcmd.?.symoff],
1508 ),
1486 )[0..symtabcmd.?.nsyms];1509 )[0..symtabcmd.?.nsyms];
14871510
1488 // TODO handle tentative (common) symbols1511 // TODO handle tentative (common) symbols
...@@ -1496,25 +1519,21 @@ pub const ModuleDebugInfo = switch (native_os) {...@@ -1496,25 +1519,21 @@ pub const ModuleDebugInfo = switch (native_os) {
1496 addr_table.putAssumeCapacityNoClobber(sym_name, sym.n_value);1519 addr_table.putAssumeCapacityNoClobber(sym_name, sym.n_value);
1497 }1520 }
14981521
1499 var opt_debug_line: ?*const macho.section_64 = null;1522 var opt_debug_line: ?macho.section_64 = null;
1500 var opt_debug_info: ?*const macho.section_64 = null;1523 var opt_debug_info: ?macho.section_64 = null;
1501 var opt_debug_abbrev: ?*const macho.section_64 = null;1524 var opt_debug_abbrev: ?macho.section_64 = null;
1502 var opt_debug_str: ?*const macho.section_64 = null;1525 var opt_debug_str: ?macho.section_64 = null;
1503 var opt_debug_line_str: ?*const macho.section_64 = null;1526 var opt_debug_str_offsets: ?macho.section_64 = null;
1504 var opt_debug_ranges: ?*const macho.section_64 = null;1527 var opt_debug_line_str: ?macho.section_64 = null;
15051528 var opt_debug_ranges: ?macho.section_64 = null;
1506 const sections = @ptrCast(1529 var opt_debug_loclists: ?macho.section_64 = null;
1507 [*]const macho.section_64,1530 var opt_debug_rnglists: ?macho.section_64 = null;
1508 @alignCast(@alignOf(macho.section_64), segptr + @sizeOf(std.macho.segment_command_64)),1531 var opt_debug_addr: ?macho.section_64 = null;
1509 )[0..segcmd.?.nsects];1532 var opt_debug_names: ?macho.section_64 = null;
1510 for (sections) |*sect| {1533 var opt_debug_frame: ?macho.section_64 = null;
1511 // The section name may not exceed 16 chars and a trailing null may1534
1512 // not be present1535 for (segcmd.?.getSections()) |sect| {
1513 const name = if (mem.indexOfScalar(u8, sect.sectname[0..], 0)) |last|1536 const name = sect.sectName();
1514 sect.sectname[0..last]
1515 else
1516 sect.sectname[0..];
1517
1518 if (mem.eql(u8, name, "__debug_line")) {1537 if (mem.eql(u8, name, "__debug_line")) {
1519 opt_debug_line = sect;1538 opt_debug_line = sect;
1520 } else if (mem.eql(u8, name, "__debug_info")) {1539 } else if (mem.eql(u8, name, "__debug_info")) {
...@@ -1523,10 +1542,22 @@ pub const ModuleDebugInfo = switch (native_os) {...@@ -1523,10 +1542,22 @@ pub const ModuleDebugInfo = switch (native_os) {
1523 opt_debug_abbrev = sect;1542 opt_debug_abbrev = sect;
1524 } else if (mem.eql(u8, name, "__debug_str")) {1543 } else if (mem.eql(u8, name, "__debug_str")) {
1525 opt_debug_str = sect;1544 opt_debug_str = sect;
1545 } else if (mem.eql(u8, name, "__debug_str_offsets")) {
1546 opt_debug_str_offsets = sect;
1526 } else if (mem.eql(u8, name, "__debug_line_str")) {1547 } else if (mem.eql(u8, name, "__debug_line_str")) {
1527 opt_debug_line_str = sect;1548 opt_debug_line_str = sect;
1528 } else if (mem.eql(u8, name, "__debug_ranges")) {1549 } else if (mem.eql(u8, name, "__debug_ranges")) {
1529 opt_debug_ranges = sect;1550 opt_debug_ranges = sect;
1551 } else if (mem.eql(u8, name, "__debug_loclists")) {
1552 opt_debug_loclists = sect;
1553 } else if (mem.eql(u8, name, "__debug_rnglists")) {
1554 opt_debug_rnglists = sect;
1555 } else if (mem.eql(u8, name, "__debug_addr")) {
1556 opt_debug_addr = sect;
1557 } else if (mem.eql(u8, name, "__debug_names")) {
1558 opt_debug_names = sect;
1559 } else if (mem.eql(u8, name, "__debug_frame")) {
1560 opt_debug_frame = sect;
1530 }1561 }
1531 }1562 }
15321563
...@@ -1544,6 +1575,10 @@ pub const ModuleDebugInfo = switch (native_os) {...@@ -1544,6 +1575,10 @@ pub const ModuleDebugInfo = switch (native_os) {
1544 .debug_info = try chopSlice(mapped_mem, debug_info.offset, debug_info.size),1575 .debug_info = try chopSlice(mapped_mem, debug_info.offset, debug_info.size),
1545 .debug_abbrev = try chopSlice(mapped_mem, debug_abbrev.offset, debug_abbrev.size),1576 .debug_abbrev = try chopSlice(mapped_mem, debug_abbrev.offset, debug_abbrev.size),
1546 .debug_str = try chopSlice(mapped_mem, debug_str.offset, debug_str.size),1577 .debug_str = try chopSlice(mapped_mem, debug_str.offset, debug_str.size),
1578 .debug_str_offsets = if (opt_debug_str_offsets) |debug_str_offsets|
1579 try chopSlice(mapped_mem, debug_str_offsets.offset, debug_str_offsets.size)
1580 else
1581 null,
1547 .debug_line = try chopSlice(mapped_mem, debug_line.offset, debug_line.size),1582 .debug_line = try chopSlice(mapped_mem, debug_line.offset, debug_line.size),
1548 .debug_line_str = if (opt_debug_line_str) |debug_line_str|1583 .debug_line_str = if (opt_debug_line_str) |debug_line_str|
1549 try chopSlice(mapped_mem, debug_line_str.offset, debug_line_str.size)1584 try chopSlice(mapped_mem, debug_line_str.offset, debug_line_str.size)
...@@ -1553,6 +1588,26 @@ pub const ModuleDebugInfo = switch (native_os) {...@@ -1553,6 +1588,26 @@ pub const ModuleDebugInfo = switch (native_os) {
1553 try chopSlice(mapped_mem, debug_ranges.offset, debug_ranges.size)1588 try chopSlice(mapped_mem, debug_ranges.offset, debug_ranges.size)
1554 else1589 else
1555 null,1590 null,
1591 .debug_loclists = if (opt_debug_loclists) |debug_loclists|
1592 try chopSlice(mapped_mem, debug_loclists.offset, debug_loclists.size)
1593 else
1594 null,
1595 .debug_rnglists = if (opt_debug_rnglists) |debug_rnglists|
1596 try chopSlice(mapped_mem, debug_rnglists.offset, debug_rnglists.size)
1597 else
1598 null,
1599 .debug_addr = if (opt_debug_addr) |debug_addr|
1600 try chopSlice(mapped_mem, debug_addr.offset, debug_addr.size)
1601 else
1602 null,
1603 .debug_names = if (opt_debug_names) |debug_names|
1604 try chopSlice(mapped_mem, debug_names.offset, debug_names.size)
1605 else
1606 null,
1607 .debug_frame = if (opt_debug_frame) |debug_frame|
1608 try chopSlice(mapped_mem, debug_frame.offset, debug_frame.size)
1609 else
1610 null,
1556 };1611 };
15571612
1558 try DW.openDwarfDebugInfo(&di, allocator);1613 try DW.openDwarfDebugInfo(&di, allocator);
...@@ -1607,6 +1662,8 @@ pub const ModuleDebugInfo = switch (native_os) {...@@ -1607,6 +1662,8 @@ pub const ModuleDebugInfo = switch (native_os) {
1607 .compile_unit_name = compile_unit.die.getAttrString(1662 .compile_unit_name = compile_unit.die.getAttrString(
1608 o_file_di,1663 o_file_di,
1609 DW.AT.name,1664 DW.AT.name,
1665 o_file_di.debug_str,
1666 compile_unit.*,
1610 ) catch |err| switch (err) {1667 ) catch |err| switch (err) {
1611 error.MissingDebugInfo, error.InvalidDebugInfo => "???",1668 error.MissingDebugInfo, error.InvalidDebugInfo => "???",
1612 },1669 },
...@@ -1647,7 +1704,7 @@ pub const ModuleDebugInfo = switch (native_os) {...@@ -1647,7 +1704,7 @@ pub const ModuleDebugInfo = switch (native_os) {
16471704
1648 switch (self.debug_data) {1705 switch (self.debug_data) {
1649 .dwarf => |*dwarf| {1706 .dwarf => |*dwarf| {
1650 const dwarf_address = relocated_address + self.coff.pe_header.image_base;1707 const dwarf_address = relocated_address + self.coff.getImageBase();
1651 return getSymbolFromDwarf(allocator, dwarf_address, dwarf);1708 return getSymbolFromDwarf(allocator, dwarf_address, dwarf);
1652 },1709 },
1653 .pdb => {1710 .pdb => {
...@@ -1655,13 +1712,14 @@ pub const ModuleDebugInfo = switch (native_os) {...@@ -1655,13 +1712,14 @@ pub const ModuleDebugInfo = switch (native_os) {
1655 },1712 },
1656 }1713 }
16571714
1658 var coff_section: *coff.Section = undefined;1715 var coff_section: *align(1) const coff.SectionHeader = undefined;
1659 const mod_index = for (self.debug_data.pdb.sect_contribs) |sect_contrib| {1716 const mod_index = for (self.debug_data.pdb.sect_contribs) |sect_contrib| {
1660 if (sect_contrib.Section > self.coff.sections.items.len) continue;1717 const sections = self.coff.getSectionHeaders();
1718 if (sect_contrib.Section > sections.len) continue;
1661 // Remember that SectionContribEntry.Section is 1-based.1719 // Remember that SectionContribEntry.Section is 1-based.
1662 coff_section = &self.coff.sections.items[sect_contrib.Section - 1];1720 coff_section = &sections[sect_contrib.Section - 1];
16631721
1664 const vaddr_start = coff_section.header.virtual_address + sect_contrib.Offset;1722 const vaddr_start = coff_section.virtual_address + sect_contrib.Offset;
1665 const vaddr_end = vaddr_start + sect_contrib.Size;1723 const vaddr_end = vaddr_start + sect_contrib.Size;
1666 if (relocated_address >= vaddr_start and relocated_address < vaddr_end) {1724 if (relocated_address >= vaddr_start and relocated_address < vaddr_end) {
1667 break sect_contrib.ModuleIndex;1725 break sect_contrib.ModuleIndex;
...@@ -1677,11 +1735,11 @@ pub const ModuleDebugInfo = switch (native_os) {...@@ -1677,11 +1735,11 @@ pub const ModuleDebugInfo = switch (native_os) {
16771735
1678 const symbol_name = self.debug_data.pdb.getSymbolName(1736 const symbol_name = self.debug_data.pdb.getSymbolName(
1679 module,1737 module,
1680 relocated_address - coff_section.header.virtual_address,1738 relocated_address - coff_section.virtual_address,
1681 ) orelse "???";1739 ) orelse "???";
1682 const opt_line_info = try self.debug_data.pdb.getLineNumberInfo(1740 const opt_line_info = try self.debug_data.pdb.getLineNumberInfo(
1683 module,1741 module,
1684 relocated_address - coff_section.header.virtual_address,1742 relocated_address - coff_section.virtual_address,
1685 );1743 );
16861744
1687 return SymbolInfo{1745 return SymbolInfo{
...@@ -1727,7 +1785,7 @@ fn getSymbolFromDwarf(allocator: mem.Allocator, address: u64, di: *DW.DwarfInfo)...@@ -1727,7 +1785,7 @@ fn getSymbolFromDwarf(allocator: mem.Allocator, address: u64, di: *DW.DwarfInfo)
1727 if (nosuspend di.findCompileUnit(address)) |compile_unit| {1785 if (nosuspend di.findCompileUnit(address)) |compile_unit| {
1728 return SymbolInfo{1786 return SymbolInfo{
1729 .symbol_name = nosuspend di.getSymbolName(address) orelse "???",1787 .symbol_name = nosuspend di.getSymbolName(address) orelse "???",
1730 .compile_unit_name = compile_unit.die.getAttrString(di, DW.AT.name) catch |err| switch (err) {1788 .compile_unit_name = compile_unit.die.getAttrString(di, DW.AT.name, di.debug_str, compile_unit.*) catch |err| switch (err) {
1731 error.MissingDebugInfo, error.InvalidDebugInfo => "???",1789 error.MissingDebugInfo, error.InvalidDebugInfo => "???",
1732 },1790 },
1733 .line_info = nosuspend di.getLineNumberInfo(allocator, compile_unit.*, address) catch |err| switch (err) {1791 .line_info = nosuspend di.getLineNumberInfo(allocator, compile_unit.*, address) catch |err| switch (err) {
...@@ -1816,7 +1874,7 @@ fn resetSegfaultHandler() void {...@@ -1816,7 +1874,7 @@ fn resetSegfaultHandler() void {
1816 return;1874 return;
1817 }1875 }
1818 var act = os.Sigaction{1876 var act = os.Sigaction{
1819 .handler = .{ .sigaction = os.SIG.DFL },1877 .handler = .{ .handler = os.SIG.DFL },
1820 .mask = os.empty_sigset,1878 .mask = os.empty_sigset,
1821 .flags = 0,1879 .flags = 0,
1822 };1880 };
...@@ -1976,7 +2034,7 @@ noinline fn showMyTrace() usize {...@@ -1976,7 +2034,7 @@ noinline fn showMyTrace() usize {
1976/// For more advanced usage, see `ConfigurableTrace`.2034/// For more advanced usage, see `ConfigurableTrace`.
1977pub const Trace = ConfigurableTrace(2, 4, builtin.mode == .Debug);2035pub const Trace = ConfigurableTrace(2, 4, builtin.mode == .Debug);
19782036
1979pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize, comptime enabled: bool) type {2037pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize, comptime is_enabled: bool) type {
1980 return struct {2038 return struct {
1981 addrs: [actual_size][stack_frame_count]usize = undefined,2039 addrs: [actual_size][stack_frame_count]usize = undefined,
1982 notes: [actual_size][]const u8 = undefined,2040 notes: [actual_size][]const u8 = undefined,
...@@ -1985,7 +2043,7 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize...@@ -1985,7 +2043,7 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize
1985 const actual_size = if (enabled) size else 0;2043 const actual_size = if (enabled) size else 0;
1986 const Index = if (enabled) usize else u0;2044 const Index = if (enabled) usize else u0;
19872045
1988 pub const enabled = enabled;2046 pub const enabled = is_enabled;
19892047
1990 pub const add = if (enabled) addNoInline else addNoOp;2048 pub const add = if (enabled) addNoInline else addNoOp;
19912049
lib/std/dwarf.zig+383-156
...@@ -168,6 +168,11 @@ const CompileUnit = struct {...@@ -168,6 +168,11 @@ const CompileUnit = struct {
168 is_64: bool,168 is_64: bool,
169 die: *Die,169 die: *Die,
170 pc_range: ?PcRange,170 pc_range: ?PcRange,
171
172 str_offsets_base: usize,
173 addr_base: usize,
174 rnglists_base: usize,
175 loclists_base: usize,
171};176};
172177
173const AbbrevTable = std.ArrayList(AbbrevTableEntry);178const AbbrevTable = std.ArrayList(AbbrevTableEntry);
...@@ -205,6 +210,7 @@ const AbbrevAttr = struct {...@@ -205,6 +210,7 @@ const AbbrevAttr = struct {
205210
206const FormValue = union(enum) {211const FormValue = union(enum) {
207 Address: u64,212 Address: u64,
213 AddrOffset: usize,
208 Block: []u8,214 Block: []u8,
209 Const: Constant,215 Const: Constant,
210 ExprLoc: []u8,216 ExprLoc: []u8,
...@@ -214,15 +220,46 @@ const FormValue = union(enum) {...@@ -214,15 +220,46 @@ const FormValue = union(enum) {
214 RefAddr: u64,220 RefAddr: u64,
215 String: []const u8,221 String: []const u8,
216 StrPtr: u64,222 StrPtr: u64,
223 StrOffset: usize,
217 LineStrPtr: u64,224 LineStrPtr: u64,
225 LocListOffset: u64,
226 RangeListOffset: u64,
227 data16: [16]u8,
228
229 fn getString(fv: FormValue, di: DwarfInfo) ![]const u8 {
230 switch (fv) {
231 .String => |s| return s,
232 .StrPtr => |off| return di.getString(off),
233 .LineStrPtr => |off| return di.getLineString(off),
234 else => return badDwarf(),
235 }
236 }
237
238 fn getUInt(fv: FormValue, comptime U: type) !U {
239 switch (fv) {
240 .Const => |c| {
241 const int = try c.asUnsignedLe();
242 return math.cast(U, int) orelse return badDwarf();
243 },
244 .SecOffset => |x| return math.cast(U, x) orelse return badDwarf(),
245 else => return badDwarf(),
246 }
247 }
248
249 fn getData16(fv: FormValue) ![16]u8 {
250 switch (fv) {
251 .data16 => |d| return d,
252 else => return badDwarf(),
253 }
254 }
218};255};
219256
220const Constant = struct {257const Constant = struct {
221 payload: u64,258 payload: u64,
222 signed: bool,259 signed: bool,
223260
224 fn asUnsignedLe(self: *const Constant) !u64 {261 fn asUnsignedLe(self: Constant) !u64 {
225 if (self.signed) return error.InvalidDebugInfo;262 if (self.signed) return badDwarf();
226 return self.payload;263 return self.payload;
227 }264 }
228};265};
...@@ -251,21 +288,46 @@ const Die = struct {...@@ -251,21 +288,46 @@ const Die = struct {
251 return null;288 return null;
252 }289 }
253290
254 fn getAttrAddr(self: *const Die, id: u64) !u64 {291 fn getAttrAddr(
292 self: *const Die,
293 di: *DwarfInfo,
294 id: u64,
295 compile_unit: CompileUnit,
296 ) error{ InvalidDebugInfo, MissingDebugInfo }!u64 {
255 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;297 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
256 return switch (form_value.*) {298 return switch (form_value.*) {
257 FormValue.Address => |value| value,299 FormValue.Address => |value| value,
300 FormValue.AddrOffset => |index| {
301 const debug_addr = di.debug_addr orelse return badDwarf();
302 // addr_base points to the first item after the header, however we
303 // need to read the header to know the size of each item. Empirically,
304 // it may disagree with is_64 on the compile unit.
305 // The header is 8 or 12 bytes depending on is_64.
306 if (compile_unit.addr_base < 8) return badDwarf();
307
308 const version = mem.readInt(u16, debug_addr[compile_unit.addr_base - 4 ..][0..2], di.endian);
309 if (version != 5) return badDwarf();
310
311 const addr_size = debug_addr[compile_unit.addr_base - 2];
312 const seg_size = debug_addr[compile_unit.addr_base - 1];
313
314 const byte_offset = compile_unit.addr_base + (addr_size + seg_size) * index;
315 if (byte_offset + addr_size > debug_addr.len) return badDwarf();
316 switch (addr_size) {
317 1 => return debug_addr[byte_offset],
318 2 => return mem.readInt(u16, debug_addr[byte_offset..][0..2], di.endian),
319 4 => return mem.readInt(u32, debug_addr[byte_offset..][0..4], di.endian),
320 8 => return mem.readInt(u64, debug_addr[byte_offset..][0..8], di.endian),
321 else => return badDwarf(),
322 }
323 },
258 else => error.InvalidDebugInfo,324 else => error.InvalidDebugInfo,
259 };325 };
260 }326 }
261327
262 fn getAttrSecOffset(self: *const Die, id: u64) !u64 {328 fn getAttrSecOffset(self: *const Die, id: u64) !u64 {
263 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;329 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
264 return switch (form_value.*) {330 return form_value.getUInt(u64);
265 FormValue.Const => |value| value.asUnsignedLe(),
266 FormValue.SecOffset => |value| value,
267 else => error.InvalidDebugInfo,
268 };
269 }331 }
270332
271 fn getAttrUnsignedLe(self: *const Die, id: u64) !u64 {333 fn getAttrUnsignedLe(self: *const Die, id: u64) !u64 {
...@@ -284,22 +346,44 @@ const Die = struct {...@@ -284,22 +346,44 @@ const Die = struct {
284 };346 };
285 }347 }
286348
287 pub fn getAttrString(self: *const Die, di: *DwarfInfo, id: u64) ![]const u8 {349 pub fn getAttrString(
350 self: *const Die,
351 di: *DwarfInfo,
352 id: u64,
353 opt_str: ?[]const u8,
354 compile_unit: CompileUnit,
355 ) error{ InvalidDebugInfo, MissingDebugInfo }![]const u8 {
288 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;356 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
289 return switch (form_value.*) {357 switch (form_value.*) {
290 FormValue.String => |value| value,358 FormValue.String => |value| return value,
291 FormValue.StrPtr => |offset| di.getString(offset),359 FormValue.StrPtr => |offset| return di.getString(offset),
292 FormValue.LineStrPtr => |offset| di.getLineString(offset),360 FormValue.StrOffset => |index| {
293 else => error.InvalidDebugInfo,361 const debug_str_offsets = di.debug_str_offsets orelse return badDwarf();
294 };362 if (compile_unit.str_offsets_base == 0) return badDwarf();
363 if (compile_unit.is_64) {
364 const byte_offset = compile_unit.str_offsets_base + 8 * index;
365 if (byte_offset + 8 > debug_str_offsets.len) return badDwarf();
366 const offset = mem.readInt(u64, debug_str_offsets[byte_offset..][0..8], di.endian);
367 return getStringGeneric(opt_str, offset);
368 } else {
369 const byte_offset = compile_unit.str_offsets_base + 4 * index;
370 if (byte_offset + 4 > debug_str_offsets.len) return badDwarf();
371 const offset = mem.readInt(u32, debug_str_offsets[byte_offset..][0..4], di.endian);
372 return getStringGeneric(opt_str, offset);
373 }
374 },
375 FormValue.LineStrPtr => |offset| return di.getLineString(offset),
376 else => return badDwarf(),
377 }
295 }378 }
296};379};
297380
298const FileEntry = struct {381const FileEntry = struct {
299 file_name: []const u8,382 path: []const u8,
300 dir_index: usize,383 dir_index: u32 = 0,
301 mtime: usize,384 mtime: u64 = 0,
302 len_bytes: usize,385 size: u64 = 0,
386 md5: [16]u8 = [1]u8{0} ** 16,
303};387};
304388
305const LineNumberProgram = struct {389const LineNumberProgram = struct {
...@@ -307,13 +391,14 @@ const LineNumberProgram = struct {...@@ -307,13 +391,14 @@ const LineNumberProgram = struct {
307 file: usize,391 file: usize,
308 line: i64,392 line: i64,
309 column: u64,393 column: u64,
394 version: u16,
310 is_stmt: bool,395 is_stmt: bool,
311 basic_block: bool,396 basic_block: bool,
312 end_sequence: bool,397 end_sequence: bool,
313398
314 default_is_stmt: bool,399 default_is_stmt: bool,
315 target_address: u64,400 target_address: u64,
316 include_dirs: []const []const u8,401 include_dirs: []const FileEntry,
317402
318 prev_valid: bool,403 prev_valid: bool,
319 prev_address: u64,404 prev_address: u64,
...@@ -344,12 +429,18 @@ const LineNumberProgram = struct {...@@ -344,12 +429,18 @@ const LineNumberProgram = struct {
344 self.prev_end_sequence = undefined;429 self.prev_end_sequence = undefined;
345 }430 }
346431
347 pub fn init(is_stmt: bool, include_dirs: []const []const u8, target_address: u64) LineNumberProgram {432 pub fn init(
433 is_stmt: bool,
434 include_dirs: []const FileEntry,
435 target_address: u64,
436 version: u16,
437 ) LineNumberProgram {
348 return LineNumberProgram{438 return LineNumberProgram{
349 .address = 0,439 .address = 0,
350 .file = 1,440 .file = 1,
351 .line = 1,441 .line = 1,
352 .column = 0,442 .column = 0,
443 .version = version,
353 .is_stmt = is_stmt,444 .is_stmt = is_stmt,
354 .basic_block = false,445 .basic_block = false,
355 .end_sequence = false,446 .end_sequence = false,
...@@ -372,18 +463,24 @@ const LineNumberProgram = struct {...@@ -372,18 +463,24 @@ const LineNumberProgram = struct {
372 allocator: mem.Allocator,463 allocator: mem.Allocator,
373 file_entries: []const FileEntry,464 file_entries: []const FileEntry,
374 ) !?debug.LineInfo {465 ) !?debug.LineInfo {
375 if (self.prev_valid and self.target_address >= self.prev_address and self.target_address < self.address) {466 if (self.prev_valid and
376 const file_entry = if (self.prev_file == 0) {467 self.target_address >= self.prev_address and
377 return error.MissingDebugInfo;468 self.target_address < self.address)
378 } else if (self.prev_file - 1 >= file_entries.len) {469 {
379 return error.InvalidDebugInfo;470 const file_index = if (self.version >= 5) self.prev_file else i: {
380 } else &file_entries[self.prev_file - 1];471 if (self.prev_file == 0) return missingDwarf();
472 break :i self.prev_file - 1;
473 };
381474
382 const dir_name = if (file_entry.dir_index >= self.include_dirs.len) {475 if (file_index >= file_entries.len) return badDwarf();
383 return error.InvalidDebugInfo;476 const file_entry = &file_entries[file_index];
384 } else self.include_dirs[file_entry.dir_index];
385477
386 const file_name = try fs.path.join(allocator, &[_][]const u8{ dir_name, file_entry.file_name });478 if (file_entry.dir_index >= self.include_dirs.len) return badDwarf();
479 const dir_name = self.include_dirs[file_entry.dir_index].path;
480
481 const file_name = try fs.path.join(allocator, &[_][]const u8{
482 dir_name, file_entry.path,
483 });
387484
388 return debug.LineInfo{485 return debug.LineInfo{
389 .line = if (self.prev_line >= 0) @intCast(u64, self.prev_line) else 0,486 .line = if (self.prev_line >= 0) @intCast(u64, self.prev_line) else 0,
...@@ -410,7 +507,7 @@ fn readUnitLength(in_stream: anytype, endian: std.builtin.Endian, is_64: *bool)...@@ -410,7 +507,7 @@ fn readUnitLength(in_stream: anytype, endian: std.builtin.Endian, is_64: *bool)
410 if (is_64.*) {507 if (is_64.*) {
411 return in_stream.readInt(u64, endian);508 return in_stream.readInt(u64, endian);
412 } else {509 } else {
413 if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;510 if (first_32_bits >= 0xfffffff0) return badDwarf();
414 // TODO this cast should not be needed511 // TODO this cast should not be needed
415 return @as(u64, first_32_bits);512 return @as(u64, first_32_bits);
416 }513 }
...@@ -487,6 +584,12 @@ fn parseFormValueRef(in_stream: anytype, endian: std.builtin.Endian, size: i32)...@@ -487,6 +584,12 @@ fn parseFormValueRef(in_stream: anytype, endian: std.builtin.Endian, size: i32)
487fn parseFormValue(allocator: mem.Allocator, in_stream: anytype, form_id: u64, endian: std.builtin.Endian, is_64: bool) anyerror!FormValue {584fn parseFormValue(allocator: mem.Allocator, in_stream: anytype, form_id: u64, endian: std.builtin.Endian, is_64: bool) anyerror!FormValue {
488 return switch (form_id) {585 return switch (form_id) {
489 FORM.addr => FormValue{ .Address = try readAddress(in_stream, endian, @sizeOf(usize) == 8) },586 FORM.addr => FormValue{ .Address = try readAddress(in_stream, endian, @sizeOf(usize) == 8) },
587 FORM.addrx1 => return FormValue{ .AddrOffset = try in_stream.readInt(u8, endian) },
588 FORM.addrx2 => return FormValue{ .AddrOffset = try in_stream.readInt(u16, endian) },
589 FORM.addrx3 => return FormValue{ .AddrOffset = try in_stream.readInt(u24, endian) },
590 FORM.addrx4 => return FormValue{ .AddrOffset = try in_stream.readInt(u32, endian) },
591 FORM.addrx => return FormValue{ .AddrOffset = try nosuspend leb.readULEB128(usize, in_stream) },
592
490 FORM.block1 => parseFormValueBlock(allocator, in_stream, endian, 1),593 FORM.block1 => parseFormValueBlock(allocator, in_stream, endian, 1),
491 FORM.block2 => parseFormValueBlock(allocator, in_stream, endian, 2),594 FORM.block2 => parseFormValueBlock(allocator, in_stream, endian, 2),
492 FORM.block4 => parseFormValueBlock(allocator, in_stream, endian, 4),595 FORM.block4 => parseFormValueBlock(allocator, in_stream, endian, 4),
...@@ -498,6 +601,11 @@ fn parseFormValue(allocator: mem.Allocator, in_stream: anytype, form_id: u64, en...@@ -498,6 +601,11 @@ fn parseFormValue(allocator: mem.Allocator, in_stream: anytype, form_id: u64, en
498 FORM.data2 => parseFormValueConstant(in_stream, false, endian, 2),601 FORM.data2 => parseFormValueConstant(in_stream, false, endian, 2),
499 FORM.data4 => parseFormValueConstant(in_stream, false, endian, 4),602 FORM.data4 => parseFormValueConstant(in_stream, false, endian, 4),
500 FORM.data8 => parseFormValueConstant(in_stream, false, endian, 8),603 FORM.data8 => parseFormValueConstant(in_stream, false, endian, 8),
604 FORM.data16 => {
605 var buf: [16]u8 = undefined;
606 if ((try nosuspend in_stream.readAll(&buf)) < 16) return error.EndOfFile;
607 return FormValue{ .data16 = buf };
608 },
501 FORM.udata, FORM.sdata => {609 FORM.udata, FORM.sdata => {
502 const signed = form_id == FORM.sdata;610 const signed = form_id == FORM.sdata;
503 return parseFormValueConstant(in_stream, signed, endian, -1);611 return parseFormValueConstant(in_stream, signed, endian, -1);
...@@ -522,6 +630,11 @@ fn parseFormValue(allocator: mem.Allocator, in_stream: anytype, form_id: u64, en...@@ -522,6 +630,11 @@ fn parseFormValue(allocator: mem.Allocator, in_stream: anytype, form_id: u64, en
522630
523 FORM.string => FormValue{ .String = try in_stream.readUntilDelimiterAlloc(allocator, 0, math.maxInt(usize)) },631 FORM.string => FormValue{ .String = try in_stream.readUntilDelimiterAlloc(allocator, 0, math.maxInt(usize)) },
524 FORM.strp => FormValue{ .StrPtr = try readAddress(in_stream, endian, is_64) },632 FORM.strp => FormValue{ .StrPtr = try readAddress(in_stream, endian, is_64) },
633 FORM.strx1 => return FormValue{ .StrOffset = try in_stream.readInt(u8, endian) },
634 FORM.strx2 => return FormValue{ .StrOffset = try in_stream.readInt(u16, endian) },
635 FORM.strx3 => return FormValue{ .StrOffset = try in_stream.readInt(u24, endian) },
636 FORM.strx4 => return FormValue{ .StrOffset = try in_stream.readInt(u32, endian) },
637 FORM.strx => return FormValue{ .StrOffset = try nosuspend leb.readULEB128(usize, in_stream) },
525 FORM.line_strp => FormValue{ .LineStrPtr = try readAddress(in_stream, endian, is_64) },638 FORM.line_strp => FormValue{ .LineStrPtr = try readAddress(in_stream, endian, is_64) },
526 FORM.indirect => {639 FORM.indirect => {
527 const child_form_id = try nosuspend leb.readULEB128(u64, in_stream);640 const child_form_id = try nosuspend leb.readULEB128(u64, in_stream);
...@@ -534,9 +647,11 @@ fn parseFormValue(allocator: mem.Allocator, in_stream: anytype, form_id: u64, en...@@ -534,9 +647,11 @@ fn parseFormValue(allocator: mem.Allocator, in_stream: anytype, form_id: u64, en
534 return await @asyncCall(frame, {}, parseFormValue, .{ allocator, in_stream, child_form_id, endian, is_64 });647 return await @asyncCall(frame, {}, parseFormValue, .{ allocator, in_stream, child_form_id, endian, is_64 });
535 },648 },
536 FORM.implicit_const => FormValue{ .Const = Constant{ .signed = true, .payload = undefined } },649 FORM.implicit_const => FormValue{ .Const = Constant{ .signed = true, .payload = undefined } },
537650 FORM.loclistx => return FormValue{ .LocListOffset = try nosuspend leb.readULEB128(u64, in_stream) },
651 FORM.rnglistx => return FormValue{ .RangeListOffset = try nosuspend leb.readULEB128(u64, in_stream) },
538 else => {652 else => {
539 return error.InvalidDebugInfo;653 //std.debug.print("unrecognized form id: {x}\n", .{form_id});
654 return badDwarf();
540 },655 },
541 };656 };
542}657}
...@@ -554,9 +669,15 @@ pub const DwarfInfo = struct {...@@ -554,9 +669,15 @@ pub const DwarfInfo = struct {
554 debug_info: []const u8,669 debug_info: []const u8,
555 debug_abbrev: []const u8,670 debug_abbrev: []const u8,
556 debug_str: []const u8,671 debug_str: []const u8,
672 debug_str_offsets: ?[]const u8,
557 debug_line: []const u8,673 debug_line: []const u8,
558 debug_line_str: ?[]const u8,674 debug_line_str: ?[]const u8,
559 debug_ranges: ?[]const u8,675 debug_ranges: ?[]const u8,
676 debug_loclists: ?[]const u8,
677 debug_rnglists: ?[]const u8,
678 debug_addr: ?[]const u8,
679 debug_names: ?[]const u8,
680 debug_frame: ?[]const u8,
560 // Filled later by the initializer681 // Filled later by the initializer
561 abbrev_table_list: std.ArrayListUnmanaged(AbbrevTableHeader) = .{},682 abbrev_table_list: std.ArrayListUnmanaged(AbbrevTableHeader) = .{},
562 compile_unit_list: std.ArrayListUnmanaged(CompileUnit) = .{},683 compile_unit_list: std.ArrayListUnmanaged(CompileUnit) = .{},
...@@ -592,7 +713,7 @@ pub const DwarfInfo = struct {...@@ -592,7 +713,7 @@ pub const DwarfInfo = struct {
592713
593 fn scanAllFunctions(di: *DwarfInfo, allocator: mem.Allocator) !void {714 fn scanAllFunctions(di: *DwarfInfo, allocator: mem.Allocator) !void {
594 var stream = io.fixedBufferStream(di.debug_info);715 var stream = io.fixedBufferStream(di.debug_info);
595 const in = &stream.reader();716 const in = stream.reader();
596 const seekable = &stream.seekableStream();717 const seekable = &stream.seekableStream();
597 var this_unit_offset: u64 = 0;718 var this_unit_offset: u64 = 0;
598719
...@@ -609,29 +730,26 @@ pub const DwarfInfo = struct {...@@ -609,29 +730,26 @@ pub const DwarfInfo = struct {
609 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));730 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
610731
611 const version = try in.readInt(u16, di.endian);732 const version = try in.readInt(u16, di.endian);
612 if (version < 2 or version > 5) return error.InvalidDebugInfo;733 if (version < 2 or version > 5) return badDwarf();
613734
614 var address_size: u8 = undefined;735 var address_size: u8 = undefined;
615 var debug_abbrev_offset: u64 = undefined;736 var debug_abbrev_offset: u64 = undefined;
616 switch (version) {737 if (version >= 5) {
617 5 => {738 const unit_type = try in.readInt(u8, di.endian);
618 const unit_type = try in.readInt(u8, di.endian);739 if (unit_type != UT.compile) return badDwarf();
619 if (unit_type != UT.compile) return error.InvalidDebugInfo;740 address_size = try in.readByte();
620 address_size = try in.readByte();741 debug_abbrev_offset = if (is_64)
621 debug_abbrev_offset = if (is_64)742 try in.readInt(u64, di.endian)
622 try in.readInt(u64, di.endian)743 else
623 else744 try in.readInt(u32, di.endian);
624 try in.readInt(u32, di.endian);745 } else {
625 },746 debug_abbrev_offset = if (is_64)
626 else => {747 try in.readInt(u64, di.endian)
627 debug_abbrev_offset = if (is_64)748 else
628 try in.readInt(u64, di.endian)749 try in.readInt(u32, di.endian);
629 else750 address_size = try in.readByte();
630 try in.readInt(u32, di.endian);
631 address_size = try in.readByte();
632 },
633 }751 }
634 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;752 if (address_size != @sizeOf(usize)) return badDwarf();
635753
636 const compile_unit_pos = try seekable.getPos();754 const compile_unit_pos = try seekable.getPos();
637 const abbrev_table = try di.getAbbrevTable(allocator, debug_abbrev_offset);755 const abbrev_table = try di.getAbbrevTable(allocator, debug_abbrev_offset);
...@@ -640,11 +758,26 @@ pub const DwarfInfo = struct {...@@ -640,11 +758,26 @@ pub const DwarfInfo = struct {
640758
641 const next_unit_pos = this_unit_offset + next_offset;759 const next_unit_pos = this_unit_offset + next_offset;
642760
761 var compile_unit: CompileUnit = undefined;
762
643 while ((try seekable.getPos()) < next_unit_pos) {763 while ((try seekable.getPos()) < next_unit_pos) {
644 const die_obj = (try di.parseDie(arena, in, abbrev_table, is_64)) orelse continue;764 var die_obj = (try di.parseDie(arena, in, abbrev_table, is_64)) orelse continue;
645 const after_die_offset = try seekable.getPos();765 const after_die_offset = try seekable.getPos();
646766
647 switch (die_obj.tag_id) {767 switch (die_obj.tag_id) {
768 TAG.compile_unit => {
769 compile_unit = .{
770 .version = version,
771 .is_64 = is_64,
772 .die = &die_obj,
773 .pc_range = null,
774
775 .str_offsets_base = if (die_obj.getAttr(AT.str_offsets_base)) |fv| try fv.getUInt(usize) else 0,
776 .addr_base = if (die_obj.getAttr(AT.addr_base)) |fv| try fv.getUInt(usize) else 0,
777 .rnglists_base = if (die_obj.getAttr(AT.rnglists_base)) |fv| try fv.getUInt(usize) else 0,
778 .loclists_base = if (die_obj.getAttr(AT.loclists_base)) |fv| try fv.getUInt(usize) else 0,
779 };
780 },
648 TAG.subprogram, TAG.inlined_subroutine, TAG.subroutine, TAG.entry_point => {781 TAG.subprogram, TAG.inlined_subroutine, TAG.subroutine, TAG.entry_point => {
649 const fn_name = x: {782 const fn_name = x: {
650 var depth: i32 = 3;783 var depth: i32 = 3;
...@@ -652,30 +785,30 @@ pub const DwarfInfo = struct {...@@ -652,30 +785,30 @@ pub const DwarfInfo = struct {
652 // Prevent endless loops785 // Prevent endless loops
653 while (depth > 0) : (depth -= 1) {786 while (depth > 0) : (depth -= 1) {
654 if (this_die_obj.getAttr(AT.name)) |_| {787 if (this_die_obj.getAttr(AT.name)) |_| {
655 const name = try this_die_obj.getAttrString(di, AT.name);788 const name = try this_die_obj.getAttrString(di, AT.name, di.debug_str, compile_unit);
656 break :x try allocator.dupe(u8, name);789 break :x try allocator.dupe(u8, name);
657 } else if (this_die_obj.getAttr(AT.abstract_origin)) |_| {790 } else if (this_die_obj.getAttr(AT.abstract_origin)) |_| {
658 // Follow the DIE it points to and repeat791 // Follow the DIE it points to and repeat
659 const ref_offset = try this_die_obj.getAttrRef(AT.abstract_origin);792 const ref_offset = try this_die_obj.getAttrRef(AT.abstract_origin);
660 if (ref_offset > next_offset) return error.InvalidDebugInfo;793 if (ref_offset > next_offset) return badDwarf();
661 try seekable.seekTo(this_unit_offset + ref_offset);794 try seekable.seekTo(this_unit_offset + ref_offset);
662 this_die_obj = (try di.parseDie(795 this_die_obj = (try di.parseDie(
663 arena,796 arena,
664 in,797 in,
665 abbrev_table,798 abbrev_table,
666 is_64,799 is_64,
667 )) orelse return error.InvalidDebugInfo;800 )) orelse return badDwarf();
668 } else if (this_die_obj.getAttr(AT.specification)) |_| {801 } else if (this_die_obj.getAttr(AT.specification)) |_| {
669 // Follow the DIE it points to and repeat802 // Follow the DIE it points to and repeat
670 const ref_offset = try this_die_obj.getAttrRef(AT.specification);803 const ref_offset = try this_die_obj.getAttrRef(AT.specification);
671 if (ref_offset > next_offset) return error.InvalidDebugInfo;804 if (ref_offset > next_offset) return badDwarf();
672 try seekable.seekTo(this_unit_offset + ref_offset);805 try seekable.seekTo(this_unit_offset + ref_offset);
673 this_die_obj = (try di.parseDie(806 this_die_obj = (try di.parseDie(
674 arena,807 arena,
675 in,808 in,
676 abbrev_table,809 abbrev_table,
677 is_64,810 is_64,
678 )) orelse return error.InvalidDebugInfo;811 )) orelse return badDwarf();
679 } else {812 } else {
680 break :x null;813 break :x null;
681 }814 }
...@@ -685,7 +818,7 @@ pub const DwarfInfo = struct {...@@ -685,7 +818,7 @@ pub const DwarfInfo = struct {
685 };818 };
686819
687 const pc_range = x: {820 const pc_range = x: {
688 if (die_obj.getAttrAddr(AT.low_pc)) |low_pc| {821 if (die_obj.getAttrAddr(di, AT.low_pc, compile_unit)) |low_pc| {
689 if (die_obj.getAttr(AT.high_pc)) |high_pc_value| {822 if (die_obj.getAttr(AT.high_pc)) |high_pc_value| {
690 const pc_end = switch (high_pc_value.*) {823 const pc_end = switch (high_pc_value.*) {
691 FormValue.Address => |value| value,824 FormValue.Address => |value| value,
...@@ -693,7 +826,7 @@ pub const DwarfInfo = struct {...@@ -693,7 +826,7 @@ pub const DwarfInfo = struct {
693 const offset = try value.asUnsignedLe();826 const offset = try value.asUnsignedLe();
694 break :b (low_pc + offset);827 break :b (low_pc + offset);
695 },828 },
696 else => return error.InvalidDebugInfo,829 else => return badDwarf(),
697 };830 };
698 break :x PcRange{831 break :x PcRange{
699 .start = low_pc,832 .start = low_pc,
...@@ -738,29 +871,26 @@ pub const DwarfInfo = struct {...@@ -738,29 +871,26 @@ pub const DwarfInfo = struct {
738 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));871 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
739872
740 const version = try in.readInt(u16, di.endian);873 const version = try in.readInt(u16, di.endian);
741 if (version < 2 or version > 5) return error.InvalidDebugInfo;874 if (version < 2 or version > 5) return badDwarf();
742875
743 var address_size: u8 = undefined;876 var address_size: u8 = undefined;
744 var debug_abbrev_offset: u64 = undefined;877 var debug_abbrev_offset: u64 = undefined;
745 switch (version) {878 if (version >= 5) {
746 5 => {879 const unit_type = try in.readInt(u8, di.endian);
747 const unit_type = try in.readInt(u8, di.endian);880 if (unit_type != UT.compile) return badDwarf();
748 if (unit_type != UT.compile) return error.InvalidDebugInfo;881 address_size = try in.readByte();
749 address_size = try in.readByte();882 debug_abbrev_offset = if (is_64)
750 debug_abbrev_offset = if (is_64)883 try in.readInt(u64, di.endian)
751 try in.readInt(u64, di.endian)884 else
752 else885 try in.readInt(u32, di.endian);
753 try in.readInt(u32, di.endian);886 } else {
754 },887 debug_abbrev_offset = if (is_64)
755 else => {888 try in.readInt(u64, di.endian)
756 debug_abbrev_offset = if (is_64)889 else
757 try in.readInt(u64, di.endian)890 try in.readInt(u32, di.endian);
758 else891 address_size = try in.readByte();
759 try in.readInt(u32, di.endian);
760 address_size = try in.readByte();
761 },
762 }892 }
763 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;893 if (address_size != @sizeOf(usize)) return badDwarf();
764894
765 const compile_unit_pos = try seekable.getPos();895 const compile_unit_pos = try seekable.getPos();
766 const abbrev_table = try di.getAbbrevTable(allocator, debug_abbrev_offset);896 const abbrev_table = try di.getAbbrevTable(allocator, debug_abbrev_offset);
...@@ -770,12 +900,23 @@ pub const DwarfInfo = struct {...@@ -770,12 +900,23 @@ pub const DwarfInfo = struct {
770 const compile_unit_die = try allocator.create(Die);900 const compile_unit_die = try allocator.create(Die);
771 errdefer allocator.destroy(compile_unit_die);901 errdefer allocator.destroy(compile_unit_die);
772 compile_unit_die.* = (try di.parseDie(allocator, in, abbrev_table, is_64)) orelse902 compile_unit_die.* = (try di.parseDie(allocator, in, abbrev_table, is_64)) orelse
773 return error.InvalidDebugInfo;903 return badDwarf();
774904
775 if (compile_unit_die.tag_id != TAG.compile_unit) return error.InvalidDebugInfo;905 if (compile_unit_die.tag_id != TAG.compile_unit) return badDwarf();
776906
777 const pc_range = x: {907 var compile_unit: CompileUnit = .{
778 if (compile_unit_die.getAttrAddr(AT.low_pc)) |low_pc| {908 .version = version,
909 .is_64 = is_64,
910 .pc_range = null,
911 .die = compile_unit_die,
912 .str_offsets_base = if (compile_unit_die.getAttr(AT.str_offsets_base)) |fv| try fv.getUInt(usize) else 0,
913 .addr_base = if (compile_unit_die.getAttr(AT.addr_base)) |fv| try fv.getUInt(usize) else 0,
914 .rnglists_base = if (compile_unit_die.getAttr(AT.rnglists_base)) |fv| try fv.getUInt(usize) else 0,
915 .loclists_base = if (compile_unit_die.getAttr(AT.loclists_base)) |fv| try fv.getUInt(usize) else 0,
916 };
917
918 compile_unit.pc_range = x: {
919 if (compile_unit_die.getAttrAddr(di, AT.low_pc, compile_unit)) |low_pc| {
779 if (compile_unit_die.getAttr(AT.high_pc)) |high_pc_value| {920 if (compile_unit_die.getAttr(AT.high_pc)) |high_pc_value| {
780 const pc_end = switch (high_pc_value.*) {921 const pc_end = switch (high_pc_value.*) {
781 FormValue.Address => |value| value,922 FormValue.Address => |value| value,
...@@ -783,7 +924,7 @@ pub const DwarfInfo = struct {...@@ -783,7 +924,7 @@ pub const DwarfInfo = struct {
783 const offset = try value.asUnsignedLe();924 const offset = try value.asUnsignedLe();
784 break :b (low_pc + offset);925 break :b (low_pc + offset);
785 },926 },
786 else => return error.InvalidDebugInfo,927 else => return badDwarf(),
787 };928 };
788 break :x PcRange{929 break :x PcRange{
789 .start = low_pc,930 .start = low_pc,
...@@ -798,12 +939,7 @@ pub const DwarfInfo = struct {...@@ -798,12 +939,7 @@ pub const DwarfInfo = struct {
798 }939 }
799 };940 };
800941
801 try di.compile_unit_list.append(allocator, CompileUnit{942 try di.compile_unit_list.append(allocator, compile_unit);
802 .version = version,
803 .is_64 = is_64,
804 .pc_range = pc_range,
805 .die = compile_unit_die,
806 });
807943
808 this_unit_offset += next_offset;944 this_unit_offset += next_offset;
809 }945 }
...@@ -824,7 +960,7 @@ pub const DwarfInfo = struct {...@@ -824,7 +960,7 @@ pub const DwarfInfo = struct {
824 // specified by DW_AT.low_pc or to some other value encoded960 // specified by DW_AT.low_pc or to some other value encoded
825 // in the list itself.961 // in the list itself.
826 // If no starting value is specified use zero.962 // If no starting value is specified use zero.
827 var base_address = compile_unit.die.getAttrAddr(AT.low_pc) catch |err| switch (err) {963 var base_address = compile_unit.die.getAttrAddr(di, AT.low_pc, compile_unit.*) catch |err| switch (err) {
828 error.MissingDebugInfo => @as(u64, 0), // TODO https://github.com/ziglang/zig/issues/11135964 error.MissingDebugInfo => @as(u64, 0), // TODO https://github.com/ziglang/zig/issues/11135
829 else => return err,965 else => return err,
830 };966 };
...@@ -852,7 +988,7 @@ pub const DwarfInfo = struct {...@@ -852,7 +988,7 @@ pub const DwarfInfo = struct {
852 }988 }
853 }989 }
854 }990 }
855 return error.MissingDebugInfo;991 return missingDwarf();
856 }992 }
857993
858 /// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,994 /// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
...@@ -919,7 +1055,7 @@ pub const DwarfInfo = struct {...@@ -919,7 +1055,7 @@ pub const DwarfInfo = struct {
919 ) !?Die {1055 ) !?Die {
920 const abbrev_code = try leb.readULEB128(u64, in_stream);1056 const abbrev_code = try leb.readULEB128(u64, in_stream);
921 if (abbrev_code == 0) return null;1057 if (abbrev_code == 0) return null;
922 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;1058 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return badDwarf();
9231059
924 var result = Die{1060 var result = Die{
925 // Lives as long as the Die.1061 // Lives as long as the Die.
...@@ -956,7 +1092,7 @@ pub const DwarfInfo = struct {...@@ -956,7 +1092,7 @@ pub const DwarfInfo = struct {
956 const in = &stream.reader();1092 const in = &stream.reader();
957 const seekable = &stream.seekableStream();1093 const seekable = &stream.seekableStream();
9581094
959 const compile_unit_cwd = try compile_unit.die.getAttrString(di, AT.comp_dir);1095 const compile_unit_cwd = try compile_unit.die.getAttrString(di, AT.comp_dir, di.debug_line_str, compile_unit);
960 const line_info_offset = try compile_unit.die.getAttrSecOffset(AT.stmt_list);1096 const line_info_offset = try compile_unit.die.getAttrSecOffset(AT.stmt_list);
9611097
962 try seekable.seekTo(line_info_offset);1098 try seekable.seekTo(line_info_offset);
...@@ -964,18 +1100,25 @@ pub const DwarfInfo = struct {...@@ -964,18 +1100,25 @@ pub const DwarfInfo = struct {
964 var is_64: bool = undefined;1100 var is_64: bool = undefined;
965 const unit_length = try readUnitLength(in, di.endian, &is_64);1101 const unit_length = try readUnitLength(in, di.endian, &is_64);
966 if (unit_length == 0) {1102 if (unit_length == 0) {
967 return error.MissingDebugInfo;1103 return missingDwarf();
968 }1104 }
969 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));1105 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
9701106
971 const version = try in.readInt(u16, di.endian);1107 const version = try in.readInt(u16, di.endian);
972 if (version < 2 or version > 4) return error.InvalidDebugInfo;1108 if (version < 2) return badDwarf();
1109
1110 var addr_size: u8 = if (is_64) 8 else 4;
1111 var seg_size: u8 = 0;
1112 if (version >= 5) {
1113 addr_size = try in.readByte();
1114 seg_size = try in.readByte();
1115 }
9731116
974 const prologue_length = if (is_64) try in.readInt(u64, di.endian) else try in.readInt(u32, di.endian);1117 const prologue_length = if (is_64) try in.readInt(u64, di.endian) else try in.readInt(u32, di.endian);
975 const prog_start_offset = (try seekable.getPos()) + prologue_length;1118 const prog_start_offset = (try seekable.getPos()) + prologue_length;
9761119
977 const minimum_instruction_length = try in.readByte();1120 const minimum_instruction_length = try in.readByte();
978 if (minimum_instruction_length == 0) return error.InvalidDebugInfo;1121 if (minimum_instruction_length == 0) return badDwarf();
9791122
980 if (version >= 4) {1123 if (version >= 4) {
981 // maximum_operations_per_instruction1124 // maximum_operations_per_instruction
...@@ -986,7 +1129,7 @@ pub const DwarfInfo = struct {...@@ -986,7 +1129,7 @@ pub const DwarfInfo = struct {
986 const line_base = try in.readByteSigned();1129 const line_base = try in.readByteSigned();
9871130
988 const line_range = try in.readByte();1131 const line_range = try in.readByte();
989 if (line_range == 0) return error.InvalidDebugInfo;1132 if (line_range == 0) return badDwarf();
9901133
991 const opcode_base = try in.readByte();1134 const opcode_base = try in.readByte();
9921135
...@@ -1004,36 +1147,120 @@ pub const DwarfInfo = struct {...@@ -1004,36 +1147,120 @@ pub const DwarfInfo = struct {
1004 defer tmp_arena.deinit();1147 defer tmp_arena.deinit();
1005 const arena = tmp_arena.allocator();1148 const arena = tmp_arena.allocator();
10061149
1007 var include_directories = std.ArrayList([]const u8).init(arena);1150 var include_directories = std.ArrayList(FileEntry).init(arena);
1008 try include_directories.append(compile_unit_cwd);1151 var file_entries = std.ArrayList(FileEntry).init(arena);
10091152
1010 while (true) {1153 if (version < 5) {
1011 const dir = try in.readUntilDelimiterAlloc(arena, 0, math.maxInt(usize));1154 try include_directories.append(.{ .path = compile_unit_cwd });
1012 if (dir.len == 0) break;1155
1013 try include_directories.append(dir);1156 while (true) {
1157 const dir = try in.readUntilDelimiterAlloc(arena, 0, math.maxInt(usize));
1158 if (dir.len == 0) break;
1159 try include_directories.append(.{ .path = dir });
1160 }
1161
1162 while (true) {
1163 const file_name = try in.readUntilDelimiterAlloc(arena, 0, math.maxInt(usize));
1164 if (file_name.len == 0) break;
1165 const dir_index = try leb.readULEB128(u32, in);
1166 const mtime = try leb.readULEB128(u64, in);
1167 const size = try leb.readULEB128(u64, in);
1168 try file_entries.append(FileEntry{
1169 .path = file_name,
1170 .dir_index = dir_index,
1171 .mtime = mtime,
1172 .size = size,
1173 });
1174 }
1175 } else {
1176 const FileEntFmt = struct {
1177 content_type_code: u8,
1178 form_code: u16,
1179 };
1180 {
1181 var dir_ent_fmt_buf: [10]FileEntFmt = undefined;
1182 const directory_entry_format_count = try in.readByte();
1183 if (directory_entry_format_count > dir_ent_fmt_buf.len) return badDwarf();
1184 for (dir_ent_fmt_buf[0..directory_entry_format_count]) |*ent_fmt| {
1185 ent_fmt.* = .{
1186 .content_type_code = try leb.readULEB128(u8, in),
1187 .form_code = try leb.readULEB128(u16, in),
1188 };
1189 }
1190
1191 const directories_count = try leb.readULEB128(usize, in);
1192 try include_directories.ensureUnusedCapacity(directories_count);
1193 {
1194 var i: usize = 0;
1195 while (i < directories_count) : (i += 1) {
1196 var e: FileEntry = .{ .path = &.{} };
1197 for (dir_ent_fmt_buf[0..directory_entry_format_count]) |ent_fmt| {
1198 const form_value = try parseFormValue(
1199 arena,
1200 in,
1201 ent_fmt.form_code,
1202 di.endian,
1203 is_64,
1204 );
1205 switch (ent_fmt.content_type_code) {
1206 LNCT.path => e.path = try form_value.getString(di.*),
1207 LNCT.directory_index => e.dir_index = try form_value.getUInt(u32),
1208 LNCT.timestamp => e.mtime = try form_value.getUInt(u64),
1209 LNCT.size => e.size = try form_value.getUInt(u64),
1210 LNCT.MD5 => e.md5 = try form_value.getData16(),
1211 else => continue,
1212 }
1213 }
1214 include_directories.appendAssumeCapacity(e);
1215 }
1216 }
1217 }
1218
1219 var file_ent_fmt_buf: [10]FileEntFmt = undefined;
1220 const file_name_entry_format_count = try in.readByte();
1221 if (file_name_entry_format_count > file_ent_fmt_buf.len) return badDwarf();
1222 for (file_ent_fmt_buf[0..file_name_entry_format_count]) |*ent_fmt| {
1223 ent_fmt.* = .{
1224 .content_type_code = try leb.readULEB128(u8, in),
1225 .form_code = try leb.readULEB128(u16, in),
1226 };
1227 }
1228
1229 const file_names_count = try leb.readULEB128(usize, in);
1230 try file_entries.ensureUnusedCapacity(file_names_count);
1231 {
1232 var i: usize = 0;
1233 while (i < file_names_count) : (i += 1) {
1234 var e: FileEntry = .{ .path = &.{} };
1235 for (file_ent_fmt_buf[0..file_name_entry_format_count]) |ent_fmt| {
1236 const form_value = try parseFormValue(
1237 arena,
1238 in,
1239 ent_fmt.form_code,
1240 di.endian,
1241 is_64,
1242 );
1243 switch (ent_fmt.content_type_code) {
1244 LNCT.path => e.path = try form_value.getString(di.*),
1245 LNCT.directory_index => e.dir_index = try form_value.getUInt(u32),
1246 LNCT.timestamp => e.mtime = try form_value.getUInt(u64),
1247 LNCT.size => e.size = try form_value.getUInt(u64),
1248 LNCT.MD5 => e.md5 = try form_value.getData16(),
1249 else => continue,
1250 }
1251 }
1252 file_entries.appendAssumeCapacity(e);
1253 }
1254 }
1014 }1255 }
10151256
1016 var file_entries = std.ArrayList(FileEntry).init(arena);
1017 var prog = LineNumberProgram.init(1257 var prog = LineNumberProgram.init(
1018 default_is_stmt,1258 default_is_stmt,
1019 include_directories.items,1259 include_directories.items,
1020 target_address,1260 target_address,
1261 version,
1021 );1262 );
10221263
1023 while (true) {
1024 const file_name = try in.readUntilDelimiterAlloc(arena, 0, math.maxInt(usize));
1025 if (file_name.len == 0) break;
1026 const dir_index = try leb.readULEB128(usize, in);
1027 const mtime = try leb.readULEB128(usize, in);
1028 const len_bytes = try leb.readULEB128(usize, in);
1029 try file_entries.append(FileEntry{
1030 .file_name = file_name,
1031 .dir_index = dir_index,
1032 .mtime = mtime,
1033 .len_bytes = len_bytes,
1034 });
1035 }
1036
1037 try seekable.seekTo(prog_start_offset);1264 try seekable.seekTo(prog_start_offset);
10381265
1039 const next_unit_pos = line_info_offset + next_offset;1266 const next_unit_pos = line_info_offset + next_offset;
...@@ -1043,7 +1270,7 @@ pub const DwarfInfo = struct {...@@ -1043,7 +1270,7 @@ pub const DwarfInfo = struct {
10431270
1044 if (opcode == LNS.extended_op) {1271 if (opcode == LNS.extended_op) {
1045 const op_size = try leb.readULEB128(u64, in);1272 const op_size = try leb.readULEB128(u64, in);
1046 if (op_size < 1) return error.InvalidDebugInfo;1273 if (op_size < 1) return badDwarf();
1047 var sub_op = try in.readByte();1274 var sub_op = try in.readByte();
1048 switch (sub_op) {1275 switch (sub_op) {
1049 LNE.end_sequence => {1276 LNE.end_sequence => {
...@@ -1056,19 +1283,19 @@ pub const DwarfInfo = struct {...@@ -1056,19 +1283,19 @@ pub const DwarfInfo = struct {
1056 prog.address = addr;1283 prog.address = addr;
1057 },1284 },
1058 LNE.define_file => {1285 LNE.define_file => {
1059 const file_name = try in.readUntilDelimiterAlloc(arena, 0, math.maxInt(usize));1286 const path = try in.readUntilDelimiterAlloc(arena, 0, math.maxInt(usize));
1060 const dir_index = try leb.readULEB128(usize, in);1287 const dir_index = try leb.readULEB128(u32, in);
1061 const mtime = try leb.readULEB128(usize, in);1288 const mtime = try leb.readULEB128(u64, in);
1062 const len_bytes = try leb.readULEB128(usize, in);1289 const size = try leb.readULEB128(u64, in);
1063 try file_entries.append(FileEntry{1290 try file_entries.append(FileEntry{
1064 .file_name = file_name,1291 .path = path,
1065 .dir_index = dir_index,1292 .dir_index = dir_index,
1066 .mtime = mtime,1293 .mtime = mtime,
1067 .len_bytes = len_bytes,1294 .size = size,
1068 });1295 });
1069 },1296 },
1070 else => {1297 else => {
1071 const fwd_amt = math.cast(isize, op_size - 1) orelse return error.InvalidDebugInfo;1298 const fwd_amt = math.cast(isize, op_size - 1) orelse return badDwarf();
1072 try seekable.seekBy(fwd_amt);1299 try seekable.seekBy(fwd_amt);
1073 },1300 },
1074 }1301 }
...@@ -1119,7 +1346,7 @@ pub const DwarfInfo = struct {...@@ -1119,7 +1346,7 @@ pub const DwarfInfo = struct {
1119 },1346 },
1120 LNS.set_prologue_end => {},1347 LNS.set_prologue_end => {},
1121 else => {1348 else => {
1122 if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;1349 if (opcode - 1 >= standard_opcode_lengths.len) return badDwarf();
1123 const len_bytes = standard_opcode_lengths[opcode - 1];1350 const len_bytes = standard_opcode_lengths[opcode - 1];
1124 try seekable.seekBy(len_bytes);1351 try seekable.seekBy(len_bytes);
1125 },1352 },
...@@ -1127,36 +1354,15 @@ pub const DwarfInfo = struct {...@@ -1127,36 +1354,15 @@ pub const DwarfInfo = struct {
1127 }1354 }
1128 }1355 }
11291356
1130 return error.MissingDebugInfo;1357 return missingDwarf();
1131 }1358 }
11321359
1133 fn getString(di: *DwarfInfo, offset: u64) ![]const u8 {1360 fn getString(di: DwarfInfo, offset: u64) ![]const u8 {
1134 if (offset > di.debug_str.len)1361 return getStringGeneric(di.debug_str, offset);
1135 return error.InvalidDebugInfo;
1136 const casted_offset = math.cast(usize, offset) orelse
1137 return error.InvalidDebugInfo;
1138
1139 // Valid strings always have a terminating zero byte
1140 if (mem.indexOfScalarPos(u8, di.debug_str, casted_offset, 0)) |last| {
1141 return di.debug_str[casted_offset..last];
1142 }
1143
1144 return error.InvalidDebugInfo;
1145 }1362 }
11461363
1147 fn getLineString(di: *DwarfInfo, offset: u64) ![]const u8 {1364 fn getLineString(di: DwarfInfo, offset: u64) ![]const u8 {
1148 const debug_line_str = di.debug_line_str orelse return error.InvalidDebugInfo;1365 return getStringGeneric(di.debug_line_str, offset);
1149 if (offset > debug_line_str.len)
1150 return error.InvalidDebugInfo;
1151 const casted_offset = math.cast(usize, offset) orelse
1152 return error.InvalidDebugInfo;
1153
1154 // Valid strings always have a terminating zero byte
1155 if (mem.indexOfScalarPos(u8, debug_line_str, casted_offset, 0)) |last| {
1156 return debug_line_str[casted_offset..last];
1157 }
1158
1159 return error.InvalidDebugInfo;
1160 }1366 }
1161};1367};
11621368
...@@ -1166,3 +1372,24 @@ pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: mem.Allocator) !void {...@@ -1166,3 +1372,24 @@ pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: mem.Allocator) !void {
1166 try di.scanAllFunctions(allocator);1372 try di.scanAllFunctions(allocator);
1167 try di.scanAllCompileUnits(allocator);1373 try di.scanAllCompileUnits(allocator);
1168}1374}
1375
1376/// This function is to make it handy to comment out the return and make it
1377/// into a crash when working on this file.
1378fn badDwarf() error{InvalidDebugInfo} {
1379 //std.os.abort(); // can be handy to uncomment when working on this file
1380 return error.InvalidDebugInfo;
1381}
1382
1383fn missingDwarf() error{MissingDebugInfo} {
1384 //std.os.abort(); // can be handy to uncomment when working on this file
1385 return error.MissingDebugInfo;
1386}
1387
1388fn getStringGeneric(opt_str: ?[]const u8, offset: u64) ![:0]const u8 {
1389 const str = opt_str orelse return badDwarf();
1390 if (offset > str.len) return badDwarf();
1391 const casted_offset = math.cast(usize, offset) orelse return badDwarf();
1392 // Valid strings always have a terminating zero byte
1393 const last = mem.indexOfScalarPos(u8, str, casted_offset, 0) orelse return badDwarf();
1394 return str[casted_offset..last :0];
1395}
lib/std/elf.zig+12-12
...@@ -3,7 +3,7 @@ const io = std.io;...@@ -3,7 +3,7 @@ const io = std.io;
3const os = std.os;3const os = std.os;
4const math = std.math;4const math = std.math;
5const mem = std.mem;5const mem = std.mem;
6const debug = std.debug;6const assert = std.debug.assert;
7const File = std.fs.File;7const File = std.fs.File;
8const native_endian = @import("builtin").target.cpu.arch.endian();8const native_endian = @import("builtin").target.cpu.arch.endian();
99
...@@ -387,7 +387,7 @@ pub const Header = struct {...@@ -387,7 +387,7 @@ pub const Header = struct {
387387
388 const machine = if (need_bswap) blk: {388 const machine = if (need_bswap) blk: {
389 const value = @enumToInt(hdr32.e_machine);389 const value = @enumToInt(hdr32.e_machine);
390 break :blk @intToEnum(EM, @byteSwap(@TypeOf(value), value));390 break :blk @intToEnum(EM, @byteSwap(value));
391 } else hdr32.e_machine;391 } else hdr32.e_machine;
392392
393 return @as(Header, .{393 return @as(Header, .{
...@@ -406,7 +406,7 @@ pub const Header = struct {...@@ -406,7 +406,7 @@ pub const Header = struct {
406 }406 }
407};407};
408408
409pub fn ProgramHeaderIterator(ParseSource: anytype) type {409pub fn ProgramHeaderIterator(comptime ParseSource: anytype) type {
410 return struct {410 return struct {
411 elf_header: Header,411 elf_header: Header,
412 parse_source: ParseSource,412 parse_source: ParseSource,
...@@ -456,7 +456,7 @@ pub fn ProgramHeaderIterator(ParseSource: anytype) type {...@@ -456,7 +456,7 @@ pub fn ProgramHeaderIterator(ParseSource: anytype) type {
456 };456 };
457}457}
458458
459pub fn SectionHeaderIterator(ParseSource: anytype) type {459pub fn SectionHeaderIterator(comptime ParseSource: anytype) type {
460 return struct {460 return struct {
461 elf_header: Header,461 elf_header: Header,
462 parse_source: ParseSource,462 parse_source: ParseSource,
...@@ -511,7 +511,7 @@ pub fn SectionHeaderIterator(ParseSource: anytype) type {...@@ -511,7 +511,7 @@ pub fn SectionHeaderIterator(ParseSource: anytype) type {
511pub fn int(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @TypeOf(int_64) {511pub fn int(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @TypeOf(int_64) {
512 if (is_64) {512 if (is_64) {
513 if (need_bswap) {513 if (need_bswap) {
514 return @byteSwap(@TypeOf(int_64), int_64);514 return @byteSwap(int_64);
515 } else {515 } else {
516 return int_64;516 return int_64;
517 }517 }
...@@ -522,7 +522,7 @@ pub fn int(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @Typ...@@ -522,7 +522,7 @@ pub fn int(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @Typ
522522
523pub fn int32(need_bswap: bool, int_32: anytype, comptime Int64: anytype) Int64 {523pub fn int32(need_bswap: bool, int_32: anytype, comptime Int64: anytype) Int64 {
524 if (need_bswap) {524 if (need_bswap) {
525 return @byteSwap(@TypeOf(int_32), int_32);525 return @byteSwap(int_32);
526 } else {526 } else {
527 return int_32;527 return int_32;
528 }528 }
...@@ -872,14 +872,14 @@ pub const Elf_MIPS_ABIFlags_v0 = extern struct {...@@ -872,14 +872,14 @@ pub const Elf_MIPS_ABIFlags_v0 = extern struct {
872};872};
873873
874comptime {874comptime {
875 debug.assert(@sizeOf(Elf32_Ehdr) == 52);875 assert(@sizeOf(Elf32_Ehdr) == 52);
876 debug.assert(@sizeOf(Elf64_Ehdr) == 64);876 assert(@sizeOf(Elf64_Ehdr) == 64);
877877
878 debug.assert(@sizeOf(Elf32_Phdr) == 32);878 assert(@sizeOf(Elf32_Phdr) == 32);
879 debug.assert(@sizeOf(Elf64_Phdr) == 56);879 assert(@sizeOf(Elf64_Phdr) == 56);
880880
881 debug.assert(@sizeOf(Elf32_Shdr) == 40);881 assert(@sizeOf(Elf32_Shdr) == 40);
882 debug.assert(@sizeOf(Elf64_Shdr) == 64);882 assert(@sizeOf(Elf64_Shdr) == 64);
883}883}
884884
885pub const Auxv = switch (@sizeOf(usize)) {885pub const Auxv = switch (@sizeOf(usize)) {
lib/std/enums.zig+1-1
...@@ -57,7 +57,7 @@ pub fn values(comptime E: type) []const E {...@@ -57,7 +57,7 @@ pub fn values(comptime E: type) []const E {
57/// the total number of items which have no matching enum key (holes in the enum57/// the total number of items which have no matching enum key (holes in the enum
58/// numbering). So for example, if an enum has values 1, 2, 5, and 6, max_unused_slots58/// numbering). So for example, if an enum has values 1, 2, 5, and 6, max_unused_slots
59/// must be at least 3, to allow unused slots 0, 3, and 4.59/// must be at least 3, to allow unused slots 0, 3, and 4.
60fn directEnumArrayLen(comptime E: type, comptime max_unused_slots: comptime_int) comptime_int {60pub fn directEnumArrayLen(comptime E: type, comptime max_unused_slots: comptime_int) comptime_int {
61 var max_value: comptime_int = -1;61 var max_value: comptime_int = -1;
62 const max_usize: comptime_int = ~@as(usize, 0);62 const max_usize: comptime_int = ~@as(usize, 0);
63 const fields = std.meta.fields(E);63 const fields = std.meta.fields(E);
lib/std/event/channel.zig+1-1
...@@ -56,7 +56,7 @@ pub fn Channel(comptime T: type) type {...@@ -56,7 +56,7 @@ pub fn Channel(comptime T: type) type {
56 pub fn init(self: *SelfChannel, buffer: []T) void {56 pub fn init(self: *SelfChannel, buffer: []T) void {
57 // The ring buffer implementation only works with power of 2 buffer sizes57 // The ring buffer implementation only works with power of 2 buffer sizes
58 // because of relying on subtracting across zero. For example (0 -% 1) % 10 == 558 // because of relying on subtracting across zero. For example (0 -% 1) % 10 == 5
59 assert(buffer.len == 0 or @popCount(usize, buffer.len) == 1);59 assert(buffer.len == 0 or @popCount(buffer.len) == 1);
6060
61 self.* = SelfChannel{61 self.* = SelfChannel{
62 .buffer_len = 0,62 .buffer_len = 0,
lib/std/fmt.zig+2-2
...@@ -195,7 +195,7 @@ pub fn format(...@@ -195,7 +195,7 @@ pub fn format(
195 }195 }
196196
197 if (comptime arg_state.hasUnusedArgs()) {197 if (comptime arg_state.hasUnusedArgs()) {
198 const missing_count = arg_state.args_len - @popCount(ArgSetType, arg_state.used_args);198 const missing_count = arg_state.args_len - @popCount(arg_state.used_args);
199 switch (missing_count) {199 switch (missing_count) {
200 0 => unreachable,200 0 => unreachable,
201 1 => @compileError("unused argument in '" ++ fmt ++ "'"),201 1 => @compileError("unused argument in '" ++ fmt ++ "'"),
...@@ -380,7 +380,7 @@ const ArgState = struct {...@@ -380,7 +380,7 @@ const ArgState = struct {
380 args_len: usize,380 args_len: usize,
381381
382 fn hasUnusedArgs(self: *@This()) bool {382 fn hasUnusedArgs(self: *@This()) bool {
383 return @popCount(ArgSetType, self.used_args) != self.args_len;383 return @popCount(self.used_args) != self.args_len;
384 }384 }
385385
386 fn nextArg(self: *@This(), arg_index: ?usize) ?usize {386 fn nextArg(self: *@This(), arg_index: ?usize) ?usize {
lib/std/fmt/parse_float/convert_eisel_lemire.zig+1-1
...@@ -36,7 +36,7 @@ pub fn convertEiselLemire(comptime T: type, q: i64, w_: u64) ?BiasedFp(f64) {...@@ -36,7 +36,7 @@ pub fn convertEiselLemire(comptime T: type, q: i64, w_: u64) ?BiasedFp(f64) {
36 }36 }
3737
38 // Normalize our significant digits, so the most-significant bit is set.38 // Normalize our significant digits, so the most-significant bit is set.
39 const lz = @clz(u64, @bitCast(u64, w));39 const lz = @clz(@bitCast(u64, w));
40 w = math.shl(u64, w, lz);40 w = math.shl(u64, w, lz);
4141
42 const r = computeProductApprox(q, w, float_info.mantissa_explicit_bits + 3);42 const r = computeProductApprox(q, w, float_info.mantissa_explicit_bits + 3);
lib/std/fs.zig+4-2
...@@ -877,8 +877,9 @@ pub const IterableDir = struct {...@@ -877,8 +877,9 @@ pub const IterableDir = struct {
877 /// a reference to the path.877 /// a reference to the path.
878 pub fn next(self: *Walker) !?WalkerEntry {878 pub fn next(self: *Walker) !?WalkerEntry {
879 while (self.stack.items.len != 0) {879 while (self.stack.items.len != 0) {
880 // `top` becomes invalid after appending to `self.stack`880 // `top` and `containing` become invalid after appending to `self.stack`
881 var top = &self.stack.items[self.stack.items.len - 1];881 var top = &self.stack.items[self.stack.items.len - 1];
882 var containing = top;
882 var dirname_len = top.dirname_len;883 var dirname_len = top.dirname_len;
883 if (try top.iter.next()) |base| {884 if (try top.iter.next()) |base| {
884 self.name_buffer.shrinkRetainingCapacity(dirname_len);885 self.name_buffer.shrinkRetainingCapacity(dirname_len);
...@@ -899,10 +900,11 @@ pub const IterableDir = struct {...@@ -899,10 +900,11 @@ pub const IterableDir = struct {
899 .dirname_len = self.name_buffer.items.len,900 .dirname_len = self.name_buffer.items.len,
900 });901 });
901 top = &self.stack.items[self.stack.items.len - 1];902 top = &self.stack.items[self.stack.items.len - 1];
903 containing = &self.stack.items[self.stack.items.len - 2];
902 }904 }
903 }905 }
904 return WalkerEntry{906 return WalkerEntry{
905 .dir = top.iter.dir,907 .dir = containing.iter.dir,
906 .basename = self.name_buffer.items[dirname_len..],908 .basename = self.name_buffer.items[dirname_len..],
907 .path = self.name_buffer.items,909 .path = self.name_buffer.items,
908 .kind = base.kind,910 .kind = base.kind,
lib/std/fs/path.zig+1-1
...@@ -42,7 +42,7 @@ pub fn isSep(byte: u8) bool {...@@ -42,7 +42,7 @@ pub fn isSep(byte: u8) bool {
4242
43/// This is different from mem.join in that the separator will not be repeated if43/// This is different from mem.join in that the separator will not be repeated if
44/// it is found at the end or beginning of a pair of consecutive paths.44/// it is found at the end or beginning of a pair of consecutive paths.
45fn joinSepMaybeZ(allocator: Allocator, separator: u8, sepPredicate: fn (u8) bool, paths: []const []const u8, zero: bool) ![]u8 {45fn joinSepMaybeZ(allocator: Allocator, separator: u8, comptime sepPredicate: fn (u8) bool, paths: []const []const u8, zero: bool) ![]u8 {
46 if (paths.len == 0) return if (zero) try allocator.dupe(u8, &[1]u8{0}) else &[0]u8{};46 if (paths.len == 0) return if (zero) try allocator.dupe(u8, &[1]u8{0}) else &[0]u8{};
4747
48 // Find first non-empty path index.48 // Find first non-empty path index.
lib/std/fs/test.zig+3
...@@ -1058,6 +1058,9 @@ test "walker" {...@@ -1058,6 +1058,9 @@ test "walker" {
1058 std.debug.print("found unexpected path: {s}\n", .{std.fmt.fmtSliceEscapeLower(entry.path)});1058 std.debug.print("found unexpected path: {s}\n", .{std.fmt.fmtSliceEscapeLower(entry.path)});
1059 return err;1059 return err;
1060 };1060 };
1061 // make sure that the entry.dir is the containing dir
1062 var entry_dir = try entry.dir.openDir(entry.basename, .{});
1063 defer entry_dir.close();
1061 num_walked += 1;1064 num_walked += 1;
1062 }1065 }
1063 try testing.expectEqual(expected_paths.kvs.len, num_walked);1066 try testing.expectEqual(expected_paths.kvs.len, num_walked);
lib/std/hash/auto_hash.zig+19-20
...@@ -30,13 +30,15 @@ pub fn hashPointer(hasher: anytype, key: anytype, comptime strat: HashStrategy)...@@ -30,13 +30,15 @@ pub fn hashPointer(hasher: anytype, key: anytype, comptime strat: HashStrategy)
30 .DeepRecursive => hash(hasher, key.*, .DeepRecursive),30 .DeepRecursive => hash(hasher, key.*, .DeepRecursive),
31 },31 },
3232
33 .Slice => switch (strat) {33 .Slice => {
34 .Shallow => {34 switch (strat) {
35 hashPointer(hasher, key.ptr, .Shallow);35 .Shallow => {
36 hash(hasher, key.len, .Shallow);36 hashPointer(hasher, key.ptr, .Shallow);
37 },37 },
38 .Deep => hashArray(hasher, key, .Shallow),38 .Deep => hashArray(hasher, key, .Shallow),
39 .DeepRecursive => hashArray(hasher, key, .DeepRecursive),39 .DeepRecursive => hashArray(hasher, key, .DeepRecursive),
40 }
41 hash(hasher, key.len, .Shallow);
40 },42 },
4143
42 .Many,44 .Many,
...@@ -53,17 +55,8 @@ pub fn hashPointer(hasher: anytype, key: anytype, comptime strat: HashStrategy)...@@ -53,17 +55,8 @@ pub fn hashPointer(hasher: anytype, key: anytype, comptime strat: HashStrategy)
5355
54/// Helper function to hash a set of contiguous objects, from an array or slice.56/// Helper function to hash a set of contiguous objects, from an array or slice.
55pub fn hashArray(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {57pub fn hashArray(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {
56 switch (strat) {58 for (key) |element| {
57 .Shallow => {59 hash(hasher, element, strat);
58 for (key) |element| {
59 hash(hasher, element, .Shallow);
60 }
61 },
62 else => {
63 for (key) |element| {
64 hash(hasher, element, strat);
65 }
66 },
67 }60 }
68}61}
6962
...@@ -193,8 +186,8 @@ fn typeContainsSlice(comptime K: type) bool {...@@ -193,8 +186,8 @@ fn typeContainsSlice(comptime K: type) bool {
193pub fn autoHash(hasher: anytype, key: anytype) void {186pub fn autoHash(hasher: anytype, key: anytype) void {
194 const Key = @TypeOf(key);187 const Key = @TypeOf(key);
195 if (comptime typeContainsSlice(Key)) {188 if (comptime typeContainsSlice(Key)) {
196 @compileError("std.auto_hash.autoHash does not allow slices as well as unions and structs containing slices here (" ++ @typeName(Key) ++189 @compileError("std.hash.autoHash does not allow slices as well as unions and structs containing slices here (" ++ @typeName(Key) ++
197 ") because the intent is unclear. Consider using std.auto_hash.hash or providing your own hash function instead.");190 ") because the intent is unclear. Consider using std.hash.autoHashStrat or providing your own hash function instead.");
198 }191 }
199192
200 hash(hasher, key, .Shallow);193 hash(hasher, key, .Shallow);
...@@ -359,6 +352,12 @@ test "testHash array" {...@@ -359,6 +352,12 @@ test "testHash array" {
359 try testing.expectEqual(h, hasher.final());352 try testing.expectEqual(h, hasher.final());
360}353}
361354
355test "testHash multi-dimensional array" {
356 const a = [_][]const u32{ &.{ 1, 2, 3 }, &.{ 4, 5 } };
357 const b = [_][]const u32{ &.{ 1, 2 }, &.{ 3, 4, 5 } };
358 try testing.expect(testHash(a) != testHash(b));
359}
360
362test "testHash struct" {361test "testHash struct" {
363 const Foo = struct {362 const Foo = struct {
364 a: u32 = 1,363 a: u32 = 1,
lib/std/hash/cityhash.zig+5-5
...@@ -143,9 +143,9 @@ pub const CityHash32 = struct {...@@ -143,9 +143,9 @@ pub const CityHash32 = struct {
143 h = rotr32(h, 19);143 h = rotr32(h, 19);
144 h = h *% 5 +% 0xe6546b64;144 h = h *% 5 +% 0xe6546b64;
145 g ^= b4;145 g ^= b4;
146 g = @byteSwap(u32, g) *% 5;146 g = @byteSwap(g) *% 5;
147 h +%= b4 *% 5;147 h +%= b4 *% 5;
148 h = @byteSwap(u32, h);148 h = @byteSwap(h);
149 f +%= b0;149 f +%= b0;
150 const t: u32 = h;150 const t: u32 = h;
151 h = f;151 h = f;
...@@ -252,11 +252,11 @@ pub const CityHash64 = struct {...@@ -252,11 +252,11 @@ pub const CityHash64 = struct {
252252
253 const u: u64 = rotr64(a +% g, 43) +% (rotr64(b, 30) +% c) *% 9;253 const u: u64 = rotr64(a +% g, 43) +% (rotr64(b, 30) +% c) *% 9;
254 const v: u64 = ((a +% g) ^ d) +% f +% 1;254 const v: u64 = ((a +% g) ^ d) +% f +% 1;
255 const w: u64 = @byteSwap(u64, (u +% v) *% mul) +% h;255 const w: u64 = @byteSwap((u +% v) *% mul) +% h;
256 const x: u64 = rotr64(e +% f, 42) +% c;256 const x: u64 = rotr64(e +% f, 42) +% c;
257 const y: u64 = (@byteSwap(u64, (v +% w) *% mul) +% g) *% mul;257 const y: u64 = (@byteSwap((v +% w) *% mul) +% g) *% mul;
258 const z: u64 = e +% f +% c;258 const z: u64 = e +% f +% c;
259 const a1: u64 = @byteSwap(u64, (x +% z) *% mul +% y) +% b;259 const a1: u64 = @byteSwap((x +% z) *% mul +% y) +% b;
260 const b1: u64 = shiftmix((z +% a1) *% mul +% d +% h) *% mul;260 const b1: u64 = shiftmix((z +% a1) *% mul +% d +% h) *% mul;
261 return b1 +% x;261 return b1 +% x;
262 }262 }
lib/std/hash/murmur.zig+11-11
...@@ -19,7 +19,7 @@ pub const Murmur2_32 = struct {...@@ -19,7 +19,7 @@ pub const Murmur2_32 = struct {
19 for (@ptrCast([*]align(1) const u32, str.ptr)[0..(len >> 2)]) |v| {19 for (@ptrCast([*]align(1) const u32, str.ptr)[0..(len >> 2)]) |v| {
20 var k1: u32 = v;20 var k1: u32 = v;
21 if (native_endian == .Big)21 if (native_endian == .Big)
22 k1 = @byteSwap(u32, k1);22 k1 = @byteSwap(k1);
23 k1 *%= m;23 k1 *%= m;
24 k1 ^= k1 >> 24;24 k1 ^= k1 >> 24;
25 k1 *%= m;25 k1 *%= m;
...@@ -104,7 +104,7 @@ pub const Murmur2_64 = struct {...@@ -104,7 +104,7 @@ pub const Murmur2_64 = struct {
104 for (@ptrCast([*]align(1) const u64, str.ptr)[0..@intCast(usize, len >> 3)]) |v| {104 for (@ptrCast([*]align(1) const u64, str.ptr)[0..@intCast(usize, len >> 3)]) |v| {
105 var k1: u64 = v;105 var k1: u64 = v;
106 if (native_endian == .Big)106 if (native_endian == .Big)
107 k1 = @byteSwap(u64, k1);107 k1 = @byteSwap(k1);
108 k1 *%= m;108 k1 *%= m;
109 k1 ^= k1 >> 47;109 k1 ^= k1 >> 47;
110 k1 *%= m;110 k1 *%= m;
...@@ -117,7 +117,7 @@ pub const Murmur2_64 = struct {...@@ -117,7 +117,7 @@ pub const Murmur2_64 = struct {
117 var k1: u64 = 0;117 var k1: u64 = 0;
118 @memcpy(@ptrCast([*]u8, &k1), @ptrCast([*]const u8, &str[@intCast(usize, offset)]), @intCast(usize, rest));118 @memcpy(@ptrCast([*]u8, &k1), @ptrCast([*]const u8, &str[@intCast(usize, offset)]), @intCast(usize, rest));
119 if (native_endian == .Big)119 if (native_endian == .Big)
120 k1 = @byteSwap(u64, k1);120 k1 = @byteSwap(k1);
121 h1 ^= k1;121 h1 ^= k1;
122 h1 *%= m;122 h1 *%= m;
123 }123 }
...@@ -184,7 +184,7 @@ pub const Murmur3_32 = struct {...@@ -184,7 +184,7 @@ pub const Murmur3_32 = struct {
184 for (@ptrCast([*]align(1) const u32, str.ptr)[0..(len >> 2)]) |v| {184 for (@ptrCast([*]align(1) const u32, str.ptr)[0..(len >> 2)]) |v| {
185 var k1: u32 = v;185 var k1: u32 = v;
186 if (native_endian == .Big)186 if (native_endian == .Big)
187 k1 = @byteSwap(u32, k1);187 k1 = @byteSwap(k1);
188 k1 *%= c1;188 k1 *%= c1;
189 k1 = rotl32(k1, 15);189 k1 = rotl32(k1, 15);
190 k1 *%= c2;190 k1 *%= c2;
...@@ -296,7 +296,7 @@ fn SMHasherTest(comptime hash_fn: anytype, comptime hashbits: u32) u32 {...@@ -296,7 +296,7 @@ fn SMHasherTest(comptime hash_fn: anytype, comptime hashbits: u32) u32 {
296296
297 var h = hash_fn(key[0..i], 256 - i);297 var h = hash_fn(key[0..i], 256 - i);
298 if (native_endian == .Big)298 if (native_endian == .Big)
299 h = @byteSwap(@TypeOf(h), h);299 h = @byteSwap(h);
300 @memcpy(@ptrCast([*]u8, &hashes[i * hashbytes]), @ptrCast([*]u8, &h), hashbytes);300 @memcpy(@ptrCast([*]u8, &hashes[i * hashbytes]), @ptrCast([*]u8, &h), hashbytes);
301 }301 }
302302
...@@ -310,8 +310,8 @@ test "murmur2_32" {...@@ -310,8 +310,8 @@ test "murmur2_32" {
310 var v0le: u32 = v0;310 var v0le: u32 = v0;
311 var v1le: u64 = v1;311 var v1le: u64 = v1;
312 if (native_endian == .Big) {312 if (native_endian == .Big) {
313 v0le = @byteSwap(u32, v0le);313 v0le = @byteSwap(v0le);
314 v1le = @byteSwap(u64, v1le);314 v1le = @byteSwap(v1le);
315 }315 }
316 try testing.expectEqual(Murmur2_32.hash(@ptrCast([*]u8, &v0le)[0..4]), Murmur2_32.hashUint32(v0));316 try testing.expectEqual(Murmur2_32.hash(@ptrCast([*]u8, &v0le)[0..4]), Murmur2_32.hashUint32(v0));
317 try testing.expectEqual(Murmur2_32.hash(@ptrCast([*]u8, &v1le)[0..8]), Murmur2_32.hashUint64(v1));317 try testing.expectEqual(Murmur2_32.hash(@ptrCast([*]u8, &v1le)[0..8]), Murmur2_32.hashUint64(v1));
...@@ -324,8 +324,8 @@ test "murmur2_64" {...@@ -324,8 +324,8 @@ test "murmur2_64" {
324 var v0le: u32 = v0;324 var v0le: u32 = v0;
325 var v1le: u64 = v1;325 var v1le: u64 = v1;
326 if (native_endian == .Big) {326 if (native_endian == .Big) {
327 v0le = @byteSwap(u32, v0le);327 v0le = @byteSwap(v0le);
328 v1le = @byteSwap(u64, v1le);328 v1le = @byteSwap(v1le);
329 }329 }
330 try testing.expectEqual(Murmur2_64.hash(@ptrCast([*]u8, &v0le)[0..4]), Murmur2_64.hashUint32(v0));330 try testing.expectEqual(Murmur2_64.hash(@ptrCast([*]u8, &v0le)[0..4]), Murmur2_64.hashUint32(v0));
331 try testing.expectEqual(Murmur2_64.hash(@ptrCast([*]u8, &v1le)[0..8]), Murmur2_64.hashUint64(v1));331 try testing.expectEqual(Murmur2_64.hash(@ptrCast([*]u8, &v1le)[0..8]), Murmur2_64.hashUint64(v1));
...@@ -338,8 +338,8 @@ test "murmur3_32" {...@@ -338,8 +338,8 @@ test "murmur3_32" {
338 var v0le: u32 = v0;338 var v0le: u32 = v0;
339 var v1le: u64 = v1;339 var v1le: u64 = v1;
340 if (native_endian == .Big) {340 if (native_endian == .Big) {
341 v0le = @byteSwap(u32, v0le);341 v0le = @byteSwap(v0le);
342 v1le = @byteSwap(u64, v1le);342 v1le = @byteSwap(v1le);
343 }343 }
344 try testing.expectEqual(Murmur3_32.hash(@ptrCast([*]u8, &v0le)[0..4]), Murmur3_32.hashUint32(v0));344 try testing.expectEqual(Murmur3_32.hash(@ptrCast([*]u8, &v0le)[0..4]), Murmur3_32.hashUint32(v0));
345 try testing.expectEqual(Murmur3_32.hash(@ptrCast([*]u8, &v1le)[0..8]), Murmur3_32.hashUint64(v1));345 try testing.expectEqual(Murmur3_32.hash(@ptrCast([*]u8, &v1le)[0..8]), Murmur3_32.hashUint64(v1));
lib/std/heap.zig+2-2
...@@ -479,7 +479,7 @@ const WasmPageAllocator = struct {...@@ -479,7 +479,7 @@ const WasmPageAllocator = struct {
479 @setCold(true);479 @setCold(true);
480 for (self.data) |segment, i| {480 for (self.data) |segment, i| {
481 const spills_into_next = @bitCast(i128, segment) < 0;481 const spills_into_next = @bitCast(i128, segment) < 0;
482 const has_enough_bits = @popCount(u128, segment) >= num_pages;482 const has_enough_bits = @popCount(segment) >= num_pages;
483483
484 if (!spills_into_next and !has_enough_bits) continue;484 if (!spills_into_next and !has_enough_bits) continue;
485485
...@@ -1185,7 +1185,7 @@ pub fn testAllocatorLargeAlignment(base_allocator: mem.Allocator) !void {...@@ -1185,7 +1185,7 @@ pub fn testAllocatorLargeAlignment(base_allocator: mem.Allocator) !void {
1185 const large_align = @as(u29, mem.page_size << 2);1185 const large_align = @as(u29, mem.page_size << 2);
11861186
1187 var align_mask: usize = undefined;1187 var align_mask: usize = undefined;
1188 _ = @shlWithOverflow(usize, ~@as(usize, 0), @as(USizeShift, @ctz(u29, large_align)), &align_mask);1188 _ = @shlWithOverflow(usize, ~@as(usize, 0), @as(USizeShift, @ctz(large_align)), &align_mask);
11891189
1190 var slice = try allocator.alignedAlloc(u8, large_align, 500);1190 var slice = try allocator.alignedAlloc(u8, large_align, 500);
1191 try testing.expect(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));1191 try testing.expect(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));
lib/std/io/bit_reader.zig+1-1
...@@ -7,7 +7,7 @@ const meta = std.meta;...@@ -7,7 +7,7 @@ const meta = std.meta;
7const math = std.math;7const math = std.math;
88
9/// Creates a stream which allows for reading bit fields from another stream9/// Creates a stream which allows for reading bit fields from another stream
10pub fn BitReader(endian: std.builtin.Endian, comptime ReaderType: type) type {10pub fn BitReader(comptime endian: std.builtin.Endian, comptime ReaderType: type) type {
11 return struct {11 return struct {
12 forward_reader: ReaderType,12 forward_reader: ReaderType,
13 bit_buffer: u7,13 bit_buffer: u7,
lib/std/io/bit_writer.zig+1-1
...@@ -7,7 +7,7 @@ const meta = std.meta;...@@ -7,7 +7,7 @@ const meta = std.meta;
7const math = std.math;7const math = std.math;
88
9/// Creates a stream which allows for writing bit fields to another stream9/// Creates a stream which allows for writing bit fields to another stream
10pub fn BitWriter(endian: std.builtin.Endian, comptime WriterType: type) type {10pub fn BitWriter(comptime endian: std.builtin.Endian, comptime WriterType: type) type {
11 return struct {11 return struct {
12 forward_writer: WriterType,12 forward_writer: WriterType,
13 bit_buffer: u8,13 bit_buffer: u8,
lib/std/io/reader.zig+21
...@@ -247,6 +247,27 @@ pub fn Reader(...@@ -247,6 +247,27 @@ pub fn Reader(
247 return bytes;247 return bytes;
248 }248 }
249249
250 /// Reads bytes into the bounded array, until
251 /// the bounded array is full, or the stream ends.
252 pub fn readIntoBoundedBytes(
253 self: Self,
254 comptime num_bytes: usize,
255 bounded: *std.BoundedArray(u8, num_bytes),
256 ) !void {
257 while (bounded.len < num_bytes) {
258 const bytes_read = try self.read(bounded.unusedCapacitySlice());
259 if (bytes_read == 0) return;
260 bounded.len += bytes_read;
261 }
262 }
263
264 /// Reads at most `num_bytes` and returns as a bounded array.
265 pub fn readBoundedBytes(self: Self, comptime num_bytes: usize) !std.BoundedArray(u8, num_bytes) {
266 var result = std.BoundedArray(u8, num_bytes){};
267 try self.readIntoBoundedBytes(num_bytes, &result);
268 return result;
269 }
270
250 /// Reads a native-endian integer271 /// Reads a native-endian integer
251 pub fn readIntNative(self: Self, comptime T: type) !T {272 pub fn readIntNative(self: Self, comptime T: type) !T {
252 const bytes = try self.readBytesNoEof((@typeInfo(T).Int.bits + 7) / 8);273 const bytes = try self.readBytesNoEof((@typeInfo(T).Int.bits + 7) / 8);
lib/std/leb128.zig+1-1
...@@ -317,7 +317,7 @@ fn test_write_leb128(value: anytype) !void {...@@ -317,7 +317,7 @@ fn test_write_leb128(value: anytype) !void {
317 const bytes_needed = bn: {317 const bytes_needed = bn: {
318 if (@typeInfo(T).Int.bits <= 7) break :bn @as(u16, 1);318 if (@typeInfo(T).Int.bits <= 7) break :bn @as(u16, 1);
319319
320 const unused_bits = if (value < 0) @clz(T, ~value) else @clz(T, value);320 const unused_bits = if (value < 0) @clz(~value) else @clz(value);
321 const used_bits: u16 = (@typeInfo(T).Int.bits - unused_bits) + @boolToInt(t_signed);321 const used_bits: u16 = (@typeInfo(T).Int.bits - unused_bits) + @boolToInt(t_signed);
322 if (used_bits <= 7) break :bn @as(u16, 1);322 if (used_bits <= 7) break :bn @as(u16, 1);
323 break :bn ((used_bits + 6) / 7);323 break :bn ((used_bits + 6) / 7);
lib/std/math.zig+3-3
...@@ -1146,7 +1146,7 @@ pub fn ceilPowerOfTwoPromote(comptime T: type, value: T) std.meta.Int(@typeInfo(...@@ -1146,7 +1146,7 @@ pub fn ceilPowerOfTwoPromote(comptime T: type, value: T) std.meta.Int(@typeInfo(
1146 assert(value != 0);1146 assert(value != 0);
1147 const PromotedType = std.meta.Int(@typeInfo(T).Int.signedness, @typeInfo(T).Int.bits + 1);1147 const PromotedType = std.meta.Int(@typeInfo(T).Int.signedness, @typeInfo(T).Int.bits + 1);
1148 const ShiftType = std.math.Log2Int(PromotedType);1148 const ShiftType = std.math.Log2Int(PromotedType);
1149 return @as(PromotedType, 1) << @intCast(ShiftType, @typeInfo(T).Int.bits - @clz(T, value - 1));1149 return @as(PromotedType, 1) << @intCast(ShiftType, @typeInfo(T).Int.bits - @clz(value - 1));
1150}1150}
11511151
1152/// Returns the next power of two (if the value is not already a power of two).1152/// Returns the next power of two (if the value is not already a power of two).
...@@ -1212,7 +1212,7 @@ pub fn log2_int(comptime T: type, x: T) Log2Int(T) {...@@ -1212,7 +1212,7 @@ pub fn log2_int(comptime T: type, x: T) Log2Int(T) {
1212 if (@typeInfo(T) != .Int or @typeInfo(T).Int.signedness != .unsigned)1212 if (@typeInfo(T) != .Int or @typeInfo(T).Int.signedness != .unsigned)
1213 @compileError("log2_int requires an unsigned integer, found " ++ @typeName(T));1213 @compileError("log2_int requires an unsigned integer, found " ++ @typeName(T));
1214 assert(x != 0);1214 assert(x != 0);
1215 return @intCast(Log2Int(T), @typeInfo(T).Int.bits - 1 - @clz(T, x));1215 return @intCast(Log2Int(T), @typeInfo(T).Int.bits - 1 - @clz(x));
1216}1216}
12171217
1218/// Return the log base 2 of integer value x, rounding up to the1218/// Return the log base 2 of integer value x, rounding up to the
...@@ -1548,7 +1548,7 @@ test "boolMask" {...@@ -1548,7 +1548,7 @@ test "boolMask" {
1548}1548}
15491549
1550/// Return the mod of `num` with the smallest integer type1550/// Return the mod of `num` with the smallest integer type
1551pub fn comptimeMod(num: anytype, denom: comptime_int) IntFittingRange(0, denom - 1) {1551pub fn comptimeMod(num: anytype, comptime denom: comptime_int) IntFittingRange(0, denom - 1) {
1552 return @intCast(IntFittingRange(0, denom - 1), @mod(num, denom));1552 return @intCast(IntFittingRange(0, denom - 1), @mod(num, denom));
1553}1553}
15541554
lib/std/math/big/int.zig+7-7
...@@ -887,7 +887,7 @@ pub const Mutable = struct {...@@ -887,7 +887,7 @@ pub const Mutable = struct {
887887
888 var sum: Limb = 0;888 var sum: Limb = 0;
889 for (r.limbs[0..r.len]) |limb| {889 for (r.limbs[0..r.len]) |limb| {
890 sum += @popCount(Limb, limb);890 sum += @popCount(limb);
891 }891 }
892 r.set(sum);892 r.set(sum);
893 }893 }
...@@ -1520,7 +1520,7 @@ pub const Mutable = struct {...@@ -1520,7 +1520,7 @@ pub const Mutable = struct {
1520 ) void {1520 ) void {
1521 // 0.1521 // 0.
1522 // Normalize so that y[t] > b/21522 // Normalize so that y[t] > b/2
1523 const lz = @clz(Limb, y.limbs[y.len - 1]);1523 const lz = @clz(y.limbs[y.len - 1]);
1524 const norm_shift = if (lz == 0 and y.toConst().isOdd())1524 const norm_shift = if (lz == 0 and y.toConst().isOdd())
1525 limb_bits // Force an extra limb so that y is even.1525 limb_bits // Force an extra limb so that y is even.
1526 else1526 else
...@@ -1917,7 +1917,7 @@ pub const Const = struct {...@@ -1917,7 +1917,7 @@ pub const Const = struct {
19171917
1918 /// Returns the number of bits required to represent the absolute value of an integer.1918 /// Returns the number of bits required to represent the absolute value of an integer.
1919 pub fn bitCountAbs(self: Const) usize {1919 pub fn bitCountAbs(self: Const) usize {
1920 return (self.limbs.len - 1) * limb_bits + (limb_bits - @clz(Limb, self.limbs[self.limbs.len - 1]));1920 return (self.limbs.len - 1) * limb_bits + (limb_bits - @clz(self.limbs[self.limbs.len - 1]));
1921 }1921 }
19221922
1923 /// Returns the number of bits required to represent the integer in twos-complement form.1923 /// Returns the number of bits required to represent the integer in twos-complement form.
...@@ -1936,9 +1936,9 @@ pub const Const = struct {...@@ -1936,9 +1936,9 @@ pub const Const = struct {
1936 if (!self.positive) block: {1936 if (!self.positive) block: {
1937 bits += 1;1937 bits += 1;
19381938
1939 if (@popCount(Limb, self.limbs[self.limbs.len - 1]) == 1) {1939 if (@popCount(self.limbs[self.limbs.len - 1]) == 1) {
1940 for (self.limbs[0 .. self.limbs.len - 1]) |limb| {1940 for (self.limbs[0 .. self.limbs.len - 1]) |limb| {
1941 if (@popCount(Limb, limb) != 0) {1941 if (@popCount(limb) != 0) {
1942 break :block;1942 break :block;
1943 }1943 }
1944 }1944 }
...@@ -3895,8 +3895,8 @@ fn llpow(r: []Limb, a: []const Limb, b: u32, tmp_limbs: []Limb) void {...@@ -3895,8 +3895,8 @@ fn llpow(r: []Limb, a: []const Limb, b: u32, tmp_limbs: []Limb) void {
3895 // The initial assignment makes the result end in `r` so an extra memory3895 // The initial assignment makes the result end in `r` so an extra memory
3896 // copy is saved, each 1 flips the index twice so it's only the zeros that3896 // copy is saved, each 1 flips the index twice so it's only the zeros that
3897 // matter.3897 // matter.
3898 const b_leading_zeros = @clz(u32, b);3898 const b_leading_zeros = @clz(b);
3899 const exp_zeros = @popCount(u32, ~b) - b_leading_zeros;3899 const exp_zeros = @popCount(~b) - b_leading_zeros;
3900 if (exp_zeros & 1 != 0) {3900 if (exp_zeros & 1 != 0) {
3901 tmp1 = tmp_limbs;3901 tmp1 = tmp_limbs;
3902 tmp2 = r;3902 tmp2 = r;
lib/std/math/float.zig+1-1
...@@ -8,7 +8,7 @@ inline fn mantissaOne(comptime T: type) comptime_int {...@@ -8,7 +8,7 @@ inline fn mantissaOne(comptime T: type) comptime_int {
8}8}
99
10/// Creates floating point type T from an unbiased exponent and raw mantissa.10/// Creates floating point type T from an unbiased exponent and raw mantissa.
11inline fn reconstructFloat(comptime T: type, exponent: comptime_int, mantissa: comptime_int) T {11inline fn reconstructFloat(comptime T: type, comptime exponent: comptime_int, comptime mantissa: comptime_int) T {
12 const TBits = @Type(.{ .Int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } });12 const TBits = @Type(.{ .Int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } });
13 const biased_exponent = @as(TBits, exponent + floatExponentMax(T));13 const biased_exponent = @as(TBits, exponent + floatExponentMax(T));
14 return @bitCast(T, (biased_exponent << floatMantissaBits(T)) | @as(TBits, mantissa));14 return @bitCast(T, (biased_exponent << floatMantissaBits(T)) | @as(TBits, mantissa));
lib/std/mem.zig+22-19
...@@ -267,7 +267,7 @@ pub fn zeroes(comptime T: type) T {...@@ -267,7 +267,7 @@ pub fn zeroes(comptime T: type) T {
267 return null;267 return null;
268 },268 },
269 .Struct => |struct_info| {269 .Struct => |struct_info| {
270 if (@sizeOf(T) == 0) return T{};270 if (@sizeOf(T) == 0) return undefined;
271 if (struct_info.layout == .Extern) {271 if (struct_info.layout == .Extern) {
272 var item: T = undefined;272 var item: T = undefined;
273 set(u8, asBytes(&item), 0);273 set(u8, asBytes(&item), 0);
...@@ -424,6 +424,9 @@ test "zeroes" {...@@ -424,6 +424,9 @@ test "zeroes" {
424424
425 comptime var comptime_union = zeroes(C_union);425 comptime var comptime_union = zeroes(C_union);
426 try testing.expectEqual(@as(u8, 0), comptime_union.a);426 try testing.expectEqual(@as(u8, 0), comptime_union.a);
427
428 // Ensure zero sized struct with fields is initialized correctly.
429 _ = zeroes(struct { handle: void });
427}430}
428431
429/// Initializes all fields of the struct with their default value, or zero values if no default value is present.432/// Initializes all fields of the struct with their default value, or zero values if no default value is present.
...@@ -1316,7 +1319,7 @@ pub fn readIntNative(comptime T: type, bytes: *const [@divExact(@typeInfo(T).Int...@@ -1316,7 +1319,7 @@ pub fn readIntNative(comptime T: type, bytes: *const [@divExact(@typeInfo(T).Int
1316/// This function cannot fail and cannot cause undefined behavior.1319/// This function cannot fail and cannot cause undefined behavior.
1317/// Assumes the endianness of memory is foreign, so it must byte-swap.1320/// Assumes the endianness of memory is foreign, so it must byte-swap.
1318pub fn readIntForeign(comptime T: type, bytes: *const [@divExact(@typeInfo(T).Int.bits, 8)]u8) T {1321pub fn readIntForeign(comptime T: type, bytes: *const [@divExact(@typeInfo(T).Int.bits, 8)]u8) T {
1319 return @byteSwap(T, readIntNative(T, bytes));1322 return @byteSwap(readIntNative(T, bytes));
1320}1323}
13211324
1322pub const readIntLittle = switch (native_endian) {1325pub const readIntLittle = switch (native_endian) {
...@@ -1345,7 +1348,7 @@ pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T {...@@ -1345,7 +1348,7 @@ pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T {
1345/// The bit count of T must be evenly divisible by 8.1348/// The bit count of T must be evenly divisible by 8.
1346/// Assumes the endianness of memory is foreign, so it must byte-swap.1349/// Assumes the endianness of memory is foreign, so it must byte-swap.
1347pub fn readIntSliceForeign(comptime T: type, bytes: []const u8) T {1350pub fn readIntSliceForeign(comptime T: type, bytes: []const u8) T {
1348 return @byteSwap(T, readIntSliceNative(T, bytes));1351 return @byteSwap(readIntSliceNative(T, bytes));
1349}1352}
13501353
1351pub const readIntSliceLittle = switch (native_endian) {1354pub const readIntSliceLittle = switch (native_endian) {
...@@ -1427,7 +1430,7 @@ pub fn writeIntNative(comptime T: type, buf: *[(@typeInfo(T).Int.bits + 7) / 8]u...@@ -1427,7 +1430,7 @@ pub fn writeIntNative(comptime T: type, buf: *[(@typeInfo(T).Int.bits + 7) / 8]u
1427/// the integer bit width must be divisible by 8.1430/// the integer bit width must be divisible by 8.
1428/// This function stores in foreign endian, which means it does a @byteSwap first.1431/// This function stores in foreign endian, which means it does a @byteSwap first.
1429pub fn writeIntForeign(comptime T: type, buf: *[@divExact(@typeInfo(T).Int.bits, 8)]u8, value: T) void {1432pub fn writeIntForeign(comptime T: type, buf: *[@divExact(@typeInfo(T).Int.bits, 8)]u8, value: T) void {
1430 writeIntNative(T, buf, @byteSwap(T, value));1433 writeIntNative(T, buf, @byteSwap(value));
1431}1434}
14321435
1433pub const writeIntLittle = switch (native_endian) {1436pub const writeIntLittle = switch (native_endian) {
...@@ -1572,7 +1575,7 @@ pub const bswapAllFields = @compileError("bswapAllFields has been renamed to byt...@@ -1572,7 +1575,7 @@ pub const bswapAllFields = @compileError("bswapAllFields has been renamed to byt
1572pub fn byteSwapAllFields(comptime S: type, ptr: *S) void {1575pub fn byteSwapAllFields(comptime S: type, ptr: *S) void {
1573 if (@typeInfo(S) != .Struct) @compileError("byteSwapAllFields expects a struct as the first argument");1576 if (@typeInfo(S) != .Struct) @compileError("byteSwapAllFields expects a struct as the first argument");
1574 inline for (std.meta.fields(S)) |f| {1577 inline for (std.meta.fields(S)) |f| {
1575 @field(ptr, f.name) = @byteSwap(f.field_type, @field(ptr, f.name));1578 @field(ptr, f.name) = @byteSwap(@field(ptr, f.name));
1576 }1579 }
1577}1580}
15781581
...@@ -2749,14 +2752,14 @@ test "replaceOwned" {...@@ -2749,14 +2752,14 @@ test "replaceOwned" {
2749pub fn littleToNative(comptime T: type, x: T) T {2752pub fn littleToNative(comptime T: type, x: T) T {
2750 return switch (native_endian) {2753 return switch (native_endian) {
2751 .Little => x,2754 .Little => x,
2752 .Big => @byteSwap(T, x),2755 .Big => @byteSwap(x),
2753 };2756 };
2754}2757}
27552758
2756/// Converts a big-endian integer to host endianness.2759/// Converts a big-endian integer to host endianness.
2757pub fn bigToNative(comptime T: type, x: T) T {2760pub fn bigToNative(comptime T: type, x: T) T {
2758 return switch (native_endian) {2761 return switch (native_endian) {
2759 .Little => @byteSwap(T, x),2762 .Little => @byteSwap(x),
2760 .Big => x,2763 .Big => x,
2761 };2764 };
2762}2765}
...@@ -2781,14 +2784,14 @@ pub fn nativeTo(comptime T: type, x: T, desired_endianness: Endian) T {...@@ -2781,14 +2784,14 @@ pub fn nativeTo(comptime T: type, x: T, desired_endianness: Endian) T {
2781pub fn nativeToLittle(comptime T: type, x: T) T {2784pub fn nativeToLittle(comptime T: type, x: T) T {
2782 return switch (native_endian) {2785 return switch (native_endian) {
2783 .Little => x,2786 .Little => x,
2784 .Big => @byteSwap(T, x),2787 .Big => @byteSwap(x),
2785 };2788 };
2786}2789}
27872790
2788/// Converts an integer which has host endianness to big endian.2791/// Converts an integer which has host endianness to big endian.
2789pub fn nativeToBig(comptime T: type, x: T) T {2792pub fn nativeToBig(comptime T: type, x: T) T {
2790 return switch (native_endian) {2793 return switch (native_endian) {
2791 .Little => @byteSwap(T, x),2794 .Little => @byteSwap(x),
2792 .Big => x,2795 .Big => x,
2793 };2796 };
2794}2797}
...@@ -2800,7 +2803,7 @@ pub fn nativeToBig(comptime T: type, x: T) T {...@@ -2800,7 +2803,7 @@ pub fn nativeToBig(comptime T: type, x: T) T {
2800/// - The delta required to align the pointer is not a multiple of the pointee's2803/// - The delta required to align the pointer is not a multiple of the pointee's
2801/// type.2804/// type.
2802pub fn alignPointerOffset(ptr: anytype, align_to: u29) ?usize {2805pub fn alignPointerOffset(ptr: anytype, align_to: u29) ?usize {
2803 assert(align_to != 0 and @popCount(u29, align_to) == 1);2806 assert(align_to != 0 and @popCount(align_to) == 1);
28042807
2805 const T = @TypeOf(ptr);2808 const T = @TypeOf(ptr);
2806 const info = @typeInfo(T);2809 const info = @typeInfo(T);
...@@ -3249,13 +3252,13 @@ test "sliceAsBytes preserves pointer attributes" {...@@ -3249,13 +3252,13 @@ test "sliceAsBytes preserves pointer attributes" {
3249 try testing.expectEqual(in.alignment, out.alignment);3252 try testing.expectEqual(in.alignment, out.alignment);
3250}3253}
32513254
3252/// Round an address up to the nearest aligned address3255/// Round an address up to the next (or current) aligned address.
3253/// The alignment must be a power of 2 and greater than 0.3256/// The alignment must be a power of 2 and greater than 0.
3254pub fn alignForward(addr: usize, alignment: usize) usize {3257pub fn alignForward(addr: usize, alignment: usize) usize {
3255 return alignForwardGeneric(usize, addr, alignment);3258 return alignForwardGeneric(usize, addr, alignment);
3256}3259}
32573260
3258/// Round an address up to the nearest aligned address3261/// Round an address up to the next (or current) aligned address.
3259/// The alignment must be a power of 2 and greater than 0.3262/// The alignment must be a power of 2 and greater than 0.
3260pub fn alignForwardGeneric(comptime T: type, addr: T, alignment: T) T {3263pub fn alignForwardGeneric(comptime T: type, addr: T, alignment: T) T {
3261 return alignBackwardGeneric(T, addr + (alignment - 1), alignment);3264 return alignBackwardGeneric(T, addr + (alignment - 1), alignment);
...@@ -3287,25 +3290,25 @@ test "alignForward" {...@@ -3287,25 +3290,25 @@ test "alignForward" {
3287 try testing.expect(alignForward(17, 8) == 24);3290 try testing.expect(alignForward(17, 8) == 24);
3288}3291}
32893292
3290/// Round an address up to the previous aligned address3293/// Round an address down to the previous (or current) aligned address.
3291/// Unlike `alignBackward`, `alignment` can be any positive number, not just a power of 2.3294/// Unlike `alignBackward`, `alignment` can be any positive number, not just a power of 2.
3292pub fn alignBackwardAnyAlign(i: usize, alignment: usize) usize {3295pub fn alignBackwardAnyAlign(i: usize, alignment: usize) usize {
3293 if (@popCount(usize, alignment) == 1)3296 if (@popCount(alignment) == 1)
3294 return alignBackward(i, alignment);3297 return alignBackward(i, alignment);
3295 assert(alignment != 0);3298 assert(alignment != 0);
3296 return i - @mod(i, alignment);3299 return i - @mod(i, alignment);
3297}3300}
32983301
3299/// Round an address up to the previous aligned address3302/// Round an address down to the previous (or current) aligned address.
3300/// The alignment must be a power of 2 and greater than 0.3303/// The alignment must be a power of 2 and greater than 0.
3301pub fn alignBackward(addr: usize, alignment: usize) usize {3304pub fn alignBackward(addr: usize, alignment: usize) usize {
3302 return alignBackwardGeneric(usize, addr, alignment);3305 return alignBackwardGeneric(usize, addr, alignment);
3303}3306}
33043307
3305/// Round an address up to the previous aligned address3308/// Round an address down to the previous (or current) aligned address.
3306/// The alignment must be a power of 2 and greater than 0.3309/// The alignment must be a power of 2 and greater than 0.
3307pub fn alignBackwardGeneric(comptime T: type, addr: T, alignment: T) T {3310pub fn alignBackwardGeneric(comptime T: type, addr: T, alignment: T) T {
3308 assert(@popCount(T, alignment) == 1);3311 assert(@popCount(alignment) == 1);
3309 // 000010000 // example alignment3312 // 000010000 // example alignment
3310 // 000001111 // subtract 13313 // 000001111 // subtract 1
3311 // 111110000 // binary not3314 // 111110000 // binary not
...@@ -3315,11 +3318,11 @@ pub fn alignBackwardGeneric(comptime T: type, addr: T, alignment: T) T {...@@ -3315,11 +3318,11 @@ pub fn alignBackwardGeneric(comptime T: type, addr: T, alignment: T) T {
3315/// Returns whether `alignment` is a valid alignment, meaning it is3318/// Returns whether `alignment` is a valid alignment, meaning it is
3316/// a positive power of 2.3319/// a positive power of 2.
3317pub fn isValidAlign(alignment: u29) bool {3320pub fn isValidAlign(alignment: u29) bool {
3318 return @popCount(u29, alignment) == 1;3321 return @popCount(alignment) == 1;
3319}3322}
33203323
3321pub fn isAlignedAnyAlign(i: usize, alignment: usize) bool {3324pub fn isAlignedAnyAlign(i: usize, alignment: usize) bool {
3322 if (@popCount(usize, alignment) == 1)3325 if (@popCount(alignment) == 1)
3323 return isAligned(i, alignment);3326 return isAligned(i, alignment);
3324 assert(alignment != 0);3327 assert(alignment != 0);
3325 return 0 == @mod(i, alignment);3328 return 0 == @mod(i, alignment);
lib/std/meta.zig+58-19
...@@ -764,7 +764,7 @@ const TagPayloadType = TagPayload;...@@ -764,7 +764,7 @@ const TagPayloadType = TagPayload;
764764
765///Given a tagged union type, and an enum, return the type of the union765///Given a tagged union type, and an enum, return the type of the union
766/// field corresponding to the enum tag.766/// field corresponding to the enum tag.
767pub fn TagPayload(comptime U: type, tag: Tag(U)) type {767pub fn TagPayload(comptime U: type, comptime tag: Tag(U)) type {
768 comptime debug.assert(trait.is(.Union)(U));768 comptime debug.assert(trait.is(.Union)(U));
769769
770 const info = @typeInfo(U).Union;770 const info = @typeInfo(U).Union;
...@@ -1024,28 +1024,13 @@ pub fn ArgsTuple(comptime Function: type) type {...@@ -1024,28 +1024,13 @@ pub fn ArgsTuple(comptime Function: type) type {
1024 if (function_info.is_var_args)1024 if (function_info.is_var_args)
1025 @compileError("Cannot create ArgsTuple for variadic function");1025 @compileError("Cannot create ArgsTuple for variadic function");
10261026
1027 var argument_field_list: [function_info.args.len]std.builtin.Type.StructField = undefined;1027 var argument_field_list: [function_info.args.len]type = undefined;
1028 inline for (function_info.args) |arg, i| {1028 inline for (function_info.args) |arg, i| {
1029 const T = arg.arg_type.?;1029 const T = arg.arg_type.?;
1030 @setEvalBranchQuota(10_000);1030 argument_field_list[i] = T;
1031 var num_buf: [128]u8 = undefined;
1032 argument_field_list[i] = .{
1033 .name = std.fmt.bufPrint(&num_buf, "{d}", .{i}) catch unreachable,
1034 .field_type = T,
1035 .default_value = null,
1036 .is_comptime = false,
1037 .alignment = if (@sizeOf(T) > 0) @alignOf(T) else 0,
1038 };
1039 }1031 }
10401032
1041 return @Type(.{1033 return CreateUniqueTuple(argument_field_list.len, argument_field_list);
1042 .Struct = .{
1043 .is_tuple = true,
1044 .layout = .Auto,
1045 .decls = &.{},
1046 .fields = &argument_field_list,
1047 },
1048 });
1049}1034}
10501035
1051/// For a given anonymous list of types, returns a new tuple type1036/// For a given anonymous list of types, returns a new tuple type
...@@ -1056,6 +1041,10 @@ pub fn ArgsTuple(comptime Function: type) type {...@@ -1056,6 +1041,10 @@ pub fn ArgsTuple(comptime Function: type) type {
1056/// - `Tuple(&[_]type {f32})` ⇒ `tuple { f32 }`1041/// - `Tuple(&[_]type {f32})` ⇒ `tuple { f32 }`
1057/// - `Tuple(&[_]type {f32,u32})` ⇒ `tuple { f32, u32 }`1042/// - `Tuple(&[_]type {f32,u32})` ⇒ `tuple { f32, u32 }`
1058pub fn Tuple(comptime types: []const type) type {1043pub fn Tuple(comptime types: []const type) type {
1044 return CreateUniqueTuple(types.len, types[0..types.len].*);
1045}
1046
1047fn CreateUniqueTuple(comptime N: comptime_int, comptime types: [N]type) type {
1059 var tuple_fields: [types.len]std.builtin.Type.StructField = undefined;1048 var tuple_fields: [types.len]std.builtin.Type.StructField = undefined;
1060 inline for (types) |T, i| {1049 inline for (types) |T, i| {
1061 @setEvalBranchQuota(10_000);1050 @setEvalBranchQuota(10_000);
...@@ -1118,6 +1107,32 @@ test "Tuple" {...@@ -1118,6 +1107,32 @@ test "Tuple" {
1118 TupleTester.assertTuple(.{ u32, f16, []const u8, void }, Tuple(&[_]type{ u32, f16, []const u8, void }));1107 TupleTester.assertTuple(.{ u32, f16, []const u8, void }, Tuple(&[_]type{ u32, f16, []const u8, void }));
1119}1108}
11201109
1110test "Tuple deduplication" {
1111 const T1 = std.meta.Tuple(&.{ u32, f32, i8 });
1112 const T2 = std.meta.Tuple(&.{ u32, f32, i8 });
1113 const T3 = std.meta.Tuple(&.{ u32, f32, i7 });
1114
1115 if (T1 != T2) {
1116 @compileError("std.meta.Tuple doesn't deduplicate tuple types.");
1117 }
1118 if (T1 == T3) {
1119 @compileError("std.meta.Tuple fails to generate different types.");
1120 }
1121}
1122
1123test "ArgsTuple forwarding" {
1124 const T1 = std.meta.Tuple(&.{ u32, f32, i8 });
1125 const T2 = std.meta.ArgsTuple(fn (u32, f32, i8) void);
1126 const T3 = std.meta.ArgsTuple(fn (u32, f32, i8) callconv(.C) noreturn);
1127
1128 if (T1 != T2) {
1129 @compileError("std.meta.ArgsTuple produces different types than std.meta.Tuple");
1130 }
1131 if (T1 != T3) {
1132 @compileError("std.meta.ArgsTuple produces different types for the same argument lists.");
1133 }
1134}
1135
1121/// TODO: https://github.com/ziglang/zig/issues/4251136/// TODO: https://github.com/ziglang/zig/issues/425
1122pub fn globalOption(comptime name: []const u8, comptime T: type) ?T {1137pub fn globalOption(comptime name: []const u8, comptime T: type) ?T {
1123 if (!@hasDecl(root, name))1138 if (!@hasDecl(root, name))
...@@ -1134,3 +1149,27 @@ test "isError" {...@@ -1134,3 +1149,27 @@ test "isError" {
1134 try std.testing.expect(isError(math.absInt(@as(i8, -128))));1149 try std.testing.expect(isError(math.absInt(@as(i8, -128))));
1135 try std.testing.expect(!isError(math.absInt(@as(i8, -127))));1150 try std.testing.expect(!isError(math.absInt(@as(i8, -127))));
1136}1151}
1152
1153/// This function returns a function pointer for a given function signature.
1154/// It's a helper to make code compatible to both stage1 and stage2.
1155///
1156/// **WARNING:** This function is deprecated and will be removed together with stage1.
1157pub fn FnPtr(comptime Fn: type) type {
1158 return if (@import("builtin").zig_backend != .stage1)
1159 *const Fn
1160 else
1161 Fn;
1162}
1163
1164test "FnPtr" {
1165 var func: FnPtr(fn () i64) = undefined;
1166
1167 // verify that we can perform runtime exchange
1168 // and not have a function body in stage2:
1169
1170 func = std.time.timestamp;
1171 _ = func();
1172
1173 func = std.time.milliTimestamp;
1174 _ = func();
1175}
lib/std/multi_array_list.zig+1-1
...@@ -459,7 +459,7 @@ pub fn MultiArrayList(comptime S: type) type {...@@ -459,7 +459,7 @@ pub fn MultiArrayList(comptime S: type) type {
459 return self.bytes[0..capacityInBytes(self.capacity)];459 return self.bytes[0..capacityInBytes(self.capacity)];
460 }460 }
461461
462 fn FieldType(field: Field) type {462 fn FieldType(comptime field: Field) type {
463 return meta.fieldInfo(S, field).field_type;463 return meta.fieldInfo(S, field).field_type;
464 }464 }
465465
lib/std/os.zig+11-11
...@@ -475,10 +475,9 @@ pub fn abort() noreturn {...@@ -475,10 +475,9 @@ pub fn abort() noreturn {
475475
476 // Install default handler so that the tkill below will terminate.476 // Install default handler so that the tkill below will terminate.
477 const sigact = Sigaction{477 const sigact = Sigaction{
478 .handler = .{ .sigaction = SIG.DFL },478 .handler = .{ .handler = SIG.DFL },
479 .mask = undefined,479 .mask = empty_sigset,
480 .flags = undefined,480 .flags = 0,
481 .restorer = undefined,
482 };481 };
483 sigaction(SIG.ABRT, &sigact, null) catch |err| switch (err) {482 sigaction(SIG.ABRT, &sigact, null) catch |err| switch (err) {
484 error.OperationNotSupported => unreachable,483 error.OperationNotSupported => unreachable,
...@@ -953,6 +952,10 @@ pub const WriteError = error{...@@ -953,6 +952,10 @@ pub const WriteError = error{
953 OperationAborted,952 OperationAborted,
954 NotOpenForWriting,953 NotOpenForWriting,
955954
955 /// The process cannot access the file because another process has locked
956 /// a portion of the file. Windows-only.
957 LockViolation,
958
956 /// This error occurs when no global event loop is configured,959 /// This error occurs when no global event loop is configured,
957 /// and reading from the file descriptor would block.960 /// and reading from the file descriptor would block.
958 WouldBlock,961 WouldBlock,
...@@ -2648,6 +2651,7 @@ pub fn renameatW(...@@ -2648,6 +2651,7 @@ pub fn renameatW(
2648 .creation = windows.FILE_OPEN,2651 .creation = windows.FILE_OPEN,
2649 .io_mode = .blocking,2652 .io_mode = .blocking,
2650 .filter = .any, // This function is supposed to rename both files and directories.2653 .filter = .any, // This function is supposed to rename both files and directories.
2654 .follow_symlinks = false,
2651 }) catch |err| switch (err) {2655 }) catch |err| switch (err) {
2652 error.WouldBlock => unreachable, // Not possible without `.share_access_nonblocking = true`.2656 error.WouldBlock => unreachable, // Not possible without `.share_access_nonblocking = true`.
2653 else => |e| return e,2657 else => |e| return e,
...@@ -5443,11 +5447,7 @@ pub fn toPosixPath(file_path: []const u8) ![MAX_PATH_BYTES - 1:0]u8 {...@@ -5443,11 +5447,7 @@ pub fn toPosixPath(file_path: []const u8) ![MAX_PATH_BYTES - 1:0]u8 {
5443/// if this happens the fix is to add the error code to the corresponding5447/// if this happens the fix is to add the error code to the corresponding
5444/// switch expression, possibly introduce a new error in the error set, and5448/// switch expression, possibly introduce a new error in the error set, and
5445/// send a patch to Zig.5449/// send a patch to Zig.
5446/// The self-hosted compiler is not fully capable of handle the related code.5450pub const unexpected_error_tracing = (builtin.zig_backend == .stage1 or builtin.zig_backend == .stage2_llvm) and builtin.mode == .Debug;
5447/// Until then, unexpected error tracing is disabled for the self-hosted compiler.
5448/// TODO remove this once self-hosted is capable enough to handle printing and
5449/// stack trace dumping.
5450pub const unexpected_error_tracing = builtin.zig_backend == .stage1 and builtin.mode == .Debug;
54515451
5452pub const UnexpectedError = error{5452pub const UnexpectedError = error{
5453 /// The Operating System returned an undocumented error code.5453 /// The Operating System returned an undocumented error code.
...@@ -6251,7 +6251,7 @@ pub const CopyFileRangeError = error{...@@ -6251,7 +6251,7 @@ pub const CopyFileRangeError = error{
6251 NoSpaceLeft,6251 NoSpaceLeft,
6252 Unseekable,6252 Unseekable,
6253 PermissionDenied,6253 PermissionDenied,
6254 FileBusy,6254 SwapFile,
6255} || PReadError || PWriteError || UnexpectedError;6255} || PReadError || PWriteError || UnexpectedError;
62566256
6257var has_copy_file_range_syscall = std.atomic.Atomic(bool).init(true);6257var has_copy_file_range_syscall = std.atomic.Atomic(bool).init(true);
...@@ -6305,7 +6305,7 @@ pub fn copy_file_range(fd_in: fd_t, off_in: u64, fd_out: fd_t, off_out: u64, len...@@ -6305,7 +6305,7 @@ pub fn copy_file_range(fd_in: fd_t, off_in: u64, fd_out: fd_t, off_out: u64, len
6305 .NOSPC => return error.NoSpaceLeft,6305 .NOSPC => return error.NoSpaceLeft,
6306 .OVERFLOW => return error.Unseekable,6306 .OVERFLOW => return error.Unseekable,
6307 .PERM => return error.PermissionDenied,6307 .PERM => return error.PermissionDenied,
6308 .TXTBSY => return error.FileBusy,6308 .TXTBSY => return error.SwapFile,
6309 // these may not be regular files, try fallback6309 // these may not be regular files, try fallback
6310 .INVAL => {},6310 .INVAL => {},
6311 // support for cross-filesystem copy added in Linux 5.3, use fallback6311 // support for cross-filesystem copy added in Linux 5.3, use fallback
lib/std/os/linux.zig+10-10
...@@ -1945,9 +1945,9 @@ pub const SIG = if (is_mips) struct {...@@ -1945,9 +1945,9 @@ pub const SIG = if (is_mips) struct {
1945 pub const SYS = 31;1945 pub const SYS = 31;
1946 pub const UNUSED = SIG.SYS;1946 pub const UNUSED = SIG.SYS;
19471947
1948 pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));1948 pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
1949 pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0);1949 pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
1950 pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1);1950 pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
1951} else if (is_sparc) struct {1951} else if (is_sparc) struct {
1952 pub const BLOCK = 1;1952 pub const BLOCK = 1;
1953 pub const UNBLOCK = 2;1953 pub const UNBLOCK = 2;
...@@ -1989,9 +1989,9 @@ pub const SIG = if (is_mips) struct {...@@ -1989,9 +1989,9 @@ pub const SIG = if (is_mips) struct {
1989 pub const PWR = LOST;1989 pub const PWR = LOST;
1990 pub const IO = SIG.POLL;1990 pub const IO = SIG.POLL;
19911991
1992 pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));1992 pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
1993 pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0);1993 pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
1994 pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1);1994 pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
1995} else struct {1995} else struct {
1996 pub const BLOCK = 0;1996 pub const BLOCK = 0;
1997 pub const UNBLOCK = 1;1997 pub const UNBLOCK = 1;
...@@ -2032,9 +2032,9 @@ pub const SIG = if (is_mips) struct {...@@ -2032,9 +2032,9 @@ pub const SIG = if (is_mips) struct {
2032 pub const SYS = 31;2032 pub const SYS = 31;
2033 pub const UNUSED = SIG.SYS;2033 pub const UNUSED = SIG.SYS;
20342034
2035 pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));2035 pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
2036 pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0);2036 pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
2037 pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1);2037 pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
2038};2038};
20392039
2040pub const kernel_rwf = u32;2040pub const kernel_rwf = u32;
...@@ -3377,7 +3377,7 @@ pub const cpu_count_t = std.meta.Int(.unsigned, std.math.log2(CPU_SETSIZE * 8));...@@ -3377,7 +3377,7 @@ pub const cpu_count_t = std.meta.Int(.unsigned, std.math.log2(CPU_SETSIZE * 8));
3377pub fn CPU_COUNT(set: cpu_set_t) cpu_count_t {3377pub fn CPU_COUNT(set: cpu_set_t) cpu_count_t {
3378 var sum: cpu_count_t = 0;3378 var sum: cpu_count_t = 0;
3379 for (set) |x| {3379 for (set) |x| {
3380 sum += @popCount(usize, x);3380 sum += @popCount(x);
3381 }3381 }
3382 return sum;3382 return sum;
3383}3383}
lib/std/os/linux/bpf.zig+1-1
...@@ -458,7 +458,7 @@ pub const Insn = packed struct {...@@ -458,7 +458,7 @@ pub const Insn = packed struct {
458 else458 else
459 ImmOrReg{ .imm = src };459 ImmOrReg{ .imm = src };
460460
461 const src_type = switch (imm_or_reg) {461 const src_type: u8 = switch (imm_or_reg) {
462 .imm => K,462 .imm => K,
463 .reg => X,463 .reg => X,
464 };464 };
lib/std/os/linux/syscalls.zig+1
...@@ -3485,6 +3485,7 @@ pub const RiscV64 = enum(usize) {...@@ -3485,6 +3485,7 @@ pub const RiscV64 = enum(usize) {
3485 landlock_create_ruleset = 444,3485 landlock_create_ruleset = 444,
3486 landlock_add_rule = 445,3486 landlock_add_rule = 445,
3487 landlock_restrict_self = 446,3487 landlock_restrict_self = 446,
3488 memfd_secret = 447,
3488 process_mrelease = 448,3489 process_mrelease = 448,
3489 futex_waitv = 449,3490 futex_waitv = 449,
3490 set_mempolicy_home_node = 450,3491 set_mempolicy_home_node = 450,
lib/std/os/plan9.zig+1-1
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
33
4pub const syscall_bits = switch (builtin.stage2_arch) {4pub const syscall_bits = switch (builtin.cpu.arch) {
5 .x86_64 => @import("plan9/x86_64.zig"),5 .x86_64 => @import("plan9/x86_64.zig"),
6 else => @compileError("more plan9 syscall implementations (needs more inline asm in stage2"),6 else => @compileError("more plan9 syscall implementations (needs more inline asm in stage2"),
7};7};
lib/std/os/test.zig+1-1
...@@ -785,7 +785,7 @@ test "sigaction" {...@@ -785,7 +785,7 @@ test "sigaction" {
785 try testing.expect(signal_test_failed == false);785 try testing.expect(signal_test_failed == false);
786 // Check if the handler has been correctly reset to SIG_DFL786 // Check if the handler has been correctly reset to SIG_DFL
787 try os.sigaction(os.SIG.USR1, null, &old_sa);787 try os.sigaction(os.SIG.USR1, null, &old_sa);
788 try testing.expectEqual(os.SIG.DFL, old_sa.handler.sigaction);788 try testing.expectEqual(os.SIG.DFL, old_sa.handler.handler);
789}789}
790790
791test "dup & dup2" {791test "dup & dup2" {
lib/std/os/uefi.zig+3-3
...@@ -55,9 +55,9 @@ pub const Guid = extern struct {...@@ -55,9 +55,9 @@ pub const Guid = extern struct {
55 if (f.len == 0) {55 if (f.len == 0) {
56 const fmt = std.fmt.fmtSliceHexLower;56 const fmt = std.fmt.fmtSliceHexLower;
5757
58 const time_low = @byteSwap(u32, self.time_low);58 const time_low = @byteSwap(self.time_low);
59 const time_mid = @byteSwap(u16, self.time_mid);59 const time_mid = @byteSwap(self.time_mid);
60 const time_high_and_version = @byteSwap(u16, self.time_high_and_version);60 const time_high_and_version = @byteSwap(self.time_high_and_version);
6161
62 return std.fmt.format(writer, "{:0>8}-{:0>4}-{:0>4}-{:0>2}{:0>2}-{:0>12}", .{62 return std.fmt.format(writer, "{:0>8}-{:0>4}-{:0>4}-{:0>2}{:0>2}-{:0>12}", .{
63 fmt(std.mem.asBytes(&time_low)),63 fmt(std.mem.asBytes(&time_low)),
lib/std/os/windows.zig+5-1
...@@ -517,6 +517,9 @@ pub const WriteFileError = error{...@@ -517,6 +517,9 @@ pub const WriteFileError = error{
517 OperationAborted,517 OperationAborted,
518 BrokenPipe,518 BrokenPipe,
519 NotOpenForWriting,519 NotOpenForWriting,
520 /// The process cannot access the file because another process has locked
521 /// a portion of the file.
522 LockViolation,
520 Unexpected,523 Unexpected,
521};524};
522525
...@@ -597,6 +600,7 @@ pub fn WriteFile(...@@ -597,6 +600,7 @@ pub fn WriteFile(
597 .IO_PENDING => unreachable,600 .IO_PENDING => unreachable,
598 .BROKEN_PIPE => return error.BrokenPipe,601 .BROKEN_PIPE => return error.BrokenPipe,
599 .INVALID_HANDLE => return error.NotOpenForWriting,602 .INVALID_HANDLE => return error.NotOpenForWriting,
603 .LOCK_VIOLATION => return error.LockViolation,
600 else => |err| return unexpectedError(err),604 else => |err| return unexpectedError(err),
601 }605 }
602 }606 }
...@@ -1798,7 +1802,7 @@ pub const PathSpace = struct {...@@ -1798,7 +1802,7 @@ pub const PathSpace = struct {
1798 data: [PATH_MAX_WIDE:0]u16,1802 data: [PATH_MAX_WIDE:0]u16,
1799 len: usize,1803 len: usize,
18001804
1801 pub fn span(self: PathSpace) [:0]const u16 {1805 pub fn span(self: *const PathSpace) [:0]const u16 {
1802 return self.data[0..self.len :0];1806 return self.data[0..self.len :0];
1803 }1807 }
1804};1808};
lib/std/packed_int_array.zig+3-3
...@@ -76,7 +76,7 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type {...@@ -76,7 +76,7 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type {
76 const value_ptr = @ptrCast(*align(1) const Container, &bytes[start_byte]);76 const value_ptr = @ptrCast(*align(1) const Container, &bytes[start_byte]);
77 var value = value_ptr.*;77 var value = value_ptr.*;
7878
79 if (endian != native_endian) value = @byteSwap(Container, value);79 if (endian != native_endian) value = @byteSwap(value);
8080
81 switch (endian) {81 switch (endian) {
82 .Big => {82 .Big => {
...@@ -126,7 +126,7 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type {...@@ -126,7 +126,7 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type {
126 const target_ptr = @ptrCast(*align(1) Container, &bytes[start_byte]);126 const target_ptr = @ptrCast(*align(1) Container, &bytes[start_byte]);
127 var target = target_ptr.*;127 var target = target_ptr.*;
128128
129 if (endian != native_endian) target = @byteSwap(Container, target);129 if (endian != native_endian) target = @byteSwap(target);
130130
131 //zero the bits we want to replace in the existing bytes131 //zero the bits we want to replace in the existing bytes
132 const inv_mask = @intCast(Container, std.math.maxInt(UnInt)) << keep_shift;132 const inv_mask = @intCast(Container, std.math.maxInt(UnInt)) << keep_shift;
...@@ -136,7 +136,7 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type {...@@ -136,7 +136,7 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type {
136 //merge the new value136 //merge the new value
137 target |= value;137 target |= value;
138138
139 if (endian != native_endian) target = @byteSwap(Container, target);139 if (endian != native_endian) target = @byteSwap(target);
140140
141 //save it back141 //save it back
142 target_ptr.* = target;142 target_ptr.* = target;
lib/std/pdb.zig+6-3
...@@ -310,6 +310,10 @@ pub const SymbolKind = enum(u16) {...@@ -310,6 +310,10 @@ pub const SymbolKind = enum(u16) {
310310
311pub const TypeIndex = u32;311pub const TypeIndex = u32;
312312
313// TODO According to this header:
314// https://github.com/microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L3722
315// we should define RecordPrefix as part of the ProcSym structure.
316// This might be important when we start generating PDB in self-hosted with our own PE linker.
313pub const ProcSym = extern struct {317pub const ProcSym = extern struct {
314 Parent: u32,318 Parent: u32,
315 End: u32,319 End: u32,
...@@ -321,8 +325,7 @@ pub const ProcSym = extern struct {...@@ -321,8 +325,7 @@ pub const ProcSym = extern struct {
321 CodeOffset: u32,325 CodeOffset: u32,
322 Segment: u16,326 Segment: u16,
323 Flags: ProcSymFlags,327 Flags: ProcSymFlags,
324 // following is a null terminated string328 Name: [1]u8, // null-terminated
325 // Name: [*]u8,
326};329};
327330
328pub const ProcSymFlags = packed struct {331pub const ProcSymFlags = packed struct {
...@@ -693,7 +696,7 @@ pub const Pdb = struct {...@@ -693,7 +696,7 @@ pub const Pdb = struct {
693 .S_LPROC32, .S_GPROC32 => {696 .S_LPROC32, .S_GPROC32 => {
694 const proc_sym = @ptrCast(*align(1) ProcSym, &module.symbols[symbol_i + @sizeOf(RecordPrefix)]);697 const proc_sym = @ptrCast(*align(1) ProcSym, &module.symbols[symbol_i + @sizeOf(RecordPrefix)]);
695 if (address >= proc_sym.CodeOffset and address < proc_sym.CodeOffset + proc_sym.CodeSize) {698 if (address >= proc_sym.CodeOffset and address < proc_sym.CodeOffset + proc_sym.CodeSize) {
696 return mem.sliceTo(@ptrCast([*:0]u8, proc_sym) + @sizeOf(ProcSym), 0);699 return mem.sliceTo(@ptrCast([*:0]u8, &proc_sym.Name[0]), 0);
697 }700 }
698 },701 },
699 else => {},702 else => {},
lib/std/priority_dequeue.zig+1-1
...@@ -69,7 +69,7 @@ pub fn PriorityDequeue(comptime T: type, comptime Context: type, comptime compar...@@ -69,7 +69,7 @@ pub fn PriorityDequeue(comptime T: type, comptime Context: type, comptime compar
69 // The first element is on a min layer;69 // The first element is on a min layer;
70 // next two are on a max layer;70 // next two are on a max layer;
71 // next four are on a min layer, and so on.71 // next four are on a min layer, and so on.
72 const leading_zeros = @clz(usize, index + 1);72 const leading_zeros = @clz(index + 1);
73 const highest_set_bit = @bitSizeOf(usize) - 1 - leading_zeros;73 const highest_set_bit = @bitSizeOf(usize) - 1 - leading_zeros;
74 return (highest_set_bit & 1) == 0;74 return (highest_set_bit & 1) == 0;
75 }75 }
lib/std/rand.zig+41-5
...@@ -257,15 +257,15 @@ pub const Random = struct {...@@ -257,15 +257,15 @@ pub const Random = struct {
257 // If all 41 bits are zero, generate additional random bits, until a257 // If all 41 bits are zero, generate additional random bits, until a
258 // set bit is found, or 126 bits have been generated.258 // set bit is found, or 126 bits have been generated.
259 const rand = r.int(u64);259 const rand = r.int(u64);
260 var rand_lz = @clz(u64, rand);260 var rand_lz = @clz(rand);
261 if (rand_lz >= 41) {261 if (rand_lz >= 41) {
262 // TODO: when #5177 or #489 is implemented,262 // TODO: when #5177 or #489 is implemented,
263 // tell the compiler it is unlikely (1/2^41) to reach this point.263 // tell the compiler it is unlikely (1/2^41) to reach this point.
264 // (Same for the if branch and the f64 calculations below.)264 // (Same for the if branch and the f64 calculations below.)
265 rand_lz = 41 + @clz(u64, r.int(u64));265 rand_lz = 41 + @clz(r.int(u64));
266 if (rand_lz == 41 + 64) {266 if (rand_lz == 41 + 64) {
267 // It is astronomically unlikely to reach this point.267 // It is astronomically unlikely to reach this point.
268 rand_lz += @clz(u32, r.int(u32) | 0x7FF);268 rand_lz += @clz(r.int(u32) | 0x7FF);
269 }269 }
270 }270 }
271 const mantissa = @truncate(u23, rand);271 const mantissa = @truncate(u23, rand);
...@@ -277,12 +277,12 @@ pub const Random = struct {...@@ -277,12 +277,12 @@ pub const Random = struct {
277 // If all 12 bits are zero, generate additional random bits, until a277 // If all 12 bits are zero, generate additional random bits, until a
278 // set bit is found, or 1022 bits have been generated.278 // set bit is found, or 1022 bits have been generated.
279 const rand = r.int(u64);279 const rand = r.int(u64);
280 var rand_lz: u64 = @clz(u64, rand);280 var rand_lz: u64 = @clz(rand);
281 if (rand_lz >= 12) {281 if (rand_lz >= 12) {
282 rand_lz = 12;282 rand_lz = 12;
283 while (true) {283 while (true) {
284 // It is astronomically unlikely for this loop to execute more than once.284 // It is astronomically unlikely for this loop to execute more than once.
285 const addl_rand_lz = @clz(u64, r.int(u64));285 const addl_rand_lz = @clz(r.int(u64));
286 rand_lz += addl_rand_lz;286 rand_lz += addl_rand_lz;
287 if (addl_rand_lz != 64) {287 if (addl_rand_lz != 64) {
288 break;288 break;
...@@ -337,6 +337,42 @@ pub const Random = struct {...@@ -337,6 +337,42 @@ pub const Random = struct {
337 mem.swap(T, &buf[i], &buf[j]);337 mem.swap(T, &buf[i], &buf[j]);
338 }338 }
339 }339 }
340
341 /// Randomly selects an index into `proportions`, where the likelihood of each
342 /// index is weighted by that proportion.
343 ///
344 /// This is useful for selecting an item from a slice where weights are not equal.
345 /// `T` must be a numeric type capable of holding the sum of `proportions`.
346 pub fn weightedIndex(r: std.rand.Random, comptime T: type, proportions: []T) usize {
347 // This implementation works by summing the proportions and picking a random
348 // point in [0, sum). We then loop over the proportions, accumulating
349 // until our accumulator is greater than the random point.
350
351 var sum: T = 0;
352 for (proportions) |v| {
353 sum += v;
354 }
355
356 const point = if (comptime std.meta.trait.isSignedInt(T))
357 r.intRangeLessThan(T, 0, sum)
358 else if (comptime std.meta.trait.isUnsignedInt(T))
359 r.uintLessThan(T, sum)
360 else if (comptime std.meta.trait.isFloat(T))
361 // take care that imprecision doesn't lead to a value slightly greater than sum
362 std.math.min(r.float(T) * sum, sum - std.math.epsilon(T))
363 else
364 @compileError("weightedIndex does not support proportions of type " ++ @typeName(T));
365
366 std.debug.assert(point < sum);
367
368 var accumulator: T = 0;
369 for (proportions) |p, index| {
370 accumulator += p;
371 if (point < accumulator) return index;
372 }
373
374 unreachable;
375 }
340};376};
341377
342/// Convert a random integer 0 <= random_int <= maxValue(T),378/// Convert a random integer 0 <= random_int <= maxValue(T),
lib/std/rand/test.zig+26
...@@ -445,3 +445,29 @@ test "CSPRNG" {...@@ -445,3 +445,29 @@ test "CSPRNG" {
445 const c = random.int(u64);445 const c = random.int(u64);
446 try expect(a ^ b ^ c != 0);446 try expect(a ^ b ^ c != 0);
447}447}
448
449test "Random weightedIndex" {
450 // Make sure weightedIndex works for various integers and floats
451 inline for (.{ u64, i4, f32, f64 }) |T| {
452 var prng = DefaultPrng.init(0);
453 const random = prng.random();
454
455 var proportions = [_]T{ 2, 1, 1, 2 };
456 var counts = [_]f64{ 0, 0, 0, 0 };
457
458 const n_trials: u64 = 10_000;
459 var i: usize = 0;
460 while (i < n_trials) : (i += 1) {
461 const pick = random.weightedIndex(T, &proportions);
462 counts[pick] += 1;
463 }
464
465 // We expect the first and last counts to be roughly 2x the second and third
466 const approxEqRel = std.math.approxEqRel;
467 // Define "roughly" to be within 10%
468 const tolerance = 0.1;
469 try std.testing.expect(approxEqRel(f64, counts[0], counts[1] * 2, tolerance));
470 try std.testing.expect(approxEqRel(f64, counts[1], counts[2], tolerance));
471 try std.testing.expect(approxEqRel(f64, counts[2] * 2, counts[3], tolerance));
472 }
473}
lib/std/start.zig+2-2
...@@ -131,7 +131,7 @@ fn wWinMainCRTStartup2() callconv(.C) noreturn {...@@ -131,7 +131,7 @@ fn wWinMainCRTStartup2() callconv(.C) noreturn {
131131
132fn exit2(code: usize) noreturn {132fn exit2(code: usize) noreturn {
133 switch (native_os) {133 switch (native_os) {
134 .linux => switch (builtin.stage2_arch) {134 .linux => switch (builtin.cpu.arch) {
135 .x86_64 => {135 .x86_64 => {
136 asm volatile ("syscall"136 asm volatile ("syscall"
137 :137 :
...@@ -175,7 +175,7 @@ fn exit2(code: usize) noreturn {...@@ -175,7 +175,7 @@ fn exit2(code: usize) noreturn {
175 else => @compileError("TODO"),175 else => @compileError("TODO"),
176 },176 },
177 // exits(0)177 // exits(0)
178 .plan9 => switch (builtin.stage2_arch) {178 .plan9 => switch (builtin.cpu.arch) {
179 .x86_64 => {179 .x86_64 => {
180 asm volatile (180 asm volatile (
181 \\push $0181 \\push $0
lib/std/target.zig+26-24
...@@ -9,6 +9,7 @@ pub const Target = struct {...@@ -9,6 +9,7 @@ pub const Target = struct {
9 cpu: Cpu,9 cpu: Cpu,
10 os: Os,10 os: Os,
11 abi: Abi,11 abi: Abi,
12 ofmt: ObjectFormat,
1213
13 pub const Os = struct {14 pub const Os = struct {
14 tag: Tag,15 tag: Tag,
...@@ -624,6 +625,20 @@ pub const Target = struct {...@@ -624,6 +625,20 @@ pub const Target = struct {
624 .dxcontainer => @panic("TODO what's the extension for these?"),625 .dxcontainer => @panic("TODO what's the extension for these?"),
625 };626 };
626 }627 }
628
629 pub fn default(os_tag: Os.Tag, cpu_arch: Cpu.Arch) ObjectFormat {
630 return switch (os_tag) {
631 .windows, .uefi => .coff,
632 .ios, .macos, .watchos, .tvos => .macho,
633 .plan9 => .plan9,
634 else => return switch (cpu_arch) {
635 .wasm32, .wasm64 => .wasm,
636 .spirv32, .spirv64 => .spirv,
637 .nvptx, .nvptx64 => .nvptx,
638 else => .elf,
639 },
640 };
641 }
627 };642 };
628643
629 pub const SubSystem = enum {644 pub const SubSystem = enum {
...@@ -1426,24 +1441,6 @@ pub const Target = struct {...@@ -1426,24 +1441,6 @@ pub const Target = struct {
1426 return libPrefix_os_abi(self.os.tag, self.abi);1441 return libPrefix_os_abi(self.os.tag, self.abi);
1427 }1442 }
14281443
1429 pub fn getObjectFormatSimple(os_tag: Os.Tag, cpu_arch: Cpu.Arch) ObjectFormat {
1430 return switch (os_tag) {
1431 .windows, .uefi => .coff,
1432 .ios, .macos, .watchos, .tvos => .macho,
1433 .plan9 => .plan9,
1434 else => return switch (cpu_arch) {
1435 .wasm32, .wasm64 => .wasm,
1436 .spirv32, .spirv64 => .spirv,
1437 .nvptx, .nvptx64 => .nvptx,
1438 else => .elf,
1439 },
1440 };
1441 }
1442
1443 pub fn getObjectFormat(self: Target) ObjectFormat {
1444 return getObjectFormatSimple(self.os.tag, self.cpu.arch);
1445 }
1446
1447 pub fn isMinGW(self: Target) bool {1444 pub fn isMinGW(self: Target) bool {
1448 return self.os.tag == .windows and self.isGnu();1445 return self.os.tag == .windows and self.isGnu();
1449 }1446 }
...@@ -1801,10 +1798,11 @@ pub const Target = struct {...@@ -1801,10 +1798,11 @@ pub const Target = struct {
1801 else => false,1798 else => false,
1802 },1799 },
1803 f64 => switch (target.cpu.arch) {1800 f64 => switch (target.cpu.arch) {
1801 .aarch64 => target.isDarwin(),
1802
1804 .x86_64,1803 .x86_64,
1805 .i386,1804 .i386,
1806 .riscv64,1805 .riscv64,
1807 .aarch64,
1808 .aarch64_be,1806 .aarch64_be,
1809 .aarch64_32,1807 .aarch64_32,
1810 .s390x,1808 .s390x,
...@@ -1856,24 +1854,28 @@ pub const Target = struct {...@@ -1856,24 +1854,28 @@ pub const Target = struct {
1856 else => 4,1854 else => 4,
1857 },1855 },
18581856
1859 // For x86_64, LLVMABIAlignmentOfType(i128) reports 8. However I think 161857 // For these, LLVMABIAlignmentOfType(i128) reports 8. Note that 16
1860 // is a better number for two reasons:1858 // is a relevant number in three cases:
1861 // 1. Better machine code when loading into SIMD register.1859 // 1. Different machine code instruction when loading into SIMD register.
1862 // 2. The C ABI wants 16 for extern structs.1860 // 2. The C ABI wants 16 for extern structs.
1863 // 3. 16-byte cmpxchg needs 16-byte alignment.1861 // 3. 16-byte cmpxchg needs 16-byte alignment.
1864 // Same logic for riscv64, powerpc64, mips64, sparc64.1862 // Same logic for powerpc64, mips64, sparc64.
1865 .x86_64,1863 .x86_64,
1866 .riscv64,
1867 .powerpc64,1864 .powerpc64,
1868 .powerpc64le,1865 .powerpc64le,
1869 .mips64,1866 .mips64,
1870 .mips64el,1867 .mips64el,
1871 .sparc64,1868 .sparc64,
1869 => return switch (target.ofmt) {
1870 .c => 16,
1871 else => 8,
1872 },
18721873
1873 // Even LLVMABIAlignmentOfType(i128) agrees on these targets.1874 // Even LLVMABIAlignmentOfType(i128) agrees on these targets.
1874 .aarch64,1875 .aarch64,
1875 .aarch64_be,1876 .aarch64_be,
1876 .aarch64_32,1877 .aarch64_32,
1878 .riscv64,
1877 .bpfel,1879 .bpfel,
1878 .bpfeb,1880 .bpfeb,
1879 .nvptx,1881 .nvptx,
lib/std/valgrind/callgrind.zig+1-1
...@@ -2,7 +2,7 @@ const std = @import("../std.zig");...@@ -2,7 +2,7 @@ const std = @import("../std.zig");
2const valgrind = std.valgrind;2const valgrind = std.valgrind;
33
4pub const CallgrindClientRequest = enum(usize) {4pub const CallgrindClientRequest = enum(usize) {
5 DumpStats = valgrind.ToolBase("CT"),5 DumpStats = valgrind.ToolBase("CT".*),
6 ZeroStats,6 ZeroStats,
7 ToggleCollect,7 ToggleCollect,
8 DumpStatsAt,8 DumpStatsAt,
lib/std/zig.zig+7-5
...@@ -103,7 +103,6 @@ pub const BinNameOptions = struct {...@@ -103,7 +103,6 @@ pub const BinNameOptions = struct {
103 target: std.Target,103 target: std.Target,
104 output_mode: std.builtin.OutputMode,104 output_mode: std.builtin.OutputMode,
105 link_mode: ?std.builtin.LinkMode = null,105 link_mode: ?std.builtin.LinkMode = null,
106 object_format: ?std.Target.ObjectFormat = null,
107 version: ?std.builtin.Version = null,106 version: ?std.builtin.Version = null,
108};107};
109108
...@@ -111,8 +110,7 @@ pub const BinNameOptions = struct {...@@ -111,8 +110,7 @@ pub const BinNameOptions = struct {
111pub fn binNameAlloc(allocator: std.mem.Allocator, options: BinNameOptions) error{OutOfMemory}![]u8 {110pub fn binNameAlloc(allocator: std.mem.Allocator, options: BinNameOptions) error{OutOfMemory}![]u8 {
112 const root_name = options.root_name;111 const root_name = options.root_name;
113 const target = options.target;112 const target = options.target;
114 const ofmt = options.object_format orelse target.getObjectFormat();113 switch (target.ofmt) {
115 switch (ofmt) {
116 .coff => switch (options.output_mode) {114 .coff => switch (options.output_mode) {
117 .Exe => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, target.exeFileExt() }),115 .Exe => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, target.exeFileExt() }),
118 .Lib => {116 .Lib => {
...@@ -186,8 +184,12 @@ pub fn binNameAlloc(allocator: std.mem.Allocator, options: BinNameOptions) error...@@ -186,8 +184,12 @@ pub fn binNameAlloc(allocator: std.mem.Allocator, options: BinNameOptions) error
186 .raw => return std.fmt.allocPrint(allocator, "{s}.bin", .{root_name}),184 .raw => return std.fmt.allocPrint(allocator, "{s}.bin", .{root_name}),
187 .plan9 => switch (options.output_mode) {185 .plan9 => switch (options.output_mode) {
188 .Exe => return allocator.dupe(u8, root_name),186 .Exe => return allocator.dupe(u8, root_name),
189 .Obj => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, ofmt.fileExt(target.cpu.arch) }),187 .Obj => return std.fmt.allocPrint(allocator, "{s}{s}", .{
190 .Lib => return std.fmt.allocPrint(allocator, "{s}{s}.a", .{ target.libPrefix(), root_name }),188 root_name, target.ofmt.fileExt(target.cpu.arch),
189 }),
190 .Lib => return std.fmt.allocPrint(allocator, "{s}{s}.a", .{
191 target.libPrefix(), root_name,
192 }),
191 },193 },
192 .nvptx => return std.fmt.allocPrint(allocator, "{s}", .{root_name}),194 .nvptx => return std.fmt.allocPrint(allocator, "{s}", .{root_name}),
193 .dxcontainer => @panic("TODO what's the file extension for these?"),195 .dxcontainer => @panic("TODO what's the file extension for these?"),
lib/std/zig/Ast.zig+1-1
...@@ -2967,7 +2967,7 @@ pub const Node = struct {...@@ -2967,7 +2967,7 @@ pub const Node = struct {
2967 /// Same as ContainerDeclTwo except there is known to be a trailing comma2967 /// Same as ContainerDeclTwo except there is known to be a trailing comma
2968 /// or semicolon before the rbrace.2968 /// or semicolon before the rbrace.
2969 container_decl_two_trailing,2969 container_decl_two_trailing,
2970 /// `union(lhs)` / `enum(lhs)`. `SubRange[rhs]`.2970 /// `struct(lhs)` / `union(lhs)` / `enum(lhs)`. `SubRange[rhs]`.
2971 container_decl_arg,2971 container_decl_arg,
2972 /// Same as container_decl_arg but there is known to be a trailing2972 /// Same as container_decl_arg but there is known to be a trailing
2973 /// comma or semicolon before the rbrace.2973 /// comma or semicolon before the rbrace.
lib/std/zig/CrossTarget.zig+12-1
...@@ -42,6 +42,9 @@ abi: ?Target.Abi = null,...@@ -42,6 +42,9 @@ abi: ?Target.Abi = null,
42/// based on the `os_tag`.42/// based on the `os_tag`.
43dynamic_linker: DynamicLinker = DynamicLinker{},43dynamic_linker: DynamicLinker = DynamicLinker{},
4444
45/// `null` means default for the cpu/arch/os combo.
46ofmt: ?Target.ObjectFormat = null,
47
45pub const CpuModel = union(enum) {48pub const CpuModel = union(enum) {
46 /// Always native49 /// Always native
47 native,50 native,
...@@ -171,6 +174,7 @@ pub fn toTarget(self: CrossTarget) Target {...@@ -171,6 +174,7 @@ pub fn toTarget(self: CrossTarget) Target {
171 .cpu = self.getCpu(),174 .cpu = self.getCpu(),
172 .os = self.getOs(),175 .os = self.getOs(),
173 .abi = self.getAbi(),176 .abi = self.getAbi(),
177 .ofmt = self.getObjectFormat(),
174 };178 };
175}179}
176180
...@@ -200,6 +204,8 @@ pub const ParseOptions = struct {...@@ -200,6 +204,8 @@ pub const ParseOptions = struct {
200 /// detected path, or a standard path.204 /// detected path, or a standard path.
201 dynamic_linker: ?[]const u8 = null,205 dynamic_linker: ?[]const u8 = null,
202206
207 object_format: ?[]const u8 = null,
208
203 /// If this is provided, the function will populate some information about parsing failures,209 /// If this is provided, the function will populate some information about parsing failures,
204 /// so that user-friendly error messages can be delivered.210 /// so that user-friendly error messages can be delivered.
205 diagnostics: ?*Diagnostics = null,211 diagnostics: ?*Diagnostics = null,
...@@ -324,6 +330,11 @@ pub fn parse(args: ParseOptions) !CrossTarget {...@@ -324,6 +330,11 @@ pub fn parse(args: ParseOptions) !CrossTarget {
324 }330 }
325 }331 }
326332
333 if (args.object_format) |ofmt_name| {
334 result.ofmt = std.meta.stringToEnum(Target.ObjectFormat, ofmt_name) orelse
335 return error.UnknownObjectFormat;
336 }
337
327 return result;338 return result;
328}339}
329340
...@@ -623,7 +634,7 @@ pub fn setGnuLibCVersion(self: *CrossTarget, major: u32, minor: u32, patch: u32)...@@ -623,7 +634,7 @@ pub fn setGnuLibCVersion(self: *CrossTarget, major: u32, minor: u32, patch: u32)
623}634}
624635
625pub fn getObjectFormat(self: CrossTarget) Target.ObjectFormat {636pub fn getObjectFormat(self: CrossTarget) Target.ObjectFormat {
626 return Target.getObjectFormatSimple(self.getOsTag(), self.getCpuArch());637 return self.ofmt orelse Target.ObjectFormat.default(self.getOsTag(), self.getCpuArch());
627}638}
628639
629pub fn updateCpuFeatures(self: CrossTarget, set: *Target.Cpu.Feature.Set) void {640pub fn updateCpuFeatures(self: CrossTarget, set: *Target.Cpu.Feature.Set) void {
lib/std/zig/c_builtins.zig+6-6
...@@ -1,13 +1,13 @@...@@ -1,13 +1,13 @@
1const std = @import("std");1const std = @import("std");
22
3pub inline fn __builtin_bswap16(val: u16) u16 {3pub inline fn __builtin_bswap16(val: u16) u16 {
4 return @byteSwap(u16, val);4 return @byteSwap(val);
5}5}
6pub inline fn __builtin_bswap32(val: u32) u32 {6pub inline fn __builtin_bswap32(val: u32) u32 {
7 return @byteSwap(u32, val);7 return @byteSwap(val);
8}8}
9pub inline fn __builtin_bswap64(val: u64) u64 {9pub inline fn __builtin_bswap64(val: u64) u64 {
10 return @byteSwap(u64, val);10 return @byteSwap(val);
11}11}
1212
13pub inline fn __builtin_signbit(val: f64) c_int {13pub inline fn __builtin_signbit(val: f64) c_int {
...@@ -20,19 +20,19 @@ pub inline fn __builtin_signbitf(val: f32) c_int {...@@ -20,19 +20,19 @@ pub inline fn __builtin_signbitf(val: f32) c_int {
20pub inline fn __builtin_popcount(val: c_uint) c_int {20pub inline fn __builtin_popcount(val: c_uint) c_int {
21 // popcount of a c_uint will never exceed the capacity of a c_int21 // popcount of a c_uint will never exceed the capacity of a c_int
22 @setRuntimeSafety(false);22 @setRuntimeSafety(false);
23 return @bitCast(c_int, @as(c_uint, @popCount(c_uint, val)));23 return @bitCast(c_int, @as(c_uint, @popCount(val)));
24}24}
25pub inline fn __builtin_ctz(val: c_uint) c_int {25pub inline fn __builtin_ctz(val: c_uint) c_int {
26 // Returns the number of trailing 0-bits in val, starting at the least significant bit position.26 // Returns the number of trailing 0-bits in val, starting at the least significant bit position.
27 // In C if `val` is 0, the result is undefined; in zig it's the number of bits in a c_uint27 // In C if `val` is 0, the result is undefined; in zig it's the number of bits in a c_uint
28 @setRuntimeSafety(false);28 @setRuntimeSafety(false);
29 return @bitCast(c_int, @as(c_uint, @ctz(c_uint, val)));29 return @bitCast(c_int, @as(c_uint, @ctz(val)));
30}30}
31pub inline fn __builtin_clz(val: c_uint) c_int {31pub inline fn __builtin_clz(val: c_uint) c_int {
32 // Returns the number of leading 0-bits in x, starting at the most significant bit position.32 // Returns the number of leading 0-bits in x, starting at the most significant bit position.
33 // In C if `val` is 0, the result is undefined; in zig it's the number of bits in a c_uint33 // In C if `val` is 0, the result is undefined; in zig it's the number of bits in a c_uint
34 @setRuntimeSafety(false);34 @setRuntimeSafety(false);
35 return @bitCast(c_int, @as(c_uint, @clz(c_uint, val)));35 return @bitCast(c_int, @as(c_uint, @clz(val)));
36}36}
3737
38pub inline fn __builtin_sqrt(val: f64) f64 {38pub inline fn __builtin_sqrt(val: f64) f64 {
lib/std/zig/c_translation.zig+1-1
...@@ -349,7 +349,7 @@ test "shuffleVectorIndex" {...@@ -349,7 +349,7 @@ test "shuffleVectorIndex" {
349349
350/// Constructs a [*c] pointer with the const and volatile annotations350/// Constructs a [*c] pointer with the const and volatile annotations
351/// from SelfType for pointing to a C flexible array of ElementType.351/// from SelfType for pointing to a C flexible array of ElementType.
352pub fn FlexibleArrayType(comptime SelfType: type, ElementType: type) type {352pub fn FlexibleArrayType(comptime SelfType: type, comptime ElementType: type) type {
353 switch (@typeInfo(SelfType)) {353 switch (@typeInfo(SelfType)) {
354 .Pointer => |ptr| {354 .Pointer => |ptr| {
355 return @Type(.{ .Pointer = .{355 return @Type(.{ .Pointer = .{
lib/std/zig/parse.zig+7-5
...@@ -3356,16 +3356,18 @@ const Parser = struct {...@@ -3356,16 +3356,18 @@ const Parser = struct {
3356 }3356 }
33573357
3358 /// Caller must have already verified the first token.3358 /// Caller must have already verified the first token.
3359 /// ContainerDeclAuto <- ContainerDeclType LBRACE container_doc_comment? ContainerMembers RBRACE
3360 ///
3359 /// ContainerDeclType3361 /// ContainerDeclType
3360 /// <- KEYWORD_struct3362 /// <- KEYWORD_struct (LPAREN Expr RPAREN)?
3363 /// / KEYWORD_opaque
3361 /// / KEYWORD_enum (LPAREN Expr RPAREN)?3364 /// / KEYWORD_enum (LPAREN Expr RPAREN)?
3362 /// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?3365 /// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?
3363 /// / KEYWORD_opaque
3364 fn parseContainerDeclAuto(p: *Parser) !Node.Index {3366 fn parseContainerDeclAuto(p: *Parser) !Node.Index {
3365 const main_token = p.nextToken();3367 const main_token = p.nextToken();
3366 const arg_expr = switch (p.token_tags[main_token]) {3368 const arg_expr = switch (p.token_tags[main_token]) {
3367 .keyword_struct, .keyword_opaque => null_node,3369 .keyword_opaque => null_node,
3368 .keyword_enum => blk: {3370 .keyword_struct, .keyword_enum => blk: {
3369 if (p.eatToken(.l_paren)) |_| {3371 if (p.eatToken(.l_paren)) |_| {
3370 const expr = try p.expectExpr();3372 const expr = try p.expectExpr();
3371 _ = try p.expectToken(.r_paren);3373 _ = try p.expectToken(.r_paren);
...@@ -3668,7 +3670,7 @@ const Parser = struct {...@@ -3668,7 +3670,7 @@ const Parser = struct {
3668 }3670 }
36693671
3670 /// KEYWORD_if LPAREN Expr RPAREN PtrPayload? Body (KEYWORD_else Payload? Body)?3672 /// KEYWORD_if LPAREN Expr RPAREN PtrPayload? Body (KEYWORD_else Payload? Body)?
3671 fn parseIf(p: *Parser, bodyParseFn: fn (p: *Parser) Error!Node.Index) !Node.Index {3673 fn parseIf(p: *Parser, comptime bodyParseFn: fn (p: *Parser) Error!Node.Index) !Node.Index {
3672 const if_token = p.eatToken(.keyword_if) orelse return null_node;3674 const if_token = p.eatToken(.keyword_if) orelse return null_node;
3673 _ = try p.expectToken(.l_paren);3675 _ = try p.expectToken(.l_paren);
3674 const condition = try p.expectExpr();3676 const condition = try p.expectExpr();
lib/std/zig/parser_test.zig+15-8
...@@ -3064,6 +3064,13 @@ test "zig fmt: struct declaration" {...@@ -3064,6 +3064,13 @@ test "zig fmt: struct declaration" {
3064 \\ c: u8,3064 \\ c: u8,
3065 \\};3065 \\};
3066 \\3066 \\
3067 \\const Ps = packed struct(u32) {
3068 \\ a: u1,
3069 \\ b: u2,
3070 \\
3071 \\ c: u29,
3072 \\};
3073 \\
3067 \\const Es = extern struct {3074 \\const Es = extern struct {
3068 \\ a: u8,3075 \\ a: u8,
3069 \\ b: u8,3076 \\ b: u8,
...@@ -4247,10 +4254,10 @@ test "zig fmt: integer literals with underscore separators" {...@@ -4247,10 +4254,10 @@ test "zig fmt: integer literals with underscore separators" {
4247 \\const4254 \\const
4248 \\ x =4255 \\ x =
4249 \\ 1_234_5674256 \\ 1_234_567
4250 \\ + (0b0_1-0o7_0+0xff_FF ) + 0_0;4257 \\ + (0b0_1-0o7_0+0xff_FF ) + 1_0;
4251 ,4258 ,
4252 \\const x =4259 \\const x =
4253 \\ 1_234_567 + (0b0_1 - 0o7_0 + 0xff_FF) + 0_0;4260 \\ 1_234_567 + (0b0_1 - 0o7_0 + 0xff_FF) + 1_0;
4254 \\4261 \\
4255 );4262 );
4256}4263}
...@@ -4259,7 +4266,7 @@ test "zig fmt: hex literals with underscore separators" {...@@ -4259,7 +4266,7 @@ test "zig fmt: hex literals with underscore separators" {
4259 try testTransform(4266 try testTransform(
4260 \\pub fn orMask(a: [ 1_000 ]u64, b: [ 1_000] u64) [1_000]u64 {4267 \\pub fn orMask(a: [ 1_000 ]u64, b: [ 1_000] u64) [1_000]u64 {
4261 \\ var c: [1_000]u64 = [1]u64{ 0xFFFF_FFFF_FFFF_FFFF}**1_000;4268 \\ var c: [1_000]u64 = [1]u64{ 0xFFFF_FFFF_FFFF_FFFF}**1_000;
4262 \\ for (c [ 0_0 .. ]) |_, i| {4269 \\ for (c [ 1_0 .. ]) |_, i| {
4263 \\ c[i] = (a[i] | b[i]) & 0xCCAA_CCAA_CCAA_CCAA;4270 \\ c[i] = (a[i] | b[i]) & 0xCCAA_CCAA_CCAA_CCAA;
4264 \\ }4271 \\ }
4265 \\ return c;4272 \\ return c;
...@@ -4269,7 +4276,7 @@ test "zig fmt: hex literals with underscore separators" {...@@ -4269,7 +4276,7 @@ test "zig fmt: hex literals with underscore separators" {
4269 ,4276 ,
4270 \\pub fn orMask(a: [1_000]u64, b: [1_000]u64) [1_000]u64 {4277 \\pub fn orMask(a: [1_000]u64, b: [1_000]u64) [1_000]u64 {
4271 \\ var c: [1_000]u64 = [1]u64{0xFFFF_FFFF_FFFF_FFFF} ** 1_000;4278 \\ var c: [1_000]u64 = [1]u64{0xFFFF_FFFF_FFFF_FFFF} ** 1_000;
4272 \\ for (c[0_0..]) |_, i| {4279 \\ for (c[1_0..]) |_, i| {
4273 \\ c[i] = (a[i] | b[i]) & 0xCCAA_CCAA_CCAA_CCAA;4280 \\ c[i] = (a[i] | b[i]) & 0xCCAA_CCAA_CCAA_CCAA;
4274 \\ }4281 \\ }
4275 \\ return c;4282 \\ return c;
...@@ -4281,14 +4288,14 @@ test "zig fmt: hex literals with underscore separators" {...@@ -4281,14 +4288,14 @@ test "zig fmt: hex literals with underscore separators" {
4281test "zig fmt: decimal float literals with underscore separators" {4288test "zig fmt: decimal float literals with underscore separators" {
4282 try testTransform(4289 try testTransform(
4283 \\pub fn main() void {4290 \\pub fn main() void {
4284 \\ const a:f64=(10.0e-0+(10.0e+0))+10_00.00_00e-2+00_00.00_10e+4;4291 \\ const a:f64=(10.0e-0+(10.0e+0))+10_00.00_00e-2+20_00.00_10e+4;
4285 \\ const b:f64=010.0--0_10.0+0_1_0.0_0+1e2;4292 \\ const b:f64=1_0.0--10_10.0+1_0_0.0_0+1e2;
4286 \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b });4293 \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b });
4287 \\}4294 \\}
4288 ,4295 ,
4289 \\pub fn main() void {4296 \\pub fn main() void {
4290 \\ const a: f64 = (10.0e-0 + (10.0e+0)) + 10_00.00_00e-2 + 00_00.00_10e+4;4297 \\ const a: f64 = (10.0e-0 + (10.0e+0)) + 10_00.00_00e-2 + 20_00.00_10e+4;
4291 \\ const b: f64 = 010.0 - -0_10.0 + 0_1_0.0_0 + 1e2;4298 \\ const b: f64 = 1_0.0 - -10_10.0 + 1_0_0.0_0 + 1e2;
4292 \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b });4299 \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b });
4293 \\}4300 \\}
4294 \\4301 \\
lib/std/zig/system/NativePaths.zig+2
...@@ -109,6 +109,8 @@ pub fn detect(allocator: Allocator, native_info: NativeTargetInfo) !NativePaths...@@ -109,6 +109,8 @@ pub fn detect(allocator: Allocator, native_info: NativeTargetInfo) !NativePaths
109109
110 if (native_target.os.tag != .windows) {110 if (native_target.os.tag != .windows) {
111 const triple = try native_target.linuxTriple(allocator);111 const triple = try native_target.linuxTriple(allocator);
112 defer allocator.free(triple);
113
112 const qual = native_target.cpu.arch.ptrBitWidth();114 const qual = native_target.cpu.arch.ptrBitWidth();
113115
114 // TODO: $ ld --verbose | grep SEARCH_DIR116 // TODO: $ ld --verbose | grep SEARCH_DIR
lib/std/zig/system/NativeTargetInfo.zig+79-31
...@@ -237,7 +237,7 @@ pub fn detect(allocator: Allocator, cross_target: CrossTarget) DetectError!Nativ...@@ -237,7 +237,7 @@ pub fn detect(allocator: Allocator, cross_target: CrossTarget) DetectError!Nativ
237237
238/// First we attempt to use the executable's own binary. If it is dynamically238/// First we attempt to use the executable's own binary. If it is dynamically
239/// linked, then it should answer both the C ABI question and the dynamic linker question.239/// linked, then it should answer both the C ABI question and the dynamic linker question.
240/// If it is statically linked, then we try /usr/bin/env. If that does not provide the answer, then240/// If it is statically linked, then we try /usr/bin/env (or the file it references in shebang). If that does not provide the answer, then
241/// we fall back to the defaults.241/// we fall back to the defaults.
242/// TODO Remove the Allocator requirement from this function.242/// TODO Remove the Allocator requirement from this function.
243fn detectAbiAndDynamicLinker(243fn detectAbiAndDynamicLinker(
...@@ -276,6 +276,7 @@ fn detectAbiAndDynamicLinker(...@@ -276,6 +276,7 @@ fn detectAbiAndDynamicLinker(
276 };276 };
277 var ld_info_list_buffer: [all_abis.len]LdInfo = undefined;277 var ld_info_list_buffer: [all_abis.len]LdInfo = undefined;
278 var ld_info_list_len: usize = 0;278 var ld_info_list_len: usize = 0;
279 const ofmt = cross_target.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch);
279280
280 for (all_abis) |abi| {281 for (all_abis) |abi| {
281 // This may be a nonsensical parameter. We detect this with error.UnknownDynamicLinkerPath and282 // This may be a nonsensical parameter. We detect this with error.UnknownDynamicLinkerPath and
...@@ -284,6 +285,7 @@ fn detectAbiAndDynamicLinker(...@@ -284,6 +285,7 @@ fn detectAbiAndDynamicLinker(
284 .cpu = cpu,285 .cpu = cpu,
285 .os = os,286 .os = os,
286 .abi = abi,287 .abi = abi,
288 .ofmt = ofmt,
287 };289 };
288 const ld = target.standardDynamicLinkerPath();290 const ld = target.standardDynamicLinkerPath();
289 if (ld.get() == null) continue;291 if (ld.get() == null) continue;
...@@ -346,6 +348,7 @@ fn detectAbiAndDynamicLinker(...@@ -346,6 +348,7 @@ fn detectAbiAndDynamicLinker(
346 .cpu = cpu,348 .cpu = cpu,
347 .os = os_adjusted,349 .os = os_adjusted,
348 .abi = cross_target.abi orelse found_ld_info.abi,350 .abi = cross_target.abi orelse found_ld_info.abi,
351 .ofmt = cross_target.ofmt orelse Target.ObjectFormat.default(os_adjusted.tag, cpu.arch),
349 },352 },
350 .dynamic_linker = if (cross_target.dynamic_linker.get() == null)353 .dynamic_linker = if (cross_target.dynamic_linker.get() == null)
351 DynamicLinker.init(found_ld_path)354 DynamicLinker.init(found_ld_path)
...@@ -355,37 +358,77 @@ fn detectAbiAndDynamicLinker(...@@ -355,37 +358,77 @@ fn detectAbiAndDynamicLinker(
355 return result;358 return result;
356 }359 }
357360
358 const env_file = std.fs.openFileAbsoluteZ("/usr/bin/env", .{}) catch |err| switch (err) {361 const elf_file = blk: {
359 error.NoSpaceLeft => unreachable,362 // This block looks for a shebang line in /usr/bin/env,
360 error.NameTooLong => unreachable,363 // if it finds one, then instead of using /usr/bin/env as the ELF file to examine, it uses the file it references instead,
361 error.PathAlreadyExists => unreachable,364 // doing the same logic recursively in case it finds another shebang line.
362 error.SharingViolation => unreachable,365
363 error.InvalidUtf8 => unreachable,366 // Since /usr/bin/env is hard-coded into the shebang line of many portable scripts, it's a
364 error.BadPathName => unreachable,367 // reasonably reliable path to start with.
365 error.PipeBusy => unreachable,368 var file_name: []const u8 = "/usr/bin/env";
366 error.FileLocksNotSupported => unreachable,369 // #! (2) + 255 (max length of shebang line since Linux 5.1) + \n (1)
367 error.WouldBlock => unreachable,370 var buffer: [258]u8 = undefined;
368 error.FileBusy => unreachable, // opened without write permissions371 while (true) {
369372 const file = std.fs.openFileAbsolute(file_name, .{}) catch |err| switch (err) {
370 error.IsDir,373 error.NoSpaceLeft => unreachable,
371 error.NotDir,374 error.NameTooLong => unreachable,
372 error.InvalidHandle,375 error.PathAlreadyExists => unreachable,
373 error.AccessDenied,376 error.SharingViolation => unreachable,
374 error.NoDevice,377 error.InvalidUtf8 => unreachable,
375 error.FileNotFound,378 error.BadPathName => unreachable,
376 error.FileTooBig,379 error.PipeBusy => unreachable,
377 error.Unexpected,380 error.FileLocksNotSupported => unreachable,
378 => return defaultAbiAndDynamicLinker(cpu, os, cross_target),381 error.WouldBlock => unreachable,
382 error.FileBusy => unreachable, // opened without write permissions
383
384 error.IsDir,
385 error.NotDir,
386 error.InvalidHandle,
387 error.AccessDenied,
388 error.NoDevice,
389 error.FileNotFound,
390 error.FileTooBig,
391 error.Unexpected,
392 => |e| {
393 std.log.warn("Encoutered error: {s}, falling back to default ABI and dynamic linker.\n", .{@errorName(e)});
394 return defaultAbiAndDynamicLinker(cpu, os, cross_target);
395 },
379396
380 else => |e| return e,397 else => |e| return e,
398 };
399
400 const line = file.reader().readUntilDelimiter(&buffer, '\n') catch |err| switch (err) {
401 error.IsDir => unreachable, // Handled before
402 error.AccessDenied => unreachable,
403 error.WouldBlock => unreachable, // Did not request blocking mode
404 error.OperationAborted => unreachable, // Windows-only
405 error.BrokenPipe => unreachable,
406 error.ConnectionResetByPeer => unreachable,
407 error.ConnectionTimedOut => unreachable,
408 error.InputOutput => unreachable,
409 error.Unexpected => unreachable,
410
411 error.StreamTooLong,
412 error.EndOfStream,
413 error.NotOpenForReading,
414 => break :blk file,
415
416 else => |e| {
417 file.close();
418 return e;
419 },
420 };
421 if (!mem.startsWith(u8, line, "#!")) break :blk file;
422 var it = std.mem.tokenize(u8, line[2..], " ");
423 file.close();
424 file_name = it.next() orelse return defaultAbiAndDynamicLinker(cpu, os, cross_target);
425 }
381 };426 };
382 defer env_file.close();427 defer elf_file.close();
383428
384 // If Zig is statically linked, such as via distributed binary static builds, the above429 // If Zig is statically linked, such as via distributed binary static builds, the above
385 // trick won't work. The next thing we fall back to is the same thing, but for /usr/bin/env.430 // trick (block self_exe) won't work. The next thing we fall back to is the same thing, but for elf_file.
386 // Since that path is hard-coded into the shebang line of many portable scripts, it's a431 return abiAndDynamicLinkerFromFile(elf_file, cpu, os, ld_info_list, cross_target) catch |err| switch (err) {
387 // reasonably reliable path to check for.
388 return abiAndDynamicLinkerFromFile(env_file, cpu, os, ld_info_list, cross_target) catch |err| switch (err) {
389 error.FileSystem,432 error.FileSystem,
390 error.SystemResources,433 error.SystemResources,
391 error.SymLinkLoop,434 error.SymLinkLoop,
...@@ -403,7 +446,10 @@ fn detectAbiAndDynamicLinker(...@@ -403,7 +446,10 @@ fn detectAbiAndDynamicLinker(
403 error.UnexpectedEndOfFile,446 error.UnexpectedEndOfFile,
404 error.NameTooLong,447 error.NameTooLong,
405 // Finally, we fall back on the standard path.448 // Finally, we fall back on the standard path.
406 => defaultAbiAndDynamicLinker(cpu, os, cross_target),449 => |e| {
450 std.log.warn("Encoutered error: {s}, falling back to default ABI and dynamic linker.\n", .{@errorName(e)});
451 return defaultAbiAndDynamicLinker(cpu, os, cross_target);
452 },
407 };453 };
408}454}
409455
...@@ -496,6 +542,7 @@ pub fn abiAndDynamicLinkerFromFile(...@@ -496,6 +542,7 @@ pub fn abiAndDynamicLinkerFromFile(
496 .cpu = cpu,542 .cpu = cpu,
497 .os = os,543 .os = os,
498 .abi = cross_target.abi orelse Target.Abi.default(cpu.arch, os),544 .abi = cross_target.abi orelse Target.Abi.default(cpu.arch, os),
545 .ofmt = cross_target.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch),
499 },546 },
500 .dynamic_linker = cross_target.dynamic_linker,547 .dynamic_linker = cross_target.dynamic_linker,
501 };548 };
...@@ -786,6 +833,7 @@ fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os, cross_target: Cros...@@ -786,6 +833,7 @@ fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os, cross_target: Cros
786 .cpu = cpu,833 .cpu = cpu,
787 .os = os,834 .os = os,
788 .abi = cross_target.abi orelse Target.Abi.default(cpu.arch, os),835 .abi = cross_target.abi orelse Target.Abi.default(cpu.arch, os),
836 .ofmt = cross_target.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch),
789 };837 };
790 return NativeTargetInfo{838 return NativeTargetInfo{
791 .target = target,839 .target = target,
...@@ -804,13 +852,13 @@ pub const LdInfo = struct {...@@ -804,13 +852,13 @@ pub const LdInfo = struct {
804pub fn elfInt(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @TypeOf(int_64) {852pub fn elfInt(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @TypeOf(int_64) {
805 if (is_64) {853 if (is_64) {
806 if (need_bswap) {854 if (need_bswap) {
807 return @byteSwap(@TypeOf(int_64), int_64);855 return @byteSwap(int_64);
808 } else {856 } else {
809 return int_64;857 return int_64;
810 }858 }
811 } else {859 } else {
812 if (need_bswap) {860 if (need_bswap) {
813 return @byteSwap(@TypeOf(int_32), int_32);861 return @byteSwap(int_32);
814 } else {862 } else {
815 return int_32;863 return int_32;
816 }864 }
lib/std/zig/tokenizer.zig+55-41
...@@ -1,5 +1,4 @@...@@ -1,5 +1,4 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2const mem = std.mem;
32
4pub const Token = struct {3pub const Token = struct {
5 tag: Tag,4 tag: Tag,
...@@ -350,7 +349,7 @@ pub const Tokenizer = struct {...@@ -350,7 +349,7 @@ pub const Tokenizer = struct {
350349
351 pub fn init(buffer: [:0]const u8) Tokenizer {350 pub fn init(buffer: [:0]const u8) Tokenizer {
352 // Skip the UTF-8 BOM if present351 // Skip the UTF-8 BOM if present
353 const src_start = if (mem.startsWith(u8, buffer, "\xEF\xBB\xBF")) 3 else @as(usize, 0);352 const src_start: usize = if (std.mem.startsWith(u8, buffer, "\xEF\xBB\xBF")) 3 else 0;
354 return Tokenizer{353 return Tokenizer{
355 .buffer = buffer,354 .buffer = buffer,
356 .index = src_start,355 .index = src_start,
...@@ -797,6 +796,10 @@ pub const Tokenizer = struct {...@@ -797,6 +796,10 @@ pub const Tokenizer = struct {
797 remaining_code_units = 3;796 remaining_code_units = 3;
798 state = .char_literal_unicode;797 state = .char_literal_unicode;
799 },798 },
799 '\n' => {
800 result.tag = .invalid;
801 break;
802 },
800 else => {803 else => {
801 state = .char_literal_end;804 state = .char_literal_end;
802 },805 },
...@@ -1429,8 +1432,8 @@ pub const Tokenizer = struct {...@@ -1429,8 +1432,8 @@ pub const Tokenizer = struct {
14291432
1430 fn getInvalidCharacterLength(self: *Tokenizer) u3 {1433 fn getInvalidCharacterLength(self: *Tokenizer) u3 {
1431 const c0 = self.buffer[self.index];1434 const c0 = self.buffer[self.index];
1432 if (c0 < 0x80) {1435 if (std.ascii.isASCII(c0)) {
1433 if (c0 < 0x20 or c0 == 0x7f) {1436 if (std.ascii.isCntrl(c0)) {
1434 // ascii control codes are never allowed1437 // ascii control codes are never allowed
1435 // (note that \n was checked before we got here)1438 // (note that \n was checked before we got here)
1436 return 1;1439 return 1;
...@@ -1465,8 +1468,8 @@ pub const Tokenizer = struct {...@@ -1465,8 +1468,8 @@ pub const Tokenizer = struct {
1465 }1468 }
1466};1469};
14671470
1468test "tokenizer" {1471test "keywords" {
1469 try testTokenize("test", &.{.keyword_test});1472 try testTokenize("test const else", &.{ .keyword_test, .keyword_const, .keyword_else });
1470}1473}
14711474
1472test "line comment followed by top-level comptime" {1475test "line comment followed by top-level comptime" {
...@@ -1481,7 +1484,7 @@ test "line comment followed by top-level comptime" {...@@ -1481,7 +1484,7 @@ test "line comment followed by top-level comptime" {
1481 });1484 });
1482}1485}
14831486
1484test "tokenizer - unknown length pointer and then c pointer" {1487test "unknown length pointer and then c pointer" {
1485 try testTokenize(1488 try testTokenize(
1486 \\[*]u81489 \\[*]u8
1487 \\[*c]u81490 \\[*c]u8
...@@ -1498,7 +1501,7 @@ test "tokenizer - unknown length pointer and then c pointer" {...@@ -1498,7 +1501,7 @@ test "tokenizer - unknown length pointer and then c pointer" {
1498 });1501 });
1499}1502}
15001503
1501test "tokenizer - code point literal with hex escape" {1504test "code point literal with hex escape" {
1502 try testTokenize(1505 try testTokenize(
1503 \\'\x1b'1506 \\'\x1b'
1504 , &.{.char_literal});1507 , &.{.char_literal});
...@@ -1507,7 +1510,21 @@ test "tokenizer - code point literal with hex escape" {...@@ -1507,7 +1510,21 @@ test "tokenizer - code point literal with hex escape" {
1507 , &.{ .invalid, .invalid });1510 , &.{ .invalid, .invalid });
1508}1511}
15091512
1510test "tokenizer - code point literal with unicode escapes" {1513test "newline in char literal" {
1514 try testTokenize(
1515 \\'
1516 \\'
1517 , &.{ .invalid, .invalid });
1518}
1519
1520test "newline in string literal" {
1521 try testTokenize(
1522 \\"
1523 \\"
1524 , &.{ .invalid, .string_literal });
1525}
1526
1527test "code point literal with unicode escapes" {
1511 // Valid unicode escapes1528 // Valid unicode escapes
1512 try testTokenize(1529 try testTokenize(
1513 \\'\u{3}'1530 \\'\u{3}'
...@@ -1557,13 +1574,13 @@ test "tokenizer - code point literal with unicode escapes" {...@@ -1557,13 +1574,13 @@ test "tokenizer - code point literal with unicode escapes" {
1557 , &.{ .invalid, .integer_literal, .invalid });1574 , &.{ .invalid, .integer_literal, .invalid });
1558}1575}
15591576
1560test "tokenizer - code point literal with unicode code point" {1577test "code point literal with unicode code point" {
1561 try testTokenize(1578 try testTokenize(
1562 \\'💩'1579 \\'💩'
1563 , &.{.char_literal});1580 , &.{.char_literal});
1564}1581}
15651582
1566test "tokenizer - float literal e exponent" {1583test "float literal e exponent" {
1567 try testTokenize("a = 4.94065645841246544177e-324;\n", &.{1584 try testTokenize("a = 4.94065645841246544177e-324;\n", &.{
1568 .identifier,1585 .identifier,
1569 .equal,1586 .equal,
...@@ -1572,7 +1589,7 @@ test "tokenizer - float literal e exponent" {...@@ -1572,7 +1589,7 @@ test "tokenizer - float literal e exponent" {
1572 });1589 });
1573}1590}
15741591
1575test "tokenizer - float literal p exponent" {1592test "float literal p exponent" {
1576 try testTokenize("a = 0x1.a827999fcef32p+1022;\n", &.{1593 try testTokenize("a = 0x1.a827999fcef32p+1022;\n", &.{
1577 .identifier,1594 .identifier,
1578 .equal,1595 .equal,
...@@ -1581,11 +1598,11 @@ test "tokenizer - float literal p exponent" {...@@ -1581,11 +1598,11 @@ test "tokenizer - float literal p exponent" {
1581 });1598 });
1582}1599}
15831600
1584test "tokenizer - chars" {1601test "chars" {
1585 try testTokenize("'c'", &.{.char_literal});1602 try testTokenize("'c'", &.{.char_literal});
1586}1603}
15871604
1588test "tokenizer - invalid token characters" {1605test "invalid token characters" {
1589 try testTokenize("#", &.{.invalid});1606 try testTokenize("#", &.{.invalid});
1590 try testTokenize("`", &.{.invalid});1607 try testTokenize("`", &.{.invalid});
1591 try testTokenize("'c", &.{.invalid});1608 try testTokenize("'c", &.{.invalid});
...@@ -1593,7 +1610,7 @@ test "tokenizer - invalid token characters" {...@@ -1593,7 +1610,7 @@ test "tokenizer - invalid token characters" {
1593 try testTokenize("''", &.{ .invalid, .invalid });1610 try testTokenize("''", &.{ .invalid, .invalid });
1594}1611}
15951612
1596test "tokenizer - invalid literal/comment characters" {1613test "invalid literal/comment characters" {
1597 try testTokenize("\"\x00\"", &.{1614 try testTokenize("\"\x00\"", &.{
1598 .string_literal,1615 .string_literal,
1599 .invalid,1616 .invalid,
...@@ -1609,12 +1626,12 @@ test "tokenizer - invalid literal/comment characters" {...@@ -1609,12 +1626,12 @@ test "tokenizer - invalid literal/comment characters" {
1609 });1626 });
1610}1627}
16111628
1612test "tokenizer - utf8" {1629test "utf8" {
1613 try testTokenize("//\xc2\x80", &.{});1630 try testTokenize("//\xc2\x80", &.{});
1614 try testTokenize("//\xf4\x8f\xbf\xbf", &.{});1631 try testTokenize("//\xf4\x8f\xbf\xbf", &.{});
1615}1632}
16161633
1617test "tokenizer - invalid utf8" {1634test "invalid utf8" {
1618 try testTokenize("//\x80", &.{1635 try testTokenize("//\x80", &.{
1619 .invalid,1636 .invalid,
1620 });1637 });
...@@ -1641,7 +1658,7 @@ test "tokenizer - invalid utf8" {...@@ -1641,7 +1658,7 @@ test "tokenizer - invalid utf8" {
1641 });1658 });
1642}1659}
16431660
1644test "tokenizer - illegal unicode codepoints" {1661test "illegal unicode codepoints" {
1645 // unicode newline characters.U+0085, U+2028, U+20291662 // unicode newline characters.U+0085, U+2028, U+2029
1646 try testTokenize("//\xc2\x84", &.{});1663 try testTokenize("//\xc2\x84", &.{});
1647 try testTokenize("//\xc2\x85", &.{1664 try testTokenize("//\xc2\x85", &.{
...@@ -1658,7 +1675,7 @@ test "tokenizer - illegal unicode codepoints" {...@@ -1658,7 +1675,7 @@ test "tokenizer - illegal unicode codepoints" {
1658 try testTokenize("//\xe2\x80\xaa", &.{});1675 try testTokenize("//\xe2\x80\xaa", &.{});
1659}1676}
16601677
1661test "tokenizer - string identifier and builtin fns" {1678test "string identifier and builtin fns" {
1662 try testTokenize(1679 try testTokenize(
1663 \\const @"if" = @import("std");1680 \\const @"if" = @import("std");
1664 , &.{1681 , &.{
...@@ -1673,7 +1690,7 @@ test "tokenizer - string identifier and builtin fns" {...@@ -1673,7 +1690,7 @@ test "tokenizer - string identifier and builtin fns" {
1673 });1690 });
1674}1691}
16751692
1676test "tokenizer - multiline string literal with literal tab" {1693test "multiline string literal with literal tab" {
1677 try testTokenize(1694 try testTokenize(
1678 \\\\foo bar1695 \\\\foo bar
1679 , &.{1696 , &.{
...@@ -1681,7 +1698,7 @@ test "tokenizer - multiline string literal with literal tab" {...@@ -1681,7 +1698,7 @@ test "tokenizer - multiline string literal with literal tab" {
1681 });1698 });
1682}1699}
16831700
1684test "tokenizer - comments with literal tab" {1701test "comments with literal tab" {
1685 try testTokenize(1702 try testTokenize(
1686 \\//foo bar1703 \\//foo bar
1687 \\//!foo bar1704 \\//!foo bar
...@@ -1697,14 +1714,14 @@ test "tokenizer - comments with literal tab" {...@@ -1697,14 +1714,14 @@ test "tokenizer - comments with literal tab" {
1697 });1714 });
1698}1715}
16991716
1700test "tokenizer - pipe and then invalid" {1717test "pipe and then invalid" {
1701 try testTokenize("||=", &.{1718 try testTokenize("||=", &.{
1702 .pipe_pipe,1719 .pipe_pipe,
1703 .equal,1720 .equal,
1704 });1721 });
1705}1722}
17061723
1707test "tokenizer - line comment and doc comment" {1724test "line comment and doc comment" {
1708 try testTokenize("//", &.{});1725 try testTokenize("//", &.{});
1709 try testTokenize("// a / b", &.{});1726 try testTokenize("// a / b", &.{});
1710 try testTokenize("// /", &.{});1727 try testTokenize("// /", &.{});
...@@ -1715,7 +1732,7 @@ test "tokenizer - line comment and doc comment" {...@@ -1715,7 +1732,7 @@ test "tokenizer - line comment and doc comment" {
1715 try testTokenize("//!!", &.{.container_doc_comment});1732 try testTokenize("//!!", &.{.container_doc_comment});
1716}1733}
17171734
1718test "tokenizer - line comment followed by identifier" {1735test "line comment followed by identifier" {
1719 try testTokenize(1736 try testTokenize(
1720 \\ Unexpected,1737 \\ Unexpected,
1721 \\ // another1738 \\ // another
...@@ -1728,7 +1745,7 @@ test "tokenizer - line comment followed by identifier" {...@@ -1728,7 +1745,7 @@ test "tokenizer - line comment followed by identifier" {
1728 });1745 });
1729}1746}
17301747
1731test "tokenizer - UTF-8 BOM is recognized and skipped" {1748test "UTF-8 BOM is recognized and skipped" {
1732 try testTokenize("\xEF\xBB\xBFa;\n", &.{1749 try testTokenize("\xEF\xBB\xBFa;\n", &.{
1733 .identifier,1750 .identifier,
1734 .semicolon,1751 .semicolon,
...@@ -1770,7 +1787,7 @@ test "correctly parse pointer dereference followed by asterisk" {...@@ -1770,7 +1787,7 @@ test "correctly parse pointer dereference followed by asterisk" {
1770 });1787 });
1771}1788}
17721789
1773test "tokenizer - range literals" {1790test "range literals" {
1774 try testTokenize("0...9", &.{ .integer_literal, .ellipsis3, .integer_literal });1791 try testTokenize("0...9", &.{ .integer_literal, .ellipsis3, .integer_literal });
1775 try testTokenize("'0'...'9'", &.{ .char_literal, .ellipsis3, .char_literal });1792 try testTokenize("'0'...'9'", &.{ .char_literal, .ellipsis3, .char_literal });
1776 try testTokenize("0x00...0x09", &.{ .integer_literal, .ellipsis3, .integer_literal });1793 try testTokenize("0x00...0x09", &.{ .integer_literal, .ellipsis3, .integer_literal });
...@@ -1778,7 +1795,7 @@ test "tokenizer - range literals" {...@@ -1778,7 +1795,7 @@ test "tokenizer - range literals" {
1778 try testTokenize("0o00...0o11", &.{ .integer_literal, .ellipsis3, .integer_literal });1795 try testTokenize("0o00...0o11", &.{ .integer_literal, .ellipsis3, .integer_literal });
1779}1796}
17801797
1781test "tokenizer - number literals decimal" {1798test "number literals decimal" {
1782 try testTokenize("0", &.{.integer_literal});1799 try testTokenize("0", &.{.integer_literal});
1783 try testTokenize("1", &.{.integer_literal});1800 try testTokenize("1", &.{.integer_literal});
1784 try testTokenize("2", &.{.integer_literal});1801 try testTokenize("2", &.{.integer_literal});
...@@ -1845,7 +1862,7 @@ test "tokenizer - number literals decimal" {...@@ -1845,7 +1862,7 @@ test "tokenizer - number literals decimal" {
1845 try testTokenize("1.0e0_+", &.{ .invalid, .plus });1862 try testTokenize("1.0e0_+", &.{ .invalid, .plus });
1846}1863}
18471864
1848test "tokenizer - number literals binary" {1865test "number literals binary" {
1849 try testTokenize("0b0", &.{.integer_literal});1866 try testTokenize("0b0", &.{.integer_literal});
1850 try testTokenize("0b1", &.{.integer_literal});1867 try testTokenize("0b1", &.{.integer_literal});
1851 try testTokenize("0b2", &.{ .invalid, .integer_literal });1868 try testTokenize("0b2", &.{ .invalid, .integer_literal });
...@@ -1884,7 +1901,7 @@ test "tokenizer - number literals binary" {...@@ -1884,7 +1901,7 @@ test "tokenizer - number literals binary" {
1884 try testTokenize("0b1_,", &.{ .invalid, .comma });1901 try testTokenize("0b1_,", &.{ .invalid, .comma });
1885}1902}
18861903
1887test "tokenizer - number literals octal" {1904test "number literals octal" {
1888 try testTokenize("0o0", &.{.integer_literal});1905 try testTokenize("0o0", &.{.integer_literal});
1889 try testTokenize("0o1", &.{.integer_literal});1906 try testTokenize("0o1", &.{.integer_literal});
1890 try testTokenize("0o2", &.{.integer_literal});1907 try testTokenize("0o2", &.{.integer_literal});
...@@ -1923,7 +1940,7 @@ test "tokenizer - number literals octal" {...@@ -1923,7 +1940,7 @@ test "tokenizer - number literals octal" {
1923 try testTokenize("0o_,", &.{ .invalid, .identifier, .comma });1940 try testTokenize("0o_,", &.{ .invalid, .identifier, .comma });
1924}1941}
19251942
1926test "tokenizer - number literals hexadecimal" {1943test "number literals hexadecimal" {
1927 try testTokenize("0x0", &.{.integer_literal});1944 try testTokenize("0x0", &.{.integer_literal});
1928 try testTokenize("0x1", &.{.integer_literal});1945 try testTokenize("0x1", &.{.integer_literal});
1929 try testTokenize("0x2", &.{.integer_literal});1946 try testTokenize("0x2", &.{.integer_literal});
...@@ -2011,22 +2028,22 @@ test "tokenizer - number literals hexadecimal" {...@@ -2011,22 +2028,22 @@ test "tokenizer - number literals hexadecimal" {
2011 try testTokenize("0x0.0p0_", &.{ .invalid, .eof });2028 try testTokenize("0x0.0p0_", &.{ .invalid, .eof });
2012}2029}
20132030
2014test "tokenizer - multi line string literal with only 1 backslash" {2031test "multi line string literal with only 1 backslash" {
2015 try testTokenize("x \\\n;", &.{ .identifier, .invalid, .semicolon });2032 try testTokenize("x \\\n;", &.{ .identifier, .invalid, .semicolon });
2016}2033}
20172034
2018test "tokenizer - invalid builtin identifiers" {2035test "invalid builtin identifiers" {
2019 try testTokenize("@()", &.{ .invalid, .l_paren, .r_paren });2036 try testTokenize("@()", &.{ .invalid, .l_paren, .r_paren });
2020 try testTokenize("@0()", &.{ .invalid, .integer_literal, .l_paren, .r_paren });2037 try testTokenize("@0()", &.{ .invalid, .integer_literal, .l_paren, .r_paren });
2021}2038}
20222039
2023test "tokenizer - invalid token with unfinished escape right before eof" {2040test "invalid token with unfinished escape right before eof" {
2024 try testTokenize("\"\\", &.{.invalid});2041 try testTokenize("\"\\", &.{.invalid});
2025 try testTokenize("'\\", &.{.invalid});2042 try testTokenize("'\\", &.{.invalid});
2026 try testTokenize("'\\u", &.{.invalid});2043 try testTokenize("'\\u", &.{.invalid});
2027}2044}
20282045
2029test "tokenizer - saturating" {2046test "saturating operators" {
2030 try testTokenize("<<", &.{.angle_bracket_angle_bracket_left});2047 try testTokenize("<<", &.{.angle_bracket_angle_bracket_left});
2031 try testTokenize("<<|", &.{.angle_bracket_angle_bracket_left_pipe});2048 try testTokenize("<<|", &.{.angle_bracket_angle_bracket_left_pipe});
2032 try testTokenize("<<|=", &.{.angle_bracket_angle_bracket_left_pipe_equal});2049 try testTokenize("<<|=", &.{.angle_bracket_angle_bracket_left_pipe_equal});
...@@ -2044,17 +2061,14 @@ test "tokenizer - saturating" {...@@ -2044,17 +2061,14 @@ test "tokenizer - saturating" {
2044 try testTokenize("-|=", &.{.minus_pipe_equal});2061 try testTokenize("-|=", &.{.minus_pipe_equal});
2045}2062}
20462063
2047fn testTokenize(source: [:0]const u8, expected_tokens: []const Token.Tag) !void {2064fn testTokenize(source: [:0]const u8, expected_token_tags: []const Token.Tag) !void {
2048 var tokenizer = Tokenizer.init(source);2065 var tokenizer = Tokenizer.init(source);
2049 for (expected_tokens) |expected_token_id| {2066 for (expected_token_tags) |expected_token_tag| {
2050 const token = tokenizer.next();2067 const token = tokenizer.next();
2051 if (token.tag != expected_token_id) {2068 try std.testing.expectEqual(expected_token_tag, token.tag);
2052 std.debug.panic("expected {s}, found {s}\n", .{
2053 @tagName(expected_token_id), @tagName(token.tag),
2054 });
2055 }
2056 }2069 }
2057 const last_token = tokenizer.next();2070 const last_token = tokenizer.next();
2058 try std.testing.expectEqual(Token.Tag.eof, last_token.tag);2071 try std.testing.expectEqual(Token.Tag.eof, last_token.tag);
2059 try std.testing.expectEqual(source.len, last_token.loc.start);2072 try std.testing.expectEqual(source.len, last_token.loc.start);
2073 try std.testing.expectEqual(source.len, last_token.loc.end);
2060}2074}
src/Air.zig+10
...@@ -660,6 +660,10 @@ pub const Inst = struct {...@@ -660,6 +660,10 @@ pub const Inst = struct {
660 /// Uses the `pl_op` field with payload `AtomicRmw`. Operand is `ptr`.660 /// Uses the `pl_op` field with payload `AtomicRmw`. Operand is `ptr`.
661 atomic_rmw,661 atomic_rmw,
662662
663 /// Returns true if enum tag value has a name.
664 /// Uses the `un_op` field.
665 is_named_enum_value,
666
663 /// Given an enum tag value, returns the tag name. The enum type may be non-exhaustive.667 /// Given an enum tag value, returns the tag name. The enum type may be non-exhaustive.
664 /// Result type is always `[:0]const u8`.668 /// Result type is always `[:0]const u8`.
665 /// Uses the `un_op` field.669 /// Uses the `un_op` field.
...@@ -669,6 +673,10 @@ pub const Inst = struct {...@@ -669,6 +673,10 @@ pub const Inst = struct {
669 /// Uses the `un_op` field.673 /// Uses the `un_op` field.
670 error_name,674 error_name,
671675
676 /// Returns true if error set has error with value.
677 /// Uses the `ty_op` field.
678 error_set_has_value,
679
672 /// Constructs a vector, tuple, struct, or array value out of runtime-known elements.680 /// Constructs a vector, tuple, struct, or array value out of runtime-known elements.
673 /// Some of the elements may be comptime-known.681 /// Some of the elements may be comptime-known.
674 /// Uses the `ty_pl` field, payload is index of an array of elements, each of which682 /// Uses the `ty_pl` field, payload is index of an array of elements, each of which
...@@ -1057,6 +1065,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -1057,6 +1065,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
1057 .is_non_err,1065 .is_non_err,
1058 .is_err_ptr,1066 .is_err_ptr,
1059 .is_non_err_ptr,1067 .is_non_err_ptr,
1068 .is_named_enum_value,
1069 .error_set_has_value,
1060 => return Type.bool,1070 => return Type.bool,
10611071
1062 .const_ty => return Type.type,1072 .const_ty => return Type.type,
src/AstGen.zig+270-63
...@@ -152,6 +152,7 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {...@@ -152,6 +152,7 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {
152 0,152 0,
153 tree.containerDeclRoot(),153 tree.containerDeclRoot(),
154 .Auto,154 .Auto,
155 0,
155 )) |struct_decl_ref| {156 )) |struct_decl_ref| {
156 assert(refToIndex(struct_decl_ref).? == 0);157 assert(refToIndex(struct_decl_ref).? == 0);
157 } else |err| switch (err) {158 } else |err| switch (err) {
...@@ -859,7 +860,12 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr...@@ -859,7 +860,12 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
859 },860 },
860 .enum_literal => return simpleStrTok(gz, rl, main_tokens[node], node, .enum_literal),861 .enum_literal => return simpleStrTok(gz, rl, main_tokens[node], node, .enum_literal),
861 .error_value => return simpleStrTok(gz, rl, node_datas[node].rhs, node, .error_value),862 .error_value => return simpleStrTok(gz, rl, node_datas[node].rhs, node, .error_value),
862 .anyframe_literal => return rvalue(gz, rl, .anyframe_type, node),863 // TODO restore this when implementing https://github.com/ziglang/zig/issues/6025
864 // .anyframe_literal => return rvalue(gz, rl, .anyframe_type, node),
865 .anyframe_literal => {
866 const result = try gz.addUnNode(.anyframe_type, .void_type, node);
867 return rvalue(gz, rl, result, node);
868 },
863 .anyframe_type => {869 .anyframe_type => {
864 const return_type = try typeExpr(gz, scope, node_datas[node].rhs);870 const return_type = try typeExpr(gz, scope, node_datas[node].rhs);
865 const result = try gz.addUnNode(.anyframe_type, return_type, node);871 const result = try gz.addUnNode(.anyframe_type, return_type, node);
...@@ -1158,6 +1164,10 @@ fn fnProtoExpr(...@@ -1158,6 +1164,10 @@ fn fnProtoExpr(
1158 const tree = astgen.tree;1164 const tree = astgen.tree;
1159 const token_tags = tree.tokens.items(.tag);1165 const token_tags = tree.tokens.items(.tag);
11601166
1167 if (fn_proto.name_token) |some| {
1168 return astgen.failTok(some, "function type cannot have a name", .{});
1169 }
1170
1161 const is_extern = blk: {1171 const is_extern = blk: {
1162 const maybe_extern_token = fn_proto.extern_export_inline_token orelse break :blk false;1172 const maybe_extern_token = fn_proto.extern_export_inline_token orelse break :blk false;
1163 break :blk token_tags[maybe_extern_token] == .keyword_extern;1173 break :blk token_tags[maybe_extern_token] == .keyword_extern;
...@@ -2449,7 +2459,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As...@@ -2449,7 +2459,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2449 .trunc,2459 .trunc,
2450 .round,2460 .round,
2451 .tag_name,2461 .tag_name,
2452 .reify,
2453 .type_name,2462 .type_name,
2454 .frame_type,2463 .frame_type,
2455 .frame_size,2464 .frame_size,
...@@ -2496,7 +2505,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As...@@ -2496,7 +2505,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2496 .closure_get,2505 .closure_get,
2497 .array_base_ptr,2506 .array_base_ptr,
2498 .field_base_ptr,2507 .field_base_ptr,
2499 .param_type,
2500 .ret_ptr,2508 .ret_ptr,
2501 .ret_type,2509 .ret_type,
2502 .@"try",2510 .@"try",
...@@ -3066,6 +3074,19 @@ fn emitDbgNode(gz: *GenZir, node: Ast.Node.Index) !void {...@@ -3066,6 +3074,19 @@ fn emitDbgNode(gz: *GenZir, node: Ast.Node.Index) !void {
3066 const line = astgen.source_line - gz.decl_line;3074 const line = astgen.source_line - gz.decl_line;
3067 const column = astgen.source_column;3075 const column = astgen.source_column;
30683076
3077 if (gz.instructions.items.len > 0) {
3078 const last = gz.instructions.items[gz.instructions.items.len - 1];
3079 const zir_tags = astgen.instructions.items(.tag);
3080 if (zir_tags[last] == .dbg_stmt) {
3081 const zir_datas = astgen.instructions.items(.data);
3082 zir_datas[last].dbg_stmt = .{
3083 .line = line,
3084 .column = column,
3085 };
3086 return;
3087 }
3088 }
3089
3069 _ = try gz.add(.{ .tag = .dbg_stmt, .data = .{3090 _ = try gz.add(.{ .tag = .dbg_stmt, .data = .{
3070 .dbg_stmt = .{3091 .dbg_stmt = .{
3071 .line = line,3092 .line = line,
...@@ -4071,6 +4092,13 @@ fn testDecl(...@@ -4071,6 +4092,13 @@ fn testDecl(
4071 true => .signed,4092 true => .signed,
4072 false => .unsigned,4093 false => .unsigned,
4073 };4094 };
4095 if (ident_name_raw.len >= 3 and ident_name_raw[1] == '0') {
4096 return astgen.failTok(
4097 test_name_token,
4098 "primitive integer type '{s}' has leading zero",
4099 .{ident_name_raw},
4100 );
4101 }
4074 _ = parseBitCount(ident_name_raw[1..]) catch |err| switch (err) {4102 _ = parseBitCount(ident_name_raw[1..]) catch |err| switch (err) {
4075 error.Overflow => return astgen.failTok(4103 error.Overflow => return astgen.failTok(
4076 test_name_token,4104 test_name_token,
...@@ -4207,15 +4235,18 @@ fn structDeclInner(...@@ -4207,15 +4235,18 @@ fn structDeclInner(
4207 node: Ast.Node.Index,4235 node: Ast.Node.Index,
4208 container_decl: Ast.full.ContainerDecl,4236 container_decl: Ast.full.ContainerDecl,
4209 layout: std.builtin.Type.ContainerLayout,4237 layout: std.builtin.Type.ContainerLayout,
4238 backing_int_node: Ast.Node.Index,
4210) InnerError!Zir.Inst.Ref {4239) InnerError!Zir.Inst.Ref {
4211 const decl_inst = try gz.reserveInstructionIndex();4240 const decl_inst = try gz.reserveInstructionIndex();
42124241
4213 if (container_decl.ast.members.len == 0) {4242 if (container_decl.ast.members.len == 0 and backing_int_node == 0) {
4214 try gz.setStruct(decl_inst, .{4243 try gz.setStruct(decl_inst, .{
4215 .src_node = node,4244 .src_node = node,
4216 .layout = layout,4245 .layout = layout,
4217 .fields_len = 0,4246 .fields_len = 0,
4218 .decls_len = 0,4247 .decls_len = 0,
4248 .backing_int_ref = .none,
4249 .backing_int_body_len = 0,
4219 .known_non_opv = false,4250 .known_non_opv = false,
4220 .known_comptime_only = false,4251 .known_comptime_only = false,
4221 });4252 });
...@@ -4238,10 +4269,13 @@ fn structDeclInner(...@@ -4238,10 +4269,13 @@ fn structDeclInner(
4238 // are in scope, so that field types, alignments, and default value expressions4269 // are in scope, so that field types, alignments, and default value expressions
4239 // can refer to decls within the struct itself.4270 // can refer to decls within the struct itself.
4240 astgen.advanceSourceCursorToNode(node);4271 astgen.advanceSourceCursorToNode(node);
4272 // If `node == 0` then this is the root struct and all the declarations should
4273 // be relative to the beginning of the file.
4274 const decl_line = if (node == 0) 0 else astgen.source_line;
4241 var block_scope: GenZir = .{4275 var block_scope: GenZir = .{
4242 .parent = &namespace.base,4276 .parent = &namespace.base,
4243 .decl_node_index = node,4277 .decl_node_index = node,
4244 .decl_line = astgen.source_line,4278 .decl_line = decl_line,
4245 .astgen = astgen,4279 .astgen = astgen,
4246 .force_comptime = true,4280 .force_comptime = true,
4247 .in_defer = false,4281 .in_defer = false,
...@@ -4250,6 +4284,35 @@ fn structDeclInner(...@@ -4250,6 +4284,35 @@ fn structDeclInner(
4250 };4284 };
4251 defer block_scope.unstack();4285 defer block_scope.unstack();
42524286
4287 const scratch_top = astgen.scratch.items.len;
4288 defer astgen.scratch.items.len = scratch_top;
4289
4290 var backing_int_body_len: usize = 0;
4291 const backing_int_ref: Zir.Inst.Ref = blk: {
4292 if (backing_int_node != 0) {
4293 if (layout != .Packed) {
4294 return astgen.failNode(backing_int_node, "non-packed struct does not support backing integer type", .{});
4295 } else {
4296 const backing_int_ref = try typeExpr(&block_scope, &namespace.base, backing_int_node);
4297 if (!block_scope.isEmpty()) {
4298 if (!block_scope.endsWithNoReturn()) {
4299 _ = try block_scope.addBreak(.break_inline, decl_inst, backing_int_ref);
4300 }
4301
4302 const body = block_scope.instructionsSlice();
4303 const old_scratch_len = astgen.scratch.items.len;
4304 try astgen.scratch.ensureUnusedCapacity(gpa, countBodyLenAfterFixups(astgen, body));
4305 appendBodyWithFixupsArrayList(astgen, &astgen.scratch, body);
4306 backing_int_body_len = astgen.scratch.items.len - old_scratch_len;
4307 block_scope.instructions.items.len = block_scope.instructions_top;
4308 }
4309 break :blk backing_int_ref;
4310 }
4311 } else {
4312 break :blk .none;
4313 }
4314 };
4315
4253 const decl_count = try astgen.scanDecls(&namespace, container_decl.ast.members);4316 const decl_count = try astgen.scanDecls(&namespace, container_decl.ast.members);
4254 const field_count = @intCast(u32, container_decl.ast.members.len - decl_count);4317 const field_count = @intCast(u32, container_decl.ast.members.len - decl_count);
42554318
...@@ -4274,7 +4337,7 @@ fn structDeclInner(...@@ -4274,7 +4337,7 @@ fn structDeclInner(
4274 var known_non_opv = false;4337 var known_non_opv = false;
4275 var known_comptime_only = false;4338 var known_comptime_only = false;
4276 for (container_decl.ast.members) |member_node| {4339 for (container_decl.ast.members) |member_node| {
4277 const member = switch (try containerMember(gz, &namespace.base, &wip_members, member_node)) {4340 const member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) {
4278 .decl => continue,4341 .decl => continue,
4279 .field => |field| field,4342 .field => |field| field,
4280 };4343 };
...@@ -4362,6 +4425,8 @@ fn structDeclInner(...@@ -4362,6 +4425,8 @@ fn structDeclInner(
4362 .layout = layout,4425 .layout = layout,
4363 .fields_len = field_count,4426 .fields_len = field_count,
4364 .decls_len = decl_count,4427 .decls_len = decl_count,
4428 .backing_int_ref = backing_int_ref,
4429 .backing_int_body_len = @intCast(u32, backing_int_body_len),
4365 .known_non_opv = known_non_opv,4430 .known_non_opv = known_non_opv,
4366 .known_comptime_only = known_comptime_only,4431 .known_comptime_only = known_comptime_only,
4367 });4432 });
...@@ -4370,7 +4435,9 @@ fn structDeclInner(...@@ -4370,7 +4435,9 @@ fn structDeclInner(
4370 const decls_slice = wip_members.declsSlice();4435 const decls_slice = wip_members.declsSlice();
4371 const fields_slice = wip_members.fieldsSlice();4436 const fields_slice = wip_members.fieldsSlice();
4372 const bodies_slice = astgen.scratch.items[bodies_start..];4437 const bodies_slice = astgen.scratch.items[bodies_start..];
4373 try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len + fields_slice.len + bodies_slice.len);4438 try astgen.extra.ensureUnusedCapacity(gpa, backing_int_body_len +
4439 decls_slice.len + fields_slice.len + bodies_slice.len);
4440 astgen.extra.appendSliceAssumeCapacity(astgen.scratch.items[scratch_top..][0..backing_int_body_len]);
4374 astgen.extra.appendSliceAssumeCapacity(decls_slice);4441 astgen.extra.appendSliceAssumeCapacity(decls_slice);
4375 astgen.extra.appendSliceAssumeCapacity(fields_slice);4442 astgen.extra.appendSliceAssumeCapacity(fields_slice);
4376 astgen.extra.appendSliceAssumeCapacity(bodies_slice);4443 astgen.extra.appendSliceAssumeCapacity(bodies_slice);
...@@ -4441,7 +4508,7 @@ fn unionDeclInner(...@@ -4441,7 +4508,7 @@ fn unionDeclInner(
4441 defer wip_members.deinit();4508 defer wip_members.deinit();
44424509
4443 for (members) |member_node| {4510 for (members) |member_node| {
4444 const member = switch (try containerMember(gz, &namespace.base, &wip_members, member_node)) {4511 const member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) {
4445 .decl => continue,4512 .decl => continue,
4446 .field => |field| field,4513 .field => |field| field,
4447 };4514 };
...@@ -4504,9 +4571,6 @@ fn unionDeclInner(...@@ -4504,9 +4571,6 @@ fn unionDeclInner(
4504 wip_members.appendToField(@enumToInt(tag_value));4571 wip_members.appendToField(@enumToInt(tag_value));
4505 }4572 }
4506 }4573 }
4507 if (field_count == 0) {
4508 return astgen.failNode(node, "union declarations must have at least one tag", .{});
4509 }
45104574
4511 if (!block_scope.isEmpty()) {4575 if (!block_scope.isEmpty()) {
4512 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);4576 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
...@@ -4566,9 +4630,7 @@ fn containerDecl(...@@ -4566,9 +4630,7 @@ fn containerDecl(
4566 else => unreachable,4630 else => unreachable,
4567 } else std.builtin.Type.ContainerLayout.Auto;4631 } else std.builtin.Type.ContainerLayout.Auto;
45684632
4569 assert(container_decl.ast.arg == 0);4633 const result = try structDeclInner(gz, scope, node, container_decl, layout, container_decl.ast.arg);
4570
4571 const result = try structDeclInner(gz, scope, node, container_decl, layout);
4572 return rvalue(gz, rl, result, node);4634 return rvalue(gz, rl, result, node);
4573 },4635 },
4574 .keyword_union => {4636 .keyword_union => {
...@@ -4664,12 +4726,6 @@ fn containerDecl(...@@ -4664,12 +4726,6 @@ fn containerDecl(
4664 .nonexhaustive_node = nonexhaustive_node,4726 .nonexhaustive_node = nonexhaustive_node,
4665 };4727 };
4666 };4728 };
4667 if (counts.total_fields == 0 and counts.nonexhaustive_node == 0) {
4668 // One can construct an enum with no tags, and it functions the same as `noreturn`. But
4669 // this is only useful for generic code; when explicitly using `enum {}` syntax, there
4670 // must be at least one tag.
4671 try astgen.appendErrorNode(node, "enum declarations must have at least one tag", .{});
4672 }
4673 if (counts.nonexhaustive_node != 0 and container_decl.ast.arg == 0) {4729 if (counts.nonexhaustive_node != 0 and container_decl.ast.arg == 0) {
4674 try astgen.appendErrorNodeNotes(4730 try astgen.appendErrorNodeNotes(
4675 node,4731 node,
...@@ -4728,7 +4784,7 @@ fn containerDecl(...@@ -4728,7 +4784,7 @@ fn containerDecl(
4728 for (container_decl.ast.members) |member_node| {4784 for (container_decl.ast.members) |member_node| {
4729 if (member_node == counts.nonexhaustive_node)4785 if (member_node == counts.nonexhaustive_node)
4730 continue;4786 continue;
4731 const member = switch (try containerMember(gz, &namespace.base, &wip_members, member_node)) {4787 const member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) {
4732 .decl => continue,4788 .decl => continue,
4733 .field => |field| field,4789 .field => |field| field,
4734 };4790 };
...@@ -4806,13 +4862,26 @@ fn containerDecl(...@@ -4806,13 +4862,26 @@ fn containerDecl(
4806 };4862 };
4807 defer namespace.deinit(gpa);4863 defer namespace.deinit(gpa);
48084864
4865 astgen.advanceSourceCursorToNode(node);
4866 var block_scope: GenZir = .{
4867 .parent = &namespace.base,
4868 .decl_node_index = node,
4869 .decl_line = astgen.source_line,
4870 .astgen = astgen,
4871 .force_comptime = true,
4872 .in_defer = false,
4873 .instructions = gz.instructions,
4874 .instructions_top = gz.instructions.items.len,
4875 };
4876 defer block_scope.unstack();
4877
4809 const decl_count = try astgen.scanDecls(&namespace, container_decl.ast.members);4878 const decl_count = try astgen.scanDecls(&namespace, container_decl.ast.members);
48104879
4811 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, 0, 0, 0);4880 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, 0, 0, 0);
4812 defer wip_members.deinit();4881 defer wip_members.deinit();
48134882
4814 for (container_decl.ast.members) |member_node| {4883 for (container_decl.ast.members) |member_node| {
4815 const res = try containerMember(gz, &namespace.base, &wip_members, member_node);4884 const res = try containerMember(&block_scope, &namespace.base, &wip_members, member_node);
4816 if (res == .field) {4885 if (res == .field) {
4817 return astgen.failNode(member_node, "opaque types cannot have fields", .{});4886 return astgen.failNode(member_node, "opaque types cannot have fields", .{});
4818 }4887 }
...@@ -5033,6 +5102,16 @@ fn tryExpr(...@@ -5033,6 +5102,16 @@ fn tryExpr(
50335102
5034 if (parent_gz.in_defer) return astgen.failNode(node, "'try' not allowed inside defer expression", .{});5103 if (parent_gz.in_defer) return astgen.failNode(node, "'try' not allowed inside defer expression", .{});
50355104
5105 // Ensure debug line/column information is emitted for this try expression.
5106 // Then we will save the line/column so that we can emit another one that goes
5107 // "backwards" because we want to evaluate the operand, but then put the debug
5108 // info back at the try keyword for error return tracing.
5109 if (!parent_gz.force_comptime) {
5110 try emitDbgNode(parent_gz, node);
5111 }
5112 const try_line = astgen.source_line - parent_gz.decl_line;
5113 const try_column = astgen.source_column;
5114
5036 const operand_rl: ResultLoc = switch (rl) {5115 const operand_rl: ResultLoc = switch (rl) {
5037 .ref => .ref,5116 .ref => .ref,
5038 else => .none,5117 else => .none,
...@@ -5062,6 +5141,7 @@ fn tryExpr(...@@ -5062,6 +5141,7 @@ fn tryExpr(
5062 };5141 };
5063 const err_code = try else_scope.addUnNode(err_tag, operand, node);5142 const err_code = try else_scope.addUnNode(err_tag, operand, node);
5064 try genDefers(&else_scope, &fn_block.base, scope, .{ .both = err_code });5143 try genDefers(&else_scope, &fn_block.base, scope, .{ .both = err_code });
5144 try emitDbgStmt(&else_scope, try_line, try_column);
5065 _ = try else_scope.addUnNode(.ret_node, err_code, node);5145 _ = try else_scope.addUnNode(.ret_node, err_code, node);
50665146
5067 try else_scope.setTryBody(try_inst, operand);5147 try else_scope.setTryBody(try_inst, operand);
...@@ -6568,6 +6648,16 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref...@@ -6568,6 +6648,16 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
65686648
6569 if (gz.in_defer) return astgen.failNode(node, "cannot return from defer expression", .{});6649 if (gz.in_defer) return astgen.failNode(node, "cannot return from defer expression", .{});
65706650
6651 // Ensure debug line/column information is emitted for this return expression.
6652 // Then we will save the line/column so that we can emit another one that goes
6653 // "backwards" because we want to evaluate the operand, but then put the debug
6654 // info back at the return keyword for error return tracing.
6655 if (!gz.force_comptime) {
6656 try emitDbgNode(gz, node);
6657 }
6658 const ret_line = astgen.source_line - gz.decl_line;
6659 const ret_column = astgen.source_column;
6660
6571 const defer_outer = &astgen.fn_block.?.base;6661 const defer_outer = &astgen.fn_block.?.base;
65726662
6573 const operand_node = node_datas[node].lhs;6663 const operand_node = node_datas[node].lhs;
...@@ -6586,11 +6676,13 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref...@@ -6586,11 +6676,13 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
6586 const defer_counts = countDefers(astgen, defer_outer, scope);6676 const defer_counts = countDefers(astgen, defer_outer, scope);
6587 if (!defer_counts.need_err_code) {6677 if (!defer_counts.need_err_code) {
6588 try genDefers(gz, defer_outer, scope, .both_sans_err);6678 try genDefers(gz, defer_outer, scope, .both_sans_err);
6679 try emitDbgStmt(gz, ret_line, ret_column);
6589 _ = try gz.addStrTok(.ret_err_value, err_name_str_index, ident_token);6680 _ = try gz.addStrTok(.ret_err_value, err_name_str_index, ident_token);
6590 return Zir.Inst.Ref.unreachable_value;6681 return Zir.Inst.Ref.unreachable_value;
6591 }6682 }
6592 const err_code = try gz.addStrTok(.ret_err_value_code, err_name_str_index, ident_token);6683 const err_code = try gz.addStrTok(.ret_err_value_code, err_name_str_index, ident_token);
6593 try genDefers(gz, defer_outer, scope, .{ .both = err_code });6684 try genDefers(gz, defer_outer, scope, .{ .both = err_code });
6685 try emitDbgStmt(gz, ret_line, ret_column);
6594 _ = try gz.addUnNode(.ret_node, err_code, node);6686 _ = try gz.addUnNode(.ret_node, err_code, node);
6595 return Zir.Inst.Ref.unreachable_value;6687 return Zir.Inst.Ref.unreachable_value;
6596 }6688 }
...@@ -6609,6 +6701,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref...@@ -6609,6 +6701,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
6609 .never => {6701 .never => {
6610 // Returning a value that cannot be an error; skip error defers.6702 // Returning a value that cannot be an error; skip error defers.
6611 try genDefers(gz, defer_outer, scope, .normal_only);6703 try genDefers(gz, defer_outer, scope, .normal_only);
6704 try emitDbgStmt(gz, ret_line, ret_column);
6612 try gz.addRet(rl, operand, node);6705 try gz.addRet(rl, operand, node);
6613 return Zir.Inst.Ref.unreachable_value;6706 return Zir.Inst.Ref.unreachable_value;
6614 },6707 },
...@@ -6616,6 +6709,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref...@@ -6616,6 +6709,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
6616 // Value is always an error. Emit both error defers and regular defers.6709 // Value is always an error. Emit both error defers and regular defers.
6617 const err_code = if (rl == .ptr) try gz.addUnNode(.load, rl.ptr, node) else operand;6710 const err_code = if (rl == .ptr) try gz.addUnNode(.load, rl.ptr, node) else operand;
6618 try genDefers(gz, defer_outer, scope, .{ .both = err_code });6711 try genDefers(gz, defer_outer, scope, .{ .both = err_code });
6712 try emitDbgStmt(gz, ret_line, ret_column);
6619 try gz.addRet(rl, operand, node);6713 try gz.addRet(rl, operand, node);
6620 return Zir.Inst.Ref.unreachable_value;6714 return Zir.Inst.Ref.unreachable_value;
6621 },6715 },
...@@ -6624,6 +6718,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref...@@ -6624,6 +6718,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
6624 if (!defer_counts.have_err) {6718 if (!defer_counts.have_err) {
6625 // Only regular defers; no branch needed.6719 // Only regular defers; no branch needed.
6626 try genDefers(gz, defer_outer, scope, .normal_only);6720 try genDefers(gz, defer_outer, scope, .normal_only);
6721 try emitDbgStmt(gz, ret_line, ret_column);
6627 try gz.addRet(rl, operand, node);6722 try gz.addRet(rl, operand, node);
6628 return Zir.Inst.Ref.unreachable_value;6723 return Zir.Inst.Ref.unreachable_value;
6629 }6724 }
...@@ -6637,6 +6732,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref...@@ -6637,6 +6732,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
6637 defer then_scope.unstack();6732 defer then_scope.unstack();
66386733
6639 try genDefers(&then_scope, defer_outer, scope, .normal_only);6734 try genDefers(&then_scope, defer_outer, scope, .normal_only);
6735 try emitDbgStmt(&then_scope, ret_line, ret_column);
6640 try then_scope.addRet(rl, operand, node);6736 try then_scope.addRet(rl, operand, node);
66416737
6642 var else_scope = gz.makeSubBlock(scope);6738 var else_scope = gz.makeSubBlock(scope);
...@@ -6646,6 +6742,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref...@@ -6646,6 +6742,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
6646 .both = try else_scope.addUnNode(.err_union_code, result, node),6742 .both = try else_scope.addUnNode(.err_union_code, result, node),
6647 };6743 };
6648 try genDefers(&else_scope, defer_outer, scope, which_ones);6744 try genDefers(&else_scope, defer_outer, scope, which_ones);
6745 try emitDbgStmt(&else_scope, ret_line, ret_column);
6649 try else_scope.addRet(rl, operand, node);6746 try else_scope.addRet(rl, operand, node);
66506747
6651 try setCondBrPayload(condbr, is_non_err, &then_scope, 0, &else_scope, 0);6748 try setCondBrPayload(condbr, is_non_err, &then_scope, 0, &else_scope, 0);
...@@ -6708,6 +6805,13 @@ fn identifier(...@@ -6708,6 +6805,13 @@ fn identifier(
6708 true => .signed,6805 true => .signed,
6709 false => .unsigned,6806 false => .unsigned,
6710 };6807 };
6808 if (ident_name_raw.len >= 3 and ident_name_raw[1] == '0') {
6809 return astgen.failNode(
6810 ident,
6811 "primitive integer type '{s}' has leading zero",
6812 .{ident_name_raw},
6813 );
6814 }
6711 const bit_count = parseBitCount(ident_name_raw[1..]) catch |err| switch (err) {6815 const bit_count = parseBitCount(ident_name_raw[1..]) catch |err| switch (err) {
6712 error.Overflow => return astgen.failNode(6816 error.Overflow => return astgen.failNode(
6713 ident,6817 ident,
...@@ -6938,17 +7042,6 @@ fn integerLiteral(gz: *GenZir, rl: ResultLoc, node: Ast.Node.Index) InnerError!Z...@@ -6938,17 +7042,6 @@ fn integerLiteral(gz: *GenZir, rl: ResultLoc, node: Ast.Node.Index) InnerError!Z
6938 const main_tokens = tree.nodes.items(.main_token);7042 const main_tokens = tree.nodes.items(.main_token);
6939 const int_token = main_tokens[node];7043 const int_token = main_tokens[node];
6940 const prefixed_bytes = tree.tokenSlice(int_token);7044 const prefixed_bytes = tree.tokenSlice(int_token);
6941 if (std.fmt.parseInt(u64, prefixed_bytes, 0)) |small_int| {
6942 const result: Zir.Inst.Ref = switch (small_int) {
6943 0 => .zero,
6944 1 => .one,
6945 else => try gz.addInt(small_int),
6946 };
6947 return rvalue(gz, rl, result, node);
6948 } else |err| switch (err) {
6949 error.InvalidCharacter => unreachable, // Caught by the parser.
6950 error.Overflow => {},
6951 }
69527045
6953 var base: u8 = 10;7046 var base: u8 = 10;
6954 var non_prefixed: []const u8 = prefixed_bytes;7047 var non_prefixed: []const u8 = prefixed_bytes;
...@@ -6963,6 +7056,24 @@ fn integerLiteral(gz: *GenZir, rl: ResultLoc, node: Ast.Node.Index) InnerError!Z...@@ -6963,6 +7056,24 @@ fn integerLiteral(gz: *GenZir, rl: ResultLoc, node: Ast.Node.Index) InnerError!Z
6963 non_prefixed = prefixed_bytes[2..];7056 non_prefixed = prefixed_bytes[2..];
6964 }7057 }
69657058
7059 if (base == 10 and prefixed_bytes.len >= 2 and prefixed_bytes[0] == '0') {
7060 return astgen.failNodeNotes(node, "integer literal '{s}' has leading zero", .{prefixed_bytes}, &.{
7061 try astgen.errNoteNode(node, "use '0o' prefix for octal literals", .{}),
7062 });
7063 }
7064
7065 if (std.fmt.parseUnsigned(u64, non_prefixed, base)) |small_int| {
7066 const result: Zir.Inst.Ref = switch (small_int) {
7067 0 => .zero,
7068 1 => .one,
7069 else => try gz.addInt(small_int),
7070 };
7071 return rvalue(gz, rl, result, node);
7072 } else |err| switch (err) {
7073 error.InvalidCharacter => unreachable, // Caught by the parser.
7074 error.Overflow => {},
7075 }
7076
6966 const gpa = astgen.gpa;7077 const gpa = astgen.gpa;
6967 var big_int = try std.math.big.int.Managed.init(gpa);7078 var big_int = try std.math.big.int.Managed.init(gpa);
6968 defer big_int.deinit();7079 defer big_int.deinit();
...@@ -7548,7 +7659,6 @@ fn builtinCall(...@@ -7548,7 +7659,6 @@ fn builtinCall(
7548 .trunc => return simpleUnOp(gz, scope, rl, node, .none, params[0], .trunc),7659 .trunc => return simpleUnOp(gz, scope, rl, node, .none, params[0], .trunc),
7549 .round => return simpleUnOp(gz, scope, rl, node, .none, params[0], .round),7660 .round => return simpleUnOp(gz, scope, rl, node, .none, params[0], .round),
7550 .tag_name => return simpleUnOp(gz, scope, rl, node, .none, params[0], .tag_name),7661 .tag_name => return simpleUnOp(gz, scope, rl, node, .none, params[0], .tag_name),
7551 .Type => return simpleUnOp(gz, scope, rl, node, .{ .coerced_ty = .type_info_type }, params[0], .reify),
7552 .type_name => return simpleUnOp(gz, scope, rl, node, .none, params[0], .type_name),7662 .type_name => return simpleUnOp(gz, scope, rl, node, .none, params[0], .type_name),
7553 .Frame => return simpleUnOp(gz, scope, rl, node, .none, params[0], .frame_type),7663 .Frame => return simpleUnOp(gz, scope, rl, node, .none, params[0], .frame_type),
7554 .frame_size => return simpleUnOp(gz, scope, rl, node, .none, params[0], .frame_size),7664 .frame_size => return simpleUnOp(gz, scope, rl, node, .none, params[0], .frame_size),
...@@ -7563,6 +7673,31 @@ fn builtinCall(...@@ -7563,6 +7673,31 @@ fn builtinCall(
7563 .truncate => return typeCast(gz, scope, rl, node, params[0], params[1], .truncate),7673 .truncate => return typeCast(gz, scope, rl, node, params[0], params[1], .truncate),
7564 // zig fmt: on7674 // zig fmt: on
75657675
7676 .Type => {
7677 const operand = try expr(gz, scope, .{ .coerced_ty = .type_info_type }, params[0]);
7678
7679 const gpa = gz.astgen.gpa;
7680
7681 try gz.instructions.ensureUnusedCapacity(gpa, 1);
7682 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
7683
7684 const payload_index = try gz.astgen.addExtra(Zir.Inst.UnNode{
7685 .node = gz.nodeIndexToRelative(node),
7686 .operand = operand,
7687 });
7688 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
7689 gz.astgen.instructions.appendAssumeCapacity(.{
7690 .tag = .extended,
7691 .data = .{ .extended = .{
7692 .opcode = .reify,
7693 .small = @enumToInt(gz.anon_name_strategy),
7694 .operand = payload_index,
7695 } },
7696 });
7697 gz.instructions.appendAssumeCapacity(new_index);
7698 const result = indexToRef(new_index);
7699 return rvalue(gz, rl, result, node);
7700 },
7566 .panic => {7701 .panic => {
7567 try emitDbgNode(gz, node);7702 try emitDbgNode(gz, node);
7568 return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], if (gz.force_comptime) .panic_comptime else .panic);7703 return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], if (gz.force_comptime) .panic_comptime else .panic);
...@@ -7605,11 +7740,11 @@ fn builtinCall(...@@ -7605,11 +7740,11 @@ fn builtinCall(
7605 .has_decl => return hasDeclOrField(gz, scope, rl, node, params[0], params[1], .has_decl),7740 .has_decl => return hasDeclOrField(gz, scope, rl, node, params[0], params[1], .has_decl),
7606 .has_field => return hasDeclOrField(gz, scope, rl, node, params[0], params[1], .has_field),7741 .has_field => return hasDeclOrField(gz, scope, rl, node, params[0], params[1], .has_field),
76077742
7608 .clz => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .clz),7743 .clz => return bitBuiltin(gz, scope, rl, node, params[0], .clz),
7609 .ctz => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .ctz),7744 .ctz => return bitBuiltin(gz, scope, rl, node, params[0], .ctz),
7610 .pop_count => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .pop_count),7745 .pop_count => return bitBuiltin(gz, scope, rl, node, params[0], .pop_count),
7611 .byte_swap => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .byte_swap),7746 .byte_swap => return bitBuiltin(gz, scope, rl, node, params[0], .byte_swap),
7612 .bit_reverse => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .bit_reverse),7747 .bit_reverse => return bitBuiltin(gz, scope, rl, node, params[0], .bit_reverse),
76137748
7614 .div_exact => return divBuiltin(gz, scope, rl, node, params[0], params[1], .div_exact),7749 .div_exact => return divBuiltin(gz, scope, rl, node, params[0], params[1], .div_exact),
7615 .div_floor => return divBuiltin(gz, scope, rl, node, params[0], params[1], .div_floor),7750 .div_floor => return divBuiltin(gz, scope, rl, node, params[0], params[1], .div_floor),
...@@ -7972,17 +8107,9 @@ fn bitBuiltin(...@@ -7972,17 +8107,9 @@ fn bitBuiltin(
7972 scope: *Scope,8107 scope: *Scope,
7973 rl: ResultLoc,8108 rl: ResultLoc,
7974 node: Ast.Node.Index,8109 node: Ast.Node.Index,
7975 int_type_node: Ast.Node.Index,
7976 operand_node: Ast.Node.Index,8110 operand_node: Ast.Node.Index,
7977 tag: Zir.Inst.Tag,8111 tag: Zir.Inst.Tag,
7978) InnerError!Zir.Inst.Ref {8112) InnerError!Zir.Inst.Ref {
7979 // The accepted proposal https://github.com/ziglang/zig/issues/6835
7980 // tells us to remove the type parameter from these builtins. To stay
7981 // source-compatible with stage1, we still observe the parameter here,
7982 // but we do not encode it into the ZIR. To implement this proposal in
7983 // stage2, only AstGen code will need to be changed.
7984 _ = try typeExpr(gz, scope, int_type_node);
7985
7986 const operand = try expr(gz, scope, .none, operand_node);8113 const operand = try expr(gz, scope, .none, operand_node);
7987 const result = try gz.addUnNode(tag, operand, node);8114 const result = try gz.addUnNode(tag, operand, node);
7988 return rvalue(gz, rl, result, node);8115 return rvalue(gz, rl, result, node);
...@@ -8147,6 +8274,33 @@ fn callExpr(...@@ -8147,6 +8274,33 @@ fn callExpr(
8147 assert(callee != .none);8274 assert(callee != .none);
8148 assert(node != 0);8275 assert(node != 0);
81498276
8277 const call_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
8278 const call_inst = Zir.indexToRef(call_index);
8279 try gz.astgen.instructions.append(astgen.gpa, undefined);
8280 try gz.instructions.append(astgen.gpa, call_index);
8281
8282 const scratch_top = astgen.scratch.items.len;
8283 defer astgen.scratch.items.len = scratch_top;
8284
8285 var scratch_index = scratch_top;
8286 try astgen.scratch.resize(astgen.gpa, scratch_top + call.ast.params.len);
8287
8288 for (call.ast.params) |param_node| {
8289 var arg_block = gz.makeSubBlock(scope);
8290 defer arg_block.unstack();
8291
8292 // `call_inst` is reused to provide the param type.
8293 const arg_ref = try expr(&arg_block, &arg_block.base, .{ .coerced_ty = call_inst }, param_node);
8294 _ = try arg_block.addBreak(.break_inline, call_index, arg_ref);
8295
8296 const body = arg_block.instructionsSlice();
8297 try astgen.scratch.ensureUnusedCapacity(astgen.gpa, countBodyLenAfterFixups(astgen, body));
8298 appendBodyWithFixupsArrayList(astgen, &astgen.scratch, body);
8299
8300 astgen.scratch.items[scratch_index] = @intCast(u32, astgen.scratch.items.len - scratch_top);
8301 scratch_index += 1;
8302 }
8303
8150 const payload_index = try addExtra(astgen, Zir.Inst.Call{8304 const payload_index = try addExtra(astgen, Zir.Inst.Call{
8151 .callee = callee,8305 .callee = callee,
8152 .flags = .{8306 .flags = .{
...@@ -8154,22 +8308,16 @@ fn callExpr(...@@ -8154,22 +8308,16 @@ fn callExpr(
8154 .args_len = @intCast(Zir.Inst.Call.Flags.PackedArgsLen, call.ast.params.len),8308 .args_len = @intCast(Zir.Inst.Call.Flags.PackedArgsLen, call.ast.params.len),
8155 },8309 },
8156 });8310 });
8157 var extra_index = try reserveExtra(astgen, call.ast.params.len);8311 if (call.ast.params.len != 0) {
81588312 try astgen.extra.appendSlice(astgen.gpa, astgen.scratch.items[scratch_top..]);
8159 for (call.ast.params) |param_node, i| {
8160 const param_type = try gz.add(.{
8161 .tag = .param_type,
8162 .data = .{ .param_type = .{
8163 .callee = callee,
8164 .param_index = @intCast(u32, i),
8165 } },
8166 });
8167 const arg_ref = try expr(gz, scope, .{ .coerced_ty = param_type }, param_node);
8168 astgen.extra.items[extra_index] = @enumToInt(arg_ref);
8169 extra_index += 1;
8170 }8313 }
81718314 gz.astgen.instructions.set(call_index, .{
8172 const call_inst = try gz.addPlNodePayloadIndex(.call, node, payload_index);8315 .tag = .call,
8316 .data = .{ .pl_node = .{
8317 .src_node = gz.nodeIndexToRelative(node),
8318 .payload_index = payload_index,
8319 } },
8320 });
8173 return rvalue(gz, rl, call_inst, node); // TODO function call with result location8321 return rvalue(gz, rl, call_inst, node); // TODO function call with result location
8174}8322}
81758323
...@@ -11153,6 +11301,8 @@ const GenZir = struct {...@@ -11153,6 +11301,8 @@ const GenZir = struct {
11153 src_node: Ast.Node.Index,11301 src_node: Ast.Node.Index,
11154 fields_len: u32,11302 fields_len: u32,
11155 decls_len: u32,11303 decls_len: u32,
11304 backing_int_ref: Zir.Inst.Ref,
11305 backing_int_body_len: u32,
11156 layout: std.builtin.Type.ContainerLayout,11306 layout: std.builtin.Type.ContainerLayout,
11157 known_non_opv: bool,11307 known_non_opv: bool,
11158 known_comptime_only: bool,11308 known_comptime_only: bool,
...@@ -11160,7 +11310,7 @@ const GenZir = struct {...@@ -11160,7 +11310,7 @@ const GenZir = struct {
11160 const astgen = gz.astgen;11310 const astgen = gz.astgen;
11161 const gpa = astgen.gpa;11311 const gpa = astgen.gpa;
1116211312
11163 try astgen.extra.ensureUnusedCapacity(gpa, 4);11313 try astgen.extra.ensureUnusedCapacity(gpa, 6);
11164 const payload_index = @intCast(u32, astgen.extra.items.len);11314 const payload_index = @intCast(u32, astgen.extra.items.len);
1116511315
11166 if (args.src_node != 0) {11316 if (args.src_node != 0) {
...@@ -11173,6 +11323,12 @@ const GenZir = struct {...@@ -11173,6 +11323,12 @@ const GenZir = struct {
11173 if (args.decls_len != 0) {11323 if (args.decls_len != 0) {
11174 astgen.extra.appendAssumeCapacity(args.decls_len);11324 astgen.extra.appendAssumeCapacity(args.decls_len);
11175 }11325 }
11326 if (args.backing_int_ref != .none) {
11327 astgen.extra.appendAssumeCapacity(args.backing_int_body_len);
11328 if (args.backing_int_body_len == 0) {
11329 astgen.extra.appendAssumeCapacity(@enumToInt(args.backing_int_ref));
11330 }
11331 }
11176 astgen.instructions.set(inst, .{11332 astgen.instructions.set(inst, .{
11177 .tag = .extended,11333 .tag = .extended,
11178 .data = .{ .extended = .{11334 .data = .{ .extended = .{
...@@ -11181,6 +11337,7 @@ const GenZir = struct {...@@ -11181,6 +11337,7 @@ const GenZir = struct {
11181 .has_src_node = args.src_node != 0,11337 .has_src_node = args.src_node != 0,
11182 .has_fields_len = args.fields_len != 0,11338 .has_fields_len = args.fields_len != 0,
11183 .has_decls_len = args.decls_len != 0,11339 .has_decls_len = args.decls_len != 0,
11340 .has_backing_int = args.backing_int_ref != .none,
11184 .known_non_opv = args.known_non_opv,11341 .known_non_opv = args.known_non_opv,
11185 .known_comptime_only = args.known_comptime_only,11342 .known_comptime_only = args.known_comptime_only,
11186 .name_strategy = gz.anon_name_strategy,11343 .name_strategy = gz.anon_name_strategy,
...@@ -11605,6 +11762,45 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast....@@ -11605,6 +11762,45 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast.
11605 error.OutOfMemory => return error.OutOfMemory,11762 error.OutOfMemory => return error.OutOfMemory,
11606 }11763 }
11607 }11764 }
11765
11766 var s = namespace.parent;
11767 while (true) switch (s.tag) {
11768 .local_val => {
11769 const local_val = s.cast(Scope.LocalVal).?;
11770 if (local_val.name == name_str_index) {
11771 return astgen.failTokNotes(name_token, "redeclaration of {s} '{s}'", .{
11772 @tagName(local_val.id_cat), token_bytes,
11773 }, &[_]u32{
11774 try astgen.errNoteTok(
11775 local_val.token_src,
11776 "previous declaration here",
11777 .{},
11778 ),
11779 });
11780 }
11781 s = local_val.parent;
11782 },
11783 .local_ptr => {
11784 const local_ptr = s.cast(Scope.LocalPtr).?;
11785 if (local_ptr.name == name_str_index) {
11786 return astgen.failTokNotes(name_token, "redeclaration of {s} '{s}'", .{
11787 @tagName(local_ptr.id_cat), token_bytes,
11788 }, &[_]u32{
11789 try astgen.errNoteTok(
11790 local_ptr.token_src,
11791 "previous declaration here",
11792 .{},
11793 ),
11794 });
11795 }
11796 s = local_ptr.parent;
11797 },
11798 .namespace => s = s.cast(Scope.Namespace).?.parent,
11799 .gen_zir => s = s.cast(GenZir).?.parent,
11800 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
11801 .defer_gen => s = s.cast(Scope.DeferGen).?.parent,
11802 .top => break,
11803 };
11608 gop.value_ptr.* = member_node;11804 gop.value_ptr.* = member_node;
11609 }11805 }
11610 return decl_count;11806 return decl_count;
...@@ -11662,3 +11858,14 @@ fn countBodyLenAfterFixups(astgen: *AstGen, body: []const Zir.Inst.Index) u32 {...@@ -11662,3 +11858,14 @@ fn countBodyLenAfterFixups(astgen: *AstGen, body: []const Zir.Inst.Index) u32 {
11662 }11858 }
11663 return @intCast(u32, count);11859 return @intCast(u32, count);
11664}11860}
11861
11862fn emitDbgStmt(gz: *GenZir, line: u32, column: u32) !void {
11863 if (gz.force_comptime) return;
11864
11865 _ = try gz.add(.{ .tag = .dbg_stmt, .data = .{
11866 .dbg_stmt = .{
11867 .line = line,
11868 .column = column,
11869 },
11870 } });
11871}
src/Autodoc.zig+316-101
...@@ -9,6 +9,7 @@ const Package = @import("Package.zig");...@@ -9,6 +9,7 @@ const Package = @import("Package.zig");
9const Zir = @import("Zir.zig");9const Zir = @import("Zir.zig");
10const Ref = Zir.Inst.Ref;10const Ref = Zir.Inst.Ref;
11const log = std.log.scoped(.autodoc);11const log = std.log.scoped(.autodoc);
12const Docgen = @import("autodoc/render_source.zig");
1213
13module: *Module,14module: *Module,
14doc_location: Compilation.EmitLoc,15doc_location: Compilation.EmitLoc,
...@@ -68,6 +69,8 @@ pub fn generateZirData(self: *Autodoc) !void {...@@ -68,6 +69,8 @@ pub fn generateZirData(self: *Autodoc) !void {
68 }69 }
69 }70 }
7071
72 log.debug("Ref map size: {}", .{Ref.typed_value_map.len});
73
71 const root_src_dir = self.module.main_pkg.root_src_directory;74 const root_src_dir = self.module.main_pkg.root_src_directory;
72 const root_src_path = self.module.main_pkg.root_src_path;75 const root_src_path = self.module.main_pkg.root_src_path;
73 const joined_src_path = try root_src_dir.join(self.arena, &.{root_src_path});76 const joined_src_path = try root_src_dir.join(self.arena, &.{root_src_path});
...@@ -158,6 +161,9 @@ pub fn generateZirData(self: *Autodoc) !void {...@@ -158,6 +161,9 @@ pub fn generateZirData(self: *Autodoc) !void {
158 .void_type => .{161 .void_type => .{
159 .Void = .{ .name = tmpbuf.toOwnedSlice() },162 .Void = .{ .name = tmpbuf.toOwnedSlice() },
160 },163 },
164 .type_info_type => .{
165 .ComptimeExpr = .{ .name = tmpbuf.toOwnedSlice() },
166 },
161 .type_type => .{167 .type_type => .{
162 .Type = .{ .name = tmpbuf.toOwnedSlice() },168 .Type = .{ .name = tmpbuf.toOwnedSlice() },
163 },169 },
...@@ -189,10 +195,14 @@ pub fn generateZirData(self: *Autodoc) !void {...@@ -189,10 +195,14 @@ pub fn generateZirData(self: *Autodoc) !void {
189 );195 );
190 }196 }
191197
192 var root_scope = Scope{ .parent = null, .enclosing_type = main_type_index };198 var root_scope = Scope{
199 .parent = null,
200 .enclosing_type = main_type_index,
201 };
202
193 try self.ast_nodes.append(self.arena, .{ .name = "(root)" });203 try self.ast_nodes.append(self.arena, .{ .name = "(root)" });
194 try self.files.put(self.arena, file, main_type_index);204 try self.files.put(self.arena, file, main_type_index);
195 _ = try self.walkInstruction(file, &root_scope, Zir.main_struct_inst, false);205 _ = try self.walkInstruction(file, &root_scope, 1, Zir.main_struct_inst, false);
196206
197 if (self.ref_paths_pending_on_decls.count() > 0) {207 if (self.ref_paths_pending_on_decls.count() > 0) {
198 @panic("some decl paths were never fully analized (pending on decls)");208 @panic("some decl paths were never fully analized (pending on decls)");
...@@ -242,6 +252,7 @@ pub fn generateZirData(self: *Autodoc) !void {...@@ -242,6 +252,7 @@ pub fn generateZirData(self: *Autodoc) !void {
242 try d.handle.openDir(self.doc_location.basename, .{})252 try d.handle.openDir(self.doc_location.basename, .{})
243 else253 else
244 try self.module.zig_cache_artifact_directory.handle.openDir(self.doc_location.basename, .{});254 try self.module.zig_cache_artifact_directory.handle.openDir(self.doc_location.basename, .{});
255
245 {256 {
246 const data_js_f = try output_dir.createFile("data.js", .{});257 const data_js_f = try output_dir.createFile("data.js", .{});
247 defer data_js_f.close();258 defer data_js_f.close();
...@@ -266,6 +277,29 @@ pub fn generateZirData(self: *Autodoc) !void {...@@ -266,6 +277,29 @@ pub fn generateZirData(self: *Autodoc) !void {
266 try buffer.flush();277 try buffer.flush();
267 }278 }
268279
280 {
281 output_dir.makeDir("src") catch |e| switch (e) {
282 error.PathAlreadyExists => {},
283 else => |err| return err,
284 };
285 const html_dir = try output_dir.openDir("src", .{});
286
287 var files_iterator = self.files.iterator();
288
289 while (files_iterator.next()) |entry| {
290 const new_html_path = entry.key_ptr.*.sub_file_path;
291
292 const html_file = try createFromPath(html_dir, new_html_path);
293 defer html_file.close();
294 var buffer = std.io.bufferedWriter(html_file.writer());
295
296 const out = buffer.writer();
297
298 try Docgen.genHtml(self.module.gpa, entry.key_ptr.*, out);
299 try buffer.flush();
300 }
301 }
302
269 // copy main.js, index.html303 // copy main.js, index.html
270 var docs_dir = try self.module.comp.zig_lib_directory.handle.openDir("docs", .{});304 var docs_dir = try self.module.comp.zig_lib_directory.handle.openDir("docs", .{});
271 defer docs_dir.close();305 defer docs_dir.close();
...@@ -273,6 +307,26 @@ pub fn generateZirData(self: *Autodoc) !void {...@@ -273,6 +307,26 @@ pub fn generateZirData(self: *Autodoc) !void {
273 try docs_dir.copyFile("index.html", output_dir, "index.html", .{});307 try docs_dir.copyFile("index.html", output_dir, "index.html", .{});
274}308}
275309
310fn createFromPath(base_dir: std.fs.Dir, path: []const u8) !std.fs.File {
311 var path_tokens = std.mem.tokenize(u8, path, std.fs.path.sep_str);
312 var dir = base_dir;
313 while (path_tokens.next()) |toc| {
314 if (path_tokens.peek() != null) {
315 dir.makeDir(toc) catch |e| switch (e) {
316 error.PathAlreadyExists => {},
317 else => |err| return err,
318 };
319 dir = try dir.openDir(toc, .{});
320 } else {
321 return dir.createFile(toc, .{}) catch |e| switch (e) {
322 error.PathAlreadyExists => try dir.openFile(toc, .{}),
323 else => |err| return err,
324 };
325 }
326 }
327 return error.EmptyPath;
328}
329
276/// Represents a chain of scopes, used to resolve decl references to the330/// Represents a chain of scopes, used to resolve decl references to the
277/// corresponding entry in `self.decls`.331/// corresponding entry in `self.decls`.
278const Scope = struct {332const Scope = struct {
...@@ -563,6 +617,7 @@ const DocData = struct {...@@ -563,6 +617,7 @@ const DocData = struct {
563 type: usize, // index in `types`617 type: usize, // index in `types`
564 this: usize, // index in `types`618 this: usize, // index in `types`
565 declRef: usize, // index in `decls`619 declRef: usize, // index in `decls`
620 builtinField: enum { len, ptr },
566 fieldRef: FieldRef,621 fieldRef: FieldRef,
567 refPath: []Expr,622 refPath: []Expr,
568 int: struct {623 int: struct {
...@@ -587,7 +642,7 @@ const DocData = struct {...@@ -587,7 +642,7 @@ const DocData = struct {
587 sizeOf: usize, // index in `exprs`642 sizeOf: usize, // index in `exprs`
588 bitSizeOf: usize, // index in `exprs`643 bitSizeOf: usize, // index in `exprs`
589 enumToInt: usize, // index in `exprs`644 enumToInt: usize, // index in `exprs`
590 compileError: []const u8,645 compileError: usize, //index in `exprs`
591 errorSets: usize,646 errorSets: usize,
592 string: []const u8, // direct value647 string: []const u8, // direct value
593 sliceIndex: usize,648 sliceIndex: usize,
...@@ -652,20 +707,26 @@ const DocData = struct {...@@ -652,20 +707,26 @@ const DocData = struct {
652 var jsw = std.json.writeStream(w, 15);707 var jsw = std.json.writeStream(w, 15);
653 try jsw.beginObject();708 try jsw.beginObject();
654 try jsw.objectField(@tagName(active_tag));709 try jsw.objectField(@tagName(active_tag));
655 inline for (comptime std.meta.fields(Expr)) |case| {710 switch (self) {
656 if (@field(Expr, case.name) == active_tag) {711 .int => {
657 switch (active_tag) {712 if (self.int.negated) try w.writeAll("-");
658 .int => {713 try jsw.emitNumber(self.int.value);
659 if (self.int.negated) try w.writeAll("-");714 },
660 try jsw.emitNumber(self.int.value);715 .int_big => {
661 },
662 .int_big => {
663716
664 //@panic("TODO: json serialization of big ints!");717 //@panic("TODO: json serialization of big ints!");
665 //if (v.negated) try w.writeAll("-");718 //if (v.negated) try w.writeAll("-");
666 //try jsw.emitNumber(v.value);719 //try jsw.emitNumber(v.value);
667 },720 },
668 else => {721 .builtinField => {
722 try jsw.emitString(@tagName(self.builtinField));
723 },
724 else => {
725 inline for (comptime std.meta.fields(Expr)) |case| {
726 // TODO: this is super ugly, fix once `inline else` is a thing
727 if (comptime std.mem.eql(u8, case.name, "builtinField"))
728 continue;
729 if (@field(Expr, case.name) == active_tag) {
669 try std.json.stringify(@field(self, case.name), opt, w);730 try std.json.stringify(@field(self, case.name), opt, w);
670 jsw.state_index -= 1;731 jsw.state_index -= 1;
671 // TODO: we should not reach into the state of the732 // TODO: we should not reach into the state of the
...@@ -674,9 +735,9 @@ const DocData = struct {...@@ -674,9 +735,9 @@ const DocData = struct {
674 // would be nice to have a proper integration735 // would be nice to have a proper integration
675 // between the json writer and the generic736 // between the json writer and the generic
676 // std.json.stringify implementation737 // std.json.stringify implementation
677 },738 }
678 }739 }
679 }740 },
680 }741 }
681 try jsw.endObject();742 try jsw.endObject();
682 }743 }
...@@ -712,6 +773,7 @@ fn walkInstruction(...@@ -712,6 +773,7 @@ fn walkInstruction(
712 self: *Autodoc,773 self: *Autodoc,
713 file: *File,774 file: *File,
714 parent_scope: *Scope,775 parent_scope: *Scope,
776 parent_line: usize,
715 inst_index: usize,777 inst_index: usize,
716 need_type: bool, // true if the caller needs us to provide also a typeRef778 need_type: bool, // true if the caller needs us to provide also a typeRef
717) AutodocErrors!DocData.WalkResult {779) AutodocErrors!DocData.WalkResult {
...@@ -794,12 +856,16 @@ fn walkInstruction(...@@ -794,12 +856,16 @@ fn walkInstruction(
794856
795 const new_file = self.module.import_table.get(abs_root_src_path).?;857 const new_file = self.module.import_table.get(abs_root_src_path).?;
796858
797 var root_scope = Scope{ .parent = null, .enclosing_type = main_type_index };859 var root_scope = Scope{
860 .parent = null,
861 .enclosing_type = main_type_index,
862 };
798 try self.ast_nodes.append(self.arena, .{ .name = "(root)" });863 try self.ast_nodes.append(self.arena, .{ .name = "(root)" });
799 try self.files.put(self.arena, new_file, main_type_index);864 try self.files.put(self.arena, new_file, main_type_index);
800 return self.walkInstruction(865 return self.walkInstruction(
801 new_file,866 new_file,
802 &root_scope,867 &root_scope,
868 1,
803 Zir.main_struct_inst,869 Zir.main_struct_inst,
804 false,870 false,
805 );871 );
...@@ -824,13 +890,14 @@ fn walkInstruction(...@@ -824,13 +890,14 @@ fn walkInstruction(
824 return self.walkInstruction(890 return self.walkInstruction(
825 new_file.file,891 new_file.file,
826 &new_scope,892 &new_scope,
893 1,
827 Zir.main_struct_inst,894 Zir.main_struct_inst,
828 need_type,895 need_type,
829 );896 );
830 },897 },
831 .ret_node => {898 .ret_node => {
832 const un_node = data[inst_index].un_node;899 const un_node = data[inst_index].un_node;
833 return self.walkRef(file, parent_scope, un_node.operand, false);900 return self.walkRef(file, parent_scope, parent_line, un_node.operand, false);
834 },901 },
835 .ret_load => {902 .ret_load => {
836 const un_node = data[inst_index].un_node;903 const un_node = data[inst_index].un_node;
...@@ -861,7 +928,7 @@ fn walkInstruction(...@@ -861,7 +928,7 @@ fn walkInstruction(
861 }928 }
862929
863 if (result_ref) |rr| {930 if (result_ref) |rr| {
864 return self.walkRef(file, parent_scope, rr, need_type);931 return self.walkRef(file, parent_scope, parent_line, rr, need_type);
865 }932 }
866933
867 return DocData.WalkResult{934 return DocData.WalkResult{
...@@ -870,11 +937,11 @@ fn walkInstruction(...@@ -870,11 +937,11 @@ fn walkInstruction(
870 },937 },
871 .closure_get => {938 .closure_get => {
872 const inst_node = data[inst_index].inst_node;939 const inst_node = data[inst_index].inst_node;
873 return try self.walkInstruction(file, parent_scope, inst_node.inst, need_type);940 return try self.walkInstruction(file, parent_scope, parent_line, inst_node.inst, need_type);
874 },941 },
875 .closure_capture => {942 .closure_capture => {
876 const un_tok = data[inst_index].un_tok;943 const un_tok = data[inst_index].un_tok;
877 return try self.walkRef(file, parent_scope, un_tok.operand, need_type);944 return try self.walkRef(file, parent_scope, parent_line, un_tok.operand, need_type);
878 },945 },
879 .cmpxchg_strong, .cmpxchg_weak => {946 .cmpxchg_strong, .cmpxchg_weak => {
880 const pl_node = data[inst_index].pl_node;947 const pl_node = data[inst_index].pl_node;
...@@ -889,6 +956,7 @@ fn walkInstruction(...@@ -889,6 +956,7 @@ fn walkInstruction(
889 var ptr: DocData.WalkResult = try self.walkRef(956 var ptr: DocData.WalkResult = try self.walkRef(
890 file,957 file,
891 parent_scope,958 parent_scope,
959 parent_line,
892 extra.data.ptr,960 extra.data.ptr,
893 false,961 false,
894 );962 );
...@@ -898,6 +966,7 @@ fn walkInstruction(...@@ -898,6 +966,7 @@ fn walkInstruction(
898 var expected_value: DocData.WalkResult = try self.walkRef(966 var expected_value: DocData.WalkResult = try self.walkRef(
899 file,967 file,
900 parent_scope,968 parent_scope,
969 parent_line,
901 extra.data.expected_value,970 extra.data.expected_value,
902 false,971 false,
903 );972 );
...@@ -907,6 +976,7 @@ fn walkInstruction(...@@ -907,6 +976,7 @@ fn walkInstruction(
907 var new_value: DocData.WalkResult = try self.walkRef(976 var new_value: DocData.WalkResult = try self.walkRef(
908 file,977 file,
909 parent_scope,978 parent_scope,
979 parent_line,
910 extra.data.new_value,980 extra.data.new_value,
911 false,981 false,
912 );982 );
...@@ -916,6 +986,7 @@ fn walkInstruction(...@@ -916,6 +986,7 @@ fn walkInstruction(
916 var success_order: DocData.WalkResult = try self.walkRef(986 var success_order: DocData.WalkResult = try self.walkRef(
917 file,987 file,
918 parent_scope,988 parent_scope,
989 parent_line,
919 extra.data.success_order,990 extra.data.success_order,
920 false,991 false,
921 );992 );
...@@ -925,6 +996,7 @@ fn walkInstruction(...@@ -925,6 +996,7 @@ fn walkInstruction(
925 var failure_order: DocData.WalkResult = try self.walkRef(996 var failure_order: DocData.WalkResult = try self.walkRef(
926 file,997 file,
927 parent_scope,998 parent_scope,
999 parent_line,
928 extra.data.failure_order,1000 extra.data.failure_order,
929 false,1001 false,
930 );1002 );
...@@ -978,17 +1050,16 @@ fn walkInstruction(...@@ -978,17 +1050,16 @@ fn walkInstruction(
978 var operand: DocData.WalkResult = try self.walkRef(1050 var operand: DocData.WalkResult = try self.walkRef(
979 file,1051 file,
980 parent_scope,1052 parent_scope,
1053 parent_line,
981 un_node.operand,1054 un_node.operand,
982 false,1055 false,
983 );1056 );
9841057
1058 const operand_index = self.exprs.items.len;
1059 try self.exprs.append(self.arena, operand.expr);
1060
985 return DocData.WalkResult{1061 return DocData.WalkResult{
986 .expr = .{1062 .expr = .{ .compileError = operand_index },
987 .compileError = switch (operand.expr) {
988 .string => |s| s,
989 else => "TODO: non-string @compileError arguments",
990 },
991 },
992 };1063 };
993 },1064 },
994 .enum_literal => {1065 .enum_literal => {
...@@ -1034,12 +1105,14 @@ fn walkInstruction(...@@ -1034,12 +1105,14 @@ fn walkInstruction(
1034 var lhs: DocData.WalkResult = try self.walkRef(1105 var lhs: DocData.WalkResult = try self.walkRef(
1035 file,1106 file,
1036 parent_scope,1107 parent_scope,
1108 parent_line,
1037 extra.data.lhs,1109 extra.data.lhs,
1038 false,1110 false,
1039 );1111 );
1040 var start: DocData.WalkResult = try self.walkRef(1112 var start: DocData.WalkResult = try self.walkRef(
1041 file,1113 file,
1042 parent_scope,1114 parent_scope,
1115 parent_line,
1043 extra.data.start,1116 extra.data.start,
1044 false,1117 false,
1045 );1118 );
...@@ -1065,18 +1138,21 @@ fn walkInstruction(...@@ -1065,18 +1138,21 @@ fn walkInstruction(
1065 var lhs: DocData.WalkResult = try self.walkRef(1138 var lhs: DocData.WalkResult = try self.walkRef(
1066 file,1139 file,
1067 parent_scope,1140 parent_scope,
1141 parent_line,
1068 extra.data.lhs,1142 extra.data.lhs,
1069 false,1143 false,
1070 );1144 );
1071 var start: DocData.WalkResult = try self.walkRef(1145 var start: DocData.WalkResult = try self.walkRef(
1072 file,1146 file,
1073 parent_scope,1147 parent_scope,
1148 parent_line,
1074 extra.data.start,1149 extra.data.start,
1075 false,1150 false,
1076 );1151 );
1077 var end: DocData.WalkResult = try self.walkRef(1152 var end: DocData.WalkResult = try self.walkRef(
1078 file,1153 file,
1079 parent_scope,1154 parent_scope,
1155 parent_line,
1080 extra.data.end,1156 extra.data.end,
1081 false,1157 false,
1082 );1158 );
...@@ -1104,24 +1180,28 @@ fn walkInstruction(...@@ -1104,24 +1180,28 @@ fn walkInstruction(
1104 var lhs: DocData.WalkResult = try self.walkRef(1180 var lhs: DocData.WalkResult = try self.walkRef(
1105 file,1181 file,
1106 parent_scope,1182 parent_scope,
1183 parent_line,
1107 extra.data.lhs,1184 extra.data.lhs,
1108 false,1185 false,
1109 );1186 );
1110 var start: DocData.WalkResult = try self.walkRef(1187 var start: DocData.WalkResult = try self.walkRef(
1111 file,1188 file,
1112 parent_scope,1189 parent_scope,
1190 parent_line,
1113 extra.data.start,1191 extra.data.start,
1114 false,1192 false,
1115 );1193 );
1116 var end: DocData.WalkResult = try self.walkRef(1194 var end: DocData.WalkResult = try self.walkRef(
1117 file,1195 file,
1118 parent_scope,1196 parent_scope,
1197 parent_line,
1119 extra.data.end,1198 extra.data.end,
1120 false,1199 false,
1121 );1200 );
1122 var sentinel: DocData.WalkResult = try self.walkRef(1201 var sentinel: DocData.WalkResult = try self.walkRef(
1123 file,1202 file,
1124 parent_scope,1203 parent_scope,
1204 parent_line,
1125 extra.data.sentinel,1205 extra.data.sentinel,
1126 false,1206 false,
1127 );1207 );
...@@ -1171,12 +1251,14 @@ fn walkInstruction(...@@ -1171,12 +1251,14 @@ fn walkInstruction(
1171 var lhs: DocData.WalkResult = try self.walkRef(1251 var lhs: DocData.WalkResult = try self.walkRef(
1172 file,1252 file,
1173 parent_scope,1253 parent_scope,
1254 parent_line,
1174 extra.data.lhs,1255 extra.data.lhs,
1175 false,1256 false,
1176 );1257 );
1177 var rhs: DocData.WalkResult = try self.walkRef(1258 var rhs: DocData.WalkResult = try self.walkRef(
1178 file,1259 file,
1179 parent_scope,1260 parent_scope,
1261 parent_line,
1180 extra.data.rhs,1262 extra.data.rhs,
1181 false,1263 false,
1182 );1264 );
...@@ -1220,7 +1302,6 @@ fn walkInstruction(...@@ -1220,7 +1302,6 @@ fn walkInstruction(
1220 .trunc,1302 .trunc,
1221 .round,1303 .round,
1222 .tag_name,1304 .tag_name,
1223 .reify,
1224 .type_name,1305 .type_name,
1225 .frame_type,1306 .frame_type,
1226 .frame_size,1307 .frame_size,
...@@ -1238,7 +1319,7 @@ fn walkInstruction(...@@ -1238,7 +1319,7 @@ fn walkInstruction(
1238 const un_node = data[inst_index].un_node;1319 const un_node = data[inst_index].un_node;
1239 const bin_index = self.exprs.items.len;1320 const bin_index = self.exprs.items.len;
1240 try self.exprs.append(self.arena, .{ .builtin = .{ .param = 0 } });1321 try self.exprs.append(self.arena, .{ .builtin = .{ .param = 0 } });
1241 const param = try self.walkRef(file, parent_scope, un_node.operand, false);1322 const param = try self.walkRef(file, parent_scope, parent_line, un_node.operand, false);
12421323
1243 const param_index = self.exprs.items.len;1324 const param_index = self.exprs.items.len;
1244 try self.exprs.append(self.arena, param.expr);1325 try self.exprs.append(self.arena, param.expr);
...@@ -1287,12 +1368,14 @@ fn walkInstruction(...@@ -1287,12 +1368,14 @@ fn walkInstruction(
1287 var lhs: DocData.WalkResult = try self.walkRef(1368 var lhs: DocData.WalkResult = try self.walkRef(
1288 file,1369 file,
1289 parent_scope,1370 parent_scope,
1371 parent_line,
1290 extra.data.lhs,1372 extra.data.lhs,
1291 false,1373 false,
1292 );1374 );
1293 var rhs: DocData.WalkResult = try self.walkRef(1375 var rhs: DocData.WalkResult = try self.walkRef(
1294 file,1376 file,
1295 parent_scope,1377 parent_scope,
1378 parent_line,
1296 extra.data.rhs,1379 extra.data.rhs,
1297 false,1380 false,
1298 );1381 );
...@@ -1315,12 +1398,14 @@ fn walkInstruction(...@@ -1315,12 +1398,14 @@ fn walkInstruction(
1315 var lhs: DocData.WalkResult = try self.walkRef(1398 var lhs: DocData.WalkResult = try self.walkRef(
1316 file,1399 file,
1317 parent_scope,1400 parent_scope,
1401 parent_line,
1318 extra.data.lhs,1402 extra.data.lhs,
1319 false,1403 false,
1320 );1404 );
1321 var rhs: DocData.WalkResult = try self.walkRef(1405 var rhs: DocData.WalkResult = try self.walkRef(
1322 file,1406 file,
1323 parent_scope,1407 parent_scope,
1408 parent_line,
1324 extra.data.rhs,1409 extra.data.rhs,
1325 false,1410 false,
1326 );1411 );
...@@ -1343,12 +1428,14 @@ fn walkInstruction(...@@ -1343,12 +1428,14 @@ fn walkInstruction(
1343 var lhs: DocData.WalkResult = try self.walkRef(1428 var lhs: DocData.WalkResult = try self.walkRef(
1344 file,1429 file,
1345 parent_scope,1430 parent_scope,
1431 parent_line,
1346 extra.data.lhs,1432 extra.data.lhs,
1347 false,1433 false,
1348 );1434 );
1349 var rhs: DocData.WalkResult = try self.walkRef(1435 var rhs: DocData.WalkResult = try self.walkRef(
1350 file,1436 file,
1351 parent_scope,1437 parent_scope,
1438 parent_line,
1352 extra.data.rhs,1439 extra.data.rhs,
1353 false,1440 false,
1354 );1441 );
...@@ -1368,7 +1455,7 @@ fn walkInstruction(...@@ -1368,7 +1455,7 @@ fn walkInstruction(
13681455
1369 // var operand: DocData.WalkResult = try self.walkRef(1456 // var operand: DocData.WalkResult = try self.walkRef(
1370 // file,1457 // file,
1371 // parent_scope,1458 // parent_scope, parent_line,
1372 // un_node.operand,1459 // un_node.operand,
1373 // false,1460 // false,
1374 // );1461 // );
...@@ -1377,7 +1464,7 @@ fn walkInstruction(...@@ -1377,7 +1464,7 @@ fn walkInstruction(
1377 // },1464 // },
1378 .overflow_arithmetic_ptr => {1465 .overflow_arithmetic_ptr => {
1379 const un_node = data[inst_index].un_node;1466 const un_node = data[inst_index].un_node;
1380 const elem_type_ref = try self.walkRef(file, parent_scope, un_node.operand, false);1467 const elem_type_ref = try self.walkRef(file, parent_scope, parent_line, un_node.operand, false);
1381 const type_slot_index = self.types.items.len;1468 const type_slot_index = self.types.items.len;
1382 try self.types.append(self.arena, .{1469 try self.types.append(self.arena, .{
1383 .Pointer = .{1470 .Pointer = .{
...@@ -1402,6 +1489,7 @@ fn walkInstruction(...@@ -1402,6 +1489,7 @@ fn walkInstruction(
1402 const elem_type_ref = try self.walkRef(1489 const elem_type_ref = try self.walkRef(
1403 file,1490 file,
1404 parent_scope,1491 parent_scope,
1492 parent_line,
1405 extra.data.elem_type,1493 extra.data.elem_type,
1406 false,1494 false,
1407 );1495 );
...@@ -1411,7 +1499,7 @@ fn walkInstruction(...@@ -1411,7 +1499,7 @@ fn walkInstruction(
1411 var sentinel: ?DocData.Expr = null;1499 var sentinel: ?DocData.Expr = null;
1412 if (ptr.flags.has_sentinel) {1500 if (ptr.flags.has_sentinel) {
1413 const ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);1501 const ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
1414 const ref_result = try self.walkRef(file, parent_scope, ref, false);1502 const ref_result = try self.walkRef(file, parent_scope, parent_line, ref, false);
1415 sentinel = ref_result.expr;1503 sentinel = ref_result.expr;
1416 extra_index += 1;1504 extra_index += 1;
1417 }1505 }
...@@ -1419,21 +1507,21 @@ fn walkInstruction(...@@ -1419,21 +1507,21 @@ fn walkInstruction(
1419 var @"align": ?DocData.Expr = null;1507 var @"align": ?DocData.Expr = null;
1420 if (ptr.flags.has_align) {1508 if (ptr.flags.has_align) {
1421 const ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);1509 const ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
1422 const ref_result = try self.walkRef(file, parent_scope, ref, false);1510 const ref_result = try self.walkRef(file, parent_scope, parent_line, ref, false);
1423 @"align" = ref_result.expr;1511 @"align" = ref_result.expr;
1424 extra_index += 1;1512 extra_index += 1;
1425 }1513 }
1426 var address_space: ?DocData.Expr = null;1514 var address_space: ?DocData.Expr = null;
1427 if (ptr.flags.has_addrspace) {1515 if (ptr.flags.has_addrspace) {
1428 const ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);1516 const ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
1429 const ref_result = try self.walkRef(file, parent_scope, ref, false);1517 const ref_result = try self.walkRef(file, parent_scope, parent_line, ref, false);
1430 address_space = ref_result.expr;1518 address_space = ref_result.expr;
1431 extra_index += 1;1519 extra_index += 1;
1432 }1520 }
1433 var bit_start: ?DocData.Expr = null;1521 var bit_start: ?DocData.Expr = null;
1434 if (ptr.flags.has_bit_range) {1522 if (ptr.flags.has_bit_range) {
1435 const ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);1523 const ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
1436 const ref_result = try self.walkRef(file, parent_scope, ref, false);1524 const ref_result = try self.walkRef(file, parent_scope, parent_line, ref, false);
1437 address_space = ref_result.expr;1525 address_space = ref_result.expr;
1438 extra_index += 1;1526 extra_index += 1;
1439 }1527 }
...@@ -1441,7 +1529,7 @@ fn walkInstruction(...@@ -1441,7 +1529,7 @@ fn walkInstruction(
1441 var host_size: ?DocData.Expr = null;1529 var host_size: ?DocData.Expr = null;
1442 if (ptr.flags.has_bit_range) {1530 if (ptr.flags.has_bit_range) {
1443 const ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);1531 const ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
1444 const ref_result = try self.walkRef(file, parent_scope, ref, false);1532 const ref_result = try self.walkRef(file, parent_scope, parent_line, ref, false);
1445 host_size = ref_result.expr;1533 host_size = ref_result.expr;
1446 }1534 }
14471535
...@@ -1471,8 +1559,8 @@ fn walkInstruction(...@@ -1471,8 +1559,8 @@ fn walkInstruction(
1471 .array_type => {1559 .array_type => {
1472 const pl_node = data[inst_index].pl_node;1560 const pl_node = data[inst_index].pl_node;
1473 const bin = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index).data;1561 const bin = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index).data;
1474 const len = try self.walkRef(file, parent_scope, bin.lhs, false);1562 const len = try self.walkRef(file, parent_scope, parent_line, bin.lhs, false);
1475 const child = try self.walkRef(file, parent_scope, bin.rhs, false);1563 const child = try self.walkRef(file, parent_scope, parent_line, bin.rhs, false);
14761564
1477 const type_slot_index = self.types.items.len;1565 const type_slot_index = self.types.items.len;
1478 try self.types.append(self.arena, .{1566 try self.types.append(self.arena, .{
...@@ -1490,9 +1578,9 @@ fn walkInstruction(...@@ -1490,9 +1578,9 @@ fn walkInstruction(
1490 .array_type_sentinel => {1578 .array_type_sentinel => {
1491 const pl_node = data[inst_index].pl_node;1579 const pl_node = data[inst_index].pl_node;
1492 const extra = file.zir.extraData(Zir.Inst.ArrayTypeSentinel, pl_node.payload_index);1580 const extra = file.zir.extraData(Zir.Inst.ArrayTypeSentinel, pl_node.payload_index);
1493 const len = try self.walkRef(file, parent_scope, extra.data.len, false);1581 const len = try self.walkRef(file, parent_scope, parent_line, extra.data.len, false);
1494 const sentinel = try self.walkRef(file, parent_scope, extra.data.sentinel, false);1582 const sentinel = try self.walkRef(file, parent_scope, parent_line, extra.data.sentinel, false);
1495 const elem_type = try self.walkRef(file, parent_scope, extra.data.elem_type, false);1583 const elem_type = try self.walkRef(file, parent_scope, parent_line, extra.data.elem_type, false);
14961584
1497 const type_slot_index = self.types.items.len;1585 const type_slot_index = self.types.items.len;
1498 try self.types.append(self.arena, .{1586 try self.types.append(self.arena, .{
...@@ -1514,10 +1602,10 @@ fn walkInstruction(...@@ -1514,10 +1602,10 @@ fn walkInstruction(
1514 const array_data = try self.arena.alloc(usize, operands.len - 1);1602 const array_data = try self.arena.alloc(usize, operands.len - 1);
15151603
1516 std.debug.assert(operands.len > 0);1604 std.debug.assert(operands.len > 0);
1517 var array_type = try self.walkRef(file, parent_scope, operands[0], false);1605 var array_type = try self.walkRef(file, parent_scope, parent_line, operands[0], false);
15181606
1519 for (operands[1..]) |op, idx| {1607 for (operands[1..]) |op, idx| {
1520 const wr = try self.walkRef(file, parent_scope, op, false);1608 const wr = try self.walkRef(file, parent_scope, parent_line, op, false);
1521 const expr_index = self.exprs.items.len;1609 const expr_index = self.exprs.items.len;
1522 try self.exprs.append(self.arena, wr.expr);1610 try self.exprs.append(self.arena, wr.expr);
1523 array_data[idx] = expr_index;1611 array_data[idx] = expr_index;
...@@ -1535,7 +1623,7 @@ fn walkInstruction(...@@ -1535,7 +1623,7 @@ fn walkInstruction(
1535 const array_data = try self.arena.alloc(usize, operands.len);1623 const array_data = try self.arena.alloc(usize, operands.len);
15361624
1537 for (operands) |op, idx| {1625 for (operands) |op, idx| {
1538 const wr = try self.walkRef(file, parent_scope, op, false);1626 const wr = try self.walkRef(file, parent_scope, parent_line, op, false);
1539 const expr_index = self.exprs.items.len;1627 const expr_index = self.exprs.items.len;
1540 try self.exprs.append(self.arena, wr.expr);1628 try self.exprs.append(self.arena, wr.expr);
1541 array_data[idx] = expr_index;1629 array_data[idx] = expr_index;
...@@ -1553,10 +1641,10 @@ fn walkInstruction(...@@ -1553,10 +1641,10 @@ fn walkInstruction(
1553 const array_data = try self.arena.alloc(usize, operands.len - 1);1641 const array_data = try self.arena.alloc(usize, operands.len - 1);
15541642
1555 std.debug.assert(operands.len > 0);1643 std.debug.assert(operands.len > 0);
1556 var array_type = try self.walkRef(file, parent_scope, operands[0], false);1644 var array_type = try self.walkRef(file, parent_scope, parent_line, operands[0], false);
15571645
1558 for (operands[1..]) |op, idx| {1646 for (operands[1..]) |op, idx| {
1559 const wr = try self.walkRef(file, parent_scope, op, false);1647 const wr = try self.walkRef(file, parent_scope, parent_line, op, false);
1560 const expr_index = self.exprs.items.len;1648 const expr_index = self.exprs.items.len;
1561 try self.exprs.append(self.arena, wr.expr);1649 try self.exprs.append(self.arena, wr.expr);
1562 array_data[idx] = expr_index;1650 array_data[idx] = expr_index;
...@@ -1585,7 +1673,7 @@ fn walkInstruction(...@@ -1585,7 +1673,7 @@ fn walkInstruction(
1585 const array_data = try self.arena.alloc(usize, operands.len);1673 const array_data = try self.arena.alloc(usize, operands.len);
15861674
1587 for (operands) |op, idx| {1675 for (operands) |op, idx| {
1588 const wr = try self.walkRef(file, parent_scope, op, false);1676 const wr = try self.walkRef(file, parent_scope, parent_line, op, false);
1589 const expr_index = self.exprs.items.len;1677 const expr_index = self.exprs.items.len;
1590 try self.exprs.append(self.arena, wr.expr);1678 try self.exprs.append(self.arena, wr.expr);
1591 array_data[idx] = expr_index;1679 array_data[idx] = expr_index;
...@@ -1620,6 +1708,7 @@ fn walkInstruction(...@@ -1620,6 +1708,7 @@ fn walkInstruction(
1620 var operand: DocData.WalkResult = try self.walkRef(1708 var operand: DocData.WalkResult = try self.walkRef(
1621 file,1709 file,
1622 parent_scope,1710 parent_scope,
1711 parent_line,
1623 un_node.operand,1712 un_node.operand,
1624 need_type,1713 need_type,
1625 );1714 );
...@@ -1641,6 +1730,7 @@ fn walkInstruction(...@@ -1641,6 +1730,7 @@ fn walkInstruction(
1641 const operand = try self.walkRef(1730 const operand = try self.walkRef(
1642 file,1731 file,
1643 parent_scope,1732 parent_scope,
1733 parent_line,
1644 un_node.operand,1734 un_node.operand,
1645 false,1735 false,
1646 );1736 );
...@@ -1657,6 +1747,7 @@ fn walkInstruction(...@@ -1657,6 +1747,7 @@ fn walkInstruction(
1657 const operand = try self.walkRef(1747 const operand = try self.walkRef(
1658 file,1748 file,
1659 parent_scope,1749 parent_scope,
1750 parent_line,
1660 un_node.operand,1751 un_node.operand,
1661 need_type,1752 need_type,
1662 );1753 );
...@@ -1674,6 +1765,7 @@ fn walkInstruction(...@@ -1674,6 +1765,7 @@ fn walkInstruction(
1674 const operand = try self.walkRef(1765 const operand = try self.walkRef(
1675 file,1766 file,
1676 parent_scope,1767 parent_scope,
1768 parent_line,
1677 un_node.operand,1769 un_node.operand,
1678 false,1770 false,
1679 );1771 );
...@@ -1690,7 +1782,7 @@ fn walkInstruction(...@@ -1690,7 +1782,7 @@ fn walkInstruction(
1690 const pl_node = data[inst_index].pl_node;1782 const pl_node = data[inst_index].pl_node;
1691 const extra = file.zir.extraData(Zir.Inst.SwitchBlock, pl_node.payload_index);1783 const extra = file.zir.extraData(Zir.Inst.SwitchBlock, pl_node.payload_index);
1692 const cond_index = self.exprs.items.len;1784 const cond_index = self.exprs.items.len;
1693 _ = try self.walkRef(file, parent_scope, extra.data.operand, false);1785 _ = try self.walkRef(file, parent_scope, parent_line, extra.data.operand, false);
16941786
1695 const ast_index = self.ast_nodes.items.len;1787 const ast_index = self.ast_nodes.items.len;
1696 const type_index = self.types.items.len - 1;1788 const type_index = self.types.items.len - 1;
...@@ -1718,6 +1810,7 @@ fn walkInstruction(...@@ -1718,6 +1810,7 @@ fn walkInstruction(
1718 const operand = try self.walkRef(1810 const operand = try self.walkRef(
1719 file,1811 file,
1720 parent_scope,1812 parent_scope,
1813 parent_line,
1721 un_node.operand,1814 un_node.operand,
1722 need_type,1815 need_type,
1723 );1816 );
...@@ -1743,6 +1836,7 @@ fn walkInstruction(...@@ -1743,6 +1836,7 @@ fn walkInstruction(
1743 const operand = try self.walkRef(1836 const operand = try self.walkRef(
1744 file,1837 file,
1745 parent_scope,1838 parent_scope,
1839 parent_line,
1746 un_node.operand,1840 un_node.operand,
1747 need_type,1841 need_type,
1748 );1842 );
...@@ -1762,6 +1856,7 @@ fn walkInstruction(...@@ -1762,6 +1856,7 @@ fn walkInstruction(
1762 var operand: DocData.WalkResult = try self.walkRef(1856 var operand: DocData.WalkResult = try self.walkRef(
1763 file,1857 file,
1764 parent_scope,1858 parent_scope,
1859 parent_line,
1765 data[body].@"break".operand,1860 data[body].@"break".operand,
1766 false,1861 false,
1767 );1862 );
...@@ -1780,6 +1875,7 @@ fn walkInstruction(...@@ -1780,6 +1875,7 @@ fn walkInstruction(
1780 const operand = try self.walkRef(1875 const operand = try self.walkRef(
1781 file,1876 file,
1782 parent_scope,1877 parent_scope,
1878 parent_line,
1783 un_node.operand,1879 un_node.operand,
1784 need_type,1880 need_type,
1785 );1881 );
...@@ -1798,6 +1894,7 @@ fn walkInstruction(...@@ -1798,6 +1894,7 @@ fn walkInstruction(
1798 const dest_type_walk = try self.walkRef(1894 const dest_type_walk = try self.walkRef(
1799 file,1895 file,
1800 parent_scope,1896 parent_scope,
1897 parent_line,
1801 extra.data.dest_type,1898 extra.data.dest_type,
1802 false,1899 false,
1803 );1900 );
...@@ -1805,6 +1902,7 @@ fn walkInstruction(...@@ -1805,6 +1902,7 @@ fn walkInstruction(
1805 const operand = try self.walkRef(1902 const operand = try self.walkRef(
1806 file,1903 file,
1807 parent_scope,1904 parent_scope,
1905 parent_line,
1808 extra.data.operand,1906 extra.data.operand,
1809 false,1907 false,
1810 );1908 );
...@@ -1832,6 +1930,7 @@ fn walkInstruction(...@@ -1832,6 +1930,7 @@ fn walkInstruction(
1832 const operand: DocData.WalkResult = try self.walkRef(1930 const operand: DocData.WalkResult = try self.walkRef(
1833 file,1931 file,
1834 parent_scope,1932 parent_scope,
1933 parent_line,
1835 un_node.operand,1934 un_node.operand,
1836 false,1935 false,
1837 );1936 );
...@@ -1863,31 +1962,60 @@ fn walkInstruction(...@@ -1863,31 +1962,60 @@ fn walkInstruction(
1863 const extra = file.zir.extraData(Zir.Inst.Field, pl_node.payload_index);1962 const extra = file.zir.extraData(Zir.Inst.Field, pl_node.payload_index);
18641963
1865 var path: std.ArrayListUnmanaged(DocData.Expr) = .{};1964 var path: std.ArrayListUnmanaged(DocData.Expr) = .{};
1866 var lhs = @enumToInt(extra.data.lhs) - Ref.typed_value_map.len; // underflow = need to handle Refs
1867
1868 try path.append(self.arena, .{1965 try path.append(self.arena, .{
1869 .string = file.zir.nullTerminatedString(extra.data.field_name_start),1966 .string = file.zir.nullTerminatedString(extra.data.field_name_start),
1870 });1967 });
1968
1871 // Put inside path the starting index of each decl name that1969 // Put inside path the starting index of each decl name that
1872 // we encounter as we navigate through all the field_vals1970 // we encounter as we navigate through all the field_*s
1873 while (tags[lhs] == .field_val or1971 const lhs_ref = blk: {
1874 tags[lhs] == .field_call_bind or1972 var lhs_extra = extra;
1875 tags[lhs] == .field_ptr or1973 while (true) {
1876 tags[lhs] == .field_type)1974 if (@enumToInt(lhs_extra.data.lhs) < Ref.typed_value_map.len) {
1877 {1975 break :blk lhs_extra.data.lhs;
1878 const lhs_extra = file.zir.extraData(1976 }
1879 Zir.Inst.Field,
1880 data[lhs].pl_node.payload_index,
1881 );
18821977
1883 try path.append(self.arena, .{1978 const lhs = @enumToInt(lhs_extra.data.lhs) - Ref.typed_value_map.len;
1884 .string = file.zir.nullTerminatedString(lhs_extra.data.field_name_start),1979 if (tags[lhs] != .field_val and
1885 });1980 tags[lhs] != .field_call_bind and
1886 lhs = @enumToInt(lhs_extra.data.lhs) - Ref.typed_value_map.len; // underflow = need to handle Refs1981 tags[lhs] != .field_ptr and
1887 }1982 tags[lhs] != .field_type) break :blk lhs_extra.data.lhs;
1983
1984 lhs_extra = file.zir.extraData(
1985 Zir.Inst.Field,
1986 data[lhs].pl_node.payload_index,
1987 );
18881988
1989 try path.append(self.arena, .{
1990 .string = file.zir.nullTerminatedString(lhs_extra.data.field_name_start),
1991 });
1992 }
1993 };
1994
1995 // If the lhs is a `call` instruction, it means that we're inside
1996 // a function call and we're referring to one of its arguments.
1997 // We can't just blindly analyze the instruction or we will
1998 // start recursing forever.
1999 // TODO: add proper resolution of the container type for `calls`
2000 // TODO: we're like testing lhs as an instruction twice
2001 // (above and below) this todo, maybe a cleaer solution woul
2002 // avoid that.
1889 // TODO: double check that we really don't need type info here2003 // TODO: double check that we really don't need type info here
1890 const wr = try self.walkInstruction(file, parent_scope, lhs, false);2004
2005 const wr = blk: {
2006 if (@enumToInt(lhs_ref) >= Ref.typed_value_map.len) {
2007 const lhs_inst = @enumToInt(lhs_ref) - Ref.typed_value_map.len;
2008 if (tags[lhs_inst] == .call) {
2009 break :blk DocData.WalkResult{
2010 .expr = .{
2011 .comptimeExpr = 0,
2012 },
2013 };
2014 }
2015 }
2016
2017 break :blk try self.walkRef(file, parent_scope, parent_line, lhs_ref, false);
2018 };
1891 try path.append(self.arena, wr.expr);2019 try path.append(self.arena, wr.expr);
18922020
1893 // This way the data in `path` has the same ordering that the ref2021 // This way the data in `path` has the same ordering that the ref
...@@ -1906,7 +2034,7 @@ fn walkInstruction(...@@ -1906,7 +2034,7 @@ fn walkInstruction(
1906 // - (2) Paths can sometimes never resolve fully. This means that2034 // - (2) Paths can sometimes never resolve fully. This means that
1907 // any value that depends on that will have to become a2035 // any value that depends on that will have to become a
1908 // comptimeExpr.2036 // comptimeExpr.
1909 try self.tryResolveRefPath(file, lhs, path.items);2037 try self.tryResolveRefPath(file, inst_index, path.items);
1910 return DocData.WalkResult{ .expr = .{ .refPath = path.items } };2038 return DocData.WalkResult{ .expr = .{ .refPath = path.items } };
1911 },2039 },
1912 .int_type => {2040 .int_type => {
...@@ -1937,6 +2065,7 @@ fn walkInstruction(...@@ -1937,6 +2065,7 @@ fn walkInstruction(
1937 return self.walkRef(2065 return self.walkRef(
1938 file,2066 file,
1939 parent_scope,2067 parent_scope,
2068 parent_line,
1940 getBlockInlineBreak(file.zir, inst_index),2069 getBlockInlineBreak(file.zir, inst_index),
1941 need_type,2070 need_type,
1942 );2071 );
...@@ -1969,6 +2098,7 @@ fn walkInstruction(...@@ -1969,6 +2098,7 @@ fn walkInstruction(
1969 const wr = try self.walkRef(2098 const wr = try self.walkRef(
1970 file,2099 file,
1971 parent_scope,2100 parent_scope,
2101 parent_line,
1972 field_extra.data.container_type,2102 field_extra.data.container_type,
1973 false,2103 false,
1974 );2104 );
...@@ -1979,6 +2109,7 @@ fn walkInstruction(...@@ -1979,6 +2109,7 @@ fn walkInstruction(
1979 const value = try self.walkRef(2109 const value = try self.walkRef(
1980 file,2110 file,
1981 parent_scope,2111 parent_scope,
2112 parent_line,
1982 init_extra.data.init,2113 init_extra.data.init,
1983 need_type,2114 need_type,
1984 );2115 );
...@@ -1995,6 +2126,7 @@ fn walkInstruction(...@@ -1995,6 +2126,7 @@ fn walkInstruction(
1995 var operand: DocData.WalkResult = try self.walkRef(2126 var operand: DocData.WalkResult = try self.walkRef(
1996 file,2127 file,
1997 parent_scope,2128 parent_scope,
2129 parent_line,
1998 un_node.operand,2130 un_node.operand,
1999 false,2131 false,
2000 );2132 );
...@@ -2011,6 +2143,34 @@ fn walkInstruction(...@@ -2011,6 +2143,34 @@ fn walkInstruction(
2011 );2143 );
2012 return self.cteTodo(@tagName(tags[inst_index]));2144 return self.cteTodo(@tagName(tags[inst_index]));
2013 },2145 },
2146 .struct_init_anon => {
2147 const pl_node = data[inst_index].pl_node;
2148 const extra = file.zir.extraData(Zir.Inst.StructInitAnon, pl_node.payload_index);
2149
2150 const field_vals = try self.arena.alloc(
2151 DocData.Expr.FieldVal,
2152 extra.data.fields_len,
2153 );
2154
2155 var idx = extra.end;
2156 for (field_vals) |*fv| {
2157 const init_extra = file.zir.extraData(Zir.Inst.StructInitAnon.Item, idx);
2158 const field_name = file.zir.nullTerminatedString(init_extra.data.field_name);
2159 const value = try self.walkRef(
2160 file,
2161 parent_scope,
2162 parent_line,
2163 init_extra.data.init,
2164 need_type,
2165 );
2166 fv.* = .{ .name = field_name, .val = value };
2167 idx = init_extra.end;
2168 }
2169
2170 return DocData.WalkResult{
2171 .expr = .{ .@"struct" = field_vals },
2172 };
2173 },
2014 .error_set_decl => {2174 .error_set_decl => {
2015 const pl_node = data[inst_index].pl_node;2175 const pl_node = data[inst_index].pl_node;
2016 const extra = file.zir.extraData(Zir.Inst.ErrorSetDecl, pl_node.payload_index);2176 const extra = file.zir.extraData(Zir.Inst.ErrorSetDecl, pl_node.payload_index);
...@@ -2075,18 +2235,23 @@ fn walkInstruction(...@@ -2075,18 +2235,23 @@ fn walkInstruction(
2075 const pl_node = data[inst_index].pl_node;2235 const pl_node = data[inst_index].pl_node;
2076 const extra = file.zir.extraData(Zir.Inst.Call, pl_node.payload_index);2236 const extra = file.zir.extraData(Zir.Inst.Call, pl_node.payload_index);
20772237
2078 const callee = try self.walkRef(file, parent_scope, extra.data.callee, need_type);2238 const callee = try self.walkRef(file, parent_scope, parent_line, extra.data.callee, need_type);
20792239
2080 const args_len = extra.data.flags.args_len;2240 const args_len = extra.data.flags.args_len;
2081 var args = try self.arena.alloc(DocData.Expr, args_len);2241 var args = try self.arena.alloc(DocData.Expr, args_len);
2082 const arg_refs = file.zir.refSlice(extra.end, args_len);2242 const body = file.zir.extra[extra.end..];
2083 for (arg_refs) |ref, idx| {2243
2244 var i: usize = 0;
2245 while (i < args_len) : (i += 1) {
2246 const arg_end = file.zir.extra[extra.end + i];
2247 const break_index = body[arg_end - 1];
2248 const ref = data[break_index].@"break".operand;
2084 // TODO: consider toggling need_type to true if we ever want2249 // TODO: consider toggling need_type to true if we ever want
2085 // to show discrepancies between the types of provided2250 // to show discrepancies between the types of provided
2086 // arguments and the types declared in the function2251 // arguments and the types declared in the function
2087 // signature for its parameters.2252 // signature for its parameters.
2088 const wr = try self.walkRef(file, parent_scope, ref, false);2253 const wr = try self.walkRef(file, parent_scope, parent_line, ref, false);
2089 args[idx] = wr.expr;2254 args[i] = wr.expr;
2090 }2255 }
20912256
2092 const cte_slot_index = self.comptime_exprs.items.len;2257 const cte_slot_index = self.comptime_exprs.items.len;
...@@ -2116,6 +2281,7 @@ fn walkInstruction(...@@ -2116,6 +2281,7 @@ fn walkInstruction(
2116 const result = self.analyzeFunction(2281 const result = self.analyzeFunction(
2117 file,2282 file,
2118 parent_scope,2283 parent_scope,
2284 parent_line,
2119 inst_index,2285 inst_index,
2120 self_ast_node_index,2286 self_ast_node_index,
2121 type_slot_index,2287 type_slot_index,
...@@ -2131,6 +2297,7 @@ fn walkInstruction(...@@ -2131,6 +2297,7 @@ fn walkInstruction(
2131 const result = self.analyzeFancyFunction(2297 const result = self.analyzeFancyFunction(
2132 file,2298 file,
2133 parent_scope,2299 parent_scope,
2300 parent_line,
2134 inst_index,2301 inst_index,
2135 self_ast_node_index,2302 self_ast_node_index,
2136 type_slot_index,2303 type_slot_index,
...@@ -2158,7 +2325,7 @@ fn walkInstruction(...@@ -2158,7 +2325,7 @@ fn walkInstruction(
21582325
2159 var array_type: ?DocData.Expr = null;2326 var array_type: ?DocData.Expr = null;
2160 for (args) |arg, idx| {2327 for (args) |arg, idx| {
2161 const wr = try self.walkRef(file, parent_scope, arg, idx == 0);2328 const wr = try self.walkRef(file, parent_scope, parent_line, arg, idx == 0);
2162 if (idx == 0) {2329 if (idx == 0) {
2163 array_type = wr.typeRef;2330 array_type = wr.typeRef;
2164 }2331 }
...@@ -2303,6 +2470,7 @@ fn walkInstruction(...@@ -2303,6 +2470,7 @@ fn walkInstruction(
2303 extra_index = try self.walkDecls(2470 extra_index = try self.walkDecls(
2304 file,2471 file,
2305 &scope,2472 &scope,
2473 parent_line,
2306 decls_first_index,2474 decls_first_index,
2307 decls_len,2475 decls_len,
2308 &decl_indexes,2476 &decl_indexes,
...@@ -2323,6 +2491,7 @@ fn walkInstruction(...@@ -2323,6 +2491,7 @@ fn walkInstruction(
2323 try self.collectUnionFieldInfo(2491 try self.collectUnionFieldInfo(
2324 file,2492 file,
2325 &scope,2493 &scope,
2494 parent_line,
2326 fields_len,2495 fields_len,
2327 &field_type_refs,2496 &field_type_refs,
2328 &field_name_indexes,2497 &field_name_indexes,
...@@ -2423,6 +2592,7 @@ fn walkInstruction(...@@ -2423,6 +2592,7 @@ fn walkInstruction(
2423 extra_index = try self.walkDecls(2592 extra_index = try self.walkDecls(
2424 file,2593 file,
2425 &scope,2594 &scope,
2595 parent_line,
2426 decls_first_index,2596 decls_first_index,
2427 decls_len,2597 decls_len,
2428 &decl_indexes,2598 &decl_indexes,
...@@ -2532,6 +2702,17 @@ fn walkInstruction(...@@ -2532,6 +2702,17 @@ fn walkInstruction(
2532 break :blk decls_len;2702 break :blk decls_len;
2533 } else 0;2703 } else 0;
25342704
2705 // TODO: Expose explicit backing integer types in some way.
2706 if (small.has_backing_int) {
2707 const backing_int_body_len = file.zir.extra[extra_index];
2708 extra_index += 1; // backing_int_body_len
2709 if (backing_int_body_len == 0) {
2710 extra_index += 1; // backing_int_ref
2711 } else {
2712 extra_index += backing_int_body_len; // backing_int_body_inst
2713 }
2714 }
2715
2535 var decl_indexes: std.ArrayListUnmanaged(usize) = .{};2716 var decl_indexes: std.ArrayListUnmanaged(usize) = .{};
2536 var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};2717 var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};
25372718
...@@ -2555,6 +2736,7 @@ fn walkInstruction(...@@ -2555,6 +2736,7 @@ fn walkInstruction(
2555 extra_index = try self.walkDecls(2736 extra_index = try self.walkDecls(
2556 file,2737 file,
2557 &scope,2738 &scope,
2739 parent_line,
2558 decls_first_index,2740 decls_first_index,
2559 decls_len,2741 decls_len,
2560 &decl_indexes,2742 &decl_indexes,
...@@ -2567,6 +2749,7 @@ fn walkInstruction(...@@ -2567,6 +2749,7 @@ fn walkInstruction(
2567 try self.collectStructFieldInfo(2749 try self.collectStructFieldInfo(
2568 file,2750 file,
2569 &scope,2751 &scope,
2752 parent_line,
2570 fields_len,2753 fields_len,
2571 &field_type_refs,2754 &field_type_refs,
2572 &field_name_indexes,2755 &field_name_indexes,
...@@ -2605,11 +2788,12 @@ fn walkInstruction(...@@ -2605,11 +2788,12 @@ fn walkInstruction(
2605 },2788 },
2606 .error_to_int,2789 .error_to_int,
2607 .int_to_error,2790 .int_to_error,
2791 .reify,
2608 => {2792 => {
2609 const extra = file.zir.extraData(Zir.Inst.UnNode, extended.operand).data;2793 const extra = file.zir.extraData(Zir.Inst.UnNode, extended.operand).data;
2610 const bin_index = self.exprs.items.len;2794 const bin_index = self.exprs.items.len;
2611 try self.exprs.append(self.arena, .{ .builtin = .{ .param = 0 } });2795 try self.exprs.append(self.arena, .{ .builtin = .{ .param = 0 } });
2612 const param = try self.walkRef(file, parent_scope, extra.operand, false);2796 const param = try self.walkRef(file, parent_scope, parent_line, extra.operand, false);
26132797
2614 const param_index = self.exprs.items.len;2798 const param_index = self.exprs.items.len;
2615 try self.exprs.append(self.arena, param.expr);2799 try self.exprs.append(self.arena, param.expr);
...@@ -2637,6 +2821,7 @@ fn walkDecls(...@@ -2637,6 +2821,7 @@ fn walkDecls(
2637 self: *Autodoc,2821 self: *Autodoc,
2638 file: *File,2822 file: *File,
2639 scope: *Scope,2823 scope: *Scope,
2824 parent_line: usize,
2640 decls_first_index: usize,2825 decls_first_index: usize,
2641 decls_len: u32,2826 decls_len: u32,
2642 decl_indexes: *std.ArrayListUnmanaged(usize),2827 decl_indexes: *std.ArrayListUnmanaged(usize),
...@@ -2669,7 +2854,7 @@ fn walkDecls(...@@ -2669,7 +2854,7 @@ fn walkDecls(
26692854
2670 // const hash_u32s = file.zir.extra[extra_index..][0..4];2855 // const hash_u32s = file.zir.extra[extra_index..][0..4];
2671 extra_index += 4;2856 extra_index += 4;
2672 const line = file.zir.extra[extra_index];2857 const line = parent_line + file.zir.extra[extra_index];
2673 extra_index += 1;2858 extra_index += 1;
2674 const decl_name_index = file.zir.extra[extra_index];2859 const decl_name_index = file.zir.extra[extra_index];
2675 extra_index += 1;2860 extra_index += 1;
...@@ -2808,7 +2993,7 @@ fn walkDecls(...@@ -2808,7 +2993,7 @@ fn walkDecls(
2808 const ast_node_index = idx: {2993 const ast_node_index = idx: {
2809 const idx = self.ast_nodes.items.len;2994 const idx = self.ast_nodes.items.len;
2810 try self.ast_nodes.append(self.arena, .{2995 try self.ast_nodes.append(self.arena, .{
2811 .file = 0,2996 .file = self.files.getIndex(file) orelse unreachable,
2812 .line = line,2997 .line = line,
2813 .col = 0,2998 .col = 0,
2814 .docs = doc_comment,2999 .docs = doc_comment,
...@@ -2820,7 +3005,7 @@ fn walkDecls(...@@ -2820,7 +3005,7 @@ fn walkDecls(
2820 const walk_result = if (is_test) // TODO: decide if tests should show up at all3005 const walk_result = if (is_test) // TODO: decide if tests should show up at all
2821 DocData.WalkResult{ .expr = .{ .void = .{} } }3006 DocData.WalkResult{ .expr = .{ .void = .{} } }
2822 else3007 else
2823 try self.walkInstruction(file, scope, value_index, true);3008 try self.walkInstruction(file, scope, line, value_index, true);
28243009
2825 if (is_pub) {3010 if (is_pub) {
2826 try decl_indexes.append(self.arena, decls_slot_index);3011 try decl_indexes.append(self.arena, decls_slot_index);
...@@ -3013,6 +3198,10 @@ fn tryResolveRefPath(...@@ -3013,6 +3198,10 @@ fn tryResolveRefPath(
3013 .{ @tagName(self.types.items[t_index]), resolved_parent },3198 .{ @tagName(self.types.items[t_index]), resolved_parent },
3014 );3199 );
3015 },3200 },
3201 .ComptimeExpr => {
3202 // Same as the comptimeExpr branch above
3203 break :outer;
3204 },
3016 .Unanalyzed => {3205 .Unanalyzed => {
3017 // This decl path is pending completion3206 // This decl path is pending completion
3018 {3207 {
...@@ -3035,6 +3224,20 @@ fn tryResolveRefPath(...@@ -3035,6 +3224,20 @@ fn tryResolveRefPath(
30353224
3036 return;3225 return;
3037 },3226 },
3227 .Array => {
3228 if (std.mem.eql(u8, child_string, "len")) {
3229 path[i + 1] = .{
3230 .builtinField = .len,
3231 };
3232 } else {
3233 panicWithContext(
3234 file,
3235 inst_index,
3236 "TODO: handle `{s}` in tryResolveDeclPath.type.Array\nInfo: {}",
3237 .{ child_string, resolved_parent },
3238 );
3239 }
3240 },
3038 .Enum => |t_enum| {3241 .Enum => |t_enum| {
3039 for (t_enum.pubDecls) |d| {3242 for (t_enum.pubDecls) |d| {
3040 // TODO: this could be improved a lot3243 // TODO: this could be improved a lot
...@@ -3198,6 +3401,7 @@ fn analyzeFancyFunction(...@@ -3198,6 +3401,7 @@ fn analyzeFancyFunction(
3198 self: *Autodoc,3401 self: *Autodoc,
3199 file: *File,3402 file: *File,
3200 scope: *Scope,3403 scope: *Scope,
3404 parent_line: usize,
3201 inst_index: usize,3405 inst_index: usize,
3202 self_ast_node_index: usize,3406 self_ast_node_index: usize,
3203 type_slot_index: usize,3407 type_slot_index: usize,
...@@ -3262,7 +3466,7 @@ fn analyzeFancyFunction(...@@ -3262,7 +3466,7 @@ fn analyzeFancyFunction(
32623466
3263 const break_index = file.zir.extra[extra.end..][extra.data.body_len - 1];3467 const break_index = file.zir.extra[extra.end..][extra.data.body_len - 1];
3264 const break_operand = data[break_index].@"break".operand;3468 const break_operand = data[break_index].@"break".operand;
3265 const param_type_ref = try self.walkRef(file, scope, break_operand, false);3469 const param_type_ref = try self.walkRef(file, scope, parent_line, break_operand, false);
32663470
3267 param_type_refs.appendAssumeCapacity(param_type_ref.expr);3471 param_type_refs.appendAssumeCapacity(param_type_ref.expr);
3268 },3472 },
...@@ -3286,7 +3490,7 @@ fn analyzeFancyFunction(...@@ -3286,7 +3490,7 @@ fn analyzeFancyFunction(
3286 if (extra.data.bits.has_align_ref) {3490 if (extra.data.bits.has_align_ref) {
3287 const align_ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);3491 const align_ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
3288 align_index = self.exprs.items.len;3492 align_index = self.exprs.items.len;
3289 _ = try self.walkRef(file, scope, align_ref, false);3493 _ = try self.walkRef(file, scope, parent_line, align_ref, false);
3290 extra_index += 1;3494 extra_index += 1;
3291 } else if (extra.data.bits.has_align_body) {3495 } else if (extra.data.bits.has_align_body) {
3292 const align_body_len = file.zir.extra[extra_index];3496 const align_body_len = file.zir.extra[extra_index];
...@@ -3303,7 +3507,7 @@ fn analyzeFancyFunction(...@@ -3303,7 +3507,7 @@ fn analyzeFancyFunction(
3303 if (extra.data.bits.has_addrspace_ref) {3507 if (extra.data.bits.has_addrspace_ref) {
3304 const addrspace_ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);3508 const addrspace_ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
3305 addrspace_index = self.exprs.items.len;3509 addrspace_index = self.exprs.items.len;
3306 _ = try self.walkRef(file, scope, addrspace_ref, false);3510 _ = try self.walkRef(file, scope, parent_line, addrspace_ref, false);
3307 extra_index += 1;3511 extra_index += 1;
3308 } else if (extra.data.bits.has_addrspace_body) {3512 } else if (extra.data.bits.has_addrspace_body) {
3309 const addrspace_body_len = file.zir.extra[extra_index];3513 const addrspace_body_len = file.zir.extra[extra_index];
...@@ -3320,7 +3524,7 @@ fn analyzeFancyFunction(...@@ -3320,7 +3524,7 @@ fn analyzeFancyFunction(
3320 if (extra.data.bits.has_section_ref) {3524 if (extra.data.bits.has_section_ref) {
3321 const section_ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);3525 const section_ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
3322 section_index = self.exprs.items.len;3526 section_index = self.exprs.items.len;
3323 _ = try self.walkRef(file, scope, section_ref, false);3527 _ = try self.walkRef(file, scope, parent_line, section_ref, false);
3324 extra_index += 1;3528 extra_index += 1;
3325 } else if (extra.data.bits.has_section_body) {3529 } else if (extra.data.bits.has_section_body) {
3326 const section_body_len = file.zir.extra[extra_index];3530 const section_body_len = file.zir.extra[extra_index];
...@@ -3337,7 +3541,7 @@ fn analyzeFancyFunction(...@@ -3337,7 +3541,7 @@ fn analyzeFancyFunction(
3337 if (extra.data.bits.has_cc_ref) {3541 if (extra.data.bits.has_cc_ref) {
3338 const cc_ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);3542 const cc_ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
3339 cc_index = self.exprs.items.len;3543 cc_index = self.exprs.items.len;
3340 _ = try self.walkRef(file, scope, cc_ref, false);3544 _ = try self.walkRef(file, scope, parent_line, cc_ref, false);
3341 extra_index += 1;3545 extra_index += 1;
3342 } else if (extra.data.bits.has_cc_body) {3546 } else if (extra.data.bits.has_cc_body) {
3343 const cc_body_len = file.zir.extra[extra_index];3547 const cc_body_len = file.zir.extra[extra_index];
...@@ -3356,14 +3560,14 @@ fn analyzeFancyFunction(...@@ -3356,14 +3560,14 @@ fn analyzeFancyFunction(
3356 .none => DocData.Expr{ .void = .{} },3560 .none => DocData.Expr{ .void = .{} },
3357 else => blk: {3561 else => blk: {
3358 const ref = fn_info.ret_ty_ref;3562 const ref = fn_info.ret_ty_ref;
3359 const wr = try self.walkRef(file, scope, ref, false);3563 const wr = try self.walkRef(file, scope, parent_line, ref, false);
3360 break :blk wr.expr;3564 break :blk wr.expr;
3361 },3565 },
3362 },3566 },
3363 else => blk: {3567 else => blk: {
3364 const last_instr_index = fn_info.ret_ty_body[fn_info.ret_ty_body.len - 1];3568 const last_instr_index = fn_info.ret_ty_body[fn_info.ret_ty_body.len - 1];
3365 const break_operand = data[last_instr_index].@"break".operand;3569 const break_operand = data[last_instr_index].@"break".operand;
3366 const wr = try self.walkRef(file, scope, break_operand, false);3570 const wr = try self.walkRef(file, scope, parent_line, break_operand, false);
3367 break :blk wr.expr;3571 break :blk wr.expr;
3368 },3572 },
3369 };3573 };
...@@ -3378,6 +3582,7 @@ fn analyzeFancyFunction(...@@ -3378,6 +3582,7 @@ fn analyzeFancyFunction(
3378 break :blk try self.getGenericReturnType(3582 break :blk try self.getGenericReturnType(
3379 file,3583 file,
3380 scope,3584 scope,
3585 parent_line,
3381 fn_info.body[fn_info.body.len - 1],3586 fn_info.body[fn_info.body.len - 1],
3382 );3587 );
3383 } else {3588 } else {
...@@ -3414,6 +3619,7 @@ fn analyzeFunction(...@@ -3414,6 +3619,7 @@ fn analyzeFunction(
3414 self: *Autodoc,3619 self: *Autodoc,
3415 file: *File,3620 file: *File,
3416 scope: *Scope,3621 scope: *Scope,
3622 parent_line: usize,
3417 inst_index: usize,3623 inst_index: usize,
3418 self_ast_node_index: usize,3624 self_ast_node_index: usize,
3419 type_slot_index: usize,3625 type_slot_index: usize,
...@@ -3479,7 +3685,7 @@ fn analyzeFunction(...@@ -3479,7 +3685,7 @@ fn analyzeFunction(
34793685
3480 const break_index = file.zir.extra[extra.end..][extra.data.body_len - 1];3686 const break_index = file.zir.extra[extra.end..][extra.data.body_len - 1];
3481 const break_operand = data[break_index].@"break".operand;3687 const break_operand = data[break_index].@"break".operand;
3482 const param_type_ref = try self.walkRef(file, scope, break_operand, false);3688 const param_type_ref = try self.walkRef(file, scope, parent_line, break_operand, false);
34833689
3484 param_type_refs.appendAssumeCapacity(param_type_ref.expr);3690 param_type_refs.appendAssumeCapacity(param_type_ref.expr);
3485 },3691 },
...@@ -3492,14 +3698,14 @@ fn analyzeFunction(...@@ -3492,14 +3698,14 @@ fn analyzeFunction(
3492 .none => DocData.Expr{ .void = .{} },3698 .none => DocData.Expr{ .void = .{} },
3493 else => blk: {3699 else => blk: {
3494 const ref = fn_info.ret_ty_ref;3700 const ref = fn_info.ret_ty_ref;
3495 const wr = try self.walkRef(file, scope, ref, false);3701 const wr = try self.walkRef(file, scope, parent_line, ref, false);
3496 break :blk wr.expr;3702 break :blk wr.expr;
3497 },3703 },
3498 },3704 },
3499 else => blk: {3705 else => blk: {
3500 const last_instr_index = fn_info.ret_ty_body[fn_info.ret_ty_body.len - 1];3706 const last_instr_index = fn_info.ret_ty_body[fn_info.ret_ty_body.len - 1];
3501 const break_operand = data[last_instr_index].@"break".operand;3707 const break_operand = data[last_instr_index].@"break".operand;
3502 const wr = try self.walkRef(file, scope, break_operand, false);3708 const wr = try self.walkRef(file, scope, parent_line, break_operand, false);
3503 break :blk wr.expr;3709 break :blk wr.expr;
3504 },3710 },
3505 };3711 };
...@@ -3514,6 +3720,7 @@ fn analyzeFunction(...@@ -3514,6 +3720,7 @@ fn analyzeFunction(
3514 break :blk try self.getGenericReturnType(3720 break :blk try self.getGenericReturnType(
3515 file,3721 file,
3516 scope,3722 scope,
3723 parent_line,
3517 fn_info.body[fn_info.body.len - 1],3724 fn_info.body[fn_info.body.len - 1],
3518 );3725 );
3519 } else {3726 } else {
...@@ -3554,9 +3761,11 @@ fn getGenericReturnType(...@@ -3554,9 +3761,11 @@ fn getGenericReturnType(
3554 self: *Autodoc,3761 self: *Autodoc,
3555 file: *File,3762 file: *File,
3556 scope: *Scope,3763 scope: *Scope,
3764 parent_line: usize, // function decl line
3557 body_end: usize,3765 body_end: usize,
3558) !DocData.Expr {3766) !DocData.Expr {
3559 const wr = try self.walkInstruction(file, scope, body_end, false);3767 // TODO: compute the correct line offset
3768 const wr = try self.walkInstruction(file, scope, parent_line, body_end, false);
3560 return wr.expr;3769 return wr.expr;
3561}3770}
35623771
...@@ -3564,6 +3773,7 @@ fn collectUnionFieldInfo(...@@ -3564,6 +3773,7 @@ fn collectUnionFieldInfo(
3564 self: *Autodoc,3773 self: *Autodoc,
3565 file: *File,3774 file: *File,
3566 scope: *Scope,3775 scope: *Scope,
3776 parent_line: usize,
3567 fields_len: usize,3777 fields_len: usize,
3568 field_type_refs: *std.ArrayListUnmanaged(DocData.Expr),3778 field_type_refs: *std.ArrayListUnmanaged(DocData.Expr),
3569 field_name_indexes: *std.ArrayListUnmanaged(usize),3779 field_name_indexes: *std.ArrayListUnmanaged(usize),
...@@ -3610,7 +3820,7 @@ fn collectUnionFieldInfo(...@@ -3610,7 +3820,7 @@ fn collectUnionFieldInfo(
36103820
3611 // type3821 // type
3612 {3822 {
3613 const walk_result = try self.walkRef(file, scope, field_type, false);3823 const walk_result = try self.walkRef(file, scope, parent_line, field_type, false);
3614 try field_type_refs.append(self.arena, walk_result.expr);3824 try field_type_refs.append(self.arena, walk_result.expr);
3615 }3825 }
36163826
...@@ -3633,6 +3843,7 @@ fn collectStructFieldInfo(...@@ -3633,6 +3843,7 @@ fn collectStructFieldInfo(
3633 self: *Autodoc,3843 self: *Autodoc,
3634 file: *File,3844 file: *File,
3635 scope: *Scope,3845 scope: *Scope,
3846 parent_line: usize,
3636 fields_len: usize,3847 fields_len: usize,
3637 field_type_refs: *std.ArrayListUnmanaged(DocData.Expr),3848 field_type_refs: *std.ArrayListUnmanaged(DocData.Expr),
3638 field_name_indexes: *std.ArrayListUnmanaged(usize),3849 field_name_indexes: *std.ArrayListUnmanaged(usize),
...@@ -3706,7 +3917,7 @@ fn collectStructFieldInfo(...@@ -3706,7 +3917,7 @@ fn collectStructFieldInfo(
3706 for (fields) |field| {3917 for (fields) |field| {
3707 const type_expr = expr: {3918 const type_expr = expr: {
3708 if (field.type_ref != .none) {3919 if (field.type_ref != .none) {
3709 const walk_result = try self.walkRef(file, scope, field.type_ref, false);3920 const walk_result = try self.walkRef(file, scope, parent_line, field.type_ref, false);
3710 break :expr walk_result.expr;3921 break :expr walk_result.expr;
3711 }3922 }
37123923
...@@ -3716,7 +3927,7 @@ fn collectStructFieldInfo(...@@ -3716,7 +3927,7 @@ fn collectStructFieldInfo(
37163927
3717 const break_inst = body[body.len - 1];3928 const break_inst = body[body.len - 1];
3718 const operand = data[break_inst].@"break".operand;3929 const operand = data[break_inst].@"break".operand;
3719 const walk_result = try self.walkRef(file, scope, operand, false);3930 const walk_result = try self.walkRef(file, scope, parent_line, operand, false);
3720 break :expr walk_result.expr;3931 break :expr walk_result.expr;
3721 };3932 };
37223933
...@@ -3746,6 +3957,7 @@ fn walkRef(...@@ -3746,6 +3957,7 @@ fn walkRef(
3746 self: *Autodoc,3957 self: *Autodoc,
3747 file: *File,3958 file: *File,
3748 parent_scope: *Scope,3959 parent_scope: *Scope,
3960 parent_line: usize,
3749 ref: Ref,3961 ref: Ref,
3750 need_type: bool, // true when the caller needs also a typeRef for the return value3962 need_type: bool, // true when the caller needs also a typeRef for the return value
3751) AutodocErrors!DocData.WalkResult {3963) AutodocErrors!DocData.WalkResult {
...@@ -3761,9 +3973,12 @@ fn walkRef(...@@ -3761,9 +3973,12 @@ fn walkRef(
3761 } else if (enum_value < Ref.typed_value_map.len) {3973 } else if (enum_value < Ref.typed_value_map.len) {
3762 switch (ref) {3974 switch (ref) {
3763 else => {3975 else => {
3764 std.debug.panic("TODO: handle {s} in `walkRef`\n", .{3976 panicWithContext(
3765 @tagName(ref),3977 file,
3766 });3978 0,
3979 "TODO: handle {s} in walkRef",
3980 .{@tagName(ref)},
3981 );
3767 },3982 },
3768 .undef => {3983 .undef => {
3769 return DocData.WalkResult{ .expr = .@"undefined" };3984 return DocData.WalkResult{ .expr = .@"undefined" };
...@@ -3854,7 +4069,7 @@ fn walkRef(...@@ -3854,7 +4069,7 @@ fn walkRef(
3854 }4069 }
3855 } else {4070 } else {
3856 const zir_index = enum_value - Ref.typed_value_map.len;4071 const zir_index = enum_value - Ref.typed_value_map.len;
3857 return self.walkInstruction(file, parent_scope, zir_index, need_type);4072 return self.walkInstruction(file, parent_scope, parent_line, zir_index, need_type);
3858 }4073 }
3859}4074}
38604075
...@@ -3886,13 +4101,13 @@ fn cteTodo(self: *Autodoc, msg: []const u8) error{OutOfMemory}!DocData.WalkResul...@@ -3886,13 +4101,13 @@ fn cteTodo(self: *Autodoc, msg: []const u8) error{OutOfMemory}!DocData.WalkResul
3886}4101}
38874102
3888fn writeFileTableToJson(map: std.AutoArrayHashMapUnmanaged(*File, usize), jsw: anytype) !void {4103fn writeFileTableToJson(map: std.AutoArrayHashMapUnmanaged(*File, usize), jsw: anytype) !void {
3889 try jsw.beginObject();4104 try jsw.beginArray();
3890 var it = map.iterator();4105 var it = map.iterator();
3891 while (it.next()) |entry| {4106 while (it.next()) |entry| {
3892 try jsw.objectField(entry.key_ptr.*.sub_file_path);4107 try jsw.arrayElem();
3893 try jsw.emitNumber(entry.value_ptr.*);4108 try jsw.emitString(entry.key_ptr.*.sub_file_path);
3894 }4109 }
3895 try jsw.endObject();4110 try jsw.endArray();
3896}4111}
38974112
3898fn writePackageTableToJson(4113fn writePackageTableToJson(
src/BuiltinFn.zig+5-5
...@@ -250,14 +250,14 @@ pub const list = list: {...@@ -250,14 +250,14 @@ pub const list = list: {
250 "@byteSwap",250 "@byteSwap",
251 .{251 .{
252 .tag = .byte_swap,252 .tag = .byte_swap,
253 .param_count = 2,253 .param_count = 1,
254 },254 },
255 },255 },
256 .{256 .{
257 "@bitReverse",257 "@bitReverse",
258 .{258 .{
259 .tag = .bit_reverse,259 .tag = .bit_reverse,
260 .param_count = 2,260 .param_count = 1,
261 },261 },
262 },262 },
263 .{263 .{
...@@ -301,7 +301,7 @@ pub const list = list: {...@@ -301,7 +301,7 @@ pub const list = list: {
301 "@clz",301 "@clz",
302 .{302 .{
303 .tag = .clz,303 .tag = .clz,
304 .param_count = 2,304 .param_count = 1,
305 },305 },
306 },306 },
307 .{307 .{
...@@ -336,7 +336,7 @@ pub const list = list: {...@@ -336,7 +336,7 @@ pub const list = list: {
336 "@ctz",336 "@ctz",
337 .{337 .{
338 .tag = .ctz,338 .tag = .ctz,
339 .param_count = 2,339 .param_count = 1,
340 },340 },
341 },341 },
342 .{342 .{
...@@ -614,7 +614,7 @@ pub const list = list: {...@@ -614,7 +614,7 @@ pub const list = list: {
614 "@popCount",614 "@popCount",
615 .{615 .{
616 .tag = .pop_count,616 .tag = .pop_count,
617 .param_count = 2,617 .param_count = 1,
618 },618 },
619 },619 },
620 .{620 .{
src/Compilation.zig+151-114
...@@ -173,6 +173,7 @@ astgen_wait_group: WaitGroup = .{},...@@ -173,6 +173,7 @@ astgen_wait_group: WaitGroup = .{},
173/// TODO: Remove this when Stage2 becomes the default compiler as it will already have this information.173/// TODO: Remove this when Stage2 becomes the default compiler as it will already have this information.
174export_symbol_names: std.ArrayListUnmanaged([]const u8) = .{},174export_symbol_names: std.ArrayListUnmanaged([]const u8) = .{},
175175
176pub const default_stack_protector_buffer_size = 4;
176pub const SemaError = Module.SemaError;177pub const SemaError = Module.SemaError;
177178
178pub const CRTFile = struct {179pub const CRTFile = struct {
...@@ -810,7 +811,6 @@ pub const InitOptions = struct {...@@ -810,7 +811,6 @@ pub const InitOptions = struct {
810 /// this flag would be set to disable this machinery to avoid false positives.811 /// this flag would be set to disable this machinery to avoid false positives.
811 disable_lld_caching: bool = false,812 disable_lld_caching: bool = false,
812 cache_mode: CacheMode = .incremental,813 cache_mode: CacheMode = .incremental,
813 object_format: ?std.Target.ObjectFormat = null,
814 optimize_mode: std.builtin.Mode = .Debug,814 optimize_mode: std.builtin.Mode = .Debug,
815 keep_source_files_loaded: bool = false,815 keep_source_files_loaded: bool = false,
816 clang_argv: []const []const u8 = &[0][]const u8{},816 clang_argv: []const []const u8 = &[0][]const u8{},
...@@ -838,6 +838,10 @@ pub const InitOptions = struct {...@@ -838,6 +838,10 @@ pub const InitOptions = struct {
838 want_pie: ?bool = null,838 want_pie: ?bool = null,
839 want_sanitize_c: ?bool = null,839 want_sanitize_c: ?bool = null,
840 want_stack_check: ?bool = null,840 want_stack_check: ?bool = null,
841 /// null means default.
842 /// 0 means no stack protector.
843 /// other number means stack protection with that buffer size.
844 want_stack_protector: ?u32 = null,
841 want_red_zone: ?bool = null,845 want_red_zone: ?bool = null,
842 omit_frame_pointer: ?bool = null,846 omit_frame_pointer: ?bool = null,
843 want_valgrind: ?bool = null,847 want_valgrind: ?bool = null,
...@@ -1015,6 +1019,15 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1015,6 +1019,15 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1015 return error.ExportTableAndImportTableConflict;1019 return error.ExportTableAndImportTableConflict;
1016 }1020 }
10171021
1022 // The `have_llvm` condition is here only because native backends cannot yet build compiler-rt.
1023 // Once they are capable this condition could be removed. When removing this condition,
1024 // also test the use case of `build-obj -fcompiler-rt` with the native backends
1025 // and make sure the compiler-rt symbols are emitted.
1026 const capable_of_building_compiler_rt = build_options.have_llvm;
1027
1028 const capable_of_building_zig_libc = build_options.have_llvm;
1029 const capable_of_building_ssp = build_options.have_llvm;
1030
1018 const comp: *Compilation = comp: {1031 const comp: *Compilation = comp: {
1019 // For allocations that have the same lifetime as Compilation. This arena is used only during this1032 // For allocations that have the same lifetime as Compilation. This arena is used only during this
1020 // initialization and then is freed in deinit().1033 // initialization and then is freed in deinit().
...@@ -1027,22 +1040,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1027,22 +1040,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1027 const comp = try arena.create(Compilation);1040 const comp = try arena.create(Compilation);
1028 const root_name = try arena.dupeZ(u8, options.root_name);1041 const root_name = try arena.dupeZ(u8, options.root_name);
10291042
1030 const ofmt = options.object_format orelse options.target.getObjectFormat();1043 const use_stage1 = options.use_stage1 orelse false;
1031
1032 const use_stage1 = options.use_stage1 orelse blk: {
1033 // Even though we may have no Zig code to compile (depending on `options.main_pkg`),
1034 // we may need to use stage1 for building compiler-rt and other dependencies.
1035
1036 if (build_options.omit_stage2)
1037 break :blk true;
1038 if (options.use_llvm) |use_llvm| {
1039 if (!use_llvm) {
1040 break :blk false;
1041 }
1042 }
1043
1044 break :blk build_options.is_stage1;
1045 };
10461044
1047 const cache_mode = if (use_stage1 and !options.disable_lld_caching)1045 const cache_mode = if (use_stage1 and !options.disable_lld_caching)
1048 CacheMode.whole1046 CacheMode.whole
...@@ -1068,7 +1066,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1068,7 +1066,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1068 break :blk true;1066 break :blk true;
10691067
1070 // If LLVM does not support the target, then we can't use it.1068 // If LLVM does not support the target, then we can't use it.
1071 if (!target_util.hasLlvmSupport(options.target, ofmt))1069 if (!target_util.hasLlvmSupport(options.target, options.target.ofmt))
1072 break :blk false;1070 break :blk false;
10731071
1074 // Prefer LLVM for release builds.1072 // Prefer LLVM for release builds.
...@@ -1111,7 +1109,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1111,7 +1109,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1111 if (!build_options.have_llvm)1109 if (!build_options.have_llvm)
1112 break :blk false;1110 break :blk false;
11131111
1114 if (ofmt == .c)1112 if (options.target.ofmt == .c)
1115 break :blk false;1113 break :blk false;
11161114
1117 if (options.want_lto) |lto| {1115 if (options.want_lto) |lto| {
...@@ -1167,9 +1165,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1167,9 +1165,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1167 break :blk false;1165 break :blk false;
1168 } else if (options.c_source_files.len == 0) {1166 } else if (options.c_source_files.len == 0) {
1169 break :blk false;1167 break :blk false;
1170 } else if (options.target.os.tag == .windows and link_libcpp) {
1171 // https://github.com/ziglang/zig/issues/8531
1172 break :blk false;
1173 } else if (options.target.cpu.arch.isRISCV()) {1168 } else if (options.target.cpu.arch.isRISCV()) {
1174 // Clang and LLVM currently don't support RISC-V target-abi for LTO.1169 // Clang and LLVM currently don't support RISC-V target-abi for LTO.
1175 // Compiling with LTO may fail or produce undesired results.1170 // Compiling with LTO may fail or produce undesired results.
...@@ -1233,7 +1228,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1233,7 +1228,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1233 break :blk lm;1228 break :blk lm;
1234 } else default_link_mode;1229 } else default_link_mode;
12351230
1236 const dll_export_fns = if (options.dll_export_fns) |explicit| explicit else is_dyn_lib or options.rdynamic;1231 const dll_export_fns = options.dll_export_fns orelse (is_dyn_lib or options.rdynamic);
12371232
1238 const libc_dirs = try detectLibCIncludeDirs(1233 const libc_dirs = try detectLibCIncludeDirs(
1239 arena,1234 arena,
...@@ -1288,11 +1283,36 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1288,11 +1283,36 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
12881283
1289 const sanitize_c = options.want_sanitize_c orelse is_safe_mode;1284 const sanitize_c = options.want_sanitize_c orelse is_safe_mode;
12901285
1291 const stack_check: bool = b: {1286 const stack_check: bool = options.want_stack_check orelse b: {
1292 if (!target_util.supportsStackProbing(options.target))1287 if (!target_util.supportsStackProbing(options.target)) break :b false;
1293 break :b false;1288 break :b is_safe_mode;
1294 break :b options.want_stack_check orelse is_safe_mode;1289 };
1290 if (stack_check and !target_util.supportsStackProbing(options.target))
1291 return error.StackCheckUnsupportedByTarget;
1292
1293 const stack_protector: u32 = options.want_stack_protector orelse b: {
1294 if (!target_util.supportsStackProtector(options.target)) break :b @as(u32, 0);
1295
1296 // This logic is checking for linking libc because otherwise our start code
1297 // which is trying to set up TLS (i.e. the fs/gs registers) but the stack
1298 // protection code depends on fs/gs registers being already set up.
1299 // If we were able to annotate start code, or perhaps the entire std lib,
1300 // as being exempt from stack protection checks, we could change this logic
1301 // to supporting stack protection even when not linking libc.
1302 // TODO file issue about this
1303 if (!link_libc) break :b 0;
1304 if (!capable_of_building_ssp) break :b 0;
1305 if (is_safe_mode) break :b default_stack_protector_buffer_size;
1306 break :b 0;
1295 };1307 };
1308 if (stack_protector != 0) {
1309 if (!target_util.supportsStackProtector(options.target))
1310 return error.StackProtectorUnsupportedByTarget;
1311 if (!capable_of_building_ssp)
1312 return error.StackProtectorUnsupportedByBackend;
1313 if (!link_libc)
1314 return error.StackProtectorUnavailableWithoutLibC;
1315 }
12961316
1297 const valgrind: bool = b: {1317 const valgrind: bool = b: {
1298 if (!target_util.hasValgrindSupport(options.target))1318 if (!target_util.hasValgrindSupport(options.target))
...@@ -1370,13 +1390,14 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1370,13 +1390,14 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1370 cache.hash.add(options.target.os.getVersionRange());1390 cache.hash.add(options.target.os.getVersionRange());
1371 cache.hash.add(options.is_native_os);1391 cache.hash.add(options.is_native_os);
1372 cache.hash.add(options.target.abi);1392 cache.hash.add(options.target.abi);
1373 cache.hash.add(ofmt);1393 cache.hash.add(options.target.ofmt);
1374 cache.hash.add(pic);1394 cache.hash.add(pic);
1375 cache.hash.add(pie);1395 cache.hash.add(pie);
1376 cache.hash.add(lto);1396 cache.hash.add(lto);
1377 cache.hash.add(unwind_tables);1397 cache.hash.add(unwind_tables);
1378 cache.hash.add(tsan);1398 cache.hash.add(tsan);
1379 cache.hash.add(stack_check);1399 cache.hash.add(stack_check);
1400 cache.hash.add(stack_protector);
1380 cache.hash.add(red_zone);1401 cache.hash.add(red_zone);
1381 cache.hash.add(omit_frame_pointer);1402 cache.hash.add(omit_frame_pointer);
1382 cache.hash.add(link_mode);1403 cache.hash.add(link_mode);
...@@ -1678,7 +1699,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1678,7 +1699,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1678 .sysroot = sysroot,1699 .sysroot = sysroot,
1679 .output_mode = options.output_mode,1700 .output_mode = options.output_mode,
1680 .link_mode = link_mode,1701 .link_mode = link_mode,
1681 .object_format = ofmt,
1682 .optimize_mode = options.optimize_mode,1702 .optimize_mode = options.optimize_mode,
1683 .use_lld = use_lld,1703 .use_lld = use_lld,
1684 .use_llvm = use_llvm,1704 .use_llvm = use_llvm,
...@@ -1741,6 +1761,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1741,6 +1761,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1741 .valgrind = valgrind,1761 .valgrind = valgrind,
1742 .tsan = tsan,1762 .tsan = tsan,
1743 .stack_check = stack_check,1763 .stack_check = stack_check,
1764 .stack_protector = stack_protector,
1744 .red_zone = red_zone,1765 .red_zone = red_zone,
1745 .omit_frame_pointer = omit_frame_pointer,1766 .omit_frame_pointer = omit_frame_pointer,
1746 .single_threaded = single_threaded,1767 .single_threaded = single_threaded,
...@@ -1769,6 +1790,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1769,6 +1790,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1769 .headerpad_size = options.headerpad_size,1790 .headerpad_size = options.headerpad_size,
1770 .headerpad_max_install_names = options.headerpad_max_install_names,1791 .headerpad_max_install_names = options.headerpad_max_install_names,
1771 .dead_strip_dylibs = options.dead_strip_dylibs,1792 .dead_strip_dylibs = options.dead_strip_dylibs,
1793 .force_undefined_symbols = .{},
1772 });1794 });
1773 errdefer bin_file.destroy();1795 errdefer bin_file.destroy();
1774 comp.* = .{1796 comp.* = .{
...@@ -1822,6 +1844,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1822,6 +1844,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1822 };1844 };
1823 errdefer comp.destroy();1845 errdefer comp.destroy();
18241846
1847 const target = comp.getTarget();
1848
1825 // Add a `CObject` for each `c_source_files`.1849 // Add a `CObject` for each `c_source_files`.
1826 try comp.c_object_table.ensureTotalCapacity(gpa, options.c_source_files.len);1850 try comp.c_object_table.ensureTotalCapacity(gpa, options.c_source_files.len);
1827 for (options.c_source_files) |c_source_file| {1851 for (options.c_source_files) |c_source_file| {
...@@ -1837,9 +1861,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1837,9 +1861,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
18371861
1838 const have_bin_emit = comp.bin_file.options.emit != null or comp.whole_bin_sub_path != null;1862 const have_bin_emit = comp.bin_file.options.emit != null or comp.whole_bin_sub_path != null;
18391863
1840 if (have_bin_emit and !comp.bin_file.options.skip_linker_dependencies) {1864 if (have_bin_emit and !comp.bin_file.options.skip_linker_dependencies and target.ofmt != .c) {
1841 if (comp.getTarget().isDarwin()) {1865 if (target.isDarwin()) {
1842 switch (comp.getTarget().abi) {1866 switch (target.abi) {
1843 .none,1867 .none,
1844 .simulator,1868 .simulator,
1845 .macabi,1869 .macabi,
...@@ -1850,9 +1874,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1850,9 +1874,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1850 // If we need to build glibc for the target, add work items for it.1874 // If we need to build glibc for the target, add work items for it.
1851 // We go through the work queue so that building can be done in parallel.1875 // We go through the work queue so that building can be done in parallel.
1852 if (comp.wantBuildGLibCFromSource()) {1876 if (comp.wantBuildGLibCFromSource()) {
1853 if (!target_util.canBuildLibC(comp.getTarget())) return error.LibCUnavailable;1877 if (!target_util.canBuildLibC(target)) return error.LibCUnavailable;
18541878
1855 if (glibc.needsCrtiCrtn(comp.getTarget())) {1879 if (glibc.needsCrtiCrtn(target)) {
1856 try comp.work_queue.write(&[_]Job{1880 try comp.work_queue.write(&[_]Job{
1857 .{ .glibc_crt_file = .crti_o },1881 .{ .glibc_crt_file = .crti_o },
1858 .{ .glibc_crt_file = .crtn_o },1882 .{ .glibc_crt_file = .crtn_o },
...@@ -1865,10 +1889,10 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1865,10 +1889,10 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1865 });1889 });
1866 }1890 }
1867 if (comp.wantBuildMuslFromSource()) {1891 if (comp.wantBuildMuslFromSource()) {
1868 if (!target_util.canBuildLibC(comp.getTarget())) return error.LibCUnavailable;1892 if (!target_util.canBuildLibC(target)) return error.LibCUnavailable;
18691893
1870 try comp.work_queue.ensureUnusedCapacity(6);1894 try comp.work_queue.ensureUnusedCapacity(6);
1871 if (musl.needsCrtiCrtn(comp.getTarget())) {1895 if (musl.needsCrtiCrtn(target)) {
1872 comp.work_queue.writeAssumeCapacity(&[_]Job{1896 comp.work_queue.writeAssumeCapacity(&[_]Job{
1873 .{ .musl_crt_file = .crti_o },1897 .{ .musl_crt_file = .crti_o },
1874 .{ .musl_crt_file = .crtn_o },1898 .{ .musl_crt_file = .crtn_o },
...@@ -1885,7 +1909,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1885,7 +1909,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1885 });1909 });
1886 }1910 }
1887 if (comp.wantBuildWasiLibcFromSource()) {1911 if (comp.wantBuildWasiLibcFromSource()) {
1888 if (!target_util.canBuildLibC(comp.getTarget())) return error.LibCUnavailable;1912 if (!target_util.canBuildLibC(target)) return error.LibCUnavailable;
18891913
1890 const wasi_emulated_libs = comp.bin_file.options.wasi_emulated_libs;1914 const wasi_emulated_libs = comp.bin_file.options.wasi_emulated_libs;
1891 try comp.work_queue.ensureUnusedCapacity(wasi_emulated_libs.len + 2); // worst-case we need all components1915 try comp.work_queue.ensureUnusedCapacity(wasi_emulated_libs.len + 2); // worst-case we need all components
...@@ -1900,7 +1924,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1900,7 +1924,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1900 });1924 });
1901 }1925 }
1902 if (comp.wantBuildMinGWFromSource()) {1926 if (comp.wantBuildMinGWFromSource()) {
1903 if (!target_util.canBuildLibC(comp.getTarget())) return error.LibCUnavailable;1927 if (!target_util.canBuildLibC(target)) return error.LibCUnavailable;
19041928
1905 const static_lib_jobs = [_]Job{1929 const static_lib_jobs = [_]Job{
1906 .{ .mingw_crt_file = .mingw32_lib },1930 .{ .mingw_crt_file = .mingw32_lib },
...@@ -1917,9 +1941,13 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1917,9 +1941,13 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1917 for (mingw.always_link_libs) |name| {1941 for (mingw.always_link_libs) |name| {
1918 try comp.bin_file.options.system_libs.put(comp.gpa, name, .{});1942 try comp.bin_file.options.system_libs.put(comp.gpa, name, .{});
1919 }1943 }
1944
1945 // LLD might drop some symbols as unused during LTO and GCing, therefore,
1946 // we force mark them for resolution here.
1947 try comp.bin_file.options.force_undefined_symbols.put(comp.gpa, "_tls_index", {});
1920 }1948 }
1921 // Generate Windows import libs.1949 // Generate Windows import libs.
1922 if (comp.getTarget().os.tag == .windows) {1950 if (target.os.tag == .windows) {
1923 const count = comp.bin_file.options.system_libs.count();1951 const count = comp.bin_file.options.system_libs.count();
1924 try comp.work_queue.ensureUnusedCapacity(count);1952 try comp.work_queue.ensureUnusedCapacity(count);
1925 var i: usize = 0;1953 var i: usize = 0;
...@@ -1938,15 +1966,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1938,15 +1966,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1938 try comp.work_queue.writeItem(.libtsan);1966 try comp.work_queue.writeItem(.libtsan);
1939 }1967 }
19401968
1941 // The `have_llvm` condition is here only because native backends cannot yet build compiler-rt.
1942 // Once they are capable this condition could be removed. When removing this condition,
1943 // also test the use case of `build-obj -fcompiler-rt` with the native backends
1944 // and make sure the compiler-rt symbols are emitted.
1945 const capable_of_building_compiler_rt = build_options.have_llvm;
1946
1947 const capable_of_building_zig_libc = build_options.have_llvm;
1948 const capable_of_building_ssp = comp.bin_file.options.use_stage1;
1949
1950 if (comp.bin_file.options.include_compiler_rt and capable_of_building_compiler_rt) {1969 if (comp.bin_file.options.include_compiler_rt and capable_of_building_compiler_rt) {
1951 if (is_exe_or_dyn_lib) {1970 if (is_exe_or_dyn_lib) {
1952 log.debug("queuing a job to build compiler_rt_lib", .{});1971 log.debug("queuing a job to build compiler_rt_lib", .{});
...@@ -1960,8 +1979,11 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1960,8 +1979,11 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1960 }1979 }
1961 }1980 }
1962 if (needs_c_symbols) {1981 if (needs_c_symbols) {
1963 // MinGW provides no libssp, use our own implementation.1982 // Related: https://github.com/ziglang/zig/issues/7265.
1964 if (comp.getTarget().isMinGW() and capable_of_building_ssp) {1983 if (comp.bin_file.options.stack_protector != 0 and
1984 (!comp.bin_file.options.link_libc or
1985 !target_util.libcProvidesStackProtector(target)))
1986 {
1965 try comp.work_queue.writeItem(.{ .libssp = {} });1987 try comp.work_queue.writeItem(.{ .libssp = {} });
1966 }1988 }
19671989
...@@ -2176,8 +2198,7 @@ pub fn update(comp: *Compilation) !void {...@@ -2176,8 +2198,7 @@ pub fn update(comp: *Compilation) !void {
2176 comp.c_object_work_queue.writeItemAssumeCapacity(key);2198 comp.c_object_work_queue.writeItemAssumeCapacity(key);
2177 }2199 }
21782200
2179 const use_stage1 = build_options.omit_stage2 or2201 const use_stage1 = build_options.have_stage1 and comp.bin_file.options.use_stage1;
2180 (build_options.is_stage1 and comp.bin_file.options.use_stage1);
2181 if (comp.bin_file.options.module) |module| {2202 if (comp.bin_file.options.module) |module| {
2182 module.compile_log_text.shrinkAndFree(module.gpa, 0);2203 module.compile_log_text.shrinkAndFree(module.gpa, 0);
2183 module.generation += 1;2204 module.generation += 1;
...@@ -2353,8 +2374,7 @@ fn flush(comp: *Compilation, prog_node: *std.Progress.Node) !void {...@@ -2353,8 +2374,7 @@ fn flush(comp: *Compilation, prog_node: *std.Progress.Node) !void {
2353 };2374 };
2354 comp.link_error_flags = comp.bin_file.errorFlags();2375 comp.link_error_flags = comp.bin_file.errorFlags();
23552376
2356 const use_stage1 = build_options.omit_stage2 or2377 const use_stage1 = build_options.have_stage1 and comp.bin_file.options.use_stage1;
2357 (build_options.is_stage1 and comp.bin_file.options.use_stage1);
2358 if (!use_stage1) {2378 if (!use_stage1) {
2359 if (comp.bin_file.options.module) |module| {2379 if (comp.bin_file.options.module) |module| {
2360 try link.File.C.flushEmitH(module);2380 try link.File.C.flushEmitH(module);
...@@ -2812,7 +2832,7 @@ pub fn performAllTheWork(...@@ -2812,7 +2832,7 @@ pub fn performAllTheWork(
2812 comp.work_queue_wait_group.reset();2832 comp.work_queue_wait_group.reset();
2813 defer comp.work_queue_wait_group.wait();2833 defer comp.work_queue_wait_group.wait();
28142834
2815 const use_stage1 = build_options.is_stage1 and comp.bin_file.options.use_stage1;2835 const use_stage1 = build_options.have_stage1 and comp.bin_file.options.use_stage1;
28162836
2817 {2837 {
2818 const astgen_frame = tracy.namedFrame("astgen");2838 const astgen_frame = tracy.namedFrame("astgen");
...@@ -2915,9 +2935,6 @@ pub fn performAllTheWork(...@@ -2915,9 +2935,6 @@ pub fn performAllTheWork(
2915fn processOneJob(comp: *Compilation, job: Job) !void {2935fn processOneJob(comp: *Compilation, job: Job) !void {
2916 switch (job) {2936 switch (job) {
2917 .codegen_decl => |decl_index| {2937 .codegen_decl => |decl_index| {
2918 if (build_options.omit_stage2)
2919 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
2920
2921 const module = comp.bin_file.options.module.?;2938 const module = comp.bin_file.options.module.?;
2922 const decl = module.declPtr(decl_index);2939 const decl = module.declPtr(decl_index);
29232940
...@@ -2952,9 +2969,6 @@ fn processOneJob(comp: *Compilation, job: Job) !void {...@@ -2952,9 +2969,6 @@ fn processOneJob(comp: *Compilation, job: Job) !void {
2952 }2969 }
2953 },2970 },
2954 .codegen_func => |func| {2971 .codegen_func => |func| {
2955 if (build_options.omit_stage2)
2956 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
2957
2958 const named_frame = tracy.namedFrame("codegen_func");2972 const named_frame = tracy.namedFrame("codegen_func");
2959 defer named_frame.end();2973 defer named_frame.end();
29602974
...@@ -2965,9 +2979,6 @@ fn processOneJob(comp: *Compilation, job: Job) !void {...@@ -2965,9 +2979,6 @@ fn processOneJob(comp: *Compilation, job: Job) !void {
2965 };2979 };
2966 },2980 },
2967 .emit_h_decl => |decl_index| {2981 .emit_h_decl => |decl_index| {
2968 if (build_options.omit_stage2)
2969 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
2970
2971 const module = comp.bin_file.options.module.?;2982 const module = comp.bin_file.options.module.?;
2972 const decl = module.declPtr(decl_index);2983 const decl = module.declPtr(decl_index);
29732984
...@@ -3026,9 +3037,6 @@ fn processOneJob(comp: *Compilation, job: Job) !void {...@@ -3026,9 +3037,6 @@ fn processOneJob(comp: *Compilation, job: Job) !void {
3026 }3037 }
3027 },3038 },
3028 .analyze_decl => |decl_index| {3039 .analyze_decl => |decl_index| {
3029 if (build_options.omit_stage2)
3030 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
3031
3032 const module = comp.bin_file.options.module.?;3040 const module = comp.bin_file.options.module.?;
3033 module.ensureDeclAnalyzed(decl_index) catch |err| switch (err) {3041 module.ensureDeclAnalyzed(decl_index) catch |err| switch (err) {
3034 error.OutOfMemory => return error.OutOfMemory,3042 error.OutOfMemory => return error.OutOfMemory,
...@@ -3036,9 +3044,6 @@ fn processOneJob(comp: *Compilation, job: Job) !void {...@@ -3036,9 +3044,6 @@ fn processOneJob(comp: *Compilation, job: Job) !void {
3036 };3044 };
3037 },3045 },
3038 .update_embed_file => |embed_file| {3046 .update_embed_file => |embed_file| {
3039 if (build_options.omit_stage2)
3040 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
3041
3042 const named_frame = tracy.namedFrame("update_embed_file");3047 const named_frame = tracy.namedFrame("update_embed_file");
3043 defer named_frame.end();3048 defer named_frame.end();
30443049
...@@ -3049,9 +3054,6 @@ fn processOneJob(comp: *Compilation, job: Job) !void {...@@ -3049,9 +3054,6 @@ fn processOneJob(comp: *Compilation, job: Job) !void {
3049 };3054 };
3050 },3055 },
3051 .update_line_number => |decl_index| {3056 .update_line_number => |decl_index| {
3052 if (build_options.omit_stage2)
3053 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
3054
3055 const named_frame = tracy.namedFrame("update_line_number");3057 const named_frame = tracy.namedFrame("update_line_number");
3056 defer named_frame.end();3058 defer named_frame.end();
30573059
...@@ -3070,9 +3072,6 @@ fn processOneJob(comp: *Compilation, job: Job) !void {...@@ -3070,9 +3072,6 @@ fn processOneJob(comp: *Compilation, job: Job) !void {
3070 };3072 };
3071 },3073 },
3072 .analyze_pkg => |pkg| {3074 .analyze_pkg => |pkg| {
3073 if (build_options.omit_stage2)
3074 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
3075
3076 const named_frame = tracy.namedFrame("analyze_pkg");3075 const named_frame = tracy.namedFrame("analyze_pkg");
3077 defer named_frame.end();3076 defer named_frame.end();
30783077
...@@ -3418,7 +3417,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult {...@@ -3418,7 +3417,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult {
3418 var man = comp.obtainCObjectCacheManifest();3417 var man = comp.obtainCObjectCacheManifest();
3419 defer man.deinit();3418 defer man.deinit();
34203419
3421 const use_stage1 = build_options.is_stage1 and comp.bin_file.options.use_stage1;3420 const use_stage1 = build_options.have_stage1 and comp.bin_file.options.use_stage1;
34223421
3423 man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects3422 man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects
3424 man.hash.add(use_stage1);3423 man.hash.add(use_stage1);
...@@ -3735,7 +3734,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P...@@ -3735,7 +3734,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
3735 else3734 else
3736 c_source_basename[0 .. c_source_basename.len - std.fs.path.extension(c_source_basename).len];3735 c_source_basename[0 .. c_source_basename.len - std.fs.path.extension(c_source_basename).len];
37373736
3738 const o_ext = comp.bin_file.options.object_format.fileExt(comp.bin_file.options.target.cpu.arch);3737 const target = comp.getTarget();
3738 const o_ext = target.ofmt.fileExt(target.cpu.arch);
3739 const digest = if (!comp.disable_c_depfile and try man.hit()) man.final() else blk: {3739 const digest = if (!comp.disable_c_depfile and try man.hit()) man.final() else blk: {
3740 var argv = std.ArrayList([]const u8).init(comp.gpa);3740 var argv = std.ArrayList([]const u8).init(comp.gpa);
3741 defer argv.deinit();3741 defer argv.deinit();
...@@ -3755,22 +3755,67 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P...@@ -3755,22 +3755,67 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
3755 };3755 };
3756 const o_basename = try std.fmt.allocPrint(arena, "{s}{s}", .{ o_basename_noext, out_ext });3756 const o_basename = try std.fmt.allocPrint(arena, "{s}{s}", .{ o_basename_noext, out_ext });
37573757
3758 try argv.appendSlice(&[_][]const u8{
3759 self_exe_path,
3760 "clang",
3761 c_object.src.src_path,
3762 });
3763
3764 const ext = classifyFileExt(c_object.src.src_path);
3765
3766 // When all these flags are true, it means that the entire purpose of
3767 // this compilation is to perform a single zig cc operation. This means
3768 // that we could "tail call" clang by doing an execve, and any use of
3769 // the caching system would actually be problematic since the user is
3770 // presumably doing their own caching by using dep file flags.
3771 if (std.process.can_execv and direct_o and
3772 comp.disable_c_depfile and comp.clang_passthrough_mode)
3773 {
3774 try comp.addCCArgs(arena, &argv, ext, null);
3775 try argv.appendSlice(c_object.src.extra_flags);
3776
3777 const out_obj_path = if (comp.bin_file.options.emit) |emit|
3778 try emit.directory.join(arena, &.{emit.sub_path})
3779 else
3780 "/dev/null";
3781
3782 try argv.ensureUnusedCapacity(5);
3783 switch (comp.clang_preprocessor_mode) {
3784 .no => argv.appendSliceAssumeCapacity(&[_][]const u8{ "-c", "-o", out_obj_path }),
3785 .yes => argv.appendSliceAssumeCapacity(&[_][]const u8{ "-E", "-o", out_obj_path }),
3786 .stdout => argv.appendAssumeCapacity("-E"),
3787 }
3788
3789 if (comp.emit_asm != null) {
3790 argv.appendAssumeCapacity("-S");
3791 } else if (comp.emit_llvm_ir != null) {
3792 argv.appendSliceAssumeCapacity(&[_][]const u8{ "-emit-llvm", "-S" });
3793 } else if (comp.emit_llvm_bc != null) {
3794 argv.appendAssumeCapacity("-emit-llvm");
3795 }
3796
3797 if (comp.verbose_cc) {
3798 dump_argv(argv.items);
3799 }
3800
3801 const err = std.process.execv(arena, argv.items);
3802 fatal("unable to execv clang: {s}", .{@errorName(err)});
3803 }
3804
3758 // We can't know the digest until we do the C compiler invocation,3805 // We can't know the digest until we do the C compiler invocation,
3759 // so we need a temporary filename.3806 // so we need a temporary filename.
3760 const out_obj_path = try comp.tmpFilePath(arena, o_basename);3807 const out_obj_path = try comp.tmpFilePath(arena, o_basename);
3761 var zig_cache_tmp_dir = try comp.local_cache_directory.handle.makeOpenPath("tmp", .{});3808 var zig_cache_tmp_dir = try comp.local_cache_directory.handle.makeOpenPath("tmp", .{});
3762 defer zig_cache_tmp_dir.close();3809 defer zig_cache_tmp_dir.close();
37633810
3764 try argv.appendSlice(&[_][]const u8{ self_exe_path, "clang" });
3765
3766 const ext = classifyFileExt(c_object.src.src_path);
3767 const out_dep_path: ?[]const u8 = if (comp.disable_c_depfile or !ext.clangSupportsDepFile())3811 const out_dep_path: ?[]const u8 = if (comp.disable_c_depfile or !ext.clangSupportsDepFile())
3768 null3812 null
3769 else3813 else
3770 try std.fmt.allocPrint(arena, "{s}.d", .{out_obj_path});3814 try std.fmt.allocPrint(arena, "{s}.d", .{out_obj_path});
3771 try comp.addCCArgs(arena, &argv, ext, out_dep_path);3815 try comp.addCCArgs(arena, &argv, ext, out_dep_path);
3816 try argv.appendSlice(c_object.src.extra_flags);
37723817
3773 try argv.ensureUnusedCapacity(6 + c_object.src.extra_flags.len);3818 try argv.ensureUnusedCapacity(5);
3774 switch (comp.clang_preprocessor_mode) {3819 switch (comp.clang_preprocessor_mode) {
3775 .no => argv.appendSliceAssumeCapacity(&[_][]const u8{ "-c", "-o", out_obj_path }),3820 .no => argv.appendSliceAssumeCapacity(&[_][]const u8{ "-c", "-o", out_obj_path }),
3776 .yes => argv.appendSliceAssumeCapacity(&[_][]const u8{ "-E", "-o", out_obj_path }),3821 .yes => argv.appendSliceAssumeCapacity(&[_][]const u8{ "-E", "-o", out_obj_path }),
...@@ -3785,8 +3830,6 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P...@@ -3785,8 +3830,6 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
3785 argv.appendAssumeCapacity("-emit-llvm");3830 argv.appendAssumeCapacity("-emit-llvm");
3786 }3831 }
3787 }3832 }
3788 argv.appendAssumeCapacity(c_object.src.src_path);
3789 argv.appendSliceAssumeCapacity(c_object.src.extra_flags);
37903833
3791 if (comp.verbose_cc) {3834 if (comp.verbose_cc) {
3792 dump_argv(argv.items);3835 dump_argv(argv.items);
...@@ -4087,10 +4130,10 @@ pub fn addCCArgs(...@@ -4087,10 +4130,10 @@ pub fn addCCArgs(
4087 }4130 }
40884131
4089 if (!comp.bin_file.options.strip) {4132 if (!comp.bin_file.options.strip) {
4090 try argv.append("-g");4133 switch (target.ofmt) {
4091 switch (comp.bin_file.options.object_format) {
4092 .coff => try argv.append("-gcodeview"),4134 .coff => try argv.append("-gcodeview"),
4093 else => {},4135 .elf, .macho => try argv.append("-gdwarf-4"),
4136 else => try argv.append("-g"),
4094 }4137 }
4095 }4138 }
40964139
...@@ -4120,6 +4163,17 @@ pub fn addCCArgs(...@@ -4120,6 +4163,17 @@ pub fn addCCArgs(
4120 try argv.append("-fno-omit-frame-pointer");4163 try argv.append("-fno-omit-frame-pointer");
4121 }4164 }
41224165
4166 const ssp_buf_size = comp.bin_file.options.stack_protector;
4167 if (ssp_buf_size != 0) {
4168 try argv.appendSlice(&[_][]const u8{
4169 "-fstack-protector-strong",
4170 "--param",
4171 try std.fmt.allocPrint(arena, "ssp-buffer-size={d}", .{ssp_buf_size}),
4172 });
4173 } else {
4174 try argv.append("-fno-stack-protector");
4175 }
4176
4123 switch (comp.bin_file.options.optimize_mode) {4177 switch (comp.bin_file.options.optimize_mode) {
4124 .Debug => {4178 .Debug => {
4125 // windows c runtime requires -D_DEBUG if using debug libraries4179 // windows c runtime requires -D_DEBUG if using debug libraries
...@@ -4128,27 +4182,12 @@ pub fn addCCArgs(...@@ -4128,27 +4182,12 @@ pub fn addCCArgs(
4128 // to -O1. Besides potentially impairing debugging, -O1/-Og significantly4182 // to -O1. Besides potentially impairing debugging, -O1/-Og significantly
4129 // increases compile times.4183 // increases compile times.
4130 try argv.append("-O0");4184 try argv.append("-O0");
4131
4132 if (comp.bin_file.options.link_libc and target.os.tag != .wasi) {
4133 try argv.append("-fstack-protector-strong");
4134 try argv.append("--param");
4135 try argv.append("ssp-buffer-size=4");
4136 } else {
4137 try argv.append("-fno-stack-protector");
4138 }
4139 },4185 },
4140 .ReleaseSafe => {4186 .ReleaseSafe => {
4141 // See the comment in the BuildModeFastRelease case for why we pass -O2 rather4187 // See the comment in the BuildModeFastRelease case for why we pass -O2 rather
4142 // than -O3 here.4188 // than -O3 here.
4143 try argv.append("-O2");4189 try argv.append("-O2");
4144 if (comp.bin_file.options.link_libc and target.os.tag != .wasi) {4190 try argv.append("-D_FORTIFY_SOURCE=2");
4145 try argv.append("-D_FORTIFY_SOURCE=2");
4146 try argv.append("-fstack-protector-strong");
4147 try argv.append("--param");
4148 try argv.append("ssp-buffer-size=4");
4149 } else {
4150 try argv.append("-fno-stack-protector");
4151 }
4152 },4191 },
4153 .ReleaseFast => {4192 .ReleaseFast => {
4154 try argv.append("-DNDEBUG");4193 try argv.append("-DNDEBUG");
...@@ -4158,12 +4197,10 @@ pub fn addCCArgs(...@@ -4158,12 +4197,10 @@ pub fn addCCArgs(
4158 // Zig code than it is for C code. Also, C programmers are used to their code4197 // Zig code than it is for C code. Also, C programmers are used to their code
4159 // running in -O2 and thus the -O3 path has been tested less.4198 // running in -O2 and thus the -O3 path has been tested less.
4160 try argv.append("-O2");4199 try argv.append("-O2");
4161 try argv.append("-fno-stack-protector");
4162 },4200 },
4163 .ReleaseSmall => {4201 .ReleaseSmall => {
4164 try argv.append("-DNDEBUG");4202 try argv.append("-DNDEBUG");
4165 try argv.append("-Os");4203 try argv.append("-Os");
4166 try argv.append("-fno-stack-protector");
4167 },4204 },
4168 }4205 }
41694206
...@@ -4656,7 +4693,7 @@ fn wantBuildLibCFromSource(comp: Compilation) bool {...@@ -4656,7 +4693,7 @@ fn wantBuildLibCFromSource(comp: Compilation) bool {
4656 };4693 };
4657 return comp.bin_file.options.link_libc and is_exe_or_dyn_lib and4694 return comp.bin_file.options.link_libc and is_exe_or_dyn_lib and
4658 comp.bin_file.options.libc_installation == null and4695 comp.bin_file.options.libc_installation == null and
4659 comp.bin_file.options.object_format != .c;4696 comp.bin_file.options.target.ofmt != .c;
4660}4697}
46614698
4662fn wantBuildGLibCFromSource(comp: Compilation) bool {4699fn wantBuildGLibCFromSource(comp: Compilation) bool {
...@@ -4684,7 +4721,7 @@ fn wantBuildLibUnwindFromSource(comp: *Compilation) bool {...@@ -4684,7 +4721,7 @@ fn wantBuildLibUnwindFromSource(comp: *Compilation) bool {
4684 .Exe => true,4721 .Exe => true,
4685 };4722 };
4686 return is_exe_or_dyn_lib and comp.bin_file.options.link_libunwind and4723 return is_exe_or_dyn_lib and comp.bin_file.options.link_libunwind and
4687 comp.bin_file.options.object_format != .c;4724 comp.bin_file.options.target.ofmt != .c;
4688}4725}
46894726
4690fn setAllocFailure(comp: *Compilation) void {4727fn setAllocFailure(comp: *Compilation) void {
...@@ -4738,12 +4775,12 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca...@@ -4738,12 +4775,12 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca
47384775
4739 const target = comp.getTarget();4776 const target = comp.getTarget();
4740 const generic_arch_name = target.cpu.arch.genericName();4777 const generic_arch_name = target.cpu.arch.genericName();
4741 const use_stage1 = build_options.is_stage1 and comp.bin_file.options.use_stage1;4778 const use_stage1 = build_options.have_stage1 and comp.bin_file.options.use_stage1;
47424779
4743 const zig_backend: std.builtin.CompilerBackend = blk: {4780 const zig_backend: std.builtin.CompilerBackend = blk: {
4744 if (use_stage1) break :blk .stage1;4781 if (use_stage1) break :blk .stage1;
4745 if (build_options.have_llvm and comp.bin_file.options.use_llvm) break :blk .stage2_llvm;4782 if (build_options.have_llvm and comp.bin_file.options.use_llvm) break :blk .stage2_llvm;
4746 if (comp.bin_file.options.object_format == .c) break :blk .stage2_c;4783 if (target.ofmt == .c) break :blk .stage2_c;
4747 break :blk switch (target.cpu.arch) {4784 break :blk switch (target.cpu.arch) {
4748 .wasm32, .wasm64 => std.builtin.CompilerBackend.stage2_wasm,4785 .wasm32, .wasm64 => std.builtin.CompilerBackend.stage2_wasm,
4749 .arm, .armeb, .thumb, .thumbeb => .stage2_arm,4786 .arm, .armeb, .thumb, .thumbeb => .stage2_arm,
...@@ -4763,8 +4800,6 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca...@@ -4763,8 +4800,6 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca
4763 \\/// feature detection (i.e. with `@hasDecl` or `@hasField`) over version checks.4800 \\/// feature detection (i.e. with `@hasDecl` or `@hasField`) over version checks.
4764 \\pub const zig_version = std.SemanticVersion.parse("{s}") catch unreachable;4801 \\pub const zig_version = std.SemanticVersion.parse("{s}") catch unreachable;
4765 \\pub const zig_backend = std.builtin.CompilerBackend.{};4802 \\pub const zig_backend = std.builtin.CompilerBackend.{};
4766 \\/// Temporary until self-hosted supports the `cpu.arch` value.
4767 \\pub const stage2_arch: std.Target.Cpu.Arch = .{};
4768 \\4803 \\
4769 \\pub const output_mode = std.builtin.OutputMode.{};4804 \\pub const output_mode = std.builtin.OutputMode.{};
4770 \\pub const link_mode = std.builtin.LinkMode.{};4805 \\pub const link_mode = std.builtin.LinkMode.{};
...@@ -4779,7 +4814,6 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca...@@ -4779,7 +4814,6 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca
4779 , .{4814 , .{
4780 build_options.version,4815 build_options.version,
4781 std.zig.fmtId(@tagName(zig_backend)),4816 std.zig.fmtId(@tagName(zig_backend)),
4782 std.zig.fmtId(@tagName(target.cpu.arch)),
4783 std.zig.fmtId(@tagName(comp.bin_file.options.output_mode)),4817 std.zig.fmtId(@tagName(comp.bin_file.options.output_mode)),
4784 std.zig.fmtId(@tagName(comp.bin_file.options.link_mode)),4818 std.zig.fmtId(@tagName(comp.bin_file.options.link_mode)),
4785 comp.bin_file.options.is_test,4819 comp.bin_file.options.is_test,
...@@ -4894,6 +4928,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca...@@ -4894,6 +4928,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca
4894 \\ .cpu = cpu,4928 \\ .cpu = cpu,
4895 \\ .os = os,4929 \\ .os = os,
4896 \\ .abi = abi,4930 \\ .abi = abi,
4931 \\ .ofmt = object_format,
4897 \\}};4932 \\}};
4898 \\pub const object_format = std.Target.ObjectFormat.{};4933 \\pub const object_format = std.Target.ObjectFormat.{};
4899 \\pub const mode = std.builtin.Mode.{};4934 \\pub const mode = std.builtin.Mode.{};
...@@ -4908,7 +4943,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca...@@ -4908,7 +4943,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca
4908 \\pub const code_model = std.builtin.CodeModel.{};4943 \\pub const code_model = std.builtin.CodeModel.{};
4909 \\4944 \\
4910 , .{4945 , .{
4911 std.zig.fmtId(@tagName(comp.bin_file.options.object_format)),4946 std.zig.fmtId(@tagName(target.ofmt)),
4912 std.zig.fmtId(@tagName(comp.bin_file.options.optimize_mode)),4947 std.zig.fmtId(@tagName(comp.bin_file.options.optimize_mode)),
4913 link_libc,4948 link_libc,
4914 comp.bin_file.options.link_libcpp,4949 comp.bin_file.options.link_libcpp,
...@@ -5027,9 +5062,10 @@ fn buildOutputFromZig(...@@ -5027,9 +5062,10 @@ fn buildOutputFromZig(
5027 .link_mode = .Static,5062 .link_mode = .Static,
5028 .function_sections = true,5063 .function_sections = true,
5029 .no_builtin = true,5064 .no_builtin = true,
5030 .use_stage1 = build_options.is_stage1 and comp.bin_file.options.use_stage1,5065 .use_stage1 = build_options.have_stage1 and comp.bin_file.options.use_stage1,
5031 .want_sanitize_c = false,5066 .want_sanitize_c = false,
5032 .want_stack_check = false,5067 .want_stack_check = false,
5068 .want_stack_protector = 0,
5033 .want_red_zone = comp.bin_file.options.red_zone,5069 .want_red_zone = comp.bin_file.options.red_zone,
5034 .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer,5070 .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer,
5035 .want_valgrind = false,5071 .want_valgrind = false,
...@@ -5310,6 +5346,7 @@ pub fn build_crt_file(...@@ -5310,6 +5346,7 @@ pub fn build_crt_file(
5310 .optimize_mode = comp.compilerRtOptMode(),5346 .optimize_mode = comp.compilerRtOptMode(),
5311 .want_sanitize_c = false,5347 .want_sanitize_c = false,
5312 .want_stack_check = false,5348 .want_stack_check = false,
5349 .want_stack_protector = 0,
5313 .want_red_zone = comp.bin_file.options.red_zone,5350 .want_red_zone = comp.bin_file.options.red_zone,
5314 .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer,5351 .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer,
5315 .want_valgrind = false,5352 .want_valgrind = false,
src/Liveness.zig+4
...@@ -267,6 +267,7 @@ pub fn categorizeOperand(...@@ -267,6 +267,7 @@ pub fn categorizeOperand(
267 .byte_swap,267 .byte_swap,
268 .bit_reverse,268 .bit_reverse,
269 .splat,269 .splat,
270 .error_set_has_value,
270 => {271 => {
271 const o = air_datas[inst].ty_op;272 const o = air_datas[inst].ty_op;
272 if (o.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);273 if (o.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
...@@ -291,6 +292,7 @@ pub fn categorizeOperand(...@@ -291,6 +292,7 @@ pub fn categorizeOperand(
291 .is_non_err_ptr,292 .is_non_err_ptr,
292 .ptrtoint,293 .ptrtoint,
293 .bool_to_int,294 .bool_to_int,
295 .is_named_enum_value,
294 .tag_name,296 .tag_name,
295 .error_name,297 .error_name,
296 .sqrt,298 .sqrt,
...@@ -841,6 +843,7 @@ fn analyzeInst(...@@ -841,6 +843,7 @@ fn analyzeInst(
841 .byte_swap,843 .byte_swap,
842 .bit_reverse,844 .bit_reverse,
843 .splat,845 .splat,
846 .error_set_has_value,
844 => {847 => {
845 const o = inst_datas[inst].ty_op;848 const o = inst_datas[inst].ty_op;
846 return trackOperands(a, new_set, inst, main_tomb, .{ o.operand, .none, .none });849 return trackOperands(a, new_set, inst, main_tomb, .{ o.operand, .none, .none });
...@@ -858,6 +861,7 @@ fn analyzeInst(...@@ -858,6 +861,7 @@ fn analyzeInst(
858 .bool_to_int,861 .bool_to_int,
859 .ret,862 .ret,
860 .ret_load,863 .ret_load,
864 .is_named_enum_value,
861 .tag_name,865 .tag_name,
862 .error_name,866 .error_name,
863 .sqrt,867 .sqrt,
src/Module.zig+117-83
...@@ -84,7 +84,6 @@ string_literal_bytes: std.ArrayListUnmanaged(u8) = .{},...@@ -84,7 +84,6 @@ string_literal_bytes: std.ArrayListUnmanaged(u8) = .{},
84/// The set of all the generic function instantiations. This is used so that when a generic84/// The set of all the generic function instantiations. This is used so that when a generic
85/// function is called twice with the same comptime parameter arguments, both calls dispatch85/// function is called twice with the same comptime parameter arguments, both calls dispatch
86/// to the same function.86/// to the same function.
87/// TODO: remove functions from this set when they are destroyed.
88monomorphed_funcs: MonomorphedFuncsSet = .{},87monomorphed_funcs: MonomorphedFuncsSet = .{},
89/// The set of all comptime function calls that have been cached so that future calls88/// The set of all comptime function calls that have been cached so that future calls
90/// with the same parameters will get the same return value.89/// with the same parameters will get the same return value.
...@@ -92,7 +91,6 @@ memoized_calls: MemoizedCallSet = .{},...@@ -92,7 +91,6 @@ memoized_calls: MemoizedCallSet = .{},
92/// Contains the values from `@setAlignStack`. A sparse table is used here91/// Contains the values from `@setAlignStack`. A sparse table is used here
93/// instead of a field of `Fn` because usage of `@setAlignStack` is rare, while92/// instead of a field of `Fn` because usage of `@setAlignStack` is rare, while
94/// functions are many.93/// functions are many.
95/// TODO: remove functions from this set when they are destroyed.
96align_stack_fns: std.AutoHashMapUnmanaged(*const Fn, SetAlignStack) = .{},94align_stack_fns: std.AutoHashMapUnmanaged(*const Fn, SetAlignStack) = .{},
9795
98/// We optimize memory usage for a compilation with no compile errors by storing the96/// We optimize memory usage for a compilation with no compile errors by storing the
...@@ -560,6 +558,10 @@ pub const Decl = struct {...@@ -560,6 +558,10 @@ pub const Decl = struct {
560 gpa.destroy(extern_fn);558 gpa.destroy(extern_fn);
561 }559 }
562 if (decl.getFunction()) |func| {560 if (decl.getFunction()) |func| {
561 _ = mod.align_stack_fns.remove(func);
562 if (func.comptime_args != null) {
563 _ = mod.monomorphed_funcs.remove(func);
564 }
563 func.deinit(gpa);565 func.deinit(gpa);
564 gpa.destroy(func);566 gpa.destroy(func);
565 }567 }
...@@ -853,8 +855,6 @@ pub const EmitH = struct {...@@ -853,8 +855,6 @@ pub const EmitH = struct {
853pub const ErrorSet = struct {855pub const ErrorSet = struct {
854 /// The Decl that corresponds to the error set itself.856 /// The Decl that corresponds to the error set itself.
855 owner_decl: Decl.Index,857 owner_decl: Decl.Index,
856 /// Offset from Decl node index, points to the error set AST node.
857 node_offset: i32,
858 /// The string bytes are stored in the owner Decl arena.858 /// The string bytes are stored in the owner Decl arena.
859 /// These must be in sorted order. See sortNames.859 /// These must be in sorted order. See sortNames.
860 names: NameMap,860 names: NameMap,
...@@ -866,7 +866,7 @@ pub const ErrorSet = struct {...@@ -866,7 +866,7 @@ pub const ErrorSet = struct {
866 return .{866 return .{
867 .file_scope = owner_decl.getFileScope(),867 .file_scope = owner_decl.getFileScope(),
868 .parent_decl_node = owner_decl.src_node,868 .parent_decl_node = owner_decl.src_node,
869 .lazy = LazySrcLoc.nodeOffset(self.node_offset),869 .lazy = LazySrcLoc.nodeOffset(0),
870 };870 };
871 }871 }
872872
...@@ -893,12 +893,15 @@ pub const Struct = struct {...@@ -893,12 +893,15 @@ pub const Struct = struct {
893 namespace: Namespace,893 namespace: Namespace,
894 /// The Decl that corresponds to the struct itself.894 /// The Decl that corresponds to the struct itself.
895 owner_decl: Decl.Index,895 owner_decl: Decl.Index,
896 /// Offset from `owner_decl`, points to the struct AST node.
897 node_offset: i32,
898 /// Index of the struct_decl ZIR instruction.896 /// Index of the struct_decl ZIR instruction.
899 zir_index: Zir.Inst.Index,897 zir_index: Zir.Inst.Index,
900898
901 layout: std.builtin.Type.ContainerLayout,899 layout: std.builtin.Type.ContainerLayout,
900 /// If the layout is not packed, this is the noreturn type.
901 /// If the layout is packed, this is the backing integer type of the packed struct.
902 /// Whether zig chooses this type or the user specifies it, it is stored here.
903 /// This will be set to the noreturn type until status is `have_layout`.
904 backing_int_ty: Type = Type.initTag(.noreturn),
902 status: enum {905 status: enum {
903 none,906 none,
904 field_types_wip,907 field_types_wip,
...@@ -934,13 +937,41 @@ pub const Struct = struct {...@@ -934,13 +937,41 @@ pub const Struct = struct {
934 /// If true then `default_val` is the comptime field value.937 /// If true then `default_val` is the comptime field value.
935 is_comptime: bool,938 is_comptime: bool,
936939
937 /// Returns the field alignment, assuming the struct is not packed.940 /// Returns the field alignment. If the struct is packed, returns 0.
938 pub fn normalAlignment(field: Field, target: Target) u32 {941 pub fn alignment(
939 if (field.abi_align == 0) {942 field: Field,
940 return field.ty.abiAlignment(target);943 target: Target,
941 } else {944 layout: std.builtin.Type.ContainerLayout,
945 ) u32 {
946 if (field.abi_align != 0) {
947 assert(layout != .Packed);
942 return field.abi_align;948 return field.abi_align;
943 }949 }
950
951 switch (layout) {
952 .Packed => return 0,
953 .Auto => {
954 if (target.ofmt == .c) {
955 return alignmentExtern(field, target);
956 } else {
957 return field.ty.abiAlignment(target);
958 }
959 },
960 .Extern => return alignmentExtern(field, target),
961 }
962 }
963
964 pub fn alignmentExtern(field: Field, target: Target) u32 {
965 // This logic is duplicated in Type.abiAlignmentAdvanced.
966 const ty_abi_align = field.ty.abiAlignment(target);
967
968 if (field.ty.isAbiInt() and field.ty.intInfo(target).bits >= 128) {
969 // The C ABI requires 128 bit integer fields of structs
970 // to be 16-bytes aligned.
971 return @maximum(ty_abi_align, 16);
972 }
973
974 return ty_abi_align;
944 }975 }
945 };976 };
946977
...@@ -953,7 +984,7 @@ pub const Struct = struct {...@@ -953,7 +984,7 @@ pub const Struct = struct {
953 return .{984 return .{
954 .file_scope = owner_decl.getFileScope(),985 .file_scope = owner_decl.getFileScope(),
955 .parent_decl_node = owner_decl.src_node,986 .parent_decl_node = owner_decl.src_node,
956 .lazy = LazySrcLoc.nodeOffset(s.node_offset),987 .lazy = LazySrcLoc.nodeOffset(0),
957 };988 };
958 }989 }
959990
...@@ -968,7 +999,7 @@ pub const Struct = struct {...@@ -968,7 +999,7 @@ pub const Struct = struct {
968 });999 });
969 return s.srcLoc(mod);1000 return s.srcLoc(mod);
970 };1001 };
971 const node = owner_decl.relativeToNodeIndex(s.node_offset);1002 const node = owner_decl.relativeToNodeIndex(0);
972 const node_tags = tree.nodes.items(.tag);1003 const node_tags = tree.nodes.items(.tag);
973 switch (node_tags[node]) {1004 switch (node_tags[node]) {
974 .container_decl,1005 .container_decl,
...@@ -1029,7 +1060,7 @@ pub const Struct = struct {...@@ -1029,7 +1060,7 @@ pub const Struct = struct {
10291060
1030 pub fn packedFieldBitOffset(s: Struct, target: Target, index: usize) u16 {1061 pub fn packedFieldBitOffset(s: Struct, target: Target, index: usize) u16 {
1031 assert(s.layout == .Packed);1062 assert(s.layout == .Packed);
1032 assert(s.haveFieldTypes());1063 assert(s.haveLayout());
1033 var bit_sum: u64 = 0;1064 var bit_sum: u64 = 0;
1034 for (s.fields.values()) |field, i| {1065 for (s.fields.values()) |field, i| {
1035 if (i == index) {1066 if (i == index) {
...@@ -1037,19 +1068,7 @@ pub const Struct = struct {...@@ -1037,19 +1068,7 @@ pub const Struct = struct {
1037 }1068 }
1038 bit_sum += field.ty.bitSize(target);1069 bit_sum += field.ty.bitSize(target);
1039 }1070 }
1040 return @intCast(u16, bit_sum);1071 unreachable; // index out of bounds
1041 }
1042
1043 pub fn packedIntegerBits(s: Struct, target: Target) u16 {
1044 return s.packedFieldBitOffset(target, s.fields.count());
1045 }
1046
1047 pub fn packedIntegerType(s: Struct, target: Target, buf: *Type.Payload.Bits) Type {
1048 buf.* = .{
1049 .base = .{ .tag = .int_unsigned },
1050 .data = s.packedIntegerBits(target),
1051 };
1052 return Type.initPayload(&buf.base);
1053 }1072 }
1054};1073};
10551074
...@@ -1060,8 +1079,6 @@ pub const Struct = struct {...@@ -1060,8 +1079,6 @@ pub const Struct = struct {
1060pub const EnumSimple = struct {1079pub const EnumSimple = struct {
1061 /// The Decl that corresponds to the enum itself.1080 /// The Decl that corresponds to the enum itself.
1062 owner_decl: Decl.Index,1081 owner_decl: Decl.Index,
1063 /// Offset from `owner_decl`, points to the enum decl AST node.
1064 node_offset: i32,
1065 /// Set of field names in declaration order.1082 /// Set of field names in declaration order.
1066 fields: NameMap,1083 fields: NameMap,
10671084
...@@ -1072,7 +1089,7 @@ pub const EnumSimple = struct {...@@ -1072,7 +1089,7 @@ pub const EnumSimple = struct {
1072 return .{1089 return .{
1073 .file_scope = owner_decl.getFileScope(),1090 .file_scope = owner_decl.getFileScope(),
1074 .parent_decl_node = owner_decl.src_node,1091 .parent_decl_node = owner_decl.src_node,
1075 .lazy = LazySrcLoc.nodeOffset(self.node_offset),1092 .lazy = LazySrcLoc.nodeOffset(0),
1076 };1093 };
1077 }1094 }
1078};1095};
...@@ -1083,8 +1100,6 @@ pub const EnumSimple = struct {...@@ -1083,8 +1100,6 @@ pub const EnumSimple = struct {
1083pub const EnumNumbered = struct {1100pub const EnumNumbered = struct {
1084 /// The Decl that corresponds to the enum itself.1101 /// The Decl that corresponds to the enum itself.
1085 owner_decl: Decl.Index,1102 owner_decl: Decl.Index,
1086 /// Offset from `owner_decl`, points to the enum decl AST node.
1087 node_offset: i32,
1088 /// An integer type which is used for the numerical value of the enum.1103 /// An integer type which is used for the numerical value of the enum.
1089 /// Whether zig chooses this type or the user specifies it, it is stored here.1104 /// Whether zig chooses this type or the user specifies it, it is stored here.
1090 tag_ty: Type,1105 tag_ty: Type,
...@@ -1103,7 +1118,7 @@ pub const EnumNumbered = struct {...@@ -1103,7 +1118,7 @@ pub const EnumNumbered = struct {
1103 return .{1118 return .{
1104 .file_scope = owner_decl.getFileScope(),1119 .file_scope = owner_decl.getFileScope(),
1105 .parent_decl_node = owner_decl.src_node,1120 .parent_decl_node = owner_decl.src_node,
1106 .lazy = LazySrcLoc.nodeOffset(self.node_offset),1121 .lazy = LazySrcLoc.nodeOffset(0),
1107 };1122 };
1108 }1123 }
1109};1124};
...@@ -1113,8 +1128,6 @@ pub const EnumNumbered = struct {...@@ -1113,8 +1128,6 @@ pub const EnumNumbered = struct {
1113pub const EnumFull = struct {1128pub const EnumFull = struct {
1114 /// The Decl that corresponds to the enum itself.1129 /// The Decl that corresponds to the enum itself.
1115 owner_decl: Decl.Index,1130 owner_decl: Decl.Index,
1116 /// Offset from `owner_decl`, points to the enum decl AST node.
1117 node_offset: i32,
1118 /// An integer type which is used for the numerical value of the enum.1131 /// An integer type which is used for the numerical value of the enum.
1119 /// Whether zig chooses this type or the user specifies it, it is stored here.1132 /// Whether zig chooses this type or the user specifies it, it is stored here.
1120 tag_ty: Type,1133 tag_ty: Type,
...@@ -1137,7 +1150,7 @@ pub const EnumFull = struct {...@@ -1137,7 +1150,7 @@ pub const EnumFull = struct {
1137 return .{1150 return .{
1138 .file_scope = owner_decl.getFileScope(),1151 .file_scope = owner_decl.getFileScope(),
1139 .parent_decl_node = owner_decl.src_node,1152 .parent_decl_node = owner_decl.src_node,
1140 .lazy = LazySrcLoc.nodeOffset(self.node_offset),1153 .lazy = LazySrcLoc.nodeOffset(0),
1141 };1154 };
1142 }1155 }
1143};1156};
...@@ -1155,8 +1168,6 @@ pub const Union = struct {...@@ -1155,8 +1168,6 @@ pub const Union = struct {
1155 namespace: Namespace,1168 namespace: Namespace,
1156 /// The Decl that corresponds to the union itself.1169 /// The Decl that corresponds to the union itself.
1157 owner_decl: Decl.Index,1170 owner_decl: Decl.Index,
1158 /// Offset from `owner_decl`, points to the union decl AST node.
1159 node_offset: i32,
1160 /// Index of the union_decl ZIR instruction.1171 /// Index of the union_decl ZIR instruction.
1161 zir_index: Zir.Inst.Index,1172 zir_index: Zir.Inst.Index,
11621173
...@@ -1203,7 +1214,7 @@ pub const Union = struct {...@@ -1203,7 +1214,7 @@ pub const Union = struct {
1203 return .{1214 return .{
1204 .file_scope = owner_decl.getFileScope(),1215 .file_scope = owner_decl.getFileScope(),
1205 .parent_decl_node = owner_decl.src_node,1216 .parent_decl_node = owner_decl.src_node,
1206 .lazy = LazySrcLoc.nodeOffset(self.node_offset),1217 .lazy = LazySrcLoc.nodeOffset(0),
1207 };1218 };
1208 }1219 }
12091220
...@@ -1218,7 +1229,7 @@ pub const Union = struct {...@@ -1218,7 +1229,7 @@ pub const Union = struct {
1218 });1229 });
1219 return u.srcLoc(mod);1230 return u.srcLoc(mod);
1220 };1231 };
1221 const node = owner_decl.relativeToNodeIndex(u.node_offset);1232 const node = owner_decl.relativeToNodeIndex(0);
1222 const node_tags = tree.nodes.items(.tag);1233 const node_tags = tree.nodes.items(.tag);
1223 var buf: [2]Ast.Node.Index = undefined;1234 var buf: [2]Ast.Node.Index = undefined;
1224 switch (node_tags[node]) {1235 switch (node_tags[node]) {
...@@ -1357,18 +1368,20 @@ pub const Union = struct {...@@ -1357,18 +1368,20 @@ pub const Union = struct {
1357 }1368 }
1358 }1369 }
1359 payload_align = @maximum(payload_align, 1);1370 payload_align = @maximum(payload_align, 1);
1360 if (!have_tag or fields.len <= 1) return .{1371 if (!have_tag or !u.tag_ty.hasRuntimeBits()) {
1361 .abi_size = std.mem.alignForwardGeneric(u64, payload_size, payload_align),1372 return .{
1362 .abi_align = payload_align,1373 .abi_size = std.mem.alignForwardGeneric(u64, payload_size, payload_align),
1363 .most_aligned_field = most_aligned_field,1374 .abi_align = payload_align,
1364 .most_aligned_field_size = most_aligned_field_size,1375 .most_aligned_field = most_aligned_field,
1365 .biggest_field = biggest_field,1376 .most_aligned_field_size = most_aligned_field_size,
1366 .payload_size = payload_size,1377 .biggest_field = biggest_field,
1367 .payload_align = payload_align,1378 .payload_size = payload_size,
1368 .tag_align = 0,1379 .payload_align = payload_align,
1369 .tag_size = 0,1380 .tag_align = 0,
1370 .padding = 0,1381 .tag_size = 0,
1371 };1382 .padding = 0,
1383 };
1384 }
1372 // Put the tag before or after the payload depending on which one's1385 // Put the tag before or after the payload depending on which one's
1373 // alignment is greater.1386 // alignment is greater.
1374 const tag_size = u.tag_ty.abiSize(target);1387 const tag_size = u.tag_ty.abiSize(target);
...@@ -1410,8 +1423,6 @@ pub const Union = struct {...@@ -1410,8 +1423,6 @@ pub const Union = struct {
1410pub const Opaque = struct {1423pub const Opaque = struct {
1411 /// The Decl that corresponds to the opaque itself.1424 /// The Decl that corresponds to the opaque itself.
1412 owner_decl: Decl.Index,1425 owner_decl: Decl.Index,
1413 /// Offset from `owner_decl`, points to the opaque decl AST node.
1414 node_offset: i32,
1415 /// Represents the declarations inside this opaque.1426 /// Represents the declarations inside this opaque.
1416 namespace: Namespace,1427 namespace: Namespace,
14171428
...@@ -1420,7 +1431,7 @@ pub const Opaque = struct {...@@ -1420,7 +1431,7 @@ pub const Opaque = struct {
1420 return .{1431 return .{
1421 .file_scope = owner_decl.getFileScope(),1432 .file_scope = owner_decl.getFileScope(),
1422 .parent_decl_node = owner_decl.src_node,1433 .parent_decl_node = owner_decl.src_node,
1423 .lazy = LazySrcLoc.nodeOffset(self.node_offset),1434 .lazy = LazySrcLoc.nodeOffset(0),
1424 };1435 };
1425 }1436 }
14261437
...@@ -1464,25 +1475,14 @@ pub const Fn = struct {...@@ -1464,25 +1475,14 @@ pub const Fn = struct {
1464 /// These never have .generic_poison for the Type1475 /// These never have .generic_poison for the Type
1465 /// because the Type is needed to pass to `Type.eql` and for inserting comptime arguments1476 /// because the Type is needed to pass to `Type.eql` and for inserting comptime arguments
1466 /// into the inst_map when analyzing the body of a generic function instantiation.1477 /// into the inst_map when analyzing the body of a generic function instantiation.
1467 /// Instead, the is_anytype knowledge is communicated via `anytype_args`.1478 /// Instead, the is_anytype knowledge is communicated via `isAnytypeParam`.
1468 comptime_args: ?[*]TypedValue,1479 comptime_args: ?[*]TypedValue,
1469 /// When comptime_args is null, this is undefined. Otherwise, this flags each
1470 /// parameter and tells whether it is anytype.
1471 /// TODO apply the same enhancement for param_names below to this field.
1472 anytype_args: [*]bool,
1473
1474 /// Prefer to use `getParamName` to access this because of the future improvement
1475 /// we want to do mentioned in the TODO below.
1476 /// Stored in gpa.
1477 /// TODO: change param ZIR instructions to be embedded inside the function
1478 /// ZIR instruction instead of before it, so that `zir_body_inst` can be used to
1479 /// determine param names rather than redundantly storing them here.
1480 param_names: []const [:0]const u8,
14811480
1482 /// Precomputed hash for monomorphed_funcs.1481 /// Precomputed hash for monomorphed_funcs.
1483 /// This is important because it may be accessed when resizing monomorphed_funcs1482 /// This is important because it may be accessed when resizing monomorphed_funcs
1484 /// while this Fn has already been added to the set, but does not have the1483 /// while this Fn has already been added to the set, but does not have the
1485 /// owner_decl, comptime_args, or other fields populated yet.1484 /// owner_decl, comptime_args, or other fields populated yet.
1485 /// This field is undefined if comptime_args == null.
1486 hash: u64,1486 hash: u64,
14871487
1488 /// Relative to owner Decl.1488 /// Relative to owner Decl.
...@@ -1590,18 +1590,43 @@ pub const Fn = struct {...@@ -1590,18 +1590,43 @@ pub const Fn = struct {
1590 gpa.destroy(node);1590 gpa.destroy(node);
1591 it = next;1591 it = next;
1592 }1592 }
1593 }
15931594
1594 for (func.param_names) |param_name| {1595 pub fn isAnytypeParam(func: Fn, mod: *Module, index: u32) bool {
1595 gpa.free(param_name);1596 const file = mod.declPtr(func.owner_decl).getFileScope();
1596 }1597
1597 gpa.free(func.param_names);1598 const tags = file.zir.instructions.items(.tag);
1599
1600 const param_body = file.zir.getParamBody(func.zir_body_inst);
1601 const param = param_body[index];
1602
1603 return switch (tags[param]) {
1604 .param, .param_comptime => false,
1605 .param_anytype, .param_anytype_comptime => true,
1606 else => unreachable,
1607 };
1598 }1608 }
15991609
1600 pub fn getParamName(func: Fn, index: u32) [:0]const u8 {1610 pub fn getParamName(func: Fn, mod: *Module, index: u32) [:0]const u8 {
1601 // TODO rework ZIR of parameters so that this function looks up1611 const file = mod.declPtr(func.owner_decl).getFileScope();
1602 // param names in ZIR instead of redundantly saving them into Fn.1612
1603 // const zir = func.owner_decl.getFileScope().zir;1613 const tags = file.zir.instructions.items(.tag);
1604 return func.param_names[index];1614 const data = file.zir.instructions.items(.data);
1615
1616 const param_body = file.zir.getParamBody(func.zir_body_inst);
1617 const param = param_body[index];
1618
1619 return switch (tags[param]) {
1620 .param, .param_comptime => blk: {
1621 const extra = file.zir.extraData(Zir.Inst.Param, data[param].pl_tok.payload_index);
1622 break :blk file.zir.nullTerminatedString(extra.data.name);
1623 },
1624 .param_anytype, .param_anytype_comptime => blk: {
1625 const param_data = data[param].str_tok;
1626 break :blk param_data.get(file.zir);
1627 },
1628 else => unreachable,
1629 };
1605 }1630 }
16061631
1607 pub fn hasInferredErrorSet(func: Fn, mod: *Module) bool {1632 pub fn hasInferredErrorSet(func: Fn, mod: *Module) bool {
...@@ -4102,6 +4127,12 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {...@@ -4102,6 +4127,12 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
4102 // The exports this Decl performs will be re-discovered, so we remove them here4127 // The exports this Decl performs will be re-discovered, so we remove them here
4103 // prior to re-analysis.4128 // prior to re-analysis.
4104 mod.deleteDeclExports(decl_index);4129 mod.deleteDeclExports(decl_index);
4130
4131 // Similarly, `@setAlignStack` invocations will be re-discovered.
4132 if (decl.getFunction()) |func| {
4133 _ = mod.align_stack_fns.remove(func);
4134 }
4135
4105 // Dependencies will be re-discovered, so we remove them here prior to re-analysis.4136 // Dependencies will be re-discovered, so we remove them here prior to re-analysis.
4106 for (decl.dependencies.keys()) |dep_index| {4137 for (decl.dependencies.keys()) |dep_index| {
4107 const dep = mod.declPtr(dep_index);4138 const dep = mod.declPtr(dep_index);
...@@ -4324,7 +4355,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {...@@ -4324,7 +4355,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
4324 struct_obj.* = .{4355 struct_obj.* = .{
4325 .owner_decl = undefined, // set below4356 .owner_decl = undefined, // set below
4326 .fields = .{},4357 .fields = .{},
4327 .node_offset = 0, // it's the struct for the root file
4328 .zir_index = undefined, // set below4358 .zir_index = undefined, // set below
4329 .layout = .Auto,4359 .layout = .Auto,
4330 .status = .none,4360 .status = .none,
...@@ -6047,17 +6077,17 @@ pub fn paramSrc(...@@ -6047,17 +6077,17 @@ pub fn paramSrc(
6047 else => unreachable,6077 else => unreachable,
6048 };6078 };
6049 var it = full.iterate(tree);6079 var it = full.iterate(tree);
6050 while (true) {6080 var i: usize = 0;
6051 if (it.param_i == param_i) {6081 while (it.next()) |param| : (i += 1) {
6052 const param = it.next().?;6082 if (i == param_i) {
6053 if (param.anytype_ellipsis3) |some| {6083 if (param.anytype_ellipsis3) |some| {
6054 const main_token = tree.nodes.items(.main_token)[decl.src_node];6084 const main_token = tree.nodes.items(.main_token)[decl.src_node];
6055 return .{ .token_offset_param = @bitCast(i32, some) - @bitCast(i32, main_token) };6085 return .{ .token_offset_param = @bitCast(i32, some) - @bitCast(i32, main_token) };
6056 }6086 }
6057 return .{ .node_offset_param = decl.nodeIndexToRelative(param.type_expr) };6087 return .{ .node_offset_param = decl.nodeIndexToRelative(param.type_expr) };
6058 }6088 }
6059 _ = it.next();
6060 }6089 }
6090 unreachable;
6061}6091}
60626092
6063pub fn argSrc(6093pub fn argSrc(
...@@ -6504,3 +6534,7 @@ pub fn addGlobalAssembly(mod: *Module, decl_index: Decl.Index, source: []const u...@@ -6504,3 +6534,7 @@ pub fn addGlobalAssembly(mod: *Module, decl_index: Decl.Index, source: []const u
65046534
6505 mod.global_assembly.putAssumeCapacityNoClobber(decl_index, duped_source);6535 mod.global_assembly.putAssumeCapacityNoClobber(decl_index, duped_source);
6506}6536}
6537
6538pub fn wantDllExports(mod: Module) bool {
6539 return mod.comp.bin_file.options.dll_export_fns and mod.getTarget().os.tag == .windows;
6540}
src/Sema.zig+1793-794
...@@ -76,8 +76,14 @@ types_to_resolve: std.ArrayListUnmanaged(Air.Inst.Ref) = .{},...@@ -76,8 +76,14 @@ types_to_resolve: std.ArrayListUnmanaged(Air.Inst.Ref) = .{},
76post_hoc_blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, *LabeledBlock) = .{},76post_hoc_blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, *LabeledBlock) = .{},
77/// Populated with the last compile error created.77/// Populated with the last compile error created.
78err: ?*Module.ErrorMsg = null,78err: ?*Module.ErrorMsg = null,
79/// True when analyzing a generic instantiation. Used to suppress some errors.
80is_generic_instantiation: bool = false,
81/// Set to true when analyzing a func type instruction so that nested generic
82/// function types will emit generic poison instead of a partial type.
83no_partial_func_ty: bool = false,
7984
80const std = @import("std");85const std = @import("std");
86const math = std.math;
81const mem = std.mem;87const mem = std.mem;
82const Allocator = std.mem.Allocator;88const Allocator = std.mem.Allocator;
83const assert = std.debug.assert;89const assert = std.debug.assert;
...@@ -772,7 +778,6 @@ fn analyzeBodyInner(...@@ -772,7 +778,6 @@ fn analyzeBodyInner(
772 .optional_payload_unsafe => try sema.zirOptionalPayload(block, inst, false),778 .optional_payload_unsafe => try sema.zirOptionalPayload(block, inst, false),
773 .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false),779 .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false),
774 .optional_type => try sema.zirOptionalType(block, inst),780 .optional_type => try sema.zirOptionalType(block, inst),
775 .param_type => try sema.zirParamType(block, inst),
776 .ptr_type => try sema.zirPtrType(block, inst),781 .ptr_type => try sema.zirPtrType(block, inst),
777 .overflow_arithmetic_ptr => try sema.zirOverflowArithmeticPtr(block, inst),782 .overflow_arithmetic_ptr => try sema.zirOverflowArithmeticPtr(block, inst),
778 .ref => try sema.zirRef(block, inst),783 .ref => try sema.zirRef(block, inst),
...@@ -816,7 +821,6 @@ fn analyzeBodyInner(...@@ -816,7 +821,6 @@ fn analyzeBodyInner(
816 .embed_file => try sema.zirEmbedFile(block, inst),821 .embed_file => try sema.zirEmbedFile(block, inst),
817 .error_name => try sema.zirErrorName(block, inst),822 .error_name => try sema.zirErrorName(block, inst),
818 .tag_name => try sema.zirTagName(block, inst),823 .tag_name => try sema.zirTagName(block, inst),
819 .reify => try sema.zirReify(block, inst),
820 .type_name => try sema.zirTypeName(block, inst),824 .type_name => try sema.zirTypeName(block, inst),
821 .frame_type => try sema.zirFrameType(block, inst),825 .frame_type => try sema.zirFrameType(block, inst),
822 .frame_size => try sema.zirFrameSize(block, inst),826 .frame_size => try sema.zirFrameSize(block, inst),
...@@ -876,9 +880,6 @@ fn analyzeBodyInner(...@@ -876,9 +880,6 @@ fn analyzeBodyInner(
876 .add => try sema.zirArithmetic(block, inst, .add),880 .add => try sema.zirArithmetic(block, inst, .add),
877 .addwrap => try sema.zirArithmetic(block, inst, .addwrap),881 .addwrap => try sema.zirArithmetic(block, inst, .addwrap),
878 .add_sat => try sema.zirArithmetic(block, inst, .add_sat),882 .add_sat => try sema.zirArithmetic(block, inst, .add_sat),
879 .mod_rem => try sema.zirArithmetic(block, inst, .mod_rem),
880 .mod => try sema.zirArithmetic(block, inst, .mod),
881 .rem => try sema.zirArithmetic(block, inst, .rem),
882 .mul => try sema.zirArithmetic(block, inst, .mul),883 .mul => try sema.zirArithmetic(block, inst, .mul),
883 .mulwrap => try sema.zirArithmetic(block, inst, .mulwrap),884 .mulwrap => try sema.zirArithmetic(block, inst, .mulwrap),
884 .mul_sat => try sema.zirArithmetic(block, inst, .mul_sat),885 .mul_sat => try sema.zirArithmetic(block, inst, .mul_sat),
...@@ -891,6 +892,10 @@ fn analyzeBodyInner(...@@ -891,6 +892,10 @@ fn analyzeBodyInner(
891 .div_floor => try sema.zirDivFloor(block, inst),892 .div_floor => try sema.zirDivFloor(block, inst),
892 .div_trunc => try sema.zirDivTrunc(block, inst),893 .div_trunc => try sema.zirDivTrunc(block, inst),
893894
895 .mod_rem => try sema.zirModRem(block, inst),
896 .mod => try sema.zirMod(block, inst),
897 .rem => try sema.zirRem(block, inst),
898
894 .maximum => try sema.zirMinMax(block, inst, .max),899 .maximum => try sema.zirMinMax(block, inst, .max),
895 .minimum => try sema.zirMinMax(block, inst, .min),900 .minimum => try sema.zirMinMax(block, inst, .min),
896901
...@@ -950,6 +955,7 @@ fn analyzeBodyInner(...@@ -950,6 +955,7 @@ fn analyzeBodyInner(
950 .select => try sema.zirSelect( block, extended),955 .select => try sema.zirSelect( block, extended),
951 .error_to_int => try sema.zirErrorToInt( block, extended),956 .error_to_int => try sema.zirErrorToInt( block, extended),
952 .int_to_error => try sema.zirIntToError( block, extended),957 .int_to_error => try sema.zirIntToError( block, extended),
958 .reify => try sema.zirReify( block, extended, inst),
953 // zig fmt: on959 // zig fmt: on
954 .fence => {960 .fence => {
955 try sema.zirFence(block, extended);961 try sema.zirFence(block, extended);
...@@ -1494,7 +1500,8 @@ pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref {...@@ -1494,7 +1500,8 @@ pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref {
14941500
1495 // Finally, the last section of indexes refers to the map of ZIR=>AIR.1501 // Finally, the last section of indexes refers to the map of ZIR=>AIR.
1496 const inst = sema.inst_map.get(@intCast(u32, i)).?;1502 const inst = sema.inst_map.get(@intCast(u32, i)).?;
1497 if (sema.typeOf(inst).tag() == .generic_poison) return error.GenericPoison;1503 const ty = sema.typeOf(inst);
1504 if (ty.tag() == .generic_poison) return error.GenericPoison;
1498 return inst;1505 return inst;
1499}1506}
15001507
...@@ -1577,8 +1584,7 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize)...@@ -1577,8 +1584,7 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize)
15771584
1578 // st.index = 0;1585 // st.index = 0;
1579 const index_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, "index", src, true);1586 const index_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, "index", src, true);
1580 const zero = try sema.addConstant(Type.usize, Value.zero);1587 try sema.storePtr2(&err_trace_block, src, index_field_ptr, src, .zero_usize, src, .store);
1581 try sema.storePtr2(&err_trace_block, src, index_field_ptr, src, zero, src, .store);
15821588
1583 // @errorReturnTrace() = &st;1589 // @errorReturnTrace() = &st;
1584 _ = try err_trace_block.addUnOp(.set_err_return_trace, st_ptr);1590 _ = try err_trace_block.addUnOp(.set_err_return_trace, st_ptr);
...@@ -1695,7 +1701,10 @@ fn resolveMaybeUndefValIntable(...@@ -1695,7 +1701,10 @@ fn resolveMaybeUndefValIntable(
1695 .elem_ptr => check = check.castTag(.elem_ptr).?.data.array_ptr,1701 .elem_ptr => check = check.castTag(.elem_ptr).?.data.array_ptr,
1696 .eu_payload_ptr, .opt_payload_ptr => check = check.cast(Value.Payload.PayloadPtr).?.data.container_ptr,1702 .eu_payload_ptr, .opt_payload_ptr => check = check.cast(Value.Payload.PayloadPtr).?.data.container_ptr,
1697 .generic_poison => return error.GenericPoison,1703 .generic_poison => return error.GenericPoison,
1698 else => return val,1704 else => {
1705 try sema.resolveLazyValue(block, src, val);
1706 return val;
1707 },
1699 };1708 };
1700}1709}
17011710
...@@ -1818,10 +1827,21 @@ fn failWithInvalidComptimeFieldStore(sema: *Sema, block: *Block, init_src: LazyS...@@ -1818,10 +1827,21 @@ fn failWithInvalidComptimeFieldStore(sema: *Sema, block: *Block, init_src: LazyS
18181827
1819 const tree = try sema.getAstTree(block);1828 const tree = try sema.getAstTree(block);
1820 const decl = sema.mod.declPtr(decl_index);1829 const decl = sema.mod.declPtr(decl_index);
1821 const field_src = enumFieldSrcLoc(decl, tree.*, container_ty.getNodeOffset(), field_index);1830 const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_index);
1822 const default_value_src: LazySrcLoc = .{ .node_offset_field_default = field_src.node_offset.x };1831 const default_value_src: LazySrcLoc = .{ .node_offset_field_default = field_src.node_offset.x };
18231832
1824 try sema.errNote(block, default_value_src, msg, "default value set here", .{});1833 try sema.mod.errNoteNonLazy(default_value_src.toSrcLoc(decl), msg, "default value set here", .{});
1834 break :msg msg;
1835 };
1836 return sema.failWithOwnedErrorMsg(msg);
1837}
1838
1839fn failWithUseOfAsync(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError {
1840 const msg = msg: {
1841 const msg = try sema.errMsg(block, src, "async has not been implemented in the self-hosted compiler yet", .{});
1842 errdefer msg.destroy(sema.gpa);
1843
1844 try sema.errNote(block, src, msg, "to use async enable the stage1 compiler with either '-fstage1' or by setting '.use_stage1 = true` in your 'build.zig' script", .{});
1825 break :msg msg;1845 break :msg msg;
1826 };1846 };
1827 return sema.failWithOwnedErrorMsg(msg);1847 return sema.failWithOwnedErrorMsg(msg);
...@@ -1855,7 +1875,7 @@ fn addFieldErrNote(...@@ -1855,7 +1875,7 @@ fn addFieldErrNote(
1855 const decl_index = container_ty.getOwnerDecl();1875 const decl_index = container_ty.getOwnerDecl();
1856 const decl = mod.declPtr(decl_index);1876 const decl = mod.declPtr(decl_index);
1857 const tree = try sema.getAstTree(block);1877 const tree = try sema.getAstTree(block);
1858 const field_src = enumFieldSrcLoc(decl, tree.*, container_ty.getNodeOffset(), field_index);1878 const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_index);
1859 try mod.errNoteNonLazy(field_src.toSrcLoc(decl), parent, format, args);1879 try mod.errNoteNonLazy(field_src.toSrcLoc(decl), parent, format, args);
1860}1880}
18611881
...@@ -1895,8 +1915,6 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {...@@ -1895,8 +1915,6 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {
1895 }1915 }
18961916
1897 const mod = sema.mod;1917 const mod = sema.mod;
1898 sema.err = err_msg;
1899
1900 {1918 {
1901 errdefer err_msg.destroy(mod.gpa);1919 errdefer err_msg.destroy(mod.gpa);
1902 if (err_msg.src_loc.lazy == .unneeded) {1920 if (err_msg.src_loc.lazy == .unneeded) {
...@@ -1914,8 +1932,10 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {...@@ -1914,8 +1932,10 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {
1914 const gop = mod.failed_decls.getOrPutAssumeCapacity(sema.owner_decl_index);1932 const gop = mod.failed_decls.getOrPutAssumeCapacity(sema.owner_decl_index);
1915 if (gop.found_existing) {1933 if (gop.found_existing) {
1916 // If there are multiple errors for the same Decl, prefer the first one added.1934 // If there are multiple errors for the same Decl, prefer the first one added.
1935 sema.err = null;
1917 err_msg.destroy(mod.gpa);1936 err_msg.destroy(mod.gpa);
1918 } else {1937 } else {
1938 sema.err = err_msg;
1919 gop.value_ptr.* = err_msg;1939 gop.value_ptr.* = err_msg;
1920 }1940 }
1921 return error.AnalysisFail;1941 return error.AnalysisFail;
...@@ -2228,6 +2248,16 @@ pub fn analyzeStructDecl(...@@ -2228,6 +2248,16 @@ pub fn analyzeStructDecl(
2228 break :blk decls_len;2248 break :blk decls_len;
2229 } else 0;2249 } else 0;
22302250
2251 if (small.has_backing_int) {
2252 const backing_int_body_len = sema.code.extra[extra_index];
2253 extra_index += 1; // backing_int_body_len
2254 if (backing_int_body_len == 0) {
2255 extra_index += 1; // backing_int_ref
2256 } else {
2257 extra_index += backing_int_body_len; // backing_int_body_inst
2258 }
2259 }
2260
2231 _ = try sema.mod.scanNamespace(&struct_obj.namespace, extra_index, decls_len, new_decl);2261 _ = try sema.mod.scanNamespace(&struct_obj.namespace, extra_index, decls_len, new_decl);
2232}2262}
22332263
...@@ -2251,7 +2281,7 @@ fn zirStructDecl(...@@ -2251,7 +2281,7 @@ fn zirStructDecl(
2251 const struct_obj = try new_decl_arena_allocator.create(Module.Struct);2281 const struct_obj = try new_decl_arena_allocator.create(Module.Struct);
2252 const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj);2282 const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj);
2253 const struct_val = try Value.Tag.ty.create(new_decl_arena_allocator, struct_ty);2283 const struct_val = try Value.Tag.ty.create(new_decl_arena_allocator, struct_ty);
2254 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{2284 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
2255 .ty = Type.type,2285 .ty = Type.type,
2256 .val = struct_val,2286 .val = struct_val,
2257 }, small.name_strategy, "struct", inst);2287 }, small.name_strategy, "struct", inst);
...@@ -2261,7 +2291,6 @@ fn zirStructDecl(...@@ -2261,7 +2291,6 @@ fn zirStructDecl(
2261 struct_obj.* = .{2291 struct_obj.* = .{
2262 .owner_decl = new_decl_index,2292 .owner_decl = new_decl_index,
2263 .fields = .{},2293 .fields = .{},
2264 .node_offset = src.node_offset.x,
2265 .zir_index = inst,2294 .zir_index = inst,
2266 .layout = small.layout,2295 .layout = small.layout,
2267 .status = .none,2296 .status = .none,
...@@ -2283,6 +2312,7 @@ fn zirStructDecl(...@@ -2283,6 +2312,7 @@ fn zirStructDecl(
2283fn createAnonymousDeclTypeNamed(2312fn createAnonymousDeclTypeNamed(
2284 sema: *Sema,2313 sema: *Sema,
2285 block: *Block,2314 block: *Block,
2315 src: LazySrcLoc,
2286 typed_value: TypedValue,2316 typed_value: TypedValue,
2287 name_strategy: Zir.Inst.NameStrategy,2317 name_strategy: Zir.Inst.NameStrategy,
2288 anon_prefix: []const u8,2318 anon_prefix: []const u8,
...@@ -2292,7 +2322,8 @@ fn createAnonymousDeclTypeNamed(...@@ -2292,7 +2322,8 @@ fn createAnonymousDeclTypeNamed(
2292 const namespace = block.namespace;2322 const namespace = block.namespace;
2293 const src_scope = block.wip_capture_scope;2323 const src_scope = block.wip_capture_scope;
2294 const src_decl = mod.declPtr(block.src_decl);2324 const src_decl = mod.declPtr(block.src_decl);
2295 const new_decl_index = try mod.allocateNewDecl(namespace, src_decl.src_node, src_scope);2325 const src_node = src_decl.relativeToNodeIndex(src.node_offset.x);
2326 const new_decl_index = try mod.allocateNewDecl(namespace, src_node, src_scope);
2296 errdefer mod.destroyDecl(new_decl_index);2327 errdefer mod.destroyDecl(new_decl_index);
22972328
2298 switch (name_strategy) {2329 switch (name_strategy) {
...@@ -2367,7 +2398,7 @@ fn createAnonymousDeclTypeNamed(...@@ -2367,7 +2398,7 @@ fn createAnonymousDeclTypeNamed(
2367 },2398 },
2368 else => {},2399 else => {},
2369 };2400 };
2370 return sema.createAnonymousDeclTypeNamed(block, typed_value, .anon, anon_prefix, null);2401 return sema.createAnonymousDeclTypeNamed(block, src, typed_value, .anon, anon_prefix, null);
2371 },2402 },
2372 }2403 }
2373}2404}
...@@ -2431,7 +2462,7 @@ fn zirEnumDecl(...@@ -2431,7 +2462,7 @@ fn zirEnumDecl(
2431 };2462 };
2432 const enum_ty = Type.initPayload(&enum_ty_payload.base);2463 const enum_ty = Type.initPayload(&enum_ty_payload.base);
2433 const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty);2464 const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty);
2434 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{2465 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
2435 .ty = Type.type,2466 .ty = Type.type,
2436 .val = enum_val,2467 .val = enum_val,
2437 }, small.name_strategy, "enum", inst);2468 }, small.name_strategy, "enum", inst);
...@@ -2445,7 +2476,6 @@ fn zirEnumDecl(...@@ -2445,7 +2476,6 @@ fn zirEnumDecl(
2445 .tag_ty_inferred = true,2476 .tag_ty_inferred = true,
2446 .fields = .{},2477 .fields = .{},
2447 .values = .{},2478 .values = .{},
2448 .node_offset = src.node_offset.x,
2449 .namespace = .{2479 .namespace = .{
2450 .parent = block.namespace,2480 .parent = block.namespace,
2451 .ty = enum_ty,2481 .ty = enum_ty,
...@@ -2467,18 +2497,6 @@ fn zirEnumDecl(...@@ -2467,18 +2497,6 @@ fn zirEnumDecl(
2467 extra_index = try mod.scanNamespace(&enum_obj.namespace, extra_index, decls_len, new_decl);2497 extra_index = try mod.scanNamespace(&enum_obj.namespace, extra_index, decls_len, new_decl);
24682498
2469 const body = sema.code.extra[extra_index..][0..body_len];2499 const body = sema.code.extra[extra_index..][0..body_len];
2470 if (fields_len == 0) {
2471 assert(body.len == 0);
2472 if (tag_type_ref != .none) {
2473 const ty = try sema.resolveType(block, tag_ty_src, tag_type_ref);
2474 if (ty.zigTypeTag() != .Int and ty.zigTypeTag() != .ComptimeInt) {
2475 return sema.fail(block, tag_ty_src, "expected integer tag type, found '{}'", .{ty.fmt(sema.mod)});
2476 }
2477 enum_obj.tag_ty = try ty.copy(new_decl_arena_allocator);
2478 enum_obj.tag_ty_inferred = false;
2479 }
2480 return decl_val;
2481 }
2482 extra_index += body.len;2500 extra_index += body.len;
24832501
2484 const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;2502 const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
...@@ -2536,6 +2554,9 @@ fn zirEnumDecl(...@@ -2536,6 +2554,9 @@ fn zirEnumDecl(
2536 }2554 }
2537 enum_obj.tag_ty = try ty.copy(decl_arena_allocator);2555 enum_obj.tag_ty = try ty.copy(decl_arena_allocator);
2538 enum_obj.tag_ty_inferred = false;2556 enum_obj.tag_ty_inferred = false;
2557 } else if (fields_len == 0) {
2558 enum_obj.tag_ty = try Type.Tag.int_unsigned.create(decl_arena_allocator, 0);
2559 enum_obj.tag_ty_inferred = true;
2539 } else {2560 } else {
2540 const bits = std.math.log2_int_ceil(usize, fields_len);2561 const bits = std.math.log2_int_ceil(usize, fields_len);
2541 enum_obj.tag_ty = try Type.Tag.int_unsigned.create(decl_arena_allocator, bits);2562 enum_obj.tag_ty = try Type.Tag.int_unsigned.create(decl_arena_allocator, bits);
...@@ -2673,7 +2694,7 @@ fn zirUnionDecl(...@@ -2673,7 +2694,7 @@ fn zirUnionDecl(
2673 const union_ty = Type.initPayload(&union_payload.base);2694 const union_ty = Type.initPayload(&union_payload.base);
2674 const union_val = try Value.Tag.ty.create(new_decl_arena_allocator, union_ty);2695 const union_val = try Value.Tag.ty.create(new_decl_arena_allocator, union_ty);
2675 const mod = sema.mod;2696 const mod = sema.mod;
2676 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{2697 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
2677 .ty = Type.type,2698 .ty = Type.type,
2678 .val = union_val,2699 .val = union_val,
2679 }, small.name_strategy, "union", inst);2700 }, small.name_strategy, "union", inst);
...@@ -2684,7 +2705,6 @@ fn zirUnionDecl(...@@ -2684,7 +2705,6 @@ fn zirUnionDecl(
2684 .owner_decl = new_decl_index,2705 .owner_decl = new_decl_index,
2685 .tag_ty = Type.initTag(.@"null"),2706 .tag_ty = Type.initTag(.@"null"),
2686 .fields = .{},2707 .fields = .{},
2687 .node_offset = src.node_offset.x,
2688 .zir_index = inst,2708 .zir_index = inst,
2689 .layout = small.layout,2709 .layout = small.layout,
2690 .status = .none,2710 .status = .none,
...@@ -2742,7 +2762,7 @@ fn zirOpaqueDecl(...@@ -2742,7 +2762,7 @@ fn zirOpaqueDecl(
2742 };2762 };
2743 const opaque_ty = Type.initPayload(&opaque_ty_payload.base);2763 const opaque_ty = Type.initPayload(&opaque_ty_payload.base);
2744 const opaque_val = try Value.Tag.ty.create(new_decl_arena_allocator, opaque_ty);2764 const opaque_val = try Value.Tag.ty.create(new_decl_arena_allocator, opaque_ty);
2745 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{2765 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
2746 .ty = Type.type,2766 .ty = Type.type,
2747 .val = opaque_val,2767 .val = opaque_val,
2748 }, small.name_strategy, "opaque", inst);2768 }, small.name_strategy, "opaque", inst);
...@@ -2752,7 +2772,6 @@ fn zirOpaqueDecl(...@@ -2752,7 +2772,6 @@ fn zirOpaqueDecl(
27522772
2753 opaque_obj.* = .{2773 opaque_obj.* = .{
2754 .owner_decl = new_decl_index,2774 .owner_decl = new_decl_index,
2755 .node_offset = src.node_offset.x,
2756 .namespace = .{2775 .namespace = .{
2757 .parent = block.namespace,2776 .parent = block.namespace,
2758 .ty = opaque_ty,2777 .ty = opaque_ty,
...@@ -2791,7 +2810,7 @@ fn zirErrorSetDecl(...@@ -2791,7 +2810,7 @@ fn zirErrorSetDecl(
2791 const error_set_ty = try Type.Tag.error_set.create(new_decl_arena_allocator, error_set);2810 const error_set_ty = try Type.Tag.error_set.create(new_decl_arena_allocator, error_set);
2792 const error_set_val = try Value.Tag.ty.create(new_decl_arena_allocator, error_set_ty);2811 const error_set_val = try Value.Tag.ty.create(new_decl_arena_allocator, error_set_ty);
2793 const mod = sema.mod;2812 const mod = sema.mod;
2794 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{2813 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
2795 .ty = Type.type,2814 .ty = Type.type,
2796 .val = error_set_val,2815 .val = error_set_val,
2797 }, name_strategy, "error", inst);2816 }, name_strategy, "error", inst);
...@@ -2816,7 +2835,6 @@ fn zirErrorSetDecl(...@@ -2816,7 +2835,6 @@ fn zirErrorSetDecl(
28162835
2817 error_set.* = .{2836 error_set.* = .{
2818 .owner_decl = new_decl_index,2837 .owner_decl = new_decl_index,
2819 .node_offset = inst_data.src_node,
2820 .names = names,2838 .names = names,
2821 };2839 };
2822 try new_decl.finalizeNewArena(&new_decl_arena);2840 try new_decl.finalizeNewArena(&new_decl_arena);
...@@ -3068,7 +3086,7 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro...@@ -3068,7 +3086,7 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
30683086
3069 const candidate = block.instructions.items[search_index];3087 const candidate = block.instructions.items[search_index];
3070 switch (air_tags[candidate]) {3088 switch (air_tags[candidate]) {
3071 .dbg_stmt => continue,3089 .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue,
3072 .store => break candidate,3090 .store => break candidate,
3073 else => break :ct,3091 else => break :ct,
3074 }3092 }
...@@ -3080,7 +3098,7 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro...@@ -3080,7 +3098,7 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
30803098
3081 const candidate = block.instructions.items[search_index];3099 const candidate = block.instructions.items[search_index];
3082 switch (air_tags[candidate]) {3100 switch (air_tags[candidate]) {
3083 .dbg_stmt => continue,3101 .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue,
3084 .alloc => {3102 .alloc => {
3085 if (Air.indexToRef(candidate) != alloc) break :ct;3103 if (Air.indexToRef(candidate) != alloc) break :ct;
3086 break;3104 break;
...@@ -3298,7 +3316,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -3298,7 +3316,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
32983316
3299 const candidate = block.instructions.items[search_index];3317 const candidate = block.instructions.items[search_index];
3300 switch (air_tags[candidate]) {3318 switch (air_tags[candidate]) {
3301 .dbg_stmt => continue,3319 .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue,
3302 .store => break candidate,3320 .store => break candidate,
3303 else => break :ct,3321 else => break :ct,
3304 }3322 }
...@@ -3310,7 +3328,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -3310,7 +3328,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
33103328
3311 const candidate = block.instructions.items[search_index];3329 const candidate = block.instructions.items[search_index];
3312 switch (air_tags[candidate]) {3330 switch (air_tags[candidate]) {
3313 .dbg_stmt => continue,3331 .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue,
3314 .bitcast => break candidate,3332 .bitcast => break candidate,
3315 else => break :ct,3333 else => break :ct,
3316 }3334 }
...@@ -3322,7 +3340,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -3322,7 +3340,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
33223340
3323 const candidate = block.instructions.items[search_index];3341 const candidate = block.instructions.items[search_index];
3324 switch (air_tags[candidate]) {3342 switch (air_tags[candidate]) {
3325 .dbg_stmt => continue,3343 .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue,
3326 .constant => break candidate,3344 .constant => break candidate,
3327 else => break :ct,3345 else => break :ct,
3328 }3346 }
...@@ -3596,8 +3614,6 @@ fn validateUnionInit(...@@ -3596,8 +3614,6 @@ fn validateUnionInit(
3596 union_ptr: Air.Inst.Ref,3614 union_ptr: Air.Inst.Ref,
3597 is_comptime: bool,3615 is_comptime: bool,
3598) CompileError!void {3616) CompileError!void {
3599 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
3600
3601 if (instrs.len != 1) {3617 if (instrs.len != 1) {
3602 const msg = msg: {3618 const msg = msg: {
3603 const msg = try sema.errMsg(3619 const msg = try sema.errMsg(
...@@ -3631,7 +3647,8 @@ fn validateUnionInit(...@@ -3631,7 +3647,8 @@ fn validateUnionInit(
3631 const field_src: LazySrcLoc = .{ .node_offset_initializer = field_ptr_data.src_node };3647 const field_src: LazySrcLoc = .{ .node_offset_initializer = field_ptr_data.src_node };
3632 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;3648 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
3633 const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start);3649 const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start);
3634 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src);3650 // Validate the field access but ignore the index since we want the tag enum field index.
3651 _ = try sema.unionFieldIndex(block, union_ty, field_name, field_src);
3635 const air_tags = sema.air_instructions.items(.tag);3652 const air_tags = sema.air_instructions.items(.tag);
3636 const air_datas = sema.air_instructions.items(.data);3653 const air_datas = sema.air_instructions.items(.data);
3637 const field_ptr_air_ref = sema.inst_map.get(field_ptr).?;3654 const field_ptr_air_ref = sema.inst_map.get(field_ptr).?;
...@@ -3690,7 +3707,9 @@ fn validateUnionInit(...@@ -3690,7 +3707,9 @@ fn validateUnionInit(
3690 break;3707 break;
3691 }3708 }
36923709
3693 const tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index);3710 const tag_ty = union_ty.unionTagTypeHypothetical();
3711 const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);
3712 const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
36943713
3695 if (init_val) |val| {3714 if (init_val) |val| {
3696 // Our task is to delete all the `field_ptr` and `store` instructions, and insert3715 // Our task is to delete all the `field_ptr` and `store` instructions, and insert
...@@ -3707,7 +3726,7 @@ fn validateUnionInit(...@@ -3707,7 +3726,7 @@ fn validateUnionInit(
3707 }3726 }
37083727
3709 try sema.requireFunctionBlock(block, init_src);3728 try sema.requireFunctionBlock(block, init_src);
3710 const new_tag = try sema.addConstant(union_obj.tag_ty, tag_val);3729 const new_tag = try sema.addConstant(tag_ty, tag_val);
3711 _ = try block.addBinOp(.set_union_tag, union_ptr, new_tag);3730 _ = try block.addBinOp(.set_union_tag, union_ptr, new_tag);
3712}3731}
37133732
...@@ -3754,11 +3773,13 @@ fn validateStructInit(...@@ -3754,11 +3773,13 @@ fn validateStructInit(
3754 }3773 }
37553774
3756 var root_msg: ?*Module.ErrorMsg = null;3775 var root_msg: ?*Module.ErrorMsg = null;
3776 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
37573777
3758 const struct_ptr = try sema.resolveInst(struct_ptr_zir_ref);3778 const struct_ptr = try sema.resolveInst(struct_ptr_zir_ref);
3759 if ((is_comptime or block.is_comptime) and3779 if ((is_comptime or block.is_comptime) and
3760 (try sema.resolveDefinedValue(block, init_src, struct_ptr)) != null)3780 (try sema.resolveDefinedValue(block, init_src, struct_ptr)) != null)
3761 {3781 {
3782 try sema.resolveStructLayout(block, init_src, struct_ty);
3762 // In this case the only thing we need to do is evaluate the implicit3783 // In this case the only thing we need to do is evaluate the implicit
3763 // store instructions for default field values, and report any missing fields.3784 // store instructions for default field values, and report any missing fields.
3764 // Avoid the cost of the extra machinery for detecting a comptime struct init value.3785 // Avoid the cost of the extra machinery for detecting a comptime struct init value.
...@@ -3929,6 +3950,7 @@ fn validateStructInit(...@@ -3929,6 +3950,7 @@ fn validateStructInit(
3929 }3950 }
39303951
3931 if (root_msg) |msg| {3952 if (root_msg) |msg| {
3953 root_msg = null;
3932 if (struct_ty.castTag(.@"struct")) |struct_obj| {3954 if (struct_ty.castTag(.@"struct")) |struct_obj| {
3933 const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod);3955 const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod);
3934 defer gpa.free(fqn);3956 defer gpa.free(fqn);
...@@ -3952,6 +3974,7 @@ fn validateStructInit(...@@ -3952,6 +3974,7 @@ fn validateStructInit(
3952 try sema.storePtr2(block, init_src, struct_ptr, init_src, struct_init, init_src, .store);3974 try sema.storePtr2(block, init_src, struct_ptr, init_src, struct_init, init_src, .store);
3953 return;3975 return;
3954 }3976 }
3977 try sema.resolveStructLayout(block, init_src, struct_ty);
39553978
3956 // Our task is to insert `store` instructions for all the default field values.3979 // Our task is to insert `store` instructions for all the default field values.
3957 for (found_fields) |field_ptr, i| {3980 for (found_fields) |field_ptr, i| {
...@@ -3987,6 +4010,8 @@ fn zirValidateArrayInit(...@@ -3987,6 +4010,8 @@ fn zirValidateArrayInit(
3987 if (instrs.len != array_len and array_ty.isTuple()) {4010 if (instrs.len != array_len and array_ty.isTuple()) {
3988 const struct_obj = array_ty.castTag(.tuple).?.data;4011 const struct_obj = array_ty.castTag(.tuple).?.data;
3989 var root_msg: ?*Module.ErrorMsg = null;4012 var root_msg: ?*Module.ErrorMsg = null;
4013 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
4014
3990 for (struct_obj.values) |default_val, i| {4015 for (struct_obj.values) |default_val, i| {
3991 if (i < instrs.len) continue;4016 if (i < instrs.len) continue;
39924017
...@@ -4001,6 +4026,7 @@ fn zirValidateArrayInit(...@@ -4001,6 +4026,7 @@ fn zirValidateArrayInit(
4001 }4026 }
40024027
4003 if (root_msg) |msg| {4028 if (root_msg) |msg| {
4029 root_msg = null;
4004 return sema.failWithOwnedErrorMsg(msg);4030 return sema.failWithOwnedErrorMsg(msg);
4005 }4031 }
4006 }4032 }
...@@ -4038,6 +4064,19 @@ fn zirValidateArrayInit(...@@ -4038,6 +4064,19 @@ fn zirValidateArrayInit(
40384064
4039 // Determine whether the value stored to this pointer is comptime-known.4065 // Determine whether the value stored to this pointer is comptime-known.
40404066
4067 if (array_ty.isTuple()) {
4068 if (array_ty.structFieldValueComptime(i)) |opv| {
4069 element_vals[i] = opv;
4070 continue;
4071 }
4072 } else {
4073 // Array has one possible value, so value is always comptime-known
4074 if (opt_opv) |opv| {
4075 element_vals[i] = opv;
4076 continue;
4077 }
4078 }
4079
4041 const elem_ptr_air_ref = sema.inst_map.get(elem_ptr).?;4080 const elem_ptr_air_ref = sema.inst_map.get(elem_ptr).?;
4042 const elem_ptr_air_inst = Air.refToIndex(elem_ptr_air_ref).?;4081 const elem_ptr_air_inst = Air.refToIndex(elem_ptr_air_ref).?;
4043 // Find the block index of the elem_ptr so that we can look at the next4082 // Find the block index of the elem_ptr so that we can look at the next
...@@ -4054,19 +4093,6 @@ fn zirValidateArrayInit(...@@ -4054,19 +4093,6 @@ fn zirValidateArrayInit(
4054 }4093 }
4055 first_block_index = @minimum(first_block_index, block_index);4094 first_block_index = @minimum(first_block_index, block_index);
40564095
4057 if (array_ty.isTuple()) {
4058 if (array_ty.structFieldValueComptime(i)) |opv| {
4059 element_vals[i] = opv;
4060 continue;
4061 }
4062 } else {
4063 // Array has one possible value, so value is always comptime-known
4064 if (opt_opv) |opv| {
4065 element_vals[i] = opv;
4066 continue;
4067 }
4068 }
4069
4070 // If the next instructon is a store with a comptime operand, this element4096 // If the next instructon is a store with a comptime operand, this element
4071 // is comptime.4097 // is comptime.
4072 const next_air_inst = block.instructions.items[block_index + 1];4098 const next_air_inst = block.instructions.items[block_index + 1];
...@@ -4433,43 +4459,6 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v...@@ -4433,43 +4459,6 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v
4433 return sema.storePtr2(block, src, ptr, src, operand, src, if (is_ret) .ret_ptr else .store);4459 return sema.storePtr2(block, src, ptr, src, operand, src, if (is_ret) .ret_ptr else .store);
4434}4460}
44354461
4436fn zirParamType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
4437 const callee_src = sema.src;
4438
4439 const inst_data = sema.code.instructions.items(.data)[inst].param_type;
4440 const callee = try sema.resolveInst(inst_data.callee);
4441 const callee_ty = sema.typeOf(callee);
4442 var param_index = inst_data.param_index;
4443
4444 const fn_ty = if (callee_ty.tag() == .bound_fn) fn_ty: {
4445 const bound_fn_val = try sema.resolveConstValue(block, .unneeded, callee, undefined);
4446 const bound_fn = bound_fn_val.castTag(.bound_fn).?.data;
4447 const fn_ty = sema.typeOf(bound_fn.func_inst);
4448 param_index += 1;
4449 break :fn_ty fn_ty;
4450 } else callee_ty;
4451
4452 const fn_info = if (fn_ty.zigTypeTag() == .Pointer)
4453 fn_ty.childType().fnInfo()
4454 else
4455 fn_ty.fnInfo();
4456
4457 if (param_index >= fn_info.param_types.len) {
4458 if (fn_info.is_var_args) {
4459 return sema.addType(Type.initTag(.var_args_param));
4460 }
4461 // TODO implement begin_call/end_call Zir instructions and check
4462 // argument count before casting arguments to parameter types.
4463 return sema.fail(block, callee_src, "wrong number of arguments", .{});
4464 }
4465
4466 if (fn_info.param_types[param_index].tag() == .generic_poison) {
4467 return sema.addType(Type.initTag(.var_args_param));
4468 }
4469
4470 return sema.addType(fn_info.param_types[param_index]);
4471}
4472
4473fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {4462fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
4474 const tracy = trace(@src());4463 const tracy = trace(@src());
4475 defer tracy.end();4464 defer tracy.end();
...@@ -4775,7 +4764,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -4775,7 +4764,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
4775fn zirSuspendBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {4764fn zirSuspendBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
4776 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;4765 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
4777 const src = inst_data.src();4766 const src = inst_data.src();
4778 return sema.fail(parent_block, src, "TODO: implement Sema.zirSuspendBlock", .{});4767 return sema.failWithUseOfAsync(parent_block, src);
4779}4768}
47804769
4781fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {4770fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -5403,6 +5392,17 @@ fn lookupInNamespace(...@@ -5403,6 +5392,17 @@ fn lookupInNamespace(
5403 }5392 }
5404 }5393 }
54055394
5395 {
5396 var i: usize = 0;
5397 while (i < candidates.items.len) {
5398 if (candidates.items[i] == sema.owner_decl_index) {
5399 _ = candidates.orderedRemove(i);
5400 } else {
5401 i += 1;
5402 }
5403 }
5404 }
5405
5406 switch (candidates.items.len) {5406 switch (candidates.items.len) {
5407 0 => {},5407 0 => {},
5408 1 => {5408 1 => {
...@@ -5439,6 +5439,19 @@ fn lookupInNamespace(...@@ -5439,6 +5439,19 @@ fn lookupInNamespace(
5439 return null;5439 return null;
5440}5440}
54415441
5442fn funcDeclSrc(sema: *Sema, block: *Block, src: LazySrcLoc, func_inst: Air.Inst.Ref) !?Module.SrcLoc {
5443 const func_val = (try sema.resolveMaybeUndefVal(block, src, func_inst)) orelse return null;
5444 if (func_val.isUndef()) return null;
5445 const owner_decl_index = switch (func_val.tag()) {
5446 .extern_fn => func_val.castTag(.extern_fn).?.data.owner_decl,
5447 .function => func_val.castTag(.function).?.data.owner_decl,
5448 .decl_ref => sema.mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data.owner_decl,
5449 else => return null,
5450 };
5451 const owner_decl = sema.mod.declPtr(owner_decl_index);
5452 return owner_decl.srcLoc();
5453}
5454
5442fn zirCall(5455fn zirCall(
5443 sema: *Sema,5456 sema: *Sema,
5444 block: *Block,5457 block: *Block,
...@@ -5451,13 +5464,14 @@ fn zirCall(...@@ -5451,13 +5464,14 @@ fn zirCall(
5451 const func_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node };5464 const func_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node };
5452 const call_src = inst_data.src();5465 const call_src = inst_data.src();
5453 const extra = sema.code.extraData(Zir.Inst.Call, inst_data.payload_index);5466 const extra = sema.code.extraData(Zir.Inst.Call, inst_data.payload_index);
5454 const args = sema.code.refSlice(extra.end, extra.data.flags.args_len);5467 const args_len = extra.data.flags.args_len;
54555468
5456 const modifier = @intToEnum(std.builtin.CallOptions.Modifier, extra.data.flags.packed_modifier);5469 const modifier = @intToEnum(std.builtin.CallOptions.Modifier, extra.data.flags.packed_modifier);
5457 const ensure_result_used = extra.data.flags.ensure_result_used;5470 const ensure_result_used = extra.data.flags.ensure_result_used;
54585471
5459 var func = try sema.resolveInst(extra.data.callee);5472 var func = try sema.resolveInst(extra.data.callee);
5460 var resolved_args: []Air.Inst.Ref = undefined;5473 var resolved_args: []Air.Inst.Ref = undefined;
5474 var arg_index: u32 = 0;
54615475
5462 const func_type = sema.typeOf(func);5476 const func_type = sema.typeOf(func);
54635477
...@@ -5468,16 +5482,93 @@ fn zirCall(...@@ -5468,16 +5482,93 @@ fn zirCall(
5468 const bound_func = try sema.resolveValue(block, .unneeded, func, undefined);5482 const bound_func = try sema.resolveValue(block, .unneeded, func, undefined);
5469 const bound_data = &bound_func.cast(Value.Payload.BoundFn).?.data;5483 const bound_data = &bound_func.cast(Value.Payload.BoundFn).?.data;
5470 func = bound_data.func_inst;5484 func = bound_data.func_inst;
5471 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args.len + 1);5485 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len + 1);
5472 resolved_args[0] = bound_data.arg0_inst;5486 resolved_args[arg_index] = bound_data.arg0_inst;
5473 for (args) |zir_arg, i| {5487 arg_index += 1;
5474 resolved_args[i + 1] = try sema.resolveInst(zir_arg);
5475 }
5476 } else {5488 } else {
5477 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args.len);5489 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len);
5478 for (args) |zir_arg, i| {5490 }
5479 resolved_args[i] = try sema.resolveInst(zir_arg);5491 const total_args = args_len + @boolToInt(bound_arg_src != null);
5492
5493 const callee_ty = sema.typeOf(func);
5494 const func_ty = func_ty: {
5495 switch (callee_ty.zigTypeTag()) {
5496 .Fn => break :func_ty callee_ty,
5497 .Pointer => {
5498 const ptr_info = callee_ty.ptrInfo().data;
5499 if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag() == .Fn) {
5500 break :func_ty ptr_info.pointee_type;
5501 }
5502 },
5503 else => {},
5504 }
5505 return sema.fail(block, func_src, "type '{}' not a function", .{callee_ty.fmt(sema.mod)});
5506 };
5507 const func_ty_info = func_ty.fnInfo();
5508
5509 const fn_params_len = func_ty_info.param_types.len;
5510 check_args: {
5511 if (func_ty_info.is_var_args) {
5512 assert(func_ty_info.cc == .C);
5513 if (total_args >= fn_params_len) break :check_args;
5514 } else if (fn_params_len == total_args) {
5515 break :check_args;
5516 }
5517
5518 const decl_src = try sema.funcDeclSrc(block, func_src, func);
5519 const member_str = if (bound_arg_src != null) "member function " else "";
5520 const variadic_str = if (func_ty_info.is_var_args) "at least " else "";
5521 const msg = msg: {
5522 const msg = try sema.errMsg(
5523 block,
5524 func_src,
5525 "{s}expected {s}{d} argument(s), found {d}",
5526 .{
5527 member_str,
5528 variadic_str,
5529 fn_params_len - @boolToInt(bound_arg_src != null),
5530 args_len,
5531 },
5532 );
5533 errdefer msg.destroy(sema.gpa);
5534
5535 if (decl_src) |some| try sema.mod.errNoteNonLazy(some, msg, "function declared here", .{});
5536 break :msg msg;
5537 };
5538 return sema.failWithOwnedErrorMsg(msg);
5539 }
5540
5541 const args_body = sema.code.extra[extra.end..];
5542
5543 const parent_comptime = block.is_comptime;
5544 // `extra_index` and `arg_index` are separate since the bound function is passed as the first argument.
5545 var extra_index: usize = 0;
5546 var arg_start: u32 = args_len;
5547 while (extra_index < args_len) : ({
5548 extra_index += 1;
5549 arg_index += 1;
5550 }) {
5551 const arg_end = sema.code.extra[extra.end + extra_index];
5552 defer arg_start = arg_end;
5553
5554 const param_ty = if (arg_index >= fn_params_len or
5555 func_ty_info.param_types[arg_index].tag() == .generic_poison)
5556 Type.initTag(.var_args_param)
5557 else
5558 func_ty_info.param_types[arg_index];
5559
5560 const old_comptime = block.is_comptime;
5561 defer block.is_comptime = old_comptime;
5562 // Generate args to comptime params in comptime block.
5563 block.is_comptime = parent_comptime;
5564 if (arg_index < fn_params_len and func_ty_info.comptime_params[arg_index]) {
5565 block.is_comptime = true;
5480 }5566 }
5567
5568 const param_ty_inst = try sema.addType(param_ty);
5569 try sema.inst_map.put(sema.gpa, inst, param_ty_inst);
5570
5571 resolved_args[arg_index] = try sema.resolveBody(block, args_body[arg_start..arg_end], inst);
5481 }5572 }
54825573
5483 return sema.analyzeCall(block, func, func_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src);5574 return sema.analyzeCall(block, func, func_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src);
...@@ -5487,11 +5578,15 @@ const GenericCallAdapter = struct {...@@ -5487,11 +5578,15 @@ const GenericCallAdapter = struct {
5487 generic_fn: *Module.Fn,5578 generic_fn: *Module.Fn,
5488 precomputed_hash: u64,5579 precomputed_hash: u64,
5489 func_ty_info: Type.Payload.Function.Data,5580 func_ty_info: Type.Payload.Function.Data,
5490 /// Unlike comptime_args, the Type here is not always present.5581 args: []const Arg,
5491 /// .generic_poison is used to communicate non-anytype parameters.
5492 comptime_tvs: []const TypedValue,
5493 module: *Module,5582 module: *Module,
54945583
5584 const Arg = struct {
5585 ty: Type,
5586 val: Value,
5587 is_anytype: bool,
5588 };
5589
5495 pub fn eql(ctx: @This(), adapted_key: void, other_key: *Module.Fn) bool {5590 pub fn eql(ctx: @This(), adapted_key: void, other_key: *Module.Fn) bool {
5496 _ = adapted_key;5591 _ = adapted_key;
5497 // The generic function Decl is guaranteed to be the first dependency5592 // The generic function Decl is guaranteed to be the first dependency
...@@ -5502,11 +5597,11 @@ const GenericCallAdapter = struct {...@@ -5502,11 +5597,11 @@ const GenericCallAdapter = struct {
55025597
5503 const other_comptime_args = other_key.comptime_args.?;5598 const other_comptime_args = other_key.comptime_args.?;
5504 for (other_comptime_args[0..ctx.func_ty_info.param_types.len]) |other_arg, i| {5599 for (other_comptime_args[0..ctx.func_ty_info.param_types.len]) |other_arg, i| {
5505 const this_arg = ctx.comptime_tvs[i];5600 const this_arg = ctx.args[i];
5506 const this_is_comptime = this_arg.val.tag() != .generic_poison;5601 const this_is_comptime = this_arg.val.tag() != .generic_poison;
5507 const other_is_comptime = other_arg.val.tag() != .generic_poison;5602 const other_is_comptime = other_arg.val.tag() != .generic_poison;
5508 const this_is_anytype = this_arg.ty.tag() != .generic_poison;5603 const this_is_anytype = this_arg.is_anytype;
5509 const other_is_anytype = other_key.anytype_args[i];5604 const other_is_anytype = other_key.isAnytypeParam(ctx.module, @intCast(u32, i));
55105605
5511 if (other_is_anytype != this_is_anytype) return false;5606 if (other_is_anytype != this_is_anytype) return false;
5512 if (other_is_comptime != this_is_comptime) return false;5607 if (other_is_comptime != this_is_comptime) return false;
...@@ -5524,7 +5619,17 @@ const GenericCallAdapter = struct {...@@ -5524,7 +5619,17 @@ const GenericCallAdapter = struct {
5524 }5619 }
5525 } else if (this_is_comptime) {5620 } else if (this_is_comptime) {
5526 // Both are comptime parameters but not anytype parameters.5621 // Both are comptime parameters but not anytype parameters.
5527 if (!this_arg.val.eql(other_arg.val, other_arg.ty, ctx.module)) {5622 // We assert no error is possible here because any lazy values must be resolved
5623 // before inserting into the generic function hash map.
5624 const is_eql = Value.eqlAdvanced(
5625 this_arg.val,
5626 this_arg.ty,
5627 other_arg.val,
5628 other_arg.ty,
5629 ctx.module,
5630 null,
5631 ) catch unreachable;
5632 if (!is_eql) {
5528 return false;5633 return false;
5529 }5634 }
5530 }5635 }
...@@ -5540,6 +5645,37 @@ const GenericCallAdapter = struct {...@@ -5540,6 +5645,37 @@ const GenericCallAdapter = struct {
5540 }5645 }
5541};5646};
55425647
5648fn addComptimeReturnTypeNote(
5649 sema: *Sema,
5650 block: *Block,
5651 func: Air.Inst.Ref,
5652 func_src: LazySrcLoc,
5653 return_ty: Type,
5654 parent: *Module.ErrorMsg,
5655 requires_comptime: bool,
5656) !void {
5657 if (!requires_comptime) return;
5658
5659 const src_loc = if (try sema.funcDeclSrc(block, func_src, func)) |capture| blk: {
5660 var src_loc = capture;
5661 src_loc.lazy = .{ .node_offset_fn_type_ret_ty = 0 };
5662 break :blk src_loc;
5663 } else blk: {
5664 const src_decl = sema.mod.declPtr(block.src_decl);
5665 break :blk func_src.toSrcLoc(src_decl);
5666 };
5667 if (return_ty.tag() == .generic_poison) {
5668 return sema.mod.errNoteNonLazy(src_loc, parent, "generic function is instantiated with a comptime only return type", .{});
5669 }
5670 try sema.mod.errNoteNonLazy(
5671 src_loc,
5672 parent,
5673 "function is being called at comptime because it returns a comptime only type '{}'",
5674 .{return_ty.fmt(sema.mod)},
5675 );
5676 try sema.explainWhyTypeIsComptime(block, func_src, parent, src_loc, return_ty);
5677}
5678
5543fn analyzeCall(5679fn analyzeCall(
5544 sema: *Sema,5680 sema: *Sema,
5545 block: *Block,5681 block: *Block,
...@@ -5571,13 +5707,20 @@ fn analyzeCall(...@@ -5571,13 +5707,20 @@ fn analyzeCall(
5571 const func_ty_info = func_ty.fnInfo();5707 const func_ty_info = func_ty.fnInfo();
5572 const cc = func_ty_info.cc;5708 const cc = func_ty_info.cc;
5573 if (cc == .Naked) {5709 if (cc == .Naked) {
5574 // TODO add error note: declared here5710 const decl_src = try sema.funcDeclSrc(block, func_src, func);
5575 return sema.fail(5711 const msg = msg: {
5576 block,5712 const msg = try sema.errMsg(
5577 func_src,5713 block,
5578 "unable to call function with naked calling convention",5714 func_src,
5579 .{},5715 "unable to call function with naked calling convention",
5580 );5716 .{},
5717 );
5718 errdefer msg.destroy(sema.gpa);
5719
5720 if (decl_src) |some| try sema.mod.errNoteNonLazy(some, msg, "function declared here", .{});
5721 break :msg msg;
5722 };
5723 return sema.failWithOwnedErrorMsg(msg);
5581 }5724 }
5582 const fn_params_len = func_ty_info.param_types.len;5725 const fn_params_len = func_ty_info.param_types.len;
5583 if (func_ty_info.is_var_args) {5726 if (func_ty_info.is_var_args) {
...@@ -5612,7 +5755,7 @@ fn analyzeCall(...@@ -5612,7 +5755,7 @@ fn analyzeCall(
5612 .never_inline => Air.Inst.Tag.call_never_inline,5755 .never_inline => Air.Inst.Tag.call_never_inline,
5613 .always_tail => Air.Inst.Tag.call_always_tail,5756 .always_tail => Air.Inst.Tag.call_always_tail,
56145757
5615 .async_kw => return sema.fail(block, call_src, "TODO implement async call", .{}),5758 .async_kw => return sema.failWithUseOfAsync(block, call_src),
5616 };5759 };
56175760
5618 if (modifier == .never_inline and func_ty_info.cc == .Inline) {5761 if (modifier == .never_inline and func_ty_info.cc == .Inline) {
...@@ -5623,9 +5766,11 @@ fn analyzeCall(...@@ -5623,9 +5766,11 @@ fn analyzeCall(
56235766
5624 var is_generic_call = func_ty_info.is_generic;5767 var is_generic_call = func_ty_info.is_generic;
5625 var is_comptime_call = block.is_comptime or modifier == .compile_time;5768 var is_comptime_call = block.is_comptime or modifier == .compile_time;
5769 var comptime_only_ret_ty = false;
5626 if (!is_comptime_call) {5770 if (!is_comptime_call) {
5627 if (sema.typeRequiresComptime(block, func_src, func_ty_info.return_type)) |ct| {5771 if (sema.typeRequiresComptime(block, func_src, func_ty_info.return_type)) |ct| {
5628 is_comptime_call = ct;5772 is_comptime_call = ct;
5773 comptime_only_ret_ty = ct;
5629 } else |err| switch (err) {5774 } else |err| switch (err) {
5630 error.GenericPoison => is_generic_call = true,5775 error.GenericPoison => is_generic_call = true,
5631 else => |e| return e,5776 else => |e| return e,
...@@ -5654,6 +5799,7 @@ fn analyzeCall(...@@ -5654,6 +5799,7 @@ fn analyzeCall(
5654 error.ComptimeReturn => {5799 error.ComptimeReturn => {
5655 is_inline_call = true;5800 is_inline_call = true;
5656 is_comptime_call = true;5801 is_comptime_call = true;
5802 comptime_only_ret_ty = true;
5657 },5803 },
5658 else => |e| return e,5804 else => |e| return e,
5659 }5805 }
...@@ -5664,8 +5810,12 @@ fn analyzeCall(...@@ -5664,8 +5810,12 @@ fn analyzeCall(
5664 }5810 }
56655811
5666 const result: Air.Inst.Ref = if (is_inline_call) res: {5812 const result: Air.Inst.Ref = if (is_inline_call) res: {
5667 // TODO explain why function is being called at comptime5813 const func_val = sema.resolveConstValue(block, func_src, func, "function being called at comptime must be comptime known") catch |err| {
5668 const func_val = try sema.resolveConstValue(block, func_src, func, "function being called at comptime must be comptime known");5814 if (err == error.AnalysisFail and sema.err != null) {
5815 try sema.addComptimeReturnTypeNote(block, func, func_src, func_ty_info.return_type, sema.err.?, comptime_only_ret_ty);
5816 }
5817 return err;
5818 };
5669 const module_fn = switch (func_val.tag()) {5819 const module_fn = switch (func_val.tag()) {
5670 .decl_ref => mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data,5820 .decl_ref => mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data,
5671 .function => func_val.castTag(.function).?.data,5821 .function => func_val.castTag(.function).?.data,
...@@ -5777,12 +5927,16 @@ fn analyzeCall(...@@ -5777,12 +5927,16 @@ fn analyzeCall(
5777 is_comptime_call,5927 is_comptime_call,
5778 &should_memoize,5928 &should_memoize,
5779 memoized_call_key,5929 memoized_call_key,
5930 // last 4 arguments are only used when reporting errors
5931 undefined,
5932 undefined,
5933 undefined,
5934 undefined,
5780 ) catch |err| switch (err) {5935 ) catch |err| switch (err) {
5781 error.NeededSourceLocation => {5936 error.NeededSourceLocation => {
5782 sema.inst_map.clearRetainingCapacity();5937 _ = sema.inst_map.remove(inst);
5783 const decl = sema.mod.declPtr(block.src_decl);5938 const decl = sema.mod.declPtr(block.src_decl);
5784 child_block.src_decl = block.src_decl;5939 child_block.src_decl = block.src_decl;
5785 arg_i = 0;
5786 try sema.analyzeInlineCallArg(5940 try sema.analyzeInlineCallArg(
5787 block,5941 block,
5788 &child_block,5942 &child_block,
...@@ -5794,6 +5948,10 @@ fn analyzeCall(...@@ -5794,6 +5948,10 @@ fn analyzeCall(
5794 is_comptime_call,5948 is_comptime_call,
5795 &should_memoize,5949 &should_memoize,
5796 memoized_call_key,5950 memoized_call_key,
5951 func,
5952 func_src,
5953 func_ty_info.return_type,
5954 comptime_only_ret_ty,
5797 );5955 );
5798 return error.AnalysisFail;5956 return error.AnalysisFail;
5799 },5957 },
...@@ -5956,7 +6114,18 @@ fn analyzeCall(...@@ -5956,7 +6114,18 @@ fn analyzeCall(
5956 else => |e| return e,6114 else => |e| return e,
5957 };6115 };
5958 } else {6116 } else {
5959 args[i] = uncasted_arg;6117 args[i] = sema.coerceVarArgParam(block, uncasted_arg, .unneeded) catch |err| switch (err) {
6118 error.NeededSourceLocation => {
6119 const decl = sema.mod.declPtr(block.src_decl);
6120 _ = try sema.coerceVarArgParam(
6121 block,
6122 uncasted_arg,
6123 Module.argSrc(call_src.node_offset.x, sema.gpa, decl, i, bound_arg_src),
6124 );
6125 return error.AnalysisFail;
6126 },
6127 else => |e| return e,
6128 };
5960 }6129 }
5961 }6130 }
59626131
...@@ -5998,6 +6167,10 @@ fn analyzeInlineCallArg(...@@ -5998,6 +6167,10 @@ fn analyzeInlineCallArg(
5998 is_comptime_call: bool,6167 is_comptime_call: bool,
5999 should_memoize: *bool,6168 should_memoize: *bool,
6000 memoized_call_key: Module.MemoizedCall.Key,6169 memoized_call_key: Module.MemoizedCall.Key,
6170 func: Air.Inst.Ref,
6171 func_src: LazySrcLoc,
6172 ret_ty: Type,
6173 comptime_only_ret_ty: bool,
6001) !void {6174) !void {
6002 const zir_tags = sema.code.instructions.items(.tag);6175 const zir_tags = sema.code.instructions.items(.tag);
6003 switch (zir_tags[inst]) {6176 switch (zir_tags[inst]) {
...@@ -6013,14 +6186,23 @@ fn analyzeInlineCallArg(...@@ -6013,14 +6186,23 @@ fn analyzeInlineCallArg(
6013 new_fn_info.param_types[arg_i.*] = param_ty;6186 new_fn_info.param_types[arg_i.*] = param_ty;
6014 const uncasted_arg = uncasted_args[arg_i.*];6187 const uncasted_arg = uncasted_args[arg_i.*];
6015 if (try sema.typeRequiresComptime(arg_block, arg_src, param_ty)) {6188 if (try sema.typeRequiresComptime(arg_block, arg_src, param_ty)) {
6016 _ = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to parameter with comptime only type must be comptime known");6189 _ = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to parameter with comptime only type must be comptime known") catch |err| {
6190 if (err == error.AnalysisFail and sema.err != null) {
6191 try sema.addComptimeReturnTypeNote(arg_block, func, func_src, ret_ty, sema.err.?, comptime_only_ret_ty);
6192 }
6193 return err;
6194 };
6017 }6195 }
6018 const casted_arg = try sema.coerce(arg_block, param_ty, uncasted_arg, arg_src);6196 const casted_arg = try sema.coerce(arg_block, param_ty, uncasted_arg, arg_src);
6019 try sema.inst_map.putNoClobber(sema.gpa, inst, casted_arg);6197 try sema.inst_map.putNoClobber(sema.gpa, inst, casted_arg);
60206198
6021 if (is_comptime_call) {6199 if (is_comptime_call) {
6022 // TODO explain why function is being called at comptime6200 const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, casted_arg, "argument to function being called at comptime must be comptime known") catch |err| {
6023 const arg_val = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, casted_arg, "argument to function being called at comptime must be comptime known");6201 if (err == error.AnalysisFail and sema.err != null) {
6202 try sema.addComptimeReturnTypeNote(arg_block, func, func_src, ret_ty, sema.err.?, comptime_only_ret_ty);
6203 }
6204 return err;
6205 };
6024 switch (arg_val.tag()) {6206 switch (arg_val.tag()) {
6025 .generic_poison, .generic_poison_type => {6207 .generic_poison, .generic_poison_type => {
6026 // This function is currently evaluated as part of an as-of-yet unresolvable6208 // This function is currently evaluated as part of an as-of-yet unresolvable
...@@ -6050,8 +6232,12 @@ fn analyzeInlineCallArg(...@@ -6050,8 +6232,12 @@ fn analyzeInlineCallArg(
6050 try sema.inst_map.putNoClobber(sema.gpa, inst, uncasted_arg);6232 try sema.inst_map.putNoClobber(sema.gpa, inst, uncasted_arg);
60516233
6052 if (is_comptime_call) {6234 if (is_comptime_call) {
6053 // TODO explain why function is being called at comptime6235 const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to function being called at comptime must be comptime known") catch |err| {
6054 const arg_val = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to function being called at comptime must be comptime known");6236 if (err == error.AnalysisFail and sema.err != null) {
6237 try sema.addComptimeReturnTypeNote(arg_block, func, func_src, ret_ty, sema.err.?, comptime_only_ret_ty);
6238 }
6239 return err;
6240 };
6055 switch (arg_val.tag()) {6241 switch (arg_val.tag()) {
6056 .generic_poison, .generic_poison_type => {6242 .generic_poison, .generic_poison_type => {
6057 // This function is currently evaluated as part of an as-of-yet unresolvable6243 // This function is currently evaluated as part of an as-of-yet unresolvable
...@@ -6157,8 +6343,7 @@ fn instantiateGenericCall(...@@ -6157,8 +6343,7 @@ fn instantiateGenericCall(
6157 var hasher = std.hash.Wyhash.init(0);6343 var hasher = std.hash.Wyhash.init(0);
6158 std.hash.autoHash(&hasher, @ptrToInt(module_fn));6344 std.hash.autoHash(&hasher, @ptrToInt(module_fn));
61596345
6160 const comptime_tvs = try sema.arena.alloc(TypedValue, func_ty_info.param_types.len);6346 const generic_args = try sema.arena.alloc(GenericCallAdapter.Arg, func_ty_info.param_types.len);
6161
6162 {6347 {
6163 var i: usize = 0;6348 var i: usize = 0;
6164 for (fn_info.param_body) |inst| {6349 for (fn_info.param_body) |inst| {
...@@ -6182,8 +6367,9 @@ fn instantiateGenericCall(...@@ -6182,8 +6367,9 @@ fn instantiateGenericCall(
6182 else => continue,6367 else => continue,
6183 }6368 }
61846369
6370 const arg_ty = sema.typeOf(uncasted_args[i]);
6371
6185 if (is_comptime) {6372 if (is_comptime) {
6186 const arg_ty = sema.typeOf(uncasted_args[i]);
6187 const arg_val = sema.analyzeGenericCallArgVal(block, .unneeded, uncasted_args[i]) catch |err| switch (err) {6373 const arg_val = sema.analyzeGenericCallArgVal(block, .unneeded, uncasted_args[i]) catch |err| switch (err) {
6188 error.NeededSourceLocation => {6374 error.NeededSourceLocation => {
6189 const decl = sema.mod.declPtr(block.src_decl);6375 const decl = sema.mod.declPtr(block.src_decl);
...@@ -6196,27 +6382,30 @@ fn instantiateGenericCall(...@@ -6196,27 +6382,30 @@ fn instantiateGenericCall(
6196 arg_val.hash(arg_ty, &hasher, mod);6382 arg_val.hash(arg_ty, &hasher, mod);
6197 if (is_anytype) {6383 if (is_anytype) {
6198 arg_ty.hashWithHasher(&hasher, mod);6384 arg_ty.hashWithHasher(&hasher, mod);
6199 comptime_tvs[i] = .{6385 generic_args[i] = .{
6200 .ty = arg_ty,6386 .ty = arg_ty,
6201 .val = arg_val,6387 .val = arg_val,
6388 .is_anytype = true,
6202 };6389 };
6203 } else {6390 } else {
6204 comptime_tvs[i] = .{6391 generic_args[i] = .{
6205 .ty = Type.initTag(.generic_poison),6392 .ty = arg_ty,
6206 .val = arg_val,6393 .val = arg_val,
6394 .is_anytype = false,
6207 };6395 };
6208 }6396 }
6209 } else if (is_anytype) {6397 } else if (is_anytype) {
6210 const arg_ty = sema.typeOf(uncasted_args[i]);
6211 arg_ty.hashWithHasher(&hasher, mod);6398 arg_ty.hashWithHasher(&hasher, mod);
6212 comptime_tvs[i] = .{6399 generic_args[i] = .{
6213 .ty = arg_ty,6400 .ty = arg_ty,
6214 .val = Value.initTag(.generic_poison),6401 .val = Value.initTag(.generic_poison),
6402 .is_anytype = true,
6215 };6403 };
6216 } else {6404 } else {
6217 comptime_tvs[i] = .{6405 generic_args[i] = .{
6218 .ty = Type.initTag(.generic_poison),6406 .ty = arg_ty,
6219 .val = Value.initTag(.generic_poison),6407 .val = Value.initTag(.generic_poison),
6408 .is_anytype = false,
6220 };6409 };
6221 }6410 }
62226411
...@@ -6230,7 +6419,7 @@ fn instantiateGenericCall(...@@ -6230,7 +6419,7 @@ fn instantiateGenericCall(
6230 .generic_fn = module_fn,6419 .generic_fn = module_fn,
6231 .precomputed_hash = precomputed_hash,6420 .precomputed_hash = precomputed_hash,
6232 .func_ty_info = func_ty_info,6421 .func_ty_info = func_ty_info,
6233 .comptime_tvs = comptime_tvs,6422 .args = generic_args,
6234 .module = mod,6423 .module = mod,
6235 };6424 };
6236 const gop = try mod.monomorphed_funcs.getOrPutAdapted(gpa, {}, adapter);6425 const gop = try mod.monomorphed_funcs.getOrPutAdapted(gpa, {}, adapter);
...@@ -6261,6 +6450,7 @@ fn instantiateGenericCall(...@@ -6261,6 +6450,7 @@ fn instantiateGenericCall(
6261 new_decl.is_exported = fn_owner_decl.is_exported;6450 new_decl.is_exported = fn_owner_decl.is_exported;
6262 new_decl.has_align = fn_owner_decl.has_align;6451 new_decl.has_align = fn_owner_decl.has_align;
6263 new_decl.has_linksection_or_addrspace = fn_owner_decl.has_linksection_or_addrspace;6452 new_decl.has_linksection_or_addrspace = fn_owner_decl.has_linksection_or_addrspace;
6453 new_decl.@"linksection" = fn_owner_decl.@"linksection";
6264 new_decl.@"addrspace" = fn_owner_decl.@"addrspace";6454 new_decl.@"addrspace" = fn_owner_decl.@"addrspace";
6265 new_decl.zir_decl_index = fn_owner_decl.zir_decl_index;6455 new_decl.zir_decl_index = fn_owner_decl.zir_decl_index;
6266 new_decl.alive = true; // This Decl is called at runtime.6456 new_decl.alive = true; // This Decl is called at runtime.
...@@ -6305,6 +6495,7 @@ fn instantiateGenericCall(...@@ -6305,6 +6495,7 @@ fn instantiateGenericCall(
6305 .comptime_args = try new_decl_arena_allocator.alloc(TypedValue, uncasted_args.len),6495 .comptime_args = try new_decl_arena_allocator.alloc(TypedValue, uncasted_args.len),
6306 .comptime_args_fn_inst = module_fn.zir_body_inst,6496 .comptime_args_fn_inst = module_fn.zir_body_inst,
6307 .preallocated_new_func = new_module_func,6497 .preallocated_new_func = new_module_func,
6498 .is_generic_instantiation = true,
6308 };6499 };
6309 defer child_sema.deinit();6500 defer child_sema.deinit();
63106501
...@@ -6386,12 +6577,9 @@ fn instantiateGenericCall(...@@ -6386,12 +6577,9 @@ fn instantiateGenericCall(
6386 errdefer new_func.deinit(gpa);6577 errdefer new_func.deinit(gpa);
6387 assert(new_func == new_module_func);6578 assert(new_func == new_module_func);
63886579
6389 const anytype_args = try new_decl_arena_allocator.alloc(bool, func_ty_info.param_types.len);
6390 new_func.anytype_args = anytype_args.ptr;
6391 arg_i = 0;6580 arg_i = 0;
6392 for (fn_info.param_body) |inst| {6581 for (fn_info.param_body) |inst| {
6393 var is_comptime = false;6582 var is_comptime = false;
6394 var is_anytype = false;
6395 switch (zir_tags[inst]) {6583 switch (zir_tags[inst]) {
6396 .param => {6584 .param => {
6397 is_comptime = func_ty_info.paramIsComptime(arg_i);6585 is_comptime = func_ty_info.paramIsComptime(arg_i);
...@@ -6400,11 +6588,9 @@ fn instantiateGenericCall(...@@ -6400,11 +6588,9 @@ fn instantiateGenericCall(
6400 is_comptime = true;6588 is_comptime = true;
6401 },6589 },
6402 .param_anytype => {6590 .param_anytype => {
6403 is_anytype = true;
6404 is_comptime = func_ty_info.paramIsComptime(arg_i);6591 is_comptime = func_ty_info.paramIsComptime(arg_i);
6405 },6592 },
6406 .param_anytype_comptime => {6593 .param_anytype_comptime => {
6407 is_anytype = true;
6408 is_comptime = true;6594 is_comptime = true;
6409 },6595 },
6410 else => continue,6596 else => continue,
...@@ -6412,10 +6598,9 @@ fn instantiateGenericCall(...@@ -6412,10 +6598,9 @@ fn instantiateGenericCall(
64126598
6413 // We populate the Type here regardless because it is needed by6599 // We populate the Type here regardless because it is needed by
6414 // `GenericCallAdapter.eql` as well as function body analysis.6600 // `GenericCallAdapter.eql` as well as function body analysis.
6415 // Whether it is anytype is communicated by `anytype_args`.6601 // Whether it is anytype is communicated by `isAnytypeParam`.
6416 const arg = child_sema.inst_map.get(inst).?;6602 const arg = child_sema.inst_map.get(inst).?;
6417 const copied_arg_ty = try child_sema.typeOf(arg).copy(new_decl_arena_allocator);6603 const copied_arg_ty = try child_sema.typeOf(arg).copy(new_decl_arena_allocator);
6418 anytype_args[arg_i] = is_anytype;
64196604
6420 if (try sema.typeRequiresComptime(block, .unneeded, copied_arg_ty)) {6605 if (try sema.typeRequiresComptime(block, .unneeded, copied_arg_ty)) {
6421 is_comptime = true;6606 is_comptime = true;
...@@ -6588,8 +6773,13 @@ fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro...@@ -6588,8 +6773,13 @@ fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
6588 defer tracy.end();6773 defer tracy.end();
65896774
6590 const inst_data = sema.code.instructions.items(.data)[inst].un_node;6775 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
6591 const src = inst_data.src();6776 const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node };
6592 const child_type = try sema.resolveType(block, src, inst_data.operand);6777 const child_type = try sema.resolveType(block, operand_src, inst_data.operand);
6778 if (child_type.zigTypeTag() == .Opaque) {
6779 return sema.fail(block, operand_src, "opaque type '{}' cannot be optional", .{child_type.fmt(sema.mod)});
6780 } else if (child_type.zigTypeTag() == .Null) {
6781 return sema.fail(block, operand_src, "type '{}' cannot be optional", .{child_type.fmt(sema.mod)});
6782 }
6593 const opt_type = try Type.optional(sema.arena, child_type);6783 const opt_type = try Type.optional(sema.arena, child_type);
65946784
6595 return sema.addType(opt_type);6785 return sema.addType(opt_type);
...@@ -6662,6 +6852,9 @@ fn zirAnyframeType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro...@@ -6662,6 +6852,9 @@ fn zirAnyframeType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
6662 defer tracy.end();6852 defer tracy.end();
66636853
6664 const inst_data = sema.code.instructions.items(.data)[inst].un_node;6854 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
6855 if (true) {
6856 return sema.failWithUseOfAsync(block, inst_data.src());
6857 }
6665 const operand_src: LazySrcLoc = .{ .node_offset_anyframe_type = inst_data.src_node };6858 const operand_src: LazySrcLoc = .{ .node_offset_anyframe_type = inst_data.src_node };
6666 const return_type = try sema.resolveType(block, operand_src, inst_data.operand);6859 const return_type = try sema.resolveType(block, operand_src, inst_data.operand);
6667 const anyframe_type = try Type.Tag.anyframe_T.create(sema.arena, return_type);6860 const anyframe_type = try Type.Tag.anyframe_T.create(sema.arena, return_type);
...@@ -6685,6 +6878,15 @@ fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -6685,6 +6878,15 @@ fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
6685 error_set.fmt(sema.mod),6878 error_set.fmt(sema.mod),
6686 });6879 });
6687 }6880 }
6881 if (payload.zigTypeTag() == .Opaque) {
6882 return sema.fail(block, rhs_src, "error union with payload of opaque type '{}' not allowed", .{
6883 payload.fmt(sema.mod),
6884 });
6885 } else if (payload.zigTypeTag() == .ErrorSet) {
6886 return sema.fail(block, rhs_src, "error union with payload of error set type '{}' not allowed", .{
6887 payload.fmt(sema.mod),
6888 });
6889 }
6688 const err_union_ty = try Type.errorUnion(sema.arena, error_set, payload, sema.mod);6890 const err_union_ty = try Type.errorUnion(sema.arena, error_set, payload, sema.mod);
6689 return sema.addType(err_union_ty);6891 return sema.addType(err_union_ty);
6690}6892}
...@@ -6716,11 +6918,10 @@ fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat...@@ -6716,11 +6918,10 @@ fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
6716 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };6918 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
6717 const uncasted_operand = try sema.resolveInst(extra.operand);6919 const uncasted_operand = try sema.resolveInst(extra.operand);
6718 const operand = try sema.coerce(block, Type.anyerror, uncasted_operand, operand_src);6920 const operand = try sema.coerce(block, Type.anyerror, uncasted_operand, operand_src);
6719 const result_ty = Type.u16;
67206921
6721 if (try sema.resolveMaybeUndefVal(block, src, operand)) |val| {6922 if (try sema.resolveMaybeUndefVal(block, src, operand)) |val| {
6722 if (val.isUndef()) {6923 if (val.isUndef()) {
6723 return sema.addConstUndef(result_ty);6924 return sema.addConstUndef(Type.err_int);
6724 }6925 }
6725 switch (val.tag()) {6926 switch (val.tag()) {
6726 .@"error" => {6927 .@"error" => {
...@@ -6729,14 +6930,14 @@ fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat...@@ -6729,14 +6930,14 @@ fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
6729 .base = .{ .tag = .int_u64 },6930 .base = .{ .tag = .int_u64 },
6730 .data = (try sema.mod.getErrorValue(val.castTag(.@"error").?.data.name)).value,6931 .data = (try sema.mod.getErrorValue(val.castTag(.@"error").?.data.name)).value,
6731 };6932 };
6732 return sema.addConstant(result_ty, Value.initPayload(&payload.base));6933 return sema.addConstant(Type.err_int, Value.initPayload(&payload.base));
6733 },6934 },
67346935
6735 // This is not a valid combination with the type `anyerror`.6936 // This is not a valid combination with the type `anyerror`.
6736 .the_only_possible_value => unreachable,6937 .the_only_possible_value => unreachable,
67376938
6738 // Assume it's already encoded as an integer.6939 // Assume it's already encoded as an integer.
6739 else => return sema.addConstant(result_ty, val),6940 else => return sema.addConstant(Type.err_int, val),
6740 }6941 }
6741 }6942 }
67426943
...@@ -6745,14 +6946,14 @@ fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat...@@ -6745,14 +6946,14 @@ fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
6745 if (!op_ty.isAnyError()) {6946 if (!op_ty.isAnyError()) {
6746 const names = op_ty.errorSetNames();6947 const names = op_ty.errorSetNames();
6747 switch (names.len) {6948 switch (names.len) {
6748 0 => return sema.addConstant(result_ty, Value.zero),6949 0 => return sema.addConstant(Type.err_int, Value.zero),
6749 1 => return sema.addIntUnsigned(result_ty, sema.mod.global_error_set.get(names[0]).?),6950 1 => return sema.addIntUnsigned(Type.err_int, sema.mod.global_error_set.get(names[0]).?),
6750 else => {},6951 else => {},
6751 }6952 }
6752 }6953 }
67536954
6754 try sema.requireRuntimeBlock(block, src, operand_src);6955 try sema.requireRuntimeBlock(block, src, operand_src);
6755 return block.addBitCast(result_ty, operand);6956 return block.addBitCast(Type.err_int, operand);
6756}6957}
67576958
6758fn zirIntToError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {6959fn zirIntToError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
...@@ -6763,7 +6964,7 @@ fn zirIntToError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat...@@ -6763,7 +6964,7 @@ fn zirIntToError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
6763 const src = LazySrcLoc.nodeOffset(extra.node);6964 const src = LazySrcLoc.nodeOffset(extra.node);
6764 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };6965 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
6765 const uncasted_operand = try sema.resolveInst(extra.operand);6966 const uncasted_operand = try sema.resolveInst(extra.operand);
6766 const operand = try sema.coerce(block, Type.u16, uncasted_operand, operand_src);6967 const operand = try sema.coerce(block, Type.err_int, uncasted_operand, operand_src);
6767 const target = sema.mod.getTarget();6968 const target = sema.mod.getTarget();
67686969
6769 if (try sema.resolveDefinedValue(block, operand_src, operand)) |value| {6970 if (try sema.resolveDefinedValue(block, operand_src, operand)) |value| {
...@@ -6780,7 +6981,10 @@ fn zirIntToError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat...@@ -6780,7 +6981,10 @@ fn zirIntToError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
6780 try sema.requireRuntimeBlock(block, src, operand_src);6981 try sema.requireRuntimeBlock(block, src, operand_src);
6781 if (block.wantSafety()) {6982 if (block.wantSafety()) {
6782 const is_lt_len = try block.addUnOp(.cmp_lt_errors_len, operand);6983 const is_lt_len = try block.addUnOp(.cmp_lt_errors_len, operand);
6783 try sema.addSafetyCheck(block, is_lt_len, .invalid_error_code);6984 const zero_val = try sema.addConstant(Type.err_int, Value.zero);
6985 const is_non_zero = try block.addBinOp(.cmp_neq, operand, zero_val);
6986 const ok = try block.addBinOp(.bit_and, is_lt_len, is_non_zero);
6987 try sema.addSafetyCheck(block, ok, .invalid_error_code);
6784 }6988 }
6785 return block.addInst(.{6989 return block.addInst(.{
6786 .tag = .bitcast,6990 .tag = .bitcast,
...@@ -6940,8 +7144,12 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -6940,8 +7144,12 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
6940 }7144 }
69417145
6942 try sema.requireRuntimeBlock(block, src, operand_src);7146 try sema.requireRuntimeBlock(block, src, operand_src);
6943 // TODO insert safety check to make sure the value matches an enum value7147 const result = try block.addTyOp(.intcast, dest_ty, operand);
6944 return block.addTyOp(.intcast, dest_ty, operand);7148 if (block.wantSafety() and !dest_ty.isNonexhaustiveEnum() and sema.mod.comp.bin_file.options.use_llvm) {
7149 const ok = try block.addUnOp(.is_named_enum_value, result);
7150 try sema.addSafetyCheck(block, ok, .invalid_enum_value);
7151 }
7152 return result;
6945}7153}
69467154
6947/// Pointer in, pointer out.7155/// Pointer in, pointer out.
...@@ -7048,6 +7256,8 @@ fn zirOptionalPayload(...@@ -7048,6 +7256,8 @@ fn zirOptionalPayload(
7048 if (operand_ty.ptrSize() != .C) {7256 if (operand_ty.ptrSize() != .C) {
7049 return sema.failWithExpectedOptionalType(block, src, operand_ty);7257 return sema.failWithExpectedOptionalType(block, src, operand_ty);
7050 }7258 }
7259 // TODO https://github.com/ziglang/zig/issues/6597
7260 if (true) break :t operand_ty;
7051 const ptr_info = operand_ty.ptrInfo().data;7261 const ptr_info = operand_ty.ptrInfo().data;
7052 break :t try Type.ptr(sema.arena, sema.mod, .{7262 break :t try Type.ptr(sema.arena, sema.mod, .{
7053 .pointee_type = try ptr_info.pointee_type.copy(sema.arena),7263 .pointee_type = try ptr_info.pointee_type.copy(sema.arena),
...@@ -7425,10 +7635,11 @@ fn handleExternLibName(...@@ -7425,10 +7635,11 @@ fn handleExternLibName(
7425) CompileError![:0]u8 {7635) CompileError![:0]u8 {
7426 blk: {7636 blk: {
7427 const mod = sema.mod;7637 const mod = sema.mod;
7638 const comp = mod.comp;
7428 const target = mod.getTarget();7639 const target = mod.getTarget();
7429 log.debug("extern fn symbol expected in lib '{s}'", .{lib_name});7640 log.debug("extern fn symbol expected in lib '{s}'", .{lib_name});
7430 if (target_util.is_libc_lib_name(target, lib_name)) {7641 if (target_util.is_libc_lib_name(target, lib_name)) {
7431 if (!mod.comp.bin_file.options.link_libc) {7642 if (!comp.bin_file.options.link_libc and !comp.bin_file.options.parent_compilation_link_libc) {
7432 return sema.fail(7643 return sema.fail(
7433 block,7644 block,
7434 src_loc,7645 src_loc,
...@@ -7436,11 +7647,11 @@ fn handleExternLibName(...@@ -7436,11 +7647,11 @@ fn handleExternLibName(
7436 .{},7647 .{},
7437 );7648 );
7438 }7649 }
7439 mod.comp.bin_file.options.link_libc = true;7650 comp.bin_file.options.link_libc = true;
7440 break :blk;7651 break :blk;
7441 }7652 }
7442 if (target_util.is_libcpp_lib_name(target, lib_name)) {7653 if (target_util.is_libcpp_lib_name(target, lib_name)) {
7443 if (!mod.comp.bin_file.options.link_libcpp) {7654 if (!comp.bin_file.options.link_libcpp) {
7444 return sema.fail(7655 return sema.fail(
7445 block,7656 block,
7446 src_loc,7657 src_loc,
...@@ -7448,14 +7659,14 @@ fn handleExternLibName(...@@ -7448,14 +7659,14 @@ fn handleExternLibName(
7448 .{},7659 .{},
7449 );7660 );
7450 }7661 }
7451 mod.comp.bin_file.options.link_libcpp = true;7662 comp.bin_file.options.link_libcpp = true;
7452 break :blk;7663 break :blk;
7453 }7664 }
7454 if (mem.eql(u8, lib_name, "unwind")) {7665 if (mem.eql(u8, lib_name, "unwind")) {
7455 mod.comp.bin_file.options.link_libunwind = true;7666 comp.bin_file.options.link_libunwind = true;
7456 break :blk;7667 break :blk;
7457 }7668 }
7458 if (!target.isWasm() and !mod.comp.bin_file.options.pic) {7669 if (!target.isWasm() and !comp.bin_file.options.pic) {
7459 return sema.fail(7670 return sema.fail(
7460 block,7671 block,
7461 src_loc,7672 src_loc,
...@@ -7463,7 +7674,7 @@ fn handleExternLibName(...@@ -7463,7 +7674,7 @@ fn handleExternLibName(
7463 .{ lib_name, lib_name },7674 .{ lib_name, lib_name },
7464 );7675 );
7465 }7676 }
7466 mod.comp.stage1AddLinkLib(lib_name) catch |err| {7677 comp.stage1AddLinkLib(lib_name) catch |err| {
7467 return sema.fail(block, src_loc, "unable to add link lib '{s}': {s}", .{7678 return sema.fail(block, src_loc, "unable to add link lib '{s}': {s}", .{
7468 lib_name, @errorName(err),7679 lib_name, @errorName(err),
7469 });7680 });
...@@ -7502,7 +7713,6 @@ fn funcCommon(...@@ -7502,7 +7713,6 @@ fn funcCommon(
7502 noalias_bits: u32,7713 noalias_bits: u32,
7503 is_noinline: bool,7714 is_noinline: bool,
7504) CompileError!Air.Inst.Ref {7715) CompileError!Air.Inst.Ref {
7505 const fn_src = LazySrcLoc.nodeOffset(src_node_offset);
7506 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };7716 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };
7507 const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = src_node_offset };7717 const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = src_node_offset };
75087718
...@@ -7573,27 +7783,25 @@ fn funcCommon(...@@ -7573,27 +7783,25 @@ fn funcCommon(
7573 param_types[i] = param.ty;7783 param_types[i] = param.ty;
7574 sema.analyzeParameter(7784 sema.analyzeParameter(
7575 block,7785 block,
7576 fn_src,
7577 .unneeded,7786 .unneeded,
7578 param,7787 param,
7579 comptime_params,7788 comptime_params,
7580 i,7789 i,
7581 &is_generic,7790 &is_generic,
7582 is_extern,
7583 cc_workaround,7791 cc_workaround,
7792 has_body,
7584 ) catch |err| switch (err) {7793 ) catch |err| switch (err) {
7585 error.NeededSourceLocation => {7794 error.NeededSourceLocation => {
7586 const decl = sema.mod.declPtr(block.src_decl);7795 const decl = sema.mod.declPtr(block.src_decl);
7587 try sema.analyzeParameter(7796 try sema.analyzeParameter(
7588 block,7797 block,
7589 fn_src,
7590 Module.paramSrc(src_node_offset, sema.gpa, decl, i),7798 Module.paramSrc(src_node_offset, sema.gpa, decl, i),
7591 param,7799 param,
7592 comptime_params,7800 comptime_params,
7593 i,7801 i,
7594 &is_generic,7802 &is_generic,
7595 is_extern,
7596 cc_workaround,7803 cc_workaround,
7804 has_body,
7597 );7805 );
7598 return error.AnalysisFail;7806 return error.AnalysisFail;
7599 },7807 },
...@@ -7601,18 +7809,17 @@ fn funcCommon(...@@ -7601,18 +7809,17 @@ fn funcCommon(
7601 };7809 };
7602 }7810 }
76037811
7604 const ret_poison = if (!is_generic) rp: {7812 var ret_ty_requires_comptime = false;
7605 if (sema.typeRequiresComptime(block, ret_ty_src, bare_return_type)) |ret_comptime| {7813 const ret_poison = if (sema.typeRequiresComptime(block, ret_ty_src, bare_return_type)) |ret_comptime| rp: {
7606 is_generic = ret_comptime;7814 ret_ty_requires_comptime = ret_comptime;
7607 break :rp bare_return_type.tag() == .generic_poison;7815 break :rp bare_return_type.tag() == .generic_poison;
7608 } else |err| switch (err) {7816 } else |err| switch (err) {
7609 error.GenericPoison => {7817 error.GenericPoison => rp: {
7610 is_generic = true;7818 is_generic = true;
7611 break :rp true;7819 break :rp true;
7612 },7820 },
7613 else => |e| return e,7821 else => |e| return e,
7614 }7822 };
7615 } else bare_return_type.tag() == .generic_poison;
76167823
7617 const return_type = if (!inferred_error_set or ret_poison)7824 const return_type = if (!inferred_error_set or ret_poison)
7618 bare_return_type7825 bare_return_type
...@@ -7657,6 +7864,41 @@ fn funcCommon(...@@ -7657,6 +7864,41 @@ fn funcCommon(
7657 return sema.failWithOwnedErrorMsg(msg);7864 return sema.failWithOwnedErrorMsg(msg);
7658 }7865 }
76597866
7867 // If the return type is comptime only but not dependent on parameters then all parameter types also need to be comptime
7868 if (!sema.is_generic_instantiation and has_body and ret_ty_requires_comptime) comptime_check: {
7869 for (block.params.items) |param| {
7870 if (!param.is_comptime) break;
7871 } else break :comptime_check;
7872
7873 const msg = try sema.errMsg(
7874 block,
7875 ret_ty_src,
7876 "function with comptime only return type '{}' requires all parameters to be comptime",
7877 .{return_type.fmt(sema.mod)},
7878 );
7879 try sema.explainWhyTypeIsComptime(block, ret_ty_src, msg, ret_ty_src.toSrcLoc(sema.owner_decl), return_type);
7880
7881 const tags = sema.code.instructions.items(.tag);
7882 const data = sema.code.instructions.items(.data);
7883 const param_body = sema.code.getParamBody(func_inst);
7884 for (block.params.items) |param, i| {
7885 if (!param.is_comptime) {
7886 const param_index = param_body[i];
7887 const param_src = switch (tags[param_index]) {
7888 .param => data[param_index].pl_tok.src(),
7889 .param_anytype => data[param_index].str_tok.src(),
7890 else => unreachable,
7891 };
7892 if (param.name.len != 0) {
7893 try sema.errNote(block, param_src, msg, "param '{s}' is required to be comptime", .{param.name});
7894 } else {
7895 try sema.errNote(block, param_src, msg, "param is required to be comptime", .{});
7896 }
7897 }
7898 }
7899 return sema.failWithOwnedErrorMsg(msg);
7900 }
7901
7660 const arch = sema.mod.getTarget().cpu.arch;7902 const arch = sema.mod.getTarget().cpu.arch;
7661 if (switch (cc_workaround) {7903 if (switch (cc_workaround) {
7662 .Unspecified, .C, .Naked, .Async, .Inline => null,7904 .Unspecified, .C, .Naked, .Async, .Inline => null,
...@@ -7699,6 +7941,9 @@ fn funcCommon(...@@ -7699,6 +7941,9 @@ fn funcCommon(
7699 if (cc_workaround == .Inline and is_noinline) {7941 if (cc_workaround == .Inline and is_noinline) {
7700 return sema.fail(block, cc_src, "'noinline' function cannot have callconv 'Inline'", .{});7942 return sema.fail(block, cc_src, "'noinline' function cannot have callconv 'Inline'", .{});
7701 }7943 }
7944 if (is_generic and sema.no_partial_func_ty) return error.GenericPoison;
7945 for (comptime_params) |ct| is_generic = is_generic or ct;
7946 is_generic = is_generic or ret_ty_requires_comptime;
77027947
7703 break :fn_ty try Type.Tag.function.create(sema.arena, .{7948 break :fn_ty try Type.Tag.function.create(sema.arena, .{
7704 .param_types = param_types,7949 .param_types = param_types,
...@@ -7760,11 +8005,6 @@ fn funcCommon(...@@ -7760,11 +8005,6 @@ fn funcCommon(
7760 break :blk if (sema.comptime_args.len == 0) null else sema.comptime_args.ptr;8005 break :blk if (sema.comptime_args.len == 0) null else sema.comptime_args.ptr;
7761 } else null;8006 } else null;
77628007
7763 const param_names = try sema.gpa.alloc([:0]const u8, block.params.items.len);
7764 for (param_names) |*param_name, i| {
7765 param_name.* = try sema.gpa.dupeZ(u8, block.params.items[i].name);
7766 }
7767
7768 const hash = new_func.hash;8008 const hash = new_func.hash;
7769 const fn_payload = try sema.arena.create(Value.Payload.Function);8009 const fn_payload = try sema.arena.create(Value.Payload.Function);
7770 new_func.* = .{8010 new_func.* = .{
...@@ -7772,13 +8012,11 @@ fn funcCommon(...@@ -7772,13 +8012,11 @@ fn funcCommon(
7772 .zir_body_inst = func_inst,8012 .zir_body_inst = func_inst,
7773 .owner_decl = sema.owner_decl_index,8013 .owner_decl = sema.owner_decl_index,
7774 .comptime_args = comptime_args,8014 .comptime_args = comptime_args,
7775 .anytype_args = undefined,
7776 .hash = hash,8015 .hash = hash,
7777 .lbrace_line = src_locs.lbrace_line,8016 .lbrace_line = src_locs.lbrace_line,
7778 .rbrace_line = src_locs.rbrace_line,8017 .rbrace_line = src_locs.rbrace_line,
7779 .lbrace_column = @truncate(u16, src_locs.columns),8018 .lbrace_column = @truncate(u16, src_locs.columns),
7780 .rbrace_column = @truncate(u16, src_locs.columns >> 16),8019 .rbrace_column = @truncate(u16, src_locs.columns >> 16),
7781 .param_names = param_names,
7782 .branch_quota = default_branch_quota,8020 .branch_quota = default_branch_quota,
7783 .is_noinline = is_noinline,8021 .is_noinline = is_noinline,
7784 };8022 };
...@@ -7796,30 +8034,20 @@ fn funcCommon(...@@ -7796,30 +8034,20 @@ fn funcCommon(
7796fn analyzeParameter(8034fn analyzeParameter(
7797 sema: *Sema,8035 sema: *Sema,
7798 block: *Block,8036 block: *Block,
7799 func_src: LazySrcLoc,
7800 param_src: LazySrcLoc,8037 param_src: LazySrcLoc,
7801 param: Block.Param,8038 param: Block.Param,
7802 comptime_params: []bool,8039 comptime_params: []bool,
7803 i: usize,8040 i: usize,
7804 is_generic: *bool,8041 is_generic: *bool,
7805 is_extern: bool,
7806 cc: std.builtin.CallingConvention,8042 cc: std.builtin.CallingConvention,
8043 has_body: bool,
7807) !void {8044) !void {
7808 const requires_comptime = try sema.typeRequiresComptime(block, param_src, param.ty);8045 const requires_comptime = try sema.typeRequiresComptime(block, param_src, param.ty);
7809 comptime_params[i] = param.is_comptime or requires_comptime;8046 comptime_params[i] = param.is_comptime or requires_comptime;
7810 const this_generic = comptime_params[i] or param.ty.tag() == .generic_poison;8047 const this_generic = param.ty.tag() == .generic_poison;
7811 is_generic.* = is_generic.* or this_generic;8048 is_generic.* = is_generic.* or this_generic;
7812 if (is_extern and this_generic) {8049 if (param.is_comptime and !Type.fnCallingConventionAllowsZigTypes(cc)) {
7813 // TODO this check should exist somewhere for notes.8050 return sema.fail(block, param_src, "comptime parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});
7814 if (param_src == .unneeded) return error.NeededSourceLocation;
7815 const msg = msg: {
7816 const msg = try sema.errMsg(block, func_src, "extern function cannot be generic", .{});
7817 errdefer msg.destroy(sema.gpa);
7818
7819 try sema.errNote(block, param_src, msg, "function is generic because of this parameter", .{});
7820 break :msg msg;
7821 };
7822 return sema.failWithOwnedErrorMsg(msg);
7823 }8051 }
7824 if (this_generic and !Type.fnCallingConventionAllowsZigTypes(cc)) {8052 if (this_generic and !Type.fnCallingConventionAllowsZigTypes(cc)) {
7825 return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});8053 return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});
...@@ -7852,9 +8080,9 @@ fn analyzeParameter(...@@ -7852,9 +8080,9 @@ fn analyzeParameter(
7852 };8080 };
7853 return sema.failWithOwnedErrorMsg(msg);8081 return sema.failWithOwnedErrorMsg(msg);
7854 }8082 }
7855 if (requires_comptime and !param.is_comptime) {8083 if (!sema.is_generic_instantiation and requires_comptime and !param.is_comptime and has_body) {
7856 const msg = msg: {8084 const msg = msg: {
7857 const msg = try sema.errMsg(block, param_src, "parametter of type '{}' must be declared comptime", .{8085 const msg = try sema.errMsg(block, param_src, "parameter of type '{}' must be declared comptime", .{
7858 param.ty.fmt(sema.mod),8086 param.ty.fmt(sema.mod),
7859 });8087 });
7860 errdefer msg.destroy(sema.gpa);8088 errdefer msg.destroy(sema.gpa);
...@@ -7885,25 +8113,19 @@ fn zirParam(...@@ -7885,25 +8113,19 @@ fn zirParam(
7885 // Make sure any nested param instructions don't clobber our work.8113 // Make sure any nested param instructions don't clobber our work.
7886 const prev_params = block.params;8114 const prev_params = block.params;
7887 const prev_preallocated_new_func = sema.preallocated_new_func;8115 const prev_preallocated_new_func = sema.preallocated_new_func;
8116 const prev_no_partial_func_type = sema.no_partial_func_ty;
7888 block.params = .{};8117 block.params = .{};
7889 sema.preallocated_new_func = null;8118 sema.preallocated_new_func = null;
8119 sema.no_partial_func_ty = true;
7890 defer {8120 defer {
7891 block.params.deinit(sema.gpa);8121 block.params.deinit(sema.gpa);
7892 block.params = prev_params;8122 block.params = prev_params;
7893 sema.preallocated_new_func = prev_preallocated_new_func;8123 sema.preallocated_new_func = prev_preallocated_new_func;
8124 sema.no_partial_func_ty = prev_no_partial_func_type;
7894 }8125 }
78958126
7896 if (sema.resolveBody(block, body, inst)) |param_ty_inst| {8127 if (sema.resolveBody(block, body, inst)) |param_ty_inst| {
7897 if (sema.analyzeAsType(block, src, param_ty_inst)) |param_ty| {8128 if (sema.analyzeAsType(block, src, param_ty_inst)) |param_ty| {
7898 if (param_ty.zigTypeTag() == .Fn and param_ty.fnInfo().is_generic) {
7899 // zirFunc will not emit error.GenericPoison to build a
7900 // partial type for generic functions but we still need to
7901 // detect if a function parameter is a generic function
7902 // to force the parent function to also be generic.
7903 if (!sema.inst_map.contains(inst)) {
7904 break :err error.GenericPoison;
7905 }
7906 }
7907 break :param_ty param_ty;8129 break :param_ty param_ty;
7908 } else |err| break :err err;8130 } else |err| break :err err;
7909 } else |err| break :err err;8131 } else |err| break :err err;
...@@ -7952,7 +8174,7 @@ fn zirParam(...@@ -7952,7 +8174,7 @@ fn zirParam(
79528174
7953 try block.params.append(sema.gpa, .{8175 try block.params.append(sema.gpa, .{
7954 .ty = param_ty,8176 .ty = param_ty,
7955 .is_comptime = is_comptime,8177 .is_comptime = comptime_syntax,
7956 .name = param_name,8178 .name = param_name,
7957 });8179 });
7958 const result = try sema.addConstant(param_ty, Value.initTag(.generic_poison));8180 const result = try sema.addConstant(param_ty, Value.initTag(.generic_poison));
...@@ -8638,13 +8860,11 @@ fn zirSwitchCapture(...@@ -8638,13 +8860,11 @@ fn zirSwitchCapture(
8638 switch (operand_ty.zigTypeTag()) {8860 switch (operand_ty.zigTypeTag()) {
8639 .Union => {8861 .Union => {
8640 const union_obj = operand_ty.cast(Type.Payload.Union).?.data;8862 const union_obj = operand_ty.cast(Type.Payload.Union).?.data;
8641 const enum_ty = union_obj.tag_ty;
8642
8643 const first_item = try sema.resolveInst(items[0]);8863 const first_item = try sema.resolveInst(items[0]);
8644 // Previous switch validation ensured this will succeed8864 // Previous switch validation ensured this will succeed
8645 const first_item_val = sema.resolveConstValue(block, .unneeded, first_item, undefined) catch unreachable;8865 const first_item_val = sema.resolveConstValue(block, .unneeded, first_item, undefined) catch unreachable;
86468866
8647 const first_field_index = @intCast(u32, enum_ty.enumTagFieldIndex(first_item_val, sema.mod).?);8867 const first_field_index = @intCast(u32, operand_ty.unionTagFieldIndex(first_item_val, sema.mod).?);
8648 const first_field = union_obj.fields.values()[first_field_index];8868 const first_field = union_obj.fields.values()[first_field_index];
86498869
8650 for (items[1..]) |item, i| {8870 for (items[1..]) |item, i| {
...@@ -8652,7 +8872,7 @@ fn zirSwitchCapture(...@@ -8652,7 +8872,7 @@ fn zirSwitchCapture(
8652 // Previous switch validation ensured this will succeed8872 // Previous switch validation ensured this will succeed
8653 const item_val = sema.resolveConstValue(block, .unneeded, item_ref, undefined) catch unreachable;8873 const item_val = sema.resolveConstValue(block, .unneeded, item_ref, undefined) catch unreachable;
86548874
8655 const field_index = enum_ty.enumTagFieldIndex(item_val, sema.mod).?;8875 const field_index = operand_ty.unionTagFieldIndex(item_val, sema.mod).?;
8656 const field = union_obj.fields.values()[field_index];8876 const field = union_obj.fields.values()[field_index];
8657 if (!field.ty.eql(first_field.ty, sema.mod)) {8877 if (!field.ty.eql(first_field.ty, sema.mod)) {
8658 const msg = msg: {8878 const msg = msg: {
...@@ -8776,6 +8996,9 @@ fn zirSwitchCond(...@@ -8776,6 +8996,9 @@ fn zirSwitchCond(
8776 .ErrorSet,8996 .ErrorSet,
8777 .Enum,8997 .Enum,
8778 => {8998 => {
8999 if (operand_ty.isSlice()) {
9000 return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(sema.mod)});
9001 }
8779 if ((try sema.typeHasOnePossibleValue(block, operand_src, operand_ty))) |opv| {9002 if ((try sema.typeHasOnePossibleValue(block, operand_src, operand_ty))) |opv| {
8780 return sema.addConstant(operand_ty, opv);9003 return sema.addConstant(operand_ty, opv);
8781 }9004 }
...@@ -8852,12 +9075,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -8852,12 +9075,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
8852 },9075 },
8853 };9076 };
88549077
8855 const union_originally = blk: {9078 const maybe_union_ty = blk: {
8856 const zir_data = sema.code.instructions.items(.data);9079 const zir_data = sema.code.instructions.items(.data);
8857 const cond_index = Zir.refToIndex(extra.data.operand).?;9080 const cond_index = Zir.refToIndex(extra.data.operand).?;
8858 const raw_operand = sema.resolveInst(zir_data[cond_index].un_node.operand) catch unreachable;9081 const raw_operand = sema.resolveInst(zir_data[cond_index].un_node.operand) catch unreachable;
8859 break :blk sema.typeOf(raw_operand).zigTypeTag() == .Union;9082 break :blk sema.typeOf(raw_operand);
8860 };9083 };
9084 const union_originally = maybe_union_ty.zigTypeTag() == .Union;
9085 var seen_union_fields: []?Module.SwitchProngSrc = &.{};
9086 defer gpa.free(seen_union_fields);
9087
9088 var empty_enum = false;
88619089
8862 const operand_ty = sema.typeOf(operand);9090 const operand_ty = sema.typeOf(operand);
88639091
...@@ -8892,7 +9120,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -8892,7 +9120,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
8892 .Union => unreachable, // handled in zirSwitchCond9120 .Union => unreachable, // handled in zirSwitchCond
8893 .Enum => {9121 .Enum => {
8894 var seen_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount());9122 var seen_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount());
8895 defer gpa.free(seen_fields);9123 empty_enum = seen_fields.len == 0 and !operand_ty.isNonexhaustiveEnum();
9124 defer if (!union_originally) gpa.free(seen_fields);
9125 if (union_originally) seen_union_fields = seen_fields;
8896 mem.set(?Module.SwitchProngSrc, seen_fields, null);9126 mem.set(?Module.SwitchProngSrc, seen_fields, null);
88979127
8898 // This is used for non-exhaustive enum values that do not correspond to any tags.9128 // This is used for non-exhaustive enum values that do not correspond to any tags.
...@@ -9486,6 +9716,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -9486,6 +9716,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
9486 }9716 }
94879717
9488 if (scalar_cases_len + multi_cases_len == 0) {9718 if (scalar_cases_len + multi_cases_len == 0) {
9719 if (empty_enum) {
9720 return Air.Inst.Ref.void_value;
9721 }
9489 if (special_prong == .none) {9722 if (special_prong == .none) {
9490 return sema.fail(block, src, "switch must handle all possibilities", .{});9723 return sema.fail(block, src, "switch must handle all possibilities", .{});
9491 }9724 }
...@@ -9525,27 +9758,37 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -9525,27 +9758,37 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
9525 const item = try sema.resolveInst(item_ref);9758 const item = try sema.resolveInst(item_ref);
9526 // `item` is already guaranteed to be constant known.9759 // `item` is already guaranteed to be constant known.
95279760
9528 _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) {9761 const analyze_body = if (union_originally) blk: {
9529 error.ComptimeBreak => {9762 const item_val = sema.resolveConstValue(block, .unneeded, item, undefined) catch unreachable;
9530 const zir_datas = sema.code.instructions.items(.data);9763 const field_ty = maybe_union_ty.unionFieldType(item_val, sema.mod);
9531 const break_data = zir_datas[sema.comptime_break_inst].@"break";9764 break :blk field_ty.zigTypeTag() != .NoReturn;
9532 try sema.addRuntimeBreak(&case_block, .{9765 } else true;
9533 .block_inst = break_data.block_inst,
9534 .operand = break_data.operand,
9535 .inst = sema.comptime_break_inst,
9536 });
9537 },
9538 else => |e| return e,
9539 };
9540
9541 try wip_captures.finalize();
95429766
9543 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);9767 if (analyze_body) {
9544 cases_extra.appendAssumeCapacity(1); // items_len9768 _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) {
9545 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));9769 error.ComptimeBreak => {
9546 cases_extra.appendAssumeCapacity(@enumToInt(item));9770 const zir_datas = sema.code.instructions.items(.data);
9547 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);9771 const break_data = zir_datas[sema.comptime_break_inst].@"break";
9548 }9772 try sema.addRuntimeBreak(&case_block, .{
9773 .block_inst = break_data.block_inst,
9774 .operand = break_data.operand,
9775 .inst = sema.comptime_break_inst,
9776 });
9777 },
9778 else => |e| return e,
9779 };
9780 } else {
9781 _ = try case_block.addNoOp(.unreach);
9782 }
9783
9784 try wip_captures.finalize();
9785
9786 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
9787 cases_extra.appendAssumeCapacity(1); // items_len
9788 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
9789 cases_extra.appendAssumeCapacity(@enumToInt(item));
9790 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
9791 }
95499792
9550 var is_first = true;9793 var is_first = true;
9551 var prev_cond_br: Air.Inst.Index = undefined;9794 var prev_cond_br: Air.Inst.Index = undefined;
...@@ -9577,20 +9820,34 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -9577,20 +9820,34 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
9577 if (ranges_len == 0) {9820 if (ranges_len == 0) {
9578 cases_len += 1;9821 cases_len += 1;
95799822
9823 const analyze_body = if (union_originally)
9824 for (items) |item_ref| {
9825 const item = try sema.resolveInst(item_ref);
9826 const item_val = sema.resolveConstValue(block, .unneeded, item, undefined) catch unreachable;
9827 const field_ty = maybe_union_ty.unionFieldType(item_val, sema.mod);
9828 if (field_ty.zigTypeTag() != .NoReturn) break true;
9829 } else false
9830 else
9831 true;
9832
9580 const body = sema.code.extra[extra_index..][0..body_len];9833 const body = sema.code.extra[extra_index..][0..body_len];
9581 extra_index += body_len;9834 extra_index += body_len;
9582 _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) {9835 if (analyze_body) {
9583 error.ComptimeBreak => {9836 _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) {
9584 const zir_datas = sema.code.instructions.items(.data);9837 error.ComptimeBreak => {
9585 const break_data = zir_datas[sema.comptime_break_inst].@"break";9838 const zir_datas = sema.code.instructions.items(.data);
9586 try sema.addRuntimeBreak(&case_block, .{9839 const break_data = zir_datas[sema.comptime_break_inst].@"break";
9587 .block_inst = break_data.block_inst,9840 try sema.addRuntimeBreak(&case_block, .{
9588 .operand = break_data.operand,9841 .block_inst = break_data.block_inst,
9589 .inst = sema.comptime_break_inst,9842 .operand = break_data.operand,
9590 });9843 .inst = sema.comptime_break_inst,
9591 },9844 });
9592 else => |e| return e,9845 },
9593 };9846 else => |e| return e,
9847 };
9848 } else {
9849 _ = try case_block.addNoOp(.unreach);
9850 }
95949851
9595 try cases_extra.ensureUnusedCapacity(gpa, 2 + items.len +9852 try cases_extra.ensureUnusedCapacity(gpa, 2 + items.len +
9596 case_block.instructions.items.len);9853 case_block.instructions.items.len);
...@@ -9705,14 +9962,24 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -9705,14 +9962,24 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
9705 }9962 }
97069963
9707 var final_else_body: []const Air.Inst.Index = &.{};9964 var final_else_body: []const Air.Inst.Index = &.{};
9708 if (special.body.len != 0 or !is_first) {9965 if (special.body.len != 0 or !is_first or case_block.wantSafety()) {
9709 var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope);9966 var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope);
9710 defer wip_captures.deinit();9967 defer wip_captures.deinit();
97119968
9712 case_block.instructions.shrinkRetainingCapacity(0);9969 case_block.instructions.shrinkRetainingCapacity(0);
9713 case_block.wip_capture_scope = wip_captures.scope;9970 case_block.wip_capture_scope = wip_captures.scope;
97149971
9715 if (special.body.len != 0) {9972 const analyze_body = if (union_originally)
9973 for (seen_union_fields) |seen_field, index| {
9974 if (seen_field != null) continue;
9975 const union_obj = maybe_union_ty.cast(Type.Payload.Union).?.data;
9976 const field_ty = union_obj.fields.values()[index].ty;
9977 if (field_ty.zigTypeTag() != .NoReturn) break true;
9978 } else false
9979 else
9980 true;
9981
9982 if (special.body.len != 0 and analyze_body) {
9716 _ = sema.analyzeBodyInner(&case_block, special.body) catch |err| switch (err) {9983 _ = sema.analyzeBodyInner(&case_block, special.body) catch |err| switch (err) {
9717 error.ComptimeBreak => {9984 error.ComptimeBreak => {
9718 const zir_datas = sema.code.instructions.items(.data);9985 const zir_datas = sema.code.instructions.items(.data);
...@@ -9728,9 +9995,11 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -9728,9 +9995,11 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
9728 } else {9995 } else {
9729 // We still need a terminator in this block, but we have proven9996 // We still need a terminator in this block, but we have proven
9730 // that it is unreachable.9997 // that it is unreachable.
9731 // TODO this should be a special safety panic other than unreachable, something9998 if (case_block.wantSafety()) {
9732 // like "panic: switch operand had corrupt value not allowed by the type"9999 _ = try sema.safetyPanic(&case_block, src, .corrupt_switch);
9733 try case_block.addUnreachable(src, true);10000 } else {
10001 _ = try case_block.addNoOp(.unreach);
10002 }
9734 }10003 }
973510004
9736 try wip_captures.finalize();10005 try wip_captures.finalize();
...@@ -10194,16 +10463,14 @@ fn zirShl(...@@ -10194,16 +10463,14 @@ fn zirShl(
1019410463
10195 const val = switch (air_tag) {10464 const val = switch (air_tag) {
10196 .shl_exact => val: {10465 .shl_exact => val: {
10197 const shifted = try lhs_val.shl(rhs_val, lhs_ty, sema.arena, target);10466 const shifted = try lhs_val.shlWithOverflow(rhs_val, lhs_ty, sema.arena, target);
10198 if (scalar_ty.zigTypeTag() == .ComptimeInt) {10467 if (scalar_ty.zigTypeTag() == .ComptimeInt) {
10199 break :val shifted;10468 break :val shifted.wrapped_result;
10200 }10469 }
10201 const int_info = scalar_ty.intInfo(target);10470 if (shifted.overflowed.compareWithZero(.eq)) {
10202 const truncated = try shifted.intTrunc(lhs_ty, sema.arena, int_info.signedness, int_info.bits, target);10471 break :val shifted.wrapped_result;
10203 if (try sema.compare(block, src, truncated, .eq, shifted, lhs_ty)) {
10204 break :val shifted;
10205 }10472 }
10206 return sema.addConstUndef(lhs_ty);10473 return sema.fail(block, src, "operation caused overflow", .{});
10207 },10474 },
1020810475
10209 .shl_sat => if (scalar_ty.zigTypeTag() == .ComptimeInt)10476 .shl_sat => if (scalar_ty.zigTypeTag() == .ComptimeInt)
...@@ -10239,34 +10506,57 @@ fn zirShl(...@@ -10239,34 +10506,57 @@ fn zirShl(
10239 } else rhs;10506 } else rhs;
1024010507
10241 try sema.requireRuntimeBlock(block, src, runtime_src);10508 try sema.requireRuntimeBlock(block, src, runtime_src);
10242 if (block.wantSafety() and air_tag == .shl_exact) {10509 if (block.wantSafety()) {
10243 const op_ov_tuple_ty = try sema.overflowArithmeticTupleType(lhs_ty);10510 const bit_count = scalar_ty.intInfo(target).bits;
10244 const op_ov = try block.addInst(.{10511 if (!std.math.isPowerOfTwo(bit_count)) {
10245 .tag = .shl_with_overflow,10512 const bit_count_val = try Value.Tag.int_u64.create(sema.arena, bit_count);
10246 .data = .{ .ty_pl = .{10513
10247 .ty = try sema.addType(op_ov_tuple_ty),10514 const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: {
10248 .payload = try sema.addExtra(Air.Bin{10515 const bit_count_inst = try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, bit_count_val));
10249 .lhs = lhs,10516 const lt = try block.addCmpVector(rhs, bit_count_inst, .lt, try sema.addType(rhs_ty));
10250 .rhs = rhs,10517 break :ok try block.addInst(.{
10251 }),10518 .tag = .reduce,
10252 } },10519 .data = .{ .reduce = .{
10253 });10520 .operand = lt,
10254 const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty);10521 .operation = .And,
10255 const any_ov_bit = if (lhs_ty.zigTypeTag() == .Vector)10522 } },
10256 try block.addInst(.{10523 });
10257 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,10524 } else ok: {
10258 .data = .{ .reduce = .{10525 const bit_count_inst = try sema.addConstant(rhs_ty, bit_count_val);
10259 .operand = ov_bit,10526 break :ok try block.addBinOp(.cmp_lt, rhs, bit_count_inst);
10260 .operation = .Or,10527 };
10528 try sema.addSafetyCheck(block, ok, .shift_rhs_too_big);
10529 }
10530
10531 if (air_tag == .shl_exact) {
10532 const op_ov_tuple_ty = try sema.overflowArithmeticTupleType(lhs_ty);
10533 const op_ov = try block.addInst(.{
10534 .tag = .shl_with_overflow,
10535 .data = .{ .ty_pl = .{
10536 .ty = try sema.addType(op_ov_tuple_ty),
10537 .payload = try sema.addExtra(Air.Bin{
10538 .lhs = lhs,
10539 .rhs = rhs,
10540 }),
10261 } },10541 } },
10262 })10542 });
10263 else10543 const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty);
10264 ov_bit;10544 const any_ov_bit = if (lhs_ty.zigTypeTag() == .Vector)
10265 const zero_ov = try sema.addConstant(Type.@"u1", Value.zero);10545 try block.addInst(.{
10266 const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov);10546 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
10547 .data = .{ .reduce = .{
10548 .operand = ov_bit,
10549 .operation = .Or,
10550 } },
10551 })
10552 else
10553 ov_bit;
10554 const zero_ov = try sema.addConstant(Type.@"u1", Value.zero);
10555 const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov);
1026710556
10268 try sema.addSafetyCheck(block, no_ov, .shl_overflow);10557 try sema.addSafetyCheck(block, no_ov, .shl_overflow);
10269 return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty);10558 return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty);
10559 }
10270 }10560 }
10271 return block.addBinOp(air_tag, lhs, new_rhs);10561 return block.addBinOp(air_tag, lhs, new_rhs);
10272}10562}
...@@ -10333,7 +10623,7 @@ fn zirShr(...@@ -10333,7 +10623,7 @@ fn zirShr(
10333 // Detect if any ones would be shifted out.10623 // Detect if any ones would be shifted out.
10334 const truncated = try lhs_val.intTruncBitsAsValue(lhs_ty, sema.arena, .unsigned, rhs_val, target);10624 const truncated = try lhs_val.intTruncBitsAsValue(lhs_ty, sema.arena, .unsigned, rhs_val, target);
10335 if (!(try truncated.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) {10625 if (!(try truncated.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) {
10336 return sema.addConstUndef(lhs_ty);10626 return sema.fail(block, src, "exact shift shifted out 1 bits", .{});
10337 }10627 }
10338 }10628 }
10339 const val = try lhs_val.shr(rhs_val, lhs_ty, sema.arena, target);10629 const val = try lhs_val.shr(rhs_val, lhs_ty, sema.arena, target);
...@@ -10345,20 +10635,43 @@ fn zirShr(...@@ -10345,20 +10635,43 @@ fn zirShr(
1034510635
10346 try sema.requireRuntimeBlock(block, src, runtime_src);10636 try sema.requireRuntimeBlock(block, src, runtime_src);
10347 const result = try block.addBinOp(air_tag, lhs, rhs);10637 const result = try block.addBinOp(air_tag, lhs, rhs);
10348 if (block.wantSafety() and air_tag == .shr_exact) {10638 if (block.wantSafety()) {
10349 const back = try block.addBinOp(.shl, result, rhs);10639 const bit_count = scalar_ty.intInfo(target).bits;
1035010640 if (!std.math.isPowerOfTwo(bit_count)) {
10351 const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: {10641 const bit_count_val = try Value.Tag.int_u64.create(sema.arena, bit_count);
10352 const eql = try block.addCmpVector(lhs, back, .eq, try sema.addType(rhs_ty));10642
10353 break :ok try block.addInst(.{10643 const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: {
10354 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,10644 const bit_count_inst = try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, bit_count_val));
10355 .data = .{ .reduce = .{10645 const lt = try block.addCmpVector(rhs, bit_count_inst, .lt, try sema.addType(rhs_ty));
10356 .operand = eql,10646 break :ok try block.addInst(.{
10357 .operation = .And,10647 .tag = .reduce,
10358 } },10648 .data = .{ .reduce = .{
10359 });10649 .operand = lt,
10360 } else try block.addBinOp(.cmp_eq, lhs, back);10650 .operation = .And,
10361 try sema.addSafetyCheck(block, ok, .shr_overflow);10651 } },
10652 });
10653 } else ok: {
10654 const bit_count_inst = try sema.addConstant(rhs_ty, bit_count_val);
10655 break :ok try block.addBinOp(.cmp_lt, rhs, bit_count_inst);
10656 };
10657 try sema.addSafetyCheck(block, ok, .shift_rhs_too_big);
10658 }
10659
10660 if (air_tag == .shr_exact) {
10661 const back = try block.addBinOp(.shl, result, rhs);
10662
10663 const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: {
10664 const eql = try block.addCmpVector(lhs, back, .eq, try sema.addType(rhs_ty));
10665 break :ok try block.addInst(.{
10666 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
10667 .data = .{ .reduce = .{
10668 .operand = eql,
10669 .operation = .And,
10670 } },
10671 });
10672 } else try block.addBinOp(.cmp_eq, lhs, back);
10673 try sema.addSafetyCheck(block, ok, .shr_overflow);
10674 }
10362 }10675 }
10363 return result;10676 return result;
10364}10677}
...@@ -11040,6 +11353,21 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins...@@ -11040,6 +11353,21 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
11040 const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs);11353 const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs);
11041 const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs);11354 const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs);
1104211355
11356 if ((lhs_ty.zigTypeTag() == .ComptimeFloat and rhs_ty.zigTypeTag() == .ComptimeInt) or
11357 (lhs_ty.zigTypeTag() == .ComptimeInt and rhs_ty.zigTypeTag() == .ComptimeFloat))
11358 {
11359 // If it makes a difference whether we coerce to ints or floats before doing the division, error.
11360 // If lhs % rhs is 0, it doesn't matter.
11361 const lhs_val = maybe_lhs_val orelse unreachable;
11362 const rhs_val = maybe_rhs_val orelse unreachable;
11363 const rem = lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target) catch unreachable;
11364 if (rem.compareWithZero(.neq)) {
11365 return sema.fail(block, src, "ambiguous coercion of division operands '{s}' and '{s}'; non-zero remainder '{}'", .{
11366 @tagName(lhs_ty.tag()), @tagName(rhs_ty.tag()), rem.fmtValue(resolved_type, sema.mod),
11367 });
11368 }
11369 }
11370
11043 // TODO: emit compile error when .div is used on integers and there would be an11371 // TODO: emit compile error when .div is used on integers and there would be an
11044 // ambiguous result between div_floor and div_trunc.11372 // ambiguous result between div_floor and div_trunc.
1104511373
...@@ -11130,7 +11458,12 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins...@@ -11130,7 +11458,12 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
11130 try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int);11458 try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int);
11131 }11459 }
1113211460
11133 const air_tag = if (is_int) Air.Inst.Tag.div_trunc else switch (block.float_mode) {11461 const air_tag = if (is_int) blk: {
11462 if (lhs_ty.isSignedInt() or rhs_ty.isSignedInt()) {
11463 return sema.fail(block, src, "division with '{s}' and '{s}': signed integers must use @divTrunc, @divFloor, or @divExact", .{ @tagName(lhs_ty.tag()), @tagName(rhs_ty.tag()) });
11464 }
11465 break :blk Air.Inst.Tag.div_trunc;
11466 } else switch (block.float_mode) {
11134 .Optimized => Air.Inst.Tag.div_float_optimized,11467 .Optimized => Air.Inst.Tag.div_float_optimized,
11135 .Strict => Air.Inst.Tag.div_float,11468 .Strict => Air.Inst.Tag.div_float,
11136 };11469 };
...@@ -11210,13 +11543,19 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -11210,13 +11543,19 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
11210 if (maybe_lhs_val) |lhs_val| {11543 if (maybe_lhs_val) |lhs_val| {
11211 if (maybe_rhs_val) |rhs_val| {11544 if (maybe_rhs_val) |rhs_val| {
11212 if (is_int) {11545 if (is_int) {
11213 // TODO: emit compile error if there is a remainder11546 const modulus_val = try lhs_val.intMod(rhs_val, resolved_type, sema.arena, target);
11547 if (modulus_val.compareWithZero(.neq)) {
11548 return sema.fail(block, src, "exact division produced remainder", .{});
11549 }
11214 return sema.addConstant(11550 return sema.addConstant(
11215 resolved_type,11551 resolved_type,
11216 try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target),11552 try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target),
11217 );11553 );
11218 } else {11554 } else {
11219 // TODO: emit compile error if there is a remainder11555 const modulus_val = try lhs_val.floatMod(rhs_val, resolved_type, sema.arena, target);
11556 if (modulus_val.compareWithZero(.neq)) {
11557 return sema.fail(block, src, "exact division produced remainder", .{});
11558 }
11220 return sema.addConstant(11559 return sema.addConstant(
11221 resolved_type,11560 resolved_type,
11222 try lhs_val.floatDiv(rhs_val, resolved_type, sema.arena, target),11561 try lhs_val.floatDiv(rhs_val, resolved_type, sema.arena, target),
...@@ -11634,6 +11973,395 @@ fn airTag(block: *Block, is_int: bool, normal: Air.Inst.Tag, optimized: Air.Inst...@@ -11634,6 +11973,395 @@ fn airTag(block: *Block, is_int: bool, normal: Air.Inst.Tag, optimized: Air.Inst
11634 };11973 };
11635}11974}
1163611975
11976fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
11977 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
11978 const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
11979 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
11980 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
11981 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
11982 const lhs = try sema.resolveInst(extra.lhs);
11983 const rhs = try sema.resolveInst(extra.rhs);
11984 const lhs_ty = sema.typeOf(lhs);
11985 const rhs_ty = sema.typeOf(rhs);
11986 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
11987 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
11988 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
11989 try sema.checkInvalidPtrArithmetic(block, src, lhs_ty, .mod_rem);
11990
11991 const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
11992 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
11993 .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
11994 });
11995
11996 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
11997 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
11998
11999 const lhs_scalar_ty = lhs_ty.scalarType();
12000 const rhs_scalar_ty = rhs_ty.scalarType();
12001 const scalar_tag = resolved_type.scalarType().zigTypeTag();
12002
12003 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
12004
12005 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .mod_rem);
12006
12007 const mod = sema.mod;
12008 const target = mod.getTarget();
12009 const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs);
12010 const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs);
12011
12012 const runtime_src = rs: {
12013 // For integers:
12014 // Either operand being undef is a compile error because there exists
12015 // a possible value (TODO what is it?) that would invoke illegal behavior.
12016 // TODO: can lhs undef be handled better?
12017 //
12018 // For floats:
12019 // If the rhs is zero, compile error for division by zero.
12020 // If the rhs is undefined, compile error because there is a possible
12021 // value (zero) for which the division would be illegal behavior.
12022 // If the lhs is undefined, result is undefined.
12023 //
12024 // For either one: if the result would be different between @mod and @rem,
12025 // then emit a compile error saying you have to pick one.
12026 if (is_int) {
12027 if (maybe_lhs_val) |lhs_val| {
12028 if (lhs_val.isUndef()) {
12029 return sema.failWithUseOfUndef(block, lhs_src);
12030 }
12031 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
12032 return sema.addConstant(resolved_type, Value.zero);
12033 }
12034 } else if (lhs_scalar_ty.isSignedInt()) {
12035 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
12036 }
12037 if (maybe_rhs_val) |rhs_val| {
12038 if (rhs_val.isUndef()) {
12039 return sema.failWithUseOfUndef(block, rhs_src);
12040 }
12041 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
12042 return sema.failWithDivideByZero(block, rhs_src);
12043 }
12044 if (maybe_lhs_val) |lhs_val| {
12045 const rem_result = try sema.intRem(block, resolved_type, lhs_val, lhs_src, rhs_val, rhs_src);
12046 // If this answer could possibly be different by doing `intMod`,
12047 // we must emit a compile error. Otherwise, it's OK.
12048 if ((try rhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) != (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) and
12049 !(try rem_result.compareWithZeroAdvanced(.eq, sema.kit(block, src))))
12050 {
12051 const bad_src = if (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src)))
12052 lhs_src
12053 else
12054 rhs_src;
12055 return sema.failWithModRemNegative(block, bad_src, lhs_ty, rhs_ty);
12056 }
12057 if (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) {
12058 // Negative
12059 return sema.addConstant(resolved_type, Value.zero);
12060 }
12061 return sema.addConstant(resolved_type, rem_result);
12062 }
12063 break :rs lhs_src;
12064 } else if (rhs_scalar_ty.isSignedInt()) {
12065 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty);
12066 } else {
12067 break :rs rhs_src;
12068 }
12069 }
12070 // float operands
12071 if (maybe_rhs_val) |rhs_val| {
12072 if (rhs_val.isUndef()) {
12073 return sema.failWithUseOfUndef(block, rhs_src);
12074 }
12075 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
12076 return sema.failWithDivideByZero(block, rhs_src);
12077 }
12078 if (try rhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) {
12079 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty);
12080 }
12081 if (maybe_lhs_val) |lhs_val| {
12082 if (lhs_val.isUndef() or (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src)))) {
12083 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
12084 }
12085 return sema.addConstant(
12086 resolved_type,
12087 try lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target),
12088 );
12089 } else {
12090 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
12091 }
12092 } else {
12093 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty);
12094 }
12095 };
12096
12097 try sema.requireRuntimeBlock(block, src, runtime_src);
12098
12099 if (block.wantSafety()) {
12100 try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int);
12101 }
12102
12103 const air_tag = airTag(block, is_int, .rem, .rem_optimized);
12104 return block.addBinOp(air_tag, casted_lhs, casted_rhs);
12105}
12106
12107fn intRem(
12108 sema: *Sema,
12109 block: *Block,
12110 ty: Type,
12111 lhs: Value,
12112 lhs_src: LazySrcLoc,
12113 rhs: Value,
12114 rhs_src: LazySrcLoc,
12115) CompileError!Value {
12116 if (ty.zigTypeTag() == .Vector) {
12117 const result_data = try sema.arena.alloc(Value, ty.vectorLen());
12118 for (result_data) |*scalar, i| {
12119 scalar.* = try sema.intRemScalar(block, lhs.indexVectorlike(i), lhs_src, rhs.indexVectorlike(i), rhs_src);
12120 }
12121 return Value.Tag.aggregate.create(sema.arena, result_data);
12122 }
12123 return sema.intRemScalar(block, lhs, lhs_src, rhs, rhs_src);
12124}
12125
12126fn intRemScalar(
12127 sema: *Sema,
12128 block: *Block,
12129 lhs: Value,
12130 lhs_src: LazySrcLoc,
12131 rhs: Value,
12132 rhs_src: LazySrcLoc,
12133) CompileError!Value {
12134 const target = sema.mod.getTarget();
12135 // TODO is this a performance issue? maybe we should try the operation without
12136 // resorting to BigInt first.
12137 var lhs_space: Value.BigIntSpace = undefined;
12138 var rhs_space: Value.BigIntSpace = undefined;
12139 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema.kit(block, lhs_src));
12140 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema.kit(block, rhs_src));
12141 const limbs_q = try sema.arena.alloc(
12142 math.big.Limb,
12143 lhs_bigint.limbs.len,
12144 );
12145 const limbs_r = try sema.arena.alloc(
12146 math.big.Limb,
12147 // TODO: consider reworking Sema to re-use Values rather than
12148 // always producing new Value objects.
12149 rhs_bigint.limbs.len,
12150 );
12151 const limbs_buffer = try sema.arena.alloc(
12152 math.big.Limb,
12153 math.big.int.calcDivLimbsBufferLen(lhs_bigint.limbs.len, rhs_bigint.limbs.len),
12154 );
12155 var result_q = math.big.int.Mutable{ .limbs = limbs_q, .positive = undefined, .len = undefined };
12156 var result_r = math.big.int.Mutable{ .limbs = limbs_r, .positive = undefined, .len = undefined };
12157 result_q.divTrunc(&result_r, lhs_bigint, rhs_bigint, limbs_buffer);
12158 return Value.fromBigInt(sema.arena, result_r.toConst());
12159}
12160
12161fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
12162 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
12163 const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
12164 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
12165 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
12166 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
12167 const lhs = try sema.resolveInst(extra.lhs);
12168 const rhs = try sema.resolveInst(extra.rhs);
12169 const lhs_ty = sema.typeOf(lhs);
12170 const rhs_ty = sema.typeOf(rhs);
12171 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
12172 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
12173 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
12174 try sema.checkInvalidPtrArithmetic(block, src, lhs_ty, .mod);
12175
12176 const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
12177 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
12178 .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
12179 });
12180
12181 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
12182 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
12183
12184 const scalar_tag = resolved_type.scalarType().zigTypeTag();
12185
12186 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
12187
12188 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .mod);
12189
12190 const mod = sema.mod;
12191 const target = mod.getTarget();
12192 const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs);
12193 const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs);
12194
12195 const runtime_src = rs: {
12196 // For integers:
12197 // Either operand being undef is a compile error because there exists
12198 // a possible value (TODO what is it?) that would invoke illegal behavior.
12199 // TODO: can lhs zero be handled better?
12200 // TODO: can lhs undef be handled better?
12201 //
12202 // For floats:
12203 // If the rhs is zero, compile error for division by zero.
12204 // If the rhs is undefined, compile error because there is a possible
12205 // value (zero) for which the division would be illegal behavior.
12206 // If the lhs is undefined, result is undefined.
12207 if (is_int) {
12208 if (maybe_lhs_val) |lhs_val| {
12209 if (lhs_val.isUndef()) {
12210 return sema.failWithUseOfUndef(block, lhs_src);
12211 }
12212 }
12213 if (maybe_rhs_val) |rhs_val| {
12214 if (rhs_val.isUndef()) {
12215 return sema.failWithUseOfUndef(block, rhs_src);
12216 }
12217 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
12218 return sema.failWithDivideByZero(block, rhs_src);
12219 }
12220 if (maybe_lhs_val) |lhs_val| {
12221 return sema.addConstant(
12222 resolved_type,
12223 try lhs_val.intMod(rhs_val, resolved_type, sema.arena, target),
12224 );
12225 }
12226 break :rs lhs_src;
12227 } else {
12228 break :rs rhs_src;
12229 }
12230 }
12231 // float operands
12232 if (maybe_rhs_val) |rhs_val| {
12233 if (rhs_val.isUndef()) {
12234 return sema.failWithUseOfUndef(block, rhs_src);
12235 }
12236 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
12237 return sema.failWithDivideByZero(block, rhs_src);
12238 }
12239 }
12240 if (maybe_lhs_val) |lhs_val| {
12241 if (lhs_val.isUndef()) {
12242 return sema.addConstUndef(resolved_type);
12243 }
12244 if (maybe_rhs_val) |rhs_val| {
12245 return sema.addConstant(
12246 resolved_type,
12247 try lhs_val.floatMod(rhs_val, resolved_type, sema.arena, target),
12248 );
12249 } else break :rs rhs_src;
12250 } else break :rs lhs_src;
12251 };
12252
12253 try sema.requireRuntimeBlock(block, src, runtime_src);
12254
12255 if (block.wantSafety()) {
12256 try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int);
12257 }
12258
12259 const air_tag = airTag(block, is_int, .mod, .mod_optimized);
12260 return block.addBinOp(air_tag, casted_lhs, casted_rhs);
12261}
12262
12263fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
12264 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
12265 const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
12266 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
12267 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
12268 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
12269 const lhs = try sema.resolveInst(extra.lhs);
12270 const rhs = try sema.resolveInst(extra.rhs);
12271 const lhs_ty = sema.typeOf(lhs);
12272 const rhs_ty = sema.typeOf(rhs);
12273 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
12274 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
12275 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
12276 try sema.checkInvalidPtrArithmetic(block, src, lhs_ty, .rem);
12277
12278 const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
12279 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
12280 .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
12281 });
12282
12283 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
12284 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
12285
12286 const scalar_tag = resolved_type.scalarType().zigTypeTag();
12287
12288 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
12289
12290 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .rem);
12291
12292 const mod = sema.mod;
12293 const target = mod.getTarget();
12294 const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs);
12295 const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(block, rhs_src, casted_rhs);
12296
12297 const runtime_src = rs: {
12298 // For integers:
12299 // Either operand being undef is a compile error because there exists
12300 // a possible value (TODO what is it?) that would invoke illegal behavior.
12301 // TODO: can lhs zero be handled better?
12302 // TODO: can lhs undef be handled better?
12303 //
12304 // For floats:
12305 // If the rhs is zero, compile error for division by zero.
12306 // If the rhs is undefined, compile error because there is a possible
12307 // value (zero) for which the division would be illegal behavior.
12308 // If the lhs is undefined, result is undefined.
12309 if (is_int) {
12310 if (maybe_lhs_val) |lhs_val| {
12311 if (lhs_val.isUndef()) {
12312 return sema.failWithUseOfUndef(block, lhs_src);
12313 }
12314 }
12315 if (maybe_rhs_val) |rhs_val| {
12316 if (rhs_val.isUndef()) {
12317 return sema.failWithUseOfUndef(block, rhs_src);
12318 }
12319 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
12320 return sema.failWithDivideByZero(block, rhs_src);
12321 }
12322 if (maybe_lhs_val) |lhs_val| {
12323 return sema.addConstant(
12324 resolved_type,
12325 try sema.intRem(block, resolved_type, lhs_val, lhs_src, rhs_val, rhs_src),
12326 );
12327 }
12328 break :rs lhs_src;
12329 } else {
12330 break :rs rhs_src;
12331 }
12332 }
12333 // float operands
12334 if (maybe_rhs_val) |rhs_val| {
12335 if (rhs_val.isUndef()) {
12336 return sema.failWithUseOfUndef(block, rhs_src);
12337 }
12338 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
12339 return sema.failWithDivideByZero(block, rhs_src);
12340 }
12341 }
12342 if (maybe_lhs_val) |lhs_val| {
12343 if (lhs_val.isUndef()) {
12344 return sema.addConstUndef(resolved_type);
12345 }
12346 if (maybe_rhs_val) |rhs_val| {
12347 return sema.addConstant(
12348 resolved_type,
12349 try lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target),
12350 );
12351 } else break :rs rhs_src;
12352 } else break :rs lhs_src;
12353 };
12354
12355 try sema.requireRuntimeBlock(block, src, runtime_src);
12356
12357 if (block.wantSafety()) {
12358 try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int);
12359 }
12360
12361 const air_tag = airTag(block, is_int, .rem, .rem_optimized);
12362 return block.addBinOp(air_tag, casted_lhs, casted_rhs);
12363}
12364
11637fn zirOverflowArithmetic(12365fn zirOverflowArithmetic(
11638 sema: *Sema,12366 sema: *Sema,
11639 block: *Block,12367 block: *Block,
...@@ -11894,9 +12622,7 @@ fn analyzeArithmetic(...@@ -11894,9 +12622,7 @@ fn analyzeArithmetic(
1189412622
11895 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);12623 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
11896 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);12624 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
1189712625
11898 const lhs_scalar_ty = lhs_ty.scalarType();
11899 const rhs_scalar_ty = rhs_ty.scalarType();
11900 const scalar_tag = resolved_type.scalarType().zigTypeTag();12626 const scalar_tag = resolved_type.scalarType().zigTypeTag();
1190112627
11902 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;12628 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
...@@ -12242,206 +12968,6 @@ fn analyzeArithmetic(...@@ -12242,206 +12968,6 @@ fn analyzeArithmetic(
12242 } else break :rs .{ .src = lhs_src, .air_tag = .mul_sat };12968 } else break :rs .{ .src = lhs_src, .air_tag = .mul_sat };
12243 } else break :rs .{ .src = rhs_src, .air_tag = .mul_sat };12969 } else break :rs .{ .src = rhs_src, .air_tag = .mul_sat };
12244 },12970 },
12245 .mod_rem => {
12246 // For integers:
12247 // Either operand being undef is a compile error because there exists
12248 // a possible value (TODO what is it?) that would invoke illegal behavior.
12249 // TODO: can lhs undef be handled better?
12250 //
12251 // For floats:
12252 // If the rhs is zero, compile error for division by zero.
12253 // If the rhs is undefined, compile error because there is a possible
12254 // value (zero) for which the division would be illegal behavior.
12255 // If the lhs is undefined, result is undefined.
12256 //
12257 // For either one: if the result would be different between @mod and @rem,
12258 // then emit a compile error saying you have to pick one.
12259 if (is_int) {
12260 if (maybe_lhs_val) |lhs_val| {
12261 if (lhs_val.isUndef()) {
12262 return sema.failWithUseOfUndef(block, lhs_src);
12263 }
12264 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
12265 return sema.addConstant(resolved_type, Value.zero);
12266 }
12267 } else if (lhs_scalar_ty.isSignedInt()) {
12268 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
12269 }
12270 if (maybe_rhs_val) |rhs_val| {
12271 if (rhs_val.isUndef()) {
12272 return sema.failWithUseOfUndef(block, rhs_src);
12273 }
12274 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
12275 return sema.failWithDivideByZero(block, rhs_src);
12276 }
12277 if (maybe_lhs_val) |lhs_val| {
12278 const rem_result = try lhs_val.intRem(rhs_val, resolved_type, sema.arena, target);
12279 // If this answer could possibly be different by doing `intMod`,
12280 // we must emit a compile error. Otherwise, it's OK.
12281 if ((try rhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) != (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) and
12282 !(try rem_result.compareWithZeroAdvanced(.eq, sema.kit(block, src))))
12283 {
12284 const bad_src = if (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src)))
12285 lhs_src
12286 else
12287 rhs_src;
12288 return sema.failWithModRemNegative(block, bad_src, lhs_ty, rhs_ty);
12289 }
12290 if (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) {
12291 // Negative
12292 return sema.addConstant(resolved_type, Value.zero);
12293 }
12294 return sema.addConstant(resolved_type, rem_result);
12295 }
12296 break :rs .{ .src = lhs_src, .air_tag = .rem };
12297 } else if (rhs_scalar_ty.isSignedInt()) {
12298 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty);
12299 } else {
12300 break :rs .{ .src = rhs_src, .air_tag = .rem };
12301 }
12302 }
12303 // float operands
12304 if (maybe_rhs_val) |rhs_val| {
12305 if (rhs_val.isUndef()) {
12306 return sema.failWithUseOfUndef(block, rhs_src);
12307 }
12308 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
12309 return sema.failWithDivideByZero(block, rhs_src);
12310 }
12311 if (try rhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) {
12312 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty);
12313 }
12314 if (maybe_lhs_val) |lhs_val| {
12315 if (lhs_val.isUndef() or (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src)))) {
12316 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
12317 }
12318 return sema.addConstant(
12319 resolved_type,
12320 try lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target),
12321 );
12322 } else {
12323 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
12324 }
12325 } else {
12326 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty);
12327 }
12328 },
12329 .rem => {
12330 // For integers:
12331 // Either operand being undef is a compile error because there exists
12332 // a possible value (TODO what is it?) that would invoke illegal behavior.
12333 // TODO: can lhs zero be handled better?
12334 // TODO: can lhs undef be handled better?
12335 //
12336 // For floats:
12337 // If the rhs is zero, compile error for division by zero.
12338 // If the rhs is undefined, compile error because there is a possible
12339 // value (zero) for which the division would be illegal behavior.
12340 // If the lhs is undefined, result is undefined.
12341 if (is_int) {
12342 if (maybe_lhs_val) |lhs_val| {
12343 if (lhs_val.isUndef()) {
12344 return sema.failWithUseOfUndef(block, lhs_src);
12345 }
12346 }
12347 if (maybe_rhs_val) |rhs_val| {
12348 if (rhs_val.isUndef()) {
12349 return sema.failWithUseOfUndef(block, rhs_src);
12350 }
12351 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
12352 return sema.failWithDivideByZero(block, rhs_src);
12353 }
12354 if (maybe_lhs_val) |lhs_val| {
12355 return sema.addConstant(
12356 resolved_type,
12357 try lhs_val.intRem(rhs_val, resolved_type, sema.arena, target),
12358 );
12359 }
12360 break :rs .{ .src = lhs_src, .air_tag = .rem };
12361 } else {
12362 break :rs .{ .src = rhs_src, .air_tag = .rem };
12363 }
12364 }
12365 // float operands
12366 if (maybe_rhs_val) |rhs_val| {
12367 if (rhs_val.isUndef()) {
12368 return sema.failWithUseOfUndef(block, rhs_src);
12369 }
12370 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
12371 return sema.failWithDivideByZero(block, rhs_src);
12372 }
12373 }
12374 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .rem_optimized else .rem;
12375 if (maybe_lhs_val) |lhs_val| {
12376 if (lhs_val.isUndef()) {
12377 return sema.addConstUndef(resolved_type);
12378 }
12379 if (maybe_rhs_val) |rhs_val| {
12380 return sema.addConstant(
12381 resolved_type,
12382 try lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target),
12383 );
12384 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
12385 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
12386 },
12387 .mod => {
12388 // For integers:
12389 // Either operand being undef is a compile error because there exists
12390 // a possible value (TODO what is it?) that would invoke illegal behavior.
12391 // TODO: can lhs zero be handled better?
12392 // TODO: can lhs undef be handled better?
12393 //
12394 // For floats:
12395 // If the rhs is zero, compile error for division by zero.
12396 // If the rhs is undefined, compile error because there is a possible
12397 // value (zero) for which the division would be illegal behavior.
12398 // If the lhs is undefined, result is undefined.
12399 if (is_int) {
12400 if (maybe_lhs_val) |lhs_val| {
12401 if (lhs_val.isUndef()) {
12402 return sema.failWithUseOfUndef(block, lhs_src);
12403 }
12404 }
12405 if (maybe_rhs_val) |rhs_val| {
12406 if (rhs_val.isUndef()) {
12407 return sema.failWithUseOfUndef(block, rhs_src);
12408 }
12409 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
12410 return sema.failWithDivideByZero(block, rhs_src);
12411 }
12412 if (maybe_lhs_val) |lhs_val| {
12413 return sema.addConstant(
12414 resolved_type,
12415 try lhs_val.intMod(rhs_val, resolved_type, sema.arena, target),
12416 );
12417 }
12418 break :rs .{ .src = lhs_src, .air_tag = .mod };
12419 } else {
12420 break :rs .{ .src = rhs_src, .air_tag = .mod };
12421 }
12422 }
12423 // float operands
12424 if (maybe_rhs_val) |rhs_val| {
12425 if (rhs_val.isUndef()) {
12426 return sema.failWithUseOfUndef(block, rhs_src);
12427 }
12428 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
12429 return sema.failWithDivideByZero(block, rhs_src);
12430 }
12431 }
12432 const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .mod_optimized else .mod;
12433 if (maybe_lhs_val) |lhs_val| {
12434 if (lhs_val.isUndef()) {
12435 return sema.addConstUndef(resolved_type);
12436 }
12437 if (maybe_rhs_val) |rhs_val| {
12438 return sema.addConstant(
12439 resolved_type,
12440 try lhs_val.floatMod(rhs_val, resolved_type, sema.arena, target),
12441 );
12442 } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
12443 } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
12444 },
12445 else => unreachable,12971 else => unreachable,
12446 }12972 }
12447 };12973 };
...@@ -12485,33 +13011,6 @@ fn analyzeArithmetic(...@@ -12485,33 +13011,6 @@ fn analyzeArithmetic(
12485 return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty);13011 return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty);
12486 }13012 }
12487 }13013 }
12488 switch (rs.air_tag) {
12489 .rem, .mod, .rem_optimized, .mod_optimized => {
12490 const ok = if (resolved_type.zigTypeTag() == .Vector) ok: {
12491 const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero);
12492 const zero = try sema.addConstant(sema.typeOf(casted_rhs), zero_val);
12493 const ok = try block.addCmpVector(casted_rhs, zero, if (scalar_tag == .Int) .gt else .neq, try sema.addType(resolved_type));
12494 break :ok try block.addInst(.{
12495 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
12496 .data = .{ .reduce = .{
12497 .operand = ok,
12498 .operation = .And,
12499 } },
12500 });
12501 } else ok: {
12502 const zero = try sema.addConstant(sema.typeOf(casted_rhs), Value.zero);
12503 const air_tag = if (scalar_tag == .Int)
12504 Air.Inst.Tag.cmp_gt
12505 else if (block.float_mode == .Optimized)
12506 Air.Inst.Tag.cmp_neq_optimized
12507 else
12508 Air.Inst.Tag.cmp_neq;
12509 break :ok try block.addBinOp(air_tag, casted_rhs, zero);
12510 };
12511 try sema.addSafetyCheck(block, ok, .remainder_division_zero_negative);
12512 },
12513 else => {},
12514 }
12515 }13014 }
12516 return block.addBinOp(rs.air_tag, casted_lhs, casted_rhs);13015 return block.addBinOp(rs.air_tag, casted_lhs, casted_rhs);
12517}13016}
...@@ -12557,7 +13056,7 @@ fn analyzePtrArithmetic(...@@ -12557,7 +13056,7 @@ fn analyzePtrArithmetic(
12557 // The resulting pointer is aligned to the lcd between the offset (an13056 // The resulting pointer is aligned to the lcd between the offset (an
12558 // arbitrary number) and the alignment factor (always a power of two,13057 // arbitrary number) and the alignment factor (always a power of two,
12559 // non zero).13058 // non zero).
12560 const new_align = @as(u32, 1) << @intCast(u5, @ctz(u64, addend | ptr_info.@"align"));13059 const new_align = @as(u32, 1) << @intCast(u5, @ctz(addend | ptr_info.@"align"));
1256113060
12562 break :t try Type.ptr(sema.arena, sema.mod, .{13061 break :t try Type.ptr(sema.arena, sema.mod, .{
12563 .pointee_type = ptr_info.pointee_type,13062 .pointee_type = ptr_info.pointee_type,
...@@ -12896,6 +13395,14 @@ fn analyzeCmpUnionTag(...@@ -12896,6 +13395,14 @@ fn analyzeCmpUnionTag(
12896 const coerced_tag = try sema.coerce(block, union_tag_ty, tag, tag_src);13395 const coerced_tag = try sema.coerce(block, union_tag_ty, tag, tag_src);
12897 const coerced_union = try sema.coerce(block, union_tag_ty, un, un_src);13396 const coerced_union = try sema.coerce(block, union_tag_ty, un, un_src);
1289813397
13398 if (try sema.resolveMaybeUndefVal(block, tag_src, coerced_tag)) |enum_val| {
13399 if (enum_val.isUndef()) return sema.addConstUndef(Type.bool);
13400 const field_ty = union_ty.unionFieldType(enum_val, sema.mod);
13401 if (field_ty.zigTypeTag() == .NoReturn) {
13402 return Air.Inst.Ref.bool_false;
13403 }
13404 }
13405
12899 return sema.cmpSelf(block, src, coerced_union, coerced_tag, op, un_src, tag_src);13406 return sema.cmpSelf(block, src, coerced_union, coerced_tag, op, un_src, tag_src);
12900}13407}
1290113408
...@@ -13961,10 +14468,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -13961,10 +14468,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
13961 else14468 else
13962 field.default_val;14469 field.default_val;
13963 const default_val_ptr = try sema.optRefValue(block, src, field.ty, opt_default_val);14470 const default_val_ptr = try sema.optRefValue(block, src, field.ty, opt_default_val);
13964 const alignment = switch (layout) {14471 const alignment = field.alignment(target, layout);
13965 .Auto, .Extern => field.normalAlignment(target),
13966 .Packed => 0,
13967 };
1396814472
13969 struct_field_fields.* = .{14473 struct_field_fields.* = .{
13970 // name: []const u8,14474 // name: []const u8,
...@@ -14003,13 +14507,27 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -14003,13 +14507,27 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1400314507
14004 const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, struct_ty.getNamespace());14508 const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, struct_ty.getNamespace());
1400514509
14006 const field_values = try sema.arena.create([4]Value);14510 const backing_integer_val = blk: {
14511 if (layout == .Packed) {
14512 const struct_obj = struct_ty.castTag(.@"struct").?.data;
14513 assert(struct_obj.haveLayout());
14514 assert(struct_obj.backing_int_ty.isInt());
14515 const backing_int_ty_val = try Value.Tag.ty.create(sema.arena, struct_obj.backing_int_ty);
14516 break :blk try Value.Tag.opt_payload.create(sema.arena, backing_int_ty_val);
14517 } else {
14518 break :blk Value.initTag(.null_value);
14519 }
14520 };
14521
14522 const field_values = try sema.arena.create([5]Value);
14007 field_values.* = .{14523 field_values.* = .{
14008 // layout: ContainerLayout,14524 // layout: ContainerLayout,
14009 try Value.Tag.enum_field_index.create(14525 try Value.Tag.enum_field_index.create(
14010 sema.arena,14526 sema.arena,
14011 @enumToInt(layout),14527 @enumToInt(layout),
14012 ),14528 ),
14529 // backing_integer: ?type,
14530 backing_integer_val,
14013 // fields: []const StructField,14531 // fields: []const StructField,
14014 fields_val,14532 fields_val,
14015 // decls: []const Declaration,14533 // decls: []const Declaration,
...@@ -14047,8 +14565,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -14047,8 +14565,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
14047 );14565 );
14048 },14566 },
14049 .BoundFn => @panic("TODO remove this type from the language and compiler"),14567 .BoundFn => @panic("TODO remove this type from the language and compiler"),
14050 .Frame => return sema.fail(block, src, "TODO: implement zirTypeInfo for Frame", .{}),14568 .Frame => return sema.failWithUseOfAsync(block, src),
14051 .AnyFrame => return sema.fail(block, src, "TODO: implement zirTypeInfo for AnyFrame", .{}),14569 .AnyFrame => return sema.failWithUseOfAsync(block, src),
14052 }14570 }
14053}14571}
1405414572
...@@ -14333,6 +14851,20 @@ fn zirBoolBr(...@@ -14333,6 +14851,20 @@ fn zirBoolBr(
14333 const rhs_result = try sema.resolveBody(rhs_block, body, inst);14851 const rhs_result = try sema.resolveBody(rhs_block, body, inst);
14334 _ = try rhs_block.addBr(block_inst, rhs_result);14852 _ = try rhs_block.addBr(block_inst, rhs_result);
1433514853
14854 return finishCondBr(sema, parent_block, &child_block, &then_block, &else_block, lhs, block_inst);
14855}
14856
14857fn finishCondBr(
14858 sema: *Sema,
14859 parent_block: *Block,
14860 child_block: *Block,
14861 then_block: *Block,
14862 else_block: *Block,
14863 cond: Air.Inst.Ref,
14864 block_inst: Air.Inst.Index,
14865) !Air.Inst.Ref {
14866 const gpa = sema.gpa;
14867
14336 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len +14868 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len +
14337 then_block.instructions.items.len + else_block.instructions.items.len +14869 then_block.instructions.items.len + else_block.instructions.items.len +
14338 @typeInfo(Air.Block).Struct.fields.len + child_block.instructions.items.len + 1);14870 @typeInfo(Air.Block).Struct.fields.len + child_block.instructions.items.len + 1);
...@@ -14345,7 +14877,7 @@ fn zirBoolBr(...@@ -14345,7 +14877,7 @@ fn zirBoolBr(
14345 sema.air_extra.appendSliceAssumeCapacity(else_block.instructions.items);14877 sema.air_extra.appendSliceAssumeCapacity(else_block.instructions.items);
1434614878
14347 _ = try child_block.addInst(.{ .tag = .cond_br, .data = .{ .pl_op = .{14879 _ = try child_block.addInst(.{ .tag = .cond_br, .data = .{ .pl_op = .{
14348 .operand = lhs,14880 .operand = cond,
14349 .payload = cond_br_payload,14881 .payload = cond_br_payload,
14350 } } });14882 } } });
1435114883
...@@ -14715,10 +15247,83 @@ fn zirRetLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir...@@ -14715,10 +15247,83 @@ fn zirRetLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir
14715 const operand = try sema.analyzeLoad(block, src, ret_ptr, src);15247 const operand = try sema.analyzeLoad(block, src, ret_ptr, src);
14716 return sema.analyzeRet(block, operand, src);15248 return sema.analyzeRet(block, operand, src);
14717 }15249 }
15250
15251 if (sema.wantErrorReturnTracing()) {
15252 const is_non_err = try sema.analyzePtrIsNonErr(block, src, ret_ptr);
15253 return retWithErrTracing(sema, block, src, is_non_err, .ret_load, ret_ptr);
15254 }
15255
14718 _ = try block.addUnOp(.ret_load, ret_ptr);15256 _ = try block.addUnOp(.ret_load, ret_ptr);
14719 return always_noreturn;15257 return always_noreturn;
14720}15258}
1472115259
15260fn retWithErrTracing(
15261 sema: *Sema,
15262 block: *Block,
15263 src: LazySrcLoc,
15264 is_non_err: Air.Inst.Ref,
15265 ret_tag: Air.Inst.Tag,
15266 operand: Air.Inst.Ref,
15267) CompileError!Zir.Inst.Index {
15268 const need_check = switch (is_non_err) {
15269 .bool_true => {
15270 _ = try block.addUnOp(ret_tag, operand);
15271 return always_noreturn;
15272 },
15273 .bool_false => false,
15274 else => true,
15275 };
15276 const gpa = sema.gpa;
15277 const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace");
15278 const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty);
15279 const ptr_stack_trace_ty = try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty);
15280 const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty);
15281 const return_err_fn = try sema.getBuiltin(block, src, "returnError");
15282 const args: [1]Air.Inst.Ref = .{err_return_trace};
15283
15284 if (!need_check) {
15285 _ = try sema.analyzeCall(block, return_err_fn, src, src, .never_inline, false, &args, null);
15286 _ = try block.addUnOp(ret_tag, operand);
15287 return always_noreturn;
15288 }
15289
15290 var then_block = block.makeSubBlock();
15291 defer then_block.instructions.deinit(gpa);
15292 _ = try then_block.addUnOp(ret_tag, operand);
15293
15294 var else_block = block.makeSubBlock();
15295 defer else_block.instructions.deinit(gpa);
15296 _ = try sema.analyzeCall(&else_block, return_err_fn, src, src, .never_inline, false, &args, null);
15297 _ = try else_block.addUnOp(ret_tag, operand);
15298
15299 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len +
15300 then_block.instructions.items.len + else_block.instructions.items.len +
15301 @typeInfo(Air.Block).Struct.fields.len + 1);
15302
15303 const cond_br_payload = sema.addExtraAssumeCapacity(Air.CondBr{
15304 .then_body_len = @intCast(u32, then_block.instructions.items.len),
15305 .else_body_len = @intCast(u32, else_block.instructions.items.len),
15306 });
15307 sema.air_extra.appendSliceAssumeCapacity(then_block.instructions.items);
15308 sema.air_extra.appendSliceAssumeCapacity(else_block.instructions.items);
15309
15310 _ = try block.addInst(.{ .tag = .cond_br, .data = .{ .pl_op = .{
15311 .operand = is_non_err,
15312 .payload = cond_br_payload,
15313 } } });
15314
15315 return always_noreturn;
15316}
15317
15318fn wantErrorReturnTracing(sema: *Sema) bool {
15319 // TODO implement this feature in all the backends and then delete this check.
15320 const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm;
15321
15322 return sema.fn_ret_ty.isError() and
15323 sema.mod.comp.bin_file.options.error_return_tracing and
15324 backend_supports_error_return_tracing;
15325}
15326
14722fn addToInferredErrorSet(sema: *Sema, uncasted_operand: Air.Inst.Ref) !void {15327fn addToInferredErrorSet(sema: *Sema, uncasted_operand: Air.Inst.Ref) !void {
14723 assert(sema.fn_ret_ty.zigTypeTag() == .ErrorUnion);15328 assert(sema.fn_ret_ty.zigTypeTag() == .ErrorUnion);
1472415329
...@@ -14764,27 +15369,15 @@ fn analyzeRet(...@@ -14764,27 +15369,15 @@ fn analyzeRet(
14764 return always_noreturn;15369 return always_noreturn;
14765 }15370 }
1476615371
14767 // TODO implement this feature in all the backends and then delete this check.15372 try sema.resolveTypeLayout(block, src, sema.fn_ret_ty);
14768 const backend_supports_error_return_tracing =
14769 sema.mod.comp.bin_file.options.use_llvm;
1477015373
14771 if (sema.fn_ret_ty.isError() and15374 if (sema.wantErrorReturnTracing()) {
14772 sema.mod.comp.bin_file.options.error_return_tracing and15375 // Avoid adding a frame to the error return trace in case the value is comptime-known
14773 backend_supports_error_return_tracing)15376 // to be not an error.
14774 ret_err: {15377 const is_non_err = try sema.analyzeIsNonErr(block, src, operand);
14775 if (try sema.resolveMaybeUndefVal(block, src, operand)) |ret_val| {15378 return retWithErrTracing(sema, block, src, is_non_err, .ret, operand);
14776 if (ret_val.tag() != .@"error") break :ret_err;
14777 }
14778 const return_err_fn = try sema.getBuiltin(block, src, "returnError");
14779 const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace");
14780 const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty);
14781 const ptr_stack_trace_ty = try Type.Tag.optional_single_mut_pointer.create(sema.arena, stack_trace_ty);
14782 const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty);
14783 const args: [1]Air.Inst.Ref = .{err_return_trace};
14784 _ = try sema.analyzeCall(block, return_err_fn, src, src, .never_inline, false, &args, null);
14785 }15379 }
1478615380
14787 try sema.resolveTypeLayout(block, src, sema.fn_ret_ty);
14788 _ = try block.addUnOp(.ret, operand);15381 _ = try block.addUnOp(.ret, operand);
14789 return always_noreturn;15382 return always_noreturn;
14790}15383}
...@@ -15015,7 +15608,9 @@ fn unionInit(...@@ -15015,7 +15608,9 @@ fn unionInit(
15015 const init = try sema.coerce(block, field.ty, uncasted_init, init_src);15608 const init = try sema.coerce(block, field.ty, uncasted_init, init_src);
1501615609
15017 if (try sema.resolveMaybeUndefVal(block, init_src, init)) |init_val| {15610 if (try sema.resolveMaybeUndefVal(block, init_src, init)) |init_val| {
15018 const tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index);15611 const tag_ty = union_ty.unionTagTypeHypothetical();
15612 const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);
15613 const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
15019 return sema.addConstant(union_ty, try Value.Tag.@"union".create(sema.arena, .{15614 return sema.addConstant(union_ty, try Value.Tag.@"union".create(sema.arena, .{
15020 .tag = tag_val,15615 .tag = tag_val,
15021 .val = init_val,15616 .val = init_val,
...@@ -15113,7 +15708,9 @@ fn zirStructInit(...@@ -15113,7 +15708,9 @@ fn zirStructInit(
15113 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;15708 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
15114 const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);15709 const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);
15115 const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src);15710 const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src);
15116 const tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index);15711 const tag_ty = resolved_ty.unionTagTypeHypothetical();
15712 const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);
15713 const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
1511715714
15118 const init_inst = try sema.resolveInst(item.data.init);15715 const init_inst = try sema.resolveInst(item.data.init);
15119 if (try sema.resolveMaybeUndefVal(block, field_src, init_inst)) |val| {15716 if (try sema.resolveMaybeUndefVal(block, field_src, init_inst)) |val| {
...@@ -15161,6 +15758,8 @@ fn finishStructInit(...@@ -15161,6 +15758,8 @@ fn finishStructInit(
15161 const gpa = sema.gpa;15758 const gpa = sema.gpa;
1516215759
15163 var root_msg: ?*Module.ErrorMsg = null;15760 var root_msg: ?*Module.ErrorMsg = null;
15761 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
15762
15164 if (struct_ty.isAnonStruct()) {15763 if (struct_ty.isAnonStruct()) {
15165 const struct_obj = struct_ty.castTag(.anon_struct).?.data;15764 const struct_obj = struct_ty.castTag(.anon_struct).?.data;
15166 for (struct_obj.values) |default_val, i| {15765 for (struct_obj.values) |default_val, i| {
...@@ -15216,6 +15815,7 @@ fn finishStructInit(...@@ -15216,6 +15815,7 @@ fn finishStructInit(
15216 }15815 }
1521715816
15218 if (root_msg) |msg| {15817 if (root_msg) |msg| {
15818 root_msg = null;
15219 if (struct_ty.castTag(.@"struct")) |struct_obj| {15819 if (struct_ty.castTag(.@"struct")) |struct_obj| {
15220 const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod);15820 const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod);
15221 defer gpa.free(fqn);15821 defer gpa.free(fqn);
...@@ -15245,6 +15845,7 @@ fn finishStructInit(...@@ -15245,6 +15845,7 @@ fn finishStructInit(
15245 }15845 }
1524615846
15247 if (is_ref) {15847 if (is_ref) {
15848 try sema.resolveStructLayout(block, dest_src, struct_ty);
15248 const target = sema.mod.getTarget();15849 const target = sema.mod.getTarget();
15249 const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{15850 const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{
15250 .pointee_type = struct_ty,15851 .pointee_type = struct_ty,
...@@ -15619,9 +16220,10 @@ fn fieldType(...@@ -15619,9 +16220,10 @@ fn fieldType(
15619 field_src: LazySrcLoc,16220 field_src: LazySrcLoc,
15620 ty_src: LazySrcLoc,16221 ty_src: LazySrcLoc,
15621) CompileError!Air.Inst.Ref {16222) CompileError!Air.Inst.Ref {
15622 const resolved_ty = try sema.resolveTypeFields(block, ty_src, aggregate_ty);16223 var cur_ty = aggregate_ty;
15623 var cur_ty = resolved_ty;
15624 while (true) {16224 while (true) {
16225 const resolved_ty = try sema.resolveTypeFields(block, ty_src, cur_ty);
16226 cur_ty = resolved_ty;
15625 switch (cur_ty.zigTypeTag()) {16227 switch (cur_ty.zigTypeTag()) {
15626 .Struct => {16228 .Struct => {
15627 if (cur_ty.isAnonStruct()) {16229 if (cur_ty.isAnonStruct()) {
...@@ -15693,7 +16295,7 @@ fn zirFrame(...@@ -15693,7 +16295,7 @@ fn zirFrame(
15693 extended: Zir.Inst.Extended.InstData,16295 extended: Zir.Inst.Extended.InstData,
15694) CompileError!Air.Inst.Ref {16296) CompileError!Air.Inst.Ref {
15695 const src = LazySrcLoc.nodeOffset(@bitCast(i32, extended.operand));16297 const src = LazySrcLoc.nodeOffset(@bitCast(i32, extended.operand));
15696 return sema.fail(block, src, "TODO: Sema.zirFrame", .{});16298 return sema.failWithUseOfAsync(block, src);
15697}16299}
1569816300
15699fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {16301fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -15742,7 +16344,7 @@ fn zirUnaryMath(...@@ -15742,7 +16344,7 @@ fn zirUnaryMath(
15742 block: *Block,16344 block: *Block,
15743 inst: Zir.Inst.Index,16345 inst: Zir.Inst.Index,
15744 air_tag: Air.Inst.Tag,16346 air_tag: Air.Inst.Tag,
15745 eval: fn (Value, Type, Allocator, std.Target) Allocator.Error!Value,16347 comptime eval: fn (Value, Type, Allocator, std.Target) Allocator.Error!Value,
15746) CompileError!Air.Inst.Ref {16348) CompileError!Air.Inst.Ref {
15747 const tracy = trace(@src());16349 const tracy = trace(@src());
15748 defer tracy.end();16350 defer tracy.end();
...@@ -15853,25 +16455,30 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -15853,25 +16455,30 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
15853 const field_name = enum_ty.enumFieldName(field_index);16455 const field_name = enum_ty.enumFieldName(field_index);
15854 return sema.addStrLit(block, field_name);16456 return sema.addStrLit(block, field_name);
15855 }16457 }
16458 try sema.requireRuntimeBlock(block, src, operand_src);
16459 if (block.wantSafety() and sema.mod.comp.bin_file.options.use_llvm) {
16460 const ok = try block.addUnOp(.is_named_enum_value, casted_operand);
16461 try sema.addSafetyCheck(block, ok, .invalid_enum_value);
16462 }
15856 // In case the value is runtime-known, we have an AIR instruction for this instead16463 // In case the value is runtime-known, we have an AIR instruction for this instead
15857 // of trying to lower it in Sema because an optimization pass may result in the operand16464 // of trying to lower it in Sema because an optimization pass may result in the operand
15858 // being comptime-known, which would let us elide the `tag_name` AIR instruction.16465 // being comptime-known, which would let us elide the `tag_name` AIR instruction.
15859 return block.addUnOp(.tag_name, casted_operand);16466 return block.addUnOp(.tag_name, casted_operand);
15860}16467}
1586116468
15862fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {16469fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
15863 const mod = sema.mod;16470 const mod = sema.mod;
15864 const inst_data = sema.code.instructions.items(.data)[inst].un_node;16471 const name_strategy = @intToEnum(Zir.Inst.NameStrategy, extended.small);
15865 const src = inst_data.src();16472 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
16473 const src = LazySrcLoc.nodeOffset(extra.node);
15866 const type_info_ty = try sema.resolveBuiltinTypeFields(block, src, "Type");16474 const type_info_ty = try sema.resolveBuiltinTypeFields(block, src, "Type");
15867 const uncasted_operand = try sema.resolveInst(inst_data.operand);16475 const uncasted_operand = try sema.resolveInst(extra.operand);
15868 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };16476 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
15869 const type_info = try sema.coerce(block, type_info_ty, uncasted_operand, operand_src);16477 const type_info = try sema.coerce(block, type_info_ty, uncasted_operand, operand_src);
15870 const val = try sema.resolveConstValue(block, operand_src, type_info, "operand to @Type must be comptime known");16478 const val = try sema.resolveConstValue(block, operand_src, type_info, "operand to @Type must be comptime known");
15871 const union_val = val.cast(Value.Payload.Union).?.data;16479 const union_val = val.cast(Value.Payload.Union).?.data;
15872 const tag_ty = type_info_ty.unionTagType().?;
15873 const target = mod.getTarget();16480 const target = mod.getTarget();
15874 const tag_index = tag_ty.enumTagFieldIndex(union_val.tag, mod).?;16481 const tag_index = type_info_ty.unionTagFieldIndex(union_val.tag, mod).?;
15875 if (union_val.val.anyUndef()) return sema.failWithUseOfUndef(block, src);16482 if (union_val.val.anyUndef()) return sema.failWithUseOfUndef(block, src);
15876 switch (@intToEnum(std.builtin.TypeId, tag_index)) {16483 switch (@intToEnum(std.builtin.TypeId, tag_index)) {
15877 .Type => return Air.Inst.Ref.type_type,16484 .Type => return Air.Inst.Ref.type_type,
...@@ -15882,7 +16489,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I...@@ -15882,7 +16489,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
15882 .ComptimeInt => return Air.Inst.Ref.comptime_int_type,16489 .ComptimeInt => return Air.Inst.Ref.comptime_int_type,
15883 .Undefined => return Air.Inst.Ref.undefined_type,16490 .Undefined => return Air.Inst.Ref.undefined_type,
15884 .Null => return Air.Inst.Ref.null_type,16491 .Null => return Air.Inst.Ref.null_type,
15885 .AnyFrame => return Air.Inst.Ref.anyframe_type,16492 .AnyFrame => return sema.failWithUseOfAsync(block, src),
15886 .EnumLiteral => return Air.Inst.Ref.enum_literal_type,16493 .EnumLiteral => return Air.Inst.Ref.enum_literal_type,
15887 .Int => {16494 .Int => {
15888 const struct_val = union_val.val.castTag(.aggregate).?.data;16495 const struct_val = union_val.val.castTag(.aggregate).?.data;
...@@ -15945,7 +16552,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I...@@ -15945,7 +16552,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
15945 if (!try sema.intFitsInType(block, src, alignment_val, Type.u32, null)) {16552 if (!try sema.intFitsInType(block, src, alignment_val, Type.u32, null)) {
15946 return sema.fail(block, src, "alignment must fit in 'u32'", .{});16553 return sema.fail(block, src, "alignment must fit in 'u32'", .{});
15947 }16554 }
15948 const abi_align = @intCast(u29, alignment_val.toUnsignedInt(target));16555 const abi_align = @intCast(u29, (try alignment_val.getUnsignedIntAdvanced(target, sema.kit(block, src))).?);
1594916556
15950 var buffer: Value.ToTypeBuffer = undefined;16557 var buffer: Value.ToTypeBuffer = undefined;
15951 const unresolved_elem_ty = child_val.toType(&buffer);16558 const unresolved_elem_ty = child_val.toType(&buffer);
...@@ -16110,22 +16717,31 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I...@@ -16110,22 +16717,31 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
16110 const struct_val = union_val.val.castTag(.aggregate).?.data;16717 const struct_val = union_val.val.castTag(.aggregate).?.data;
16111 // layout: containerlayout,16718 // layout: containerlayout,
16112 const layout_val = struct_val[0];16719 const layout_val = struct_val[0];
16720 // backing_int: ?type,
16721 const backing_int_val = struct_val[1];
16113 // fields: []const enumfield,16722 // fields: []const enumfield,
16114 const fields_val = struct_val[1];16723 const fields_val = struct_val[2];
16115 // decls: []const declaration,16724 // decls: []const declaration,
16116 const decls_val = struct_val[2];16725 const decls_val = struct_val[3];
16117 // is_tuple: bool,16726 // is_tuple: bool,
16118 const is_tuple_val = struct_val[3];16727 const is_tuple_val = struct_val[4];
16728 assert(struct_val.len == 5);
16729
16730 const layout = layout_val.toEnum(std.builtin.Type.ContainerLayout);
1611916731
16120 // Decls16732 // Decls
16121 if (decls_val.sliceLen(mod) > 0) {16733 if (decls_val.sliceLen(mod) > 0) {
16122 return sema.fail(block, src, "reified structs must have no decls", .{});16734 return sema.fail(block, src, "reified structs must have no decls", .{});
16123 }16735 }
1612416736
16737 if (layout != .Packed and !backing_int_val.isNull()) {
16738 return sema.fail(block, src, "non-packed struct does not support backing integer type", .{});
16739 }
16740
16125 return if (is_tuple_val.toBool())16741 return if (is_tuple_val.toBool())
16126 try sema.reifyTuple(block, src, fields_val)16742 try sema.reifyTuple(block, src, fields_val)
16127 else16743 else
16128 try sema.reifyStruct(block, inst, src, layout_val, fields_val);16744 try sema.reifyStruct(block, inst, src, layout, backing_int_val, fields_val, name_strategy);
16129 },16745 },
16130 .Enum => {16746 .Enum => {
16131 const struct_val = union_val.val.castTag(.aggregate).?.data;16747 const struct_val = union_val.val.castTag(.aggregate).?.data;
...@@ -16171,10 +16787,10 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I...@@ -16171,10 +16787,10 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
16171 };16787 };
16172 const enum_ty = Type.initPayload(&enum_ty_payload.base);16788 const enum_ty = Type.initPayload(&enum_ty_payload.base);
16173 const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty);16789 const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty);
16174 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{16790 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
16175 .ty = Type.type,16791 .ty = Type.type,
16176 .val = enum_val,16792 .val = enum_val,
16177 }, .anon, "enum", null);16793 }, name_strategy, "enum", inst);
16178 const new_decl = mod.declPtr(new_decl_index);16794 const new_decl = mod.declPtr(new_decl_index);
16179 new_decl.owns_tv = true;16795 new_decl.owns_tv = true;
16180 errdefer mod.abortAnonDecl(new_decl_index);16796 errdefer mod.abortAnonDecl(new_decl_index);
...@@ -16185,7 +16801,6 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I...@@ -16185,7 +16801,6 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
16185 .tag_ty_inferred = false,16801 .tag_ty_inferred = false,
16186 .fields = .{},16802 .fields = .{},
16187 .values = .{},16803 .values = .{},
16188 .node_offset = src.node_offset.x,
16189 .namespace = .{16804 .namespace = .{
16190 .parent = block.namespace,16805 .parent = block.namespace,
16191 .ty = enum_ty,16806 .ty = enum_ty,
...@@ -16204,43 +16819,39 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I...@@ -16204,43 +16819,39 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
1620416819
16205 // Fields16820 // Fields
16206 const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod));16821 const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod));
16207 if (fields_len > 0) {16822 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
16208 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);16823 try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{
16209 try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{16824 .ty = enum_obj.tag_ty,
16210 .ty = enum_obj.tag_ty,16825 .mod = mod,
16211 .mod = mod,16826 });
16212 });
16213
16214 var i: usize = 0;
16215 while (i < fields_len) : (i += 1) {
16216 const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i);
16217 const field_struct_val = elem_val.castTag(.aggregate).?.data;
16218 // TODO use reflection instead of magic numbers here
16219 // name: []const u8
16220 const name_val = field_struct_val[0];
16221 // value: comptime_int
16222 const value_val = field_struct_val[1];
16223
16224 const field_name = try name_val.toAllocatedBytes(
16225 Type.initTag(.const_slice_u8),
16226 new_decl_arena_allocator,
16227 sema.mod,
16228 );
1622916827
16230 const gop = enum_obj.fields.getOrPutAssumeCapacity(field_name);16828 var i: usize = 0;
16231 if (gop.found_existing) {16829 while (i < fields_len) : (i += 1) {
16232 // TODO: better source location16830 const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i);
16233 return sema.fail(block, src, "duplicate enum tag {s}", .{field_name});16831 const field_struct_val = elem_val.castTag(.aggregate).?.data;
16234 }16832 // TODO use reflection instead of magic numbers here
16833 // name: []const u8
16834 const name_val = field_struct_val[0];
16835 // value: comptime_int
16836 const value_val = field_struct_val[1];
16837
16838 const field_name = try name_val.toAllocatedBytes(
16839 Type.initTag(.const_slice_u8),
16840 new_decl_arena_allocator,
16841 sema.mod,
16842 );
1623516843
16236 const copied_tag_val = try value_val.copy(new_decl_arena_allocator);16844 const gop = enum_obj.fields.getOrPutAssumeCapacity(field_name);
16237 enum_obj.values.putAssumeCapacityNoClobberContext(copied_tag_val, {}, .{16845 if (gop.found_existing) {
16238 .ty = enum_obj.tag_ty,16846 // TODO: better source location
16239 .mod = mod,16847 return sema.fail(block, src, "duplicate enum tag {s}", .{field_name});
16240 });
16241 }16848 }
16242 } else {16849
16243 return sema.fail(block, src, "enums must have at least one field", .{});16850 const copied_tag_val = try value_val.copy(new_decl_arena_allocator);
16851 enum_obj.values.putAssumeCapacityNoClobberContext(copied_tag_val, {}, .{
16852 .ty = enum_obj.tag_ty,
16853 .mod = mod,
16854 });
16244 }16855 }
1624516856
16246 try new_decl.finalizeNewArena(&new_decl_arena);16857 try new_decl.finalizeNewArena(&new_decl_arena);
...@@ -16268,17 +16879,16 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I...@@ -16268,17 +16879,16 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
16268 };16879 };
16269 const opaque_ty = Type.initPayload(&opaque_ty_payload.base);16880 const opaque_ty = Type.initPayload(&opaque_ty_payload.base);
16270 const opaque_val = try Value.Tag.ty.create(new_decl_arena_allocator, opaque_ty);16881 const opaque_val = try Value.Tag.ty.create(new_decl_arena_allocator, opaque_ty);
16271 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{16882 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
16272 .ty = Type.type,16883 .ty = Type.type,
16273 .val = opaque_val,16884 .val = opaque_val,
16274 }, .anon, "opaque", null);16885 }, name_strategy, "opaque", inst);
16275 const new_decl = mod.declPtr(new_decl_index);16886 const new_decl = mod.declPtr(new_decl_index);
16276 new_decl.owns_tv = true;16887 new_decl.owns_tv = true;
16277 errdefer mod.abortAnonDecl(new_decl_index);16888 errdefer mod.abortAnonDecl(new_decl_index);
1627816889
16279 opaque_obj.* = .{16890 opaque_obj.* = .{
16280 .owner_decl = new_decl_index,16891 .owner_decl = new_decl_index,
16281 .node_offset = src.node_offset.x,
16282 .namespace = .{16892 .namespace = .{
16283 .parent = block.namespace,16893 .parent = block.namespace,
16284 .ty = opaque_ty,16894 .ty = opaque_ty,
...@@ -16327,10 +16937,10 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I...@@ -16327,10 +16937,10 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
16327 };16937 };
16328 const union_ty = Type.initPayload(&union_payload.base);16938 const union_ty = Type.initPayload(&union_payload.base);
16329 const new_union_val = try Value.Tag.ty.create(new_decl_arena_allocator, union_ty);16939 const new_union_val = try Value.Tag.ty.create(new_decl_arena_allocator, union_ty);
16330 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{16940 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
16331 .ty = Type.type,16941 .ty = Type.type,
16332 .val = new_union_val,16942 .val = new_union_val,
16333 }, .anon, "union", null);16943 }, name_strategy, "union", inst);
16334 const new_decl = mod.declPtr(new_decl_index);16944 const new_decl = mod.declPtr(new_decl_index);
16335 new_decl.owns_tv = true;16945 new_decl.owns_tv = true;
16336 errdefer mod.abortAnonDecl(new_decl_index);16946 errdefer mod.abortAnonDecl(new_decl_index);
...@@ -16338,7 +16948,6 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I...@@ -16338,7 +16948,6 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
16338 .owner_decl = new_decl_index,16948 .owner_decl = new_decl_index,
16339 .tag_ty = Type.initTag(.@"null"),16949 .tag_ty = Type.initTag(.@"null"),
16340 .fields = .{},16950 .fields = .{},
16341 .node_offset = src.node_offset.x,
16342 .zir_index = inst,16951 .zir_index = inst,
16343 .layout = layout,16952 .layout = layout,
16344 .status = .have_field_types,16953 .status = .have_field_types,
...@@ -16367,58 +16976,54 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I...@@ -16367,58 +16976,54 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
16367 }16976 }
1636816977
16369 // Fields16978 // Fields
16370 if (fields_len > 0) {16979 try union_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
16371 try union_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
16372
16373 var i: usize = 0;
16374 while (i < fields_len) : (i += 1) {
16375 const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i);
16376 const field_struct_val = elem_val.castTag(.aggregate).?.data;
16377 // TODO use reflection instead of magic numbers here
16378 // name: []const u8
16379 const name_val = field_struct_val[0];
16380 // field_type: type,
16381 const field_type_val = field_struct_val[1];
16382 // alignment: comptime_int,
16383 const alignment_val = field_struct_val[2];
1638416980
16385 const field_name = try name_val.toAllocatedBytes(16981 var i: usize = 0;
16386 Type.initTag(.const_slice_u8),16982 while (i < fields_len) : (i += 1) {
16387 new_decl_arena_allocator,16983 const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i);
16388 sema.mod,16984 const field_struct_val = elem_val.castTag(.aggregate).?.data;
16389 );16985 // TODO use reflection instead of magic numbers here
16986 // name: []const u8
16987 const name_val = field_struct_val[0];
16988 // field_type: type,
16989 const field_type_val = field_struct_val[1];
16990 // alignment: comptime_int,
16991 const alignment_val = field_struct_val[2];
1639016992
16391 if (enum_field_names) |set| {16993 const field_name = try name_val.toAllocatedBytes(
16392 set.putAssumeCapacity(field_name, {});16994 Type.initTag(.const_slice_u8),
16393 }16995 new_decl_arena_allocator,
16996 sema.mod,
16997 );
1639416998
16395 if (tag_ty_field_names) |*names| {16999 if (enum_field_names) |set| {
16396 const enum_has_field = names.orderedRemove(field_name);17000 set.putAssumeCapacity(field_name, {});
16397 if (!enum_has_field) {17001 }
16398 const msg = msg: {
16399 const msg = try sema.errMsg(block, src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(sema.mod) });
16400 errdefer msg.destroy(sema.gpa);
16401 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
16402 break :msg msg;
16403 };
16404 return sema.failWithOwnedErrorMsg(msg);
16405 }
16406 }
1640717002
16408 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);17003 if (tag_ty_field_names) |*names| {
16409 if (gop.found_existing) {17004 const enum_has_field = names.orderedRemove(field_name);
16410 // TODO: better source location17005 if (!enum_has_field) {
16411 return sema.fail(block, src, "duplicate union field {s}", .{field_name});17006 const msg = msg: {
17007 const msg = try sema.errMsg(block, src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(sema.mod) });
17008 errdefer msg.destroy(sema.gpa);
17009 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
17010 break :msg msg;
17011 };
17012 return sema.failWithOwnedErrorMsg(msg);
16412 }17013 }
17014 }
1641317015
16414 var buffer: Value.ToTypeBuffer = undefined;17016 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);
16415 gop.value_ptr.* = .{17017 if (gop.found_existing) {
16416 .ty = try field_type_val.toType(&buffer).copy(new_decl_arena_allocator),17018 // TODO: better source location
16417 .abi_align = @intCast(u32, alignment_val.toUnsignedInt(target)),17019 return sema.fail(block, src, "duplicate union field {s}", .{field_name});
16418 };
16419 }17020 }
16420 } else {17021
16421 return sema.fail(block, src, "unions must have at least one field", .{});17022 var buffer: Value.ToTypeBuffer = undefined;
17023 gop.value_ptr.* = .{
17024 .ty = try field_type_val.toType(&buffer).copy(new_decl_arena_allocator),
17025 .abi_align = @intCast(u32, alignment_val.toUnsignedInt(target)),
17026 };
16422 }17027 }
1642317028
16424 if (tag_ty_field_names) |names| {17029 if (tag_ty_field_names) |names| {
...@@ -16534,7 +17139,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I...@@ -16534,7 +17139,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
16534 return sema.addType(ty);17139 return sema.addType(ty);
16535 },17140 },
16536 .BoundFn => @panic("TODO delete BoundFn from the language"),17141 .BoundFn => @panic("TODO delete BoundFn from the language"),
16537 .Frame => @panic("TODO implement https://github.com/ziglang/zig/issues/10710"),17142 .Frame => return sema.failWithUseOfAsync(block, src),
16538 }17143 }
16539}17144}
1654017145
...@@ -16621,8 +17226,10 @@ fn reifyStruct(...@@ -16621,8 +17226,10 @@ fn reifyStruct(
16621 block: *Block,17226 block: *Block,
16622 inst: Zir.Inst.Index,17227 inst: Zir.Inst.Index,
16623 src: LazySrcLoc,17228 src: LazySrcLoc,
16624 layout_val: Value,17229 layout: std.builtin.Type.ContainerLayout,
17230 backing_int_val: Value,
16625 fields_val: Value,17231 fields_val: Value,
17232 name_strategy: Zir.Inst.NameStrategy,
16626) CompileError!Air.Inst.Ref {17233) CompileError!Air.Inst.Ref {
16627 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);17234 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
16628 errdefer new_decl_arena.deinit();17235 errdefer new_decl_arena.deinit();
...@@ -16632,19 +17239,18 @@ fn reifyStruct(...@@ -16632,19 +17239,18 @@ fn reifyStruct(
16632 const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj);17239 const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj);
16633 const new_struct_val = try Value.Tag.ty.create(new_decl_arena_allocator, struct_ty);17240 const new_struct_val = try Value.Tag.ty.create(new_decl_arena_allocator, struct_ty);
16634 const mod = sema.mod;17241 const mod = sema.mod;
16635 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{17242 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
16636 .ty = Type.type,17243 .ty = Type.type,
16637 .val = new_struct_val,17244 .val = new_struct_val,
16638 }, .anon, "struct", null);17245 }, name_strategy, "struct", inst);
16639 const new_decl = mod.declPtr(new_decl_index);17246 const new_decl = mod.declPtr(new_decl_index);
16640 new_decl.owns_tv = true;17247 new_decl.owns_tv = true;
16641 errdefer mod.abortAnonDecl(new_decl_index);17248 errdefer mod.abortAnonDecl(new_decl_index);
16642 struct_obj.* = .{17249 struct_obj.* = .{
16643 .owner_decl = new_decl_index,17250 .owner_decl = new_decl_index,
16644 .fields = .{},17251 .fields = .{},
16645 .node_offset = src.node_offset.x,
16646 .zir_index = inst,17252 .zir_index = inst,
16647 .layout = layout_val.toEnum(std.builtin.Type.ContainerLayout),17253 .layout = layout,
16648 .status = .have_field_types,17254 .status = .have_field_types,
16649 .known_non_opv = false,17255 .known_non_opv = false,
16650 .namespace = .{17256 .namespace = .{
...@@ -16710,6 +17316,41 @@ fn reifyStruct(...@@ -16710,6 +17316,41 @@ fn reifyStruct(
16710 };17316 };
16711 }17317 }
1671217318
17319 if (layout == .Packed) {
17320 struct_obj.status = .layout_wip;
17321
17322 for (struct_obj.fields.values()) |field, index| {
17323 sema.resolveTypeLayout(block, src, field.ty) catch |err| switch (err) {
17324 error.AnalysisFail => {
17325 const msg = sema.err orelse return err;
17326 try sema.addFieldErrNote(block, struct_ty, index, msg, "while checking this field", .{});
17327 return err;
17328 },
17329 else => return err,
17330 };
17331 }
17332
17333 var fields_bit_sum: u64 = 0;
17334 for (struct_obj.fields.values()) |field| {
17335 fields_bit_sum += field.ty.bitSize(target);
17336 }
17337
17338 if (backing_int_val.optionalValue()) |payload| {
17339 var buf: Value.ToTypeBuffer = undefined;
17340 const backing_int_ty = payload.toType(&buf);
17341 try sema.checkBackingIntType(block, src, backing_int_ty, fields_bit_sum);
17342 struct_obj.backing_int_ty = try backing_int_ty.copy(new_decl_arena_allocator);
17343 } else {
17344 var buf: Type.Payload.Bits = .{
17345 .base = .{ .tag = .int_unsigned },
17346 .data = @intCast(u16, fields_bit_sum),
17347 };
17348 struct_obj.backing_int_ty = try Type.initPayload(&buf.base).copy(new_decl_arena_allocator);
17349 }
17350
17351 struct_obj.status = .have_layout;
17352 }
17353
16713 try new_decl.finalizeNewArena(&new_decl_arena);17354 try new_decl.finalizeNewArena(&new_decl_arena);
16714 return sema.analyzeDeclVal(block, src, new_decl_index);17355 return sema.analyzeDeclVal(block, src, new_decl_index);
16715}17356}
...@@ -16736,13 +17377,13 @@ fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -16736,13 +17377,13 @@ fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
16736fn zirFrameType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {17377fn zirFrameType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
16737 const inst_data = sema.code.instructions.items(.data)[inst].un_node;17378 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
16738 const src = inst_data.src();17379 const src = inst_data.src();
16739 return sema.fail(block, src, "TODO: Sema.zirFrameType", .{});17380 return sema.failWithUseOfAsync(block, src);
16740}17381}
1674117382
16742fn zirFrameSize(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {17383fn zirFrameSize(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
16743 const inst_data = sema.code.instructions.items(.data)[inst].un_node;17384 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
16744 const src = inst_data.src();17385 const src = inst_data.src();
16745 return sema.fail(block, src, "TODO: Sema.zirFrameSize", .{});17386 return sema.failWithUseOfAsync(block, src);
16746}17387}
1674717388
16748fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {17389fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -16834,7 +17475,7 @@ fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -16834,7 +17475,7 @@ fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
16834 }17475 }
1683517476
16836 try sema.requireRuntimeBlock(block, src, operand_src);17477 try sema.requireRuntimeBlock(block, src, operand_src);
16837 if (block.wantSafety()) {17478 if (block.wantSafety() and try sema.typeHasRuntimeBits(block, sema.src, type_res.elemType2())) {
16838 if (!type_res.isAllowzeroPtr()) {17479 if (!type_res.isAllowzeroPtr()) {
16839 const is_non_zero = try block.addBinOp(.cmp_neq, operand_coerced, .zero_usize);17480 const is_non_zero = try block.addBinOp(.cmp_neq, operand_coerced, .zero_usize);
16840 try sema.addSafetyCheck(block, is_non_zero, .cast_to_null);17481 try sema.addSafetyCheck(block, is_non_zero, .cast_to_null);
...@@ -16931,17 +17572,10 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat...@@ -16931,17 +17572,10 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
16931 }17572 }
1693217573
16933 try sema.requireRuntimeBlock(block, src, operand_src);17574 try sema.requireRuntimeBlock(block, src, operand_src);
16934 if (block.wantSafety() and !dest_ty.isAnyError()) {17575 if (block.wantSafety() and !dest_ty.isAnyError() and sema.mod.comp.bin_file.options.use_llvm) {
16935 const err_int_inst = try block.addBitCast(Type.u16, operand);17576 const err_int_inst = try block.addBitCast(Type.err_int, operand);
16936 // TODO: Output a switch instead of chained OR's.17577 const ok = try block.addTyOp(.error_set_has_value, dest_ty, err_int_inst);
16937 var found_match: Air.Inst.Ref = undefined;17578 try sema.addSafetyCheck(block, ok, .invalid_error_code);
16938 for (dest_ty.errorSetNames()) |dest_err_name, i| {
16939 const dest_err_int = (try sema.mod.getErrorValue(dest_err_name)).value;
16940 const dest_err_int_inst = try sema.addIntUnsigned(Type.u16, dest_err_int);
16941 const next_match = try block.addBinOp(.cmp_eq, dest_err_int_inst, err_int_inst);
16942 found_match = if (i == 0) next_match else try block.addBinOp(.bool_or, found_match, next_match);
16943 }
16944 try sema.addSafetyCheck(block, found_match, .invalid_error_code);
16945 }17579 }
16946 return block.addBitCast(dest_ty, operand);17580 return block.addBitCast(dest_ty, operand);
16947}17581}
...@@ -16969,6 +17603,15 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -16969,6 +17603,15 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
16969 else17603 else
16970 operand;17604 operand;
1697117605
17606 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |operand_val| {
17607 if (!dest_ty.ptrAllowsZero() and operand_val.isUndef()) {
17608 return sema.failWithUseOfUndef(block, operand_src);
17609 }
17610 if (!dest_ty.ptrAllowsZero() and operand_val.isNull()) {
17611 return sema.fail(block, operand_src, "null pointer casted to type {}", .{dest_ty.fmt(sema.mod)});
17612 }
17613 }
17614
16972 const dest_elem_ty = dest_ty.elemType2();17615 const dest_elem_ty = dest_ty.elemType2();
16973 try sema.resolveTypeLayout(block, dest_ty_src, dest_elem_ty);17616 try sema.resolveTypeLayout(block, dest_ty_src, dest_elem_ty);
16974 const dest_align = dest_ty.ptrAlignment(target);17617 const dest_align = dest_ty.ptrAlignment(target);
...@@ -17126,7 +17769,9 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -17126,7 +17769,9 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
17126 }17769 }
1712717770
17128 try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src);17771 try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src);
17129 if (block.wantSafety() and dest_align > 1) {17772 if (block.wantSafety() and dest_align > 1 and
17773 try sema.typeHasRuntimeBits(block, sema.src, dest_ty.elemType2()))
17774 {
17130 const val_payload = try sema.arena.create(Value.Payload.U64);17775 const val_payload = try sema.arena.create(Value.Payload.U64);
17131 val_payload.* = .{17776 val_payload.* = .{
17132 .base = .{ .tag = .int_u64 },17777 .base = .{ .tag = .int_u64 },
...@@ -17145,7 +17790,7 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -17145,7 +17790,7 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
17145 const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);17790 const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);
17146 const ok = if (ptr_ty.isSlice()) ok: {17791 const ok = if (ptr_ty.isSlice()) ok: {
17147 const len = try sema.analyzeSliceLen(block, ptr_src, ptr);17792 const len = try sema.analyzeSliceLen(block, ptr_src, ptr);
17148 const len_zero = try block.addBinOp(.cmp_eq, len, try sema.addConstant(Type.usize, Value.zero));17793 const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize);
17149 break :ok try block.addBinOp(.bit_or, len_zero, is_aligned);17794 break :ok try block.addBinOp(.bit_or, len_zero, is_aligned);
17150 } else is_aligned;17795 } else is_aligned;
17151 try sema.addSafetyCheck(block, ok, .incorrect_alignment);17796 try sema.addSafetyCheck(block, ok, .incorrect_alignment);
...@@ -17158,11 +17803,11 @@ fn zirBitCount(...@@ -17158,11 +17803,11 @@ fn zirBitCount(
17158 block: *Block,17803 block: *Block,
17159 inst: Zir.Inst.Index,17804 inst: Zir.Inst.Index,
17160 air_tag: Air.Inst.Tag,17805 air_tag: Air.Inst.Tag,
17161 comptimeOp: fn (val: Value, ty: Type, target: std.Target) u64,17806 comptime comptimeOp: fn (val: Value, ty: Type, target: std.Target) u64,
17162) CompileError!Air.Inst.Ref {17807) CompileError!Air.Inst.Ref {
17163 const inst_data = sema.code.instructions.items(.data)[inst].un_node;17808 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
17164 const src = inst_data.src();17809 const src = inst_data.src();
17165 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };17810 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
17166 const operand = try sema.resolveInst(inst_data.operand);17811 const operand = try sema.resolveInst(inst_data.operand);
17167 const operand_ty = sema.typeOf(operand);17812 const operand_ty = sema.typeOf(operand);
17168 _ = try checkIntOrVector(sema, block, operand, operand_src);17813 _ = try checkIntOrVector(sema, block, operand, operand_src);
...@@ -17214,17 +17859,16 @@ fn zirBitCount(...@@ -17214,17 +17859,16 @@ fn zirBitCount(
17214fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {17859fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
17215 const inst_data = sema.code.instructions.items(.data)[inst].un_node;17860 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
17216 const src = inst_data.src();17861 const src = inst_data.src();
17217 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };17862 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
17218 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
17219 const operand = try sema.resolveInst(inst_data.operand);17863 const operand = try sema.resolveInst(inst_data.operand);
17220 const operand_ty = sema.typeOf(operand);17864 const operand_ty = sema.typeOf(operand);
17221 const scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src);17865 const scalar_ty = try sema.checkIntOrVector(block, operand, operand_src);
17222 const target = sema.mod.getTarget();17866 const target = sema.mod.getTarget();
17223 const bits = scalar_ty.intInfo(target).bits;17867 const bits = scalar_ty.intInfo(target).bits;
17224 if (bits % 8 != 0) {17868 if (bits % 8 != 0) {
17225 return sema.fail(17869 return sema.fail(
17226 block,17870 block,
17227 ty_src,17871 operand_src,
17228 "@byteSwap requires the number of bits to be evenly divisible by 8, but {} has {} bits",17872 "@byteSwap requires the number of bits to be evenly divisible by 8, but {} has {} bits",
17229 .{ scalar_ty.fmt(sema.mod), bits },17873 .{ scalar_ty.fmt(sema.mod), bits },
17230 );17874 );
...@@ -17235,7 +17879,7 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17235,7 +17879,7 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17235 }17879 }
1723617880
17237 switch (operand_ty.zigTypeTag()) {17881 switch (operand_ty.zigTypeTag()) {
17238 .Int, .ComptimeInt => {17882 .Int => {
17239 const runtime_src = if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {17883 const runtime_src = if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
17240 if (val.isUndef()) return sema.addConstUndef(operand_ty);17884 if (val.isUndef()) return sema.addConstUndef(operand_ty);
17241 const result_val = try val.byteSwap(operand_ty, target, sema.arena);17885 const result_val = try val.byteSwap(operand_ty, target, sema.arena);
...@@ -17273,7 +17917,7 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17273,7 +17917,7 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17273fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {17917fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
17274 const inst_data = sema.code.instructions.items(.data)[inst].un_node;17918 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
17275 const src = inst_data.src();17919 const src = inst_data.src();
17276 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };17920 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
17277 const operand = try sema.resolveInst(inst_data.operand);17921 const operand = try sema.resolveInst(inst_data.operand);
17278 const operand_ty = sema.typeOf(operand);17922 const operand_ty = sema.typeOf(operand);
17279 _ = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src);17923 _ = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src);
...@@ -18973,13 +19617,13 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void...@@ -18973,13 +19617,13 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
18973fn zirBuiltinAsyncCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {19617fn zirBuiltinAsyncCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
18974 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;19618 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
18975 const src = inst_data.src();19619 const src = inst_data.src();
18976 return sema.fail(block, src, "TODO: Sema.zirBuiltinAsyncCall", .{});19620 return sema.failWithUseOfAsync(block, src);
18977}19621}
1897819622
18979fn zirResume(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {19623fn zirResume(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
18980 const inst_data = sema.code.instructions.items(.data)[inst].un_node;19624 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
18981 const src = inst_data.src();19625 const src = inst_data.src();
18982 return sema.fail(block, src, "TODO: Sema.zirResume", .{});19626 return sema.failWithUseOfAsync(block, src);
18983}19627}
1898419628
18985fn zirAwait(19629fn zirAwait(
...@@ -18990,7 +19634,7 @@ fn zirAwait(...@@ -18990,7 +19634,7 @@ fn zirAwait(
18990 const inst_data = sema.code.instructions.items(.data)[inst].un_node;19634 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
18991 const src = inst_data.src();19635 const src = inst_data.src();
1899219636
18993 return sema.fail(block, src, "TODO: Sema.zirAwait", .{});19637 return sema.failWithUseOfAsync(block, src);
18994}19638}
1899519639
18996fn zirAwaitNosuspend(19640fn zirAwaitNosuspend(
...@@ -19001,7 +19645,7 @@ fn zirAwaitNosuspend(...@@ -19001,7 +19645,7 @@ fn zirAwaitNosuspend(
19001 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;19645 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
19002 const src = LazySrcLoc.nodeOffset(extra.node);19646 const src = LazySrcLoc.nodeOffset(extra.node);
1900319647
19004 return sema.fail(block, src, "TODO: Sema.zirAwaitNosuspend", .{});19648 return sema.failWithUseOfAsync(block, src);
19005}19649}
1900619650
19007fn zirVarExtended(19651fn zirVarExtended(
...@@ -19670,6 +20314,8 @@ fn validateRunTimeType(...@@ -19670,6 +20314,8 @@ fn validateRunTimeType(
19670 };20314 };
19671}20315}
1967220316
20317const TypeSet = std.HashMapUnmanaged(Type, void, Type.HashContext64, std.hash_map.default_max_load_percentage);
20318
19673fn explainWhyTypeIsComptime(20319fn explainWhyTypeIsComptime(
19674 sema: *Sema,20320 sema: *Sema,
19675 block: *Block,20321 block: *Block,
...@@ -19677,6 +20323,22 @@ fn explainWhyTypeIsComptime(...@@ -19677,6 +20323,22 @@ fn explainWhyTypeIsComptime(
19677 msg: *Module.ErrorMsg,20323 msg: *Module.ErrorMsg,
19678 src_loc: Module.SrcLoc,20324 src_loc: Module.SrcLoc,
19679 ty: Type,20325 ty: Type,
20326) CompileError!void {
20327 var type_set = TypeSet{};
20328 defer type_set.deinit(sema.gpa);
20329
20330 try sema.resolveTypeFully(block, src, ty);
20331 return sema.explainWhyTypeIsComptimeInner(block, src, msg, src_loc, ty, &type_set);
20332}
20333
20334fn explainWhyTypeIsComptimeInner(
20335 sema: *Sema,
20336 block: *Block,
20337 src: LazySrcLoc,
20338 msg: *Module.ErrorMsg,
20339 src_loc: Module.SrcLoc,
20340 ty: Type,
20341 type_set: *TypeSet,
19680) CompileError!void {20342) CompileError!void {
19681 const mod = sema.mod;20343 const mod = sema.mod;
19682 switch (ty.zigTypeTag()) {20344 switch (ty.zigTypeTag()) {
...@@ -19714,7 +20376,7 @@ fn explainWhyTypeIsComptime(...@@ -19714,7 +20376,7 @@ fn explainWhyTypeIsComptime(
19714 },20376 },
1971520377
19716 .Array, .Vector => {20378 .Array, .Vector => {
19717 try sema.explainWhyTypeIsComptime(block, src, msg, src_loc, ty.elemType());20379 try sema.explainWhyTypeIsComptimeInner(block, src, msg, src_loc, ty.elemType(), type_set);
19718 },20380 },
19719 .Pointer => {20381 .Pointer => {
19720 const elem_ty = ty.elemType2();20382 const elem_ty = ty.elemType2();
...@@ -19732,18 +20394,20 @@ fn explainWhyTypeIsComptime(...@@ -19732,18 +20394,20 @@ fn explainWhyTypeIsComptime(
19732 }20394 }
19733 return;20395 return;
19734 }20396 }
19735 try sema.explainWhyTypeIsComptime(block, src, msg, src_loc, ty.elemType());20397 try sema.explainWhyTypeIsComptimeInner(block, src, msg, src_loc, ty.elemType(), type_set);
19736 },20398 },
1973720399
19738 .Optional => {20400 .Optional => {
19739 var buf: Type.Payload.ElemType = undefined;20401 var buf: Type.Payload.ElemType = undefined;
19740 try sema.explainWhyTypeIsComptime(block, src, msg, src_loc, ty.optionalChild(&buf));20402 try sema.explainWhyTypeIsComptimeInner(block, src, msg, src_loc, ty.optionalChild(&buf), type_set);
19741 },20403 },
19742 .ErrorUnion => {20404 .ErrorUnion => {
19743 try sema.explainWhyTypeIsComptime(block, src, msg, src_loc, ty.errorUnionPayload());20405 try sema.explainWhyTypeIsComptimeInner(block, src, msg, src_loc, ty.errorUnionPayload(), type_set);
19744 },20406 },
1974520407
19746 .Struct => {20408 .Struct => {
20409 if ((try type_set.getOrPutContext(sema.gpa, ty, .{ .mod = mod })).found_existing) return;
20410
19747 if (ty.castTag(.@"struct")) |payload| {20411 if (ty.castTag(.@"struct")) |payload| {
19748 const struct_obj = payload.data;20412 const struct_obj = payload.data;
19749 for (struct_obj.fields.values()) |field, i| {20413 for (struct_obj.fields.values()) |field, i| {
...@@ -19751,9 +20415,10 @@ fn explainWhyTypeIsComptime(...@@ -19751,9 +20415,10 @@ fn explainWhyTypeIsComptime(
19751 .index = i,20415 .index = i,
19752 .range = .type,20416 .range = .type,
19753 });20417 });
20418
19754 if (try sema.typeRequiresComptime(block, src, field.ty)) {20419 if (try sema.typeRequiresComptime(block, src, field.ty)) {
19755 try mod.errNoteNonLazy(field_src_loc, msg, "struct requires comptime because of this field", .{});20420 try mod.errNoteNonLazy(field_src_loc, msg, "struct requires comptime because of this field", .{});
19756 try sema.explainWhyTypeIsComptime(block, src, msg, field_src_loc, field.ty);20421 try sema.explainWhyTypeIsComptimeInner(block, src, msg, field_src_loc, field.ty, type_set);
19757 }20422 }
19758 }20423 }
19759 }20424 }
...@@ -19761,6 +20426,8 @@ fn explainWhyTypeIsComptime(...@@ -19761,6 +20426,8 @@ fn explainWhyTypeIsComptime(
19761 },20426 },
1976220427
19763 .Union => {20428 .Union => {
20429 if ((try type_set.getOrPutContext(sema.gpa, ty, .{ .mod = mod })).found_existing) return;
20430
19764 if (ty.cast(Type.Payload.Union)) |payload| {20431 if (ty.cast(Type.Payload.Union)) |payload| {
19765 const union_obj = payload.data;20432 const union_obj = payload.data;
19766 for (union_obj.fields.values()) |field, i| {20433 for (union_obj.fields.values()) |field, i| {
...@@ -19768,9 +20435,10 @@ fn explainWhyTypeIsComptime(...@@ -19768,9 +20435,10 @@ fn explainWhyTypeIsComptime(
19768 .index = i,20435 .index = i,
19769 .range = .type,20436 .range = .type,
19770 });20437 });
20438
19771 if (try sema.typeRequiresComptime(block, src, field.ty)) {20439 if (try sema.typeRequiresComptime(block, src, field.ty)) {
19772 try mod.errNoteNonLazy(field_src_loc, msg, "union requires comptime because of this field", .{});20440 try mod.errNoteNonLazy(field_src_loc, msg, "union requires comptime because of this field", .{});
19773 try sema.explainWhyTypeIsComptime(block, src, msg, field_src_loc, field.ty);20441 try sema.explainWhyTypeIsComptimeInner(block, src, msg, field_src_loc, field.ty, type_set);
19774 }20442 }
19775 }20443 }
19776 }20444 }
...@@ -19911,8 +20579,8 @@ fn validatePackedType(ty: Type) bool {...@@ -19911,8 +20579,8 @@ fn validatePackedType(ty: Type) bool {
19911 .AnyFrame,20579 .AnyFrame,
19912 .Fn,20580 .Fn,
19913 .Array,20581 .Array,
19914 .Optional,
19915 => return false,20582 => return false,
20583 .Optional => return ty.isPtrLikeOptional(),
19916 .Void,20584 .Void,
19917 .Bool,20585 .Bool,
19918 .Float,20586 .Float,
...@@ -19978,11 +20646,13 @@ pub const PanicId = enum {...@@ -19978,11 +20646,13 @@ pub const PanicId = enum {
19978 shl_overflow,20646 shl_overflow,
19979 shr_overflow,20647 shr_overflow,
19980 divide_by_zero,20648 divide_by_zero,
19981 remainder_division_zero_negative,
19982 exact_division_remainder,20649 exact_division_remainder,
19983 /// TODO make this call `std.builtin.panicInactiveUnionField`.20650 /// TODO make this call `std.builtin.panicInactiveUnionField`.
19984 inactive_union_field,20651 inactive_union_field,
19985 integer_part_out_of_bounds,20652 integer_part_out_of_bounds,
20653 corrupt_switch,
20654 shift_rhs_too_big,
20655 invalid_enum_value,
19986};20656};
1998720657
19988fn addSafetyCheck(20658fn addSafetyCheck(
...@@ -20076,7 +20746,7 @@ fn panicWithMsg(...@@ -20076,7 +20746,7 @@ fn panicWithMsg(
20076 const arena = sema.arena;20746 const arena = sema.arena;
2007720747
20078 const this_feature_is_implemented_in_the_backend =20748 const this_feature_is_implemented_in_the_backend =
20079 mod.comp.bin_file.options.object_format == .c or20749 mod.comp.bin_file.options.target.ofmt == .c or
20080 mod.comp.bin_file.options.use_llvm;20750 mod.comp.bin_file.options.use_llvm;
20081 if (!this_feature_is_implemented_in_the_backend) {20751 if (!this_feature_is_implemented_in_the_backend) {
20082 // TODO implement this feature in all the backends and then delete this branch20752 // TODO implement this feature in all the backends and then delete this branch
...@@ -20274,10 +20944,12 @@ fn safetyPanic(...@@ -20274,10 +20944,12 @@ fn safetyPanic(
20274 .shl_overflow => "left shift overflowed bits",20944 .shl_overflow => "left shift overflowed bits",
20275 .shr_overflow => "right shift overflowed bits",20945 .shr_overflow => "right shift overflowed bits",
20276 .divide_by_zero => "division by zero",20946 .divide_by_zero => "division by zero",
20277 .remainder_division_zero_negative => "remainder division by zero or negative value",
20278 .exact_division_remainder => "exact division produced remainder",20947 .exact_division_remainder => "exact division produced remainder",
20279 .inactive_union_field => "access of inactive union field",20948 .inactive_union_field => "access of inactive union field",
20280 .integer_part_out_of_bounds => "integer part of floating point value out of bounds",20949 .integer_part_out_of_bounds => "integer part of floating point value out of bounds",
20950 .corrupt_switch => "switch on corrupt value",
20951 .shift_rhs_too_big => "shift amount is greater than the type size",
20952 .invalid_enum_value => "invalid enum value",
20281 };20953 };
2028220954
20283 const msg_inst = msg_inst: {20955 const msg_inst = msg_inst: {
...@@ -20736,14 +21408,30 @@ fn fieldCallBind(...@@ -20736,14 +21408,30 @@ fn fieldCallBind(
20736 switch (concrete_ty.zigTypeTag()) {21408 switch (concrete_ty.zigTypeTag()) {
20737 .Struct => {21409 .Struct => {
20738 const struct_ty = try sema.resolveTypeFields(block, src, concrete_ty);21410 const struct_ty = try sema.resolveTypeFields(block, src, concrete_ty);
20739 const struct_obj = struct_ty.castTag(.@"struct").?.data;21411 if (struct_ty.castTag(.@"struct")) |struct_obj| {
2074021412 const field_index_usize = struct_obj.data.fields.getIndex(field_name) orelse
20741 const field_index_usize = struct_obj.fields.getIndex(field_name) orelse21413 break :find_field;
20742 break :find_field;21414 const field_index = @intCast(u32, field_index_usize);
20743 const field_index = @intCast(u32, field_index_usize);21415 const field = struct_obj.data.fields.values()[field_index];
20744 const field = struct_obj.fields.values()[field_index];
2074521416
20746 return finishFieldCallBind(sema, block, src, ptr_ty, field.ty, field_index, object_ptr);21417 return finishFieldCallBind(sema, block, src, ptr_ty, field.ty, field_index, object_ptr);
21418 } else if (struct_ty.isTuple()) {
21419 if (mem.eql(u8, field_name, "len")) {
21420 return sema.addIntUnsigned(Type.usize, struct_ty.structFieldCount());
21421 }
21422 if (std.fmt.parseUnsigned(u32, field_name, 10)) |field_index| {
21423 if (field_index >= struct_ty.structFieldCount()) break :find_field;
21424 return finishFieldCallBind(sema, block, src, ptr_ty, struct_ty.structFieldType(field_index), field_index, object_ptr);
21425 } else |_| {}
21426 } else {
21427 const max = struct_ty.structFieldCount();
21428 var i: u32 = 0;
21429 while (i < max) : (i += 1) {
21430 if (mem.eql(u8, struct_ty.structFieldName(i), field_name)) {
21431 return finishFieldCallBind(sema, block, src, ptr_ty, struct_ty.structFieldType(i), i, object_ptr);
21432 }
21433 }
21434 }
20747 },21435 },
20748 .Union => {21436 .Union => {
20749 const union_ty = try sema.resolveTypeFields(block, src, concrete_ty);21437 const union_ty = try sema.resolveTypeFields(block, src, concrete_ty);
...@@ -21009,7 +21697,7 @@ fn structFieldPtrByIndex(...@@ -21009,7 +21697,7 @@ fn structFieldPtrByIndex(
21009 const elem_size_bits = ptr_ty_data.pointee_type.bitSize(target);21697 const elem_size_bits = ptr_ty_data.pointee_type.bitSize(target);
21010 if (elem_size_bytes * 8 == elem_size_bits) {21698 if (elem_size_bytes * 8 == elem_size_bits) {
21011 const byte_offset = ptr_ty_data.bit_offset / 8;21699 const byte_offset = ptr_ty_data.bit_offset / 8;
21012 const new_align = @as(u32, 1) << @intCast(u5, @ctz(u64, byte_offset | parent_align));21700 const new_align = @as(u32, 1) << @intCast(u5, @ctz(byte_offset | parent_align));
21013 ptr_ty_data.bit_offset = 0;21701 ptr_ty_data.bit_offset = 0;
21014 ptr_ty_data.host_size = 0;21702 ptr_ty_data.host_size = 0;
21015 ptr_ty_data.@"align" = new_align;21703 ptr_ty_data.@"align" = new_align;
...@@ -21184,6 +21872,18 @@ fn unionFieldPtr(...@@ -21184,6 +21872,18 @@ fn unionFieldPtr(
21184 .@"addrspace" = union_ptr_ty.ptrAddressSpace(),21872 .@"addrspace" = union_ptr_ty.ptrAddressSpace(),
21185 });21873 });
2118621874
21875 if (initializing and field.ty.zigTypeTag() == .NoReturn) {
21876 const msg = msg: {
21877 const msg = try sema.errMsg(block, src, "cannot initialize 'noreturn' field of union", .{});
21878 errdefer msg.destroy(sema.gpa);
21879
21880 try sema.addFieldErrNote(block, union_ty, field_index, msg, "field '{s}' declared here", .{field_name});
21881 try sema.addDeclaredHereNote(msg, union_ty);
21882 break :msg msg;
21883 };
21884 return sema.failWithOwnedErrorMsg(msg);
21885 }
21886
21187 if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| ct: {21887 if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| ct: {
21188 switch (union_obj.layout) {21888 switch (union_obj.layout) {
21189 .Auto => if (!initializing) {21889 .Auto => if (!initializing) {
...@@ -21192,17 +21892,18 @@ fn unionFieldPtr(...@@ -21192,17 +21892,18 @@ fn unionFieldPtr(
21192 if (union_val.isUndef()) {21892 if (union_val.isUndef()) {
21193 return sema.failWithUseOfUndef(block, src);21893 return sema.failWithUseOfUndef(block, src);
21194 }21894 }
21895 const enum_field_index = union_obj.tag_ty.enumFieldIndex(field_name).?;
21195 const tag_and_val = union_val.castTag(.@"union").?.data;21896 const tag_and_val = union_val.castTag(.@"union").?.data;
21196 var field_tag_buf: Value.Payload.U32 = .{21897 var field_tag_buf: Value.Payload.U32 = .{
21197 .base = .{ .tag = .enum_field_index },21898 .base = .{ .tag = .enum_field_index },
21198 .data = field_index,21899 .data = @intCast(u32, enum_field_index),
21199 };21900 };
21200 const field_tag = Value.initPayload(&field_tag_buf.base);21901 const field_tag = Value.initPayload(&field_tag_buf.base);
21201 const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod);21902 const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod);
21202 if (!tag_matches) {21903 if (!tag_matches) {
21203 const msg = msg: {21904 const msg = msg: {
21204 const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data;21905 const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data;
21205 const active_field_name = union_obj.fields.keys()[active_index];21906 const active_field_name = union_obj.tag_ty.enumFieldName(active_index);
21206 const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name });21907 const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name });
21207 errdefer msg.destroy(sema.gpa);21908 errdefer msg.destroy(sema.gpa);
21208 try sema.addDeclaredHereNote(msg, union_ty);21909 try sema.addDeclaredHereNote(msg, union_ty);
...@@ -21227,15 +21928,18 @@ fn unionFieldPtr(...@@ -21227,15 +21928,18 @@ fn unionFieldPtr(
21227 if (!initializing and union_obj.layout == .Auto and block.wantSafety() and21928 if (!initializing and union_obj.layout == .Auto and block.wantSafety() and
21228 union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)21929 union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)
21229 {21930 {
21230 const enum_ty = union_ty.unionTagTypeHypothetical();
21231 const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index);21931 const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index);
21232 const wanted_tag = try sema.addConstant(enum_ty, wanted_tag_val);21932 const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val);
21233 // TODO would it be better if get_union_tag supported pointers to unions?21933 // TODO would it be better if get_union_tag supported pointers to unions?
21234 const union_val = try block.addTyOp(.load, union_ty, union_ptr);21934 const union_val = try block.addTyOp(.load, union_ty, union_ptr);
21235 const active_tag = try block.addTyOp(.get_union_tag, enum_ty, union_val);21935 const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_val);
21236 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);21936 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);
21237 try sema.addSafetyCheck(block, ok, .inactive_union_field);21937 try sema.addSafetyCheck(block, ok, .inactive_union_field);
21238 }21938 }
21939 if (field.ty.zigTypeTag() == .NoReturn) {
21940 _ = try block.addNoOp(.unreach);
21941 return Air.Inst.Ref.unreachable_value;
21942 }
21239 return block.addStructFieldPtr(union_ptr, field_index, ptr_field_ty);21943 return block.addStructFieldPtr(union_ptr, field_index, ptr_field_ty);
21240}21944}
2124121945
...@@ -21259,9 +21963,10 @@ fn unionFieldVal(...@@ -21259,9 +21963,10 @@ fn unionFieldVal(
21259 if (union_val.isUndef()) return sema.addConstUndef(field.ty);21963 if (union_val.isUndef()) return sema.addConstUndef(field.ty);
2126021964
21261 const tag_and_val = union_val.castTag(.@"union").?.data;21965 const tag_and_val = union_val.castTag(.@"union").?.data;
21966 const enum_field_index = union_obj.tag_ty.enumFieldIndex(field_name).?;
21262 var field_tag_buf: Value.Payload.U32 = .{21967 var field_tag_buf: Value.Payload.U32 = .{
21263 .base = .{ .tag = .enum_field_index },21968 .base = .{ .tag = .enum_field_index },
21264 .data = field_index,21969 .data = @intCast(u32, enum_field_index),
21265 };21970 };
21266 const field_tag = Value.initPayload(&field_tag_buf.base);21971 const field_tag = Value.initPayload(&field_tag_buf.base);
21267 const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod);21972 const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod);
...@@ -21272,7 +21977,7 @@ fn unionFieldVal(...@@ -21272,7 +21977,7 @@ fn unionFieldVal(
21272 } else {21977 } else {
21273 const msg = msg: {21978 const msg = msg: {
21274 const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data;21979 const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data;
21275 const active_field_name = union_obj.fields.keys()[active_index];21980 const active_field_name = union_obj.tag_ty.enumFieldName(active_index);
21276 const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name });21981 const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name });
21277 errdefer msg.destroy(sema.gpa);21982 errdefer msg.destroy(sema.gpa);
21278 try sema.addDeclaredHereNote(msg, union_ty);21983 try sema.addDeclaredHereNote(msg, union_ty);
...@@ -21297,13 +22002,16 @@ fn unionFieldVal(...@@ -21297,13 +22002,16 @@ fn unionFieldVal(
21297 if (union_obj.layout == .Auto and block.wantSafety() and22002 if (union_obj.layout == .Auto and block.wantSafety() and
21298 union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)22003 union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)
21299 {22004 {
21300 const enum_ty = union_ty.unionTagTypeHypothetical();
21301 const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index);22005 const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index);
21302 const wanted_tag = try sema.addConstant(enum_ty, wanted_tag_val);22006 const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val);
21303 const active_tag = try block.addTyOp(.get_union_tag, enum_ty, union_byval);22007 const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_byval);
21304 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);22008 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);
21305 try sema.addSafetyCheck(block, ok, .inactive_union_field);22009 try sema.addSafetyCheck(block, ok, .inactive_union_field);
21306 }22010 }
22011 if (field.ty.zigTypeTag() == .NoReturn) {
22012 _ = try block.addNoOp(.unreach);
22013 return Air.Inst.Ref.unreachable_value;
22014 }
21307 return block.addStructFieldVal(union_byval, field_index, field.ty);22015 return block.addStructFieldVal(union_byval, field_index, field.ty);
21308}22016}
2130922017
...@@ -21543,8 +22251,7 @@ fn tupleField(...@@ -21543,8 +22251,7 @@ fn tupleField(
2154322251
21544 if (try sema.resolveMaybeUndefVal(block, tuple_src, tuple)) |tuple_val| {22252 if (try sema.resolveMaybeUndefVal(block, tuple_src, tuple)) |tuple_val| {
21545 if (tuple_val.isUndef()) return sema.addConstUndef(field_ty);22253 if (tuple_val.isUndef()) return sema.addConstUndef(field_ty);
21546 const field_values = tuple_val.castTag(.aggregate).?.data;22254 return sema.addConstant(field_ty, tuple_val.fieldValue(tuple_ty, field_index));
21547 return sema.addConstant(field_ty, field_values[field_index]);
21548 }22255 }
2154922256
21550 try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src);22257 try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src);
...@@ -21886,7 +22593,7 @@ fn coerceExtra(...@@ -21886,7 +22593,7 @@ fn coerceExtra(
21886 // Function body to function pointer.22593 // Function body to function pointer.
21887 if (inst_ty.zigTypeTag() == .Fn) {22594 if (inst_ty.zigTypeTag() == .Fn) {
21888 const fn_val = try sema.resolveConstValue(block, .unneeded, inst, undefined);22595 const fn_val = try sema.resolveConstValue(block, .unneeded, inst, undefined);
21889 const fn_decl = fn_val.castTag(.function).?.data.owner_decl;22596 const fn_decl = fn_val.pointerDecl().?;
21890 const inst_as_ptr = try sema.analyzeDeclRef(fn_decl);22597 const inst_as_ptr = try sema.analyzeDeclRef(fn_decl);
21891 return sema.coerce(block, dest_ty, inst_as_ptr, inst_src);22598 return sema.coerce(block, dest_ty, inst_as_ptr, inst_src);
21892 }22599 }
...@@ -21966,7 +22673,6 @@ fn coerceExtra(...@@ -21966,7 +22673,6 @@ fn coerceExtra(
21966 .ok => {},22673 .ok => {},
21967 else => break :src_c_ptr,22674 else => break :src_c_ptr,
21968 }22675 }
21969 // TODO add safety check for null pointer
21970 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);22676 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
21971 }22677 }
2197222678
...@@ -23271,7 +23977,10 @@ fn coerceVarArgParam(...@@ -23271,7 +23977,10 @@ fn coerceVarArgParam(
23271 inst_src: LazySrcLoc,23977 inst_src: LazySrcLoc,
23272) !Air.Inst.Ref {23978) !Air.Inst.Ref {
23273 const inst_ty = sema.typeOf(inst);23979 const inst_ty = sema.typeOf(inst);
23980 if (block.is_typeof) return inst;
23981
23274 switch (inst_ty.zigTypeTag()) {23982 switch (inst_ty.zigTypeTag()) {
23983 // TODO consider casting to c_int/f64 if they fit
23275 .ComptimeInt, .ComptimeFloat => return sema.fail(block, inst_src, "integer and float literals in var args function must be casted", .{}),23984 .ComptimeInt, .ComptimeFloat => return sema.fail(block, inst_src, "integer and float literals in var args function must be casted", .{}),
23276 else => {},23985 else => {},
23277 }23986 }
...@@ -23653,7 +24362,10 @@ fn beginComptimePtrMutation(...@@ -23653,7 +24362,10 @@ fn beginComptimePtrMutation(
23653 const array_len_including_sentinel =24362 const array_len_including_sentinel =
23654 try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel());24363 try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel());
23655 const elems = try arena.alloc(Value, array_len_including_sentinel);24364 const elems = try arena.alloc(Value, array_len_including_sentinel);
23656 mem.set(Value, elems, repeated_val);24365 if (elems.len > 0) elems[0] = repeated_val;
24366 for (elems[1..]) |*elem| {
24367 elem.* = try repeated_val.copy(arena);
24368 }
2365724369
23658 val_ptr.* = try Value.Tag.aggregate.create(arena, elems);24370 val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
2365924371
...@@ -24439,6 +25151,24 @@ fn coerceCompatiblePtrs(...@@ -24439,6 +25151,24 @@ fn coerceCompatiblePtrs(
24439 return sema.addConstant(dest_ty, val);25151 return sema.addConstant(dest_ty, val);
24440 }25152 }
24441 try sema.requireRuntimeBlock(block, inst_src, null);25153 try sema.requireRuntimeBlock(block, inst_src, null);
25154 const inst_ty = sema.typeOf(inst);
25155 const inst_allows_zero = (inst_ty.zigTypeTag() == .Pointer and inst_ty.ptrAllowsZero()) or true;
25156 if (block.wantSafety() and inst_allows_zero and !dest_ty.ptrAllowsZero() and
25157 try sema.typeHasRuntimeBits(block, sema.src, dest_ty.elemType2()))
25158 {
25159 const actual_ptr = if (inst_ty.isSlice())
25160 try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty)
25161 else
25162 inst;
25163 const ptr_int = try block.addUnOp(.ptrtoint, actual_ptr);
25164 const is_non_zero = try block.addBinOp(.cmp_neq, ptr_int, .zero_usize);
25165 const ok = if (inst_ty.isSlice()) ok: {
25166 const len = try sema.analyzeSliceLen(block, inst_src, inst);
25167 const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize);
25168 break :ok try block.addBinOp(.bit_or, len_zero, is_non_zero);
25169 } else is_non_zero;
25170 try sema.addSafetyCheck(block, ok, .cast_to_null);
25171 }
24442 return sema.bitCast(block, dest_ty, inst, inst_src);25172 return sema.bitCast(block, dest_ty, inst, inst_src);
24443}25173}
2444425174
...@@ -24467,8 +25197,7 @@ fn coerceEnumToUnion(...@@ -24467,8 +25197,7 @@ fn coerceEnumToUnion(
2446725197
24468 const enum_tag = try sema.coerce(block, tag_ty, inst, inst_src);25198 const enum_tag = try sema.coerce(block, tag_ty, inst, inst_src);
24469 if (try sema.resolveDefinedValue(block, inst_src, enum_tag)) |val| {25199 if (try sema.resolveDefinedValue(block, inst_src, enum_tag)) |val| {
24470 const union_obj = union_ty.cast(Type.Payload.Union).?.data;25200 const field_index = union_ty.unionTagFieldIndex(val, sema.mod) orelse {
24471 const field_index = union_obj.tag_ty.enumTagFieldIndex(val, sema.mod) orelse {
24472 const msg = msg: {25201 const msg = msg: {
24473 const msg = try sema.errMsg(block, inst_src, "union '{}' has no tag with value '{}'", .{25202 const msg = try sema.errMsg(block, inst_src, "union '{}' has no tag with value '{}'", .{
24474 union_ty.fmt(sema.mod), val.fmtValue(tag_ty, sema.mod),25203 union_ty.fmt(sema.mod), val.fmtValue(tag_ty, sema.mod),
...@@ -24479,8 +25208,22 @@ fn coerceEnumToUnion(...@@ -24479,8 +25208,22 @@ fn coerceEnumToUnion(
24479 };25208 };
24480 return sema.failWithOwnedErrorMsg(msg);25209 return sema.failWithOwnedErrorMsg(msg);
24481 };25210 };
25211
25212 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
24482 const field = union_obj.fields.values()[field_index];25213 const field = union_obj.fields.values()[field_index];
24483 const field_ty = try sema.resolveTypeFields(block, inst_src, field.ty);25214 const field_ty = try sema.resolveTypeFields(block, inst_src, field.ty);
25215 if (field_ty.zigTypeTag() == .NoReturn) {
25216 const msg = msg: {
25217 const msg = try sema.errMsg(block, inst_src, "cannot initialize 'noreturn' field of union", .{});
25218 errdefer msg.destroy(sema.gpa);
25219
25220 const field_name = union_obj.fields.keys()[field_index];
25221 try sema.addFieldErrNote(block, union_ty, field_index, msg, "field '{s}' declared here", .{field_name});
25222 try sema.addDeclaredHereNote(msg, union_ty);
25223 break :msg msg;
25224 };
25225 return sema.failWithOwnedErrorMsg(msg);
25226 }
24484 const opv = (try sema.typeHasOnePossibleValue(block, inst_src, field_ty)) orelse {25227 const opv = (try sema.typeHasOnePossibleValue(block, inst_src, field_ty)) orelse {
24485 const msg = msg: {25228 const msg = msg: {
24486 const field_name = union_obj.fields.keys()[field_index];25229 const field_name = union_obj.fields.keys()[field_index];
...@@ -24516,13 +25259,37 @@ fn coerceEnumToUnion(...@@ -24516,13 +25259,37 @@ fn coerceEnumToUnion(
24516 return sema.failWithOwnedErrorMsg(msg);25259 return sema.failWithOwnedErrorMsg(msg);
24517 }25260 }
2451825261
25262 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
25263 {
25264 var msg: ?*Module.ErrorMsg = null;
25265 errdefer if (msg) |some| some.destroy(sema.gpa);
25266
25267 for (union_obj.fields.values()) |field, i| {
25268 if (field.ty.zigTypeTag() == .NoReturn) {
25269 const err_msg = msg orelse try sema.errMsg(
25270 block,
25271 inst_src,
25272 "runtime coercion from enum '{}' to union '{}' which has a 'noreturn' field",
25273 .{ tag_ty.fmt(sema.mod), union_ty.fmt(sema.mod) },
25274 );
25275 msg = err_msg;
25276
25277 try sema.addFieldErrNote(block, union_ty, i, err_msg, "'noreturn' field here", .{});
25278 }
25279 }
25280 if (msg) |some| {
25281 msg = null;
25282 try sema.addDeclaredHereNote(some, union_ty);
25283 return sema.failWithOwnedErrorMsg(some);
25284 }
25285 }
25286
24519 // If the union has all fields 0 bits, the union value is just the enum value.25287 // If the union has all fields 0 bits, the union value is just the enum value.
24520 if (union_ty.unionHasAllZeroBitFieldTypes()) {25288 if (union_ty.unionHasAllZeroBitFieldTypes()) {
24521 return block.addBitCast(union_ty, enum_tag);25289 return block.addBitCast(union_ty, enum_tag);
24522 }25290 }
2452325291
24524 const msg = msg: {25292 const msg = msg: {
24525 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
24526 const msg = try sema.errMsg(25293 const msg = try sema.errMsg(
24527 block,25294 block,
24528 inst_src,25295 inst_src,
...@@ -24533,11 +25300,11 @@ fn coerceEnumToUnion(...@@ -24533,11 +25300,11 @@ fn coerceEnumToUnion(
2453325300
24534 var it = union_obj.fields.iterator();25301 var it = union_obj.fields.iterator();
24535 var field_index: usize = 0;25302 var field_index: usize = 0;
24536 while (it.next()) |field| {25303 while (it.next()) |field| : (field_index += 1) {
24537 const field_name = field.key_ptr.*;25304 const field_name = field.key_ptr.*;
24538 const field_ty = field.value_ptr.ty;25305 const field_ty = field.value_ptr.ty;
25306 if (!field_ty.hasRuntimeBits()) continue;
24539 try sema.addFieldErrNote(block, union_ty, field_index, msg, "field '{s}' has type '{}'", .{ field_name, field_ty.fmt(sema.mod) });25307 try sema.addFieldErrNote(block, union_ty, field_index, msg, "field '{s}' has type '{}'", .{ field_name, field_ty.fmt(sema.mod) });
24540 field_index += 1;
24541 }25308 }
24542 try sema.addDeclaredHereNote(msg, union_ty);25309 try sema.addDeclaredHereNote(msg, union_ty);
24543 break :msg msg;25310 break :msg msg;
...@@ -24840,6 +25607,7 @@ fn coerceTupleToStruct(...@@ -24840,6 +25607,7 @@ fn coerceTupleToStruct(
2484025607
24841 // Populate default field values and report errors for missing fields.25608 // Populate default field values and report errors for missing fields.
24842 var root_msg: ?*Module.ErrorMsg = null;25609 var root_msg: ?*Module.ErrorMsg = null;
25610 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
2484325611
24844 for (field_refs) |*field_ref, i| {25612 for (field_refs) |*field_ref, i| {
24845 if (field_ref.* != .none) continue;25613 if (field_ref.* != .none) continue;
...@@ -24865,6 +25633,7 @@ fn coerceTupleToStruct(...@@ -24865,6 +25633,7 @@ fn coerceTupleToStruct(
24865 }25633 }
2486625634
24867 if (root_msg) |msg| {25635 if (root_msg) |msg| {
25636 root_msg = null;
24868 try sema.addDeclaredHereNote(msg, struct_ty);25637 try sema.addDeclaredHereNote(msg, struct_ty);
24869 return sema.failWithOwnedErrorMsg(msg);25638 return sema.failWithOwnedErrorMsg(msg);
24870 }25639 }
...@@ -24934,6 +25703,7 @@ fn coerceTupleToTuple(...@@ -24934,6 +25703,7 @@ fn coerceTupleToTuple(
2493425703
24935 // Populate default field values and report errors for missing fields.25704 // Populate default field values and report errors for missing fields.
24936 var root_msg: ?*Module.ErrorMsg = null;25705 var root_msg: ?*Module.ErrorMsg = null;
25706 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
2493725707
24938 for (field_refs) |*field_ref, i| {25708 for (field_refs) |*field_ref, i| {
24939 if (field_ref.* != .none) continue;25709 if (field_ref.* != .none) continue;
...@@ -24969,6 +25739,7 @@ fn coerceTupleToTuple(...@@ -24969,6 +25739,7 @@ fn coerceTupleToTuple(
24969 }25739 }
2497025740
24971 if (root_msg) |msg| {25741 if (root_msg) |msg| {
25742 root_msg = null;
24972 try sema.addDeclaredHereNote(msg, tuple_ty);25743 try sema.addDeclaredHereNote(msg, tuple_ty);
24973 return sema.failWithOwnedErrorMsg(msg);25744 return sema.failWithOwnedErrorMsg(msg);
24974 }25745 }
...@@ -25207,11 +25978,38 @@ fn analyzeIsNull(...@@ -25207,11 +25978,38 @@ fn analyzeIsNull(
25207 return Air.Inst.Ref.bool_false;25978 return Air.Inst.Ref.bool_false;
25208 }25979 }
25209 }25980 }
25981
25982 const operand_ty = sema.typeOf(operand);
25983 var buf: Type.Payload.ElemType = undefined;
25984 if (operand_ty.zigTypeTag() == .Optional and operand_ty.optionalChild(&buf).zigTypeTag() == .NoReturn) {
25985 return Air.Inst.Ref.bool_true;
25986 }
25210 try sema.requireRuntimeBlock(block, src, null);25987 try sema.requireRuntimeBlock(block, src, null);
25211 const air_tag: Air.Inst.Tag = if (invert_logic) .is_non_null else .is_null;25988 const air_tag: Air.Inst.Tag = if (invert_logic) .is_non_null else .is_null;
25212 return block.addUnOp(air_tag, operand);25989 return block.addUnOp(air_tag, operand);
25213}25990}
2521425991
25992fn analyzePtrIsNonErrComptimeOnly(
25993 sema: *Sema,
25994 block: *Block,
25995 src: LazySrcLoc,
25996 operand: Air.Inst.Ref,
25997) CompileError!Air.Inst.Ref {
25998 const ptr_ty = sema.typeOf(operand);
25999 assert(ptr_ty.zigTypeTag() == .Pointer);
26000 const child_ty = ptr_ty.childType();
26001
26002 const child_tag = child_ty.zigTypeTag();
26003 if (child_tag != .ErrorSet and child_tag != .ErrorUnion) return Air.Inst.Ref.bool_true;
26004 if (child_tag == .ErrorSet) return Air.Inst.Ref.bool_false;
26005 assert(child_tag == .ErrorUnion);
26006
26007 _ = block;
26008 _ = src;
26009
26010 return Air.Inst.Ref.none;
26011}
26012
25215fn analyzeIsNonErrComptimeOnly(26013fn analyzeIsNonErrComptimeOnly(
25216 sema: *Sema,26014 sema: *Sema,
25217 block: *Block,26015 block: *Block,
...@@ -25224,11 +26022,22 @@ fn analyzeIsNonErrComptimeOnly(...@@ -25224,11 +26022,22 @@ fn analyzeIsNonErrComptimeOnly(
25224 if (ot == .ErrorSet) return Air.Inst.Ref.bool_false;26022 if (ot == .ErrorSet) return Air.Inst.Ref.bool_false;
25225 assert(ot == .ErrorUnion);26023 assert(ot == .ErrorUnion);
2522626024
26025 const payload_ty = operand_ty.errorUnionPayload();
26026 if (payload_ty.zigTypeTag() == .NoReturn) {
26027 return Air.Inst.Ref.bool_false;
26028 }
26029
25227 if (Air.refToIndex(operand)) |operand_inst| {26030 if (Air.refToIndex(operand)) |operand_inst| {
25228 const air_tags = sema.air_instructions.items(.tag);26031 switch (sema.air_instructions.items(.tag)[operand_inst]) {
25229 if (air_tags[operand_inst] == .wrap_errunion_payload) {26032 .wrap_errunion_payload => return Air.Inst.Ref.bool_true,
25230 return Air.Inst.Ref.bool_true;26033 .wrap_errunion_err => return Air.Inst.Ref.bool_false,
26034 else => {},
25231 }26035 }
26036 } else if (operand == .undef) {
26037 return sema.addConstUndef(Type.bool);
26038 } else {
26039 // None of the ref tags can be errors.
26040 return Air.Inst.Ref.bool_true;
25232 }26041 }
2523326042
25234 const maybe_operand_val = try sema.resolveMaybeUndefVal(block, src, operand);26043 const maybe_operand_val = try sema.resolveMaybeUndefVal(block, src, operand);
...@@ -25304,6 +26113,21 @@ fn analyzeIsNonErr(...@@ -25304,6 +26113,21 @@ fn analyzeIsNonErr(
25304 }26113 }
25305}26114}
2530626115
26116fn analyzePtrIsNonErr(
26117 sema: *Sema,
26118 block: *Block,
26119 src: LazySrcLoc,
26120 operand: Air.Inst.Ref,
26121) CompileError!Air.Inst.Ref {
26122 const result = try sema.analyzePtrIsNonErrComptimeOnly(block, src, operand);
26123 if (result == .none) {
26124 try sema.requireRuntimeBlock(block, src, null);
26125 return block.addUnOp(.is_non_err_ptr, operand);
26126 } else {
26127 return result;
26128 }
26129}
26130
25307fn analyzeSlice(26131fn analyzeSlice(
25308 sema: *Sema,26132 sema: *Sema,
25309 block: *Block,26133 block: *Block,
...@@ -25330,11 +26154,12 @@ fn analyzeSlice(...@@ -25330,11 +26154,12 @@ fn analyzeSlice(
25330 var array_ty = ptr_ptr_child_ty;26154 var array_ty = ptr_ptr_child_ty;
25331 var slice_ty = ptr_ptr_ty;26155 var slice_ty = ptr_ptr_ty;
25332 var ptr_or_slice = ptr_ptr;26156 var ptr_or_slice = ptr_ptr;
25333 var elem_ty = ptr_ptr_child_ty.childType();26157 var elem_ty: Type = undefined;
25334 var ptr_sentinel: ?Value = null;26158 var ptr_sentinel: ?Value = null;
25335 switch (ptr_ptr_child_ty.zigTypeTag()) {26159 switch (ptr_ptr_child_ty.zigTypeTag()) {
25336 .Array => {26160 .Array => {
25337 ptr_sentinel = ptr_ptr_child_ty.sentinel();26161 ptr_sentinel = ptr_ptr_child_ty.sentinel();
26162 elem_ty = ptr_ptr_child_ty.childType();
25338 },26163 },
25339 .Pointer => switch (ptr_ptr_child_ty.ptrSize()) {26164 .Pointer => switch (ptr_ptr_child_ty.ptrSize()) {
25340 .One => {26165 .One => {
...@@ -25578,6 +26403,27 @@ fn analyzeSlice(...@@ -25578,6 +26403,27 @@ fn analyzeSlice(
25578 const new_ptr_val = opt_new_ptr_val orelse {26403 const new_ptr_val = opt_new_ptr_val orelse {
25579 const result = try block.addBitCast(return_ty, new_ptr);26404 const result = try block.addBitCast(return_ty, new_ptr);
25580 if (block.wantSafety()) {26405 if (block.wantSafety()) {
26406 // requirement: slicing C ptr is non-null
26407 if (ptr_ptr_child_ty.isCPtr()) {
26408 const is_non_null = try sema.analyzeIsNull(block, ptr_src, ptr, true);
26409 try sema.addSafetyCheck(block, is_non_null, .unwrap_null);
26410 }
26411
26412 if (slice_ty.isSlice()) {
26413 const slice_len_inst = try block.addTyOp(.slice_len, Type.usize, ptr_or_slice);
26414 const actual_len = if (slice_ty.sentinel() == null)
26415 slice_len_inst
26416 else
26417 try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src);
26418
26419 const actual_end = if (slice_sentinel != null)
26420 try sema.analyzeArithmetic(block, .add, end, .one, src, end_src, end_src)
26421 else
26422 end;
26423
26424 try sema.panicIndexOutOfBounds(block, src, actual_end, actual_len, .cmp_lte);
26425 }
26426
25581 // requirement: result[new_len] == slice_sentinel26427 // requirement: result[new_len] == slice_sentinel
25582 try sema.panicSentinelMismatch(block, src, slice_sentinel, elem_ty, result, new_len);26428 try sema.panicSentinelMismatch(block, src, slice_sentinel, elem_ty, result, new_len);
25583 }26429 }
...@@ -25639,7 +26485,11 @@ fn analyzeSlice(...@@ -25639,7 +26485,11 @@ fn analyzeSlice(
25639 break :blk try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src);26485 break :blk try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src);
25640 } else null;26486 } else null;
25641 if (opt_len_inst) |len_inst| {26487 if (opt_len_inst) |len_inst| {
25642 try sema.panicIndexOutOfBounds(block, src, end, len_inst, .cmp_lte);26488 const actual_end = if (slice_sentinel != null)
26489 try sema.analyzeArithmetic(block, .add, end, .one, src, end_src, end_src)
26490 else
26491 end;
26492 try sema.panicIndexOutOfBounds(block, src, actual_end, len_inst, .cmp_lte);
25643 }26493 }
2564426494
25645 // requirement: start <= end26495 // requirement: start <= end
...@@ -26616,9 +27466,6 @@ pub fn resolveTypeLayout(...@@ -26616,9 +27466,6 @@ pub fn resolveTypeLayout(
26616 src: LazySrcLoc,27466 src: LazySrcLoc,
26617 ty: Type,27467 ty: Type,
26618) CompileError!void {27468) CompileError!void {
26619 if (build_options.omit_stage2)
26620 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
26621
26622 switch (ty.zigTypeTag()) {27469 switch (ty.zigTypeTag()) {
26623 .Struct => return sema.resolveStructLayout(block, src, ty),27470 .Struct => return sema.resolveStructLayout(block, src, ty),
26624 .Union => return sema.resolveUnionLayout(block, src, ty),27471 .Union => return sema.resolveUnionLayout(block, src, ty),
...@@ -26677,6 +27524,11 @@ fn resolveStructLayout(...@@ -26677,6 +27524,11 @@ fn resolveStructLayout(
26677 else => return err,27524 else => return err,
26678 };27525 };
26679 }27526 }
27527
27528 if (struct_obj.layout == .Packed) {
27529 try semaBackingIntType(sema.mod, struct_obj);
27530 }
27531
26680 struct_obj.status = .have_layout;27532 struct_obj.status = .have_layout;
2668127533
26682 // In case of querying the ABI alignment of this struct, we will ask27534 // In case of querying the ABI alignment of this struct, we will ask
...@@ -26696,6 +27548,109 @@ fn resolveStructLayout(...@@ -26696,6 +27548,109 @@ fn resolveStructLayout(
26696 // otherwise it's a tuple; no need to resolve anything27548 // otherwise it's a tuple; no need to resolve anything
26697}27549}
2669827550
27551fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!void {
27552 const gpa = mod.gpa;
27553 const target = mod.getTarget();
27554
27555 var fields_bit_sum: u64 = 0;
27556 for (struct_obj.fields.values()) |field| {
27557 fields_bit_sum += field.ty.bitSize(target);
27558 }
27559
27560 const decl_index = struct_obj.owner_decl;
27561 const decl = mod.declPtr(decl_index);
27562 var decl_arena = decl.value_arena.?.promote(gpa);
27563 defer decl.value_arena.?.* = decl_arena.state;
27564 const decl_arena_allocator = decl_arena.allocator();
27565
27566 const zir = struct_obj.namespace.file_scope.zir;
27567 const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended;
27568 assert(extended.opcode == .struct_decl);
27569 const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
27570
27571 if (small.has_backing_int) {
27572 var extra_index: usize = extended.operand;
27573 extra_index += @boolToInt(small.has_src_node);
27574 extra_index += @boolToInt(small.has_fields_len);
27575 extra_index += @boolToInt(small.has_decls_len);
27576
27577 const backing_int_body_len = zir.extra[extra_index];
27578 extra_index += 1;
27579
27580 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
27581 defer analysis_arena.deinit();
27582
27583 var sema: Sema = .{
27584 .mod = mod,
27585 .gpa = gpa,
27586 .arena = analysis_arena.allocator(),
27587 .perm_arena = decl_arena_allocator,
27588 .code = zir,
27589 .owner_decl = decl,
27590 .owner_decl_index = decl_index,
27591 .func = null,
27592 .fn_ret_ty = Type.void,
27593 .owner_func = null,
27594 };
27595 defer sema.deinit();
27596
27597 var wip_captures = try WipCaptureScope.init(gpa, decl_arena_allocator, decl.src_scope);
27598 defer wip_captures.deinit();
27599
27600 var block: Block = .{
27601 .parent = null,
27602 .sema = &sema,
27603 .src_decl = decl_index,
27604 .namespace = &struct_obj.namespace,
27605 .wip_capture_scope = wip_captures.scope,
27606 .instructions = .{},
27607 .inlining = null,
27608 .is_comptime = true,
27609 };
27610 defer {
27611 assert(block.instructions.items.len == 0);
27612 block.params.deinit(gpa);
27613 }
27614
27615 const backing_int_src: LazySrcLoc = .{ .node_offset_container_tag = 0 };
27616 const backing_int_ty = blk: {
27617 if (backing_int_body_len == 0) {
27618 const backing_int_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
27619 break :blk try sema.resolveType(&block, backing_int_src, backing_int_ref);
27620 } else {
27621 const body = zir.extra[extra_index..][0..backing_int_body_len];
27622 const ty_ref = try sema.resolveBody(&block, body, struct_obj.zir_index);
27623 break :blk try sema.analyzeAsType(&block, backing_int_src, ty_ref);
27624 }
27625 };
27626
27627 try sema.checkBackingIntType(&block, backing_int_src, backing_int_ty, fields_bit_sum);
27628 struct_obj.backing_int_ty = try backing_int_ty.copy(decl_arena_allocator);
27629 } else {
27630 var buf: Type.Payload.Bits = .{
27631 .base = .{ .tag = .int_unsigned },
27632 .data = @intCast(u16, fields_bit_sum),
27633 };
27634 struct_obj.backing_int_ty = try Type.initPayload(&buf.base).copy(decl_arena_allocator);
27635 }
27636}
27637
27638fn checkBackingIntType(sema: *Sema, block: *Block, src: LazySrcLoc, backing_int_ty: Type, fields_bit_sum: u64) CompileError!void {
27639 const target = sema.mod.getTarget();
27640
27641 if (!backing_int_ty.isInt()) {
27642 return sema.fail(block, src, "expected backing integer type, found '{}'", .{backing_int_ty.fmt(sema.mod)});
27643 }
27644 if (backing_int_ty.bitSize(target) != fields_bit_sum) {
27645 return sema.fail(
27646 block,
27647 src,
27648 "backing integer type '{}' has bit size {} but the struct fields have a total bit size of {}",
27649 .{ backing_int_ty.fmt(sema.mod), backing_int_ty.bitSize(target), fields_bit_sum },
27650 );
27651 }
27652}
27653
26699fn resolveUnionLayout(27654fn resolveUnionLayout(
26700 sema: *Sema,27655 sema: *Sema,
26701 block: *Block,27656 block: *Block,
...@@ -26849,8 +27804,6 @@ fn resolveUnionFully(...@@ -26849,8 +27804,6 @@ fn resolveUnionFully(
26849}27804}
2685027805
26851pub fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!Type {27806pub fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!Type {
26852 if (build_options.omit_stage2)
26853 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
26854 switch (ty.tag()) {27807 switch (ty.tag()) {
26855 .@"struct" => {27808 .@"struct" => {
26856 const struct_obj = ty.castTag(.@"struct").?.data;27809 const struct_obj = ty.castTag(.@"struct").?.data;
...@@ -26997,13 +27950,15 @@ fn resolveInferredErrorSetTy(...@@ -26997,13 +27950,15 @@ fn resolveInferredErrorSetTy(
26997fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void {27950fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void {
26998 const gpa = mod.gpa;27951 const gpa = mod.gpa;
26999 const decl_index = struct_obj.owner_decl;27952 const decl_index = struct_obj.owner_decl;
27000 const zir = struct_obj.namespace.file_scope.zir;27953 const file_scope = struct_obj.namespace.file_scope;
27954 if (file_scope.status != .success_zir) return error.AnalysisFail;
27955 const zir = file_scope.zir;
27001 const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended;27956 const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended;
27002 assert(extended.opcode == .struct_decl);27957 assert(extended.opcode == .struct_decl);
27003 const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);27958 const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
27004 var extra_index: usize = extended.operand;27959 var extra_index: usize = extended.operand;
2700527960
27006 const src = LazySrcLoc.nodeOffset(struct_obj.node_offset);27961 const src = LazySrcLoc.nodeOffset(0);
27007 extra_index += @boolToInt(small.has_src_node);27962 extra_index += @boolToInt(small.has_src_node);
2700827963
27009 const fields_len = if (small.has_fields_len) blk: {27964 const fields_len = if (small.has_fields_len) blk: {
...@@ -27018,12 +27973,26 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -27018,12 +27973,26 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
27018 break :decls_len decls_len;27973 break :decls_len decls_len;
27019 } else 0;27974 } else 0;
2702027975
27976 // The backing integer cannot be handled until `resolveStructLayout()`.
27977 if (small.has_backing_int) {
27978 const backing_int_body_len = zir.extra[extra_index];
27979 extra_index += 1; // backing_int_body_len
27980 if (backing_int_body_len == 0) {
27981 extra_index += 1; // backing_int_ref
27982 } else {
27983 extra_index += backing_int_body_len; // backing_int_body_inst
27984 }
27985 }
27986
27021 // Skip over decls.27987 // Skip over decls.
27022 var decls_it = zir.declIteratorInner(extra_index, decls_len);27988 var decls_it = zir.declIteratorInner(extra_index, decls_len);
27023 while (decls_it.next()) |_| {}27989 while (decls_it.next()) |_| {}
27024 extra_index = decls_it.extra_index;27990 extra_index = decls_it.extra_index;
2702527991
27026 if (fields_len == 0) {27992 if (fields_len == 0) {
27993 if (struct_obj.layout == .Packed) {
27994 try semaBackingIntType(mod, struct_obj);
27995 }
27027 struct_obj.status = .have_layout;27996 struct_obj.status = .have_layout;
27028 return;27997 return;
27029 }27998 }
...@@ -27122,12 +28091,12 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -27122,12 +28091,12 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
27122 if (gop.found_existing) {28091 if (gop.found_existing) {
27123 const msg = msg: {28092 const msg = msg: {
27124 const tree = try sema.getAstTree(&block_scope);28093 const tree = try sema.getAstTree(&block_scope);
27125 const field_src = enumFieldSrcLoc(decl, tree.*, struct_obj.node_offset, field_i);28094 const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i);
27126 const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{s}'", .{field_name});28095 const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{s}'", .{field_name});
27127 errdefer msg.destroy(gpa);28096 errdefer msg.destroy(gpa);
2712828097
27129 const prev_field_index = struct_obj.fields.getIndex(field_name).?;28098 const prev_field_index = struct_obj.fields.getIndex(field_name).?;
27130 const prev_field_src = enumFieldSrcLoc(decl, tree.*, struct_obj.node_offset, prev_field_index);28099 const prev_field_src = enumFieldSrcLoc(decl, tree.*, 0, prev_field_index);
27131 try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl), msg, "other field here", .{});28100 try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl), msg, "other field here", .{});
27132 try sema.errNote(&block_scope, src, msg, "struct declared here", .{});28101 try sema.errNote(&block_scope, src, msg, "struct declared here", .{});
27133 break :msg msg;28102 break :msg msg;
...@@ -27184,7 +28153,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -27184,7 +28153,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
27184 if (field_ty.zigTypeTag() == .Opaque) {28153 if (field_ty.zigTypeTag() == .Opaque) {
27185 const msg = msg: {28154 const msg = msg: {
27186 const tree = try sema.getAstTree(&block_scope);28155 const tree = try sema.getAstTree(&block_scope);
27187 const field_src = enumFieldSrcLoc(decl, tree.*, struct_obj.node_offset, i);28156 const field_src = enumFieldSrcLoc(decl, tree.*, 0, i);
27188 const msg = try sema.errMsg(&block_scope, field_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});28157 const msg = try sema.errMsg(&block_scope, field_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
27189 errdefer msg.destroy(sema.gpa);28158 errdefer msg.destroy(sema.gpa);
2719028159
...@@ -27193,10 +28162,22 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -27193,10 +28162,22 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
27193 };28162 };
27194 return sema.failWithOwnedErrorMsg(msg);28163 return sema.failWithOwnedErrorMsg(msg);
27195 }28164 }
28165 if (field_ty.zigTypeTag() == .NoReturn) {
28166 const msg = msg: {
28167 const tree = try sema.getAstTree(&block_scope);
28168 const field_src = enumFieldSrcLoc(decl, tree.*, 0, i);
28169 const msg = try sema.errMsg(&block_scope, field_src, "struct fields cannot be 'noreturn'", .{});
28170 errdefer msg.destroy(sema.gpa);
28171
28172 try sema.addDeclaredHereNote(msg, field_ty);
28173 break :msg msg;
28174 };
28175 return sema.failWithOwnedErrorMsg(msg);
28176 }
27196 if (struct_obj.layout == .Extern and !sema.validateExternType(field.ty, .other)) {28177 if (struct_obj.layout == .Extern and !sema.validateExternType(field.ty, .other)) {
27197 const msg = msg: {28178 const msg = msg: {
27198 const tree = try sema.getAstTree(&block_scope);28179 const tree = try sema.getAstTree(&block_scope);
27199 const fields_src = enumFieldSrcLoc(decl, tree.*, struct_obj.node_offset, i);28180 const fields_src = enumFieldSrcLoc(decl, tree.*, 0, i);
27200 const msg = try sema.errMsg(&block_scope, fields_src, "extern structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)});28181 const msg = try sema.errMsg(&block_scope, fields_src, "extern structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)});
27201 errdefer msg.destroy(sema.gpa);28182 errdefer msg.destroy(sema.gpa);
2720228183
...@@ -27209,7 +28190,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void...@@ -27209,7 +28190,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
27209 } else if (struct_obj.layout == .Packed and !(validatePackedType(field.ty))) {28190 } else if (struct_obj.layout == .Packed and !(validatePackedType(field.ty))) {
27210 const msg = msg: {28191 const msg = msg: {
27211 const tree = try sema.getAstTree(&block_scope);28192 const tree = try sema.getAstTree(&block_scope);
27212 const fields_src = enumFieldSrcLoc(decl, tree.*, struct_obj.node_offset, i);28193 const fields_src = enumFieldSrcLoc(decl, tree.*, 0, i);
27213 const msg = try sema.errMsg(&block_scope, fields_src, "packed structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)});28194 const msg = try sema.errMsg(&block_scope, fields_src, "packed structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)});
27214 errdefer msg.destroy(sema.gpa);28195 errdefer msg.destroy(sema.gpa);
2721528196
...@@ -27266,7 +28247,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -27266,7 +28247,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
27266 const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small);28247 const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small);
27267 var extra_index: usize = extended.operand;28248 var extra_index: usize = extended.operand;
2726828249
27269 const src = LazySrcLoc.nodeOffset(union_obj.node_offset);28250 const src = LazySrcLoc.nodeOffset(0);
27270 extra_index += @boolToInt(small.has_src_node);28251 extra_index += @boolToInt(small.has_src_node);
2727128252
27272 const tag_type_ref: Zir.Inst.Ref = if (small.has_tag_type) blk: {28253 const tag_type_ref: Zir.Inst.Ref = if (small.has_tag_type) blk: {
...@@ -27299,10 +28280,6 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -27299,10 +28280,6 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
27299 extra_index = decls_it.extra_index;28280 extra_index = decls_it.extra_index;
2730028281
27301 const body = zir.extra[extra_index..][0..body_len];28282 const body = zir.extra[extra_index..][0..body_len];
27302 if (fields_len == 0) {
27303 assert(body.len == 0);
27304 return;
27305 }
27306 extra_index += body.len;28283 extra_index += body.len;
2730728284
27308 const decl = mod.declPtr(decl_index);28285 const decl = mod.declPtr(decl_index);
...@@ -27390,6 +28367,10 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -27390,6 +28367,10 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
27390 enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields;28367 enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields;
27391 }28368 }
2739228369
28370 if (fields_len == 0) {
28371 return;
28372 }
28373
27393 const bits_per_field = 4;28374 const bits_per_field = 4;
27394 const fields_per_u32 = 32 / bits_per_field;28375 const fields_per_u32 = 32 / bits_per_field;
27395 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;28376 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
...@@ -27490,12 +28471,12 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -27490,12 +28471,12 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
27490 if (gop.found_existing) {28471 if (gop.found_existing) {
27491 const msg = msg: {28472 const msg = msg: {
27492 const tree = try sema.getAstTree(&block_scope);28473 const tree = try sema.getAstTree(&block_scope);
27493 const field_src = enumFieldSrcLoc(decl, tree.*, union_obj.node_offset, field_i);28474 const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i);
27494 const msg = try sema.errMsg(&block_scope, field_src, "duplicate union field: '{s}'", .{field_name});28475 const msg = try sema.errMsg(&block_scope, field_src, "duplicate union field: '{s}'", .{field_name});
27495 errdefer msg.destroy(gpa);28476 errdefer msg.destroy(gpa);
2749628477
27497 const prev_field_index = union_obj.fields.getIndex(field_name).?;28478 const prev_field_index = union_obj.fields.getIndex(field_name).?;
27498 const prev_field_src = enumFieldSrcLoc(decl, tree.*, union_obj.node_offset, prev_field_index);28479 const prev_field_src = enumFieldSrcLoc(decl, tree.*, 0, prev_field_index);
27499 try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl), msg, "other field here", .{});28480 try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl), msg, "other field here", .{});
27500 try sema.errNote(&block_scope, src, msg, "union declared here", .{});28481 try sema.errNote(&block_scope, src, msg, "union declared here", .{});
27501 break :msg msg;28482 break :msg msg;
...@@ -27508,7 +28489,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -27508,7 +28489,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
27508 if (!enum_has_field) {28489 if (!enum_has_field) {
27509 const msg = msg: {28490 const msg = msg: {
27510 const tree = try sema.getAstTree(&block_scope);28491 const tree = try sema.getAstTree(&block_scope);
27511 const field_src = enumFieldSrcLoc(decl, tree.*, union_obj.node_offset, field_i);28492 const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i);
27512 const msg = try sema.errMsg(&block_scope, field_src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(sema.mod) });28493 const msg = try sema.errMsg(&block_scope, field_src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(sema.mod) });
27513 errdefer msg.destroy(sema.gpa);28494 errdefer msg.destroy(sema.gpa);
27514 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);28495 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
...@@ -27521,7 +28502,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -27521,7 +28502,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
27521 if (field_ty.zigTypeTag() == .Opaque) {28502 if (field_ty.zigTypeTag() == .Opaque) {
27522 const msg = msg: {28503 const msg = msg: {
27523 const tree = try sema.getAstTree(&block_scope);28504 const tree = try sema.getAstTree(&block_scope);
27524 const field_src = enumFieldSrcLoc(decl, tree.*, union_obj.node_offset, field_i);28505 const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i);
27525 const msg = try sema.errMsg(&block_scope, field_src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{});28506 const msg = try sema.errMsg(&block_scope, field_src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{});
27526 errdefer msg.destroy(sema.gpa);28507 errdefer msg.destroy(sema.gpa);
2752728508
...@@ -27533,7 +28514,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -27533,7 +28514,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
27533 if (union_obj.layout == .Extern and !sema.validateExternType(field_ty, .union_field)) {28514 if (union_obj.layout == .Extern and !sema.validateExternType(field_ty, .union_field)) {
27534 const msg = msg: {28515 const msg = msg: {
27535 const tree = try sema.getAstTree(&block_scope);28516 const tree = try sema.getAstTree(&block_scope);
27536 const field_src = enumFieldSrcLoc(decl, tree.*, union_obj.node_offset, field_i);28517 const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i);
27537 const msg = try sema.errMsg(&block_scope, field_src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});28518 const msg = try sema.errMsg(&block_scope, field_src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
27538 errdefer msg.destroy(sema.gpa);28519 errdefer msg.destroy(sema.gpa);
2753928520
...@@ -27546,7 +28527,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -27546,7 +28527,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
27546 } else if (union_obj.layout == .Packed and !(validatePackedType(field_ty))) {28527 } else if (union_obj.layout == .Packed and !(validatePackedType(field_ty))) {
27547 const msg = msg: {28528 const msg = msg: {
27548 const tree = try sema.getAstTree(&block_scope);28529 const tree = try sema.getAstTree(&block_scope);
27549 const fields_src = enumFieldSrcLoc(decl, tree.*, union_obj.node_offset, field_i);28530 const fields_src = enumFieldSrcLoc(decl, tree.*, 0, field_i);
27550 const msg = try sema.errMsg(&block_scope, fields_src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});28531 const msg = try sema.errMsg(&block_scope, fields_src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
27551 errdefer msg.destroy(sema.gpa);28532 errdefer msg.destroy(sema.gpa);
2755228533
...@@ -27638,7 +28619,6 @@ fn generateUnionTagTypeNumbered(...@@ -27638,7 +28619,6 @@ fn generateUnionTagTypeNumbered(
27638 .tag_ty = int_ty,28619 .tag_ty = int_ty,
27639 .fields = .{},28620 .fields = .{},
27640 .values = .{},28621 .values = .{},
27641 .node_offset = 0,
27642 };28622 };
27643 // Here we pre-allocate the maps using the decl arena.28623 // Here we pre-allocate the maps using the decl arena.
27644 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);28624 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
...@@ -27696,7 +28676,6 @@ fn generateUnionTagTypeSimple(sema: *Sema, block: *Block, fields_len: usize, may...@@ -27696,7 +28676,6 @@ fn generateUnionTagTypeSimple(sema: *Sema, block: *Block, fields_len: usize, may
27696 enum_obj.* = .{28676 enum_obj.* = .{
27697 .owner_decl = new_decl_index,28677 .owner_decl = new_decl_index,
27698 .fields = .{},28678 .fields = .{},
27699 .node_offset = 0,
27700 };28679 };
27701 // Here we pre-allocate the maps using the decl arena.28680 // Here we pre-allocate the maps using the decl arena.
27702 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);28681 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
...@@ -27871,10 +28850,11 @@ pub fn typeHasOnePossibleValue(...@@ -27871,10 +28850,11 @@ pub fn typeHasOnePossibleValue(
2787128850
27872 .tuple, .anon_struct => {28851 .tuple, .anon_struct => {
27873 const tuple = ty.tupleFields();28852 const tuple = ty.tupleFields();
27874 for (tuple.values) |val| {28853 for (tuple.values) |val, i| {
27875 if (val.tag() == .unreachable_value) {28854 const is_comptime = val.tag() != .unreachable_value;
27876 return null; // non-comptime field28855 if (is_comptime) continue;
27877 }28856 if ((try sema.typeHasOnePossibleValue(block, src, tuple.types[i])) != null) continue;
28857 return null;
27878 }28858 }
27879 return Value.initTag(.empty_struct_value);28859 return Value.initTag(.empty_struct_value);
27880 },28860 },
...@@ -27882,6 +28862,10 @@ pub fn typeHasOnePossibleValue(...@@ -27882,6 +28862,10 @@ pub fn typeHasOnePossibleValue(
27882 .enum_numbered => {28862 .enum_numbered => {
27883 const resolved_ty = try sema.resolveTypeFields(block, src, ty);28863 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
27884 const enum_obj = resolved_ty.castTag(.enum_numbered).?.data;28864 const enum_obj = resolved_ty.castTag(.enum_numbered).?.data;
28865 // An explicit tag type is always provided for enum_numbered.
28866 if (enum_obj.tag_ty.hasRuntimeBits()) {
28867 return null;
28868 }
27885 if (enum_obj.fields.count() == 1) {28869 if (enum_obj.fields.count() == 1) {
27886 if (enum_obj.values.count() == 0) {28870 if (enum_obj.values.count() == 0) {
27887 return Value.zero; // auto-numbered28871 return Value.zero; // auto-numbered
...@@ -27895,6 +28879,9 @@ pub fn typeHasOnePossibleValue(...@@ -27895,6 +28879,9 @@ pub fn typeHasOnePossibleValue(
27895 .enum_full => {28879 .enum_full => {
27896 const resolved_ty = try sema.resolveTypeFields(block, src, ty);28880 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
27897 const enum_obj = resolved_ty.castTag(.enum_full).?.data;28881 const enum_obj = resolved_ty.castTag(.enum_full).?.data;
28882 if (enum_obj.tag_ty.hasRuntimeBits()) {
28883 return null;
28884 }
27898 if (enum_obj.fields.count() == 1) {28885 if (enum_obj.fields.count() == 1) {
27899 if (enum_obj.values.count() == 0) {28886 if (enum_obj.values.count() == 0) {
27900 return Value.zero; // auto-numbered28887 return Value.zero; // auto-numbered
...@@ -27927,7 +28914,9 @@ pub fn typeHasOnePossibleValue(...@@ -27927,7 +28914,9 @@ pub fn typeHasOnePossibleValue(
27927 const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;28914 const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;
27928 const tag_val = (try sema.typeHasOnePossibleValue(block, src, union_obj.tag_ty)) orelse28915 const tag_val = (try sema.typeHasOnePossibleValue(block, src, union_obj.tag_ty)) orelse
27929 return null;28916 return null;
27930 const only_field = union_obj.fields.values()[0];28917 const fields = union_obj.fields.values();
28918 if (fields.len == 0) return Value.initTag(.empty_struct_value);
28919 const only_field = fields[0];
27931 if (only_field.ty.eql(resolved_ty, sema.mod)) {28920 if (only_field.ty.eql(resolved_ty, sema.mod)) {
27932 const msg = try Module.ErrorMsg.create(28921 const msg = try Module.ErrorMsg.create(
27933 sema.gpa,28922 sema.gpa,
...@@ -28006,8 +28995,18 @@ fn enumFieldSrcLoc(...@@ -28006,8 +28995,18 @@ fn enumFieldSrcLoc(
28006 .container_decl_arg_trailing,28995 .container_decl_arg_trailing,
28007 => tree.containerDeclArg(enum_node),28996 => tree.containerDeclArg(enum_node),
2800828997
28998 .tagged_union,
28999 .tagged_union_trailing,
29000 => tree.taggedUnion(enum_node),
29001 .tagged_union_two,
29002 .tagged_union_two_trailing,
29003 => tree.taggedUnionTwo(&buffer, enum_node),
29004 .tagged_union_enum_tag,
29005 .tagged_union_enum_tag_trailing,
29006 => tree.taggedUnionEnumTag(enum_node),
29007
28009 // Container was constructed with `@Type`.29008 // Container was constructed with `@Type`.
28010 else => return LazySrcLoc.nodeOffset(node_offset),29009 else => return LazySrcLoc.nodeOffset(0),
28011 };29010 };
28012 var it_index: usize = 0;29011 var it_index: usize = 0;
28013 for (container_decl.ast.members) |member_node| {29012 for (container_decl.ast.members) |member_node| {
...@@ -28437,8 +29436,6 @@ fn typePtrOrOptionalPtrTy(...@@ -28437,8 +29436,6 @@ fn typePtrOrOptionalPtrTy(
28437/// TODO merge these implementations together with the "advanced"/sema_kit pattern seen29436/// TODO merge these implementations together with the "advanced"/sema_kit pattern seen
28438/// elsewhere in value.zig29437/// elsewhere in value.zig
28439pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {29438pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {
28440 if (build_options.omit_stage2)
28441 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
28442 return switch (ty.tag()) {29439 return switch (ty.tag()) {
28443 .u1,29440 .u1,
28444 .u8,29441 .u8,
...@@ -28543,7 +29540,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ...@@ -28543,7 +29540,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ
28543 => {29540 => {
28544 const child_ty = ty.childType();29541 const child_ty = ty.childType();
28545 if (child_ty.zigTypeTag() == .Fn) {29542 if (child_ty.zigTypeTag() == .Fn) {
28546 return false;29543 return child_ty.fnInfo().is_generic;
28547 } else {29544 } else {
28548 return sema.typeRequiresComptime(block, src, child_ty);29545 return sema.typeRequiresComptime(block, src, child_ty);
28549 }29546 }
...@@ -28656,7 +29653,9 @@ fn unionFieldAlignment(...@@ -28656,7 +29653,9 @@ fn unionFieldAlignment(
28656 src: LazySrcLoc,29653 src: LazySrcLoc,
28657 field: Module.Union.Field,29654 field: Module.Union.Field,
28658) !u32 {29655) !u32 {
28659 if (field.abi_align == 0) {29656 if (field.ty.zigTypeTag() == .NoReturn) {
29657 return @as(u32, 0);
29658 } else if (field.abi_align == 0) {
28660 return sema.typeAbiAlignment(block, src, field.ty);29659 return sema.typeAbiAlignment(block, src, field.ty);
28661 } else {29660 } else {
28662 return field.abi_align;29661 return field.abi_align;
...@@ -29430,7 +30429,7 @@ fn valuesEqual(...@@ -29430,7 +30429,7 @@ fn valuesEqual(
29430 rhs: Value,30429 rhs: Value,
29431 ty: Type,30430 ty: Type,
29432) CompileError!bool {30431) CompileError!bool {
29433 return Value.eqlAdvanced(lhs, rhs, ty, sema.mod, sema.kit(block, src));30432 return Value.eqlAdvanced(lhs, ty, rhs, ty, sema.mod, sema.kit(block, src));
29434}30433}
2943530434
29436/// Asserts the values are comparable vectors of type `ty`.30435/// Asserts the values are comparable vectors of type `ty`.
...@@ -29478,7 +30477,7 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {...@@ -29478,7 +30477,7 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {
29478 // The resulting pointer is aligned to the lcd between the offset (an30477 // The resulting pointer is aligned to the lcd between the offset (an
29479 // arbitrary number) and the alignment factor (always a power of two,30478 // arbitrary number) and the alignment factor (always a power of two,
29480 // non zero).30479 // non zero).
29481 const new_align = @as(u32, 1) << @intCast(u5, @ctz(u64, addend | ptr_info.@"align"));30480 const new_align = @as(u32, 1) << @intCast(u5, @ctz(addend | ptr_info.@"align"));
29482 break :a new_align;30481 break :a new_align;
29483 };30482 };
29484 return try Type.ptr(sema.arena, sema.mod, .{30483 return try Type.ptr(sema.arena, sema.mod, .{
src/Zir.zig+53-29
...@@ -43,7 +43,11 @@ pub const Header = extern struct {...@@ -43,7 +43,11 @@ pub const Header = extern struct {
43 instructions_len: u32,43 instructions_len: u32,
44 string_bytes_len: u32,44 string_bytes_len: u32,
45 extra_len: u32,45 extra_len: u32,
4646 /// We could leave this as padding, however it triggers a Valgrind warning because
47 /// we read and write undefined bytes to the file system. This is harmless, but
48 /// it's essentially free to have a zero field here and makes the warning go away,
49 /// making it more likely that following Valgrind warnings will be taken seriously.
50 unused: u32 = 0,
47 stat_inode: std.fs.File.INode,51 stat_inode: std.fs.File.INode,
48 stat_size: u64,52 stat_size: u64,
49 stat_mtime: i128,53 stat_mtime: i128,
...@@ -490,14 +494,6 @@ pub const Inst = struct {...@@ -490,14 +494,6 @@ pub const Inst = struct {
490 /// Merge two error sets into one, `E1 || E2`.494 /// Merge two error sets into one, `E1 || E2`.
491 /// Uses the `pl_node` field with payload `Bin`.495 /// Uses the `pl_node` field with payload `Bin`.
492 merge_error_sets,496 merge_error_sets,
493 /// Given a reference to a function and a parameter index, returns the
494 /// type of the parameter. The only usage of this instruction is for the
495 /// result location of parameters of function calls. In the case of a function's
496 /// parameter type being `anytype`, it is the type coercion's job to detect this
497 /// scenario and skip the coercion, so that semantic analysis of this instruction
498 /// is not in a position where it must create an invalid type.
499 /// Uses the `param_type` union field.
500 param_type,
501 /// Turns an R-Value into a const L-Value. In other words, it takes a value,497 /// Turns an R-Value into a const L-Value. In other words, it takes a value,
502 /// stores it in a memory location, and returns a const pointer to it. If the value498 /// stores it in a memory location, and returns a const pointer to it. If the value
503 /// is `comptime`, the memory location is global static constant data. Otherwise,499 /// is `comptime`, the memory location is global static constant data. Otherwise,
...@@ -839,8 +835,6 @@ pub const Inst = struct {...@@ -839,8 +835,6 @@ pub const Inst = struct {
839 round,835 round,
840 /// Implement builtin `@tagName`. Uses `un_node`.836 /// Implement builtin `@tagName`. Uses `un_node`.
841 tag_name,837 tag_name,
842 /// Implement builtin `@Type`. Uses `un_node`.
843 reify,
844 /// Implement builtin `@typeName`. Uses `un_node`.838 /// Implement builtin `@typeName`. Uses `un_node`.
845 type_name,839 type_name,
846 /// Implement builtin `@Frame`. Uses `un_node`.840 /// Implement builtin `@Frame`. Uses `un_node`.
...@@ -1097,7 +1091,6 @@ pub const Inst = struct {...@@ -1097,7 +1091,6 @@ pub const Inst = struct {
1097 .mul,1091 .mul,
1098 .mulwrap,1092 .mulwrap,
1099 .mul_sat,1093 .mul_sat,
1100 .param_type,
1101 .ref,1094 .ref,
1102 .shl,1095 .shl,
1103 .shl_sat,1096 .shl_sat,
...@@ -1197,7 +1190,6 @@ pub const Inst = struct {...@@ -1197,7 +1190,6 @@ pub const Inst = struct {
1197 .trunc,1190 .trunc,
1198 .round,1191 .round,
1199 .tag_name,1192 .tag_name,
1200 .reify,
1201 .type_name,1193 .type_name,
1202 .frame_type,1194 .frame_type,
1203 .frame_size,1195 .frame_size,
...@@ -1400,7 +1392,6 @@ pub const Inst = struct {...@@ -1400,7 +1392,6 @@ pub const Inst = struct {
1400 .mul,1392 .mul,
1401 .mulwrap,1393 .mulwrap,
1402 .mul_sat,1394 .mul_sat,
1403 .param_type,
1404 .ref,1395 .ref,
1405 .shl,1396 .shl,
1406 .shl_sat,1397 .shl_sat,
...@@ -1484,7 +1475,6 @@ pub const Inst = struct {...@@ -1484,7 +1475,6 @@ pub const Inst = struct {
1484 .trunc,1475 .trunc,
1485 .round,1476 .round,
1486 .tag_name,1477 .tag_name,
1487 .reify,
1488 .type_name,1478 .type_name,
1489 .frame_type,1479 .frame_type,
1490 .frame_size,1480 .frame_size,
...@@ -1573,7 +1563,6 @@ pub const Inst = struct {...@@ -1573,7 +1563,6 @@ pub const Inst = struct {
1573 .mulwrap = .pl_node,1563 .mulwrap = .pl_node,
1574 .mul_sat = .pl_node,1564 .mul_sat = .pl_node,
15751565
1576 .param_type = .param_type,
1577 .param = .pl_tok,1566 .param = .pl_tok,
1578 .param_comptime = .pl_tok,1567 .param_comptime = .pl_tok,
1579 .param_anytype = .str_tok,1568 .param_anytype = .str_tok,
...@@ -1759,7 +1748,6 @@ pub const Inst = struct {...@@ -1759,7 +1748,6 @@ pub const Inst = struct {
1759 .trunc = .un_node,1748 .trunc = .un_node,
1760 .round = .un_node,1749 .round = .un_node,
1761 .tag_name = .un_node,1750 .tag_name = .un_node,
1762 .reify = .un_node,
1763 .type_name = .un_node,1751 .type_name = .un_node,
1764 .frame_type = .un_node,1752 .frame_type = .un_node,
1765 .frame_size = .un_node,1753 .frame_size = .un_node,
...@@ -1980,6 +1968,10 @@ pub const Inst = struct {...@@ -1980,6 +1968,10 @@ pub const Inst = struct {
1980 /// Implement builtin `@intToError`.1968 /// Implement builtin `@intToError`.
1981 /// `operand` is payload index to `UnNode`.1969 /// `operand` is payload index to `UnNode`.
1982 int_to_error,1970 int_to_error,
1971 /// Implement builtin `@Type`.
1972 /// `operand` is payload index to `UnNode`.
1973 /// `small` contains `NameStrategy
1974 reify,
19831975
1984 pub const InstData = struct {1976 pub const InstData = struct {
1985 opcode: Extended,1977 opcode: Extended,
...@@ -2541,10 +2533,6 @@ pub const Inst = struct {...@@ -2541,10 +2533,6 @@ pub const Inst = struct {
2541 /// Points to a `Block`.2533 /// Points to a `Block`.
2542 payload_index: u32,2534 payload_index: u32,
2543 },2535 },
2544 param_type: struct {
2545 callee: Ref,
2546 param_index: u32,
2547 },
2548 @"unreachable": struct {2536 @"unreachable": struct {
2549 /// Offset from Decl AST node index.2537 /// Offset from Decl AST node index.
2550 /// `Tag` determines which kind of AST node this points to.2538 /// `Tag` determines which kind of AST node this points to.
...@@ -2615,7 +2603,6 @@ pub const Inst = struct {...@@ -2615,7 +2603,6 @@ pub const Inst = struct {
2615 ptr_type,2603 ptr_type,
2616 int_type,2604 int_type,
2617 bool_br,2605 bool_br,
2618 param_type,
2619 @"unreachable",2606 @"unreachable",
2620 @"break",2607 @"break",
2621 switch_capture,2608 switch_capture,
...@@ -2795,7 +2782,9 @@ pub const Inst = struct {...@@ -2795,7 +2782,9 @@ pub const Inst = struct {
2795 };2782 };
27962783
2797 /// Stored inside extra, with trailing arguments according to `args_len`.2784 /// Stored inside extra, with trailing arguments according to `args_len`.
2798 /// Each argument is a `Ref`.2785 /// Implicit 0. arg_0_start: u32, // always same as `args_len`
2786 /// 1. arg_end: u32, // for each `args_len`
2787 /// arg_N_start is the same as arg_N-1_end
2799 pub const Call = struct {2788 pub const Call = struct {
2800 // Note: Flags *must* come first so that unusedResultExpr2789 // Note: Flags *must* come first so that unusedResultExpr
2801 // can find it when it goes to modify them.2790 // can find it when it goes to modify them.
...@@ -3100,13 +3089,16 @@ pub const Inst = struct {...@@ -3100,13 +3089,16 @@ pub const Inst = struct {
3100 /// 0. src_node: i32, // if has_src_node3089 /// 0. src_node: i32, // if has_src_node
3101 /// 1. fields_len: u32, // if has_fields_len3090 /// 1. fields_len: u32, // if has_fields_len
3102 /// 2. decls_len: u32, // if has_decls_len3091 /// 2. decls_len: u32, // if has_decls_len
3103 /// 3. decl_bits: u32 // for every 8 decls3092 /// 3. backing_int_body_len: u32, // if has_backing_int
3093 /// 4. backing_int_ref: Ref, // if has_backing_int and backing_int_body_len is 0
3094 /// 5. backing_int_body_inst: Inst, // if has_backing_int and backing_int_body_len is > 0
3095 /// 6. decl_bits: u32 // for every 8 decls
3104 /// - sets of 4 bits:3096 /// - sets of 4 bits:
3105 /// 0b000X: whether corresponding decl is pub3097 /// 0b000X: whether corresponding decl is pub
3106 /// 0b00X0: whether corresponding decl is exported3098 /// 0b00X0: whether corresponding decl is exported
3107 /// 0b0X00: whether corresponding decl has an align expression3099 /// 0b0X00: whether corresponding decl has an align expression
3108 /// 0bX000: whether corresponding decl has a linksection or an address space expression3100 /// 0bX000: whether corresponding decl has a linksection or an address space expression
3109 /// 4. decl: { // for every decls_len3101 /// 7. decl: { // for every decls_len
3110 /// src_hash: [4]u32, // hash of source bytes3102 /// src_hash: [4]u32, // hash of source bytes
3111 /// line: u32, // line number of decl, relative to parent3103 /// line: u32, // line number of decl, relative to parent
3112 /// name: u32, // null terminated string index3104 /// name: u32, // null terminated string index
...@@ -3124,13 +3116,13 @@ pub const Inst = struct {...@@ -3124,13 +3116,13 @@ pub const Inst = struct {
3124 /// address_space: Ref,3116 /// address_space: Ref,
3125 /// }3117 /// }
3126 /// }3118 /// }
3127 /// 5. flags: u32 // for every 8 fields3119 /// 8. flags: u32 // for every 8 fields
3128 /// - sets of 4 bits:3120 /// - sets of 4 bits:
3129 /// 0b000X: whether corresponding field has an align expression3121 /// 0b000X: whether corresponding field has an align expression
3130 /// 0b00X0: whether corresponding field has a default expression3122 /// 0b00X0: whether corresponding field has a default expression
3131 /// 0b0X00: whether corresponding field is comptime3123 /// 0b0X00: whether corresponding field is comptime
3132 /// 0bX000: whether corresponding field has a type expression3124 /// 0bX000: whether corresponding field has a type expression
3133 /// 6. fields: { // for every fields_len3125 /// 9. fields: { // for every fields_len
3134 /// field_name: u32,3126 /// field_name: u32,
3135 /// doc_comment: u32, // 0 if no doc comment3127 /// doc_comment: u32, // 0 if no doc comment
3136 /// field_type: Ref, // if corresponding bit is not set. none means anytype.3128 /// field_type: Ref, // if corresponding bit is not set. none means anytype.
...@@ -3138,7 +3130,7 @@ pub const Inst = struct {...@@ -3138,7 +3130,7 @@ pub const Inst = struct {
3138 /// align_body_len: u32, // if corresponding bit is set3130 /// align_body_len: u32, // if corresponding bit is set
3139 /// init_body_len: u32, // if corresponding bit is set3131 /// init_body_len: u32, // if corresponding bit is set
3140 /// }3132 /// }
3141 /// 7. bodies: { // for every fields_len3133 /// 10. bodies: { // for every fields_len
3142 /// field_type_body_inst: Inst, // for each field_type_body_len3134 /// field_type_body_inst: Inst, // for each field_type_body_len
3143 /// align_body_inst: Inst, // for each align_body_len3135 /// align_body_inst: Inst, // for each align_body_len
3144 /// init_body_inst: Inst, // for each init_body_len3136 /// init_body_inst: Inst, // for each init_body_len
...@@ -3148,11 +3140,12 @@ pub const Inst = struct {...@@ -3148,11 +3140,12 @@ pub const Inst = struct {
3148 has_src_node: bool,3140 has_src_node: bool,
3149 has_fields_len: bool,3141 has_fields_len: bool,
3150 has_decls_len: bool,3142 has_decls_len: bool,
3143 has_backing_int: bool,
3151 known_non_opv: bool,3144 known_non_opv: bool,
3152 known_comptime_only: bool,3145 known_comptime_only: bool,
3153 name_strategy: NameStrategy,3146 name_strategy: NameStrategy,
3154 layout: std.builtin.Type.ContainerLayout,3147 layout: std.builtin.Type.ContainerLayout,
3155 _: u7 = undefined,3148 _: u6 = undefined,
3156 };3149 };
3157 };3150 };
31583151
...@@ -3619,6 +3612,16 @@ pub fn declIterator(zir: Zir, decl_inst: u32) DeclIterator {...@@ -3619,6 +3612,16 @@ pub fn declIterator(zir: Zir, decl_inst: u32) DeclIterator {
3619 break :decls_len decls_len;3612 break :decls_len decls_len;
3620 } else 0;3613 } else 0;
36213614
3615 if (small.has_backing_int) {
3616 const backing_int_body_len = zir.extra[extra_index];
3617 extra_index += 1; // backing_int_body_len
3618 if (backing_int_body_len == 0) {
3619 extra_index += 1; // backing_int_ref
3620 } else {
3621 extra_index += backing_int_body_len; // backing_int_body_inst
3622 }
3623 }
3624
3622 return declIteratorInner(zir, extra_index, decls_len);3625 return declIteratorInner(zir, extra_index, decls_len);
3623 },3626 },
3624 .enum_decl => {3627 .enum_decl => {
...@@ -3915,6 +3918,27 @@ pub const FnInfo = struct {...@@ -3915,6 +3918,27 @@ pub const FnInfo = struct {
3915 total_params_len: u32,3918 total_params_len: u32,
3916};3919};
39173920
3921pub fn getParamBody(zir: Zir, fn_inst: Inst.Index) []const u32 {
3922 const tags = zir.instructions.items(.tag);
3923 const datas = zir.instructions.items(.data);
3924 const inst_data = datas[fn_inst].pl_node;
3925
3926 const param_block_index = switch (tags[fn_inst]) {
3927 .func, .func_inferred => blk: {
3928 const extra = zir.extraData(Inst.Func, inst_data.payload_index);
3929 break :blk extra.data.param_block;
3930 },
3931 .func_fancy => blk: {
3932 const extra = zir.extraData(Inst.FuncFancy, inst_data.payload_index);
3933 break :blk extra.data.param_block;
3934 },
3935 else => unreachable,
3936 };
3937
3938 const param_block = zir.extraData(Inst.Block, datas[param_block_index].pl_node.payload_index);
3939 return zir.extra[param_block.end..][0..param_block.data.body_len];
3940}
3941
3918pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {3942pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
3919 const tags = zir.instructions.items(.tag);3943 const tags = zir.instructions.items(.tag);
3920 const datas = zir.instructions.items(.data);3944 const datas = zir.instructions.items(.data);
src/arch/aarch64/CodeGen.zig+703-161
...@@ -166,10 +166,12 @@ const MCValue = union(enum) {...@@ -166,10 +166,12 @@ const MCValue = union(enum) {
166 /// the type is u1) or true (if the type in bool) iff the166 /// the type is u1) or true (if the type in bool) iff the
167 /// specified condition is true.167 /// specified condition is true.
168 condition_flags: Condition,168 condition_flags: Condition,
169 /// The value is a function argument passed via the stack.
170 stack_argument_offset: u32,
169171
170 fn isMemory(mcv: MCValue) bool {172 fn isMemory(mcv: MCValue) bool {
171 return switch (mcv) {173 return switch (mcv) {
172 .memory, .stack_offset => true,174 .memory, .stack_offset, .stack_argument_offset => true,
173 else => false,175 else => false,
174 };176 };
175 }177 }
...@@ -192,6 +194,7 @@ const MCValue = union(enum) {...@@ -192,6 +194,7 @@ const MCValue = union(enum) {
192 .condition_flags,194 .condition_flags,
193 .ptr_stack_offset,195 .ptr_stack_offset,
194 .undef,196 .undef,
197 .stack_argument_offset,
195 => false,198 => false,
196199
197 .register,200 .register,
...@@ -337,6 +340,7 @@ pub fn generate(...@@ -337,6 +340,7 @@ pub fn generate(
337 .prev_di_line = module_fn.lbrace_line,340 .prev_di_line = module_fn.lbrace_line,
338 .prev_di_column = module_fn.lbrace_column,341 .prev_di_column = module_fn.lbrace_column,
339 .stack_size = mem.alignForwardGeneric(u32, function.max_end_stack, function.stack_align),342 .stack_size = mem.alignForwardGeneric(u32, function.max_end_stack, function.stack_align),
343 .saved_regs_stack_space = function.saved_regs_stack_space,
340 };344 };
341 defer emit.deinit();345 defer emit.deinit();
342346
...@@ -414,6 +418,23 @@ fn gen(self: *Self) !void {...@@ -414,6 +418,23 @@ fn gen(self: *Self) !void {
414 // sub sp, sp, #reloc418 // sub sp, sp, #reloc
415 const backpatch_reloc = try self.addNop();419 const backpatch_reloc = try self.addNop();
416420
421 if (self.ret_mcv == .stack_offset) {
422 // The address of where to store the return value is in x0
423 // (or w0 when pointer size is 32 bits). As this register
424 // might get overwritten along the way, save the address
425 // to the stack.
426 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
427 const ptr_bytes = @divExact(ptr_bits, 8);
428 const ret_ptr_reg = registerAlias(.x0, ptr_bytes);
429
430 const stack_offset = mem.alignForwardGeneric(u32, self.next_stack_offset, ptr_bytes) + ptr_bytes;
431 self.next_stack_offset = stack_offset;
432 self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset);
433
434 try self.genSetStack(Type.usize, stack_offset, MCValue{ .register = ret_ptr_reg });
435 self.ret_mcv = MCValue{ .stack_offset = stack_offset };
436 }
437
417 _ = try self.addInst(.{438 _ = try self.addInst(.{
418 .tag = .dbg_prologue_end,439 .tag = .dbg_prologue_end,
419 .data = .{ .nop = {} },440 .data = .{ .nop = {} },
...@@ -540,33 +561,38 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -540,33 +561,38 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
540561
541 switch (air_tags[inst]) {562 switch (air_tags[inst]) {
542 // zig fmt: off563 // zig fmt: off
543 .add => try self.airBinOp(inst, .add),564 .add => try self.airBinOp(inst, .add),
544 .addwrap => try self.airBinOp(inst, .addwrap),565 .addwrap => try self.airBinOp(inst, .addwrap),
545 .sub => try self.airBinOp(inst, .sub),566 .sub => try self.airBinOp(inst, .sub),
546 .subwrap => try self.airBinOp(inst, .subwrap),567 .subwrap => try self.airBinOp(inst, .subwrap),
547 .mul => try self.airBinOp(inst, .mul),568 .mul => try self.airBinOp(inst, .mul),
548 .mulwrap => try self.airBinOp(inst, .mulwrap),569 .mulwrap => try self.airBinOp(inst, .mulwrap),
549 .shl => try self.airBinOp(inst, .shl),570 .shl => try self.airBinOp(inst, .shl),
550 .shl_exact => try self.airBinOp(inst, .shl_exact),571 .shl_exact => try self.airBinOp(inst, .shl_exact),
551 .bool_and => try self.airBinOp(inst, .bool_and),572 .bool_and => try self.airBinOp(inst, .bool_and),
552 .bool_or => try self.airBinOp(inst, .bool_or),573 .bool_or => try self.airBinOp(inst, .bool_or),
553 .bit_and => try self.airBinOp(inst, .bit_and),574 .bit_and => try self.airBinOp(inst, .bit_and),
554 .bit_or => try self.airBinOp(inst, .bit_or),575 .bit_or => try self.airBinOp(inst, .bit_or),
555 .xor => try self.airBinOp(inst, .xor),576 .xor => try self.airBinOp(inst, .xor),
556 .shr => try self.airBinOp(inst, .shr),577 .shr => try self.airBinOp(inst, .shr),
557 .shr_exact => try self.airBinOp(inst, .shr_exact),578 .shr_exact => try self.airBinOp(inst, .shr_exact),
558579 .div_float => try self.airBinOp(inst, .div_float),
559 .ptr_add => try self.airPtrArithmetic(inst, .ptr_add),580 .div_trunc => try self.airBinOp(inst, .div_trunc),
560 .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub),581 .div_floor => try self.airBinOp(inst, .div_floor),
582 .div_exact => try self.airBinOp(inst, .div_exact),
583 .rem => try self.airBinOp(inst, .rem),
584 .mod => try self.airBinOp(inst, .mod),
585
586 .ptr_add => try self.airPtrArithmetic(inst, .ptr_add),
587 .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub),
588
589 .min => try self.airMin(inst),
590 .max => try self.airMax(inst),
561591
562 .add_sat => try self.airAddSat(inst),592 .add_sat => try self.airAddSat(inst),
563 .sub_sat => try self.airSubSat(inst),593 .sub_sat => try self.airSubSat(inst),
564 .mul_sat => try self.airMulSat(inst),594 .mul_sat => try self.airMulSat(inst),
565 .rem => try self.airRem(inst),
566 .mod => try self.airMod(inst),
567 .shl_sat => try self.airShlSat(inst),595 .shl_sat => try self.airShlSat(inst),
568 .min => try self.airMin(inst),
569 .max => try self.airMax(inst),
570 .slice => try self.airSlice(inst),596 .slice => try self.airSlice(inst),
571597
572 .sqrt,598 .sqrt,
...@@ -591,8 +617,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -591,8 +617,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
591 .mul_with_overflow => try self.airMulWithOverflow(inst),617 .mul_with_overflow => try self.airMulWithOverflow(inst),
592 .shl_with_overflow => try self.airShlWithOverflow(inst),618 .shl_with_overflow => try self.airShlWithOverflow(inst),
593619
594 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
595
596 .cmp_lt => try self.airCmp(inst, .lt),620 .cmp_lt => try self.airCmp(inst, .lt),
597 .cmp_lte => try self.airCmp(inst, .lte),621 .cmp_lte => try self.airCmp(inst, .lte),
598 .cmp_eq => try self.airCmp(inst, .eq),622 .cmp_eq => try self.airCmp(inst, .eq),
...@@ -753,6 +777,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -753,6 +777,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
753 .float_to_int_optimized,777 .float_to_int_optimized,
754 => return self.fail("TODO implement optimized float mode", .{}),778 => return self.fail("TODO implement optimized float mode", .{}),
755779
780 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),
781 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),
782
756 .wasm_memory_size => unreachable,783 .wasm_memory_size => unreachable,
757 .wasm_memory_grow => unreachable,784 .wasm_memory_grow => unreachable,
758 // zig fmt: on785 // zig fmt: on
...@@ -1008,17 +1035,43 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {...@@ -1008,17 +1035,43 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
1008 if (self.liveness.isUnused(inst))1035 if (self.liveness.isUnused(inst))
1009 return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });1036 return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
10101037
1011 const operand_ty = self.air.typeOf(ty_op.operand);1038 const operand = ty_op.operand;
1012 const operand = try self.resolveInst(ty_op.operand);1039 const operand_mcv = try self.resolveInst(operand);
1013 const info_a = operand_ty.intInfo(self.target.*);1040 const operand_ty = self.air.typeOf(operand);
1014 const info_b = self.air.typeOfIndex(inst).intInfo(self.target.*);1041 const operand_info = operand_ty.intInfo(self.target.*);
1015 if (info_a.signedness != info_b.signedness)
1016 return self.fail("TODO gen intcast sign safety in semantic analysis", .{});
10171042
1018 if (info_a.bits == info_b.bits)1043 const dest_ty = self.air.typeOfIndex(inst);
1019 return self.finishAir(inst, operand, .{ ty_op.operand, .none, .none });1044 const dest_abi_size = dest_ty.abiSize(self.target.*);
1045 const dest_info = dest_ty.intInfo(self.target.*);
1046
1047 const result: MCValue = result: {
1048 const operand_lock: ?RegisterLock = switch (operand_mcv) {
1049 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
1050 else => null,
1051 };
1052 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
1053
1054 const truncated: MCValue = switch (operand_mcv) {
1055 .register => |r| MCValue{ .register = registerAlias(r, dest_abi_size) },
1056 else => operand_mcv,
1057 };
1058
1059 if (dest_info.bits > operand_info.bits) {
1060 const dest_mcv = try self.allocRegOrMem(inst, true);
1061 try self.setRegOrMem(self.air.typeOfIndex(inst), dest_mcv, truncated);
1062 break :result dest_mcv;
1063 } else {
1064 if (self.reuseOperand(inst, operand, 0, truncated)) {
1065 break :result truncated;
1066 } else {
1067 const dest_mcv = try self.allocRegOrMem(inst, true);
1068 try self.setRegOrMem(self.air.typeOfIndex(inst), dest_mcv, truncated);
1069 break :result dest_mcv;
1070 }
1071 }
1072 };
10201073
1021 return self.fail("TODO implement intCast for {}", .{self.target.cpu.arch});1074 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1022}1075}
10231076
1024fn truncRegister(1077fn truncRegister(
...@@ -1044,6 +1097,8 @@ fn truncRegister(...@@ -1044,6 +1097,8 @@ fn truncRegister(
1044 });1097 });
1045 },1098 },
1046 32, 64 => {1099 32, 64 => {
1100 assert(dest_reg.size() == operand_reg.size());
1101
1047 _ = try self.addInst(.{1102 _ = try self.addInst(.{
1048 .tag = .mov_register,1103 .tag = .mov_register,
1049 .data = .{ .rr = .{1104 .data = .{ .rr = .{
...@@ -1099,7 +1154,7 @@ fn trunc(...@@ -1099,7 +1154,7 @@ fn trunc(
10991154
1100 return MCValue{ .register = dest_reg };1155 return MCValue{ .register = dest_reg };
1101 } else {1156 } else {
1102 return self.fail("TODO: truncate to ints > 32 bits", .{});1157 return self.fail("TODO: truncate to ints > 64 bits", .{});
1103 }1158 }
1104}1159}
11051160
...@@ -1262,6 +1317,9 @@ fn binOpRegister(...@@ -1262,6 +1317,9 @@ fn binOpRegister(
1262 const lhs_is_register = lhs == .register;1317 const lhs_is_register = lhs == .register;
1263 const rhs_is_register = rhs == .register;1318 const rhs_is_register = rhs == .register;
12641319
1320 if (lhs_is_register) assert(lhs.register == registerAlias(lhs.register, lhs_ty.abiSize(self.target.*)));
1321 if (rhs_is_register) assert(rhs.register == registerAlias(rhs.register, rhs_ty.abiSize(self.target.*)));
1322
1265 const lhs_lock: ?RegisterLock = if (lhs_is_register)1323 const lhs_lock: ?RegisterLock = if (lhs_is_register)
1266 self.register_manager.lockReg(lhs.register)1324 self.register_manager.lockReg(lhs.register)
1267 else1325 else
...@@ -1291,13 +1349,22 @@ fn binOpRegister(...@@ -1291,13 +1349,22 @@ fn binOpRegister(
1291 const new_lhs_lock = self.register_manager.lockReg(lhs_reg);1349 const new_lhs_lock = self.register_manager.lockReg(lhs_reg);
1292 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);1350 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);
12931351
1294 const rhs_reg = if (rhs_is_register) rhs.register else blk: {1352 const rhs_reg = if (rhs_is_register)
1353 // lhs is almost always equal to rhs, except in shifts. In
1354 // order to guarantee that registers will have equal sizes, we
1355 // use the register alias of rhs corresponding to the size of
1356 // lhs.
1357 registerAlias(rhs.register, lhs_ty.abiSize(self.target.*))
1358 else blk: {
1295 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {1359 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
1296 break :inst Air.refToIndex(md.rhs).?;1360 break :inst Air.refToIndex(md.rhs).?;
1297 } else null;1361 } else null;
12981362
1299 const raw_reg = try self.register_manager.allocReg(track_inst, gp);1363 const raw_reg = try self.register_manager.allocReg(track_inst, gp);
1300 const reg = registerAlias(raw_reg, rhs_ty.abiAlignment(self.target.*));1364
1365 // Here, we deliberately use lhs as lhs and rhs may differ in
1366 // the case of shifts. See comment above.
1367 const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
13011368
1302 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });1369 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
13031370
...@@ -1348,6 +1415,8 @@ fn binOpRegister(...@@ -1348,6 +1415,8 @@ fn binOpRegister(
1348 .lsl_register,1415 .lsl_register,
1349 .asr_register,1416 .asr_register,
1350 .lsr_register,1417 .lsr_register,
1418 .sdiv,
1419 .udiv,
1351 => .{ .rrr = .{1420 => .{ .rrr = .{
1352 .rd = dest_reg,1421 .rd = dest_reg,
1353 .rn = lhs_reg,1422 .rn = lhs_reg,
...@@ -1404,6 +1473,8 @@ fn binOpImmediate(...@@ -1404,6 +1473,8 @@ fn binOpImmediate(
1404) !MCValue {1473) !MCValue {
1405 const lhs_is_register = lhs == .register;1474 const lhs_is_register = lhs == .register;
14061475
1476 if (lhs_is_register) assert(lhs.register == registerAlias(lhs.register, lhs_ty.abiSize(self.target.*)));
1477
1407 const lhs_lock: ?RegisterLock = if (lhs_is_register)1478 const lhs_lock: ?RegisterLock = if (lhs_is_register)
1408 self.register_manager.lockReg(lhs.register)1479 self.register_manager.lockReg(lhs.register)
1409 else1480 else
...@@ -1586,6 +1657,151 @@ fn binOp(...@@ -1586,6 +1657,151 @@ fn binOp(
1586 else => unreachable,1657 else => unreachable,
1587 }1658 }
1588 },1659 },
1660 .div_float => {
1661 switch (lhs_ty.zigTypeTag()) {
1662 .Float => return self.fail("TODO div_float", .{}),
1663 .Vector => return self.fail("TODO div_float on vectors", .{}),
1664 else => unreachable,
1665 }
1666 },
1667 .div_trunc, .div_floor, .div_exact => {
1668 switch (lhs_ty.zigTypeTag()) {
1669 .Float => return self.fail("TODO div on floats", .{}),
1670 .Vector => return self.fail("TODO div on vectors", .{}),
1671 .Int => {
1672 assert(lhs_ty.eql(rhs_ty, mod));
1673 const int_info = lhs_ty.intInfo(self.target.*);
1674 if (int_info.bits <= 64) {
1675 switch (int_info.signedness) {
1676 .signed => {
1677 switch (tag) {
1678 .div_trunc, .div_exact => {
1679 // TODO optimize integer division by constants
1680 return try self.binOpRegister(.sdiv, lhs, rhs, lhs_ty, rhs_ty, metadata);
1681 },
1682 .div_floor => return self.fail("TODO div_floor on signed integers", .{}),
1683 else => unreachable,
1684 }
1685 },
1686 .unsigned => {
1687 // TODO optimize integer division by constants
1688 return try self.binOpRegister(.udiv, lhs, rhs, lhs_ty, rhs_ty, metadata);
1689 },
1690 }
1691 } else {
1692 return self.fail("TODO integer division for ints with bits > 64", .{});
1693 }
1694 },
1695 else => unreachable,
1696 }
1697 },
1698 .rem, .mod => {
1699 switch (lhs_ty.zigTypeTag()) {
1700 .Float => return self.fail("TODO rem/mod on floats", .{}),
1701 .Vector => return self.fail("TODO rem/mod on vectors", .{}),
1702 .Int => {
1703 assert(lhs_ty.eql(rhs_ty, mod));
1704 const int_info = lhs_ty.intInfo(self.target.*);
1705 if (int_info.bits <= 64) {
1706 if (int_info.signedness == .signed and tag == .mod) {
1707 return self.fail("TODO mod on signed integers", .{});
1708 } else {
1709 const lhs_is_register = lhs == .register;
1710 const rhs_is_register = rhs == .register;
1711
1712 const lhs_lock: ?RegisterLock = if (lhs_is_register)
1713 self.register_manager.lockReg(lhs.register)
1714 else
1715 null;
1716 defer if (lhs_lock) |reg| self.register_manager.unlockReg(reg);
1717
1718 const rhs_lock: ?RegisterLock = if (rhs_is_register)
1719 self.register_manager.lockReg(rhs.register)
1720 else
1721 null;
1722 defer if (rhs_lock) |reg| self.register_manager.unlockReg(reg);
1723
1724 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
1725
1726 const lhs_reg = if (lhs_is_register) lhs.register else blk: {
1727 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
1728 break :inst Air.refToIndex(md.lhs).?;
1729 } else null;
1730
1731 const raw_reg = try self.register_manager.allocReg(track_inst, gp);
1732 const reg = registerAlias(raw_reg, lhs_ty.abiSize(self.target.*));
1733
1734 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
1735
1736 break :blk reg;
1737 };
1738 const new_lhs_lock = self.register_manager.lockReg(lhs_reg);
1739 defer if (new_lhs_lock) |reg| self.register_manager.unlockReg(reg);
1740
1741 const rhs_reg = if (rhs_is_register) rhs.register else blk: {
1742 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
1743 break :inst Air.refToIndex(md.rhs).?;
1744 } else null;
1745
1746 const raw_reg = try self.register_manager.allocReg(track_inst, gp);
1747 const reg = registerAlias(raw_reg, rhs_ty.abiAlignment(self.target.*));
1748
1749 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
1750
1751 break :blk reg;
1752 };
1753 const new_rhs_lock = self.register_manager.lockReg(rhs_reg);
1754 defer if (new_rhs_lock) |reg| self.register_manager.unlockReg(reg);
1755
1756 const dest_regs: [2]Register = blk: {
1757 const raw_regs = try self.register_manager.allocRegs(2, .{ null, null }, gp);
1758 const abi_size = lhs_ty.abiSize(self.target.*);
1759 break :blk .{
1760 registerAlias(raw_regs[0], abi_size),
1761 registerAlias(raw_regs[1], abi_size),
1762 };
1763 };
1764 const dest_regs_locks = self.register_manager.lockRegsAssumeUnused(2, dest_regs);
1765 defer for (dest_regs_locks) |reg| {
1766 self.register_manager.unlockReg(reg);
1767 };
1768 const quotient_reg = dest_regs[0];
1769 const remainder_reg = dest_regs[1];
1770
1771 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
1772 if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs);
1773
1774 _ = try self.addInst(.{
1775 .tag = switch (int_info.signedness) {
1776 .signed => .sdiv,
1777 .unsigned => .udiv,
1778 },
1779 .data = .{ .rrr = .{
1780 .rd = quotient_reg,
1781 .rn = lhs_reg,
1782 .rm = rhs_reg,
1783 } },
1784 });
1785
1786 _ = try self.addInst(.{
1787 .tag = .msub,
1788 .data = .{ .rrrr = .{
1789 .rd = remainder_reg,
1790 .rn = quotient_reg,
1791 .rm = rhs_reg,
1792 .ra = lhs_reg,
1793 } },
1794 });
1795
1796 return MCValue{ .register = remainder_reg };
1797 }
1798 } else {
1799 return self.fail("TODO rem/mod for integers with bits > 64", .{});
1800 }
1801 },
1802 else => unreachable,
1803 }
1804 },
1589 .addwrap,1805 .addwrap,
1590 .subwrap,1806 .subwrap,
1591 .mulwrap,1807 .mulwrap,
...@@ -1869,7 +2085,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1869,7 +2085,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
1869 try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits);2085 try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits);
18702086
1871 // cmp dest, truncated2087 // cmp dest, truncated
1872 _ = try self.binOp(.cmp_eq, dest, .{ .register = truncated_reg }, Type.usize, Type.usize, null);2088 _ = try self.binOp(.cmp_eq, dest, .{ .register = truncated_reg }, lhs_ty, lhs_ty, null);
18732089
1874 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });2090 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });
1875 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .condition_flags = .ne });2091 try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .condition_flags = .ne });
...@@ -2257,24 +2473,6 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -2257,24 +2473,6 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
2257 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });2473 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
2258}2474}
22592475
2260fn airDiv(self: *Self, inst: Air.Inst.Index) !void {
2261 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2262 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement div for {}", .{self.target.cpu.arch});
2263 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2264}
2265
2266fn airRem(self: *Self, inst: Air.Inst.Index) !void {
2267 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2268 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement rem for {}", .{self.target.cpu.arch});
2269 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2270}
2271
2272fn airMod(self: *Self, inst: Air.Inst.Index) !void {
2273 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2274 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement mod for {}", .{self.target.cpu.arch});
2275 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2276}
2277
2278fn airShlSat(self: *Self, inst: Air.Inst.Index) !void {2476fn airShlSat(self: *Self, inst: Air.Inst.Index) !void {
2279 const bin_op = self.air.instructions.items(.data)[inst].bin_op;2477 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2280 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement shl_sat for {}", .{self.target.cpu.arch});2478 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement shl_sat for {}", .{self.target.cpu.arch});
...@@ -2313,6 +2511,9 @@ fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCV...@@ -2313,6 +2511,9 @@ fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCV
2313 const err_offset = @intCast(u32, errUnionErrorOffset(payload_ty, self.target.*));2511 const err_offset = @intCast(u32, errUnionErrorOffset(payload_ty, self.target.*));
2314 switch (error_union_mcv) {2512 switch (error_union_mcv) {
2315 .register => return self.fail("TODO errUnionErr for registers", .{}),2513 .register => return self.fail("TODO errUnionErr for registers", .{}),
2514 .stack_argument_offset => |off| {
2515 return MCValue{ .stack_argument_offset = off + err_offset };
2516 },
2316 .stack_offset => |off| {2517 .stack_offset => |off| {
2317 return MCValue{ .stack_offset = off - err_offset };2518 return MCValue{ .stack_offset = off - err_offset };
2318 },2519 },
...@@ -2347,6 +2548,9 @@ fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type)...@@ -2347,6 +2548,9 @@ fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type)
2347 const payload_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, self.target.*));2548 const payload_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, self.target.*));
2348 switch (error_union_mcv) {2549 switch (error_union_mcv) {
2349 .register => return self.fail("TODO errUnionPayload for registers", .{}),2550 .register => return self.fail("TODO errUnionPayload for registers", .{}),
2551 .stack_argument_offset => |off| {
2552 return MCValue{ .stack_argument_offset = off + payload_offset };
2553 },
2350 .stack_offset => |off| {2554 .stack_offset => |off| {
2351 return MCValue{ .stack_offset = off - payload_offset };2555 return MCValue{ .stack_offset = off - payload_offset };
2352 },2556 },
...@@ -2436,21 +2640,28 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2436,21 +2640,28 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
2436 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });2640 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2437}2641}
24382642
2643fn slicePtr(mcv: MCValue) MCValue {
2644 switch (mcv) {
2645 .dead, .unreach, .none => unreachable,
2646 .register => unreachable, // a slice doesn't fit in one register
2647 .stack_argument_offset => |off| {
2648 return MCValue{ .stack_argument_offset = off };
2649 },
2650 .stack_offset => |off| {
2651 return MCValue{ .stack_offset = off };
2652 },
2653 .memory => |addr| {
2654 return MCValue{ .memory = addr };
2655 },
2656 else => unreachable, // invalid MCValue for a slice
2657 }
2658}
2659
2439fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {2660fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
2440 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2661 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2441 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {2662 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2442 const mcv = try self.resolveInst(ty_op.operand);2663 const mcv = try self.resolveInst(ty_op.operand);
2443 switch (mcv) {2664 break :result slicePtr(mcv);
2444 .dead, .unreach, .none => unreachable,
2445 .register => unreachable, // a slice doesn't fit in one register
2446 .stack_offset => |off| {
2447 break :result MCValue{ .stack_offset = off };
2448 },
2449 .memory => |addr| {
2450 break :result MCValue{ .memory = addr };
2451 },
2452 else => return self.fail("TODO implement slice_len for {}", .{mcv}),
2453 }
2454 };2665 };
2455 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });2666 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2456}2667}
...@@ -2464,6 +2675,9 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {...@@ -2464,6 +2675,9 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
2464 switch (mcv) {2675 switch (mcv) {
2465 .dead, .unreach, .none => unreachable,2676 .dead, .unreach, .none => unreachable,
2466 .register => unreachable, // a slice doesn't fit in one register2677 .register => unreachable, // a slice doesn't fit in one register
2678 .stack_argument_offset => |off| {
2679 break :result MCValue{ .stack_argument_offset = off + ptr_bytes };
2680 },
2467 .stack_offset => |off| {2681 .stack_offset => |off| {
2468 break :result MCValue{ .stack_offset = off - ptr_bytes };2682 break :result MCValue{ .stack_offset = off - ptr_bytes };
2469 },2683 },
...@@ -2514,6 +2728,9 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2514,6 +2728,9 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
25142728
2515 if (!is_volatile and self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });2729 if (!is_volatile and self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
2516 const result: MCValue = result: {2730 const result: MCValue = result: {
2731 const slice_ty = self.air.typeOf(bin_op.lhs);
2732 const elem_ty = slice_ty.childType();
2733 const elem_size = elem_ty.abiSize(self.target.*);
2517 const slice_mcv = try self.resolveInst(bin_op.lhs);2734 const slice_mcv = try self.resolveInst(bin_op.lhs);
25182735
2519 // TODO optimize for the case where the index is a constant,2736 // TODO optimize for the case where the index is a constant,
...@@ -2521,10 +2738,6 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2521,10 +2738,6 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
2521 const index_mcv = try self.resolveInst(bin_op.rhs);2738 const index_mcv = try self.resolveInst(bin_op.rhs);
2522 const index_is_register = index_mcv == .register;2739 const index_is_register = index_mcv == .register;
25232740
2524 const slice_ty = self.air.typeOf(bin_op.lhs);
2525 const elem_ty = slice_ty.childType();
2526 const elem_size = elem_ty.abiSize(self.target.*);
2527
2528 var buf: Type.SlicePtrFieldTypeBuffer = undefined;2741 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
2529 const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf);2742 const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf);
25302743
...@@ -2534,15 +2747,17 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2534,15 +2747,17 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
2534 null;2747 null;
2535 defer if (index_lock) |reg| self.register_manager.unlockReg(reg);2748 defer if (index_lock) |reg| self.register_manager.unlockReg(reg);
25362749
2537 const base_mcv: MCValue = switch (slice_mcv) {2750 const base_mcv = slicePtr(slice_mcv);
2538 .stack_offset => |off| .{ .register = try self.copyToTmpRegister(slice_ptr_field_type, .{ .stack_offset = off }) },
2539 else => return self.fail("TODO slice_elem_val when slice is {}", .{slice_mcv}),
2540 };
2541 const base_lock = self.register_manager.lockRegAssumeUnused(base_mcv.register);
2542 defer self.register_manager.unlockReg(base_lock);
25432751
2544 switch (elem_size) {2752 switch (elem_size) {
2545 else => {2753 else => {
2754 const base_reg = switch (base_mcv) {
2755 .register => |r| r,
2756 else => try self.copyToTmpRegister(slice_ptr_field_type, base_mcv),
2757 };
2758 const base_reg_lock = self.register_manager.lockRegAssumeUnused(base_reg);
2759 defer self.register_manager.unlockReg(base_reg_lock);
2760
2546 const dest = try self.allocRegOrMem(inst, true);2761 const dest = try self.allocRegOrMem(inst, true);
2547 const addr = try self.binOp(.ptr_add, base_mcv, index_mcv, slice_ptr_field_type, Type.usize, null);2762 const addr = try self.binOp(.ptr_add, base_mcv, index_mcv, slice_ptr_field_type, Type.usize, null);
2548 try self.load(dest, addr, slice_ptr_field_type);2763 try self.load(dest, addr, slice_ptr_field_type);
...@@ -2557,7 +2772,16 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2557,7 +2772,16 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
2557fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {2772fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {
2558 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;2773 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
2559 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;2774 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
2560 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement slice_elem_ptr for {}", .{self.target.cpu.arch});2775 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2776 const slice_mcv = try self.resolveInst(extra.lhs);
2777 const index_mcv = try self.resolveInst(extra.rhs);
2778 const base_mcv = slicePtr(slice_mcv);
2779
2780 const slice_ty = self.air.typeOf(extra.lhs);
2781
2782 const addr = try self.binOp(.ptr_add, base_mcv, index_mcv, slice_ty, Type.usize, null);
2783 break :result addr;
2784 };
2561 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });2785 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
2562}2786}
25632787
...@@ -2577,7 +2801,15 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2577,7 +2801,15 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
2577fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {2801fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
2578 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;2802 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
2579 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;2803 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
2580 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement ptr_elem_ptr for {}", .{self.target.cpu.arch});2804 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2805 const ptr_mcv = try self.resolveInst(extra.lhs);
2806 const index_mcv = try self.resolveInst(extra.rhs);
2807
2808 const ptr_ty = self.air.typeOf(extra.lhs);
2809
2810 const addr = try self.binOp(.ptr_add, ptr_mcv, index_mcv, ptr_ty, Type.usize, null);
2811 break :result addr;
2812 };
2581 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });2813 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
2582}2814}
25832815
...@@ -2726,6 +2958,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -2726,6 +2958,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
2726 },2958 },
2727 .memory,2959 .memory,
2728 .stack_offset,2960 .stack_offset,
2961 .stack_argument_offset,
2729 .got_load,2962 .got_load,
2730 .direct_load,2963 .direct_load,
2731 => {2964 => {
...@@ -2907,6 +3140,8 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2907,6 +3140,8 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2907 defer if (addr_reg_lock) |reg| self.register_manager.unlockReg(reg);3140 defer if (addr_reg_lock) |reg| self.register_manager.unlockReg(reg);
29083141
2909 switch (value) {3142 switch (value) {
3143 .dead => unreachable,
3144 .undef => unreachable,
2910 .register => |value_reg| {3145 .register => |value_reg| {
2911 try self.genStrRegister(value_reg, addr_reg, value_ty);3146 try self.genStrRegister(value_reg, addr_reg, value_ty);
2912 },3147 },
...@@ -2920,13 +3155,48 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2920,13 +3155,48 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2920 try self.genSetReg(value_ty, tmp_reg, value);3155 try self.genSetReg(value_ty, tmp_reg, value);
2921 try self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);3156 try self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);
2922 } else {3157 } else {
2923 return self.fail("TODO implement memcpy", .{});3158 const regs = try self.register_manager.allocRegs(4, .{ null, null, null, null }, gp);
3159 const regs_locks = self.register_manager.lockRegsAssumeUnused(4, regs);
3160 defer for (regs_locks) |reg| {
3161 self.register_manager.unlockReg(reg);
3162 };
3163
3164 const src_reg = addr_reg;
3165 const dst_reg = regs[0];
3166 const len_reg = regs[1];
3167 const count_reg = regs[2];
3168 const tmp_reg = regs[3];
3169
3170 switch (value) {
3171 .stack_offset => |off| {
3172 // sub src_reg, fp, #off
3173 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off });
3174 },
3175 .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = @intCast(u32, addr) }),
3176 .stack_argument_offset => |off| {
3177 _ = try self.addInst(.{
3178 .tag = .ldr_ptr_stack_argument,
3179 .data = .{ .load_store_stack = .{
3180 .rt = src_reg,
3181 .offset = off,
3182 } },
3183 });
3184 },
3185 else => return self.fail("TODO store {} to register", .{value}),
3186 }
3187
3188 // mov len, #abi_size
3189 try self.genSetReg(Type.usize, len_reg, .{ .immediate = abi_size });
3190
3191 // memcpy(src, dst, len)
3192 try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg);
2924 }3193 }
2925 },3194 },
2926 }3195 }
2927 },3196 },
2928 .memory,3197 .memory,
2929 .stack_offset,3198 .stack_offset,
3199 .stack_argument_offset,
2930 .got_load,3200 .got_load,
2931 .direct_load,3201 .direct_load,
2932 => {3202 => {
...@@ -3005,10 +3275,14 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -3005,10 +3275,14 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
3005 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {3275 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
3006 const mcv = try self.resolveInst(operand);3276 const mcv = try self.resolveInst(operand);
3007 const struct_ty = self.air.typeOf(operand);3277 const struct_ty = self.air.typeOf(operand);
3278 const struct_field_ty = struct_ty.structFieldType(index);
3008 const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*));3279 const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*));
30093280
3010 switch (mcv) {3281 switch (mcv) {
3011 .dead, .unreach => unreachable,3282 .dead, .unreach => unreachable,
3283 .stack_argument_offset => |off| {
3284 break :result MCValue{ .stack_argument_offset = off + struct_field_offset };
3285 },
3012 .stack_offset => |off| {3286 .stack_offset => |off| {
3013 break :result MCValue{ .stack_offset = off - struct_field_offset };3287 break :result MCValue{ .stack_offset = off - struct_field_offset };
3014 },3288 },
...@@ -3016,29 +3290,28 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -3016,29 +3290,28 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
3016 break :result MCValue{ .memory = addr + struct_field_offset };3290 break :result MCValue{ .memory = addr + struct_field_offset };
3017 },3291 },
3018 .register_with_overflow => |rwo| {3292 .register_with_overflow => |rwo| {
3019 switch (index) {3293 const reg_lock = self.register_manager.lockRegAssumeUnused(rwo.reg);
3020 0 => {3294 defer self.register_manager.unlockReg(reg_lock);
3021 // get wrapped value: return register
3022 break :result MCValue{ .register = rwo.reg };
3023 },
3024 1 => {
3025 // TODO return special MCValue condition flags
3026 // get overflow bit: set register to C flag
3027 // resp. V flag
3028 const raw_dest_reg = try self.register_manager.allocReg(null, gp);
3029 const dest_reg = raw_dest_reg.to32();
30303295
3031 _ = try self.addInst(.{3296 const field: MCValue = switch (index) {
3032 .tag = .cset,3297 // get wrapped value: return register
3033 .data = .{ .r_cond = .{3298 0 => MCValue{ .register = rwo.reg },
3034 .rd = dest_reg,3299
3035 .cond = rwo.flag,3300 // get overflow bit: return C or V flag
3036 } },3301 1 => MCValue{ .condition_flags = rwo.flag },
3037 });
30383302
3039 break :result MCValue{ .register = dest_reg };
3040 },
3041 else => unreachable,3303 else => unreachable,
3304 };
3305
3306 if (self.reuseOperand(inst, operand, 0, field)) {
3307 break :result field;
3308 } else {
3309 // Copy to new register
3310 const raw_dest_reg = try self.register_manager.allocReg(null, gp);
3311 const dest_reg = registerAlias(raw_dest_reg, struct_field_ty.abiSize(self.target.*));
3312 try self.genSetReg(struct_field_ty, dest_reg, field);
3313
3314 break :result MCValue{ .register = dest_reg };
3042 }3315 }
3043 },3316 },
3044 else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}),3317 else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}),
...@@ -3143,6 +3416,31 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -3143,6 +3416,31 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
3143 // saving compare flags may require a new caller-saved register3416 // saving compare flags may require a new caller-saved register
3144 try self.spillCompareFlagsIfOccupied();3417 try self.spillCompareFlagsIfOccupied();
31453418
3419 if (info.return_value == .stack_offset) {
3420 log.debug("airCall: return by reference", .{});
3421 const ret_ty = fn_ty.fnReturnType();
3422 const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*));
3423 const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(self.target.*));
3424 const stack_offset = try self.allocMem(inst, ret_abi_size, ret_abi_align);
3425
3426 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
3427 const ptr_bytes = @divExact(ptr_bits, 8);
3428 const ret_ptr_reg = registerAlias(.x0, ptr_bytes);
3429
3430 var ptr_ty_payload: Type.Payload.ElemType = .{
3431 .base = .{ .tag = .single_mut_pointer },
3432 .data = ret_ty,
3433 };
3434 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
3435 try self.register_manager.getReg(ret_ptr_reg, null);
3436 try self.genSetReg(ptr_ty, ret_ptr_reg, .{ .ptr_stack_offset = stack_offset });
3437
3438 info.return_value = .{ .stack_offset = stack_offset };
3439 }
3440
3441 // Make space for the arguments passed via the stack
3442 self.max_end_stack += info.stack_byte_count;
3443
3146 for (info.args) |mc_arg, arg_i| {3444 for (info.args) |mc_arg, arg_i| {
3147 const arg = args[arg_i];3445 const arg = args[arg_i];
3148 const arg_ty = self.air.typeOf(arg);3446 const arg_ty = self.air.typeOf(arg);
...@@ -3154,12 +3452,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -3154,12 +3452,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
3154 try self.register_manager.getReg(reg, null);3452 try self.register_manager.getReg(reg, null);
3155 try self.genSetReg(arg_ty, reg, arg_mcv);3453 try self.genSetReg(arg_ty, reg, arg_mcv);
3156 },3454 },
3157 .stack_offset => {3455 .stack_offset => unreachable,
3158 return self.fail("TODO implement calling with parameters in memory", .{});3456 .stack_argument_offset => |offset| try self.genSetStackArgument(
3159 },3457 arg_ty,
3160 .ptr_stack_offset => {3458 offset,
3161 return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});3459 arg_mcv,
3162 },3460 ),
3163 else => unreachable,3461 else => unreachable,
3164 }3462 }
3165 }3463 }
...@@ -3303,8 +3601,15 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {...@@ -3303,8 +3601,15 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {
3303 },3601 },
3304 .stack_offset => {3602 .stack_offset => {
3305 // Return result by reference3603 // Return result by reference
3306 // TODO3604 //
3307 return self.fail("TODO implement airRet for {}", .{self.ret_mcv});3605 // self.ret_mcv is an address to where this function
3606 // should store its result into
3607 var ptr_ty_payload: Type.Payload.ElemType = .{
3608 .base = .{ .tag = .single_mut_pointer },
3609 .data = ret_ty,
3610 };
3611 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
3612 try self.store(self.ret_mcv, operand, ptr_ty, ret_ty);
3308 },3613 },
3309 else => unreachable,3614 else => unreachable,
3310 }3615 }
...@@ -3330,10 +3635,34 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -3330,10 +3635,34 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
3330 },3635 },
3331 .stack_offset => {3636 .stack_offset => {
3332 // Return result by reference3637 // Return result by reference
3333 // TODO3638 //
3334 return self.fail("TODO implement airRetLoad for {}", .{self.ret_mcv});3639 // self.ret_mcv is an address to where this function
3640 // should store its result into
3641 //
3642 // If the operand is a ret_ptr instruction, we are done
3643 // here. Else we need to load the result from the location
3644 // pointed to by the operand and store it to the result
3645 // location.
3646 const op_inst = Air.refToIndex(un_op).?;
3647 if (self.air.instructions.items(.tag)[op_inst] != .ret_ptr) {
3648 const abi_size = @intCast(u32, ret_ty.abiSize(self.target.*));
3649 const abi_align = ret_ty.abiAlignment(self.target.*);
3650
3651 // This is essentially allocMem without the
3652 // instruction tracking
3653 if (abi_align > self.stack_align)
3654 self.stack_align = abi_align;
3655 // TODO find a free slot instead of always appending
3656 const offset = mem.alignForwardGeneric(u32, self.next_stack_offset, abi_align) + abi_size;
3657 self.next_stack_offset = offset;
3658 self.max_end_stack = @maximum(self.max_end_stack, self.next_stack_offset);
3659
3660 const tmp_mcv = MCValue{ .stack_offset = offset };
3661 try self.load(tmp_mcv, ptr, ptr_ty);
3662 try self.store(self.ret_mcv, tmp_mcv, ptr_ty, ret_ty);
3663 }
3335 },3664 },
3336 else => unreachable,3665 else => unreachable, // invalid return result
3337 }3666 }
33383667
3339 try self.exitlude_jump_relocs.append(self.gpa, try self.addNop());3668 try self.exitlude_jump_relocs.append(self.gpa, try self.addNop());
...@@ -3635,40 +3964,14 @@ fn isNonNull(self: *Self, operand: MCValue) !MCValue {...@@ -3635,40 +3964,14 @@ fn isNonNull(self: *Self, operand: MCValue) !MCValue {
36353964
3636fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {3965fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
3637 const error_type = ty.errorUnionSet();3966 const error_type = ty.errorUnionSet();
3638 const payload_type = ty.errorUnionPayload();3967 const error_int_type = Type.initTag(.u16);
36393968
3640 if (error_type.errorSetIsEmpty()) {3969 if (error_type.errorSetIsEmpty()) {
3641 return MCValue{ .immediate = 0 }; // always false3970 return MCValue{ .immediate = 0 }; // always false
3642 }3971 }
36433972
3644 const err_off = errUnionErrorOffset(payload_type, self.target.*);3973 const error_mcv = try self.errUnionErr(operand, ty);
3645 switch (operand) {3974 _ = try self.binOp(.cmp_eq, error_mcv, .{ .immediate = 0 }, error_int_type, error_int_type, null);
3646 .stack_offset => |off| {
3647 const offset = off - @intCast(u32, err_off);
3648 const tmp_reg = try self.copyToTmpRegister(Type.anyerror, .{ .stack_offset = offset });
3649 _ = try self.addInst(.{
3650 .tag = .cmp_immediate,
3651 .data = .{ .r_imm12_sh = .{
3652 .rn = tmp_reg,
3653 .imm12 = 0,
3654 } },
3655 });
3656 },
3657 .register => |reg| {
3658 if (err_off > 0 or payload_type.hasRuntimeBitsIgnoreComptime()) {
3659 return self.fail("TODO implement isErr for register operand with payload bits", .{});
3660 }
3661 _ = try self.addInst(.{
3662 .tag = .cmp_immediate,
3663 .data = .{ .r_imm12_sh = .{
3664 .rn = reg,
3665 .imm12 = 0,
3666 } },
3667 });
3668 },
3669 else => return self.fail("TODO implement isErr for {}", .{operand}),
3670 }
3671
3672 return MCValue{ .condition_flags = .hi };3975 return MCValue{ .condition_flags = .hi };
3673}3976}
36743977
...@@ -3886,7 +4189,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {...@@ -3886,7 +4189,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
3886 block_data.mcv = switch (operand_mcv) {4189 block_data.mcv = switch (operand_mcv) {
3887 .none, .dead, .unreach => unreachable,4190 .none, .dead, .unreach => unreachable,
3888 .register, .stack_offset, .memory => operand_mcv,4191 .register, .stack_offset, .memory => operand_mcv,
3889 .immediate, .condition_flags => blk: {4192 .immediate, .stack_argument_offset, .condition_flags => blk: {
3890 const new_mcv = try self.allocRegOrMem(block, true);4193 const new_mcv = try self.allocRegOrMem(block, true);
3891 try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv);4194 try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv);
3892 break :blk new_mcv;4195 break :blk new_mcv;
...@@ -4128,6 +4431,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -4128,6 +4431,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
4128 .got_load,4431 .got_load,
4129 .direct_load,4432 .direct_load,
4130 .memory,4433 .memory,
4434 .stack_argument_offset,
4131 .stack_offset,4435 .stack_offset,
4132 => {4436 => {
4133 switch (mcv) {4437 switch (mcv) {
...@@ -4166,6 +4470,15 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -4166,6 +4470,15 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
4166 // sub src_reg, fp, #off4470 // sub src_reg, fp, #off
4167 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off });4471 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off });
4168 },4472 },
4473 .stack_argument_offset => |off| {
4474 _ = try self.addInst(.{
4475 .tag = .ldr_ptr_stack_argument,
4476 .data = .{ .load_store_stack = .{
4477 .rt = src_reg,
4478 .offset = off,
4479 } },
4480 });
4481 },
4169 .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = addr }),4482 .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = addr }),
4170 .got_load,4483 .got_load,
4171 .direct_load,4484 .direct_load,
...@@ -4269,6 +4582,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -4269,6 +4582,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
4269 }4582 }
4270 },4583 },
4271 .register => |src_reg| {4584 .register => |src_reg| {
4585 assert(src_reg.size() == reg.size());
4586
4272 // If the registers are the same, nothing to do.4587 // If the registers are the same, nothing to do.
4273 if (src_reg.id() == reg.id())4588 if (src_reg.id() == reg.id())
4274 return;4589 return;
...@@ -4330,6 +4645,196 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -4330,6 +4645,196 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
4330 else => unreachable,4645 else => unreachable,
4331 }4646 }
4332 },4647 },
4648 .stack_argument_offset => |off| {
4649 const abi_size = ty.abiSize(self.target.*);
4650
4651 switch (abi_size) {
4652 1, 2, 4, 8 => {
4653 const tag: Mir.Inst.Tag = switch (abi_size) {
4654 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb_stack_argument else .ldrb_stack_argument,
4655 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh_stack_argument else .ldrh_stack_argument,
4656 4, 8 => .ldr_stack_argument,
4657 else => unreachable, // unexpected abi size
4658 };
4659
4660 _ = try self.addInst(.{
4661 .tag = tag,
4662 .data = .{ .load_store_stack = .{
4663 .rt = reg,
4664 .offset = @intCast(u32, off),
4665 } },
4666 });
4667 },
4668 3, 5, 6, 7 => return self.fail("TODO implement genSetReg types size {}", .{abi_size}),
4669 else => unreachable,
4670 }
4671 },
4672 }
4673}
4674
4675fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void {
4676 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
4677 switch (mcv) {
4678 .dead => unreachable,
4679 .none, .unreach => return,
4680 .undef => {
4681 if (!self.wantSafety())
4682 return; // The already existing value will do just fine.
4683 // TODO Upgrade this to a memset call when we have that available.
4684 switch (ty.abiSize(self.target.*)) {
4685 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }),
4686 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }),
4687 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }),
4688 8 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa }),
4689 else => return self.fail("TODO implement memset", .{}),
4690 }
4691 },
4692 .register => |reg| {
4693 switch (abi_size) {
4694 1, 2, 4, 8 => {
4695 const tag: Mir.Inst.Tag = switch (abi_size) {
4696 1 => .strb_immediate,
4697 2 => .strh_immediate,
4698 4, 8 => .str_immediate,
4699 else => unreachable, // unexpected abi size
4700 };
4701 const rt = registerAlias(reg, abi_size);
4702 const offset = switch (abi_size) {
4703 1 => blk: {
4704 if (math.cast(u12, stack_offset)) |imm| {
4705 break :blk Instruction.LoadStoreOffset.imm(imm);
4706 } else {
4707 return self.fail("TODO genSetStackArgument byte with larger offset", .{});
4708 }
4709 },
4710 2 => blk: {
4711 assert(std.mem.isAlignedGeneric(u32, stack_offset, 2)); // misaligned stack entry
4712 if (math.cast(u12, @divExact(stack_offset, 2))) |imm| {
4713 break :blk Instruction.LoadStoreOffset.imm(imm);
4714 } else {
4715 return self.fail("TODO getSetStackArgument halfword with larger offset", .{});
4716 }
4717 },
4718 4, 8 => blk: {
4719 const alignment = abi_size;
4720 assert(std.mem.isAlignedGeneric(u32, stack_offset, alignment)); // misaligned stack entry
4721 if (math.cast(u12, @divExact(stack_offset, alignment))) |imm| {
4722 break :blk Instruction.LoadStoreOffset.imm(imm);
4723 } else {
4724 return self.fail("TODO genSetStackArgument with larger offset", .{});
4725 }
4726 },
4727 else => unreachable,
4728 };
4729
4730 _ = try self.addInst(.{
4731 .tag = tag,
4732 .data = .{ .load_store_register_immediate = .{
4733 .rt = rt,
4734 .rn = .sp,
4735 .offset = offset.immediate,
4736 } },
4737 });
4738 },
4739 else => return self.fail("TODO genSetStackArgument other types abi_size={}", .{abi_size}),
4740 }
4741 },
4742 .register_with_overflow => {
4743 return self.fail("TODO implement genSetStackArgument {}", .{mcv});
4744 },
4745 .got_load,
4746 .direct_load,
4747 .memory,
4748 .stack_argument_offset,
4749 .stack_offset,
4750 => {
4751 if (abi_size <= 4) {
4752 const reg = try self.copyToTmpRegister(ty, mcv);
4753 return self.genSetStackArgument(ty, stack_offset, MCValue{ .register = reg });
4754 } else {
4755 var ptr_ty_payload: Type.Payload.ElemType = .{
4756 .base = .{ .tag = .single_mut_pointer },
4757 .data = ty,
4758 };
4759 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
4760
4761 // TODO call extern memcpy
4762 const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null }, gp);
4763 const regs_locks = self.register_manager.lockRegsAssumeUnused(5, regs);
4764 defer for (regs_locks) |reg| {
4765 self.register_manager.unlockReg(reg);
4766 };
4767
4768 const src_reg = regs[0];
4769 const dst_reg = regs[1];
4770 const len_reg = regs[2];
4771 const count_reg = regs[3];
4772 const tmp_reg = regs[4];
4773
4774 switch (mcv) {
4775 .stack_offset => |off| {
4776 // sub src_reg, fp, #off
4777 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off });
4778 },
4779 .stack_argument_offset => |off| {
4780 _ = try self.addInst(.{
4781 .tag = .ldr_ptr_stack_argument,
4782 .data = .{ .load_store_stack = .{
4783 .rt = src_reg,
4784 .offset = off,
4785 } },
4786 });
4787 },
4788 .memory => |addr| try self.genSetReg(ptr_ty, src_reg, .{ .immediate = @intCast(u32, addr) }),
4789 .got_load,
4790 .direct_load,
4791 => |sym_index| {
4792 const tag: Mir.Inst.Tag = switch (mcv) {
4793 .got_load => .load_memory_ptr_got,
4794 .direct_load => .load_memory_ptr_direct,
4795 else => unreachable,
4796 };
4797 const mod = self.bin_file.options.module.?;
4798 _ = try self.addInst(.{
4799 .tag = tag,
4800 .data = .{
4801 .payload = try self.addExtra(Mir.LoadMemoryPie{
4802 .register = @enumToInt(src_reg),
4803 .atom_index = mod.declPtr(self.mod_fn.owner_decl).link.macho.sym_index,
4804 .sym_index = sym_index,
4805 }),
4806 },
4807 });
4808 },
4809 else => unreachable,
4810 }
4811
4812 // add dst_reg, sp, #stack_offset
4813 _ = try self.addInst(.{
4814 .tag = .add_immediate,
4815 .data = .{ .rr_imm12_sh = .{
4816 .rd = dst_reg,
4817 .rn = .sp,
4818 .imm12 = math.cast(u12, stack_offset) orelse {
4819 return self.fail("TODO load: set reg to stack offset with all possible offsets", .{});
4820 },
4821 } },
4822 });
4823
4824 // mov len, #abi_size
4825 try self.genSetReg(Type.usize, len_reg, .{ .immediate = abi_size });
4826
4827 // memcpy(src, dst, len)
4828 try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg);
4829 }
4830 },
4831 .condition_flags,
4832 .immediate,
4833 .ptr_stack_offset,
4834 => {
4835 const reg = try self.copyToTmpRegister(ty, mcv);
4836 return self.genSetStackArgument(ty, stack_offset, MCValue{ .register = reg });
4837 },
4333 }4838 }
4334}4839}
43354840
...@@ -4799,11 +5304,27 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -4799,11 +5304,27 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
4799 result.stack_align = 1;5304 result.stack_align = 1;
4800 return result;5305 return result;
4801 },5306 },
4802 .Unspecified, .C => {5307 .C => {
4803 // ARM64 Procedure Call Standard5308 // ARM64 Procedure Call Standard
4804 var ncrn: usize = 0; // Next Core Register Number5309 var ncrn: usize = 0; // Next Core Register Number
4805 var nsaa: u32 = 0; // Next stacked argument address5310 var nsaa: u32 = 0; // Next stacked argument address
48065311
5312 if (ret_ty.zigTypeTag() == .NoReturn) {
5313 result.return_value = .{ .unreach = {} };
5314 } else if (!ret_ty.hasRuntimeBitsIgnoreComptime() and !ret_ty.isError()) {
5315 result.return_value = .{ .none = {} };
5316 } else {
5317 const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*));
5318 if (ret_ty_size == 0) {
5319 assert(ret_ty.isError());
5320 result.return_value = .{ .immediate = 0 };
5321 } else if (ret_ty_size <= 8) {
5322 result.return_value = .{ .register = registerAlias(c_abi_int_return_regs[0], ret_ty_size) };
5323 } else {
5324 return self.fail("TODO support more return types for ARM backend", .{});
5325 }
5326 }
5327
4807 for (param_types) |ty, i| {5328 for (param_types) |ty, i| {
4808 const param_size = @intCast(u32, ty.abiSize(self.target.*));5329 const param_size = @intCast(u32, ty.abiSize(self.target.*));
4809 if (param_size == 0) {5330 if (param_size == 0) {
...@@ -4837,7 +5358,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -4837,7 +5358,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
4837 }5358 }
4838 }5359 }
48395360
4840 result.args[i] = .{ .stack_offset = nsaa };5361 result.args[i] = .{ .stack_argument_offset = nsaa };
4841 nsaa += param_size;5362 nsaa += param_size;
4842 }5363 }
4843 }5364 }
...@@ -4845,28 +5366,49 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -4845,28 +5366,49 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
4845 result.stack_byte_count = nsaa;5366 result.stack_byte_count = nsaa;
4846 result.stack_align = 16;5367 result.stack_align = 16;
4847 },5368 },
4848 else => return self.fail("TODO implement function parameters for {} on aarch64", .{cc}),5369 .Unspecified => {
4849 }5370 if (ret_ty.zigTypeTag() == .NoReturn) {
48505371 result.return_value = .{ .unreach = {} };
4851 if (ret_ty.zigTypeTag() == .NoReturn) {5372 } else if (!ret_ty.hasRuntimeBitsIgnoreComptime() and !ret_ty.isError()) {
4852 result.return_value = .{ .unreach = {} };5373 result.return_value = .{ .none = {} };
4853 } else if (!ret_ty.hasRuntimeBitsIgnoreComptime() and !ret_ty.isError()) {
4854 result.return_value = .{ .none = {} };
4855 } else switch (cc) {
4856 .Naked => unreachable,
4857 .Unspecified, .C => {
4858 const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*));
4859 if (ret_ty_size == 0) {
4860 assert(ret_ty.isError());
4861 result.return_value = .{ .immediate = 0 };
4862 } else if (ret_ty_size <= 8) {
4863 result.return_value = .{ .register = registerAlias(c_abi_int_return_regs[0], ret_ty_size) };
4864 } else {5374 } else {
4865 return self.fail("TODO support more return types for ARM backend", .{});5375 const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*));
5376 if (ret_ty_size == 0) {
5377 assert(ret_ty.isError());
5378 result.return_value = .{ .immediate = 0 };
5379 } else if (ret_ty_size <= 8) {
5380 result.return_value = .{ .register = registerAlias(.x0, ret_ty_size) };
5381 } else {
5382 // The result is returned by reference, not by
5383 // value. This means that x0 (or w0 when pointer
5384 // size is 32 bits) will contain the address of
5385 // where this function should write the result
5386 // into.
5387 result.return_value = .{ .stack_offset = 0 };
5388 }
4866 }5389 }
5390
5391 var stack_offset: u32 = 0;
5392
5393 for (param_types) |ty, i| {
5394 if (ty.abiSize(self.target.*) > 0) {
5395 const param_size = @intCast(u32, ty.abiSize(self.target.*));
5396 const param_alignment = ty.abiAlignment(self.target.*);
5397
5398 stack_offset = std.mem.alignForwardGeneric(u32, stack_offset, param_alignment);
5399 result.args[i] = .{ .stack_argument_offset = stack_offset };
5400 stack_offset += param_size;
5401 } else {
5402 result.args[i] = .{ .none = {} };
5403 }
5404 }
5405
5406 result.stack_byte_count = stack_offset;
5407 result.stack_align = 16;
4867 },5408 },
4868 else => return self.fail("TODO implement function return values for {}", .{cc}),5409 else => return self.fail("TODO implement function parameters for {} on aarch64", .{cc}),
4869 }5410 }
5411
4870 return result;5412 return result;
4871}5413}
48725414
src/arch/aarch64/Emit.zig+111-12
...@@ -27,14 +27,21 @@ code: *std.ArrayList(u8),...@@ -27,14 +27,21 @@ code: *std.ArrayList(u8),
2727
28prev_di_line: u32,28prev_di_line: u32,
29prev_di_column: u32,29prev_di_column: u32,
30
30/// Relative to the beginning of `code`.31/// Relative to the beginning of `code`.
31prev_di_pc: usize,32prev_di_pc: usize,
3233
34/// The amount of stack space consumed by the saved callee-saved
35/// registers in bytes
36saved_regs_stack_space: u32,
37
33/// The branch type of every branch38/// The branch type of every branch
34branch_types: std.AutoHashMapUnmanaged(Mir.Inst.Index, BranchType) = .{},39branch_types: std.AutoHashMapUnmanaged(Mir.Inst.Index, BranchType) = .{},
40
35/// For every forward branch, maps the target instruction to a list of41/// For every forward branch, maps the target instruction to a list of
36/// branches which branch to this target instruction42/// branches which branch to this target instruction
37branch_forward_origins: std.AutoHashMapUnmanaged(Mir.Inst.Index, std.ArrayListUnmanaged(Mir.Inst.Index)) = .{},43branch_forward_origins: std.AutoHashMapUnmanaged(Mir.Inst.Index, std.ArrayListUnmanaged(Mir.Inst.Index)) = .{},
44
38/// For backward branches: stores the code offset of the target45/// For backward branches: stores the code offset of the target
39/// instruction46/// instruction
40///47///
...@@ -42,6 +49,8 @@ branch_forward_origins: std.AutoHashMapUnmanaged(Mir.Inst.Index, std.ArrayListUn...@@ -42,6 +49,8 @@ branch_forward_origins: std.AutoHashMapUnmanaged(Mir.Inst.Index, std.ArrayListUn
42/// instruction49/// instruction
43code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .{},50code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .{},
4451
52/// The final stack frame size of the function (already aligned to the
53/// respective stack alignment). Does not include prologue stack space.
45stack_size: u32,54stack_size: u32,
4655
47const InnerError = error{56const InnerError = error{
...@@ -82,9 +91,11 @@ pub fn emitMir(...@@ -82,9 +91,11 @@ pub fn emitMir(
82 .sub_immediate => try emit.mirAddSubtractImmediate(inst),91 .sub_immediate => try emit.mirAddSubtractImmediate(inst),
83 .subs_immediate => try emit.mirAddSubtractImmediate(inst),92 .subs_immediate => try emit.mirAddSubtractImmediate(inst),
8493
85 .asr_register => try emit.mirShiftRegister(inst),94 .asr_register => try emit.mirDataProcessing2Source(inst),
86 .lsl_register => try emit.mirShiftRegister(inst),95 .lsl_register => try emit.mirDataProcessing2Source(inst),
87 .lsr_register => try emit.mirShiftRegister(inst),96 .lsr_register => try emit.mirDataProcessing2Source(inst),
97 .sdiv => try emit.mirDataProcessing2Source(inst),
98 .udiv => try emit.mirDataProcessing2Source(inst),
8899
89 .asr_immediate => try emit.mirShiftImmediate(inst),100 .asr_immediate => try emit.mirShiftImmediate(inst),
90 .lsl_immediate => try emit.mirShiftImmediate(inst),101 .lsl_immediate => try emit.mirShiftImmediate(inst),
...@@ -148,6 +159,13 @@ pub fn emitMir(...@@ -148,6 +159,13 @@ pub fn emitMir(
148 .strb_stack => try emit.mirLoadStoreStack(inst),159 .strb_stack => try emit.mirLoadStoreStack(inst),
149 .strh_stack => try emit.mirLoadStoreStack(inst),160 .strh_stack => try emit.mirLoadStoreStack(inst),
150161
162 .ldr_stack_argument => try emit.mirLoadStackArgument(inst),
163 .ldr_ptr_stack_argument => try emit.mirLoadStackArgument(inst),
164 .ldrb_stack_argument => try emit.mirLoadStackArgument(inst),
165 .ldrh_stack_argument => try emit.mirLoadStackArgument(inst),
166 .ldrsb_stack_argument => try emit.mirLoadStackArgument(inst),
167 .ldrsh_stack_argument => try emit.mirLoadStackArgument(inst),
168
151 .ldr_register => try emit.mirLoadStoreRegisterRegister(inst),169 .ldr_register => try emit.mirLoadStoreRegisterRegister(inst),
152 .ldrb_register => try emit.mirLoadStoreRegisterRegister(inst),170 .ldrb_register => try emit.mirLoadStoreRegisterRegister(inst),
153 .ldrh_register => try emit.mirLoadStoreRegisterRegister(inst),171 .ldrh_register => try emit.mirLoadStoreRegisterRegister(inst),
...@@ -172,6 +190,7 @@ pub fn emitMir(...@@ -172,6 +190,7 @@ pub fn emitMir(
172 .movk => try emit.mirMoveWideImmediate(inst),190 .movk => try emit.mirMoveWideImmediate(inst),
173 .movz => try emit.mirMoveWideImmediate(inst),191 .movz => try emit.mirMoveWideImmediate(inst),
174192
193 .msub => try emit.mirDataProcessing3Source(inst),
175 .mul => try emit.mirDataProcessing3Source(inst),194 .mul => try emit.mirDataProcessing3Source(inst),
176 .smulh => try emit.mirDataProcessing3Source(inst),195 .smulh => try emit.mirDataProcessing3Source(inst),
177 .smull => try emit.mirDataProcessing3Source(inst),196 .smull => try emit.mirDataProcessing3Source(inst),
...@@ -258,7 +277,7 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize {...@@ -258,7 +277,7 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize {
258 => return 2 * 4,277 => return 2 * 4,
259 .pop_regs, .push_regs => {278 .pop_regs, .push_regs => {
260 const reg_list = emit.mir.instructions.items(.data)[inst].reg_list;279 const reg_list = emit.mir.instructions.items(.data)[inst].reg_list;
261 const number_of_regs = @popCount(u32, reg_list);280 const number_of_regs = @popCount(reg_list);
262 const number_of_insts = std.math.divCeil(u6, number_of_regs, 2) catch unreachable;281 const number_of_insts = std.math.divCeil(u6, number_of_regs, 2) catch unreachable;
263 return number_of_insts * 4;282 return number_of_insts * 4;
264 },283 },
...@@ -504,7 +523,7 @@ fn mirAddSubtractImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -504,7 +523,7 @@ fn mirAddSubtractImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
504 }523 }
505}524}
506525
507fn mirShiftRegister(emit: *Emit, inst: Mir.Inst.Index) !void {526fn mirDataProcessing2Source(emit: *Emit, inst: Mir.Inst.Index) !void {
508 const tag = emit.mir.instructions.items(.tag)[inst];527 const tag = emit.mir.instructions.items(.tag)[inst];
509 const rrr = emit.mir.instructions.items(.data)[inst].rrr;528 const rrr = emit.mir.instructions.items(.data)[inst].rrr;
510 const rd = rrr.rd;529 const rd = rrr.rd;
...@@ -515,6 +534,8 @@ fn mirShiftRegister(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -515,6 +534,8 @@ fn mirShiftRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
515 .asr_register => try emit.writeInstruction(Instruction.asrRegister(rd, rn, rm)),534 .asr_register => try emit.writeInstruction(Instruction.asrRegister(rd, rn, rm)),
516 .lsl_register => try emit.writeInstruction(Instruction.lslRegister(rd, rn, rm)),535 .lsl_register => try emit.writeInstruction(Instruction.lslRegister(rd, rn, rm)),
517 .lsr_register => try emit.writeInstruction(Instruction.lsrRegister(rd, rn, rm)),536 .lsr_register => try emit.writeInstruction(Instruction.lsrRegister(rd, rn, rm)),
537 .sdiv => try emit.writeInstruction(Instruction.sdiv(rd, rn, rm)),
538 .udiv => try emit.writeInstruction(Instruction.udiv(rd, rn, rm)),
518 else => unreachable,539 else => unreachable,
519 }540 }
520}541}
...@@ -920,6 +941,67 @@ fn mirLoadStoreRegisterPair(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -920,6 +941,67 @@ fn mirLoadStoreRegisterPair(emit: *Emit, inst: Mir.Inst.Index) !void {
920 }941 }
921}942}
922943
944fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void {
945 const tag = emit.mir.instructions.items(.tag)[inst];
946 const load_store_stack = emit.mir.instructions.items(.data)[inst].load_store_stack;
947 const rt = load_store_stack.rt;
948
949 const raw_offset = emit.stack_size + emit.saved_regs_stack_space + load_store_stack.offset;
950 switch (tag) {
951 .ldr_ptr_stack_argument => {
952 const offset = if (math.cast(u12, raw_offset)) |imm| imm else {
953 return emit.fail("TODO load stack argument ptr with larger offset", .{});
954 };
955
956 switch (tag) {
957 .ldr_ptr_stack_argument => try emit.writeInstruction(Instruction.add(rt, .sp, offset, false)),
958 else => unreachable,
959 }
960 },
961 .ldrb_stack_argument, .ldrsb_stack_argument => {
962 const offset = if (math.cast(u12, raw_offset)) |imm| Instruction.LoadStoreOffset.imm(imm) else {
963 return emit.fail("TODO load stack argument byte with larger offset", .{});
964 };
965
966 switch (tag) {
967 .ldrb_stack_argument => try emit.writeInstruction(Instruction.ldrb(rt, .sp, offset)),
968 .ldrsb_stack_argument => try emit.writeInstruction(Instruction.ldrsb(rt, .sp, offset)),
969 else => unreachable,
970 }
971 },
972 .ldrh_stack_argument, .ldrsh_stack_argument => {
973 assert(std.mem.isAlignedGeneric(u32, raw_offset, 2)); // misaligned stack entry
974 const offset = if (math.cast(u12, @divExact(raw_offset, 2))) |imm| Instruction.LoadStoreOffset.imm(imm) else {
975 return emit.fail("TODO load stack argument halfword with larger offset", .{});
976 };
977
978 switch (tag) {
979 .ldrh_stack_argument => try emit.writeInstruction(Instruction.ldrh(rt, .sp, offset)),
980 .ldrsh_stack_argument => try emit.writeInstruction(Instruction.ldrsh(rt, .sp, offset)),
981 else => unreachable,
982 }
983 },
984 .ldr_stack_argument => {
985 const alignment: u32 = switch (rt.size()) {
986 32 => 4,
987 64 => 8,
988 else => unreachable,
989 };
990
991 assert(std.mem.isAlignedGeneric(u32, raw_offset, alignment)); // misaligned stack entry
992 const offset = if (math.cast(u12, @divExact(raw_offset, alignment))) |imm| Instruction.LoadStoreOffset.imm(imm) else {
993 return emit.fail("TODO load stack argument with larger offset", .{});
994 };
995
996 switch (tag) {
997 .ldr_stack_argument => try emit.writeInstruction(Instruction.ldr(rt, .sp, offset)),
998 else => unreachable,
999 }
1000 },
1001 else => unreachable,
1002 }
1003}
1004
923fn mirLoadStoreStack(emit: *Emit, inst: Mir.Inst.Index) !void {1005fn mirLoadStoreStack(emit: *Emit, inst: Mir.Inst.Index) !void {
924 const tag = emit.mir.instructions.items(.tag)[inst];1006 const tag = emit.mir.instructions.items(.tag)[inst];
925 const load_store_stack = emit.mir.instructions.items(.data)[inst].load_store_stack;1007 const load_store_stack = emit.mir.instructions.items(.data)[inst].load_store_stack;
...@@ -1059,14 +1141,31 @@ fn mirMoveWideImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -1059,14 +1141,31 @@ fn mirMoveWideImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
10591141
1060fn mirDataProcessing3Source(emit: *Emit, inst: Mir.Inst.Index) !void {1142fn mirDataProcessing3Source(emit: *Emit, inst: Mir.Inst.Index) !void {
1061 const tag = emit.mir.instructions.items(.tag)[inst];1143 const tag = emit.mir.instructions.items(.tag)[inst];
1062 const rrr = emit.mir.instructions.items(.data)[inst].rrr;
10631144
1064 switch (tag) {1145 switch (tag) {
1065 .mul => try emit.writeInstruction(Instruction.mul(rrr.rd, rrr.rn, rrr.rm)),1146 .mul,
1066 .smulh => try emit.writeInstruction(Instruction.smulh(rrr.rd, rrr.rn, rrr.rm)),1147 .smulh,
1067 .smull => try emit.writeInstruction(Instruction.smull(rrr.rd, rrr.rn, rrr.rm)),1148 .smull,
1068 .umulh => try emit.writeInstruction(Instruction.umulh(rrr.rd, rrr.rn, rrr.rm)),1149 .umulh,
1069 .umull => try emit.writeInstruction(Instruction.umull(rrr.rd, rrr.rn, rrr.rm)),1150 .umull,
1151 => {
1152 const rrr = emit.mir.instructions.items(.data)[inst].rrr;
1153 switch (tag) {
1154 .mul => try emit.writeInstruction(Instruction.mul(rrr.rd, rrr.rn, rrr.rm)),
1155 .smulh => try emit.writeInstruction(Instruction.smulh(rrr.rd, rrr.rn, rrr.rm)),
1156 .smull => try emit.writeInstruction(Instruction.smull(rrr.rd, rrr.rn, rrr.rm)),
1157 .umulh => try emit.writeInstruction(Instruction.umulh(rrr.rd, rrr.rn, rrr.rm)),
1158 .umull => try emit.writeInstruction(Instruction.umull(rrr.rd, rrr.rn, rrr.rm)),
1159 else => unreachable,
1160 }
1161 },
1162 .msub => {
1163 const rrrr = emit.mir.instructions.items(.data)[inst].rrrr;
1164 switch (tag) {
1165 .msub => try emit.writeInstruction(Instruction.msub(rrrr.rd, rrrr.rn, rrrr.rm, rrrr.ra)),
1166 else => unreachable,
1167 }
1168 },
1070 else => unreachable,1169 else => unreachable,
1071 }1170 }
1072}1171}
...@@ -1084,7 +1183,7 @@ fn mirPushPopRegs(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -1084,7 +1183,7 @@ fn mirPushPopRegs(emit: *Emit, inst: Mir.Inst.Index) !void {
1084 // sp must be aligned at all times, so we only use stp and ldp1183 // sp must be aligned at all times, so we only use stp and ldp
1085 // instructions for minimal instruction count. However, if we do1184 // instructions for minimal instruction count. However, if we do
1086 // not have an even number of registers, we use str and ldr1185 // not have an even number of registers, we use str and ldr
1087 const number_of_regs = @popCount(u32, reg_list);1186 const number_of_regs = @popCount(reg_list);
10881187
1089 switch (tag) {1188 switch (tag) {
1090 .pop_regs => {1189 .pop_regs => {
src/arch/aarch64/Mir.zig+27
...@@ -92,20 +92,28 @@ pub const Inst = struct {...@@ -92,20 +92,28 @@ pub const Inst = struct {
92 load_memory_ptr_direct,92 load_memory_ptr_direct,
93 /// Load Pair of Registers93 /// Load Pair of Registers
94 ldp,94 ldp,
95 /// Pseudo-instruction: Load pointer to stack argument
96 ldr_ptr_stack_argument,
95 /// Pseudo-instruction: Load from stack97 /// Pseudo-instruction: Load from stack
96 ldr_stack,98 ldr_stack,
99 /// Pseudo-instruction: Load from stack argument
100 ldr_stack_argument,
97 /// Load Register (immediate)101 /// Load Register (immediate)
98 ldr_immediate,102 ldr_immediate,
99 /// Load Register (register)103 /// Load Register (register)
100 ldr_register,104 ldr_register,
101 /// Pseudo-instruction: Load byte from stack105 /// Pseudo-instruction: Load byte from stack
102 ldrb_stack,106 ldrb_stack,
107 /// Pseudo-instruction: Load byte from stack argument
108 ldrb_stack_argument,
103 /// Load Register Byte (immediate)109 /// Load Register Byte (immediate)
104 ldrb_immediate,110 ldrb_immediate,
105 /// Load Register Byte (register)111 /// Load Register Byte (register)
106 ldrb_register,112 ldrb_register,
107 /// Pseudo-instruction: Load halfword from stack113 /// Pseudo-instruction: Load halfword from stack
108 ldrh_stack,114 ldrh_stack,
115 /// Pseudo-instruction: Load halfword from stack argument
116 ldrh_stack_argument,
109 /// Load Register Halfword (immediate)117 /// Load Register Halfword (immediate)
110 ldrh_immediate,118 ldrh_immediate,
111 /// Load Register Halfword (register)119 /// Load Register Halfword (register)
...@@ -114,10 +122,14 @@ pub const Inst = struct {...@@ -114,10 +122,14 @@ pub const Inst = struct {
114 ldrsb_immediate,122 ldrsb_immediate,
115 /// Pseudo-instruction: Load signed byte from stack123 /// Pseudo-instruction: Load signed byte from stack
116 ldrsb_stack,124 ldrsb_stack,
125 /// Pseudo-instruction: Load signed byte from stack argument
126 ldrsb_stack_argument,
117 /// Load Register Signed Halfword (immediate)127 /// Load Register Signed Halfword (immediate)
118 ldrsh_immediate,128 ldrsh_immediate,
119 /// Pseudo-instruction: Load signed halfword from stack129 /// Pseudo-instruction: Load signed halfword from stack
120 ldrsh_stack,130 ldrsh_stack,
131 /// Pseudo-instruction: Load signed halfword from stack argument
132 ldrsh_stack_argument,
121 /// Load Register Signed Word (immediate)133 /// Load Register Signed Word (immediate)
122 ldrsw_immediate,134 ldrsw_immediate,
123 /// Logical Shift Left (immediate)135 /// Logical Shift Left (immediate)
...@@ -136,6 +148,8 @@ pub const Inst = struct {...@@ -136,6 +148,8 @@ pub const Inst = struct {
136 movk,148 movk,
137 /// Move wide with zero149 /// Move wide with zero
138 movz,150 movz,
151 /// Multiply-subtract
152 msub,
139 /// Multiply153 /// Multiply
140 mul,154 mul,
141 /// Bitwise NOT155 /// Bitwise NOT
...@@ -152,6 +166,8 @@ pub const Inst = struct {...@@ -152,6 +166,8 @@ pub const Inst = struct {
152 ret,166 ret,
153 /// Signed bitfield extract167 /// Signed bitfield extract
154 sbfx,168 sbfx,
169 /// Signed divide
170 sdiv,
155 /// Signed multiply high171 /// Signed multiply high
156 smulh,172 smulh,
157 /// Signed multiply long173 /// Signed multiply long
...@@ -200,6 +216,8 @@ pub const Inst = struct {...@@ -200,6 +216,8 @@ pub const Inst = struct {
200 tst_immediate,216 tst_immediate,
201 /// Unsigned bitfield extract217 /// Unsigned bitfield extract
202 ubfx,218 ubfx,
219 /// Unsigned divide
220 udiv,
203 /// Unsigned multiply high221 /// Unsigned multiply high
204 umulh,222 umulh,
205 /// Unsigned multiply long223 /// Unsigned multiply long
...@@ -430,6 +448,15 @@ pub const Inst = struct {...@@ -430,6 +448,15 @@ pub const Inst = struct {
430 rn: Register,448 rn: Register,
431 offset: bits.Instruction.LoadStorePairOffset,449 offset: bits.Instruction.LoadStorePairOffset,
432 },450 },
451 /// Four registers
452 ///
453 /// Used by e.g. msub
454 rrrr: struct {
455 rd: Register,
456 rn: Register,
457 rm: Register,
458 ra: Register,
459 },
433 /// Debug info: line and column460 /// Debug info: line and column
434 ///461 ///
435 /// Used by e.g. dbg_line462 /// Used by e.g. dbg_line
src/arch/aarch64/bits.zig+8
...@@ -1698,6 +1698,14 @@ pub const Instruction = union(enum) {...@@ -1698,6 +1698,14 @@ pub const Instruction = union(enum) {
16981698
1699 // Data processing (2 source)1699 // Data processing (2 source)
17001700
1701 pub fn udiv(rd: Register, rn: Register, rm: Register) Instruction {
1702 return dataProcessing2Source(0b0, 0b000010, rd, rn, rm);
1703 }
1704
1705 pub fn sdiv(rd: Register, rn: Register, rm: Register) Instruction {
1706 return dataProcessing2Source(0b0, 0b000011, rd, rn, rm);
1707 }
1708
1701 pub fn lslv(rd: Register, rn: Register, rm: Register) Instruction {1709 pub fn lslv(rd: Register, rn: Register, rm: Register) Instruction {
1702 return dataProcessing2Source(0b0, 0b001000, rd, rn, rm);1710 return dataProcessing2Source(0b0, 0b001000, rd, rn, rm);
1703 }1711 }
src/arch/arm/CodeGen.zig+168-31
...@@ -247,6 +247,31 @@ const BigTomb = struct {...@@ -247,6 +247,31 @@ const BigTomb = struct {
247 log.debug("%{d} => {}", .{ bt.inst, result });247 log.debug("%{d} => {}", .{ bt.inst, result });
248 const branch = &bt.function.branch_stack.items[bt.function.branch_stack.items.len - 1];248 const branch = &bt.function.branch_stack.items[bt.function.branch_stack.items.len - 1];
249 branch.inst_table.putAssumeCapacityNoClobber(bt.inst, result);249 branch.inst_table.putAssumeCapacityNoClobber(bt.inst, result);
250
251 switch (result) {
252 .register => |reg| {
253 // In some cases (such as bitcast), an operand
254 // may be the same MCValue as the result. If
255 // that operand died and was a register, it
256 // was freed by processDeath. We have to
257 // "re-allocate" the register.
258 if (bt.function.register_manager.isRegFree(reg)) {
259 bt.function.register_manager.getRegAssumeFree(reg, bt.inst);
260 }
261 },
262 .register_c_flag,
263 .register_v_flag,
264 => |reg| {
265 if (bt.function.register_manager.isRegFree(reg)) {
266 bt.function.register_manager.getRegAssumeFree(reg, bt.inst);
267 }
268 bt.function.cpsr_flags_inst = bt.inst;
269 },
270 .cpsr_flags => {
271 bt.function.cpsr_flags_inst = bt.inst;
272 },
273 else => {},
274 }
250 }275 }
251 bt.function.finishAirBookkeeping();276 bt.function.finishAirBookkeeping();
252 }277 }
...@@ -332,7 +357,7 @@ pub fn generate(...@@ -332,7 +357,7 @@ pub fn generate(
332 };357 };
333358
334 for (function.dbg_arg_relocs.items) |reloc| {359 for (function.dbg_arg_relocs.items) |reloc| {
335 try function.genArgDbgInfo(reloc.inst, reloc.index, call_info.stack_byte_count);360 try function.genArgDbgInfo(reloc.inst, reloc.index);
336 }361 }
337362
338 var mir = Mir{363 var mir = Mir{
...@@ -351,7 +376,8 @@ pub fn generate(...@@ -351,7 +376,8 @@ pub fn generate(
351 .prev_di_pc = 0,376 .prev_di_pc = 0,
352 .prev_di_line = module_fn.lbrace_line,377 .prev_di_line = module_fn.lbrace_line,
353 .prev_di_column = module_fn.lbrace_column,378 .prev_di_column = module_fn.lbrace_column,
354 .prologue_stack_space = call_info.stack_byte_count + function.saved_regs_stack_space,379 .stack_size = function.max_end_stack,
380 .saved_regs_stack_space = function.saved_regs_stack_space,
355 };381 };
356 defer emit.deinit();382 defer emit.deinit();
357383
...@@ -464,6 +490,7 @@ fn gen(self: *Self) !void {...@@ -464,6 +490,7 @@ fn gen(self: *Self) !void {
464 const total_stack_size = self.max_end_stack + self.saved_regs_stack_space;490 const total_stack_size = self.max_end_stack + self.saved_regs_stack_space;
465 const aligned_total_stack_end = mem.alignForwardGeneric(u32, total_stack_size, self.stack_align);491 const aligned_total_stack_end = mem.alignForwardGeneric(u32, total_stack_size, self.stack_align);
466 const stack_size = aligned_total_stack_end - self.saved_regs_stack_space;492 const stack_size = aligned_total_stack_end - self.saved_regs_stack_space;
493 self.max_end_stack = stack_size;
467 if (Instruction.Operand.fromU32(stack_size)) |op| {494 if (Instruction.Operand.fromU32(stack_size)) |op| {
468 self.mir_instructions.set(sub_reloc, .{495 self.mir_instructions.set(sub_reloc, .{
469 .tag = .sub,496 .tag = .sub,
...@@ -768,6 +795,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -768,6 +795,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
768 .float_to_int_optimized,795 .float_to_int_optimized,
769 => return self.fail("TODO implement optimized float mode", .{}),796 => return self.fail("TODO implement optimized float mode", .{}),
770797
798 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),
799 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),
800
771 .wasm_memory_size => unreachable,801 .wasm_memory_size => unreachable,
772 .wasm_memory_grow => unreachable,802 .wasm_memory_grow => unreachable,
773 // zig fmt: on803 // zig fmt: on
...@@ -1810,7 +1840,7 @@ fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCV...@@ -1810,7 +1840,7 @@ fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCV
1810 switch (error_union_mcv) {1840 switch (error_union_mcv) {
1811 .register => return self.fail("TODO errUnionErr for registers", .{}),1841 .register => return self.fail("TODO errUnionErr for registers", .{}),
1812 .stack_argument_offset => |off| {1842 .stack_argument_offset => |off| {
1813 return MCValue{ .stack_argument_offset = off - err_offset };1843 return MCValue{ .stack_argument_offset = off + err_offset };
1814 },1844 },
1815 .stack_offset => |off| {1845 .stack_offset => |off| {
1816 return MCValue{ .stack_offset = off - err_offset };1846 return MCValue{ .stack_offset = off - err_offset };
...@@ -1847,7 +1877,7 @@ fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type)...@@ -1847,7 +1877,7 @@ fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type)
1847 switch (error_union_mcv) {1877 switch (error_union_mcv) {
1848 .register => return self.fail("TODO errUnionPayload for registers", .{}),1878 .register => return self.fail("TODO errUnionPayload for registers", .{}),
1849 .stack_argument_offset => |off| {1879 .stack_argument_offset => |off| {
1850 return MCValue{ .stack_argument_offset = off - payload_offset };1880 return MCValue{ .stack_argument_offset = off + payload_offset };
1851 },1881 },
1852 .stack_offset => |off| {1882 .stack_offset => |off| {
1853 return MCValue{ .stack_offset = off - payload_offset };1883 return MCValue{ .stack_offset = off - payload_offset };
...@@ -1981,7 +2011,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {...@@ -1981,7 +2011,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
1981 .dead, .unreach => unreachable,2011 .dead, .unreach => unreachable,
1982 .register => unreachable, // a slice doesn't fit in one register2012 .register => unreachable, // a slice doesn't fit in one register
1983 .stack_argument_offset => |off| {2013 .stack_argument_offset => |off| {
1984 break :result MCValue{ .stack_argument_offset = off - 4 };2014 break :result MCValue{ .stack_argument_offset = off + 4 };
1985 },2015 },
1986 .stack_offset => |off| {2016 .stack_offset => |off| {
1987 break :result MCValue{ .stack_offset = off - 4 };2017 break :result MCValue{ .stack_offset = off - 4 };
...@@ -2257,16 +2287,17 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -2257,16 +2287,17 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
2257 .register_c_flag,2287 .register_c_flag,
2258 .register_v_flag,2288 .register_v_flag,
2259 => unreachable, // cannot hold an address2289 => unreachable, // cannot hold an address
2260 .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }),2290 .immediate => |imm| {
2261 .ptr_stack_offset => |off| try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }),2291 try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm });
2292 },
2293 .ptr_stack_offset => |off| {
2294 try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off });
2295 },
2262 .register => |reg| {2296 .register => |reg| {
2263 const reg_lock = self.register_manager.lockReg(reg);2297 const reg_lock = self.register_manager.lockReg(reg);
2264 defer if (reg_lock) |reg_locked| self.register_manager.unlockReg(reg_locked);2298 defer if (reg_lock) |reg_locked| self.register_manager.unlockReg(reg_locked);
22652299
2266 switch (dst_mcv) {2300 switch (dst_mcv) {
2267 .dead => unreachable,
2268 .undef => unreachable,
2269 .cpsr_flags => unreachable,
2270 .register => |dst_reg| {2301 .register => |dst_reg| {
2271 try self.genLdrRegister(dst_reg, reg, elem_ty);2302 try self.genLdrRegister(dst_reg, reg, elem_ty);
2272 },2303 },
...@@ -2302,7 +2333,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -2302,7 +2333,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
2302 try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg);2333 try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg);
2303 }2334 }
2304 },2335 },
2305 else => return self.fail("TODO load from register into {}", .{dst_mcv}),2336 else => unreachable, // attempting to load into non-register or non-stack MCValue
2306 }2337 }
2307 },2338 },
2308 .memory,2339 .memory,
...@@ -2399,7 +2430,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2399,7 +2430,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2399 // sub src_reg, fp, #off2430 // sub src_reg, fp, #off
2400 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off });2431 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off });
2401 },2432 },
2402 .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = @intCast(u32, addr) }),2433 .memory => |addr| try self.genSetReg(ptr_ty, src_reg, .{ .immediate = @intCast(u32, addr) }),
2403 .stack_argument_offset => |off| {2434 .stack_argument_offset => |off| {
2404 _ = try self.addInst(.{2435 _ = try self.addInst(.{
2405 .tag = .ldr_ptr_stack_argument,2436 .tag = .ldr_ptr_stack_argument,
...@@ -2505,7 +2536,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2505,7 +2536,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
2505 switch (mcv) {2536 switch (mcv) {
2506 .dead, .unreach => unreachable,2537 .dead, .unreach => unreachable,
2507 .stack_argument_offset => |off| {2538 .stack_argument_offset => |off| {
2508 break :result MCValue{ .stack_argument_offset = off - struct_field_offset };2539 break :result MCValue{ .stack_argument_offset = off + struct_field_offset };
2509 },2540 },
2510 .stack_offset => |off| {2541 .stack_offset => |off| {
2511 break :result MCValue{ .stack_offset = off - struct_field_offset };2542 break :result MCValue{ .stack_offset = off - struct_field_offset };
...@@ -3345,6 +3376,102 @@ fn genInlineMemcpy(...@@ -3345,6 +3376,102 @@ fn genInlineMemcpy(
3345 // end:3376 // end:
3346}3377}
33473378
3379fn genInlineMemset(
3380 self: *Self,
3381 dst: MCValue,
3382 val: MCValue,
3383 len: MCValue,
3384) !void {
3385 const dst_reg = switch (dst) {
3386 .register => |r| r,
3387 else => try self.copyToTmpRegister(Type.initTag(.manyptr_u8), dst),
3388 };
3389 const dst_reg_lock = self.register_manager.lockReg(dst_reg);
3390 defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock);
3391
3392 const val_reg = switch (val) {
3393 .register => |r| r,
3394 else => try self.copyToTmpRegister(Type.initTag(.u8), val),
3395 };
3396 const val_reg_lock = self.register_manager.lockReg(val_reg);
3397 defer if (val_reg_lock) |lock| self.register_manager.unlockReg(lock);
3398
3399 const len_reg = switch (len) {
3400 .register => |r| r,
3401 else => try self.copyToTmpRegister(Type.usize, len),
3402 };
3403 const len_reg_lock = self.register_manager.lockReg(len_reg);
3404 defer if (len_reg_lock) |lock| self.register_manager.unlockReg(lock);
3405
3406 const count_reg = try self.register_manager.allocReg(null, gp);
3407
3408 try self.genInlineMemsetCode(dst_reg, val_reg, len_reg, count_reg);
3409}
3410
3411fn genInlineMemsetCode(
3412 self: *Self,
3413 dst: Register,
3414 val: Register,
3415 len: Register,
3416 count: Register,
3417) !void {
3418 // mov count, #0
3419 _ = try self.addInst(.{
3420 .tag = .mov,
3421 .data = .{ .rr_op = .{
3422 .rd = count,
3423 .rn = .r0,
3424 .op = Instruction.Operand.imm(0, 0),
3425 } },
3426 });
3427
3428 // loop:
3429 // cmp count, len
3430 _ = try self.addInst(.{
3431 .tag = .cmp,
3432 .data = .{ .rr_op = .{
3433 .rd = .r0,
3434 .rn = count,
3435 .op = Instruction.Operand.reg(len, Instruction.Operand.Shift.none),
3436 } },
3437 });
3438
3439 // bge end
3440 _ = try self.addInst(.{
3441 .tag = .b,
3442 .cond = .ge,
3443 .data = .{ .inst = @intCast(u32, self.mir_instructions.len + 4) },
3444 });
3445
3446 // strb val, [src, count]
3447 _ = try self.addInst(.{
3448 .tag = .strb,
3449 .data = .{ .rr_offset = .{
3450 .rt = val,
3451 .rn = dst,
3452 .offset = .{ .offset = Instruction.Offset.reg(count, .none) },
3453 } },
3454 });
3455
3456 // add count, count, #1
3457 _ = try self.addInst(.{
3458 .tag = .add,
3459 .data = .{ .rr_op = .{
3460 .rd = count,
3461 .rn = count,
3462 .op = Instruction.Operand.imm(1, 0),
3463 } },
3464 });
3465
3466 // b loop
3467 _ = try self.addInst(.{
3468 .tag = .b,
3469 .data = .{ .inst = @intCast(u32, self.mir_instructions.len - 4) },
3470 });
3471
3472 // end:
3473}
3474
3348/// Adds a Type to the .debug_info at the current position. The bytes will be populated later,3475/// Adds a Type to the .debug_info at the current position. The bytes will be populated later,
3349/// after codegen for this symbol is done.3476/// after codegen for this symbol is done.
3350fn addDbgInfoTypeReloc(self: *Self, ty: Type) error{OutOfMemory}!void {3477fn addDbgInfoTypeReloc(self: *Self, ty: Type) error{OutOfMemory}!void {
...@@ -3367,12 +3494,10 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) error{OutOfMemory}!void {...@@ -3367,12 +3494,10 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) error{OutOfMemory}!void {
3367 }3494 }
3368}3495}
33693496
3370fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, arg_index: u32, stack_byte_count: u32) error{OutOfMemory}!void {3497fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, arg_index: u32) error{OutOfMemory}!void {
3371 const prologue_stack_space = stack_byte_count + self.saved_regs_stack_space;
3372
3373 const mcv = self.args[arg_index];3498 const mcv = self.args[arg_index];
3374 const ty = self.air.instructions.items(.data)[inst].ty;3499 const ty = self.air.instructions.items(.data)[inst].ty;
3375 const name = self.mod_fn.getParamName(arg_index);3500 const name = self.mod_fn.getParamName(self.bin_file.options.module.?, arg_index);
3376 const name_with_null = name.ptr[0 .. name.len + 1];3501 const name_with_null = name.ptr[0 .. name.len + 1];
33773502
3378 switch (mcv) {3503 switch (mcv) {
...@@ -3402,7 +3527,7 @@ fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, arg_index: u32, stack_byte_c...@@ -3402,7 +3527,7 @@ fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, arg_index: u32, stack_byte_c
3402 // const abi_size = @intCast(u32, ty.abiSize(self.target.*));3527 // const abi_size = @intCast(u32, ty.abiSize(self.target.*));
3403 const adjusted_stack_offset = switch (mcv) {3528 const adjusted_stack_offset = switch (mcv) {
3404 .stack_offset => |offset| -@intCast(i32, offset),3529 .stack_offset => |offset| -@intCast(i32, offset),
3405 .stack_argument_offset => |offset| @intCast(i32, prologue_stack_space - offset),3530 .stack_argument_offset => |offset| @intCast(i32, self.saved_regs_stack_space + offset),
3406 else => unreachable,3531 else => unreachable,
3407 };3532 };
34083533
...@@ -3522,7 +3647,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -3522,7 +3647,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
3522 try self.register_manager.getReg(reg, null);3647 try self.register_manager.getReg(reg, null);
3523 }3648 }
35243649
3525 if (info.return_value == .stack_offset) {3650 // If returning by reference, r0 will contain the address of where
3651 // to put the result into. In that case, make sure that r0 remains
3652 // untouched by the parameter passing code
3653 const r0_lock: ?RegisterLock = if (info.return_value == .stack_offset) blk: {
3526 log.debug("airCall: return by reference", .{});3654 log.debug("airCall: return by reference", .{});
3527 const ret_ty = fn_ty.fnReturnType();3655 const ret_ty = fn_ty.fnReturnType();
3528 const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*));3656 const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*));
...@@ -3538,7 +3666,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -3538,7 +3666,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
3538 try self.genSetReg(ptr_ty, .r0, .{ .ptr_stack_offset = stack_offset });3666 try self.genSetReg(ptr_ty, .r0, .{ .ptr_stack_offset = stack_offset });
35393667
3540 info.return_value = .{ .stack_offset = stack_offset };3668 info.return_value = .{ .stack_offset = stack_offset };
3541 }3669
3670 break :blk self.register_manager.lockRegAssumeUnused(.r0);
3671 } else null;
3672 defer if (r0_lock) |reg| self.register_manager.unlockReg(reg);
35423673
3543 // Make space for the arguments passed via the stack3674 // Make space for the arguments passed via the stack
3544 self.max_end_stack += info.stack_byte_count;3675 self.max_end_stack += info.stack_byte_count;
...@@ -3557,7 +3688,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -3557,7 +3688,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
3557 .stack_offset => unreachable,3688 .stack_offset => unreachable,
3558 .stack_argument_offset => |offset| try self.genSetStackArgument(3689 .stack_argument_offset => |offset| try self.genSetStackArgument(
3559 arg_ty,3690 arg_ty,
3560 info.stack_byte_count - offset,3691 offset,
3561 arg_mcv,3692 arg_mcv,
3562 ),3693 ),
3563 else => unreachable,3694 else => unreachable,
...@@ -4619,11 +4750,15 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -4619,11 +4750,15 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
4619 if (!self.wantSafety())4750 if (!self.wantSafety())
4620 return; // The already existing value will do just fine.4751 return; // The already existing value will do just fine.
4621 // TODO Upgrade this to a memset call when we have that available.4752 // TODO Upgrade this to a memset call when we have that available.
4622 switch (ty.abiSize(self.target.*)) {4753 switch (abi_size) {
4623 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }),4754 1 => try self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }),
4624 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }),4755 2 => try self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }),
4625 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }),4756 4 => try self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }),
4626 else => return self.fail("TODO implement memset", .{}),4757 else => try self.genInlineMemset(
4758 .{ .ptr_stack_offset = stack_offset },
4759 .{ .immediate = 0xaa },
4760 .{ .immediate = abi_size },
4761 ),
4627 }4762 }
4628 },4763 },
4629 .cpsr_flags,4764 .cpsr_flags,
...@@ -5035,9 +5170,9 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I...@@ -5035,9 +5170,9 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
5035 return; // The already existing value will do just fine.5170 return; // The already existing value will do just fine.
5036 // TODO Upgrade this to a memset call when we have that available.5171 // TODO Upgrade this to a memset call when we have that available.
5037 switch (abi_size) {5172 switch (abi_size) {
5038 1 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaa }),5173 1 => try self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaa }),
5039 2 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaa }),5174 2 => try self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaa }),
5040 4 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }),5175 4 => try self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }),
5041 else => return self.fail("TODO implement memset", .{}),5176 else => return self.fail("TODO implement memset", .{}),
5042 }5177 }
5043 },5178 },
...@@ -5651,8 +5786,8 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -5651,8 +5786,8 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
5651 if (ty.abiAlignment(self.target.*) == 8)5786 if (ty.abiAlignment(self.target.*) == 8)
5652 nsaa = std.mem.alignForwardGeneric(u32, nsaa, 8);5787 nsaa = std.mem.alignForwardGeneric(u32, nsaa, 8);
56535788
5654 nsaa += param_size;
5655 result.args[i] = .{ .stack_argument_offset = nsaa };5789 result.args[i] = .{ .stack_argument_offset = nsaa };
5790 nsaa += param_size;
5656 }5791 }
5657 }5792 }
56585793
...@@ -5685,9 +5820,11 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -5685,9 +5820,11 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
5685 for (param_types) |ty, i| {5820 for (param_types) |ty, i| {
5686 if (ty.abiSize(self.target.*) > 0) {5821 if (ty.abiSize(self.target.*) > 0) {
5687 const param_size = @intCast(u32, ty.abiSize(self.target.*));5822 const param_size = @intCast(u32, ty.abiSize(self.target.*));
5823 const param_alignment = ty.abiAlignment(self.target.*);
56885824
5689 stack_offset = std.mem.alignForwardGeneric(u32, stack_offset, ty.abiAlignment(self.target.*)) + param_size;5825 stack_offset = std.mem.alignForwardGeneric(u32, stack_offset, param_alignment);
5690 result.args[i] = .{ .stack_argument_offset = stack_offset };5826 result.args[i] = .{ .stack_argument_offset = stack_offset };
5827 stack_offset += param_size;
5691 } else {5828 } else {
5692 result.args[i] = .{ .none = {} };5829 result.args[i] = .{ .none = {} };
5693 }5830 }
src/arch/arm/Emit.zig+19-38
...@@ -33,9 +33,13 @@ prev_di_column: u32,...@@ -33,9 +33,13 @@ prev_di_column: u32,
33/// Relative to the beginning of `code`.33/// Relative to the beginning of `code`.
34prev_di_pc: usize,34prev_di_pc: usize,
3535
36/// The amount of stack space consumed by all stack arguments as well36/// The amount of stack space consumed by the saved callee-saved
37/// as the saved callee-saved registers37/// registers in bytes
38prologue_stack_space: u32,38saved_regs_stack_space: u32,
39
40/// The final stack frame size of the function (already aligned to the
41/// respective stack alignment). Does not include prologue stack space.
42stack_size: u32,
3943
40/// The branch type of every branch44/// The branch type of every branch
41branch_types: std.AutoHashMapUnmanaged(Mir.Inst.Index, BranchType) = .{},45branch_types: std.AutoHashMapUnmanaged(Mir.Inst.Index, BranchType) = .{},
...@@ -500,14 +504,15 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -500,14 +504,15 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void {
500 const tag = emit.mir.instructions.items(.tag)[inst];504 const tag = emit.mir.instructions.items(.tag)[inst];
501 const cond = emit.mir.instructions.items(.cond)[inst];505 const cond = emit.mir.instructions.items(.cond)[inst];
502 const r_stack_offset = emit.mir.instructions.items(.data)[inst].r_stack_offset;506 const r_stack_offset = emit.mir.instructions.items(.data)[inst].r_stack_offset;
507 const rt = r_stack_offset.rt;
503508
504 const raw_offset = emit.prologue_stack_space - r_stack_offset.stack_offset;509 const raw_offset = emit.stack_size + emit.saved_regs_stack_space + r_stack_offset.stack_offset;
505 switch (tag) {510 switch (tag) {
506 .ldr_ptr_stack_argument => {511 .ldr_ptr_stack_argument => {
507 const operand = Instruction.Operand.fromU32(raw_offset) orelse512 const operand = Instruction.Operand.fromU32(raw_offset) orelse
508 return emit.fail("TODO mirLoadStack larger offsets", .{});513 return emit.fail("TODO mirLoadStack larger offsets", .{});
509514
510 try emit.writeInstruction(Instruction.add(cond, r_stack_offset.rt, .fp, operand));515 try emit.writeInstruction(Instruction.add(cond, rt, .sp, operand));
511 },516 },
512 .ldr_stack_argument,517 .ldr_stack_argument,
513 .ldrb_stack_argument,518 .ldrb_stack_argument,
...@@ -516,23 +521,11 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -516,23 +521,11 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void {
516 break :blk Instruction.Offset.imm(@intCast(u12, raw_offset));521 break :blk Instruction.Offset.imm(@intCast(u12, raw_offset));
517 } else return emit.fail("TODO mirLoadStack larger offsets", .{});522 } else return emit.fail("TODO mirLoadStack larger offsets", .{});
518523
519 const ldr = switch (tag) {524 switch (tag) {
520 .ldr_stack_argument => &Instruction.ldr,525 .ldr_stack_argument => try emit.writeInstruction(Instruction.ldr(cond, rt, .sp, .{ .offset = offset })),
521 .ldrb_stack_argument => &Instruction.ldrb,526 .ldrb_stack_argument => try emit.writeInstruction(Instruction.ldrb(cond, rt, .sp, .{ .offset = offset })),
522 else => unreachable,527 else => unreachable,
523 };528 }
524
525 const ldr_workaround = switch (builtin.zig_backend) {
526 .stage1 => ldr.*,
527 else => ldr,
528 };
529
530 try emit.writeInstruction(ldr_workaround(
531 cond,
532 r_stack_offset.rt,
533 .fp,
534 .{ .offset = offset },
535 ));
536 },529 },
537 .ldrh_stack_argument,530 .ldrh_stack_argument,
538 .ldrsb_stack_argument,531 .ldrsb_stack_argument,
...@@ -542,24 +535,12 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -542,24 +535,12 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void {
542 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, raw_offset));535 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, raw_offset));
543 } else return emit.fail("TODO mirLoadStack larger offsets", .{});536 } else return emit.fail("TODO mirLoadStack larger offsets", .{});
544537
545 const ldr = switch (tag) {538 switch (tag) {
546 .ldrh_stack_argument => &Instruction.ldrh,539 .ldrh_stack_argument => try emit.writeInstruction(Instruction.ldrh(cond, rt, .sp, .{ .offset = offset })),
547 .ldrsb_stack_argument => &Instruction.ldrsb,540 .ldrsb_stack_argument => try emit.writeInstruction(Instruction.ldrsb(cond, rt, .sp, .{ .offset = offset })),
548 .ldrsh_stack_argument => &Instruction.ldrsh,541 .ldrsh_stack_argument => try emit.writeInstruction(Instruction.ldrsh(cond, rt, .sp, .{ .offset = offset })),
549 else => unreachable,542 else => unreachable,
550 };543 }
551
552 const ldr_workaround = switch (builtin.zig_backend) {
553 .stage1 => ldr.*,
554 else => ldr,
555 };
556
557 try emit.writeInstruction(ldr_workaround(
558 cond,
559 r_stack_offset.rt,
560 .fp,
561 .{ .offset = offset },
562 ));
563 },544 },
564 else => unreachable,545 else => unreachable,
565 }546 }
src/arch/riscv64/CodeGen.zig+4-1
...@@ -693,6 +693,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -693,6 +693,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
693 .float_to_int_optimized,693 .float_to_int_optimized,
694 => return self.fail("TODO implement optimized float mode", .{}),694 => return self.fail("TODO implement optimized float mode", .{}),
695695
696 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),
697 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),
698
696 .wasm_memory_size => unreachable,699 .wasm_memory_size => unreachable,
697 .wasm_memory_grow => unreachable,700 .wasm_memory_grow => unreachable,
698 // zig fmt: on701 // zig fmt: on
...@@ -1619,7 +1622,7 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1619,7 +1622,7 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
16191622
1620fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32) !void {1623fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32) !void {
1621 const ty = self.air.instructions.items(.data)[inst].ty;1624 const ty = self.air.instructions.items(.data)[inst].ty;
1622 const name = self.mod_fn.getParamName(arg_index);1625 const name = self.mod_fn.getParamName(self.bin_file.options.module.?, arg_index);
1623 const name_with_null = name.ptr[0 .. name.len + 1];1626 const name_with_null = name.ptr[0 .. name.len + 1];
16241627
1625 switch (mcv) {1628 switch (mcv) {
src/arch/sparc64/CodeGen.zig+4-1
...@@ -705,6 +705,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -705,6 +705,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
705 .float_to_int_optimized,705 .float_to_int_optimized,
706 => @panic("TODO implement optimized float mode"),706 => @panic("TODO implement optimized float mode"),
707707
708 .is_named_enum_value => @panic("TODO implement is_named_enum_value"),
709 .error_set_has_value => @panic("TODO implement error_set_has_value"),
710
708 .wasm_memory_size => unreachable,711 .wasm_memory_size => unreachable,
709 .wasm_memory_grow => unreachable,712 .wasm_memory_grow => unreachable,
710 // zig fmt: on713 // zig fmt: on
...@@ -2959,7 +2962,7 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live...@@ -2959,7 +2962,7 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live
29592962
2960fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32) !void {2963fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32) !void {
2961 const ty = self.air.instructions.items(.data)[inst].ty;2964 const ty = self.air.instructions.items(.data)[inst].ty;
2962 const name = self.mod_fn.getParamName(arg_index);2965 const name = self.mod_fn.getParamName(self.bin_file.options.module.?, arg_index);
2963 const name_with_null = name.ptr[0 .. name.len + 1];2966 const name_with_null = name.ptr[0 .. name.len + 1];
29642967
2965 switch (mcv) {2968 switch (mcv) {
src/arch/wasm/CodeGen.zig+422-330
...@@ -29,6 +29,8 @@ const errUnionErrorOffset = codegen.errUnionErrorOffset;...@@ -29,6 +29,8 @@ const errUnionErrorOffset = codegen.errUnionErrorOffset;
29const WValue = union(enum) {29const WValue = union(enum) {
30 /// May be referenced but is unused30 /// May be referenced but is unused
31 none: void,31 none: void,
32 /// The value lives on top of the stack
33 stack: void,
32 /// Index of the local variable34 /// Index of the local variable
33 local: u32,35 local: u32,
34 /// An immediate 32bit value36 /// An immediate 32bit value
...@@ -55,7 +57,7 @@ const WValue = union(enum) {...@@ -55,7 +57,7 @@ const WValue = union(enum) {
55 /// In wasm function pointers are indexes into a function table,57 /// In wasm function pointers are indexes into a function table,
56 /// rather than an address in the data section.58 /// rather than an address in the data section.
57 function_index: u32,59 function_index: u32,
58 /// Offset from the bottom of the stack, with the offset60 /// Offset from the bottom of the virtual stack, with the offset
59 /// pointing to where the value lives.61 /// pointing to where the value lives.
60 stack_offset: u32,62 stack_offset: u32,
6163
...@@ -71,6 +73,38 @@ const WValue = union(enum) {...@@ -71,6 +73,38 @@ const WValue = union(enum) {
71 else => return 0,73 else => return 0,
72 }74 }
73 }75 }
76
77 /// Promotes a `WValue` to a local when given value is on top of the stack.
78 /// When encountering a `local` or `stack_offset` this is essentially a no-op.
79 /// All other tags are illegal.
80 fn toLocal(value: WValue, gen: *Self, ty: Type) InnerError!WValue {
81 switch (value) {
82 .stack => {
83 const local = try gen.allocLocal(ty);
84 try gen.addLabel(.local_set, local.local);
85 return local;
86 },
87 .local, .stack_offset => return value,
88 else => unreachable,
89 }
90 }
91
92 /// Marks a local as no longer being referenced and essentially allows
93 /// us to re-use it somewhere else within the function.
94 /// The valtype of the local is deducted by using the index of the given.
95 fn free(value: *WValue, gen: *Self) void {
96 if (value.* != .local) return;
97 const local_value = value.local;
98 const index = local_value - gen.args.len - @boolToInt(gen.return_value != .none);
99 const valtype = @intToEnum(wasm.Valtype, gen.locals.items[index]);
100 switch (valtype) {
101 .i32 => gen.free_locals_i32.append(gen.gpa, local_value) catch return, // It's ok to fail any of those, a new local can be allocated instead
102 .i64 => gen.free_locals_i64.append(gen.gpa, local_value) catch return,
103 .f32 => gen.free_locals_f32.append(gen.gpa, local_value) catch return,
104 .f64 => gen.free_locals_f64.append(gen.gpa, local_value) catch return,
105 }
106 value.* = WValue{ .none = {} };
107 }
74};108};
75109
76/// Wasm ops, but without input/output/signedness information110/// Wasm ops, but without input/output/signedness information
...@@ -601,6 +635,21 @@ stack_size: u32 = 0,...@@ -601,6 +635,21 @@ stack_size: u32 = 0,
601/// However, local variables or the usage of `@setAlignStack` can overwrite this default.635/// However, local variables or the usage of `@setAlignStack` can overwrite this default.
602stack_alignment: u32 = 16,636stack_alignment: u32 = 16,
603637
638// For each individual Wasm valtype we store a seperate free list which
639// allows us to re-use locals that are no longer used. e.g. a temporary local.
640/// A list of indexes which represents a local of valtype `i32`.
641/// It is illegal to store a non-i32 valtype in this list.
642free_locals_i32: std.ArrayListUnmanaged(u32) = .{},
643/// A list of indexes which represents a local of valtype `i64`.
644/// It is illegal to store a non-i32 valtype in this list.
645free_locals_i64: std.ArrayListUnmanaged(u32) = .{},
646/// A list of indexes which represents a local of valtype `f32`.
647/// It is illegal to store a non-i32 valtype in this list.
648free_locals_f32: std.ArrayListUnmanaged(u32) = .{},
649/// A list of indexes which represents a local of valtype `f64`.
650/// It is illegal to store a non-i32 valtype in this list.
651free_locals_f64: std.ArrayListUnmanaged(u32) = .{},
652
604const InnerError = error{653const InnerError = error{
605 OutOfMemory,654 OutOfMemory,
606 /// An error occurred when trying to lower AIR to MIR.655 /// An error occurred when trying to lower AIR to MIR.
...@@ -759,7 +808,7 @@ fn genBlockType(ty: Type, target: std.Target) u8 {...@@ -759,7 +808,7 @@ fn genBlockType(ty: Type, target: std.Target) u8 {
759/// Writes the bytecode depending on the given `WValue` in `val`808/// Writes the bytecode depending on the given `WValue` in `val`
760fn emitWValue(self: *Self, value: WValue) InnerError!void {809fn emitWValue(self: *Self, value: WValue) InnerError!void {
761 switch (value) {810 switch (value) {
762 .none => {}, // no-op811 .none, .stack => {}, // no-op
763 .local => |idx| try self.addLabel(.local_get, idx),812 .local => |idx| try self.addLabel(.local_get, idx),
764 .imm32 => |val| try self.addImm32(@bitCast(i32, val)),813 .imm32 => |val| try self.addImm32(@bitCast(i32, val)),
765 .imm64 => |val| try self.addImm64(val),814 .imm64 => |val| try self.addImm64(val),
...@@ -781,9 +830,30 @@ fn emitWValue(self: *Self, value: WValue) InnerError!void {...@@ -781,9 +830,30 @@ fn emitWValue(self: *Self, value: WValue) InnerError!void {
781/// Creates one locals for a given `Type`.830/// Creates one locals for a given `Type`.
782/// Returns a corresponding `Wvalue` with `local` as active tag831/// Returns a corresponding `Wvalue` with `local` as active tag
783fn allocLocal(self: *Self, ty: Type) InnerError!WValue {832fn allocLocal(self: *Self, ty: Type) InnerError!WValue {
833 const valtype = typeToValtype(ty, self.target);
834 switch (valtype) {
835 .i32 => if (self.free_locals_i32.popOrNull()) |index| {
836 return WValue{ .local = index };
837 },
838 .i64 => if (self.free_locals_i64.popOrNull()) |index| {
839 return WValue{ .local = index };
840 },
841 .f32 => if (self.free_locals_f32.popOrNull()) |index| {
842 return WValue{ .local = index };
843 },
844 .f64 => if (self.free_locals_f64.popOrNull()) |index| {
845 return WValue{ .local = index };
846 },
847 }
848 // no local was free to be re-used, so allocate a new local instead
849 return self.ensureAllocLocal(ty);
850}
851
852/// Ensures a new local will be created. This is useful when it's useful
853/// to use a zero-initialized local.
854fn ensureAllocLocal(self: *Self, ty: Type) InnerError!WValue {
855 try self.locals.append(self.gpa, genValtype(ty, self.target));
784 const initial_index = self.local_index;856 const initial_index = self.local_index;
785 const valtype = genValtype(ty, self.target);
786 try self.locals.append(self.gpa, valtype);
787 self.local_index += 1;857 self.local_index += 1;
788 return WValue{ .local = initial_index };858 return WValue{ .local = initial_index };
789}859}
...@@ -1135,9 +1205,9 @@ fn initializeStack(self: *Self) !void {...@@ -1135,9 +1205,9 @@ fn initializeStack(self: *Self) !void {
1135 // Reserve a local to store the current stack pointer1205 // Reserve a local to store the current stack pointer
1136 // We can later use this local to set the stack pointer back to the value1206 // We can later use this local to set the stack pointer back to the value
1137 // we have stored here.1207 // we have stored here.
1138 self.initial_stack_value = try self.allocLocal(Type.usize);1208 self.initial_stack_value = try self.ensureAllocLocal(Type.usize);
1139 // Also reserve a local to store the bottom stack value1209 // Also reserve a local to store the bottom stack value
1140 self.bottom_stack_value = try self.allocLocal(Type.usize);1210 self.bottom_stack_value = try self.ensureAllocLocal(Type.usize);
1141}1211}
11421212
1143/// Reads the stack pointer from `Context.initial_stack_value` and writes it1213/// Reads the stack pointer from `Context.initial_stack_value` and writes it
...@@ -1268,7 +1338,9 @@ fn memcpy(self: *Self, dst: WValue, src: WValue, len: WValue) !void {...@@ -1268,7 +1338,9 @@ fn memcpy(self: *Self, dst: WValue, src: WValue, len: WValue) !void {
1268 else => {1338 else => {
1269 // TODO: We should probably lower this to a call to compiler_rt1339 // TODO: We should probably lower this to a call to compiler_rt
1270 // But for now, we implement it manually1340 // But for now, we implement it manually
1271 const offset = try self.allocLocal(Type.usize); // local for counter1341 var offset = try self.ensureAllocLocal(Type.usize); // local for counter
1342 defer offset.free(self);
1343
1272 // outer block to jump to when loop is done1344 // outer block to jump to when loop is done
1273 try self.startBlock(.block, wasm.block_empty);1345 try self.startBlock(.block, wasm.block_empty);
1274 try self.startBlock(.loop, wasm.block_empty);1346 try self.startBlock(.loop, wasm.block_empty);
...@@ -1405,7 +1477,7 @@ fn buildPointerOffset(self: *Self, ptr_value: WValue, offset: u64, action: enum...@@ -1405,7 +1477,7 @@ fn buildPointerOffset(self: *Self, ptr_value: WValue, offset: u64, action: enum
1405 // do not perform arithmetic when offset is 0.1477 // do not perform arithmetic when offset is 0.
1406 if (offset == 0 and ptr_value.offset() == 0 and action == .modify) return ptr_value;1478 if (offset == 0 and ptr_value.offset() == 0 and action == .modify) return ptr_value;
1407 const result_ptr: WValue = switch (action) {1479 const result_ptr: WValue = switch (action) {
1408 .new => try self.allocLocal(Type.usize),1480 .new => try self.ensureAllocLocal(Type.usize),
1409 .modify => ptr_value,1481 .modify => ptr_value,
1410 };1482 };
1411 try self.emitWValue(ptr_value);1483 try self.emitWValue(ptr_value);
...@@ -1621,6 +1693,8 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1621,6 +1693,8 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1621 .tag_name,1693 .tag_name,
1622 .err_return_trace,1694 .err_return_trace,
1623 .set_err_return_trace,1695 .set_err_return_trace,
1696 .is_named_enum_value,
1697 .error_set_has_value,
1624 => |tag| return self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}),1698 => |tag| return self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}),
16251699
1626 .add_optimized,1700 .add_optimized,
...@@ -1652,7 +1726,10 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1652,7 +1726,10 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1652fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {1726fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
1653 for (body) |inst| {1727 for (body) |inst| {
1654 const result = try self.genInst(inst);1728 const result = try self.genInst(inst);
1655 try self.values.putNoClobber(self.gpa, Air.indexToRef(inst), result);1729 if (result != .none) {
1730 assert(result != .stack); // not allowed to store stack values as we cannot keep track of where they are on the stack
1731 try self.values.putNoClobber(self.gpa, Air.indexToRef(inst), result);
1732 }
1656 }1733 }
1657}1734}
16581735
...@@ -1726,8 +1803,8 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1726,8 +1803,8 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
17261803
1727 const fn_info = self.decl.ty.fnInfo();1804 const fn_info = self.decl.ty.fnInfo();
1728 if (!firstParamSRet(fn_info.cc, fn_info.return_type, self.target)) {1805 if (!firstParamSRet(fn_info.cc, fn_info.return_type, self.target)) {
1729 const result = try self.load(operand, ret_ty, 0);1806 // leave on the stack
1730 try self.emitWValue(result);1807 _ = try self.load(operand, ret_ty, 0);
1731 }1808 }
17321809
1733 try self.restoreStackPointer();1810 try self.restoreStackPointer();
...@@ -1846,6 +1923,7 @@ fn airStore(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1846,6 +1923,7 @@ fn airStore(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1846}1923}
18471924
1848fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerError!void {1925fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerError!void {
1926 assert(!(lhs != .stack and rhs == .stack));
1849 switch (ty.zigTypeTag()) {1927 switch (ty.zigTypeTag()) {
1850 .ErrorUnion => {1928 .ErrorUnion => {
1851 const pl_ty = ty.errorUnionPayload();1929 const pl_ty = ty.errorUnionPayload();
...@@ -1879,20 +1957,26 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro...@@ -1879,20 +1957,26 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
1879 .Pointer => {1957 .Pointer => {
1880 if (ty.isSlice()) {1958 if (ty.isSlice()) {
1881 // store pointer first1959 // store pointer first
1960 // lower it to the stack so we do not have to store rhs into a local first
1961 try self.emitWValue(lhs);
1882 const ptr_local = try self.load(rhs, Type.usize, 0);1962 const ptr_local = try self.load(rhs, Type.usize, 0);
1883 try self.store(lhs, ptr_local, Type.usize, 0);1963 try self.store(.{ .stack = {} }, ptr_local, Type.usize, 0 + lhs.offset());
18841964
1885 // retrieve length from rhs, and store that alongside lhs as well1965 // retrieve length from rhs, and store that alongside lhs as well
1966 try self.emitWValue(lhs);
1886 const len_local = try self.load(rhs, Type.usize, self.ptrSize());1967 const len_local = try self.load(rhs, Type.usize, self.ptrSize());
1887 try self.store(lhs, len_local, Type.usize, self.ptrSize());1968 try self.store(.{ .stack = {} }, len_local, Type.usize, self.ptrSize() + lhs.offset());
1888 return;1969 return;
1889 }1970 }
1890 },1971 },
1891 .Int => if (ty.intInfo(self.target).bits > 64) {1972 .Int => if (ty.intInfo(self.target).bits > 64) {
1973 try self.emitWValue(lhs);
1892 const lsb = try self.load(rhs, Type.u64, 0);1974 const lsb = try self.load(rhs, Type.u64, 0);
1975 try self.store(.{ .stack = {} }, lsb, Type.u64, 0 + lhs.offset());
1976
1977 try self.emitWValue(lhs);
1893 const msb = try self.load(rhs, Type.u64, 8);1978 const msb = try self.load(rhs, Type.u64, 8);
1894 try self.store(lhs, lsb, Type.u64, 0);1979 try self.store(.{ .stack = {} }, msb, Type.u64, 8 + lhs.offset());
1895 try self.store(lhs, msb, Type.u64, 8);
1896 return;1980 return;
1897 },1981 },
1898 else => {},1982 else => {},
...@@ -1931,9 +2015,12 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1931,9 +2015,12 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1931 return new_local;2015 return new_local;
1932 }2016 }
19332017
1934 return self.load(operand, ty, 0);2018 const stack_loaded = try self.load(operand, ty, 0);
2019 return stack_loaded.toLocal(self, ty);
1935}2020}
19362021
2022/// Loads an operand from the linear memory section.
2023/// NOTE: Leaves the value on the stack.
1937fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue {2024fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue {
1938 // load local's value from memory by its stack position2025 // load local's value from memory by its stack position
1939 try self.emitWValue(operand);2026 try self.emitWValue(operand);
...@@ -1951,10 +2038,7 @@ fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue {...@@ -1951,10 +2038,7 @@ fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue {
1951 .{ .offset = offset + operand.offset(), .alignment = ty.abiAlignment(self.target) },2038 .{ .offset = offset + operand.offset(), .alignment = ty.abiAlignment(self.target) },
1952 );2039 );
19532040
1954 // store the result in a local2041 return WValue{ .stack = {} };
1955 const result = try self.allocLocal(ty);
1956 try self.addLabel(.local_set, result.local);
1957 return result;
1958}2042}
19592043
1960fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2044fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -1991,7 +2075,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1991,7 +2075,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1991 switch (self.debug_output) {2075 switch (self.debug_output) {
1992 .dwarf => |dwarf| {2076 .dwarf => |dwarf| {
1993 // TODO: Get the original arg index rather than wasm arg index2077 // TODO: Get the original arg index rather than wasm arg index
1994 const name = self.mod_fn.getParamName(arg_index);2078 const name = self.mod_fn.getParamName(self.bin_file.base.options.module.?, arg_index);
1995 const leb_size = link.File.Wasm.getULEB128Size(arg.local);2079 const leb_size = link.File.Wasm.getULEB128Size(arg.local);
1996 const dbg_info = &dwarf.dbg_info;2080 const dbg_info = &dwarf.dbg_info;
1997 try dbg_info.ensureUnusedCapacity(3 + leb_size + 5 + name.len + 1);2081 try dbg_info.ensureUnusedCapacity(3 + leb_size + 5 + name.len + 1);
...@@ -2024,10 +2108,14 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {...@@ -2024,10 +2108,14 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
2024 const rhs = try self.resolveInst(bin_op.rhs);2108 const rhs = try self.resolveInst(bin_op.rhs);
2025 const ty = self.air.typeOf(bin_op.lhs);2109 const ty = self.air.typeOf(bin_op.lhs);
20262110
2027 return self.binOp(lhs, rhs, ty, op);2111 const stack_value = try self.binOp(lhs, rhs, ty, op);
2112 return stack_value.toLocal(self, ty);
2028}2113}
20292114
2115/// Performs a binary operation on the given `WValue`'s
2116/// NOTE: THis leaves the value on top of the stack.
2030fn binOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {2117fn binOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {
2118 assert(!(lhs != .stack and rhs == .stack));
2031 if (isByRef(ty, self.target)) {2119 if (isByRef(ty, self.target)) {
2032 if (ty.zigTypeTag() == .Int) {2120 if (ty.zigTypeTag() == .Int) {
2033 return self.binOpBigInt(lhs, rhs, ty, op);2121 return self.binOpBigInt(lhs, rhs, ty, op);
...@@ -2053,24 +2141,18 @@ fn binOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WVa...@@ -2053,24 +2141,18 @@ fn binOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WVa
20532141
2054 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));2142 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
20552143
2056 // save the result in a temporary2144 return WValue{ .stack = {} };
2057 const bin_local = try self.allocLocal(ty);
2058 try self.addLabel(.local_set, bin_local.local);
2059 return bin_local;
2060}2145}
20612146
2147/// Performs a binary operation for 16-bit floats.
2148/// NOTE: Leaves the result value on the stack
2062fn binOpFloat16(self: *Self, lhs: WValue, rhs: WValue, op: Op) InnerError!WValue {2149fn binOpFloat16(self: *Self, lhs: WValue, rhs: WValue, op: Op) InnerError!WValue {
2063 const ext_lhs = try self.fpext(lhs, Type.f16, Type.f32);
2064 const ext_rhs = try self.fpext(rhs, Type.f16, Type.f32);
2065
2066 const opcode: wasm.Opcode = buildOpcode(.{ .op = op, .valtype1 = .f32, .signedness = .unsigned });2150 const opcode: wasm.Opcode = buildOpcode(.{ .op = op, .valtype1 = .f32, .signedness = .unsigned });
2067 try self.emitWValue(ext_lhs);2151 _ = try self.fpext(lhs, Type.f16, Type.f32);
2068 try self.emitWValue(ext_rhs);2152 _ = try self.fpext(rhs, Type.f16, Type.f32);
2069 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));2153 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
20702154
2071 // re-use temporary local2155 return self.fptrunc(.{ .stack = {} }, Type.f32, Type.f16);
2072 try self.addLabel(.local_set, ext_lhs.local);
2073 return self.fptrunc(ext_lhs, Type.f32, Type.f16);
2074}2156}
20752157
2076fn binOpBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {2158fn binOpBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {
...@@ -2083,13 +2165,16 @@ fn binOpBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerErr...@@ -2083,13 +2165,16 @@ fn binOpBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerErr
2083 }2165 }
20842166
2085 const result = try self.allocStack(ty);2167 const result = try self.allocStack(ty);
2086 const lhs_high_bit = try self.load(lhs, Type.u64, 0);2168 var lhs_high_bit = try (try self.load(lhs, Type.u64, 0)).toLocal(self, Type.u64);
2169 defer lhs_high_bit.free(self);
2170 var rhs_high_bit = try (try self.load(rhs, Type.u64, 0)).toLocal(self, Type.u64);
2171 defer rhs_high_bit.free(self);
2172 var high_op_res = try (try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op)).toLocal(self, Type.u64);
2173 defer high_op_res.free(self);
2174
2087 const lhs_low_bit = try self.load(lhs, Type.u64, 8);2175 const lhs_low_bit = try self.load(lhs, Type.u64, 8);
2088 const rhs_high_bit = try self.load(rhs, Type.u64, 0);
2089 const rhs_low_bit = try self.load(rhs, Type.u64, 8);2176 const rhs_low_bit = try self.load(rhs, Type.u64, 8);
2090
2091 const low_op_res = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op);2177 const low_op_res = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op);
2092 const high_op_res = try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op);
20932178
2094 const lt = if (op == .add) blk: {2179 const lt = if (op == .add) blk: {
2095 break :blk try self.cmp(high_op_res, rhs_high_bit, Type.u64, .lt);2180 break :blk try self.cmp(high_op_res, rhs_high_bit, Type.u64, .lt);
...@@ -2097,7 +2182,8 @@ fn binOpBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerErr...@@ -2097,7 +2182,8 @@ fn binOpBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerErr
2097 break :blk try self.cmp(lhs_high_bit, rhs_high_bit, Type.u64, .lt);2182 break :blk try self.cmp(lhs_high_bit, rhs_high_bit, Type.u64, .lt);
2098 } else unreachable;2183 } else unreachable;
2099 const tmp = try self.intcast(lt, Type.u32, Type.u64);2184 const tmp = try self.intcast(lt, Type.u32, Type.u64);
2100 const tmp_op = try self.binOp(low_op_res, tmp, Type.u64, op);2185 var tmp_op = try (try self.binOp(low_op_res, tmp, Type.u64, op)).toLocal(self, Type.u64);
2186 defer tmp_op.free(self);
21012187
2102 try self.store(result, high_op_res, Type.u64, 0);2188 try self.store(result, high_op_res, Type.u64, 0);
2103 try self.store(result, tmp_op, Type.u64, 8);2189 try self.store(result, tmp_op, Type.u64, 8);
...@@ -2114,40 +2200,22 @@ fn airWrapBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {...@@ -2114,40 +2200,22 @@ fn airWrapBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
2114 return self.fail("TODO: Implement wrapping arithmetic for vectors", .{});2200 return self.fail("TODO: Implement wrapping arithmetic for vectors", .{});
2115 }2201 }
21162202
2117 return self.wrapBinOp(lhs, rhs, ty, op);2203 return (try self.wrapBinOp(lhs, rhs, ty, op)).toLocal(self, ty);
2118}2204}
21192205
2206/// Performs a wrapping binary operation.
2207/// Asserts rhs is not a stack value when lhs also isn't.
2208/// NOTE: Leaves the result on the stack when its Type is <= 64 bits
2120fn wrapBinOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {2209fn wrapBinOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {
2121 const bit_size = ty.intInfo(self.target).bits;2210 const bin_local = try self.binOp(lhs, rhs, ty, op);
2122 var wasm_bits = toWasmBits(bit_size) orelse {
2123 return self.fail("TODO: Implement wrapping arithmetic for integers with bitsize: {d}\n", .{bit_size});
2124 };
2125
2126 if (wasm_bits == 128) {
2127 const bin_op = try self.binOpBigInt(lhs, rhs, ty, op);
2128 return self.wrapOperand(bin_op, ty);
2129 }
2130
2131 const opcode: wasm.Opcode = buildOpcode(.{
2132 .op = op,
2133 .valtype1 = typeToValtype(ty, self.target),
2134 .signedness = if (ty.isSignedInt()) .signed else .unsigned,
2135 });
2136
2137 try self.emitWValue(lhs);
2138 try self.emitWValue(rhs);
2139 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
2140 const bin_local = try self.allocLocal(ty);
2141 try self.addLabel(.local_set, bin_local.local);
2142
2143 return self.wrapOperand(bin_local, ty);2211 return self.wrapOperand(bin_local, ty);
2144}2212}
21452213
2146/// Wraps an operand based on a given type's bitsize.2214/// Wraps an operand based on a given type's bitsize.
2147/// Asserts `Type` is <= 128 bits.2215/// Asserts `Type` is <= 128 bits.
2216/// NOTE: When the Type is <= 64 bits, leaves the value on top of the stack.
2148fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue {2217fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue {
2149 assert(ty.abiSize(self.target) <= 16);2218 assert(ty.abiSize(self.target) <= 16);
2150 const result_local = try self.allocLocal(ty);
2151 const bitsize = ty.intInfo(self.target).bits;2219 const bitsize = ty.intInfo(self.target).bits;
2152 const wasm_bits = toWasmBits(bitsize) orelse {2220 const wasm_bits = toWasmBits(bitsize) orelse {
2153 return self.fail("TODO: Implement wrapOperand for bitsize '{d}'", .{bitsize});2221 return self.fail("TODO: Implement wrapOperand for bitsize '{d}'", .{bitsize});
...@@ -2156,14 +2224,15 @@ fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue {...@@ -2156,14 +2224,15 @@ fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue {
2156 if (wasm_bits == bitsize) return operand;2224 if (wasm_bits == bitsize) return operand;
21572225
2158 if (wasm_bits == 128) {2226 if (wasm_bits == 128) {
2159 const msb = try self.load(operand, Type.u64, 0);2227 assert(operand != .stack);
2160 const lsb = try self.load(operand, Type.u64, 8);2228 const lsb = try self.load(operand, Type.u64, 8);
21612229
2162 const result_ptr = try self.allocStack(ty);2230 const result_ptr = try self.allocStack(ty);
2163 try self.store(result_ptr, lsb, Type.u64, 8);2231 try self.emitWValue(result_ptr);
2232 try self.store(.{ .stack = {} }, lsb, Type.u64, 8 + result_ptr.offset());
2164 const result = (@as(u64, 1) << @intCast(u6, 64 - (wasm_bits - bitsize))) - 1;2233 const result = (@as(u64, 1) << @intCast(u6, 64 - (wasm_bits - bitsize))) - 1;
2165 try self.emitWValue(result_ptr);2234 try self.emitWValue(result_ptr);
2166 try self.emitWValue(msb);2235 _ = try self.load(operand, Type.u64, 0);
2167 try self.addImm64(result);2236 try self.addImm64(result);
2168 try self.addTag(.i64_and);2237 try self.addTag(.i64_and);
2169 try self.addMemArg(.i64_store, .{ .offset = result_ptr.offset(), .alignment = 8 });2238 try self.addMemArg(.i64_store, .{ .offset = result_ptr.offset(), .alignment = 8 });
...@@ -2180,8 +2249,7 @@ fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue {...@@ -2180,8 +2249,7 @@ fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue {
2180 try self.addTag(.i64_and);2249 try self.addTag(.i64_and);
2181 } else unreachable;2250 } else unreachable;
21822251
2183 try self.addLabel(.local_set, result_local.local);2252 return WValue{ .stack = {} };
2184 return result_local;
2185}2253}
21862254
2187fn lowerParentPtr(self: *Self, ptr_val: Value, ptr_child_ty: Type) InnerError!WValue {2255fn lowerParentPtr(self: *Self, ptr_val: Value, ptr_child_ty: Type) InnerError!WValue {
...@@ -2593,10 +2661,14 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner...@@ -2593,10 +2661,14 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner
2593 const lhs = try self.resolveInst(bin_op.lhs);2661 const lhs = try self.resolveInst(bin_op.lhs);
2594 const rhs = try self.resolveInst(bin_op.rhs);2662 const rhs = try self.resolveInst(bin_op.rhs);
2595 const operand_ty = self.air.typeOf(bin_op.lhs);2663 const operand_ty = self.air.typeOf(bin_op.lhs);
2596 return self.cmp(lhs, rhs, operand_ty, op);2664 return (try self.cmp(lhs, rhs, operand_ty, op)).toLocal(self, Type.u32); // comparison result is always 32 bits
2597}2665}
25982666
2667/// Compares two operands.
2668/// Asserts rhs is not a stack value when the lhs isn't a stack value either
2669/// NOTE: This leaves the result on top of the stack, rather than a new local.
2599fn cmp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOperator) InnerError!WValue {2670fn cmp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOperator) InnerError!WValue {
2671 assert(!(lhs != .stack and rhs == .stack));
2600 if (ty.zigTypeTag() == .Optional and !ty.optionalReprIsPayload()) {2672 if (ty.zigTypeTag() == .Optional and !ty.optionalReprIsPayload()) {
2601 var buf: Type.Payload.ElemType = undefined;2673 var buf: Type.Payload.ElemType = undefined;
2602 const payload_ty = ty.optionalChild(&buf);2674 const payload_ty = ty.optionalChild(&buf);
...@@ -2638,15 +2710,12 @@ fn cmp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOper...@@ -2638,15 +2710,12 @@ fn cmp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOper
2638 });2710 });
2639 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));2711 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
26402712
2641 const cmp_tmp = try self.allocLocal(Type.initTag(.i32)); // bool is always i322713 return WValue{ .stack = {} };
2642 try self.addLabel(.local_set, cmp_tmp.local);
2643 return cmp_tmp;
2644}2714}
26452715
2716/// Compares 16-bit floats
2717/// NOTE: The result value remains on top of the stack.
2646fn cmpFloat16(self: *Self, lhs: WValue, rhs: WValue, op: std.math.CompareOperator) InnerError!WValue {2718fn cmpFloat16(self: *Self, lhs: WValue, rhs: WValue, op: std.math.CompareOperator) InnerError!WValue {
2647 const ext_lhs = try self.fpext(lhs, Type.f16, Type.f32);
2648 const ext_rhs = try self.fpext(rhs, Type.f16, Type.f32);
2649
2650 const opcode: wasm.Opcode = buildOpcode(.{2719 const opcode: wasm.Opcode = buildOpcode(.{
2651 .op = switch (op) {2720 .op = switch (op) {
2652 .lt => .lt,2721 .lt => .lt,
...@@ -2659,13 +2728,11 @@ fn cmpFloat16(self: *Self, lhs: WValue, rhs: WValue, op: std.math.CompareOperato...@@ -2659,13 +2728,11 @@ fn cmpFloat16(self: *Self, lhs: WValue, rhs: WValue, op: std.math.CompareOperato
2659 .valtype1 = .f32,2728 .valtype1 = .f32,
2660 .signedness = .unsigned,2729 .signedness = .unsigned,
2661 });2730 });
2662 try self.emitWValue(ext_lhs);2731 _ = try self.fpext(lhs, Type.f16, Type.f32);
2663 try self.emitWValue(ext_rhs);2732 _ = try self.fpext(rhs, Type.f16, Type.f32);
2664 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));2733 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
26652734
2666 const result = try self.allocLocal(Type.initTag(.i32)); // bool is always i322735 return WValue{ .stack = {} };
2667 try self.addLabel(.local_set, result.local);
2668 return result;
2669}2736}
26702737
2671fn airCmpVector(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2738fn airCmpVector(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -2726,21 +2793,23 @@ fn airNot(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2726,21 +2793,23 @@ fn airNot(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2726 switch (wasm_bits) {2793 switch (wasm_bits) {
2727 32 => {2794 32 => {
2728 const bin_op = try self.binOp(operand, .{ .imm32 = ~@as(u32, 0) }, operand_ty, .xor);2795 const bin_op = try self.binOp(operand, .{ .imm32 = ~@as(u32, 0) }, operand_ty, .xor);
2729 return self.wrapOperand(bin_op, operand_ty);2796 return (try self.wrapOperand(bin_op, operand_ty)).toLocal(self, operand_ty);
2730 },2797 },
2731 64 => {2798 64 => {
2732 const bin_op = try self.binOp(operand, .{ .imm64 = ~@as(u64, 0) }, operand_ty, .xor);2799 const bin_op = try self.binOp(operand, .{ .imm64 = ~@as(u64, 0) }, operand_ty, .xor);
2733 return self.wrapOperand(bin_op, operand_ty);2800 return (try self.wrapOperand(bin_op, operand_ty)).toLocal(self, operand_ty);
2734 },2801 },
2735 128 => {2802 128 => {
2736 const result_ptr = try self.allocStack(operand_ty);2803 const result_ptr = try self.allocStack(operand_ty);
2804 try self.emitWValue(result_ptr);
2737 const msb = try self.load(operand, Type.u64, 0);2805 const msb = try self.load(operand, Type.u64, 0);
2738 const lsb = try self.load(operand, Type.u64, 8);
2739
2740 const msb_xor = try self.binOp(msb, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor);2806 const msb_xor = try self.binOp(msb, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor);
2807 try self.store(.{ .stack = {} }, msb_xor, Type.u64, 0 + result_ptr.offset());
2808
2809 try self.emitWValue(result_ptr);
2810 const lsb = try self.load(operand, Type.u64, 8);
2741 const lsb_xor = try self.binOp(lsb, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor);2811 const lsb_xor = try self.binOp(lsb, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor);
2742 try self.store(result_ptr, msb_xor, Type.u64, 0);2812 try self.store(result_ptr, lsb_xor, Type.u64, 8 + result_ptr.offset());
2743 try self.store(result_ptr, lsb_xor, Type.u64, 8);
2744 return result_ptr;2813 return result_ptr;
2745 },2814 },
2746 else => unreachable,2815 else => unreachable,
...@@ -2828,7 +2897,8 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2828,7 +2897,8 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2828 }2897 }
2829 }2898 }
28302899
2831 return self.load(operand, field_ty, offset);2900 const field = try self.load(operand, field_ty, offset);
2901 return field.toLocal(self, field_ty);
2832}2902}
28332903
2834fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2904fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -3038,7 +3108,9 @@ fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool)...@@ -3038,7 +3108,9 @@ fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool)
3038 if (op_is_ptr or isByRef(payload_ty, self.target)) {3108 if (op_is_ptr or isByRef(payload_ty, self.target)) {
3039 return self.buildPointerOffset(operand, pl_offset, .new);3109 return self.buildPointerOffset(operand, pl_offset, .new);
3040 }3110 }
3041 return self.load(operand, payload_ty, pl_offset);3111
3112 const payload = try self.load(operand, payload_ty, pl_offset);
3113 return payload.toLocal(self, payload_ty);
3042}3114}
30433115
3044fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!WValue {3116fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!WValue {
...@@ -3058,7 +3130,8 @@ fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool) In...@@ -3058,7 +3130,8 @@ fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index, op_is_ptr: bool) In
3058 return operand;3130 return operand;
3059 }3131 }
30603132
3061 return self.load(operand, Type.anyerror, @intCast(u32, errUnionErrorOffset(payload_ty, self.target)));3133 const error_val = try self.load(operand, Type.anyerror, @intCast(u32, errUnionErrorOffset(payload_ty, self.target)));
3134 return error_val.toLocal(self, Type.anyerror);
3062}3135}
30633136
3064fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3137fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -3124,12 +3197,13 @@ fn airIntcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3124,12 +3197,13 @@ fn airIntcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3124 return self.fail("todo Wasm intcast for bitsize > 128", .{});3197 return self.fail("todo Wasm intcast for bitsize > 128", .{});
3125 }3198 }
31263199
3127 return self.intcast(operand, operand_ty, ty);3200 return (try self.intcast(operand, operand_ty, ty)).toLocal(self, ty);
3128}3201}
31293202
3130/// Upcasts or downcasts an integer based on the given and wanted types,3203/// Upcasts or downcasts an integer based on the given and wanted types,
3131/// and stores the result in a new operand.3204/// and stores the result in a new operand.
3132/// Asserts type's bitsize <= 1283205/// Asserts type's bitsize <= 128
3206/// NOTE: May leave the result on the top of the stack.
3133fn intcast(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WValue {3207fn intcast(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WValue {
3134 const given_info = given.intInfo(self.target);3208 const given_info = given.intInfo(self.target);
3135 const wanted_info = wanted.intInfo(self.target);3209 const wanted_info = wanted.intInfo(self.target);
...@@ -3152,25 +3226,22 @@ fn intcast(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!W...@@ -3152,25 +3226,22 @@ fn intcast(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!W
3152 } else if (wanted_bits == 128) {3226 } else if (wanted_bits == 128) {
3153 // for 128bit integers we store the integer in the virtual stack, rather than a local3227 // for 128bit integers we store the integer in the virtual stack, rather than a local
3154 const stack_ptr = try self.allocStack(wanted);3228 const stack_ptr = try self.allocStack(wanted);
3229 try self.emitWValue(stack_ptr);
31553230
3156 // for 32 bit integers, we first coerce the value into a 64 bit integer before storing it3231 // for 32 bit integers, we first coerce the value into a 64 bit integer before storing it
3157 // meaning less store operations are required.3232 // meaning less store operations are required.
3158 const lhs = if (op_bits == 32) blk: {3233 const lhs = if (op_bits == 32) blk: {
3159 const tmp = try self.intcast(3234 break :blk try self.intcast(operand, given, if (wanted.isSignedInt()) Type.i64 else Type.u64);
3160 operand,
3161 given,
3162 if (wanted.isSignedInt()) Type.i64 else Type.u64,
3163 );
3164 break :blk tmp;
3165 } else operand;3235 } else operand;
31663236
3167 // store msb first3237 // store msb first
3168 try self.store(stack_ptr, lhs, Type.u64, 0);3238 try self.store(.{ .stack = {} }, lhs, Type.u64, 0 + stack_ptr.offset());
31693239
3170 // For signed integers we shift msb by 63 (64bit integer - 1 sign bit) and store remaining value3240 // For signed integers we shift msb by 63 (64bit integer - 1 sign bit) and store remaining value
3171 if (wanted.isSignedInt()) {3241 if (wanted.isSignedInt()) {
3242 try self.emitWValue(stack_ptr);
3172 const shr = try self.binOp(lhs, .{ .imm64 = 63 }, Type.i64, .shr);3243 const shr = try self.binOp(lhs, .{ .imm64 = 63 }, Type.i64, .shr);
3173 try self.store(stack_ptr, shr, Type.u64, 8);3244 try self.store(.{ .stack = {} }, shr, Type.u64, 8 + stack_ptr.offset());
3174 } else {3245 } else {
3175 // Ensure memory of lsb is zero'd3246 // Ensure memory of lsb is zero'd
3176 try self.store(stack_ptr, .{ .imm64 = 0 }, Type.u64, 8);3247 try self.store(stack_ptr, .{ .imm64 = 0 }, Type.u64, 8);
...@@ -3178,9 +3249,7 @@ fn intcast(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!W...@@ -3178,9 +3249,7 @@ fn intcast(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!W
3178 return stack_ptr;3249 return stack_ptr;
3179 } else return self.load(operand, wanted, 0);3250 } else return self.load(operand, wanted, 0);
31803251
3181 const result = try self.allocLocal(wanted);3252 return WValue{ .stack = {} };
3182 try self.addLabel(.local_set, result.local);
3183 return result;
3184}3253}
31853254
3186fn airIsNull(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode, op_kind: enum { value, ptr }) InnerError!WValue {3255fn airIsNull(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode, op_kind: enum { value, ptr }) InnerError!WValue {
...@@ -3189,9 +3258,12 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode, op_kind: en...@@ -3189,9 +3258,12 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode, op_kind: en
31893258
3190 const op_ty = self.air.typeOf(un_op);3259 const op_ty = self.air.typeOf(un_op);
3191 const optional_ty = if (op_kind == .ptr) op_ty.childType() else op_ty;3260 const optional_ty = if (op_kind == .ptr) op_ty.childType() else op_ty;
3192 return self.isNull(operand, optional_ty, opcode);3261 const is_null = try self.isNull(operand, optional_ty, opcode);
3262 return is_null.toLocal(self, optional_ty);
3193}3263}
31943264
3265/// For a given type and operand, checks if it's considered `null`.
3266/// NOTE: Leaves the result on the stack
3195fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode) InnerError!WValue {3267fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode) InnerError!WValue {
3196 try self.emitWValue(operand);3268 try self.emitWValue(operand);
3197 if (!optional_ty.optionalReprIsPayload()) {3269 if (!optional_ty.optionalReprIsPayload()) {
...@@ -3208,9 +3280,7 @@ fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode)...@@ -3208,9 +3280,7 @@ fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode)
3208 try self.addImm32(0);3280 try self.addImm32(0);
3209 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));3281 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
32103282
3211 const is_null_tmp = try self.allocLocal(Type.initTag(.i32));3283 return WValue{ .stack = {} };
3212 try self.addLabel(.local_set, is_null_tmp.local);
3213 return is_null_tmp;
3214}3284}
32153285
3216fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3286fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -3228,7 +3298,8 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3228,7 +3298,8 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3228 return self.buildPointerOffset(operand, offset, .new);3298 return self.buildPointerOffset(operand, offset, .new);
3229 }3299 }
32303300
3231 return self.load(operand, payload_ty, @intCast(u32, offset));3301 const payload = try self.load(operand, payload_ty, @intCast(u32, offset));
3302 return payload.toLocal(self, payload_ty);
3232}3303}
32333304
3234fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3305fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -3331,7 +3402,8 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3331,7 +3402,8 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3331 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3402 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3332 const operand = try self.resolveInst(ty_op.operand);3403 const operand = try self.resolveInst(ty_op.operand);
33333404
3334 return self.load(operand, Type.usize, self.ptrSize());3405 const len = try self.load(operand, Type.usize, self.ptrSize());
3406 return len.toLocal(self, Type.usize);
3335}3407}
33363408
3337fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3409fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -3345,8 +3417,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3345,8 +3417,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3345 const elem_size = elem_ty.abiSize(self.target);3417 const elem_size = elem_ty.abiSize(self.target);
33463418
3347 // load pointer onto stack3419 // load pointer onto stack
3348 const slice_ptr = try self.load(slice, Type.usize, 0);3420 _ = try self.load(slice, Type.usize, 0);
3349 try self.addLabel(.local_get, slice_ptr.local);
33503421
3351 // calculate index into slice3422 // calculate index into slice
3352 try self.emitWValue(index);3423 try self.emitWValue(index);
...@@ -3360,7 +3431,9 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3360,7 +3431,9 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3360 if (isByRef(elem_ty, self.target)) {3431 if (isByRef(elem_ty, self.target)) {
3361 return result;3432 return result;
3362 }3433 }
3363 return self.load(result, elem_ty, 0);3434
3435 const elem_val = try self.load(result, elem_ty, 0);
3436 return elem_val.toLocal(self, elem_ty);
3364}3437}
33653438
3366fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3439fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -3373,8 +3446,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3373,8 +3446,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3373 const slice = try self.resolveInst(bin_op.lhs);3446 const slice = try self.resolveInst(bin_op.lhs);
3374 const index = try self.resolveInst(bin_op.rhs);3447 const index = try self.resolveInst(bin_op.rhs);
33753448
3376 const slice_ptr = try self.load(slice, Type.usize, 0);3449 _ = try self.load(slice, Type.usize, 0);
3377 try self.addLabel(.local_get, slice_ptr.local);
33783450
3379 // calculate index into slice3451 // calculate index into slice
3380 try self.emitWValue(index);3452 try self.emitWValue(index);
...@@ -3382,7 +3454,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3382,7 +3454,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3382 try self.addTag(.i32_mul);3454 try self.addTag(.i32_mul);
3383 try self.addTag(.i32_add);3455 try self.addTag(.i32_add);
33843456
3385 const result = try self.allocLocal(Type.initTag(.i32));3457 const result = try self.allocLocal(Type.i32);
3386 try self.addLabel(.local_set, result.local);3458 try self.addLabel(.local_set, result.local);
3387 return result;3459 return result;
3388}3460}
...@@ -3391,7 +3463,8 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3391,7 +3463,8 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3391 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };3463 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
3392 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3464 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3393 const operand = try self.resolveInst(ty_op.operand);3465 const operand = try self.resolveInst(ty_op.operand);
3394 return self.load(operand, Type.usize, 0);3466 const ptr = try self.load(operand, Type.usize, 0);
3467 return ptr.toLocal(self, Type.usize);
3395}3468}
33963469
3397fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3470fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -3406,13 +3479,13 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3406,13 +3479,13 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3406 return self.fail("TODO: Implement wasm integer truncation for integer bitsize: {d}", .{int_info.bits});3479 return self.fail("TODO: Implement wasm integer truncation for integer bitsize: {d}", .{int_info.bits});
3407 }3480 }
34083481
3409 const result = try self.intcast(operand, op_ty, wanted_ty);3482 var result = try self.intcast(operand, op_ty, wanted_ty);
3410 const wanted_bits = wanted_ty.intInfo(self.target).bits;3483 const wanted_bits = wanted_ty.intInfo(self.target).bits;
3411 const wasm_bits = toWasmBits(wanted_bits).?;3484 const wasm_bits = toWasmBits(wanted_bits).?;
3412 if (wasm_bits != wanted_bits) {3485 if (wasm_bits != wanted_bits) {
3413 return self.wrapOperand(result, wanted_ty);3486 result = try self.wrapOperand(result, wanted_ty);
3414 }3487 }
3415 return result;3488 return result.toLocal(self, wanted_ty);
3416}3489}
34173490
3418fn airBoolToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3491fn airBoolToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -3465,8 +3538,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3465,8 +3538,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
34653538
3466 // load pointer onto the stack3539 // load pointer onto the stack
3467 if (ptr_ty.isSlice()) {3540 if (ptr_ty.isSlice()) {
3468 const ptr_local = try self.load(ptr, Type.usize, 0);3541 _ = try self.load(ptr, Type.usize, 0);
3469 try self.addLabel(.local_get, ptr_local.local);
3470 } else {3542 } else {
3471 try self.lowerToStack(ptr);3543 try self.lowerToStack(ptr);
3472 }3544 }
...@@ -3477,12 +3549,15 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3477,12 +3549,15 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3477 try self.addTag(.i32_mul);3549 try self.addTag(.i32_mul);
3478 try self.addTag(.i32_add);3550 try self.addTag(.i32_add);
34793551
3480 const result = try self.allocLocal(elem_ty);3552 var result = try self.allocLocal(elem_ty);
3481 try self.addLabel(.local_set, result.local);3553 try self.addLabel(.local_set, result.local);
3482 if (isByRef(elem_ty, self.target)) {3554 if (isByRef(elem_ty, self.target)) {
3483 return result;3555 return result;
3484 }3556 }
3485 return self.load(result, elem_ty, 0);3557 defer result.free(self); // only free if it's not returned like above
3558
3559 const elem_val = try self.load(result, elem_ty, 0);
3560 return elem_val.toLocal(self, elem_ty);
3486}3561}
34873562
3488fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3563fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -3498,8 +3573,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3498,8 +3573,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
34983573
3499 // load pointer onto the stack3574 // load pointer onto the stack
3500 if (ptr_ty.isSlice()) {3575 if (ptr_ty.isSlice()) {
3501 const ptr_local = try self.load(ptr, Type.usize, 0);3576 _ = try self.load(ptr, Type.usize, 0);
3502 try self.addLabel(.local_get, ptr_local.local);
3503 } else {3577 } else {
3504 try self.lowerToStack(ptr);3578 try self.lowerToStack(ptr);
3505 }3579 }
...@@ -3510,7 +3584,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3510,7 +3584,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3510 try self.addTag(.i32_mul);3584 try self.addTag(.i32_mul);
3511 try self.addTag(.i32_add);3585 try self.addTag(.i32_add);
35123586
3513 const result = try self.allocLocal(Type.initTag(.i32));3587 const result = try self.allocLocal(Type.i32);
3514 try self.addLabel(.local_set, result.local);3588 try self.addLabel(.local_set, result.local);
3515 return result;3589 return result;
3516}3590}
...@@ -3598,7 +3672,7 @@ fn memset(self: *Self, ptr: WValue, len: WValue, value: WValue) InnerError!void...@@ -3598,7 +3672,7 @@ fn memset(self: *Self, ptr: WValue, len: WValue, value: WValue) InnerError!void
3598 else => {3672 else => {
3599 // TODO: We should probably lower this to a call to compiler_rt3673 // TODO: We should probably lower this to a call to compiler_rt
3600 // But for now, we implement it manually3674 // But for now, we implement it manually
3601 const offset = try self.allocLocal(Type.usize); // local for counter3675 const offset = try self.ensureAllocLocal(Type.usize); // local for counter
3602 // outer block to jump to when loop is done3676 // outer block to jump to when loop is done
3603 try self.startBlock(.block, wasm.block_empty);3677 try self.startBlock(.block, wasm.block_empty);
3604 try self.startBlock(.loop, wasm.block_empty);3678 try self.startBlock(.loop, wasm.block_empty);
...@@ -3655,13 +3729,16 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3655,13 +3729,16 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3655 try self.addTag(.i32_mul);3729 try self.addTag(.i32_mul);
3656 try self.addTag(.i32_add);3730 try self.addTag(.i32_add);
36573731
3658 const result = try self.allocLocal(Type.usize);3732 var result = try self.allocLocal(Type.usize);
3659 try self.addLabel(.local_set, result.local);3733 try self.addLabel(.local_set, result.local);
36603734
3661 if (isByRef(elem_ty, self.target)) {3735 if (isByRef(elem_ty, self.target)) {
3662 return result;3736 return result;
3663 }3737 }
3664 return self.load(result, elem_ty, 0);3738 defer result.free(self); // only free if no longer needed and not returned like above
3739
3740 const elem_val = try self.load(result, elem_ty, 0);
3741 return elem_val.toLocal(self, elem_ty);
3665}3742}
36663743
3667fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3744fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -3684,11 +3761,8 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3684,11 +3761,8 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3684 .signedness = if (dest_ty.isSignedInt()) .signed else .unsigned,3761 .signedness = if (dest_ty.isSignedInt()) .signed else .unsigned,
3685 });3762 });
3686 try self.addTag(Mir.Inst.Tag.fromOpcode(op));3763 try self.addTag(Mir.Inst.Tag.fromOpcode(op));
36873764 const wrapped = try self.wrapOperand(.{ .stack = {} }, dest_ty);
3688 const result = try self.allocLocal(dest_ty);3765 return wrapped.toLocal(self, dest_ty);
3689 try self.addLabel(.local_set, result.local);
3690
3691 return self.wrapOperand(result, dest_ty);
3692}3766}
36933767
3694fn airIntToFloat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {3768fn airIntToFloat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -3886,24 +3960,19 @@ fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std...@@ -3886,24 +3960,19 @@ fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std
3886 const payload_ty = operand_ty.optionalChild(&buf);3960 const payload_ty = operand_ty.optionalChild(&buf);
3887 const offset = @intCast(u32, operand_ty.abiSize(self.target) - payload_ty.abiSize(self.target));3961 const offset = @intCast(u32, operand_ty.abiSize(self.target) - payload_ty.abiSize(self.target));
38883962
3889 const lhs_is_null = try self.isNull(lhs, operand_ty, .i32_eq);
3890 const rhs_is_null = try self.isNull(rhs, operand_ty, .i32_eq);
3891
3892 // We store the final result in here that will be validated3963 // We store the final result in here that will be validated
3893 // if the optional is truly equal.3964 // if the optional is truly equal.
3894 const result = try self.allocLocal(Type.initTag(.i32));3965 var result = try self.ensureAllocLocal(Type.initTag(.i32));
3966 defer result.free(self);
38953967
3896 try self.startBlock(.block, wasm.block_empty);3968 try self.startBlock(.block, wasm.block_empty);
3897 try self.emitWValue(lhs_is_null);3969 _ = try self.isNull(lhs, operand_ty, .i32_eq);
3898 try self.emitWValue(rhs_is_null);3970 _ = try self.isNull(rhs, operand_ty, .i32_eq);
3899 try self.addTag(.i32_ne); // inverse so we can exit early3971 try self.addTag(.i32_ne); // inverse so we can exit early
3900 try self.addLabel(.br_if, 0);3972 try self.addLabel(.br_if, 0);
39013973
3902 const lhs_pl = try self.load(lhs, payload_ty, offset);3974 _ = try self.load(lhs, payload_ty, offset);
3903 const rhs_pl = try self.load(rhs, payload_ty, offset);3975 _ = try self.load(rhs, payload_ty, offset);
3904
3905 try self.emitWValue(lhs_pl);
3906 try self.emitWValue(rhs_pl);
3907 const opcode = buildOpcode(.{ .op = .ne, .valtype1 = typeToValtype(payload_ty, self.target) });3976 const opcode = buildOpcode(.{ .op = .ne, .valtype1 = typeToValtype(payload_ty, self.target) });
3908 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));3977 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
3909 try self.addLabel(.br_if, 0);3978 try self.addLabel(.br_if, 0);
...@@ -3915,26 +3984,29 @@ fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std...@@ -3915,26 +3984,29 @@ fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std
3915 try self.emitWValue(result);3984 try self.emitWValue(result);
3916 try self.addImm32(0);3985 try self.addImm32(0);
3917 try self.addTag(if (op == .eq) .i32_ne else .i32_eq);3986 try self.addTag(if (op == .eq) .i32_ne else .i32_eq);
3918 try self.addLabel(.local_set, result.local);3987 return WValue{ .stack = {} };
3919 return result;
3920}3988}
39213989
3922/// Compares big integers by checking both its high bits and low bits.3990/// Compares big integers by checking both its high bits and low bits.
3991/// NOTE: Leaves the result of the comparison on top of the stack.
3923/// TODO: Lower this to compiler_rt call when bitsize > 1283992/// TODO: Lower this to compiler_rt call when bitsize > 128
3924fn cmpBigInt(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {3993fn cmpBigInt(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {
3925 assert(operand_ty.abiSize(self.target) >= 16);3994 assert(operand_ty.abiSize(self.target) >= 16);
3995 assert(!(lhs != .stack and rhs == .stack));
3926 if (operand_ty.intInfo(self.target).bits > 128) {3996 if (operand_ty.intInfo(self.target).bits > 128) {
3927 return self.fail("TODO: Support cmpBigInt for integer bitsize: '{d}'", .{operand_ty.intInfo(self.target).bits});3997 return self.fail("TODO: Support cmpBigInt for integer bitsize: '{d}'", .{operand_ty.intInfo(self.target).bits});
3928 }3998 }
39293999
3930 const lhs_high_bit = try self.load(lhs, Type.u64, 0);4000 var lhs_high_bit = try (try self.load(lhs, Type.u64, 0)).toLocal(self, Type.u64);
3931 const lhs_low_bit = try self.load(lhs, Type.u64, 8);4001 defer lhs_high_bit.free(self);
3932 const rhs_high_bit = try self.load(rhs, Type.u64, 0);4002 var rhs_high_bit = try (try self.load(rhs, Type.u64, 0)).toLocal(self, Type.u64);
3933 const rhs_low_bit = try self.load(rhs, Type.u64, 8);4003 defer rhs_high_bit.free(self);
39344004
3935 switch (op) {4005 switch (op) {
3936 .eq, .neq => {4006 .eq, .neq => {
3937 const xor_high = try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, .xor);4007 const xor_high = try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, .xor);
4008 const lhs_low_bit = try self.load(lhs, Type.u64, 8);
4009 const rhs_low_bit = try self.load(rhs, Type.u64, 8);
3938 const xor_low = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, .xor);4010 const xor_low = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, .xor);
3939 const or_result = try self.binOp(xor_high, xor_low, Type.u64, .@"or");4011 const or_result = try self.binOp(xor_high, xor_low, Type.u64, .@"or");
39404012
...@@ -3946,20 +4018,17 @@ fn cmpBigInt(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.ma...@@ -3946,20 +4018,17 @@ fn cmpBigInt(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.ma
3946 },4018 },
3947 else => {4019 else => {
3948 const ty = if (operand_ty.isSignedInt()) Type.i64 else Type.u64;4020 const ty = if (operand_ty.isSignedInt()) Type.i64 else Type.u64;
3949 const high_bit_eql = try self.cmp(lhs_high_bit, rhs_high_bit, ty, .eq);4021 // leave those value on top of the stack for '.select'
3950 const high_bit_cmp = try self.cmp(lhs_high_bit, rhs_high_bit, ty, op);4022 const lhs_low_bit = try self.load(lhs, Type.u64, 8);
3951 const low_bit_cmp = try self.cmp(lhs_low_bit, rhs_low_bit, ty, op);4023 const rhs_low_bit = try self.load(rhs, Type.u64, 8);
39524024 _ = try self.cmp(lhs_low_bit, rhs_low_bit, ty, op);
3953 try self.emitWValue(low_bit_cmp);4025 _ = try self.cmp(lhs_high_bit, rhs_high_bit, ty, op);
3954 try self.emitWValue(high_bit_cmp);4026 _ = try self.cmp(lhs_high_bit, rhs_high_bit, ty, .eq);
3955 try self.emitWValue(high_bit_eql);
3956 try self.addTag(.select);4027 try self.addTag(.select);
3957 },4028 },
3958 }4029 }
39594030
3960 const result = try self.allocLocal(Type.initTag(.i32));4031 return WValue{ .stack = {} };
3961 try self.addLabel(.local_set, result.local);
3962 return result;
3963}4032}
39644033
3965fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) InnerError!WValue {4034fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -3999,7 +4068,8 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3999,7 +4068,8 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3999 const offset = if (layout.tag_align < layout.payload_align) blk: {4068 const offset = if (layout.tag_align < layout.payload_align) blk: {
4000 break :blk @intCast(u32, layout.payload_size);4069 break :blk @intCast(u32, layout.payload_size);
4001 } else @as(u32, 0);4070 } else @as(u32, 0);
4002 return self.load(operand, tag_ty, offset);4071 const tag = try self.load(operand, tag_ty, offset);
4072 return tag.toLocal(self, tag_ty);
4003}4073}
40044074
4005fn airFpext(self: *Self, inst: Air.Inst.Index) InnerError!WValue {4075fn airFpext(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -4009,19 +4079,20 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4009,19 +4079,20 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
4009 const dest_ty = self.air.typeOfIndex(inst);4079 const dest_ty = self.air.typeOfIndex(inst);
4010 const operand = try self.resolveInst(ty_op.operand);4080 const operand = try self.resolveInst(ty_op.operand);
40114081
4012 return self.fpext(operand, self.air.typeOf(ty_op.operand), dest_ty);4082 const extended = try self.fpext(operand, self.air.typeOf(ty_op.operand), dest_ty);
4083 return extended.toLocal(self, dest_ty);
4013}4084}
40144085
4086/// Extends a float from a given `Type` to a larger wanted `Type`
4087/// NOTE: Leaves the result on the stack
4015fn fpext(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WValue {4088fn fpext(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WValue {
4016 const given_bits = given.floatBits(self.target);4089 const given_bits = given.floatBits(self.target);
4017 const wanted_bits = wanted.floatBits(self.target);4090 const wanted_bits = wanted.floatBits(self.target);
40184091
4019 if (wanted_bits == 64 and given_bits == 32) {4092 if (wanted_bits == 64 and given_bits == 32) {
4020 const result = try self.allocLocal(wanted);
4021 try self.emitWValue(operand);4093 try self.emitWValue(operand);
4022 try self.addTag(.f64_promote_f32);4094 try self.addTag(.f64_promote_f32);
4023 try self.addLabel(.local_set, result.local);4095 return WValue{ .stack = {} };
4024 return result;
4025 } else if (given_bits == 16) {4096 } else if (given_bits == 16) {
4026 // call __extendhfsf2(f16) f324097 // call __extendhfsf2(f16) f32
4027 const f32_result = try self.callIntrinsic(4098 const f32_result = try self.callIntrinsic(
...@@ -4035,11 +4106,8 @@ fn fpext(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WVa...@@ -4035,11 +4106,8 @@ fn fpext(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WVa
4035 return f32_result;4106 return f32_result;
4036 }4107 }
4037 if (wanted_bits == 64) {4108 if (wanted_bits == 64) {
4038 const result = try self.allocLocal(wanted);
4039 try self.emitWValue(f32_result);
4040 try self.addTag(.f64_promote_f32);4109 try self.addTag(.f64_promote_f32);
4041 try self.addLabel(.local_set, result.local);4110 return WValue{ .stack = {} };
4042 return result;
4043 }4111 }
4044 return self.fail("TODO: Implement 'fpext' for floats with bitsize: {d}", .{wanted_bits});4112 return self.fail("TODO: Implement 'fpext' for floats with bitsize: {d}", .{wanted_bits});
4045 } else {4113 } else {
...@@ -4054,26 +4122,25 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4054,26 +4122,25 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
4054 const ty_op = self.air.instructions.items(.data)[inst].ty_op;4122 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
4055 const dest_ty = self.air.typeOfIndex(inst);4123 const dest_ty = self.air.typeOfIndex(inst);
4056 const operand = try self.resolveInst(ty_op.operand);4124 const operand = try self.resolveInst(ty_op.operand);
4057 return self.fptrunc(operand, self.air.typeOf(ty_op.operand), dest_ty);4125 const trunc = try self.fptrunc(operand, self.air.typeOf(ty_op.operand), dest_ty);
4126 return trunc.toLocal(self, dest_ty);
4058}4127}
40594128
4129/// Truncates a float from a given `Type` to its wanted `Type`
4130/// NOTE: The result value remains on the stack
4060fn fptrunc(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WValue {4131fn fptrunc(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WValue {
4061 const given_bits = given.floatBits(self.target);4132 const given_bits = given.floatBits(self.target);
4062 const wanted_bits = wanted.floatBits(self.target);4133 const wanted_bits = wanted.floatBits(self.target);
40634134
4064 if (wanted_bits == 32 and given_bits == 64) {4135 if (wanted_bits == 32 and given_bits == 64) {
4065 const result = try self.allocLocal(wanted);
4066 try self.emitWValue(operand);4136 try self.emitWValue(operand);
4067 try self.addTag(.f32_demote_f64);4137 try self.addTag(.f32_demote_f64);
4068 try self.addLabel(.local_set, result.local);4138 return WValue{ .stack = {} };
4069 return result;
4070 } else if (wanted_bits == 16) {4139 } else if (wanted_bits == 16) {
4071 const op: WValue = if (given_bits == 64) blk: {4140 const op: WValue = if (given_bits == 64) blk: {
4072 const tmp = try self.allocLocal(Type.f32);
4073 try self.emitWValue(operand);4141 try self.emitWValue(operand);
4074 try self.addTag(.f32_demote_f64);4142 try self.addTag(.f32_demote_f64);
4075 try self.addLabel(.local_set, tmp.local);4143 break :blk WValue{ .stack = {} };
4076 break :blk tmp;
4077 } else operand;4144 } else operand;
40784145
4079 // call __truncsfhf2(f32) f164146 // call __truncsfhf2(f32) f16
...@@ -4158,12 +4225,9 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4158,12 +4225,9 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
41584225
4159 switch (wasm_bits) {4226 switch (wasm_bits) {
4160 128 => {4227 128 => {
4161 const msb = try self.load(operand, Type.u64, 0);4228 _ = try self.load(operand, Type.u64, 0);
4162 const lsb = try self.load(operand, Type.u64, 8);
4163
4164 try self.emitWValue(msb);
4165 try self.addTag(.i64_popcnt);4229 try self.addTag(.i64_popcnt);
4166 try self.emitWValue(lsb);4230 _ = try self.load(operand, Type.u64, 8);
4167 try self.addTag(.i64_popcnt);4231 try self.addTag(.i64_popcnt);
4168 try self.addTag(.i64_add);4232 try self.addTag(.i64_add);
4169 try self.addTag(.i32_wrap_i64);4233 try self.addTag(.i32_wrap_i64);
...@@ -4267,24 +4331,26 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!W...@@ -4267,24 +4331,26 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!W
42674331
4268 // for signed integers, we first apply signed shifts by the difference in bits4332 // for signed integers, we first apply signed shifts by the difference in bits
4269 // to get the signed value, as we store it internally as 2's complement.4333 // to get the signed value, as we store it internally as 2's complement.
4270 const lhs = if (wasm_bits != int_info.bits and is_signed) blk: {4334 var lhs = if (wasm_bits != int_info.bits and is_signed) blk: {
4271 break :blk try self.signAbsValue(lhs_op, lhs_ty);4335 break :blk try (try self.signAbsValue(lhs_op, lhs_ty)).toLocal(self, lhs_ty);
4272 } else lhs_op;4336 } else lhs_op;
4273 const rhs = if (wasm_bits != int_info.bits and is_signed) blk: {4337 var rhs = if (wasm_bits != int_info.bits and is_signed) blk: {
4274 break :blk try self.signAbsValue(rhs_op, lhs_ty);4338 break :blk try (try self.signAbsValue(rhs_op, lhs_ty)).toLocal(self, lhs_ty);
4275 } else rhs_op;4339 } else rhs_op;
42764340
4277 const bin_op = try self.binOp(lhs, rhs, lhs_ty, op);4341 var bin_op = try (try self.binOp(lhs, rhs, lhs_ty, op)).toLocal(self, lhs_ty);
4278 const result = if (wasm_bits != int_info.bits) blk: {4342 defer bin_op.free(self);
4279 break :blk try self.wrapOperand(bin_op, lhs_ty);4343 var result = if (wasm_bits != int_info.bits) blk: {
4344 break :blk try (try self.wrapOperand(bin_op, lhs_ty)).toLocal(self, lhs_ty);
4280 } else bin_op;4345 } else bin_op;
4346 defer result.free(self); // no-op when wasm_bits == int_info.bits
42814347
4282 const cmp_op: std.math.CompareOperator = if (op == .sub) .gt else .lt;4348 const cmp_op: std.math.CompareOperator = if (op == .sub) .gt else .lt;
4283 const overflow_bit: WValue = if (is_signed) blk: {4349 const overflow_bit: WValue = if (is_signed) blk: {
4284 if (wasm_bits == int_info.bits) {4350 if (wasm_bits == int_info.bits) {
4285 const cmp_zero = try self.cmp(rhs, zero, lhs_ty, cmp_op);4351 const cmp_zero = try self.cmp(rhs, zero, lhs_ty, cmp_op);
4286 const lt = try self.cmp(bin_op, lhs, lhs_ty, .lt);4352 const lt = try self.cmp(bin_op, lhs, lhs_ty, .lt);
4287 break :blk try self.binOp(cmp_zero, lt, Type.u32, .xor); // result of cmp_zero and lt is always 32bit4353 break :blk try self.binOp(cmp_zero, lt, Type.u32, .xor);
4288 }4354 }
4289 const abs = try self.signAbsValue(bin_op, lhs_ty);4355 const abs = try self.signAbsValue(bin_op, lhs_ty);
4290 break :blk try self.cmp(abs, bin_op, lhs_ty, .neq);4356 break :blk try self.cmp(abs, bin_op, lhs_ty, .neq);
...@@ -4292,11 +4358,22 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!W...@@ -4292,11 +4358,22 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!W
4292 try self.cmp(bin_op, lhs, lhs_ty, cmp_op)4358 try self.cmp(bin_op, lhs, lhs_ty, cmp_op)
4293 else4359 else
4294 try self.cmp(bin_op, result, lhs_ty, .neq);4360 try self.cmp(bin_op, result, lhs_ty, .neq);
4361 var overflow_local = try overflow_bit.toLocal(self, Type.u32);
4362 defer overflow_local.free(self);
42954363
4296 const result_ptr = try self.allocStack(self.air.typeOfIndex(inst));4364 const result_ptr = try self.allocStack(self.air.typeOfIndex(inst));
4297 try self.store(result_ptr, result, lhs_ty, 0);4365 try self.store(result_ptr, result, lhs_ty, 0);
4298 const offset = @intCast(u32, lhs_ty.abiSize(self.target));4366 const offset = @intCast(u32, lhs_ty.abiSize(self.target));
4299 try self.store(result_ptr, overflow_bit, Type.initTag(.u1), offset);4367 try self.store(result_ptr, overflow_local, Type.initTag(.u1), offset);
4368
4369 // in this case, we performed a signAbsValue which created a temporary local
4370 // so let's free this so it can be re-used instead.
4371 // In the other case we do not want to free it, because that would free the
4372 // resolved instructions which may be referenced by other instructions.
4373 if (wasm_bits != int_info.bits and is_signed) {
4374 lhs.free(self);
4375 rhs.free(self);
4376 }
43004377
4301 return result_ptr;4378 return result_ptr;
4302}4379}
...@@ -4309,52 +4386,58 @@ fn airAddSubWithOverflowBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type,...@@ -4309,52 +4386,58 @@ fn airAddSubWithOverflowBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type,
4309 return self.fail("TODO: Implement @{{add/sub}}WithOverflow for integer bitsize '{d}'", .{int_info.bits});4386 return self.fail("TODO: Implement @{{add/sub}}WithOverflow for integer bitsize '{d}'", .{int_info.bits});
4310 }4387 }
43114388
4312 const lhs_high_bit = try self.load(lhs, Type.u64, 0);4389 var lhs_high_bit = try (try self.load(lhs, Type.u64, 0)).toLocal(self, Type.u64);
4313 const lhs_low_bit = try self.load(lhs, Type.u64, 8);4390 defer lhs_high_bit.free(self);
4314 const rhs_high_bit = try self.load(rhs, Type.u64, 0);4391 var lhs_low_bit = try (try self.load(lhs, Type.u64, 8)).toLocal(self, Type.u64);
4315 const rhs_low_bit = try self.load(rhs, Type.u64, 8);4392 defer lhs_low_bit.free(self);
4393 var rhs_high_bit = try (try self.load(rhs, Type.u64, 0)).toLocal(self, Type.u64);
4394 defer rhs_high_bit.free(self);
4395 var rhs_low_bit = try (try self.load(rhs, Type.u64, 8)).toLocal(self, Type.u64);
4396 defer rhs_low_bit.free(self);
43164397
4317 const low_op_res = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op);4398 var low_op_res = try (try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, op)).toLocal(self, Type.u64);
4318 const high_op_res = try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op);4399 defer low_op_res.free(self);
4400 var high_op_res = try (try self.binOp(lhs_high_bit, rhs_high_bit, Type.u64, op)).toLocal(self, Type.u64);
4401 defer high_op_res.free(self);
43194402
4320 const lt = if (op == .add) blk: {4403 var lt = if (op == .add) blk: {
4321 break :blk try self.cmp(high_op_res, lhs_high_bit, Type.u64, .lt);4404 break :blk try (try self.cmp(high_op_res, lhs_high_bit, Type.u64, .lt)).toLocal(self, Type.u32);
4322 } else if (op == .sub) blk: {4405 } else if (op == .sub) blk: {
4323 break :blk try self.cmp(lhs_high_bit, rhs_high_bit, Type.u64, .lt);4406 break :blk try (try self.cmp(lhs_high_bit, rhs_high_bit, Type.u64, .lt)).toLocal(self, Type.u32);
4324 } else unreachable;4407 } else unreachable;
4325 const tmp = try self.intcast(lt, Type.u32, Type.u64);4408 defer lt.free(self);
4326 const tmp_op = try self.binOp(low_op_res, tmp, Type.u64, op);4409 var tmp = try (try self.intcast(lt, Type.u32, Type.u64)).toLocal(self, Type.u64);
4410 defer tmp.free(self);
4411 var tmp_op = try (try self.binOp(low_op_res, tmp, Type.u64, op)).toLocal(self, Type.u64);
4412 defer tmp_op.free(self);
43274413
4328 const overflow_bit = if (is_signed) blk: {4414 const overflow_bit = if (is_signed) blk: {
4329 const xor_op = try self.binOp(lhs_low_bit, tmp_op, Type.u64, .xor);
4330 const xor_low = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, .xor);4415 const xor_low = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, .xor);
4331 const to_wrap = if (op == .add) wrap: {4416 const to_wrap = if (op == .add) wrap: {
4332 break :wrap try self.binOp(xor_low, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor);4417 break :wrap try self.binOp(xor_low, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor);
4333 } else xor_low;4418 } else xor_low;
4419 const xor_op = try self.binOp(lhs_low_bit, tmp_op, Type.u64, .xor);
4334 const wrap = try self.binOp(to_wrap, xor_op, Type.u64, .@"and");4420 const wrap = try self.binOp(to_wrap, xor_op, Type.u64, .@"and");
4335 break :blk try self.cmp(wrap, .{ .imm64 = 0 }, Type.i64, .lt); // i64 because signed4421 break :blk try self.cmp(wrap, .{ .imm64 = 0 }, Type.i64, .lt); // i64 because signed
4336 } else blk: {4422 } else blk: {
4337 const eq = try self.cmp(tmp_op, lhs_low_bit, Type.u64, .eq);
4338 const op_eq = try self.cmp(tmp_op, lhs_low_bit, Type.u64, if (op == .add) .lt else .gt);
4339
4340 const first_arg = if (op == .sub) arg: {4423 const first_arg = if (op == .sub) arg: {
4341 break :arg try self.cmp(high_op_res, lhs_high_bit, Type.u64, .gt);4424 break :arg try self.cmp(high_op_res, lhs_high_bit, Type.u64, .gt);
4342 } else lt;4425 } else lt;
43434426
4344 try self.emitWValue(first_arg);4427 try self.emitWValue(first_arg);
4345 try self.emitWValue(op_eq);4428 _ = try self.cmp(tmp_op, lhs_low_bit, Type.u64, if (op == .add) .lt else .gt);
4346 try self.emitWValue(eq);4429 _ = try self.cmp(tmp_op, lhs_low_bit, Type.u64, .eq);
4347 try self.addTag(.select);4430 try self.addTag(.select);
43484431
4349 const overflow_bit = try self.allocLocal(Type.initTag(.u1));4432 break :blk WValue{ .stack = {} };
4350 try self.addLabel(.local_set, overflow_bit.local);
4351 break :blk overflow_bit;
4352 };4433 };
4434 var overflow_local = try overflow_bit.toLocal(self, Type.initTag(.u1));
4435 defer overflow_local.free(self);
43534436
4354 const result_ptr = try self.allocStack(result_ty);4437 const result_ptr = try self.allocStack(result_ty);
4355 try self.store(result_ptr, high_op_res, Type.u64, 0);4438 try self.store(result_ptr, high_op_res, Type.u64, 0);
4356 try self.store(result_ptr, tmp_op, Type.u64, 8);4439 try self.store(result_ptr, tmp_op, Type.u64, 8);
4357 try self.store(result_ptr, overflow_bit, Type.initTag(.u1), 16);4440 try self.store(result_ptr, overflow_local, Type.initTag(.u1), 16);
43584441
4359 return result_ptr;4442 return result_ptr;
4360}4443}
...@@ -4376,24 +4459,31 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4376,24 +4459,31 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
4376 return self.fail("TODO: Implement shl_with_overflow for integer bitsize: {d}", .{int_info.bits});4459 return self.fail("TODO: Implement shl_with_overflow for integer bitsize: {d}", .{int_info.bits});
4377 };4460 };
43784461
4379 const shl = try self.binOp(lhs, rhs, lhs_ty, .shl);4462 var shl = try (try self.binOp(lhs, rhs, lhs_ty, .shl)).toLocal(self, lhs_ty);
4380 const result = if (wasm_bits != int_info.bits) blk: {4463 defer shl.free(self);
4381 break :blk try self.wrapOperand(shl, lhs_ty);4464 var result = if (wasm_bits != int_info.bits) blk: {
4465 break :blk try (try self.wrapOperand(shl, lhs_ty)).toLocal(self, lhs_ty);
4382 } else shl;4466 } else shl;
4467 defer result.free(self); // it's a no-op to free the same local twice (when wasm_bits == int_info.bits)
43834468
4384 const overflow_bit = if (wasm_bits != int_info.bits and is_signed) blk: {4469 const overflow_bit = if (wasm_bits != int_info.bits and is_signed) blk: {
4470 // emit lhs to stack to we can keep 'wrapped' on the stack also
4471 try self.emitWValue(lhs);
4385 const abs = try self.signAbsValue(shl, lhs_ty);4472 const abs = try self.signAbsValue(shl, lhs_ty);
4386 const wrapped = try self.wrapBinOp(abs, rhs, lhs_ty, .shr);4473 const wrapped = try self.wrapBinOp(abs, rhs, lhs_ty, .shr);
4387 break :blk try self.cmp(lhs, wrapped, lhs_ty, .neq);4474 break :blk try self.cmp(.{ .stack = {} }, wrapped, lhs_ty, .neq);
4388 } else blk: {4475 } else blk: {
4476 try self.emitWValue(lhs);
4389 const shr = try self.binOp(result, rhs, lhs_ty, .shr);4477 const shr = try self.binOp(result, rhs, lhs_ty, .shr);
4390 break :blk try self.cmp(lhs, shr, lhs_ty, .neq);4478 break :blk try self.cmp(.{ .stack = {} }, shr, lhs_ty, .neq);
4391 };4479 };
4480 var overflow_local = try overflow_bit.toLocal(self, Type.initTag(.u1));
4481 defer overflow_local.free(self);
43924482
4393 const result_ptr = try self.allocStack(self.air.typeOfIndex(inst));4483 const result_ptr = try self.allocStack(self.air.typeOfIndex(inst));
4394 try self.store(result_ptr, result, lhs_ty, 0);4484 try self.store(result_ptr, result, lhs_ty, 0);
4395 const offset = @intCast(u32, lhs_ty.abiSize(self.target));4485 const offset = @intCast(u32, lhs_ty.abiSize(self.target));
4396 try self.store(result_ptr, overflow_bit, Type.initTag(.u1), offset);4486 try self.store(result_ptr, overflow_local, Type.initTag(.u1), offset);
43974487
4398 return result_ptr;4488 return result_ptr;
4399}4489}
...@@ -4411,7 +4501,9 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4411,7 +4501,9 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
44114501
4412 // We store the bit if it's overflowed or not in this. As it's zero-initialized4502 // We store the bit if it's overflowed or not in this. As it's zero-initialized
4413 // we only need to update it if an overflow (or underflow) occurred.4503 // we only need to update it if an overflow (or underflow) occurred.
4414 const overflow_bit = try self.allocLocal(Type.initTag(.u1));4504 var overflow_bit = try self.ensureAllocLocal(Type.initTag(.u1));
4505 defer overflow_bit.free(self);
4506
4415 const int_info = lhs_ty.intInfo(self.target);4507 const int_info = lhs_ty.intInfo(self.target);
4416 const wasm_bits = toWasmBits(int_info.bits) orelse {4508 const wasm_bits = toWasmBits(int_info.bits) orelse {
4417 return self.fail("TODO: Implement overflow arithmetic for integer bitsize: {d}", .{int_info.bits});4509 return self.fail("TODO: Implement overflow arithmetic for integer bitsize: {d}", .{int_info.bits});
...@@ -4432,49 +4524,49 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4432,49 +4524,49 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
4432 const new_ty = if (int_info.signedness == .signed) Type.i64 else Type.u64;4524 const new_ty = if (int_info.signedness == .signed) Type.i64 else Type.u64;
4433 const lhs_upcast = try self.intcast(lhs, lhs_ty, new_ty);4525 const lhs_upcast = try self.intcast(lhs, lhs_ty, new_ty);
4434 const rhs_upcast = try self.intcast(rhs, lhs_ty, new_ty);4526 const rhs_upcast = try self.intcast(rhs, lhs_ty, new_ty);
4435 const bin_op = try self.binOp(lhs_upcast, rhs_upcast, new_ty, .mul);4527 const bin_op = try (try self.binOp(lhs_upcast, rhs_upcast, new_ty, .mul)).toLocal(self, new_ty);
4436 if (int_info.signedness == .unsigned) {4528 if (int_info.signedness == .unsigned) {
4437 const shr = try self.binOp(bin_op, .{ .imm64 = int_info.bits }, new_ty, .shr);4529 const shr = try self.binOp(bin_op, .{ .imm64 = int_info.bits }, new_ty, .shr);
4438 const wrap = try self.intcast(shr, new_ty, lhs_ty);4530 const wrap = try self.intcast(shr, new_ty, lhs_ty);
4439 const cmp_res = try self.cmp(wrap, zero, lhs_ty, .neq);4531 _ = try self.cmp(wrap, zero, lhs_ty, .neq);
4440 try self.emitWValue(cmp_res);
4441 try self.addLabel(.local_set, overflow_bit.local);4532 try self.addLabel(.local_set, overflow_bit.local);
4442 break :blk try self.intcast(bin_op, new_ty, lhs_ty);4533 break :blk try self.intcast(bin_op, new_ty, lhs_ty);
4443 } else {4534 } else {
4444 const down_cast = try self.intcast(bin_op, new_ty, lhs_ty);4535 const down_cast = try (try self.intcast(bin_op, new_ty, lhs_ty)).toLocal(self, lhs_ty);
4445 const shr = try self.binOp(down_cast, .{ .imm32 = int_info.bits - 1 }, lhs_ty, .shr);4536 var shr = try (try self.binOp(down_cast, .{ .imm32 = int_info.bits - 1 }, lhs_ty, .shr)).toLocal(self, lhs_ty);
4537 defer shr.free(self);
44464538
4447 const shr_res = try self.binOp(bin_op, .{ .imm64 = int_info.bits }, new_ty, .shr);4539 const shr_res = try self.binOp(bin_op, .{ .imm64 = int_info.bits }, new_ty, .shr);
4448 const down_shr_res = try self.intcast(shr_res, new_ty, lhs_ty);4540 const down_shr_res = try self.intcast(shr_res, new_ty, lhs_ty);
4449 const cmp_res = try self.cmp(down_shr_res, shr, lhs_ty, .neq);4541 _ = try self.cmp(down_shr_res, shr, lhs_ty, .neq);
4450 try self.emitWValue(cmp_res);
4451 try self.addLabel(.local_set, overflow_bit.local);4542 try self.addLabel(.local_set, overflow_bit.local);
4452 break :blk down_cast;4543 break :blk down_cast;
4453 }4544 }
4454 } else if (int_info.signedness == .signed) blk: {4545 } else if (int_info.signedness == .signed) blk: {
4455 const lhs_abs = try self.signAbsValue(lhs, lhs_ty);4546 const lhs_abs = try self.signAbsValue(lhs, lhs_ty);
4456 const rhs_abs = try self.signAbsValue(rhs, lhs_ty);4547 const rhs_abs = try self.signAbsValue(rhs, lhs_ty);
4457 const bin_op = try self.binOp(lhs_abs, rhs_abs, lhs_ty, .mul);4548 const bin_op = try (try self.binOp(lhs_abs, rhs_abs, lhs_ty, .mul)).toLocal(self, lhs_ty);
4458 const mul_abs = try self.signAbsValue(bin_op, lhs_ty);4549 const mul_abs = try self.signAbsValue(bin_op, lhs_ty);
4459 const cmp_op = try self.cmp(mul_abs, bin_op, lhs_ty, .neq);4550 _ = try self.cmp(mul_abs, bin_op, lhs_ty, .neq);
4460 try self.emitWValue(cmp_op);
4461 try self.addLabel(.local_set, overflow_bit.local);4551 try self.addLabel(.local_set, overflow_bit.local);
4462 break :blk try self.wrapOperand(bin_op, lhs_ty);4552 break :blk try self.wrapOperand(bin_op, lhs_ty);
4463 } else blk: {4553 } else blk: {
4464 const bin_op = try self.binOp(lhs, rhs, lhs_ty, .mul);4554 var bin_op = try (try self.binOp(lhs, rhs, lhs_ty, .mul)).toLocal(self, lhs_ty);
4555 defer bin_op.free(self);
4465 const shift_imm = if (wasm_bits == 32)4556 const shift_imm = if (wasm_bits == 32)
4466 WValue{ .imm32 = int_info.bits }4557 WValue{ .imm32 = int_info.bits }
4467 else4558 else
4468 WValue{ .imm64 = int_info.bits };4559 WValue{ .imm64 = int_info.bits };
4469 const shr = try self.binOp(bin_op, shift_imm, lhs_ty, .shr);4560 const shr = try self.binOp(bin_op, shift_imm, lhs_ty, .shr);
4470 const cmp_op = try self.cmp(shr, zero, lhs_ty, .neq);4561 _ = try self.cmp(shr, zero, lhs_ty, .neq);
4471 try self.emitWValue(cmp_op);
4472 try self.addLabel(.local_set, overflow_bit.local);4562 try self.addLabel(.local_set, overflow_bit.local);
4473 break :blk try self.wrapOperand(bin_op, lhs_ty);4563 break :blk try self.wrapOperand(bin_op, lhs_ty);
4474 };4564 };
4565 var bin_op_local = try bin_op.toLocal(self, lhs_ty);
4566 defer bin_op_local.free(self);
44754567
4476 const result_ptr = try self.allocStack(self.air.typeOfIndex(inst));4568 const result_ptr = try self.allocStack(self.air.typeOfIndex(inst));
4477 try self.store(result_ptr, bin_op, lhs_ty, 0);4569 try self.store(result_ptr, bin_op_local, lhs_ty, 0);
4478 const offset = @intCast(u32, lhs_ty.abiSize(self.target));4570 const offset = @intCast(u32, lhs_ty.abiSize(self.target));
4479 try self.store(result_ptr, overflow_bit, Type.initTag(.u1), offset);4571 try self.store(result_ptr, overflow_bit, Type.initTag(.u1), offset);
44804572
...@@ -4496,12 +4588,10 @@ fn airMaxMin(self: *Self, inst: Air.Inst.Index, op: enum { max, min }) InnerErro...@@ -4496,12 +4588,10 @@ fn airMaxMin(self: *Self, inst: Air.Inst.Index, op: enum { max, min }) InnerErro
4496 const lhs = try self.resolveInst(bin_op.lhs);4588 const lhs = try self.resolveInst(bin_op.lhs);
4497 const rhs = try self.resolveInst(bin_op.rhs);4589 const rhs = try self.resolveInst(bin_op.rhs);
44984590
4499 const cmp_result = try self.cmp(lhs, rhs, ty, if (op == .max) .gt else .lt);
4500
4501 // operands to select from4591 // operands to select from
4502 try self.lowerToStack(lhs);4592 try self.lowerToStack(lhs);
4503 try self.lowerToStack(rhs);4593 try self.lowerToStack(rhs);
4504 try self.emitWValue(cmp_result);4594 _ = try self.cmp(lhs, rhs, ty, if (op == .max) .gt else .lt);
45054595
4506 // based on the result from comparison, return operand 0 or 1.4596 // based on the result from comparison, return operand 0 or 1.
4507 try self.addTag(.select);4597 try self.addTag(.select);
...@@ -4527,21 +4617,21 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4527,21 +4617,21 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
4527 const rhs = try self.resolveInst(bin_op.rhs);4617 const rhs = try self.resolveInst(bin_op.rhs);
45284618
4529 if (ty.floatBits(self.target) == 16) {4619 if (ty.floatBits(self.target) == 16) {
4530 const addend_ext = try self.fpext(addend, ty, Type.f32);
4531 const lhs_ext = try self.fpext(lhs, ty, Type.f32);
4532 const rhs_ext = try self.fpext(rhs, ty, Type.f32);4620 const rhs_ext = try self.fpext(rhs, ty, Type.f32);
4621 const lhs_ext = try self.fpext(lhs, ty, Type.f32);
4622 const addend_ext = try self.fpext(addend, ty, Type.f32);
4533 // call to compiler-rt `fn fmaf(f32, f32, f32) f32`4623 // call to compiler-rt `fn fmaf(f32, f32, f32) f32`
4534 const result = try self.callIntrinsic(4624 var result = try self.callIntrinsic(
4535 "fmaf",4625 "fmaf",
4536 &.{ Type.f32, Type.f32, Type.f32 },4626 &.{ Type.f32, Type.f32, Type.f32 },
4537 Type.f32,4627 Type.f32,
4538 &.{ rhs_ext, lhs_ext, addend_ext },4628 &.{ rhs_ext, lhs_ext, addend_ext },
4539 );4629 );
4540 return try self.fptrunc(result, Type.f32, ty);4630 return try (try self.fptrunc(result, Type.f32, ty)).toLocal(self, ty);
4541 }4631 }
45424632
4543 const mul_result = try self.binOp(lhs, rhs, ty, .mul);4633 const mul_result = try self.binOp(lhs, rhs, ty, .mul);
4544 return self.binOp(mul_result, addend, ty, .add);4634 return (try self.binOp(mul_result, addend, ty, .add)).toLocal(self, ty);
4545}4635}
45464636
4547fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {4637fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -4570,17 +4660,16 @@ fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4570,17 +4660,16 @@ fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
4570 try self.addTag(.i32_wrap_i64);4660 try self.addTag(.i32_wrap_i64);
4571 },4661 },
4572 128 => {4662 128 => {
4573 const msb = try self.load(operand, Type.u64, 0);4663 var lsb = try (try self.load(operand, Type.u64, 8)).toLocal(self, Type.u64);
4574 const lsb = try self.load(operand, Type.u64, 8);4664 defer lsb.free(self);
4575 const neq = try self.cmp(lsb, .{ .imm64 = 0 }, Type.u64, .neq);
45764665
4577 try self.emitWValue(lsb);4666 try self.emitWValue(lsb);
4578 try self.addTag(.i64_clz);4667 try self.addTag(.i64_clz);
4579 try self.emitWValue(msb);4668 _ = try self.load(operand, Type.u64, 0);
4580 try self.addTag(.i64_clz);4669 try self.addTag(.i64_clz);
4581 try self.emitWValue(.{ .imm64 = 64 });4670 try self.emitWValue(.{ .imm64 = 64 });
4582 try self.addTag(.i64_add);4671 try self.addTag(.i64_add);
4583 try self.emitWValue(neq);4672 _ = try self.cmp(lsb, .{ .imm64 = 0 }, Type.u64, .neq);
4584 try self.addTag(.select);4673 try self.addTag(.select);
4585 try self.addTag(.i32_wrap_i64);4674 try self.addTag(.i32_wrap_i64);
4586 },4675 },
...@@ -4617,28 +4706,27 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4617,28 +4706,27 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
4617 32 => {4706 32 => {
4618 if (wasm_bits != int_info.bits) {4707 if (wasm_bits != int_info.bits) {
4619 const val: u32 = @as(u32, 1) << @intCast(u5, int_info.bits);4708 const val: u32 = @as(u32, 1) << @intCast(u5, int_info.bits);
4620 const bin_op = try self.binOp(operand, .{ .imm32 = val }, ty, .@"or");4709 // leave value on the stack
4621 try self.emitWValue(bin_op);4710 _ = try self.binOp(operand, .{ .imm32 = val }, ty, .@"or");
4622 } else try self.emitWValue(operand);4711 } else try self.emitWValue(operand);
4623 try self.addTag(.i32_ctz);4712 try self.addTag(.i32_ctz);
4624 },4713 },
4625 64 => {4714 64 => {
4626 if (wasm_bits != int_info.bits) {4715 if (wasm_bits != int_info.bits) {
4627 const val: u64 = @as(u64, 1) << @intCast(u6, int_info.bits);4716 const val: u64 = @as(u64, 1) << @intCast(u6, int_info.bits);
4628 const bin_op = try self.binOp(operand, .{ .imm64 = val }, ty, .@"or");4717 // leave value on the stack
4629 try self.emitWValue(bin_op);4718 _ = try self.binOp(operand, .{ .imm64 = val }, ty, .@"or");
4630 } else try self.emitWValue(operand);4719 } else try self.emitWValue(operand);
4631 try self.addTag(.i64_ctz);4720 try self.addTag(.i64_ctz);
4632 try self.addTag(.i32_wrap_i64);4721 try self.addTag(.i32_wrap_i64);
4633 },4722 },
4634 128 => {4723 128 => {
4635 const msb = try self.load(operand, Type.u64, 0);4724 var msb = try (try self.load(operand, Type.u64, 0)).toLocal(self, Type.u64);
4636 const lsb = try self.load(operand, Type.u64, 8);4725 defer msb.free(self);
4637 const neq = try self.cmp(msb, .{ .imm64 = 0 }, Type.u64, .neq);
46384726
4639 try self.emitWValue(msb);4727 try self.emitWValue(msb);
4640 try self.addTag(.i64_ctz);4728 try self.addTag(.i64_ctz);
4641 try self.emitWValue(lsb);4729 _ = try self.load(operand, Type.u64, 8);
4642 if (wasm_bits != int_info.bits) {4730 if (wasm_bits != int_info.bits) {
4643 try self.addImm64(@as(u64, 1) << @intCast(u6, int_info.bits - 64));4731 try self.addImm64(@as(u64, 1) << @intCast(u6, int_info.bits - 64));
4644 try self.addTag(.i64_or);4732 try self.addTag(.i64_or);
...@@ -4650,7 +4738,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4650,7 +4738,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
4650 } else {4738 } else {
4651 try self.addTag(.i64_add);4739 try self.addTag(.i64_add);
4652 }4740 }
4653 try self.emitWValue(neq);4741 _ = try self.cmp(msb, .{ .imm64 = 0 }, Type.u64, .neq);
4654 try self.addTag(.select);4742 try self.addTag(.select);
4655 try self.addTag(.i32_wrap_i64);4743 try self.addTag(.i32_wrap_i64);
4656 },4744 },
...@@ -4776,7 +4864,8 @@ fn lowerTry(...@@ -4776,7 +4864,8 @@ fn lowerTry(
4776 if (isByRef(pl_ty, self.target)) {4864 if (isByRef(pl_ty, self.target)) {
4777 return buildPointerOffset(self, err_union, pl_offset, .new);4865 return buildPointerOffset(self, err_union, pl_offset, .new);
4778 }4866 }
4779 return self.load(err_union, pl_ty, pl_offset);4867 const payload = try self.load(err_union, pl_ty, pl_offset);
4868 return payload.toLocal(self, pl_ty);
4780}4869}
47814870
4782fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue {4871fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -4806,11 +4895,11 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4806,11 +4895,11 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
4806 const res = if (int_info.signedness == .signed) blk: {4895 const res = if (int_info.signedness == .signed) blk: {
4807 break :blk try self.wrapOperand(shr_res, Type.u8);4896 break :blk try self.wrapOperand(shr_res, Type.u8);
4808 } else shr_res;4897 } else shr_res;
4809 return self.binOp(lhs, res, ty, .@"or");4898 return (try self.binOp(lhs, res, ty, .@"or")).toLocal(self, ty);
4810 },4899 },
4811 24 => {4900 24 => {
4812 const msb = try self.wrapOperand(operand, Type.u16);4901 var msb = try (try self.wrapOperand(operand, Type.u16)).toLocal(self, Type.u16);
4813 const lsb = try self.wrapBinOp(operand, .{ .imm32 = 16 }, Type.u8, .shr);4902 defer msb.free(self);
48144903
4815 const shl_res = try self.binOp(msb, .{ .imm32 = 8 }, Type.u16, .shl);4904 const shl_res = try self.binOp(msb, .{ .imm32 = 8 }, Type.u16, .shl);
4816 const lhs = try self.binOp(shl_res, .{ .imm32 = 0xFF0000 }, Type.u16, .@"and");4905 const lhs = try self.binOp(shl_res, .{ .imm32 = 0xFF0000 }, Type.u16, .@"and");
...@@ -4824,22 +4913,26 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4824,22 +4913,26 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
4824 const rhs_wrap = try self.wrapOperand(msb, Type.u8);4913 const rhs_wrap = try self.wrapOperand(msb, Type.u8);
4825 const rhs_result = try self.binOp(rhs_wrap, .{ .imm32 = 16 }, ty, .shl);4914 const rhs_result = try self.binOp(rhs_wrap, .{ .imm32 = 16 }, ty, .shl);
48264915
4916 const lsb = try self.wrapBinOp(operand, .{ .imm32 = 16 }, Type.u8, .shr);
4827 const tmp = try self.binOp(lhs_result, rhs_result, ty, .@"or");4917 const tmp = try self.binOp(lhs_result, rhs_result, ty, .@"or");
4828 return self.binOp(tmp, lsb, ty, .@"or");4918 return (try self.binOp(tmp, lsb, ty, .@"or")).toLocal(self, ty);
4829 },4919 },
4830 32 => {4920 32 => {
4831 const shl_tmp = try self.binOp(operand, .{ .imm32 = 8 }, ty, .shl);4921 const shl_tmp = try self.binOp(operand, .{ .imm32 = 8 }, ty, .shl);
4832 const lhs = try self.binOp(shl_tmp, .{ .imm32 = 0xFF00FF00 }, ty, .@"and");4922 var lhs = try (try self.binOp(shl_tmp, .{ .imm32 = 0xFF00FF00 }, ty, .@"and")).toLocal(self, ty);
4923 defer lhs.free(self);
4833 const shr_tmp = try self.binOp(operand, .{ .imm32 = 8 }, ty, .shr);4924 const shr_tmp = try self.binOp(operand, .{ .imm32 = 8 }, ty, .shr);
4834 const rhs = try self.binOp(shr_tmp, .{ .imm32 = 0xFF00FF }, ty, .@"and");4925 var rhs = try (try self.binOp(shr_tmp, .{ .imm32 = 0xFF00FF }, ty, .@"and")).toLocal(self, ty);
4835 const tmp_or = try self.binOp(lhs, rhs, ty, .@"or");4926 defer rhs.free(self);
4927 var tmp_or = try (try self.binOp(lhs, rhs, ty, .@"or")).toLocal(self, ty);
4928 defer tmp_or.free(self);
48364929
4837 const shl = try self.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shl);4930 const shl = try self.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shl);
4838 const shr = try self.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shr);4931 const shr = try self.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shr);
4839 const res = if (int_info.signedness == .signed) blk: {4932 const res = if (int_info.signedness == .signed) blk: {
4840 break :blk try self.wrapOperand(shr, Type.u16);4933 break :blk try self.wrapOperand(shr, Type.u16);
4841 } else shr;4934 } else shr;
4842 return self.binOp(shl, res, ty, .@"or");4935 return (try self.binOp(shl, res, ty, .@"or")).toLocal(self, ty);
4843 },4936 },
4844 else => return self.fail("TODO: @byteSwap for integers with bitsize {d}", .{int_info.bits}),4937 else => return self.fail("TODO: @byteSwap for integers with bitsize {d}", .{int_info.bits}),
4845 }4938 }
...@@ -4856,7 +4949,7 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4856,7 +4949,7 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
4856 if (ty.isSignedInt()) {4949 if (ty.isSignedInt()) {
4857 return self.divSigned(lhs, rhs, ty);4950 return self.divSigned(lhs, rhs, ty);
4858 }4951 }
4859 return self.binOp(lhs, rhs, ty, .div);4952 return (try self.binOp(lhs, rhs, ty, .div)).toLocal(self, ty);
4860}4953}
48614954
4862fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue {4955fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -4868,33 +4961,31 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4868,33 +4961,31 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
4868 const rhs = try self.resolveInst(bin_op.rhs);4961 const rhs = try self.resolveInst(bin_op.rhs);
48694962
4870 if (ty.isUnsignedInt()) {4963 if (ty.isUnsignedInt()) {
4871 return self.binOp(lhs, rhs, ty, .div);4964 return (try self.binOp(lhs, rhs, ty, .div)).toLocal(self, ty);
4872 } else if (ty.isSignedInt()) {4965 } else if (ty.isSignedInt()) {
4873 const int_bits = ty.intInfo(self.target).bits;4966 const int_bits = ty.intInfo(self.target).bits;
4874 const wasm_bits = toWasmBits(int_bits) orelse {4967 const wasm_bits = toWasmBits(int_bits) orelse {
4875 return self.fail("TODO: `@divFloor` for signed integers larger than '{d}' bits", .{int_bits});4968 return self.fail("TODO: `@divFloor` for signed integers larger than '{d}' bits", .{int_bits});
4876 };4969 };
4877 const lhs_res = if (wasm_bits != int_bits) blk: {4970 const lhs_res = if (wasm_bits != int_bits) blk: {
4878 break :blk try self.signAbsValue(lhs, ty);4971 break :blk try (try self.signAbsValue(lhs, ty)).toLocal(self, ty);
4879 } else lhs;4972 } else lhs;
4880 const rhs_res = if (wasm_bits != int_bits) blk: {4973 const rhs_res = if (wasm_bits != int_bits) blk: {
4881 break :blk try self.signAbsValue(rhs, ty);4974 break :blk try (try self.signAbsValue(rhs, ty)).toLocal(self, ty);
4882 } else rhs;4975 } else rhs;
48834976
4884 const div_result = try self.binOp(lhs_res, rhs_res, ty, .div);
4885 const rem_result = try self.binOp(lhs_res, rhs_res, ty, .rem);
4886
4887 const zero = switch (wasm_bits) {4977 const zero = switch (wasm_bits) {
4888 32 => WValue{ .imm32 = 0 },4978 32 => WValue{ .imm32 = 0 },
4889 64 => WValue{ .imm64 = 0 },4979 64 => WValue{ .imm64 = 0 },
4890 else => unreachable,4980 else => unreachable,
4891 };4981 };
4892 const lhs_less_than_zero = try self.cmp(lhs_res, zero, ty, .lt);
4893 const rhs_less_than_zero = try self.cmp(rhs_res, zero, ty, .lt);
48944982
4895 try self.emitWValue(div_result);4983 const div_result = try self.allocLocal(ty);
4896 try self.emitWValue(lhs_less_than_zero);4984 // leave on stack
4897 try self.emitWValue(rhs_less_than_zero);4985 _ = try self.binOp(lhs_res, rhs_res, ty, .div);
4986 try self.addLabel(.local_tee, div_result.local);
4987 _ = try self.cmp(lhs_res, zero, ty, .lt);
4988 _ = try self.cmp(rhs_res, zero, ty, .lt);
4898 switch (wasm_bits) {4989 switch (wasm_bits) {
4899 32 => {4990 32 => {
4900 try self.addTag(.i32_xor);4991 try self.addTag(.i32_xor);
...@@ -4907,7 +4998,8 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4907,7 +4998,8 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
4907 else => unreachable,4998 else => unreachable,
4908 }4999 }
4909 try self.emitWValue(div_result);5000 try self.emitWValue(div_result);
4910 try self.emitWValue(rem_result);5001 // leave value on the stack
5002 _ = try self.binOp(lhs_res, rhs_res, ty, .rem);
4911 try self.addTag(.select);5003 try self.addTag(.select);
4912 } else {5004 } else {
4913 const float_bits = ty.floatBits(self.target);5005 const float_bits = ty.floatBits(self.target);
...@@ -4939,9 +5031,7 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -4939,9 +5031,7 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
4939 }5031 }
49405032
4941 if (is_f16) {5033 if (is_f16) {
4942 // we can re-use temporary local5034 _ = try self.fptrunc(.{ .stack = {} }, Type.f32, Type.f16);
4943 try self.addLabel(.local_set, lhs_operand.local);
4944 return self.fptrunc(lhs_operand, Type.f32, Type.f16);
4945 }5035 }
4946 }5036 }
49475037
...@@ -4961,10 +5051,9 @@ fn divSigned(self: *Self, lhs: WValue, rhs: WValue, ty: Type) InnerError!WValue...@@ -4961,10 +5051,9 @@ fn divSigned(self: *Self, lhs: WValue, rhs: WValue, ty: Type) InnerError!WValue
4961 }5051 }
49625052
4963 if (wasm_bits != int_bits) {5053 if (wasm_bits != int_bits) {
4964 const lhs_abs = try self.signAbsValue(lhs, ty);5054 // Leave both values on the stack
4965 const rhs_abs = try self.signAbsValue(rhs, ty);5055 _ = try self.signAbsValue(lhs, ty);
4966 try self.emitWValue(lhs_abs);5056 _ = try self.signAbsValue(rhs, ty);
4967 try self.emitWValue(rhs_abs);
4968 } else {5057 } else {
4969 try self.emitWValue(lhs);5058 try self.emitWValue(lhs);
4970 try self.emitWValue(rhs);5059 try self.emitWValue(rhs);
...@@ -4976,6 +5065,8 @@ fn divSigned(self: *Self, lhs: WValue, rhs: WValue, ty: Type) InnerError!WValue...@@ -4976,6 +5065,8 @@ fn divSigned(self: *Self, lhs: WValue, rhs: WValue, ty: Type) InnerError!WValue
4976 return result;5065 return result;
4977}5066}
49785067
5068/// Retrieves the absolute value of a signed integer
5069/// NOTE: Leaves the result value on the stack.
4979fn signAbsValue(self: *Self, operand: WValue, ty: Type) InnerError!WValue {5070fn signAbsValue(self: *Self, operand: WValue, ty: Type) InnerError!WValue {
4980 const int_bits = ty.intInfo(self.target).bits;5071 const int_bits = ty.intInfo(self.target).bits;
4981 const wasm_bits = toWasmBits(int_bits) orelse {5072 const wasm_bits = toWasmBits(int_bits) orelse {
...@@ -5004,9 +5095,8 @@ fn signAbsValue(self: *Self, operand: WValue, ty: Type) InnerError!WValue {...@@ -5004,9 +5095,8 @@ fn signAbsValue(self: *Self, operand: WValue, ty: Type) InnerError!WValue {
5004 },5095 },
5005 else => unreachable,5096 else => unreachable,
5006 }5097 }
5007 const result = try self.allocLocal(ty);5098
5008 try self.addLabel(.local_set, result.local);5099 return WValue{ .stack = {} };
5009 return result;
5010}5100}
50115101
5012fn airCeilFloorTrunc(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {5102fn airCeilFloorTrunc(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
...@@ -5033,9 +5123,7 @@ fn airCeilFloorTrunc(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValu...@@ -5033,9 +5123,7 @@ fn airCeilFloorTrunc(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValu
5033 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));5123 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
50345124
5035 if (is_f16) {5125 if (is_f16) {
5036 // re-use temporary to save locals5126 _ = try self.fptrunc(.{ .stack = {} }, Type.f32, Type.f16);
5037 try self.addLabel(.local_set, op_to_lower.local);
5038 return self.fptrunc(op_to_lower, Type.f32, Type.f16);
5039 }5127 }
50405128
5041 const result = try self.allocLocal(ty);5129 const result = try self.allocLocal(ty);
...@@ -5064,7 +5152,8 @@ fn airSatBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {...@@ -5064,7 +5152,8 @@ fn airSatBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
5064 }5152 }
50655153
5066 const wasm_bits = toWasmBits(int_info.bits).?;5154 const wasm_bits = toWasmBits(int_info.bits).?;
5067 const bin_result = try self.binOp(lhs, rhs, ty, op);5155 var bin_result = try (try self.binOp(lhs, rhs, ty, op)).toLocal(self, ty);
5156 defer bin_result.free(self);
5068 if (wasm_bits != int_info.bits and op == .add) {5157 if (wasm_bits != int_info.bits and op == .add) {
5069 const val: u64 = @intCast(u64, (@as(u65, 1) << @intCast(u7, int_info.bits)) - 1);5158 const val: u64 = @intCast(u64, (@as(u65, 1) << @intCast(u7, int_info.bits)) - 1);
5070 const imm_val = switch (wasm_bits) {5159 const imm_val = switch (wasm_bits) {
...@@ -5073,19 +5162,17 @@ fn airSatBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {...@@ -5073,19 +5162,17 @@ fn airSatBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
5073 else => unreachable,5162 else => unreachable,
5074 };5163 };
50755164
5076 const cmp_result = try self.cmp(bin_result, imm_val, ty, .lt);
5077 try self.emitWValue(bin_result);5165 try self.emitWValue(bin_result);
5078 try self.emitWValue(imm_val);5166 try self.emitWValue(imm_val);
5079 try self.emitWValue(cmp_result);5167 _ = try self.cmp(bin_result, imm_val, ty, .lt);
5080 } else {5168 } else {
5081 const cmp_result = try self.cmp(bin_result, lhs, ty, if (op == .add) .lt else .gt);
5082 switch (wasm_bits) {5169 switch (wasm_bits) {
5083 32 => try self.addImm32(if (op == .add) @as(i32, -1) else 0),5170 32 => try self.addImm32(if (op == .add) @as(i32, -1) else 0),
5084 64 => try self.addImm64(if (op == .add) @bitCast(u64, @as(i64, -1)) else 0),5171 64 => try self.addImm64(if (op == .add) @bitCast(u64, @as(i64, -1)) else 0),
5085 else => unreachable,5172 else => unreachable,
5086 }5173 }
5087 try self.emitWValue(bin_result);5174 try self.emitWValue(bin_result);
5088 try self.emitWValue(cmp_result);5175 _ = try self.cmp(bin_result, lhs, ty, if (op == .add) .lt else .gt);
5089 }5176 }
50905177
5091 try self.addTag(.select);5178 try self.addTag(.select);
...@@ -5099,8 +5186,12 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op...@@ -5099,8 +5186,12 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op
5099 const wasm_bits = toWasmBits(int_info.bits).?;5186 const wasm_bits = toWasmBits(int_info.bits).?;
5100 const is_wasm_bits = wasm_bits == int_info.bits;5187 const is_wasm_bits = wasm_bits == int_info.bits;
51015188
5102 const lhs = if (!is_wasm_bits) try self.signAbsValue(lhs_operand, ty) else lhs_operand;5189 var lhs = if (!is_wasm_bits) lhs: {
5103 const rhs = if (!is_wasm_bits) try self.signAbsValue(rhs_operand, ty) else rhs_operand;5190 break :lhs try (try self.signAbsValue(lhs_operand, ty)).toLocal(self, ty);
5191 } else lhs_operand;
5192 var rhs = if (!is_wasm_bits) rhs: {
5193 break :rhs try (try self.signAbsValue(rhs_operand, ty)).toLocal(self, ty);
5194 } else rhs_operand;
51045195
5105 const max_val: u64 = @intCast(u64, (@as(u65, 1) << @intCast(u7, int_info.bits - 1)) - 1);5196 const max_val: u64 = @intCast(u64, (@as(u65, 1) << @intCast(u7, int_info.bits - 1)) - 1);
5106 const min_val: i64 = (-@intCast(i64, @intCast(u63, max_val))) - 1;5197 const min_val: i64 = (-@intCast(i64, @intCast(u63, max_val))) - 1;
...@@ -5115,38 +5206,38 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op...@@ -5115,38 +5206,38 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op
5115 else => unreachable,5206 else => unreachable,
5116 };5207 };
51175208
5118 const bin_result = try self.binOp(lhs, rhs, ty, op);5209 var bin_result = try (try self.binOp(lhs, rhs, ty, op)).toLocal(self, ty);
5119 if (!is_wasm_bits) {5210 if (!is_wasm_bits) {
5120 const cmp_result_lt = try self.cmp(bin_result, max_wvalue, ty, .lt);5211 defer bin_result.free(self); // not returned in this branch
5212 defer lhs.free(self); // uses temporary local for absvalue
5213 defer rhs.free(self); // uses temporary local for absvalue
5121 try self.emitWValue(bin_result);5214 try self.emitWValue(bin_result);
5122 try self.emitWValue(max_wvalue);5215 try self.emitWValue(max_wvalue);
5123 try self.emitWValue(cmp_result_lt);5216 _ = try self.cmp(bin_result, max_wvalue, ty, .lt);
5124 try self.addTag(.select);5217 try self.addTag(.select);
5125 try self.addLabel(.local_set, bin_result.local); // re-use local5218 try self.addLabel(.local_set, bin_result.local); // re-use local
51265219
5127 const cmp_result_gt = try self.cmp(bin_result, min_wvalue, ty, .gt);
5128 try self.emitWValue(bin_result);5220 try self.emitWValue(bin_result);
5129 try self.emitWValue(min_wvalue);5221 try self.emitWValue(min_wvalue);
5130 try self.emitWValue(cmp_result_gt);5222 _ = try self.cmp(bin_result, min_wvalue, ty, .gt);
5131 try self.addTag(.select);5223 try self.addTag(.select);
5132 try self.addLabel(.local_set, bin_result.local); // re-use local5224 try self.addLabel(.local_set, bin_result.local); // re-use local
5133 return self.wrapOperand(bin_result, ty);5225 return (try self.wrapOperand(bin_result, ty)).toLocal(self, ty);
5134 } else {5226 } else {
5135 const zero = switch (wasm_bits) {5227 const zero = switch (wasm_bits) {
5136 32 => WValue{ .imm32 = 0 },5228 32 => WValue{ .imm32 = 0 },
5137 64 => WValue{ .imm64 = 0 },5229 64 => WValue{ .imm64 = 0 },
5138 else => unreachable,5230 else => unreachable,
5139 };5231 };
5140 const cmp_bin_result = try self.cmp(bin_result, lhs, ty, .lt);
5141 const cmp_zero_result = try self.cmp(rhs, zero, ty, if (op == .add) .lt else .gt);
5142 const xor = try self.binOp(cmp_zero_result, cmp_bin_result, Type.u32, .xor); // comparisons always return i32, so provide u32 as type to xor.
5143 const cmp_bin_zero_result = try self.cmp(bin_result, zero, ty, .lt);
5144 try self.emitWValue(max_wvalue);5232 try self.emitWValue(max_wvalue);
5145 try self.emitWValue(min_wvalue);5233 try self.emitWValue(min_wvalue);
5146 try self.emitWValue(cmp_bin_zero_result);5234 _ = try self.cmp(bin_result, zero, ty, .lt);
5147 try self.addTag(.select);5235 try self.addTag(.select);
5148 try self.emitWValue(bin_result);5236 try self.emitWValue(bin_result);
5149 try self.emitWValue(xor);5237 // leave on stack
5238 const cmp_zero_result = try self.cmp(rhs, zero, ty, if (op == .add) .lt else .gt);
5239 const cmp_bin_result = try self.cmp(bin_result, lhs, ty, .lt);
5240 _ = try self.binOp(cmp_zero_result, cmp_bin_result, Type.u32, .xor); // comparisons always return i32, so provide u32 as type to xor.
5150 try self.addTag(.select);5241 try self.addTag(.select);
5151 try self.addLabel(.local_set, bin_result.local); // re-use local5242 try self.addLabel(.local_set, bin_result.local); // re-use local
5152 return bin_result;5243 return bin_result;
...@@ -5170,9 +5261,10 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -5170,9 +5261,10 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
5170 const result = try self.allocLocal(ty);5261 const result = try self.allocLocal(ty);
51715262
5172 if (wasm_bits == int_info.bits) {5263 if (wasm_bits == int_info.bits) {
5173 const shl = try self.binOp(lhs, rhs, ty, .shl);5264 var shl = try (try self.binOp(lhs, rhs, ty, .shl)).toLocal(self, ty);
5174 const shr = try self.binOp(shl, rhs, ty, .shr);5265 defer shl.free(self);
5175 const cmp_result = try self.cmp(lhs, shr, ty, .neq);5266 var shr = try (try self.binOp(shl, rhs, ty, .shr)).toLocal(self, ty);
5267 defer shr.free(self);
51765268
5177 switch (wasm_bits) {5269 switch (wasm_bits) {
5178 32 => blk: {5270 32 => blk: {
...@@ -5180,10 +5272,9 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -5180,10 +5272,9 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
5180 try self.addImm32(-1);5272 try self.addImm32(-1);
5181 break :blk;5273 break :blk;
5182 }5274 }
5183 const less_than_zero = try self.cmp(lhs, .{ .imm32 = 0 }, ty, .lt);
5184 try self.addImm32(std.math.minInt(i32));5275 try self.addImm32(std.math.minInt(i32));
5185 try self.addImm32(std.math.maxInt(i32));5276 try self.addImm32(std.math.maxInt(i32));
5186 try self.emitWValue(less_than_zero);5277 _ = try self.cmp(lhs, .{ .imm32 = 0 }, ty, .lt);
5187 try self.addTag(.select);5278 try self.addTag(.select);
5188 },5279 },
5189 64 => blk: {5280 64 => blk: {
...@@ -5191,16 +5282,15 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -5191,16 +5282,15 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
5191 try self.addImm64(@bitCast(u64, @as(i64, -1)));5282 try self.addImm64(@bitCast(u64, @as(i64, -1)));
5192 break :blk;5283 break :blk;
5193 }5284 }
5194 const less_than_zero = try self.cmp(lhs, .{ .imm64 = 0 }, ty, .lt);
5195 try self.addImm64(@bitCast(u64, @as(i64, std.math.minInt(i64))));5285 try self.addImm64(@bitCast(u64, @as(i64, std.math.minInt(i64))));
5196 try self.addImm64(@bitCast(u64, @as(i64, std.math.maxInt(i64))));5286 try self.addImm64(@bitCast(u64, @as(i64, std.math.maxInt(i64))));
5197 try self.emitWValue(less_than_zero);5287 _ = try self.cmp(lhs, .{ .imm64 = 0 }, ty, .lt);
5198 try self.addTag(.select);5288 try self.addTag(.select);
5199 },5289 },
5200 else => unreachable,5290 else => unreachable,
5201 }5291 }
5202 try self.emitWValue(shl);5292 try self.emitWValue(shl);
5203 try self.emitWValue(cmp_result);5293 _ = try self.cmp(lhs, shr, ty, .neq);
5204 try self.addTag(.select);5294 try self.addTag(.select);
5205 try self.addLabel(.local_set, result.local);5295 try self.addLabel(.local_set, result.local);
5206 return result;5296 return result;
...@@ -5212,10 +5302,12 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -5212,10 +5302,12 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
5212 else => unreachable,5302 else => unreachable,
5213 };5303 };
52145304
5215 const shl_res = try self.binOp(lhs, shift_value, ty, .shl);5305 var shl_res = try (try self.binOp(lhs, shift_value, ty, .shl)).toLocal(self, ty);
5216 const shl = try self.binOp(shl_res, rhs, ty, .shl);5306 defer shl_res.free(self);
5217 const shr = try self.binOp(shl, rhs, ty, .shr);5307 var shl = try (try self.binOp(shl_res, rhs, ty, .shl)).toLocal(self, ty);
5218 const cmp_result = try self.cmp(shl_res, shr, ty, .neq);5308 defer shl.free(self);
5309 var shr = try (try self.binOp(shl, rhs, ty, .shr)).toLocal(self, ty);
5310 defer shr.free(self);
52195311
5220 switch (wasm_bits) {5312 switch (wasm_bits) {
5221 32 => blk: {5313 32 => blk: {
...@@ -5224,10 +5316,9 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -5224,10 +5316,9 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
5224 break :blk;5316 break :blk;
5225 }5317 }
52265318
5227 const less_than_zero = try self.cmp(shl_res, .{ .imm32 = 0 }, ty, .lt);
5228 try self.addImm32(std.math.minInt(i32));5319 try self.addImm32(std.math.minInt(i32));
5229 try self.addImm32(std.math.maxInt(i32));5320 try self.addImm32(std.math.maxInt(i32));
5230 try self.emitWValue(less_than_zero);5321 _ = try self.cmp(shl_res, .{ .imm32 = 0 }, ty, .lt);
5231 try self.addTag(.select);5322 try self.addTag(.select);
5232 },5323 },
5233 64 => blk: {5324 64 => blk: {
...@@ -5236,29 +5327,31 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -5236,29 +5327,31 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
5236 break :blk;5327 break :blk;
5237 }5328 }
52385329
5239 const less_than_zero = try self.cmp(shl_res, .{ .imm64 = 0 }, ty, .lt);
5240 try self.addImm64(@bitCast(u64, @as(i64, std.math.minInt(i64))));5330 try self.addImm64(@bitCast(u64, @as(i64, std.math.minInt(i64))));
5241 try self.addImm64(@bitCast(u64, @as(i64, std.math.maxInt(i64))));5331 try self.addImm64(@bitCast(u64, @as(i64, std.math.maxInt(i64))));
5242 try self.emitWValue(less_than_zero);5332 _ = try self.cmp(shl_res, .{ .imm64 = 0 }, ty, .lt);
5243 try self.addTag(.select);5333 try self.addTag(.select);
5244 },5334 },
5245 else => unreachable,5335 else => unreachable,
5246 }5336 }
5247 try self.emitWValue(shl);5337 try self.emitWValue(shl);
5248 try self.emitWValue(cmp_result);5338 _ = try self.cmp(shl_res, shr, ty, .neq);
5249 try self.addTag(.select);5339 try self.addTag(.select);
5250 try self.addLabel(.local_set, result.local);5340 try self.addLabel(.local_set, result.local);
5251 const shift_result = try self.binOp(result, shift_value, ty, .shr);5341 var shift_result = try self.binOp(result, shift_value, ty, .shr);
5252 if (is_signed) {5342 if (is_signed) {
5253 return self.wrapOperand(shift_result, ty);5343 shift_result = try self.wrapOperand(shift_result, ty);
5254 }5344 }
5255 return shift_result;5345 return shift_result.toLocal(self, ty);
5256 }5346 }
5257}5347}
52585348
5259/// Calls a compiler-rt intrinsic by creating an undefined symbol,5349/// Calls a compiler-rt intrinsic by creating an undefined symbol,
5260/// then lowering the arguments and calling the symbol as a function call.5350/// then lowering the arguments and calling the symbol as a function call.
5261/// This function call assumes the C-ABI.5351/// This function call assumes the C-ABI.
5352/// Asserts arguments are not stack values when the return value is
5353/// passed as the first parameter.
5354/// May leave the return value on the stack.
5262fn callIntrinsic(5355fn callIntrinsic(
5263 self: *Self,5356 self: *Self,
5264 name: []const u8,5357 name: []const u8,
...@@ -5288,6 +5381,7 @@ fn callIntrinsic(...@@ -5288,6 +5381,7 @@ fn callIntrinsic(
52885381
5289 // Lower all arguments to the stack before we call our function5382 // Lower all arguments to the stack before we call our function
5290 for (args) |arg, arg_i| {5383 for (args) |arg, arg_i| {
5384 assert(!(want_sret_param and arg == .stack));
5291 assert(param_types[arg_i].hasRuntimeBitsIgnoreComptime());5385 assert(param_types[arg_i].hasRuntimeBitsIgnoreComptime());
5292 try self.lowerArg(.C, param_types[arg_i], arg);5386 try self.lowerArg(.C, param_types[arg_i], arg);
5293 }5387 }
...@@ -5303,8 +5397,6 @@ fn callIntrinsic(...@@ -5303,8 +5397,6 @@ fn callIntrinsic(
5303 } else if (want_sret_param) {5397 } else if (want_sret_param) {
5304 return sret;5398 return sret;
5305 } else {5399 } else {
5306 const result_local = try self.allocLocal(return_type);5400 return WValue{ .stack = {} };
5307 try self.addLabel(.local_set, result_local.local);
5308 return result_local;
5309 }5401 }
5310}5402}
src/arch/wasm/Emit.zig+1-1
...@@ -343,7 +343,7 @@ fn emitMemArg(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) !void {...@@ -343,7 +343,7 @@ fn emitMemArg(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) !void {
343 try emit.code.append(@enumToInt(tag));343 try emit.code.append(@enumToInt(tag));
344344
345 // wasm encodes alignment as power of 2, rather than natural alignment345 // wasm encodes alignment as power of 2, rather than natural alignment
346 const encoded_alignment = @ctz(u32, mem_arg.alignment);346 const encoded_alignment = @ctz(mem_arg.alignment);
347 try leb128.writeULEB128(emit.code.writer(), encoded_alignment);347 try leb128.writeULEB128(emit.code.writer(), encoded_alignment);
348 try leb128.writeULEB128(emit.code.writer(), mem_arg.offset);348 try leb128.writeULEB128(emit.code.writer(), mem_arg.offset);
349}349}
src/arch/x86_64/CodeGen.zig+53-4
...@@ -775,6 +775,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -775,6 +775,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
775 .float_to_int_optimized,775 .float_to_int_optimized,
776 => return self.fail("TODO implement optimized float mode", .{}),776 => return self.fail("TODO implement optimized float mode", .{}),
777777
778 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),
779 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),
780
778 .wasm_memory_size => unreachable,781 .wasm_memory_size => unreachable,
779 .wasm_memory_grow => unreachable,782 .wasm_memory_grow => unreachable,
780 // zig fmt: on783 // zig fmt: on
...@@ -3789,7 +3792,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {...@@ -3789,7 +3792,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
37893792
3790 const ty = self.air.typeOfIndex(inst);3793 const ty = self.air.typeOfIndex(inst);
3791 const mcv = self.args[arg_index];3794 const mcv = self.args[arg_index];
3792 const name = self.mod_fn.getParamName(arg_index);3795 const name = self.mod_fn.getParamName(self.bin_file.options.module.?, arg_index);
3793 const name_with_null = name.ptr[0 .. name.len + 1];3796 const name_with_null = name.ptr[0 .. name.len + 1];
37943797
3795 if (self.liveness.isUnused(inst))3798 if (self.liveness.isUnused(inst))
...@@ -4368,6 +4371,7 @@ fn genVarDbgInfo(...@@ -4368,6 +4371,7 @@ fn genVarDbgInfo(
4368 .dwarf => |dw| {4371 .dwarf => |dw| {
4369 const dbg_info = &dw.dbg_info;4372 const dbg_info = &dw.dbg_info;
4370 try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable));4373 try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable));
4374 const endian = self.target.cpu.arch.endian();
43714375
4372 switch (mcv) {4376 switch (mcv) {
4373 .register => |reg| {4377 .register => |reg| {
...@@ -4388,7 +4392,6 @@ fn genVarDbgInfo(...@@ -4388,7 +4392,6 @@ fn genVarDbgInfo(
4388 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);4392 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
4389 },4393 },
4390 .memory, .got_load, .direct_load => {4394 .memory, .got_load, .direct_load => {
4391 const endian = self.target.cpu.arch.endian();
4392 const ptr_width = @intCast(u8, @divExact(self.target.cpu.arch.ptrBitWidth(), 8));4395 const ptr_width = @intCast(u8, @divExact(self.target.cpu.arch.ptrBitWidth(), 8));
4393 const is_ptr = switch (tag) {4396 const is_ptr = switch (tag) {
4394 .dbg_var_ptr => true,4397 .dbg_var_ptr => true,
...@@ -4423,7 +4426,53 @@ fn genVarDbgInfo(...@@ -4423,7 +4426,53 @@ fn genVarDbgInfo(
4423 else => {},4426 else => {},
4424 }4427 }
4425 },4428 },
4429 .immediate => |x| {
4430 const signedness: std.builtin.Signedness = blk: {
4431 if (ty.zigTypeTag() != .Int) break :blk .unsigned;
4432 break :blk ty.intInfo(self.target.*).signedness;
4433 };
4434 try dbg_info.ensureUnusedCapacity(2);
4435 const fixup = dbg_info.items.len;
4436 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
4437 1,
4438 switch (signedness) {
4439 .signed => DW.OP.consts,
4440 .unsigned => DW.OP.constu,
4441 },
4442 });
4443 switch (signedness) {
4444 .signed => try leb128.writeILEB128(dbg_info.writer(), @bitCast(i64, x)),
4445 .unsigned => try leb128.writeULEB128(dbg_info.writer(), x),
4446 }
4447 try dbg_info.append(DW.OP.stack_value);
4448 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
4449 },
4450 .undef => {
4451 // DW.AT.location, DW.FORM.exprloc
4452 // uleb128(exprloc_len)
4453 // DW.OP.implicit_value uleb128(len_of_bytes) bytes
4454 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
4455 var implicit_value_len = std.ArrayList(u8).init(self.gpa);
4456 defer implicit_value_len.deinit();
4457 try leb128.writeULEB128(implicit_value_len.writer(), abi_size);
4458 const total_exprloc_len = 1 + implicit_value_len.items.len + abi_size;
4459 try leb128.writeULEB128(dbg_info.writer(), total_exprloc_len);
4460 try dbg_info.ensureUnusedCapacity(total_exprloc_len);
4461 dbg_info.appendAssumeCapacity(DW.OP.implicit_value);
4462 dbg_info.appendSliceAssumeCapacity(implicit_value_len.items);
4463 dbg_info.appendNTimesAssumeCapacity(0xaa, abi_size);
4464 },
4465 .none => {
4466 try dbg_info.ensureUnusedCapacity(3);
4467 dbg_info.appendSliceAssumeCapacity(&[3]u8{ // DW.AT.location, DW.FORM.exprloc
4468 2, DW.OP.lit0, DW.OP.stack_value,
4469 });
4470 },
4426 else => {4471 else => {
4472 try dbg_info.ensureUnusedCapacity(2);
4473 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
4474 1, DW.OP.nop,
4475 });
4427 log.debug("TODO generate debug info for {}", .{mcv});4476 log.debug("TODO generate debug info for {}", .{mcv});
4428 },4477 },
4429 }4478 }
...@@ -6475,13 +6524,13 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {...@@ -6475,13 +6524,13 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
6475 const extra = self.air.extraData(Air.Block, ty_pl.payload);6524 const extra = self.air.extraData(Air.Block, ty_pl.payload);
6476 _ = ty_pl;6525 _ = ty_pl;
6477 _ = extra;6526 _ = extra;
6478 return self.fail("TODO implement airCmpxchg for {}", .{self.target.cpu.arch});6527 return self.fail("TODO implement x86 airCmpxchg", .{});
6479 // return self.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value });6528 // return self.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value });
6480}6529}
64816530
6482fn airAtomicRmw(self: *Self, inst: Air.Inst.Index) !void {6531fn airAtomicRmw(self: *Self, inst: Air.Inst.Index) !void {
6483 _ = inst;6532 _ = inst;
6484 return self.fail("TODO implement airCmpxchg for {}", .{self.target.cpu.arch});6533 return self.fail("TODO implement x86 airAtomicRaw", .{});
6485}6534}
64866535
6487fn airAtomicLoad(self: *Self, inst: Air.Inst.Index) !void {6536fn airAtomicLoad(self: *Self, inst: Air.Inst.Index) !void {
src/autodoc/render_source.zig created+424
...@@ -0,0 +1,424 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const io = std.io;
4const fs = std.fs;
5const process = std.process;
6const ChildProcess = std.ChildProcess;
7const Progress = std.Progress;
8const print = std.debug.print;
9const mem = std.mem;
10const testing = std.testing;
11const Allocator = std.mem.Allocator;
12const Module = @import("../Module.zig");
13
14pub fn genHtml(
15 allocator: Allocator,
16 src: *Module.File,
17 out: anytype,
18) !void {
19 try out.writeAll(
20 \\<!doctype html>
21 \\<html lang="en">
22 \\<head>
23 \\ <meta charset="utf-8">
24 \\ <meta name="viewport" content="width=device-width, initial-scale=1.0">
25 );
26 try out.print(" <title>{s} - source view</title>\n", .{src.sub_file_path});
27 try out.writeAll(
28 \\ <link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg=="/>
29 \\ <style>
30 \\ body{
31 \\ font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
32 \\ margin: 0;
33 \\ line-height: 1.5;
34 \\ }
35 \\
36 \\ pre > code {
37 \\ display: block;
38 \\ overflow: auto;
39 \\ line-height: normal;
40 \\ margin: 0em;
41 \\ }
42 \\ .tok-kw {
43 \\ color: #333;
44 \\ font-weight: bold;
45 \\ }
46 \\ .tok-str {
47 \\ color: #d14;
48 \\ }
49 \\ .tok-builtin {
50 \\ color: #005C7A;
51 \\ }
52 \\ .tok-comment {
53 \\ color: #545454;
54 \\ font-style: italic;
55 \\ }
56 \\ .tok-fn {
57 \\ color: #900;
58 \\ font-weight: bold;
59 \\ }
60 \\ .tok-null {
61 \\ color: #005C5C;
62 \\ }
63 \\ .tok-number {
64 \\ color: #005C5C;
65 \\ }
66 \\ .tok-type {
67 \\ color: #458;
68 \\ font-weight: bold;
69 \\ }
70 \\ pre {
71 \\ counter-reset: line;
72 \\ }
73 \\ pre .line:before {
74 \\ counter-increment: line;
75 \\ content: counter(line);
76 \\ display: inline-block;
77 \\ padding-right: 1em;
78 \\ width: 2em;
79 \\ text-align: right;
80 \\ color: #999;
81 \\ }
82 \\
83 \\ @media (prefers-color-scheme: dark) {
84 \\ body{
85 \\ background:#222;
86 \\ color: #ccc;
87 \\ }
88 \\ pre > code {
89 \\ color: #ccc;
90 \\ background: #222;
91 \\ border: unset;
92 \\ }
93 \\ .tok-kw {
94 \\ color: #eee;
95 \\ }
96 \\ .tok-str {
97 \\ color: #2e5;
98 \\ }
99 \\ .tok-builtin {
100 \\ color: #ff894c;
101 \\ }
102 \\ .tok-comment {
103 \\ color: #aa7;
104 \\ }
105 \\ .tok-fn {
106 \\ color: #B1A0F8;
107 \\ }
108 \\ .tok-null {
109 \\ color: #ff8080;
110 \\ }
111 \\ .tok-number {
112 \\ color: #ff8080;
113 \\ }
114 \\ .tok-type {
115 \\ color: #68f;
116 \\ }
117 \\ }
118 \\ </style>
119 \\</head>
120 \\<body>
121 \\
122 );
123
124 const source = try src.getSource(allocator);
125 try tokenizeAndPrintRaw(allocator, out, source.bytes);
126 try out.writeAll(
127 \\</body>
128 \\</html>
129 );
130}
131
132const start_line = "<span class=\"line\" id=\"L{d}\">";
133const end_line = "</span>\n";
134
135var line_counter: usize = 1;
136
137pub fn tokenizeAndPrintRaw(
138 allocator: Allocator,
139 out: anytype,
140 raw_src: [:0]const u8,
141) !void {
142 const src = try allocator.dupeZ(u8, raw_src);
143 defer allocator.free(src);
144
145 line_counter = 1;
146
147 try out.print("<pre><code>" ++ start_line, .{line_counter});
148 var tokenizer = std.zig.Tokenizer.init(src);
149 var index: usize = 0;
150 var next_tok_is_fn = false;
151 while (true) {
152 const prev_tok_was_fn = next_tok_is_fn;
153 next_tok_is_fn = false;
154
155 const token = tokenizer.next();
156 if (mem.indexOf(u8, src[index..token.loc.start], "//")) |comment_start_off| {
157 // render one comment
158 const comment_start = index + comment_start_off;
159 const comment_end_off = mem.indexOf(u8, src[comment_start..token.loc.start], "\n");
160 const comment_end = if (comment_end_off) |o| comment_start + o else token.loc.start;
161
162 try writeEscapedLines(out, src[index..comment_start]);
163 try out.writeAll("<span class=\"tok-comment\">");
164 try writeEscaped(out, src[comment_start..comment_end]);
165 try out.writeAll("</span>\n");
166 index = comment_end;
167 tokenizer.index = index;
168 continue;
169 }
170
171 try writeEscapedLines(out, src[index..token.loc.start]);
172 switch (token.tag) {
173 .eof => break,
174
175 .keyword_addrspace,
176 .keyword_align,
177 .keyword_and,
178 .keyword_asm,
179 .keyword_async,
180 .keyword_await,
181 .keyword_break,
182 .keyword_catch,
183 .keyword_comptime,
184 .keyword_const,
185 .keyword_continue,
186 .keyword_defer,
187 .keyword_else,
188 .keyword_enum,
189 .keyword_errdefer,
190 .keyword_error,
191 .keyword_export,
192 .keyword_extern,
193 .keyword_for,
194 .keyword_if,
195 .keyword_inline,
196 .keyword_noalias,
197 .keyword_noinline,
198 .keyword_nosuspend,
199 .keyword_opaque,
200 .keyword_or,
201 .keyword_orelse,
202 .keyword_packed,
203 .keyword_anyframe,
204 .keyword_pub,
205 .keyword_resume,
206 .keyword_return,
207 .keyword_linksection,
208 .keyword_callconv,
209 .keyword_struct,
210 .keyword_suspend,
211 .keyword_switch,
212 .keyword_test,
213 .keyword_threadlocal,
214 .keyword_try,
215 .keyword_union,
216 .keyword_unreachable,
217 .keyword_usingnamespace,
218 .keyword_var,
219 .keyword_volatile,
220 .keyword_allowzero,
221 .keyword_while,
222 .keyword_anytype,
223 => {
224 try out.writeAll("<span class=\"tok-kw\">");
225 try writeEscaped(out, src[token.loc.start..token.loc.end]);
226 try out.writeAll("</span>");
227 },
228
229 .keyword_fn => {
230 try out.writeAll("<span class=\"tok-kw\">");
231 try writeEscaped(out, src[token.loc.start..token.loc.end]);
232 try out.writeAll("</span>");
233 next_tok_is_fn = true;
234 },
235
236 .string_literal,
237 .char_literal,
238 => {
239 try out.writeAll("<span class=\"tok-str\">");
240 try writeEscaped(out, src[token.loc.start..token.loc.end]);
241 try out.writeAll("</span>");
242 },
243
244 .multiline_string_literal_line => {
245 if (src[token.loc.end - 1] == '\n') {
246 try out.writeAll("<span class=\"tok-str\">");
247 try writeEscaped(out, src[token.loc.start .. token.loc.end - 1]);
248 line_counter += 1;
249 try out.print("</span>" ++ end_line ++ "\n" ++ start_line, .{line_counter});
250 } else {
251 try out.writeAll("<span class=\"tok-str\">");
252 try writeEscaped(out, src[token.loc.start..token.loc.end]);
253 try out.writeAll("</span>");
254 }
255 },
256
257 .builtin => {
258 try out.writeAll("<span class=\"tok-builtin\">");
259 try writeEscaped(out, src[token.loc.start..token.loc.end]);
260 try out.writeAll("</span>");
261 },
262
263 .doc_comment,
264 .container_doc_comment,
265 => {
266 try out.writeAll("<span class=\"tok-comment\">");
267 try writeEscaped(out, src[token.loc.start..token.loc.end]);
268 try out.writeAll("</span>");
269 },
270
271 .identifier => {
272 const tok_bytes = src[token.loc.start..token.loc.end];
273 if (mem.eql(u8, tok_bytes, "undefined") or
274 mem.eql(u8, tok_bytes, "null") or
275 mem.eql(u8, tok_bytes, "true") or
276 mem.eql(u8, tok_bytes, "false"))
277 {
278 try out.writeAll("<span class=\"tok-null\">");
279 try writeEscaped(out, tok_bytes);
280 try out.writeAll("</span>");
281 } else if (prev_tok_was_fn) {
282 try out.writeAll("<span class=\"tok-fn\">");
283 try writeEscaped(out, tok_bytes);
284 try out.writeAll("</span>");
285 } else {
286 const is_int = blk: {
287 if (src[token.loc.start] != 'i' and src[token.loc.start] != 'u')
288 break :blk false;
289 var i = token.loc.start + 1;
290 if (i == token.loc.end)
291 break :blk false;
292 while (i != token.loc.end) : (i += 1) {
293 if (src[i] < '0' or src[i] > '9')
294 break :blk false;
295 }
296 break :blk true;
297 };
298 if (is_int or isType(tok_bytes)) {
299 try out.writeAll("<span class=\"tok-type\">");
300 try writeEscaped(out, tok_bytes);
301 try out.writeAll("</span>");
302 } else {
303 try writeEscaped(out, tok_bytes);
304 }
305 }
306 },
307
308 .integer_literal,
309 .float_literal,
310 => {
311 try out.writeAll("<span class=\"tok-number\">");
312 try writeEscaped(out, src[token.loc.start..token.loc.end]);
313 try out.writeAll("</span>");
314 },
315
316 .bang,
317 .pipe,
318 .pipe_pipe,
319 .pipe_equal,
320 .equal,
321 .equal_equal,
322 .equal_angle_bracket_right,
323 .bang_equal,
324 .l_paren,
325 .r_paren,
326 .semicolon,
327 .percent,
328 .percent_equal,
329 .l_brace,
330 .r_brace,
331 .l_bracket,
332 .r_bracket,
333 .period,
334 .period_asterisk,
335 .ellipsis2,
336 .ellipsis3,
337 .caret,
338 .caret_equal,
339 .plus,
340 .plus_plus,
341 .plus_equal,
342 .plus_percent,
343 .plus_percent_equal,
344 .plus_pipe,
345 .plus_pipe_equal,
346 .minus,
347 .minus_equal,
348 .minus_percent,
349 .minus_percent_equal,
350 .minus_pipe,
351 .minus_pipe_equal,
352 .asterisk,
353 .asterisk_equal,
354 .asterisk_asterisk,
355 .asterisk_percent,
356 .asterisk_percent_equal,
357 .asterisk_pipe,
358 .asterisk_pipe_equal,
359 .arrow,
360 .colon,
361 .slash,
362 .slash_equal,
363 .comma,
364 .ampersand,
365 .ampersand_equal,
366 .question_mark,
367 .angle_bracket_left,
368 .angle_bracket_left_equal,
369 .angle_bracket_angle_bracket_left,
370 .angle_bracket_angle_bracket_left_equal,
371 .angle_bracket_angle_bracket_left_pipe,
372 .angle_bracket_angle_bracket_left_pipe_equal,
373 .angle_bracket_right,
374 .angle_bracket_right_equal,
375 .angle_bracket_angle_bracket_right,
376 .angle_bracket_angle_bracket_right_equal,
377 .tilde,
378 => try writeEscaped(out, src[token.loc.start..token.loc.end]),
379
380 .invalid, .invalid_periodasterisks => return error.ParseError,
381 }
382 index = token.loc.end;
383 }
384 try out.writeAll(end_line ++ "</code></pre>");
385}
386
387fn writeEscapedLines(out: anytype, text: []const u8) !void {
388 for (text) |char| {
389 if (char == '\n') {
390 try out.writeAll(end_line);
391 line_counter += 1;
392 try out.print(start_line, .{line_counter});
393 } else {
394 try writeEscaped(out, &[_]u8{char});
395 }
396 }
397}
398
399fn writeEscaped(out: anytype, input: []const u8) !void {
400 for (input) |c| {
401 try switch (c) {
402 '&' => out.writeAll("&amp;"),
403 '<' => out.writeAll("&lt;"),
404 '>' => out.writeAll("&gt;"),
405 '"' => out.writeAll("&quot;"),
406 else => out.writeByte(c),
407 };
408 }
409}
410
411const builtin_types = [_][]const u8{
412 "f16", "f32", "f64", "f128", "c_longdouble", "c_short",
413 "c_ushort", "c_int", "c_uint", "c_long", "c_ulong", "c_longlong",
414 "c_ulonglong", "c_char", "anyopaque", "void", "bool", "isize",
415 "usize", "noreturn", "type", "anyerror", "comptime_int", "comptime_float",
416};
417
418fn isType(name: []const u8) bool {
419 for (builtin_types) |t| {
420 if (mem.eql(u8, t, name))
421 return true;
422 }
423 return false;
424}
src/clang_options_data.zig+50-8
...@@ -33,7 +33,14 @@ flagpd1("H"),...@@ -33,7 +33,14 @@ flagpd1("H"),
33 .psl = false,33 .psl = false,
34},34},
35flagpd1("I-"),35flagpd1("I-"),
36flagpd1("M"),36.{
37 .name = "M",
38 .syntax = .flag,
39 .zig_equivalent = .dep_file_to_stdout,
40 .pd1 = true,
41 .pd2 = false,
42 .psl = false,
43},
37.{44.{
38 .name = "MD",45 .name = "MD",
39 .syntax = .flag,46 .syntax = .flag,
...@@ -53,7 +60,7 @@ flagpd1("M"),...@@ -53,7 +60,7 @@ flagpd1("M"),
53.{60.{
54 .name = "MM",61 .name = "MM",
55 .syntax = .flag,62 .syntax = .flag,
56 .zig_equivalent = .dep_file_mm,63 .zig_equivalent = .dep_file_to_stdout,
57 .pd1 = true,64 .pd1 = true,
58 .pd2 = false,65 .pd2 = false,
59 .psl = false,66 .psl = false,
...@@ -2033,7 +2040,7 @@ flagpsl("MT"),...@@ -2033,7 +2040,7 @@ flagpsl("MT"),
2033.{2040.{
2034 .name = "user-dependencies",2041 .name = "user-dependencies",
2035 .syntax = .flag,2042 .syntax = .flag,
2036 .zig_equivalent = .dep_file_mm,2043 .zig_equivalent = .dep_file_to_stdout,
2037 .pd1 = false,2044 .pd1 = false,
2038 .pd2 = true,2045 .pd2 = true,
2039 .psl = false,2046 .psl = false,
...@@ -3390,7 +3397,14 @@ flagpd1("fno-stack-arrays"),...@@ -3390,7 +3397,14 @@ flagpd1("fno-stack-arrays"),
3390 .psl = false,3397 .psl = false,
3391},3398},
3392flagpd1("fno-stack-clash-protection"),3399flagpd1("fno-stack-clash-protection"),
3393flagpd1("fno-stack-protector"),3400.{
3401 .name = "fno-stack-protector",
3402 .syntax = .flag,
3403 .zig_equivalent = .no_stack_protector,
3404 .pd1 = true,
3405 .pd2 = false,
3406 .psl = false,
3407},
3394flagpd1("fno-stack-size-section"),3408flagpd1("fno-stack-size-section"),
3395flagpd1("fno-standalone-debug"),3409flagpd1("fno-standalone-debug"),
3396flagpd1("fno-strength-reduce"),3410flagpd1("fno-strength-reduce"),
...@@ -3689,9 +3703,30 @@ flagpd1("fstack-arrays"),...@@ -3689,9 +3703,30 @@ flagpd1("fstack-arrays"),
3689 .psl = false,3703 .psl = false,
3690},3704},
3691flagpd1("fstack-clash-protection"),3705flagpd1("fstack-clash-protection"),
3692flagpd1("fstack-protector"),3706.{
3693flagpd1("fstack-protector-all"),3707 .name = "fstack-protector",
3694flagpd1("fstack-protector-strong"),3708 .syntax = .flag,
3709 .zig_equivalent = .stack_protector,
3710 .pd1 = true,
3711 .pd2 = false,
3712 .psl = false,
3713},
3714.{
3715 .name = "fstack-protector-all",
3716 .syntax = .flag,
3717 .zig_equivalent = .stack_protector,
3718 .pd1 = true,
3719 .pd2 = false,
3720 .psl = false,
3721},
3722.{
3723 .name = "fstack-protector-strong",
3724 .syntax = .flag,
3725 .zig_equivalent = .stack_protector,
3726 .pd1 = true,
3727 .pd2 = false,
3728 .psl = false,
3729},
3695flagpd1("fstack-size-section"),3730flagpd1("fstack-size-section"),
3696flagpd1("fstack-usage"),3731flagpd1("fstack-usage"),
3697flagpd1("fstandalone-debug"),3732flagpd1("fstandalone-debug"),
...@@ -4978,7 +5013,14 @@ flagpd1("single_module"),...@@ -4978,7 +5013,14 @@ flagpd1("single_module"),
4978},5013},
4979sepd1("split-dwarf-file"),5014sepd1("split-dwarf-file"),
4980sepd1("split-dwarf-output"),5015sepd1("split-dwarf-output"),
4981sepd1("stack-protector"),5016.{
5017 .name = "stack-protector",
5018 .syntax = .separate,
5019 .zig_equivalent = .stack_protector,
5020 .pd1 = true,
5021 .pd2 = false,
5022 .psl = false,
5023},
4982sepd1("stack-protector-buffer-size"),5024sepd1("stack-protector-buffer-size"),
4983sepd1("stack-usage-file"),5025sepd1("stack-usage-file"),
4984.{5026.{
src/codegen.zig+1-1
...@@ -607,7 +607,7 @@ pub fn generateSymbol(...@@ -607,7 +607,7 @@ pub fn generateSymbol(
607607
608 const union_ty = typed_value.ty.cast(Type.Payload.Union).?.data;608 const union_ty = typed_value.ty.cast(Type.Payload.Union).?.data;
609 const mod = bin_file.options.module.?;609 const mod = bin_file.options.module.?;
610 const field_index = union_ty.tag_ty.enumTagFieldIndex(union_obj.tag, mod).?;610 const field_index = typed_value.ty.unionTagFieldIndex(union_obj.tag, mod).?;
611 assert(union_ty.haveFieldTypes());611 assert(union_ty.haveFieldTypes());
612 const field_ty = union_ty.fields.values()[field_index].ty;612 const field_ty = union_ty.fields.values()[field_index].ty;
613 if (!field_ty.hasRuntimeBits()) {613 if (!field_ty.hasRuntimeBits()) {
src/codegen/c.zig+5-3
...@@ -835,7 +835,6 @@ pub const DeclGen = struct {...@@ -835,7 +835,6 @@ pub const DeclGen = struct {
835 },835 },
836 .Union => {836 .Union => {
837 const union_obj = val.castTag(.@"union").?.data;837 const union_obj = val.castTag(.@"union").?.data;
838 const union_ty = ty.cast(Type.Payload.Union).?.data;
839 const layout = ty.unionGetLayout(target);838 const layout = ty.unionGetLayout(target);
840839
841 try writer.writeAll("(");840 try writer.writeAll("(");
...@@ -851,7 +850,7 @@ pub const DeclGen = struct {...@@ -851,7 +850,7 @@ pub const DeclGen = struct {
851 try writer.writeAll(".payload = {");850 try writer.writeAll(".payload = {");
852 }851 }
853852
854 const index = union_ty.tag_ty.enumTagFieldIndex(union_obj.tag, dg.module).?;853 const index = ty.unionTagFieldIndex(union_obj.tag, dg.module).?;
855 const field_ty = ty.unionFields().values()[index].ty;854 const field_ty = ty.unionFields().values()[index].ty;
856 const field_name = ty.unionFields().keys()[index];855 const field_name = ty.unionFields().keys()[index];
857 if (field_ty.hasRuntimeBits()) {856 if (field_ty.hasRuntimeBits()) {
...@@ -1952,6 +1951,9 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1952,6 +1951,9 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1952 .reduce_optimized,1951 .reduce_optimized,
1953 .float_to_int_optimized,1952 .float_to_int_optimized,
1954 => return f.fail("TODO implement optimized float mode", .{}),1953 => return f.fail("TODO implement optimized float mode", .{}),
1954
1955 .is_named_enum_value => return f.fail("TODO: C backend: implement is_named_enum_value", .{}),
1956 .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}),
1955 // zig fmt: on1957 // zig fmt: on
1956 };1958 };
1957 switch (result_value) {1959 switch (result_value) {
...@@ -3250,7 +3252,7 @@ fn airIsNull(...@@ -3250,7 +3252,7 @@ fn airIsNull(
32503252
3251 const ty = f.air.typeOf(un_op);3253 const ty = f.air.typeOf(un_op);
3252 var opt_buf: Type.Payload.ElemType = undefined;3254 var opt_buf: Type.Payload.ElemType = undefined;
3253 const payload_ty = if (ty.zigTypeTag() == .Pointer)3255 const payload_ty = if (deref_suffix[0] != 0)
3254 ty.childType().optionalChild(&opt_buf)3256 ty.childType().optionalChild(&opt_buf)
3255 else3257 else
3256 ty.optionalChild(&opt_buf);3258 ty.optionalChild(&opt_buf);
src/codegen/llvm.zig+393-43
...@@ -222,6 +222,8 @@ pub const Object = struct {...@@ -222,6 +222,8 @@ pub const Object = struct {
222 /// * it works for functions not all globals.222 /// * it works for functions not all globals.
223 /// Therefore, this table keeps track of the mapping.223 /// Therefore, this table keeps track of the mapping.
224 decl_map: std.AutoHashMapUnmanaged(Module.Decl.Index, *const llvm.Value),224 decl_map: std.AutoHashMapUnmanaged(Module.Decl.Index, *const llvm.Value),
225 /// Serves the same purpose as `decl_map` but only used for the `is_named_enum_value` instruction.
226 named_enum_map: std.AutoHashMapUnmanaged(Module.Decl.Index, *const llvm.Value),
225 /// Maps Zig types to LLVM types. The table memory itself is backed by the GPA of227 /// Maps Zig types to LLVM types. The table memory itself is backed by the GPA of
226 /// the compiler, but the Type/Value memory here is backed by `type_map_arena`.228 /// the compiler, but the Type/Value memory here is backed by `type_map_arena`.
227 /// TODO we need to remove entries from this map in response to incremental compilation229 /// TODO we need to remove entries from this map in response to incremental compilation
...@@ -292,7 +294,7 @@ pub const Object = struct {...@@ -292,7 +294,7 @@ pub const Object = struct {
292 var di_compile_unit: ?*llvm.DICompileUnit = null;294 var di_compile_unit: ?*llvm.DICompileUnit = null;
293295
294 if (!options.strip) {296 if (!options.strip) {
295 switch (options.object_format) {297 switch (options.target.ofmt) {
296 .coff => llvm_module.addModuleCodeViewFlag(),298 .coff => llvm_module.addModuleCodeViewFlag(),
297 else => llvm_module.addModuleDebugInfoFlag(),299 else => llvm_module.addModuleDebugInfoFlag(),
298 }300 }
...@@ -398,6 +400,7 @@ pub const Object = struct {...@@ -398,6 +400,7 @@ pub const Object = struct {
398 .target_data = target_data,400 .target_data = target_data,
399 .target = options.target,401 .target = options.target,
400 .decl_map = .{},402 .decl_map = .{},
403 .named_enum_map = .{},
401 .type_map = .{},404 .type_map = .{},
402 .type_map_arena = std.heap.ArenaAllocator.init(gpa),405 .type_map_arena = std.heap.ArenaAllocator.init(gpa),
403 .di_type_map = .{},406 .di_type_map = .{},
...@@ -417,6 +420,7 @@ pub const Object = struct {...@@ -417,6 +420,7 @@ pub const Object = struct {
417 self.llvm_module.dispose();420 self.llvm_module.dispose();
418 self.context.dispose();421 self.context.dispose();
419 self.decl_map.deinit(gpa);422 self.decl_map.deinit(gpa);
423 self.named_enum_map.deinit(gpa);
420 self.type_map.deinit(gpa);424 self.type_map.deinit(gpa);
421 self.type_map_arena.deinit();425 self.type_map_arena.deinit();
422 self.extern_collisions.deinit(gpa);426 self.extern_collisions.deinit(gpa);
...@@ -728,9 +732,14 @@ pub const Object = struct {...@@ -728,9 +732,14 @@ pub const Object = struct {
728 DeclGen.removeFnAttr(llvm_func, "noinline");732 DeclGen.removeFnAttr(llvm_func, "noinline");
729 }733 }
730734
731 // TODO: port these over from stage1735 // TODO: disable this if safety is off for the function scope
732 // addLLVMFnAttr(llvm_fn, "sspstrong");736 const ssp_buf_size = module.comp.bin_file.options.stack_protector;
733 // addLLVMFnAttrStr(llvm_fn, "stack-protector-buffer-size", "4");737 if (ssp_buf_size != 0) {
738 var buf: [12]u8 = undefined;
739 const arg = std.fmt.bufPrintZ(&buf, "{d}", .{ssp_buf_size}) catch unreachable;
740 dg.addFnAttr(llvm_func, "sspstrong");
741 dg.addFnAttrString(llvm_func, "stack-protector-buffer-size", arg);
742 }
734743
735 // TODO: disable this if safety is off for the function scope744 // TODO: disable this if safety is off for the function scope
736 if (module.comp.bin_file.options.stack_check) {745 if (module.comp.bin_file.options.stack_check) {
...@@ -739,6 +748,10 @@ pub const Object = struct {...@@ -739,6 +748,10 @@ pub const Object = struct {
739 dg.addFnAttrString(llvm_func, "no-stack-arg-probe", "");748 dg.addFnAttrString(llvm_func, "no-stack-arg-probe", "");
740 }749 }
741750
751 if (decl.@"linksection") |section| {
752 llvm_func.setSection(section);
753 }
754
742 // Remove all the basic blocks of a function in order to start over, generating755 // Remove all the basic blocks of a function in order to start over, generating
743 // LLVM IR from an empty function body.756 // LLVM IR from an empty function body.
744 while (llvm_func.getFirstBasicBlock()) |bb| {757 while (llvm_func.getFirstBasicBlock()) |bb| {
...@@ -935,6 +948,40 @@ pub const Object = struct {...@@ -935,6 +948,40 @@ pub const Object = struct {
935 };948 };
936 try args.append(loaded);949 try args.append(loaded);
937 },950 },
951 .multiple_llvm_float => {
952 const llvm_floats = it.llvm_types_buffer[0..it.llvm_types_len];
953 const param_ty = fn_info.param_types[it.zig_index - 1];
954 const param_llvm_ty = try dg.lowerType(param_ty);
955 const param_alignment = param_ty.abiAlignment(target);
956 const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty);
957 arg_ptr.setAlignment(param_alignment);
958 var field_types_buf: [8]*const llvm.Type = undefined;
959 const field_types = field_types_buf[0..llvm_floats.len];
960 for (llvm_floats) |float_bits, i| {
961 switch (float_bits) {
962 64 => field_types[i] = dg.context.doubleType(),
963 80 => field_types[i] = dg.context.x86FP80Type(),
964 else => {},
965 }
966 }
967 const ints_llvm_ty = dg.context.structType(field_types.ptr, @intCast(c_uint, field_types.len), .False);
968 const casted_ptr = builder.buildBitCast(arg_ptr, ints_llvm_ty.pointerType(0), "");
969 for (llvm_floats) |_, i_usize| {
970 const i = @intCast(c_uint, i_usize);
971 const param = llvm_func.getParam(i);
972 const field_ptr = builder.buildStructGEP(casted_ptr, i, "");
973 const store_inst = builder.buildStore(param, field_ptr);
974 store_inst.setAlignment(target.cpu.arch.ptrBitWidth() / 8);
975 }
976
977 const is_by_ref = isByRef(param_ty);
978 const loaded = if (is_by_ref) arg_ptr else l: {
979 const load_inst = builder.buildLoad(arg_ptr, "");
980 load_inst.setAlignment(param_alignment);
981 break :l load_inst;
982 };
983 try args.append(loaded);
984 },
938 .as_u16 => {985 .as_u16 => {
939 const param = llvm_func.getParam(llvm_arg_i);986 const param = llvm_func.getParam(llvm_arg_i);
940 llvm_arg_i += 1;987 llvm_arg_i += 1;
...@@ -1078,6 +1125,7 @@ pub const Object = struct {...@@ -1078,6 +1125,7 @@ pub const Object = struct {
1078 }1125 }
1079 llvm_global.setUnnamedAddr(.False);1126 llvm_global.setUnnamedAddr(.False);
1080 llvm_global.setLinkage(.External);1127 llvm_global.setLinkage(.External);
1128 if (module.wantDllExports()) llvm_global.setDLLStorageClass(.Default);
1081 if (self.di_map.get(decl)) |di_node| {1129 if (self.di_map.get(decl)) |di_node| {
1082 if (try decl.isFunction()) {1130 if (try decl.isFunction()) {
1083 const di_func = @ptrCast(*llvm.DISubprogram, di_node);1131 const di_func = @ptrCast(*llvm.DISubprogram, di_node);
...@@ -1103,6 +1151,7 @@ pub const Object = struct {...@@ -1103,6 +1151,7 @@ pub const Object = struct {
1103 const exp_name = exports[0].options.name;1151 const exp_name = exports[0].options.name;
1104 llvm_global.setValueName2(exp_name.ptr, exp_name.len);1152 llvm_global.setValueName2(exp_name.ptr, exp_name.len);
1105 llvm_global.setUnnamedAddr(.False);1153 llvm_global.setUnnamedAddr(.False);
1154 if (module.wantDllExports()) llvm_global.setDLLStorageClass(.DLLExport);
1106 if (self.di_map.get(decl)) |di_node| {1155 if (self.di_map.get(decl)) |di_node| {
1107 if (try decl.isFunction()) {1156 if (try decl.isFunction()) {
1108 const di_func = @ptrCast(*llvm.DISubprogram, di_node);1157 const di_func = @ptrCast(*llvm.DISubprogram, di_node);
...@@ -1125,6 +1174,11 @@ pub const Object = struct {...@@ -1125,6 +1174,11 @@ pub const Object = struct {
1125 .hidden => llvm_global.setVisibility(.Hidden),1174 .hidden => llvm_global.setVisibility(.Hidden),
1126 .protected => llvm_global.setVisibility(.Protected),1175 .protected => llvm_global.setVisibility(.Protected),
1127 }1176 }
1177 if (exports[0].options.section) |section| {
1178 const section_z = try module.gpa.dupeZ(u8, section);
1179 defer module.gpa.free(section_z);
1180 llvm_global.setSection(section_z);
1181 }
1128 if (decl.val.castTag(.variable)) |variable| {1182 if (decl.val.castTag(.variable)) |variable| {
1129 if (variable.data.is_threadlocal) {1183 if (variable.data.is_threadlocal) {
1130 llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);1184 llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);
...@@ -1157,6 +1211,7 @@ pub const Object = struct {...@@ -1157,6 +1211,7 @@ pub const Object = struct {
1157 defer module.gpa.free(fqn);1211 defer module.gpa.free(fqn);
1158 llvm_global.setValueName2(fqn.ptr, fqn.len);1212 llvm_global.setValueName2(fqn.ptr, fqn.len);
1159 llvm_global.setLinkage(.Internal);1213 llvm_global.setLinkage(.Internal);
1214 if (module.wantDllExports()) llvm_global.setDLLStorageClass(.Default);
1160 llvm_global.setUnnamedAddr(.True);1215 llvm_global.setUnnamedAddr(.True);
1161 if (decl.val.castTag(.variable)) |variable| {1216 if (decl.val.castTag(.variable)) |variable| {
1162 const single_threaded = module.comp.bin_file.options.single_threaded;1217 const single_threaded = module.comp.bin_file.options.single_threaded;
...@@ -1701,8 +1756,7 @@ pub const Object = struct {...@@ -1701,8 +1756,7 @@ pub const Object = struct {
1701 if (ty.castTag(.@"struct")) |payload| {1756 if (ty.castTag(.@"struct")) |payload| {
1702 const struct_obj = payload.data;1757 const struct_obj = payload.data;
1703 if (struct_obj.layout == .Packed) {1758 if (struct_obj.layout == .Packed) {
1704 var buf: Type.Payload.Bits = undefined;1759 const info = struct_obj.backing_int_ty.intInfo(target);
1705 const info = struct_obj.packedIntegerType(target, &buf).intInfo(target);
1706 const dwarf_encoding: c_uint = switch (info.signedness) {1760 const dwarf_encoding: c_uint = switch (info.signedness) {
1707 .signed => DW.ATE.signed,1761 .signed => DW.ATE.signed,
1708 .unsigned => DW.ATE.unsigned,1762 .unsigned => DW.ATE.unsigned,
...@@ -1817,6 +1871,7 @@ pub const Object = struct {...@@ -1817,6 +1871,7 @@ pub const Object = struct {
1817 }1871 }
18181872
1819 const fields = ty.structFields();1873 const fields = ty.structFields();
1874 const layout = ty.containerLayout();
18201875
1821 var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};1876 var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};
1822 defer di_fields.deinit(gpa);1877 defer di_fields.deinit(gpa);
...@@ -1827,10 +1882,10 @@ pub const Object = struct {...@@ -1827,10 +1882,10 @@ pub const Object = struct {
1827 var offset: u64 = 0;1882 var offset: u64 = 0;
18281883
1829 for (fields.values()) |field, i| {1884 for (fields.values()) |field, i| {
1830 if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue;1885 if (field.is_comptime or !field.ty.hasRuntimeBits()) continue;
18311886
1832 const field_size = field.ty.abiSize(target);1887 const field_size = field.ty.abiSize(target);
1833 const field_align = field.normalAlignment(target);1888 const field_align = field.alignment(target, layout);
1834 const field_offset = std.mem.alignForwardGeneric(u64, offset, field_align);1889 const field_offset = std.mem.alignForwardGeneric(u64, offset, field_align);
1835 offset = field_offset + field_size;1890 offset = field_offset + field_size;
18361891
...@@ -2202,6 +2257,7 @@ pub const DeclGen = struct {...@@ -2202,6 +2257,7 @@ pub const DeclGen = struct {
2202 const target = dg.module.getTarget();2257 const target = dg.module.getTarget();
2203 var global = try dg.resolveGlobalDecl(decl_index);2258 var global = try dg.resolveGlobalDecl(decl_index);
2204 global.setAlignment(decl.getAlignment(target));2259 global.setAlignment(decl.getAlignment(target));
2260 if (decl.@"linksection") |section| global.setSection(section);
2205 assert(decl.has_tv);2261 assert(decl.has_tv);
2206 const init_val = if (decl.val.castTag(.variable)) |payload| init_val: {2262 const init_val = if (decl.val.castTag(.variable)) |payload| init_val: {
2207 const variable = payload.data;2263 const variable = payload.data;
...@@ -2235,6 +2291,7 @@ pub const DeclGen = struct {...@@ -2235,6 +2291,7 @@ pub const DeclGen = struct {
2235 new_global.setLinkage(global.getLinkage());2291 new_global.setLinkage(global.getLinkage());
2236 new_global.setUnnamedAddr(global.getUnnamedAddress());2292 new_global.setUnnamedAddr(global.getUnnamedAddress());
2237 new_global.setAlignment(global.getAlignment());2293 new_global.setAlignment(global.getAlignment());
2294 if (decl.@"linksection") |section| new_global.setSection(section);
2238 new_global.setInitializer(llvm_init);2295 new_global.setInitializer(llvm_init);
2239 // replaceAllUsesWith requires the type to be unchanged. So we bitcast2296 // replaceAllUsesWith requires the type to be unchanged. So we bitcast
2240 // the new global to the old type and use that as the thing to replace2297 // the new global to the old type and use that as the thing to replace
...@@ -2349,6 +2406,14 @@ pub const DeclGen = struct {...@@ -2349,6 +2406,14 @@ pub const DeclGen = struct {
2349 dg.addFnAttr(llvm_fn, "noreturn");2406 dg.addFnAttr(llvm_fn, "noreturn");
2350 }2407 }
23512408
2409 var llvm_arg_i = @as(c_uint, @boolToInt(sret)) + @boolToInt(err_return_tracing);
2410 var it = iterateParamTypes(dg, fn_info);
2411 while (it.next()) |_| : (llvm_arg_i += 1) {
2412 if (!it.byval_attr) continue;
2413 const param = llvm_fn.getParam(llvm_arg_i);
2414 llvm_fn.addByValAttr(llvm_arg_i, param.typeOf().getElementType());
2415 }
2416
2352 return llvm_fn;2417 return llvm_fn;
2353 }2418 }
23542419
...@@ -2688,9 +2753,7 @@ pub const DeclGen = struct {...@@ -2688,9 +2753,7 @@ pub const DeclGen = struct {
2688 const struct_obj = t.castTag(.@"struct").?.data;2753 const struct_obj = t.castTag(.@"struct").?.data;
26892754
2690 if (struct_obj.layout == .Packed) {2755 if (struct_obj.layout == .Packed) {
2691 var buf: Type.Payload.Bits = undefined;2756 const int_llvm_ty = try dg.lowerType(struct_obj.backing_int_ty);
2692 const int_ty = struct_obj.packedIntegerType(target, &buf);
2693 const int_llvm_ty = try dg.lowerType(int_ty);
2694 gop.value_ptr.* = int_llvm_ty;2757 gop.value_ptr.* = int_llvm_ty;
2695 return int_llvm_ty;2758 return int_llvm_ty;
2696 }2759 }
...@@ -2714,9 +2777,9 @@ pub const DeclGen = struct {...@@ -2714,9 +2777,9 @@ pub const DeclGen = struct {
2714 var any_underaligned_fields = false;2777 var any_underaligned_fields = false;
27152778
2716 for (struct_obj.fields.values()) |field| {2779 for (struct_obj.fields.values()) |field| {
2717 if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue;2780 if (field.is_comptime or !field.ty.hasRuntimeBits()) continue;
27182781
2719 const field_align = field.normalAlignment(target);2782 const field_align = field.alignment(target, struct_obj.layout);
2720 const field_ty_align = field.ty.abiAlignment(target);2783 const field_ty_align = field.ty.abiAlignment(target);
2721 any_underaligned_fields = any_underaligned_fields or2784 any_underaligned_fields = any_underaligned_fields or
2722 field_align < field_ty_align;2785 field_align < field_ty_align;
...@@ -2895,6 +2958,18 @@ pub const DeclGen = struct {...@@ -2895,6 +2958,18 @@ pub const DeclGen = struct {
2895 llvm_params.appendAssumeCapacity(big_int_ty);2958 llvm_params.appendAssumeCapacity(big_int_ty);
2896 }2959 }
2897 },2960 },
2961 .multiple_llvm_float => {
2962 const llvm_ints = it.llvm_types_buffer[0..it.llvm_types_len];
2963 try llvm_params.ensureUnusedCapacity(it.llvm_types_len);
2964 for (llvm_ints) |float_bits| {
2965 const float_ty = switch (float_bits) {
2966 64 => dg.context.doubleType(),
2967 80 => dg.context.x86FP80Type(),
2968 else => unreachable,
2969 };
2970 llvm_params.appendAssumeCapacity(float_ty);
2971 }
2972 },
2898 .as_u16 => {2973 .as_u16 => {
2899 try llvm_params.append(dg.context.intType(16));2974 try llvm_params.append(dg.context.intType(16));
2900 },2975 },
...@@ -3356,8 +3431,8 @@ pub const DeclGen = struct {...@@ -3356,8 +3431,8 @@ pub const DeclGen = struct {
3356 const struct_obj = tv.ty.castTag(.@"struct").?.data;3431 const struct_obj = tv.ty.castTag(.@"struct").?.data;
33573432
3358 if (struct_obj.layout == .Packed) {3433 if (struct_obj.layout == .Packed) {
3359 const big_bits = struct_obj.packedIntegerBits(target);3434 const big_bits = struct_obj.backing_int_ty.bitSize(target);
3360 const int_llvm_ty = dg.context.intType(big_bits);3435 const int_llvm_ty = dg.context.intType(@intCast(c_uint, big_bits));
3361 const fields = struct_obj.fields.values();3436 const fields = struct_obj.fields.values();
3362 comptime assert(Type.packed_struct_layout_version == 2);3437 comptime assert(Type.packed_struct_layout_version == 2);
3363 var running_int: *const llvm.Value = int_llvm_ty.constNull();3438 var running_int: *const llvm.Value = int_llvm_ty.constNull();
...@@ -3372,7 +3447,10 @@ pub const DeclGen = struct {...@@ -3372,7 +3447,10 @@ pub const DeclGen = struct {
3372 });3447 });
3373 const ty_bit_size = @intCast(u16, field.ty.bitSize(target));3448 const ty_bit_size = @intCast(u16, field.ty.bitSize(target));
3374 const small_int_ty = dg.context.intType(ty_bit_size);3449 const small_int_ty = dg.context.intType(ty_bit_size);
3375 const small_int_val = non_int_val.constBitCast(small_int_ty);3450 const small_int_val = if (field.ty.isPtrAtRuntime())
3451 non_int_val.constPtrToInt(small_int_ty)
3452 else
3453 non_int_val.constBitCast(small_int_ty);
3376 const shift_rhs = int_llvm_ty.constInt(running_bits, .False);3454 const shift_rhs = int_llvm_ty.constInt(running_bits, .False);
3377 // If the field is as large as the entire packed struct, this3455 // If the field is as large as the entire packed struct, this
3378 // zext would go from, e.g. i16 to i16. This is legal with3456 // zext would go from, e.g. i16 to i16. This is legal with
...@@ -3395,9 +3473,9 @@ pub const DeclGen = struct {...@@ -3395,9 +3473,9 @@ pub const DeclGen = struct {
3395 var need_unnamed = false;3473 var need_unnamed = false;
33963474
3397 for (struct_obj.fields.values()) |field, i| {3475 for (struct_obj.fields.values()) |field, i| {
3398 if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue;3476 if (field.is_comptime or !field.ty.hasRuntimeBits()) continue;
33993477
3400 const field_align = field.normalAlignment(target);3478 const field_align = field.alignment(target, struct_obj.layout);
3401 big_align = @maximum(big_align, field_align);3479 big_align = @maximum(big_align, field_align);
3402 const prev_offset = offset;3480 const prev_offset = offset;
3403 offset = std.mem.alignForwardGeneric(u64, offset, field_align);3481 offset = std.mem.alignForwardGeneric(u64, offset, field_align);
...@@ -3457,7 +3535,7 @@ pub const DeclGen = struct {...@@ -3457,7 +3535,7 @@ pub const DeclGen = struct {
3457 });3535 });
3458 }3536 }
3459 const union_obj = tv.ty.cast(Type.Payload.Union).?.data;3537 const union_obj = tv.ty.cast(Type.Payload.Union).?.data;
3460 const field_index = union_obj.tag_ty.enumTagFieldIndex(tag_and_val.tag, dg.module).?;3538 const field_index = tv.ty.unionTagFieldIndex(tag_and_val.tag, dg.module).?;
3461 assert(union_obj.haveFieldTypes());3539 assert(union_obj.haveFieldTypes());
34623540
3463 // Sometimes we must make an unnamed struct because LLVM does3541 // Sometimes we must make an unnamed struct because LLVM does
...@@ -3976,6 +4054,9 @@ pub const FuncGen = struct {...@@ -3976,6 +4054,9 @@ pub const FuncGen = struct {
3976 /// Note that this can disagree with isByRef for the return type in the case4054 /// Note that this can disagree with isByRef for the return type in the case
3977 /// of C ABI functions.4055 /// of C ABI functions.
3978 ret_ptr: ?*const llvm.Value,4056 ret_ptr: ?*const llvm.Value,
4057 /// Any function that needs to perform Valgrind client requests needs an array alloca
4058 /// instruction, however a maximum of one per function is needed.
4059 valgrind_client_request_array: ?*const llvm.Value = null,
3979 /// These fields are used to refer to the LLVM value of the function parameters4060 /// These fields are used to refer to the LLVM value of the function parameters
3980 /// in an Arg instruction.4061 /// in an Arg instruction.
3981 /// This list may be shorter than the list according to the zig type system;4062 /// This list may be shorter than the list according to the zig type system;
...@@ -4215,6 +4296,9 @@ pub const FuncGen = struct {...@@ -4215,6 +4296,9 @@ pub const FuncGen = struct {
4215 .union_init => try self.airUnionInit(inst),4296 .union_init => try self.airUnionInit(inst),
4216 .prefetch => try self.airPrefetch(inst),4297 .prefetch => try self.airPrefetch(inst),
42174298
4299 .is_named_enum_value => try self.airIsNamedEnumValue(inst),
4300 .error_set_has_value => try self.airErrorSetHasValue(inst),
4301
4218 .reduce => try self.airReduce(inst, false),4302 .reduce => try self.airReduce(inst, false),
4219 .reduce_optimized => try self.airReduce(inst, true),4303 .reduce_optimized => try self.airReduce(inst, true),
42204304
...@@ -4423,6 +4507,39 @@ pub const FuncGen = struct {...@@ -4423,6 +4507,39 @@ pub const FuncGen = struct {
4423 llvm_args.appendAssumeCapacity(load_inst);4507 llvm_args.appendAssumeCapacity(load_inst);
4424 }4508 }
4425 },4509 },
4510 .multiple_llvm_float => {
4511 const arg = args[it.zig_index - 1];
4512 const param_ty = self.air.typeOf(arg);
4513 const llvm_floats = it.llvm_types_buffer[0..it.llvm_types_len];
4514 const llvm_arg = try self.resolveInst(arg);
4515 const is_by_ref = isByRef(param_ty);
4516 const arg_ptr = if (is_by_ref) llvm_arg else p: {
4517 const p = self.buildAlloca(llvm_arg.typeOf());
4518 const store_inst = self.builder.buildStore(llvm_arg, p);
4519 store_inst.setAlignment(param_ty.abiAlignment(target));
4520 break :p p;
4521 };
4522
4523 var field_types_buf: [8]*const llvm.Type = undefined;
4524 const field_types = field_types_buf[0..llvm_floats.len];
4525 for (llvm_floats) |float_bits, i| {
4526 switch (float_bits) {
4527 64 => field_types[i] = self.dg.context.doubleType(),
4528 80 => field_types[i] = self.dg.context.x86FP80Type(),
4529 else => {},
4530 }
4531 }
4532 const ints_llvm_ty = self.dg.context.structType(field_types.ptr, @intCast(c_uint, field_types.len), .False);
4533 const casted_ptr = self.builder.buildBitCast(arg_ptr, ints_llvm_ty.pointerType(0), "");
4534 try llvm_args.ensureUnusedCapacity(it.llvm_types_len);
4535 for (llvm_floats) |_, i_usize| {
4536 const i = @intCast(c_uint, i_usize);
4537 const field_ptr = self.builder.buildStructGEP(casted_ptr, i, "");
4538 const load_inst = self.builder.buildLoad(field_ptr, "");
4539 load_inst.setAlignment(target.cpu.arch.ptrBitWidth() / 8);
4540 llvm_args.appendAssumeCapacity(load_inst);
4541 }
4542 },
4426 .as_u16 => {4543 .as_u16 => {
4427 const arg = args[it.zig_index - 1];4544 const arg = args[it.zig_index - 1];
4428 const llvm_arg = try self.resolveInst(arg);4545 const llvm_arg = try self.resolveInst(arg);
...@@ -5295,7 +5412,7 @@ pub const FuncGen = struct {...@@ -5295,7 +5412,7 @@ pub const FuncGen = struct {
5295 const same_size_int = self.context.intType(elem_bits);5412 const same_size_int = self.context.intType(elem_bits);
5296 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");5413 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");
5297 return self.builder.buildBitCast(truncated_int, elem_llvm_ty, "");5414 return self.builder.buildBitCast(truncated_int, elem_llvm_ty, "");
5298 } else if (field_ty.zigTypeTag() == .Pointer) {5415 } else if (field_ty.isPtrAtRuntime()) {
5299 const elem_bits = @intCast(c_uint, field_ty.bitSize(target));5416 const elem_bits = @intCast(c_uint, field_ty.bitSize(target));
5300 const same_size_int = self.context.intType(elem_bits);5417 const same_size_int = self.context.intType(elem_bits);
5301 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");5418 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");
...@@ -6166,7 +6283,9 @@ pub const FuncGen = struct {...@@ -6166,7 +6283,9 @@ pub const FuncGen = struct {
6166 }6283 }
6167 const llvm_optional_ty = try self.dg.lowerType(optional_ty);6284 const llvm_optional_ty = try self.dg.lowerType(optional_ty);
6168 if (isByRef(optional_ty)) {6285 if (isByRef(optional_ty)) {
6286 const target = self.dg.module.getTarget();
6169 const optional_ptr = self.buildAlloca(llvm_optional_ty);6287 const optional_ptr = self.buildAlloca(llvm_optional_ty);
6288 optional_ptr.setAlignment(optional_ty.abiAlignment(target));
6170 const payload_ptr = self.builder.buildStructGEP(llvm_optional_ty, optional_ptr, 0, "");6289 const payload_ptr = self.builder.buildStructGEP(llvm_optional_ty, optional_ptr, 0, "");
6171 var ptr_ty_payload: Type.Payload.ElemType = .{6290 var ptr_ty_payload: Type.Payload.ElemType = .{
6172 .base = .{ .tag = .single_mut_pointer },6291 .base = .{ .tag = .single_mut_pointer },
...@@ -6186,20 +6305,21 @@ pub const FuncGen = struct {...@@ -6186,20 +6305,21 @@ pub const FuncGen = struct {
6186 if (self.liveness.isUnused(inst)) return null;6305 if (self.liveness.isUnused(inst)) return null;
61876306
6188 const ty_op = self.air.instructions.items(.data)[inst].ty_op;6307 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
6189 const inst_ty = self.air.typeOfIndex(inst);6308 const err_un_ty = self.air.typeOfIndex(inst);
6190 const operand = try self.resolveInst(ty_op.operand);6309 const operand = try self.resolveInst(ty_op.operand);
6191 const payload_ty = self.air.typeOf(ty_op.operand);6310 const payload_ty = self.air.typeOf(ty_op.operand);
6192 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {6311 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
6193 return operand;6312 return operand;
6194 }6313 }
6195 const ok_err_code = (try self.dg.lowerType(Type.anyerror)).constNull();6314 const ok_err_code = (try self.dg.lowerType(Type.anyerror)).constNull();
6196 const err_un_llvm_ty = try self.dg.lowerType(inst_ty);6315 const err_un_llvm_ty = try self.dg.lowerType(err_un_ty);
61976316
6198 const target = self.dg.module.getTarget();6317 const target = self.dg.module.getTarget();
6199 const payload_offset = errUnionPayloadOffset(payload_ty, target);6318 const payload_offset = errUnionPayloadOffset(payload_ty, target);
6200 const error_offset = errUnionErrorOffset(payload_ty, target);6319 const error_offset = errUnionErrorOffset(payload_ty, target);
6201 if (isByRef(inst_ty)) {6320 if (isByRef(err_un_ty)) {
6202 const result_ptr = self.buildAlloca(err_un_llvm_ty);6321 const result_ptr = self.buildAlloca(err_un_llvm_ty);
6322 result_ptr.setAlignment(err_un_ty.abiAlignment(target));
6203 const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, "");6323 const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, "");
6204 const store_inst = self.builder.buildStore(ok_err_code, err_ptr);6324 const store_inst = self.builder.buildStore(ok_err_code, err_ptr);
6205 store_inst.setAlignment(Type.anyerror.abiAlignment(target));6325 store_inst.setAlignment(Type.anyerror.abiAlignment(target));
...@@ -6234,6 +6354,7 @@ pub const FuncGen = struct {...@@ -6234,6 +6354,7 @@ pub const FuncGen = struct {
6234 const error_offset = errUnionErrorOffset(payload_ty, target);6354 const error_offset = errUnionErrorOffset(payload_ty, target);
6235 if (isByRef(err_un_ty)) {6355 if (isByRef(err_un_ty)) {
6236 const result_ptr = self.buildAlloca(err_un_llvm_ty);6356 const result_ptr = self.buildAlloca(err_un_llvm_ty);
6357 result_ptr.setAlignment(err_un_ty.abiAlignment(target));
6237 const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, "");6358 const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, "");
6238 const store_inst = self.builder.buildStore(operand, err_ptr);6359 const store_inst = self.builder.buildStore(operand, err_ptr);
6239 store_inst.setAlignment(Type.anyerror.abiAlignment(target));6360 store_inst.setAlignment(Type.anyerror.abiAlignment(target));
...@@ -7412,7 +7533,7 @@ pub const FuncGen = struct {...@@ -7412,7 +7533,7 @@ pub const FuncGen = struct {
7412 const lbrace_col = func.lbrace_column + 1;7533 const lbrace_col = func.lbrace_column + 1;
7413 const di_local_var = dib.createParameterVariable(7534 const di_local_var = dib.createParameterVariable(
7414 self.di_scope.?,7535 self.di_scope.?,
7415 func.getParamName(src_index).ptr, // TODO test 0 bit args7536 func.getParamName(self.dg.module, src_index).ptr, // TODO test 0 bit args
7416 self.di_file.?,7537 self.di_file.?,
7417 lbrace_line,7538 lbrace_line,
7418 try self.dg.object.lowerDebugType(inst_ty, .full),7539 try self.dg.object.lowerDebugType(inst_ty, .full),
...@@ -7515,8 +7636,7 @@ pub const FuncGen = struct {...@@ -7515,8 +7636,7 @@ pub const FuncGen = struct {
7515 const len = usize_llvm_ty.constInt(operand_size, .False);7636 const len = usize_llvm_ty.constInt(operand_size, .False);
7516 _ = self.builder.buildMemSet(dest_ptr_u8, fill_char, len, dest_ptr_align, ptr_ty.isVolatilePtr());7637 _ = self.builder.buildMemSet(dest_ptr_u8, fill_char, len, dest_ptr_align, ptr_ty.isVolatilePtr());
7517 if (self.dg.module.comp.bin_file.options.valgrind) {7638 if (self.dg.module.comp.bin_file.options.valgrind) {
7518 // TODO generate valgrind client request to mark byte range as undefined7639 self.valgrindMarkUndef(dest_ptr, len);
7519 // see gen_valgrind_undef() in codegen.cpp
7520 }7640 }
7521 } else {7641 } else {
7522 const src_operand = try self.resolveInst(bin_op.rhs);7642 const src_operand = try self.resolveInst(bin_op.rhs);
...@@ -7786,8 +7906,7 @@ pub const FuncGen = struct {...@@ -7786,8 +7906,7 @@ pub const FuncGen = struct {
7786 _ = self.builder.buildMemSet(dest_ptr_u8, fill_char, len, dest_ptr_align, ptr_ty.isVolatilePtr());7906 _ = self.builder.buildMemSet(dest_ptr_u8, fill_char, len, dest_ptr_align, ptr_ty.isVolatilePtr());
77877907
7788 if (val_is_undef and self.dg.module.comp.bin_file.options.valgrind) {7908 if (val_is_undef and self.dg.module.comp.bin_file.options.valgrind) {
7789 // TODO generate valgrind client request to mark byte range as undefined7909 self.valgrindMarkUndef(dest_ptr_u8, len);
7790 // see gen_valgrind_undef() in codegen.cpp
7791 }7910 }
7792 return null;7911 return null;
7793 }7912 }
...@@ -7994,6 +8113,134 @@ pub const FuncGen = struct {...@@ -7994,6 +8113,134 @@ pub const FuncGen = struct {
7994 }8113 }
7995 }8114 }
79968115
8116 fn airErrorSetHasValue(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
8117 if (self.liveness.isUnused(inst)) return null;
8118
8119 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
8120 const operand = try self.resolveInst(ty_op.operand);
8121 const error_set_ty = self.air.getRefType(ty_op.ty);
8122
8123 const names = error_set_ty.errorSetNames();
8124 const valid_block = self.dg.context.appendBasicBlock(self.llvm_func, "Valid");
8125 const invalid_block = self.dg.context.appendBasicBlock(self.llvm_func, "Invalid");
8126 const end_block = self.context.appendBasicBlock(self.llvm_func, "End");
8127 const switch_instr = self.builder.buildSwitch(operand, invalid_block, @intCast(c_uint, names.len));
8128
8129 for (names) |name| {
8130 const err_int = self.dg.module.global_error_set.get(name).?;
8131 const this_tag_int_value = int: {
8132 var tag_val_payload: Value.Payload.U64 = .{
8133 .base = .{ .tag = .int_u64 },
8134 .data = err_int,
8135 };
8136 break :int try self.dg.lowerValue(.{
8137 .ty = Type.err_int,
8138 .val = Value.initPayload(&tag_val_payload.base),
8139 });
8140 };
8141 switch_instr.addCase(this_tag_int_value, valid_block);
8142 }
8143 self.builder.positionBuilderAtEnd(valid_block);
8144 _ = self.builder.buildBr(end_block);
8145
8146 self.builder.positionBuilderAtEnd(invalid_block);
8147 _ = self.builder.buildBr(end_block);
8148
8149 self.builder.positionBuilderAtEnd(end_block);
8150
8151 const llvm_type = self.dg.context.intType(1);
8152 const incoming_values: [2]*const llvm.Value = .{
8153 llvm_type.constInt(1, .False), llvm_type.constInt(0, .False),
8154 };
8155 const incoming_blocks: [2]*const llvm.BasicBlock = .{
8156 valid_block, invalid_block,
8157 };
8158 const phi_node = self.builder.buildPhi(llvm_type, "");
8159 phi_node.addIncoming(&incoming_values, &incoming_blocks, 2);
8160 return phi_node;
8161 }
8162
8163 fn airIsNamedEnumValue(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
8164 if (self.liveness.isUnused(inst)) return null;
8165
8166 const un_op = self.air.instructions.items(.data)[inst].un_op;
8167 const operand = try self.resolveInst(un_op);
8168 const enum_ty = self.air.typeOf(un_op);
8169
8170 const llvm_fn = try self.getIsNamedEnumValueFunction(enum_ty);
8171 const params = [_]*const llvm.Value{operand};
8172 return self.builder.buildCall(llvm_fn, &params, params.len, .Fast, .Auto, "");
8173 }
8174
8175 fn getIsNamedEnumValueFunction(self: *FuncGen, enum_ty: Type) !*const llvm.Value {
8176 const enum_decl = enum_ty.getOwnerDecl();
8177
8178 // TODO: detect when the type changes and re-emit this function.
8179 const gop = try self.dg.object.named_enum_map.getOrPut(self.dg.gpa, enum_decl);
8180 if (gop.found_existing) return gop.value_ptr.*;
8181 errdefer assert(self.dg.object.named_enum_map.remove(enum_decl));
8182
8183 var arena_allocator = std.heap.ArenaAllocator.init(self.gpa);
8184 defer arena_allocator.deinit();
8185 const arena = arena_allocator.allocator();
8186
8187 const mod = self.dg.module;
8188 const llvm_fn_name = try std.fmt.allocPrintZ(arena, "__zig_is_named_enum_value_{s}", .{
8189 try mod.declPtr(enum_decl).getFullyQualifiedName(mod),
8190 });
8191
8192 var int_tag_type_buffer: Type.Payload.Bits = undefined;
8193 const int_tag_ty = enum_ty.intTagType(&int_tag_type_buffer);
8194 const param_types = [_]*const llvm.Type{try self.dg.lowerType(int_tag_ty)};
8195
8196 const llvm_ret_ty = try self.dg.lowerType(Type.bool);
8197 const fn_type = llvm.functionType(llvm_ret_ty, &param_types, param_types.len, .False);
8198 const fn_val = self.dg.object.llvm_module.addFunction(llvm_fn_name, fn_type);
8199 fn_val.setLinkage(.Internal);
8200 fn_val.setFunctionCallConv(.Fast);
8201 self.dg.addCommonFnAttributes(fn_val);
8202 gop.value_ptr.* = fn_val;
8203
8204 const prev_block = self.builder.getInsertBlock();
8205 const prev_debug_location = self.builder.getCurrentDebugLocation2();
8206 defer {
8207 self.builder.positionBuilderAtEnd(prev_block);
8208 if (self.di_scope != null) {
8209 self.builder.setCurrentDebugLocation2(prev_debug_location);
8210 }
8211 }
8212
8213 const entry_block = self.dg.context.appendBasicBlock(fn_val, "Entry");
8214 self.builder.positionBuilderAtEnd(entry_block);
8215 self.builder.clearCurrentDebugLocation();
8216
8217 const fields = enum_ty.enumFields();
8218 const named_block = self.dg.context.appendBasicBlock(fn_val, "Named");
8219 const unnamed_block = self.dg.context.appendBasicBlock(fn_val, "Unnamed");
8220 const tag_int_value = fn_val.getParam(0);
8221 const switch_instr = self.builder.buildSwitch(tag_int_value, unnamed_block, @intCast(c_uint, fields.count()));
8222
8223 for (fields.keys()) |_, field_index| {
8224 const this_tag_int_value = int: {
8225 var tag_val_payload: Value.Payload.U32 = .{
8226 .base = .{ .tag = .enum_field_index },
8227 .data = @intCast(u32, field_index),
8228 };
8229 break :int try self.dg.lowerValue(.{
8230 .ty = enum_ty,
8231 .val = Value.initPayload(&tag_val_payload.base),
8232 });
8233 };
8234 switch_instr.addCase(this_tag_int_value, named_block);
8235 }
8236 self.builder.positionBuilderAtEnd(named_block);
8237 _ = self.builder.buildRet(self.dg.context.intType(1).constInt(1, .False));
8238
8239 self.builder.positionBuilderAtEnd(unnamed_block);
8240 _ = self.builder.buildRet(self.dg.context.intType(1).constInt(0, .False));
8241 return fn_val;
8242 }
8243
7997 fn airTagName(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {8244 fn airTagName(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
7998 if (self.liveness.isUnused(inst)) return null;8245 if (self.liveness.isUnused(inst)) return null;
79998246
...@@ -8272,8 +8519,8 @@ pub const FuncGen = struct {...@@ -8272,8 +8519,8 @@ pub const FuncGen = struct {
8272 .Struct => {8519 .Struct => {
8273 if (result_ty.containerLayout() == .Packed) {8520 if (result_ty.containerLayout() == .Packed) {
8274 const struct_obj = result_ty.castTag(.@"struct").?.data;8521 const struct_obj = result_ty.castTag(.@"struct").?.data;
8275 const big_bits = struct_obj.packedIntegerBits(target);8522 const big_bits = struct_obj.backing_int_ty.bitSize(target);
8276 const int_llvm_ty = self.dg.context.intType(big_bits);8523 const int_llvm_ty = self.dg.context.intType(@intCast(c_uint, big_bits));
8277 const fields = struct_obj.fields.values();8524 const fields = struct_obj.fields.values();
8278 comptime assert(Type.packed_struct_layout_version == 2);8525 comptime assert(Type.packed_struct_layout_version == 2);
8279 var running_int: *const llvm.Value = int_llvm_ty.constNull();8526 var running_int: *const llvm.Value = int_llvm_ty.constNull();
...@@ -8285,7 +8532,7 @@ pub const FuncGen = struct {...@@ -8285,7 +8532,7 @@ pub const FuncGen = struct {
8285 const non_int_val = try self.resolveInst(elem);8532 const non_int_val = try self.resolveInst(elem);
8286 const ty_bit_size = @intCast(u16, field.ty.bitSize(target));8533 const ty_bit_size = @intCast(u16, field.ty.bitSize(target));
8287 const small_int_ty = self.dg.context.intType(ty_bit_size);8534 const small_int_ty = self.dg.context.intType(ty_bit_size);
8288 const small_int_val = if (field.ty.zigTypeTag() == .Pointer)8535 const small_int_val = if (field.ty.isPtrAtRuntime())
8289 self.builder.buildPtrToInt(non_int_val, small_int_ty, "")8536 self.builder.buildPtrToInt(non_int_val, small_int_ty, "")
8290 else8537 else
8291 self.builder.buildBitCast(non_int_val, small_int_ty, "");8538 self.builder.buildBitCast(non_int_val, small_int_ty, "");
...@@ -8973,6 +9220,89 @@ pub const FuncGen = struct {...@@ -8973,6 +9220,89 @@ pub const FuncGen = struct {
8973 info.@"volatile",9220 info.@"volatile",
8974 );9221 );
8975 }9222 }
9223
9224 fn valgrindMarkUndef(fg: *FuncGen, ptr: *const llvm.Value, len: *const llvm.Value) void {
9225 const VG_USERREQ__MAKE_MEM_UNDEFINED = 1296236545;
9226 const target = fg.dg.module.getTarget();
9227 const usize_llvm_ty = fg.context.intType(target.cpu.arch.ptrBitWidth());
9228 const zero = usize_llvm_ty.constInt(0, .False);
9229 const req = usize_llvm_ty.constInt(VG_USERREQ__MAKE_MEM_UNDEFINED, .False);
9230 const ptr_as_usize = fg.builder.buildPtrToInt(ptr, usize_llvm_ty, "");
9231 _ = valgrindClientRequest(fg, zero, req, ptr_as_usize, len, zero, zero, zero);
9232 }
9233
9234 fn valgrindClientRequest(
9235 fg: *FuncGen,
9236 default_value: *const llvm.Value,
9237 request: *const llvm.Value,
9238 a1: *const llvm.Value,
9239 a2: *const llvm.Value,
9240 a3: *const llvm.Value,
9241 a4: *const llvm.Value,
9242 a5: *const llvm.Value,
9243 ) *const llvm.Value {
9244 const target = fg.dg.module.getTarget();
9245 if (!target_util.hasValgrindSupport(target)) return default_value;
9246
9247 const usize_llvm_ty = fg.context.intType(target.cpu.arch.ptrBitWidth());
9248 const usize_alignment = @intCast(c_uint, Type.usize.abiSize(target));
9249
9250 switch (target.cpu.arch) {
9251 .x86_64 => {
9252 const array_ptr = fg.valgrind_client_request_array orelse a: {
9253 const array_ptr = fg.buildAlloca(usize_llvm_ty.arrayType(6));
9254 array_ptr.setAlignment(usize_alignment);
9255 fg.valgrind_client_request_array = array_ptr;
9256 break :a array_ptr;
9257 };
9258 const array_elements = [_]*const llvm.Value{ request, a1, a2, a3, a4, a5 };
9259 const zero = usize_llvm_ty.constInt(0, .False);
9260 for (array_elements) |elem, i| {
9261 const indexes = [_]*const llvm.Value{
9262 zero, usize_llvm_ty.constInt(@intCast(c_uint, i), .False),
9263 };
9264 const elem_ptr = fg.builder.buildInBoundsGEP(array_ptr, &indexes, indexes.len, "");
9265 const store_inst = fg.builder.buildStore(elem, elem_ptr);
9266 store_inst.setAlignment(usize_alignment);
9267 }
9268
9269 const asm_template =
9270 \\rolq $$3, %rdi ; rolq $$13, %rdi
9271 \\rolq $$61, %rdi ; rolq $$51, %rdi
9272 \\xchgq %rbx,%rbx
9273 ;
9274
9275 const asm_constraints = "={rdx},{rax},0,~{cc},~{memory}";
9276
9277 const array_ptr_as_usize = fg.builder.buildPtrToInt(array_ptr, usize_llvm_ty, "");
9278 const args = [_]*const llvm.Value{ array_ptr_as_usize, default_value };
9279 const param_types = [_]*const llvm.Type{ usize_llvm_ty, usize_llvm_ty };
9280 const fn_llvm_ty = llvm.functionType(usize_llvm_ty, &param_types, args.len, .False);
9281 const asm_fn = llvm.getInlineAsm(
9282 fn_llvm_ty,
9283 asm_template,
9284 asm_template.len,
9285 asm_constraints,
9286 asm_constraints.len,
9287 .True, // has side effects
9288 .False, // alignstack
9289 .ATT,
9290 .False,
9291 );
9292
9293 const call = fg.builder.buildCall(
9294 asm_fn,
9295 &args,
9296 args.len,
9297 .C,
9298 .Auto,
9299 "",
9300 );
9301 return call;
9302 },
9303 else => unreachable,
9304 }
9305 }
8976};9306};
89779307
8978fn initializeLLVMTarget(arch: std.Target.Cpu.Arch) void {9308fn initializeLLVMTarget(arch: std.Target.Cpu.Arch) void {
...@@ -9266,13 +9596,14 @@ fn llvmFieldIndex(...@@ -9266,13 +9596,14 @@ fn llvmFieldIndex(
9266 }9596 }
9267 return null;9597 return null;
9268 }9598 }
9269 assert(ty.containerLayout() != .Packed);9599 const layout = ty.containerLayout();
9600 assert(layout != .Packed);
92709601
9271 var llvm_field_index: c_uint = 0;9602 var llvm_field_index: c_uint = 0;
9272 for (ty.structFields().values()) |field, i| {9603 for (ty.structFields().values()) |field, i| {
9273 if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue;9604 if (field.is_comptime or !field.ty.hasRuntimeBits()) continue;
92749605
9275 const field_align = field.normalAlignment(target);9606 const field_align = field.alignment(target, layout);
9276 big_align = @maximum(big_align, field_align);9607 big_align = @maximum(big_align, field_align);
9277 const prev_offset = offset;9608 const prev_offset = offset;
9278 offset = std.mem.alignForwardGeneric(u64, offset, field_align);9609 offset = std.mem.alignForwardGeneric(u64, offset, field_align);
...@@ -9392,16 +9723,20 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm....@@ -9392,16 +9723,20 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm.
9392 llvm_types_index += 1;9723 llvm_types_index += 1;
9393 },9724 },
9394 .sse => {9725 .sse => {
9395 @panic("TODO");9726 llvm_types_buffer[llvm_types_index] = dg.context.doubleType();
9727 llvm_types_index += 1;
9396 },9728 },
9397 .sseup => {9729 .sseup => {
9398 @panic("TODO");9730 llvm_types_buffer[llvm_types_index] = dg.context.doubleType();
9731 llvm_types_index += 1;
9399 },9732 },
9400 .x87 => {9733 .x87 => {
9401 @panic("TODO");9734 llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type();
9735 llvm_types_index += 1;
9402 },9736 },
9403 .x87up => {9737 .x87up => {
9404 @panic("TODO");9738 llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type();
9739 llvm_types_index += 1;
9405 },9740 },
9406 .complex_x87 => {9741 .complex_x87 => {
9407 @panic("TODO");9742 @panic("TODO");
...@@ -9447,6 +9782,7 @@ const ParamTypeIterator = struct {...@@ -9447,6 +9782,7 @@ const ParamTypeIterator = struct {
9447 target: std.Target,9782 target: std.Target,
9448 llvm_types_len: u32,9783 llvm_types_len: u32,
9449 llvm_types_buffer: [8]u16,9784 llvm_types_buffer: [8]u16,
9785 byval_attr: bool,
94509786
9451 const Lowering = enum {9787 const Lowering = enum {
9452 no_bits,9788 no_bits,
...@@ -9454,6 +9790,7 @@ const ParamTypeIterator = struct {...@@ -9454,6 +9790,7 @@ const ParamTypeIterator = struct {
9454 byref,9790 byref,
9455 abi_sized_int,9791 abi_sized_int,
9456 multiple_llvm_ints,9792 multiple_llvm_ints,
9793 multiple_llvm_float,
9457 slice,9794 slice,
9458 as_u16,9795 as_u16,
9459 };9796 };
...@@ -9461,6 +9798,7 @@ const ParamTypeIterator = struct {...@@ -9461,6 +9798,7 @@ const ParamTypeIterator = struct {
9461 pub fn next(it: *ParamTypeIterator) ?Lowering {9798 pub fn next(it: *ParamTypeIterator) ?Lowering {
9462 if (it.zig_index >= it.fn_info.param_types.len) return null;9799 if (it.zig_index >= it.fn_info.param_types.len) return null;
9463 const ty = it.fn_info.param_types[it.zig_index];9800 const ty = it.fn_info.param_types[it.zig_index];
9801 it.byval_attr = false;
9464 return nextInner(it, ty);9802 return nextInner(it, ty);
9465 }9803 }
94669804
...@@ -9546,6 +9884,7 @@ const ParamTypeIterator = struct {...@@ -9546,6 +9884,7 @@ const ParamTypeIterator = struct {
9546 .memory => {9884 .memory => {
9547 it.zig_index += 1;9885 it.zig_index += 1;
9548 it.llvm_index += 1;9886 it.llvm_index += 1;
9887 it.byval_attr = true;
9549 return .byref;9888 return .byref;
9550 },9889 },
9551 .sse => {9890 .sse => {
...@@ -9565,6 +9904,7 @@ const ParamTypeIterator = struct {...@@ -9565,6 +9904,7 @@ const ParamTypeIterator = struct {
9565 if (classes[0] == .memory) {9904 if (classes[0] == .memory) {
9566 it.zig_index += 1;9905 it.zig_index += 1;
9567 it.llvm_index += 1;9906 it.llvm_index += 1;
9907 it.byval_attr = true;
9568 return .byref;9908 return .byref;
9569 }9909 }
9570 var llvm_types_buffer: [8]u16 = undefined;9910 var llvm_types_buffer: [8]u16 = undefined;
...@@ -9576,16 +9916,20 @@ const ParamTypeIterator = struct {...@@ -9576,16 +9916,20 @@ const ParamTypeIterator = struct {
9576 llvm_types_index += 1;9916 llvm_types_index += 1;
9577 },9917 },
9578 .sse => {9918 .sse => {
9579 @panic("TODO");9919 llvm_types_buffer[llvm_types_index] = 64;
9920 llvm_types_index += 1;
9580 },9921 },
9581 .sseup => {9922 .sseup => {
9582 @panic("TODO");9923 llvm_types_buffer[llvm_types_index] = 64;
9924 llvm_types_index += 1;
9583 },9925 },
9584 .x87 => {9926 .x87 => {
9585 @panic("TODO");9927 llvm_types_buffer[llvm_types_index] = 80;
9928 llvm_types_index += 1;
9586 },9929 },
9587 .x87up => {9930 .x87up => {
9588 @panic("TODO");9931 llvm_types_buffer[llvm_types_index] = 80;
9932 llvm_types_index += 1;
9589 },9933 },
9590 .complex_x87 => {9934 .complex_x87 => {
9591 @panic("TODO");9935 @panic("TODO");
...@@ -9599,11 +9943,16 @@ const ParamTypeIterator = struct {...@@ -9599,11 +9943,16 @@ const ParamTypeIterator = struct {
9599 it.llvm_index += 1;9943 it.llvm_index += 1;
9600 return .abi_sized_int;9944 return .abi_sized_int;
9601 }9945 }
9946 if (classes[0] == .sse and classes[1] == .none) {
9947 it.zig_index += 1;
9948 it.llvm_index += 1;
9949 return .byval;
9950 }
9602 it.llvm_types_buffer = llvm_types_buffer;9951 it.llvm_types_buffer = llvm_types_buffer;
9603 it.llvm_types_len = llvm_types_index;9952 it.llvm_types_len = llvm_types_index;
9604 it.llvm_index += llvm_types_index;9953 it.llvm_index += llvm_types_index;
9605 it.zig_index += 1;9954 it.zig_index += 1;
9606 return .multiple_llvm_ints;9955 return if (classes[0] == .integer) .multiple_llvm_ints else .multiple_llvm_float;
9607 },9956 },
9608 },9957 },
9609 .wasm32 => {9958 .wasm32 => {
...@@ -9644,6 +9993,7 @@ fn iterateParamTypes(dg: *DeclGen, fn_info: Type.Payload.Function.Data) ParamTyp...@@ -9644,6 +9993,7 @@ fn iterateParamTypes(dg: *DeclGen, fn_info: Type.Payload.Function.Data) ParamTyp
9644 .target = dg.module.getTarget(),9993 .target = dg.module.getTarget(),
9645 .llvm_types_buffer = undefined,9994 .llvm_types_buffer = undefined,
9646 .llvm_types_len = 0,9995 .llvm_types_len = 0,
9996 .byval_attr = false,
9647 };9997 };
9648}9998}
96499999
src/codegen/llvm/bindings.zig+15
...@@ -129,6 +129,9 @@ pub const Value = opaque {...@@ -129,6 +129,9 @@ pub const Value = opaque {
129 pub const setThreadLocalMode = LLVMSetThreadLocalMode;129 pub const setThreadLocalMode = LLVMSetThreadLocalMode;
130 extern fn LLVMSetThreadLocalMode(Global: *const Value, Mode: ThreadLocalMode) void;130 extern fn LLVMSetThreadLocalMode(Global: *const Value, Mode: ThreadLocalMode) void;
131131
132 pub const setSection = LLVMSetSection;
133 extern fn LLVMSetSection(Global: *const Value, Section: [*:0]const u8) void;
134
132 pub const deleteGlobal = LLVMDeleteGlobal;135 pub const deleteGlobal = LLVMDeleteGlobal;
133 extern fn LLVMDeleteGlobal(GlobalVar: *const Value) void;136 extern fn LLVMDeleteGlobal(GlobalVar: *const Value) void;
134137
...@@ -216,6 +219,9 @@ pub const Value = opaque {...@@ -216,6 +219,9 @@ pub const Value = opaque {
216 pub const setInitializer = LLVMSetInitializer;219 pub const setInitializer = LLVMSetInitializer;
217 extern fn LLVMSetInitializer(GlobalVar: *const Value, ConstantVal: *const Value) void;220 extern fn LLVMSetInitializer(GlobalVar: *const Value, ConstantVal: *const Value) void;
218221
222 pub const setDLLStorageClass = LLVMSetDLLStorageClass;
223 extern fn LLVMSetDLLStorageClass(Global: *const Value, Class: DLLStorageClass) void;
224
219 pub const addCase = LLVMAddCase;225 pub const addCase = LLVMAddCase;
220 extern fn LLVMAddCase(Switch: *const Value, OnVal: *const Value, Dest: *const BasicBlock) void;226 extern fn LLVMAddCase(Switch: *const Value, OnVal: *const Value, Dest: *const BasicBlock) void;
221227
...@@ -244,6 +250,9 @@ pub const Value = opaque {...@@ -244,6 +250,9 @@ pub const Value = opaque {
244250
245 pub const getGEPResultElementType = ZigLLVMGetGEPResultElementType;251 pub const getGEPResultElementType = ZigLLVMGetGEPResultElementType;
246 extern fn ZigLLVMGetGEPResultElementType(GEP: *const Value) *const Type;252 extern fn ZigLLVMGetGEPResultElementType(GEP: *const Value) *const Type;
253
254 pub const addByValAttr = ZigLLVMAddByValAttr;
255 extern fn ZigLLVMAddByValAttr(Fn: *const Value, ArgNo: c_uint, type: *const Type) void;
247};256};
248257
249pub const Type = opaque {258pub const Type = opaque {
...@@ -1486,6 +1495,12 @@ pub const CallAttr = enum(c_int) {...@@ -1486,6 +1495,12 @@ pub const CallAttr = enum(c_int) {
1486 AlwaysInline,1495 AlwaysInline,
1487};1496};
14881497
1498pub const DLLStorageClass = enum(c_uint) {
1499 Default,
1500 DLLImport,
1501 DLLExport,
1502};
1503
1489pub const address_space = struct {1504pub const address_space = struct {
1490 pub const default: c_uint = 0;1505 pub const default: c_uint = 0;
14911506
src/config.zig.in+1-2
...@@ -8,6 +8,5 @@ pub const enable_logging: bool = @ZIG_ENABLE_LOGGING_BOOL@;...@@ -8,6 +8,5 @@ pub const enable_logging: bool = @ZIG_ENABLE_LOGGING_BOOL@;
8pub const enable_link_snapshots: bool = false;8pub const enable_link_snapshots: bool = false;
9pub const enable_tracy = false;9pub const enable_tracy = false;
10pub const value_tracing = false;10pub const value_tracing = false;
11pub const is_stage1 = true;11pub const have_stage1 = true;
12pub const skip_non_native = false;12pub const skip_non_native = false;
13pub const omit_stage2: bool = @ZIG_OMIT_STAGE2_BOOL@;
src/glibc.zig+4-49
...@@ -41,29 +41,7 @@ pub const libs = [_]Lib{...@@ -41,29 +41,7 @@ pub const libs = [_]Lib{
41 .{ .name = "rt", .sover = 1 },41 .{ .name = "rt", .sover = 1 },
42 .{ .name = "ld", .sover = 2 },42 .{ .name = "ld", .sover = 2 },
43 .{ .name = "util", .sover = 1 },43 .{ .name = "util", .sover = 1 },
44};44 .{ .name = "resolv", .sover = 2 },
45
46// glibc's naming of Zig architectures
47const Arch = enum(c_int) {
48 arm,
49 armeb,
50 aarch64,
51 aarch64_be,
52 mips,
53 mipsel,
54 mips64,
55 mips64el,
56 powerpc,
57 powerpc64,
58 powerpc64le,
59 riscv32,
60 riscv64,
61 sparc,
62 sparcv9,
63 sparcel,
64 s390x,
65 i386,
66 x86_64,
67};45};
6846
69pub const LoadMetaDataError = error{47pub const LoadMetaDataError = error{
...@@ -157,7 +135,7 @@ pub fn loadMetaData(gpa: Allocator, zig_lib_dir: fs.Dir) LoadMetaDataError!*ABI...@@ -157,7 +135,7 @@ pub fn loadMetaData(gpa: Allocator, zig_lib_dir: fs.Dir) LoadMetaDataError!*ABI
157 log.err("abilists: expected ABI name", .{});135 log.err("abilists: expected ABI name", .{});
158 return error.ZigInstallationCorrupt;136 return error.ZigInstallationCorrupt;
159 };137 };
160 const arch_tag = std.meta.stringToEnum(Arch, arch_name) orelse {138 const arch_tag = std.meta.stringToEnum(std.Target.Cpu.Arch, arch_name) orelse {
161 log.err("abilists: unrecognized arch: '{s}'", .{arch_name});139 log.err("abilists: unrecognized arch: '{s}'", .{arch_name});
162 return error.ZigInstallationCorrupt;140 return error.ZigInstallationCorrupt;
163 };141 };
...@@ -171,7 +149,7 @@ pub fn loadMetaData(gpa: Allocator, zig_lib_dir: fs.Dir) LoadMetaDataError!*ABI...@@ -171,7 +149,7 @@ pub fn loadMetaData(gpa: Allocator, zig_lib_dir: fs.Dir) LoadMetaDataError!*ABI
171 };149 };
172150
173 targets[i] = .{151 targets[i] = .{
174 .arch = glibcToZigArch(arch_tag),152 .arch = arch_tag,
175 .os = .linux,153 .os = .linux,
176 .abi = abi_tag,154 .abi = abi_tag,
177 };155 };
...@@ -1111,6 +1089,7 @@ fn buildSharedLib(...@@ -1111,6 +1089,7 @@ fn buildSharedLib(
1111 .optimize_mode = comp.compilerRtOptMode(),1089 .optimize_mode = comp.compilerRtOptMode(),
1112 .want_sanitize_c = false,1090 .want_sanitize_c = false,
1113 .want_stack_check = false,1091 .want_stack_check = false,
1092 .want_stack_protector = 0,
1114 .want_red_zone = comp.bin_file.options.red_zone,1093 .want_red_zone = comp.bin_file.options.red_zone,
1115 .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer,1094 .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer,
1116 .want_valgrind = false,1095 .want_valgrind = false,
...@@ -1138,30 +1117,6 @@ fn buildSharedLib(...@@ -1138,30 +1117,6 @@ fn buildSharedLib(
1138 try sub_compilation.updateSubCompilation();1117 try sub_compilation.updateSubCompilation();
1139}1118}
11401119
1141fn glibcToZigArch(arch_tag: Arch) std.Target.Cpu.Arch {
1142 return switch (arch_tag) {
1143 .arm => .arm,
1144 .armeb => .armeb,
1145 .aarch64 => .aarch64,
1146 .aarch64_be => .aarch64_be,
1147 .mips => .mips,
1148 .mipsel => .mipsel,
1149 .mips64 => .mips64,
1150 .mips64el => .mips64el,
1151 .powerpc => .powerpc,
1152 .powerpc64 => .powerpc64,
1153 .powerpc64le => .powerpc64le,
1154 .riscv32 => .riscv32,
1155 .riscv64 => .riscv64,
1156 .sparc => .sparc,
1157 .sparcv9 => .sparc64, // In glibc, sparc64 is called sparcv9.
1158 .sparcel => .sparcel,
1159 .s390x => .s390x,
1160 .i386 => .i386,
1161 .x86_64 => .x86_64,
1162 };
1163}
1164
1165// Return true if glibc has crti/crtn sources for that architecture.1120// Return true if glibc has crti/crtn sources for that architecture.
1166pub fn needsCrtiCrtn(target: std.Target) bool {1121pub fn needsCrtiCrtn(target: std.Target) bool {
1167 return switch (target.cpu.arch) {1122 return switch (target.cpu.arch) {
src/libcxx.zig+2
...@@ -208,6 +208,7 @@ pub fn buildLibCXX(comp: *Compilation) !void {...@@ -208,6 +208,7 @@ pub fn buildLibCXX(comp: *Compilation) !void {
208 .link_mode = link_mode,208 .link_mode = link_mode,
209 .want_sanitize_c = false,209 .want_sanitize_c = false,
210 .want_stack_check = false,210 .want_stack_check = false,
211 .want_stack_protector = 0,
211 .want_red_zone = comp.bin_file.options.red_zone,212 .want_red_zone = comp.bin_file.options.red_zone,
212 .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer,213 .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer,
213 .want_valgrind = false,214 .want_valgrind = false,
...@@ -351,6 +352,7 @@ pub fn buildLibCXXABI(comp: *Compilation) !void {...@@ -351,6 +352,7 @@ pub fn buildLibCXXABI(comp: *Compilation) !void {
351 .link_mode = link_mode,352 .link_mode = link_mode,
352 .want_sanitize_c = false,353 .want_sanitize_c = false,
353 .want_stack_check = false,354 .want_stack_check = false,
355 .want_stack_protector = 0,
354 .want_red_zone = comp.bin_file.options.red_zone,356 .want_red_zone = comp.bin_file.options.red_zone,
355 .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer,357 .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer,
356 .want_valgrind = false,358 .want_valgrind = false,
src/libtsan.zig+1
...@@ -211,6 +211,7 @@ pub fn buildTsan(comp: *Compilation) !void {...@@ -211,6 +211,7 @@ pub fn buildTsan(comp: *Compilation) !void {
211 .link_mode = link_mode,211 .link_mode = link_mode,
212 .want_sanitize_c = false,212 .want_sanitize_c = false,
213 .want_stack_check = false,213 .want_stack_check = false,
214 .want_stack_protector = 0,
214 .want_valgrind = false,215 .want_valgrind = false,
215 .want_tsan = false,216 .want_tsan = false,
216 .want_pic = true,217 .want_pic = true,
src/libunwind.zig+1
...@@ -102,6 +102,7 @@ pub fn buildStaticLib(comp: *Compilation) !void {...@@ -102,6 +102,7 @@ pub fn buildStaticLib(comp: *Compilation) !void {
102 .link_mode = link_mode,102 .link_mode = link_mode,
103 .want_sanitize_c = false,103 .want_sanitize_c = false,
104 .want_stack_check = false,104 .want_stack_check = false,
105 .want_stack_protector = 0,
105 .want_red_zone = comp.bin_file.options.red_zone,106 .want_red_zone = comp.bin_file.options.red_zone,
106 .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer,107 .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer,
107 .want_valgrind = false,108 .want_valgrind = false,
src/link.zig+23-11
...@@ -72,7 +72,6 @@ pub const Options = struct {...@@ -72,7 +72,6 @@ pub const Options = struct {
72 target: std.Target,72 target: std.Target,
73 output_mode: std.builtin.OutputMode,73 output_mode: std.builtin.OutputMode,
74 link_mode: std.builtin.LinkMode,74 link_mode: std.builtin.LinkMode,
75 object_format: std.Target.ObjectFormat,
76 optimize_mode: std.builtin.Mode,75 optimize_mode: std.builtin.Mode,
77 machine_code_model: std.builtin.CodeModel,76 machine_code_model: std.builtin.CodeModel,
78 root_name: [:0]const u8,77 root_name: [:0]const u8,
...@@ -91,6 +90,9 @@ pub const Options = struct {...@@ -91,6 +90,9 @@ pub const Options = struct {
91 entry: ?[]const u8,90 entry: ?[]const u8,
92 stack_size_override: ?u64,91 stack_size_override: ?u64,
93 image_base_override: ?u64,92 image_base_override: ?u64,
93 /// 0 means no stack protector
94 /// other value means stack protector with that buffer size.
95 stack_protector: u32,
94 cache_mode: CacheMode,96 cache_mode: CacheMode,
95 include_compiler_rt: bool,97 include_compiler_rt: bool,
96 /// Set to `true` to omit debug info.98 /// Set to `true` to omit debug info.
...@@ -173,6 +175,12 @@ pub const Options = struct {...@@ -173,6 +175,12 @@ pub const Options = struct {
173 lib_dirs: []const []const u8,175 lib_dirs: []const []const u8,
174 rpath_list: []const []const u8,176 rpath_list: []const []const u8,
175177
178 /// List of symbols forced as undefined in the symbol table
179 /// thus forcing their resolution by the linker.
180 /// Corresponds to `-u <symbol>` for ELF and `/include:<symbol>` for COFF/PE.
181 /// TODO add handling for MachO.
182 force_undefined_symbols: std.StringArrayHashMapUnmanaged(void),
183
176 version: ?std.builtin.Version,184 version: ?std.builtin.Version,
177 compatibility_version: ?std.builtin.Version,185 compatibility_version: ?std.builtin.Version,
178 libc_installation: ?*const LibCInstallation,186 libc_installation: ?*const LibCInstallation,
...@@ -273,13 +281,13 @@ pub const File = struct {...@@ -273,13 +281,13 @@ pub const File = struct {
273 /// rewriting it. A malicious file is detected as incremental link failure281 /// rewriting it. A malicious file is detected as incremental link failure
274 /// and does not cause Illegal Behavior. This operation is not atomic.282 /// and does not cause Illegal Behavior. This operation is not atomic.
275 pub fn openPath(allocator: Allocator, options: Options) !*File {283 pub fn openPath(allocator: Allocator, options: Options) !*File {
276 if (options.object_format == .macho) {284 if (options.target.ofmt == .macho) {
277 return &(try MachO.openPath(allocator, options)).base;285 return &(try MachO.openPath(allocator, options)).base;
278 }286 }
279287
280 const use_stage1 = build_options.is_stage1 and options.use_stage1;288 const use_stage1 = build_options.have_stage1 and options.use_stage1;
281 if (use_stage1 or options.emit == null) {289 if (use_stage1 or options.emit == null) {
282 return switch (options.object_format) {290 return switch (options.target.ofmt) {
283 .coff => &(try Coff.createEmpty(allocator, options)).base,291 .coff => &(try Coff.createEmpty(allocator, options)).base,
284 .elf => &(try Elf.createEmpty(allocator, options)).base,292 .elf => &(try Elf.createEmpty(allocator, options)).base,
285 .macho => unreachable,293 .macho => unreachable,
...@@ -299,7 +307,7 @@ pub const File = struct {...@@ -299,7 +307,7 @@ pub const File = struct {
299 if (options.module == null) {307 if (options.module == null) {
300 // No point in opening a file, we would not write anything to it.308 // No point in opening a file, we would not write anything to it.
301 // Initialize with empty.309 // Initialize with empty.
302 return switch (options.object_format) {310 return switch (options.target.ofmt) {
303 .coff => &(try Coff.createEmpty(allocator, options)).base,311 .coff => &(try Coff.createEmpty(allocator, options)).base,
304 .elf => &(try Elf.createEmpty(allocator, options)).base,312 .elf => &(try Elf.createEmpty(allocator, options)).base,
305 .macho => unreachable,313 .macho => unreachable,
...@@ -316,12 +324,12 @@ pub const File = struct {...@@ -316,12 +324,12 @@ pub const File = struct {
316 // Open a temporary object file, not the final output file because we324 // Open a temporary object file, not the final output file because we
317 // want to link with LLD.325 // want to link with LLD.
318 break :blk try std.fmt.allocPrint(allocator, "{s}{s}", .{326 break :blk try std.fmt.allocPrint(allocator, "{s}{s}", .{
319 emit.sub_path, options.object_format.fileExt(options.target.cpu.arch),327 emit.sub_path, options.target.ofmt.fileExt(options.target.cpu.arch),
320 });328 });
321 } else emit.sub_path;329 } else emit.sub_path;
322 errdefer if (use_lld) allocator.free(sub_path);330 errdefer if (use_lld) allocator.free(sub_path);
323331
324 const file: *File = switch (options.object_format) {332 const file: *File = switch (options.target.ofmt) {
325 .coff => &(try Coff.openPath(allocator, sub_path, options)).base,333 .coff => &(try Coff.openPath(allocator, sub_path, options)).base,
326 .elf => &(try Elf.openPath(allocator, sub_path, options)).base,334 .elf => &(try Elf.openPath(allocator, sub_path, options)).base,
327 .macho => unreachable,335 .macho => unreachable,
...@@ -421,7 +429,7 @@ pub const File = struct {...@@ -421,7 +429,7 @@ pub const File = struct {
421 NoSpaceLeft,429 NoSpaceLeft,
422 Unseekable,430 Unseekable,
423 PermissionDenied,431 PermissionDenied,
424 FileBusy,432 SwapFile,
425 SystemResources,433 SystemResources,
426 OperationAborted,434 OperationAborted,
427 BrokenPipe,435 BrokenPipe,
...@@ -438,6 +446,7 @@ pub const File = struct {...@@ -438,6 +446,7 @@ pub const File = struct {
438 EmitFail,446 EmitFail,
439 NameTooLong,447 NameTooLong,
440 CurrentWorkingDirectoryUnlinked,448 CurrentWorkingDirectoryUnlinked,
449 LockViolation,
441 };450 };
442451
443 /// Called from within the CodeGen to lower a local variable instantion as an unnamed452 /// Called from within the CodeGen to lower a local variable instantion as an unnamed
...@@ -774,12 +783,15 @@ pub const File = struct {...@@ -774,12 +783,15 @@ pub const File = struct {
774 error.FileNotFound => {},783 error.FileNotFound => {},
775 else => |e| return e,784 else => |e| return e,
776 }785 }
777 try std.fs.rename(786 std.fs.rename(
778 cache_directory.handle,787 cache_directory.handle,
779 tmp_dir_sub_path,788 tmp_dir_sub_path,
780 cache_directory.handle,789 cache_directory.handle,
781 o_sub_path,790 o_sub_path,
782 );791 ) catch |err| switch (err) {
792 error.AccessDenied => unreachable, // We are most likely trying to move a dir with open handles to its resources
793 else => |e| return e,
794 };
783 break;795 break;
784 } else {796 } else {
785 std.fs.rename(797 std.fs.rename(
...@@ -814,7 +826,7 @@ pub const File = struct {...@@ -814,7 +826,7 @@ pub const File = struct {
814 // If there is no Zig code to compile, then we should skip flushing the output file826 // If there is no Zig code to compile, then we should skip flushing the output file
815 // because it will not be part of the linker line anyway.827 // because it will not be part of the linker line anyway.
816 const module_obj_path: ?[]const u8 = if (base.options.module) |module| blk: {828 const module_obj_path: ?[]const u8 = if (base.options.module) |module| blk: {
817 const use_stage1 = build_options.is_stage1 and base.options.use_stage1;829 const use_stage1 = build_options.have_stage1 and base.options.use_stage1;
818 if (use_stage1) {830 if (use_stage1) {
819 const obj_basename = try std.zig.binNameAlloc(arena, .{831 const obj_basename = try std.zig.binNameAlloc(arena, .{
820 .root_name = base.options.root_name,832 .root_name = base.options.root_name,
src/link/C.zig+1-1
...@@ -48,7 +48,7 @@ const DeclBlock = struct {...@@ -48,7 +48,7 @@ const DeclBlock = struct {
48};48};
4949
50pub fn openPath(gpa: Allocator, sub_path: []const u8, options: link.Options) !*C {50pub fn openPath(gpa: Allocator, sub_path: []const u8, options: link.Options) !*C {
51 assert(options.object_format == .c);51 assert(options.target.ofmt == .c);
5252
53 if (options.use_llvm) return error.LLVMHasNoCBackend;53 if (options.use_llvm) return error.LLVMHasNoCBackend;
54 if (options.use_lld) return error.LLDHasNoCBackend;54 if (options.use_lld) return error.LLDHasNoCBackend;
src/link/Coff.zig+25-14
...@@ -128,7 +128,7 @@ pub const TextBlock = struct {...@@ -128,7 +128,7 @@ pub const TextBlock = struct {
128pub const SrcFn = void;128pub const SrcFn = void;
129129
130pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Coff {130pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Coff {
131 assert(options.object_format == .coff);131 assert(options.target.ofmt == .coff);
132132
133 if (build_options.have_llvm and options.use_llvm) {133 if (build_options.have_llvm and options.use_llvm) {
134 return createEmpty(allocator, options);134 return createEmpty(allocator, options);
...@@ -204,15 +204,18 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option...@@ -204,15 +204,18 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
204 index += 2;204 index += 2;
205205
206 // Characteristics206 // Characteristics
207 var characteristics: u16 = std.coff.IMAGE_FILE_DEBUG_STRIPPED | std.coff.IMAGE_FILE_RELOCS_STRIPPED; // TODO Remove debug info stripped flag when necessary207 var characteristics: std.coff.CoffHeaderFlags = .{
208 .DEBUG_STRIPPED = 1, // TODO remove debug info stripped flag when necessary
209 .RELOCS_STRIPPED = 1,
210 };
208 if (options.output_mode == .Exe) {211 if (options.output_mode == .Exe) {
209 characteristics |= std.coff.IMAGE_FILE_EXECUTABLE_IMAGE;212 characteristics.EXECUTABLE_IMAGE = 1;
210 }213 }
211 switch (self.ptr_width) {214 switch (self.ptr_width) {
212 .p32 => characteristics |= std.coff.IMAGE_FILE_32BIT_MACHINE,215 .p32 => characteristics.@"32BIT_MACHINE" = 1,
213 .p64 => characteristics |= std.coff.IMAGE_FILE_LARGE_ADDRESS_AWARE,216 .p64 => characteristics.LARGE_ADDRESS_AWARE = 1,
214 }217 }
215 mem.writeIntLittle(u16, hdr_data[index..][0..2], characteristics);218 mem.writeIntLittle(u16, hdr_data[index..][0..2], @bitCast(u16, characteristics));
216 index += 2;219 index += 2;
217220
218 assert(index == 20);221 assert(index == 20);
...@@ -352,7 +355,10 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option...@@ -352,7 +355,10 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
352 mem.set(u8, hdr_data[index..][0..12], 0);355 mem.set(u8, hdr_data[index..][0..12], 0);
353 index += 12;356 index += 12;
354 // Section flags357 // Section flags
355 mem.writeIntLittle(u32, hdr_data[index..][0..4], std.coff.IMAGE_SCN_CNT_INITIALIZED_DATA | std.coff.IMAGE_SCN_MEM_READ);358 mem.writeIntLittle(u32, hdr_data[index..][0..4], @bitCast(u32, std.coff.SectionHeaderFlags{
359 .CNT_INITIALIZED_DATA = 1,
360 .MEM_READ = 1,
361 }));
356 index += 4;362 index += 4;
357 // Then, the .text section363 // Then, the .text section
358 hdr_data[index..][0..8].* = ".text\x00\x00\x00".*;364 hdr_data[index..][0..8].* = ".text\x00\x00\x00".*;
...@@ -378,11 +384,12 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option...@@ -378,11 +384,12 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
378 mem.set(u8, hdr_data[index..][0..12], 0);384 mem.set(u8, hdr_data[index..][0..12], 0);
379 index += 12;385 index += 12;
380 // Section flags386 // Section flags
381 mem.writeIntLittle(387 mem.writeIntLittle(u32, hdr_data[index..][0..4], @bitCast(u32, std.coff.SectionHeaderFlags{
382 u32,388 .CNT_CODE = 1,
383 hdr_data[index..][0..4],389 .MEM_EXECUTE = 1,
384 std.coff.IMAGE_SCN_CNT_CODE | std.coff.IMAGE_SCN_MEM_EXECUTE | std.coff.IMAGE_SCN_MEM_READ | std.coff.IMAGE_SCN_MEM_WRITE,390 .MEM_READ = 1,
385 );391 .MEM_WRITE = 1,
392 }));
386 index += 4;393 index += 4;
387394
388 assert(index == optional_header_size + section_table_size);395 assert(index == optional_header_size + section_table_size);
...@@ -411,7 +418,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Coff {...@@ -411,7 +418,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Coff {
411 };418 };
412419
413 const use_llvm = build_options.have_llvm and options.use_llvm;420 const use_llvm = build_options.have_llvm and options.use_llvm;
414 const use_stage1 = build_options.is_stage1 and options.use_stage1;421 const use_stage1 = build_options.have_stage1 and options.use_stage1;
415 if (use_llvm and !use_stage1) {422 if (use_llvm and !use_stage1) {
416 self.llvm_object = try LlvmObject.create(gpa, options);423 self.llvm_object = try LlvmObject.create(gpa, options);
417 }424 }
...@@ -949,7 +956,7 @@ fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -949,7 +956,7 @@ fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !
949 // If there is no Zig code to compile, then we should skip flushing the output file because it956 // If there is no Zig code to compile, then we should skip flushing the output file because it
950 // will not be part of the linker line anyway.957 // will not be part of the linker line anyway.
951 const module_obj_path: ?[]const u8 = if (self.base.options.module) |module| blk: {958 const module_obj_path: ?[]const u8 = if (self.base.options.module) |module| blk: {
952 const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1;959 const use_stage1 = build_options.have_stage1 and self.base.options.use_stage1;
953 if (use_stage1) {960 if (use_stage1) {
954 const obj_basename = try std.zig.binNameAlloc(arena, .{961 const obj_basename = try std.zig.binNameAlloc(arena, .{
955 .root_name = self.base.options.root_name,962 .root_name = self.base.options.root_name,
...@@ -1126,6 +1133,10 @@ fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -1126,6 +1133,10 @@ fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !
1126 }1133 }
1127 }1134 }
11281135
1136 for (self.base.options.force_undefined_symbols.keys()) |symbol| {
1137 try argv.append(try allocPrint(arena, "-INCLUDE:{s}", .{symbol}));
1138 }
1139
1129 if (is_dyn_lib) {1140 if (is_dyn_lib) {
1130 try argv.append("-DLL");1141 try argv.append("-DLL");
1131 }1142 }
src/link/Dwarf.zig+12-7
...@@ -102,7 +102,7 @@ pub const DeclState = struct {...@@ -102,7 +102,7 @@ pub const DeclState = struct {
102 }102 }
103103
104 pub fn addExprlocReloc(self: *DeclState, target: u32, offset: u32, is_ptr: bool) !void {104 pub fn addExprlocReloc(self: *DeclState, target: u32, offset: u32, is_ptr: bool) !void {
105 log.debug("{x}: target sym @{d}, via GOT {}", .{ offset, target, is_ptr });105 log.debug("{x}: target sym %{d}, via GOT {}", .{ offset, target, is_ptr });
106 try self.exprloc_relocs.append(self.gpa, .{106 try self.exprloc_relocs.append(self.gpa, .{
107 .@"type" = if (is_ptr) .got_load else .direct_load,107 .@"type" = if (is_ptr) .got_load else .direct_load,
108 .target = target,108 .target = target,
...@@ -135,7 +135,7 @@ pub const DeclState = struct {...@@ -135,7 +135,7 @@ pub const DeclState = struct {
135 .@"type" = ty,135 .@"type" = ty,
136 .offset = undefined,136 .offset = undefined,
137 });137 });
138 log.debug("@{d}: {}", .{ sym_index, ty.fmtDebug() });138 log.debug("%{d}: {}", .{ sym_index, ty.fmtDebug() });
139 try self.abbrev_resolver.putNoClobberContext(self.gpa, ty, sym_index, .{139 try self.abbrev_resolver.putNoClobberContext(self.gpa, ty, sym_index, .{
140 .mod = self.mod,140 .mod = self.mod,
141 });141 });
...@@ -143,7 +143,7 @@ pub const DeclState = struct {...@@ -143,7 +143,7 @@ pub const DeclState = struct {
143 .mod = self.mod,143 .mod = self.mod,
144 }).?;144 }).?;
145 };145 };
146 log.debug("{x}: @{d} + 0", .{ offset, resolv });146 log.debug("{x}: %{d} + 0", .{ offset, resolv });
147 try self.abbrev_relocs.append(self.gpa, .{147 try self.abbrev_relocs.append(self.gpa, .{
148 .target = resolv,148 .target = resolv,
149 .atom = atom,149 .atom = atom,
...@@ -243,11 +243,13 @@ pub const DeclState = struct {...@@ -243,11 +243,13 @@ pub const DeclState = struct {
243 .Pointer => {243 .Pointer => {
244 if (ty.isSlice()) {244 if (ty.isSlice()) {
245 // Slices are structs: struct { .ptr = *, .len = N }245 // Slices are structs: struct { .ptr = *, .len = N }
246 const ptr_bits = target.cpu.arch.ptrBitWidth();
247 const ptr_bytes = @intCast(u8, @divExact(ptr_bits, 8));
246 // DW.AT.structure_type248 // DW.AT.structure_type
247 try dbg_info_buffer.ensureUnusedCapacity(2);249 try dbg_info_buffer.ensureUnusedCapacity(2);
248 dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_type));250 dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_type));
249 // DW.AT.byte_size, DW.FORM.sdata251 // DW.AT.byte_size, DW.FORM.sdata
250 dbg_info_buffer.appendAssumeCapacity(@sizeOf(usize) * 2);252 dbg_info_buffer.appendAssumeCapacity(ptr_bytes * 2);
251 // DW.AT.name, DW.FORM.string253 // DW.AT.name, DW.FORM.string
252 try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(module)});254 try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(module)});
253 // DW.AT.member255 // DW.AT.member
...@@ -276,7 +278,7 @@ pub const DeclState = struct {...@@ -276,7 +278,7 @@ pub const DeclState = struct {
276 try self.addTypeRelocGlobal(atom, Type.usize, @intCast(u32, index));278 try self.addTypeRelocGlobal(atom, Type.usize, @intCast(u32, index));
277 // DW.AT.data_member_location, DW.FORM.sdata279 // DW.AT.data_member_location, DW.FORM.sdata
278 try dbg_info_buffer.ensureUnusedCapacity(2);280 try dbg_info_buffer.ensureUnusedCapacity(2);
279 dbg_info_buffer.appendAssumeCapacity(@sizeOf(usize));281 dbg_info_buffer.appendAssumeCapacity(ptr_bytes);
280 // DW.AT.structure_type delimit children282 // DW.AT.structure_type delimit children
281 dbg_info_buffer.appendAssumeCapacity(0);283 dbg_info_buffer.appendAssumeCapacity(0);
282 } else {284 } else {
...@@ -1054,6 +1056,7 @@ pub fn commitDeclState(...@@ -1054,6 +1056,7 @@ pub fn commitDeclState(
1054 break :blk false;1056 break :blk false;
1055 };1057 };
1056 if (deferred) {1058 if (deferred) {
1059 log.debug("resolving %{d} deferred until flush", .{target});
1057 try self.global_abbrev_relocs.append(gpa, .{1060 try self.global_abbrev_relocs.append(gpa, .{
1058 .target = null,1061 .target = null,
1059 .offset = reloc.offset,1062 .offset = reloc.offset,
...@@ -1061,10 +1064,12 @@ pub fn commitDeclState(...@@ -1061,10 +1064,12 @@ pub fn commitDeclState(
1061 .addend = reloc.addend,1064 .addend = reloc.addend,
1062 });1065 });
1063 } else {1066 } else {
1067 const value = symbol.atom.off + symbol.offset + reloc.addend;
1068 log.debug("{x}: [() => {x}] (%{d}, '{}')", .{ reloc.offset, value, target, ty.fmtDebug() });
1064 mem.writeInt(1069 mem.writeInt(
1065 u32,1070 u32,
1066 dbg_info_buffer.items[reloc.offset..][0..@sizeOf(u32)],1071 dbg_info_buffer.items[reloc.offset..][0..@sizeOf(u32)],
1067 symbol.atom.off + symbol.offset + reloc.addend,1072 value,
1068 target_endian,1073 target_endian,
1069 );1074 );
1070 }1075 }
...@@ -1257,7 +1262,7 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co...@@ -1257,7 +1262,7 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co
1257 debug_info_sect.addr = dwarf_segment.vmaddr + new_offset - dwarf_segment.fileoff;1262 debug_info_sect.addr = dwarf_segment.vmaddr + new_offset - dwarf_segment.fileoff;
1258 }1263 }
1259 debug_info_sect.size = needed_size;1264 debug_info_sect.size = needed_size;
1260 d_sym.debug_line_header_dirty = true;1265 d_sym.debug_info_header_dirty = true;
1261 }1266 }
1262 const file_pos = debug_info_sect.offset + atom.off;1267 const file_pos = debug_info_sect.offset + atom.off;
1263 try pwriteDbgInfoNops(1268 try pwriteDbgInfoNops(
src/link/Elf.zig+13-2
...@@ -249,7 +249,7 @@ pub const Export = struct {...@@ -249,7 +249,7 @@ pub const Export = struct {
249};249};
250250
251pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Elf {251pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Elf {
252 assert(options.object_format == .elf);252 assert(options.target.ofmt == .elf);
253253
254 if (build_options.have_llvm and options.use_llvm) {254 if (build_options.have_llvm and options.use_llvm) {
255 return createEmpty(allocator, options);255 return createEmpty(allocator, options);
...@@ -328,7 +328,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf {...@@ -328,7 +328,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf {
328 .page_size = page_size,328 .page_size = page_size,
329 };329 };
330 const use_llvm = build_options.have_llvm and options.use_llvm;330 const use_llvm = build_options.have_llvm and options.use_llvm;
331 const use_stage1 = build_options.is_stage1 and options.use_stage1;331 const use_stage1 = build_options.have_stage1 and options.use_stage1;
332 if (use_llvm and !use_stage1) {332 if (use_llvm and !use_stage1) {
333 self.llvm_object = try LlvmObject.create(gpa, options);333 self.llvm_object = try LlvmObject.create(gpa, options);
334 }334 }
...@@ -1448,6 +1448,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v...@@ -1448,6 +1448,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
1448 try argv.append(entry);1448 try argv.append(entry);
1449 }1449 }
14501450
1451 for (self.base.options.force_undefined_symbols.keys()) |symbol| {
1452 try argv.append("-u");
1453 try argv.append(symbol);
1454 }
1455
1451 switch (self.base.options.hash_style) {1456 switch (self.base.options.hash_style) {
1452 .gnu => try argv.append("--hash-style=gnu"),1457 .gnu => try argv.append("--hash-style=gnu"),
1453 .sysv => try argv.append("--hash-style=sysv"),1458 .sysv => try argv.append("--hash-style=sysv"),
...@@ -1673,6 +1678,12 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v...@@ -1673,6 +1678,12 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
1673 }1678 }
1674 }1679 }
16751680
1681 // stack-protector.
1682 // Related: https://github.com/ziglang/zig/issues/7265
1683 if (comp.libssp_static_lib) |ssp| {
1684 try argv.append(ssp.full_object_path);
1685 }
1686
1676 // compiler-rt1687 // compiler-rt
1677 if (compiler_rt_path) |p| {1688 if (compiler_rt_path) |p| {
1678 try argv.append(p);1689 try argv.append(p);
src/link/MachO.zig+25-24
...@@ -270,42 +270,42 @@ pub const Export = struct {...@@ -270,42 +270,42 @@ pub const Export = struct {
270};270};
271271
272pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {272pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {
273 assert(options.object_format == .macho);273 assert(options.target.ofmt == .macho);
274274
275 const use_stage1 = build_options.is_stage1 and options.use_stage1;275 const use_stage1 = build_options.have_stage1 and options.use_stage1;
276 if (use_stage1 or options.emit == null) {276 if (use_stage1 or options.emit == null or options.module == null) {
277 return createEmpty(allocator, options);277 return createEmpty(allocator, options);
278 }278 }
279 const emit = options.emit.?;
280 const file = try emit.directory.handle.createFile(emit.sub_path, .{
281 .truncate = false,
282 .read = true,
283 .mode = link.determineMode(options),
284 });
285 errdefer file.close();
286279
280 const emit = options.emit.?;
287 const self = try createEmpty(allocator, options);281 const self = try createEmpty(allocator, options);
288 errdefer {282 errdefer {
289 self.base.file = null;283 self.base.file = null;
290 self.base.destroy();284 self.base.destroy();
291 }285 }
292286
293 self.base.file = file;
294
295 if (build_options.have_llvm and options.use_llvm and options.module != null) {287 if (build_options.have_llvm and options.use_llvm and options.module != null) {
296 // TODO this intermediary_basename isn't enough; in the case of `zig build-exe`,288 // TODO this intermediary_basename isn't enough; in the case of `zig build-exe`,
297 // we also want to put the intermediary object file in the cache while the289 // we also want to put the intermediary object file in the cache while the
298 // main emit directory is the cwd.290 // main emit directory is the cwd.
299 self.base.intermediary_basename = try std.fmt.allocPrint(allocator, "{s}{s}", .{291 self.base.intermediary_basename = try std.fmt.allocPrint(allocator, "{s}{s}", .{
300 emit.sub_path, options.object_format.fileExt(options.target.cpu.arch),292 emit.sub_path, options.target.ofmt.fileExt(options.target.cpu.arch),
301 });293 });
302 }294 }
303295
304 if (options.output_mode == .Lib and296 if (self.base.intermediary_basename != null) switch (options.output_mode) {
305 options.link_mode == .Static and self.base.intermediary_basename != null)297 .Obj => return self,
306 {298 .Lib => if (options.link_mode == .Static) return self,
307 return self;299 else => {},
308 }300 };
301
302 const file = try emit.directory.handle.createFile(emit.sub_path, .{
303 .truncate = false,
304 .read = true,
305 .mode = link.determineMode(options),
306 });
307 errdefer file.close();
308 self.base.file = file;
309309
310 if (!options.strip and options.module != null) blk: {310 if (!options.strip and options.module != null) blk: {
311 // TODO once I add support for converting (and relocating) DWARF info from relocatable311 // TODO once I add support for converting (and relocating) DWARF info from relocatable
...@@ -363,7 +363,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO {...@@ -363,7 +363,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO {
363 const cpu_arch = options.target.cpu.arch;363 const cpu_arch = options.target.cpu.arch;
364 const page_size: u16 = if (cpu_arch == .aarch64) 0x4000 else 0x1000;364 const page_size: u16 = if (cpu_arch == .aarch64) 0x4000 else 0x1000;
365 const use_llvm = build_options.have_llvm and options.use_llvm;365 const use_llvm = build_options.have_llvm and options.use_llvm;
366 const use_stage1 = build_options.is_stage1 and options.use_stage1;366 const use_stage1 = build_options.have_stage1 and options.use_stage1;
367367
368 const self = try gpa.create(MachO);368 const self = try gpa.create(MachO);
369 errdefer gpa.destroy(self);369 errdefer gpa.destroy(self);
...@@ -5315,10 +5315,10 @@ fn writeFunctionStarts(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {...@@ -5315,10 +5315,10 @@ fn writeFunctionStarts(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
5315}5315}
53165316
5317fn filterDataInCode(5317fn filterDataInCode(
5318 dices: []const macho.data_in_code_entry,5318 dices: []align(1) const macho.data_in_code_entry,
5319 start_addr: u64,5319 start_addr: u64,
5320 end_addr: u64,5320 end_addr: u64,
5321) []const macho.data_in_code_entry {5321) []align(1) const macho.data_in_code_entry {
5322 const Predicate = struct {5322 const Predicate = struct {
5323 addr: u64,5323 addr: u64,
53245324
...@@ -5825,7 +5825,7 @@ pub fn getEntryPoint(self: MachO) error{MissingMainEntrypoint}!SymbolWithLoc {...@@ -5825,7 +5825,7 @@ pub fn getEntryPoint(self: MachO) error{MissingMainEntrypoint}!SymbolWithLoc {
5825 return global;5825 return global;
5826}5826}
58275827
5828pub fn findFirst(comptime T: type, haystack: []const T, start: usize, predicate: anytype) usize {5828pub fn findFirst(comptime T: type, haystack: []align(1) const T, start: usize, predicate: anytype) usize {
5829 if (!@hasDecl(@TypeOf(predicate), "predicate"))5829 if (!@hasDecl(@TypeOf(predicate), "predicate"))
5830 @compileError("Predicate is required to define fn predicate(@This(), T) bool");5830 @compileError("Predicate is required to define fn predicate(@This(), T) bool");
58315831
...@@ -5861,8 +5861,9 @@ pub fn generateSymbolStabs(...@@ -5861,8 +5861,9 @@ pub fn generateSymbolStabs(
5861 },5861 },
5862 else => |e| return e,5862 else => |e| return e,
5863 };5863 };
5864 const tu_name = try compile_unit.die.getAttrString(&debug_info, dwarf.AT.name);5864
5865 const tu_comp_dir = try compile_unit.die.getAttrString(&debug_info, dwarf.AT.comp_dir);5865 const tu_name = try compile_unit.die.getAttrString(&debug_info, dwarf.AT.name, debug_info.debug_str, compile_unit.*);
5866 const tu_comp_dir = try compile_unit.die.getAttrString(&debug_info, dwarf.AT.comp_dir, debug_info.debug_str, compile_unit.*);
58665867
5867 // Open scope5868 // Open scope
5868 try locals.ensureUnusedCapacity(3);5869 try locals.ensureUnusedCapacity(3);
src/link/MachO/Atom.zig+1-1
...@@ -218,7 +218,7 @@ const RelocContext = struct {...@@ -218,7 +218,7 @@ const RelocContext = struct {
218 base_offset: i32 = 0,218 base_offset: i32 = 0,
219};219};
220220
221pub fn parseRelocs(self: *Atom, relocs: []const macho.relocation_info, context: RelocContext) !void {221pub fn parseRelocs(self: *Atom, relocs: []align(1) const macho.relocation_info, context: RelocContext) !void {
222 const tracy = trace(@src());222 const tracy = trace(@src());
223 defer tracy.end();223 defer tracy.end();
224224
src/link/MachO/DebugSymbols.zig+8-8
...@@ -63,17 +63,16 @@ pub const Reloc = struct {...@@ -63,17 +63,16 @@ pub const Reloc = struct {
63pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void {63pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void {
64 if (self.linkedit_segment_cmd_index == null) {64 if (self.linkedit_segment_cmd_index == null) {
65 self.linkedit_segment_cmd_index = @intCast(u8, self.segments.items.len);65 self.linkedit_segment_cmd_index = @intCast(u8, self.segments.items.len);
66 log.debug("found __LINKEDIT segment free space 0x{x} to 0x{x}", .{66 const fileoff = @intCast(u64, self.base.page_size);
67 self.base.page_size,67 const needed_size = @intCast(u64, self.base.page_size) * 2;
68 self.base.page_size * 2,68 log.debug("found __LINKEDIT segment free space 0x{x} to 0x{x}", .{ fileoff, needed_size });
69 });
70 // TODO this needs reworking69 // TODO this needs reworking
71 try self.segments.append(allocator, .{70 try self.segments.append(allocator, .{
72 .segname = makeStaticString("__LINKEDIT"),71 .segname = makeStaticString("__LINKEDIT"),
73 .vmaddr = self.base.page_size,72 .vmaddr = fileoff,
74 .vmsize = self.base.page_size,73 .vmsize = needed_size,
75 .fileoff = self.base.page_size,74 .fileoff = fileoff,
76 .filesize = self.base.page_size,75 .filesize = needed_size,
77 .maxprot = macho.PROT.READ,76 .maxprot = macho.PROT.READ,
78 .initprot = macho.PROT.READ,77 .initprot = macho.PROT.READ,
79 .cmdsize = @sizeOf(macho.segment_command_64),78 .cmdsize = @sizeOf(macho.segment_command_64),
...@@ -284,6 +283,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti...@@ -284,6 +283,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
284 const lc_writer = lc_buffer.writer();283 const lc_writer = lc_buffer.writer();
285 var ncmds: u32 = 0;284 var ncmds: u32 = 0;
286285
286 self.updateDwarfSegment();
287 try self.writeLinkeditSegmentData(&ncmds, lc_writer);287 try self.writeLinkeditSegmentData(&ncmds, lc_writer);
288 self.updateDwarfSegment();288 self.updateDwarfSegment();
289289
src/link/MachO/Object.zig+32-13
...@@ -24,7 +24,7 @@ mtime: u64,...@@ -24,7 +24,7 @@ mtime: u64,
24contents: []align(@alignOf(u64)) const u8,24contents: []align(@alignOf(u64)) const u8,
2525
26header: macho.mach_header_64 = undefined,26header: macho.mach_header_64 = undefined,
27in_symtab: []const macho.nlist_64 = undefined,27in_symtab: []align(1) const macho.nlist_64 = undefined,
28in_strtab: []const u8 = undefined,28in_strtab: []const u8 = undefined,
2929
30symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{},30symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{},
...@@ -99,12 +99,13 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch)...@@ -99,12 +99,13 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch)
99 },99 },
100 .SYMTAB => {100 .SYMTAB => {
101 const symtab = cmd.cast(macho.symtab_command).?;101 const symtab = cmd.cast(macho.symtab_command).?;
102 // Sadly, SYMTAB may be at an unaligned offset within the object file.
102 self.in_symtab = @ptrCast(103 self.in_symtab = @ptrCast(
103 [*]const macho.nlist_64,104 [*]align(1) const macho.nlist_64,
104 @alignCast(@alignOf(macho.nlist_64), &self.contents[symtab.symoff]),105 self.contents.ptr + symtab.symoff,
105 )[0..symtab.nsyms];106 )[0..symtab.nsyms];
106 self.in_strtab = self.contents[symtab.stroff..][0..symtab.strsize];107 self.in_strtab = self.contents[symtab.stroff..][0..symtab.strsize];
107 try self.symtab.appendSlice(allocator, self.in_symtab);108 try self.symtab.appendUnalignedSlice(allocator, self.in_symtab);
108 },109 },
109 else => {},110 else => {},
110 }111 }
...@@ -196,10 +197,10 @@ fn filterSymbolsByAddress(...@@ -196,10 +197,10 @@ fn filterSymbolsByAddress(
196}197}
197198
198fn filterRelocs(199fn filterRelocs(
199 relocs: []const macho.relocation_info,200 relocs: []align(1) const macho.relocation_info,
200 start_addr: u64,201 start_addr: u64,
201 end_addr: u64,202 end_addr: u64,
202) []const macho.relocation_info {203) []align(1) const macho.relocation_info {
203 const Predicate = struct {204 const Predicate = struct {
204 addr: u64,205 addr: u64,
205206
...@@ -303,8 +304,8 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)...@@ -303,8 +304,8 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)
303304
304 // Read section's list of relocations305 // Read section's list of relocations
305 const relocs = @ptrCast(306 const relocs = @ptrCast(
306 [*]const macho.relocation_info,307 [*]align(1) const macho.relocation_info,
307 @alignCast(@alignOf(macho.relocation_info), &self.contents[sect.reloff]),308 self.contents.ptr + sect.reloff,
308 )[0..sect.nreloc];309 )[0..sect.nreloc];
309310
310 // Symbols within this section only.311 // Symbols within this section only.
...@@ -390,7 +391,7 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)...@@ -390,7 +391,7 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)
390 break :blk cc[start..][0..size];391 break :blk cc[start..][0..size];
391 } else null;392 } else null;
392 const atom_align = if (addr > 0)393 const atom_align = if (addr > 0)
393 math.min(@ctz(u64, addr), sect.@"align")394 math.min(@ctz(addr), sect.@"align")
394 else395 else
395 sect.@"align";396 sect.@"align";
396 const atom = try self.createAtomFromSubsection(397 const atom = try self.createAtomFromSubsection(
...@@ -472,7 +473,7 @@ fn createAtomFromSubsection(...@@ -472,7 +473,7 @@ fn createAtomFromSubsection(
472 size: u64,473 size: u64,
473 alignment: u32,474 alignment: u32,
474 code: ?[]const u8,475 code: ?[]const u8,
475 relocs: []const macho.relocation_info,476 relocs: []align(1) const macho.relocation_info,
476 indexes: []const SymbolAtIndex,477 indexes: []const SymbolAtIndex,
477 match: u8,478 match: u8,
478 sect: macho.section_64,479 sect: macho.section_64,
...@@ -538,7 +539,7 @@ pub fn getSourceSection(self: Object, index: u16) macho.section_64 {...@@ -538,7 +539,7 @@ pub fn getSourceSection(self: Object, index: u16) macho.section_64 {
538 return self.sections.items[index];539 return self.sections.items[index];
539}540}
540541
541pub fn parseDataInCode(self: Object) ?[]const macho.data_in_code_entry {542pub fn parseDataInCode(self: Object) ?[]align(1) const macho.data_in_code_entry {
542 var it = LoadCommandIterator{543 var it = LoadCommandIterator{
543 .ncmds = self.header.ncmds,544 .ncmds = self.header.ncmds,
544 .buffer = self.contents[@sizeOf(macho.mach_header_64)..][0..self.header.sizeofcmds],545 .buffer = self.contents[@sizeOf(macho.mach_header_64)..][0..self.header.sizeofcmds],
...@@ -549,8 +550,8 @@ pub fn parseDataInCode(self: Object) ?[]const macho.data_in_code_entry {...@@ -549,8 +550,8 @@ pub fn parseDataInCode(self: Object) ?[]const macho.data_in_code_entry {
549 const dice = cmd.cast(macho.linkedit_data_command).?;550 const dice = cmd.cast(macho.linkedit_data_command).?;
550 const ndice = @divExact(dice.datasize, @sizeOf(macho.data_in_code_entry));551 const ndice = @divExact(dice.datasize, @sizeOf(macho.data_in_code_entry));
551 return @ptrCast(552 return @ptrCast(
552 [*]const macho.data_in_code_entry,553 [*]align(1) const macho.data_in_code_entry,
553 @alignCast(@alignOf(macho.data_in_code_entry), &self.contents[dice.dataoff]),554 self.contents.ptr + dice.dataoff,
554 )[0..ndice];555 )[0..ndice];
555 },556 },
556 else => {},557 else => {},
...@@ -579,9 +580,15 @@ pub fn parseDwarfInfo(self: Object) error{Overflow}!dwarf.DwarfInfo {...@@ -579,9 +580,15 @@ pub fn parseDwarfInfo(self: Object) error{Overflow}!dwarf.DwarfInfo {
579 .debug_info = &[0]u8{},580 .debug_info = &[0]u8{},
580 .debug_abbrev = &[0]u8{},581 .debug_abbrev = &[0]u8{},
581 .debug_str = &[0]u8{},582 .debug_str = &[0]u8{},
583 .debug_str_offsets = &[0]u8{},
582 .debug_line = &[0]u8{},584 .debug_line = &[0]u8{},
583 .debug_line_str = &[0]u8{},585 .debug_line_str = &[0]u8{},
584 .debug_ranges = &[0]u8{},586 .debug_ranges = &[0]u8{},
587 .debug_loclists = &[0]u8{},
588 .debug_rnglists = &[0]u8{},
589 .debug_addr = &[0]u8{},
590 .debug_names = &[0]u8{},
591 .debug_frame = &[0]u8{},
585 };592 };
586 for (self.sections.items) |sect| {593 for (self.sections.items) |sect| {
587 const segname = sect.segName();594 const segname = sect.segName();
...@@ -593,12 +600,24 @@ pub fn parseDwarfInfo(self: Object) error{Overflow}!dwarf.DwarfInfo {...@@ -593,12 +600,24 @@ pub fn parseDwarfInfo(self: Object) error{Overflow}!dwarf.DwarfInfo {
593 di.debug_abbrev = try self.getSectionContents(sect);600 di.debug_abbrev = try self.getSectionContents(sect);
594 } else if (mem.eql(u8, sectname, "__debug_str")) {601 } else if (mem.eql(u8, sectname, "__debug_str")) {
595 di.debug_str = try self.getSectionContents(sect);602 di.debug_str = try self.getSectionContents(sect);
603 } else if (mem.eql(u8, sectname, "__debug_str_offsets")) {
604 di.debug_str_offsets = try self.getSectionContents(sect);
596 } else if (mem.eql(u8, sectname, "__debug_line")) {605 } else if (mem.eql(u8, sectname, "__debug_line")) {
597 di.debug_line = try self.getSectionContents(sect);606 di.debug_line = try self.getSectionContents(sect);
598 } else if (mem.eql(u8, sectname, "__debug_line_str")) {607 } else if (mem.eql(u8, sectname, "__debug_line_str")) {
599 di.debug_line_str = try self.getSectionContents(sect);608 di.debug_line_str = try self.getSectionContents(sect);
600 } else if (mem.eql(u8, sectname, "__debug_ranges")) {609 } else if (mem.eql(u8, sectname, "__debug_ranges")) {
601 di.debug_ranges = try self.getSectionContents(sect);610 di.debug_ranges = try self.getSectionContents(sect);
611 } else if (mem.eql(u8, sectname, "__debug_loclists")) {
612 di.debug_loclists = try self.getSectionContents(sect);
613 } else if (mem.eql(u8, sectname, "__debug_rnglists")) {
614 di.debug_rnglists = try self.getSectionContents(sect);
615 } else if (mem.eql(u8, sectname, "__debug_addr")) {
616 di.debug_addr = try self.getSectionContents(sect);
617 } else if (mem.eql(u8, sectname, "__debug_names")) {
618 di.debug_names = try self.getSectionContents(sect);
619 } else if (mem.eql(u8, sectname, "__debug_frame")) {
620 di.debug_frame = try self.getSectionContents(sect);
602 }621 }
603 }622 }
604 }623 }
src/link/NvPtx.zig+1-1
...@@ -57,7 +57,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*NvPtx {...@@ -57,7 +57,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*NvPtx {
57pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*NvPtx {57pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*NvPtx {
58 if (!build_options.have_llvm) @panic("nvptx target requires a zig compiler with llvm enabled.");58 if (!build_options.have_llvm) @panic("nvptx target requires a zig compiler with llvm enabled.");
59 if (!options.use_llvm) return error.PtxArchNotSupported;59 if (!options.use_llvm) return error.PtxArchNotSupported;
60 assert(options.object_format == .nvptx);60 assert(options.target.ofmt == .nvptx);
6161
62 const nvptx = try createEmpty(allocator, options);62 const nvptx = try createEmpty(allocator, options);
63 log.info("Opening .ptx target file {s}", .{sub_path});63 log.info("Opening .ptx target file {s}", .{sub_path});
src/link/Plan9.zig+1-1
...@@ -657,7 +657,7 @@ pub const base_tag = .plan9;...@@ -657,7 +657,7 @@ pub const base_tag = .plan9;
657pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Plan9 {657pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Plan9 {
658 if (options.use_llvm)658 if (options.use_llvm)
659 return error.LLVMBackendDoesNotSupportPlan9;659 return error.LLVMBackendDoesNotSupportPlan9;
660 assert(options.object_format == .plan9);660 assert(options.target.ofmt == .plan9);
661661
662 const self = try createEmpty(allocator, options);662 const self = try createEmpty(allocator, options);
663 errdefer self.base.destroy();663 errdefer self.base.destroy();
src/link/SpirV.zig+1-1
...@@ -99,7 +99,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*SpirV {...@@ -99,7 +99,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*SpirV {
99}99}
100100
101pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*SpirV {101pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*SpirV {
102 assert(options.object_format == .spirv);102 assert(options.target.ofmt == .spirv);
103103
104 if (options.use_llvm) return error.LLVM_BackendIsTODO_ForSpirV; // TODO: LLVM Doesn't support SpirV at all.104 if (options.use_llvm) return error.LLVM_BackendIsTODO_ForSpirV; // TODO: LLVM Doesn't support SpirV at all.
105 if (options.use_lld) return error.LLD_LinkingIsTODO_ForSpirV; // TODO: LLD Doesn't support SpirV at all.105 if (options.use_lld) return error.LLD_LinkingIsTODO_ForSpirV; // TODO: LLD Doesn't support SpirV at all.
src/link/Wasm.zig+108-13
...@@ -282,7 +282,7 @@ pub const StringTable = struct {...@@ -282,7 +282,7 @@ pub const StringTable = struct {
282};282};
283283
284pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Wasm {284pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Wasm {
285 assert(options.object_format == .wasm);285 assert(options.target.ofmt == .wasm);
286286
287 if (build_options.have_llvm and options.use_llvm) {287 if (build_options.have_llvm and options.use_llvm) {
288 return createEmpty(allocator, options);288 return createEmpty(allocator, options);
...@@ -356,7 +356,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm {...@@ -356,7 +356,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm {
356 }356 }
357357
358 const use_llvm = build_options.have_llvm and options.use_llvm;358 const use_llvm = build_options.have_llvm and options.use_llvm;
359 const use_stage1 = build_options.is_stage1 and options.use_stage1;359 const use_stage1 = build_options.have_stage1 and options.use_stage1;
360 if (use_llvm and !use_stage1) {360 if (use_llvm and !use_stage1) {
361 self.llvm_object = try LlvmObject.create(gpa, options);361 self.llvm_object = try LlvmObject.create(gpa, options);
362 }362 }
...@@ -378,7 +378,7 @@ fn parseObjectFile(self: *Wasm, path: []const u8) !bool {...@@ -378,7 +378,7 @@ fn parseObjectFile(self: *Wasm, path: []const u8) !bool {
378 const file = try fs.cwd().openFile(path, .{});378 const file = try fs.cwd().openFile(path, .{});
379 errdefer file.close();379 errdefer file.close();
380380
381 var object = Object.create(self.base.allocator, file, path) catch |err| switch (err) {381 var object = Object.create(self.base.allocator, file, path, null) catch |err| switch (err) {
382 error.InvalidMagicByte, error.NotObjectFile => return false,382 error.InvalidMagicByte, error.NotObjectFile => return false,
383 else => |e| return e,383 else => |e| return e,
384 };384 };
...@@ -463,8 +463,6 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {...@@ -463,8 +463,6 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
463 continue;463 continue;
464 }464 }
465465
466 // TODO: Store undefined symbols so we can verify at the end if they've all been found
467 // if not, emit an error (unless --allow-undefined is enabled).
468 const maybe_existing = try self.globals.getOrPut(self.base.allocator, sym_name_index);466 const maybe_existing = try self.globals.getOrPut(self.base.allocator, sym_name_index);
469 if (!maybe_existing.found_existing) {467 if (!maybe_existing.found_existing) {
470 maybe_existing.value_ptr.* = location;468 maybe_existing.value_ptr.* = location;
...@@ -483,8 +481,15 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {...@@ -483,8 +481,15 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
483 break :blk self.objects.items[file].name;481 break :blk self.objects.items[file].name;
484 } else self.name;482 } else self.name;
485483
486 if (!existing_sym.isUndefined()) {484 if (!existing_sym.isUndefined()) outer: {
487 if (!symbol.isUndefined()) {485 if (!symbol.isUndefined()) inner: {
486 if (symbol.isWeak()) {
487 break :inner; // ignore the new symbol (discard it)
488 }
489 if (existing_sym.isWeak()) {
490 break :outer; // existing is weak, while new one isn't. Replace it.
491 }
492 // both are defined and weak, we have a symbol collision.
488 log.err("symbol '{s}' defined multiple times", .{sym_name});493 log.err("symbol '{s}' defined multiple times", .{sym_name});
489 log.err(" first definition in '{s}'", .{existing_file_path});494 log.err(" first definition in '{s}'", .{existing_file_path});
490 log.err(" next definition in '{s}'", .{object.name});495 log.err(" next definition in '{s}'", .{object.name});
...@@ -502,6 +507,53 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {...@@ -502,6 +507,53 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
502 return error.SymbolMismatchingType;507 return error.SymbolMismatchingType;
503 }508 }
504509
510 if (existing_sym.isUndefined() and symbol.isUndefined()) {
511 const existing_name = if (existing_loc.file) |file_index| blk: {
512 const obj = self.objects.items[file_index];
513 const name_index = obj.findImport(symbol.tag.externalType(), existing_sym.index).module_name;
514 break :blk obj.string_table.get(name_index);
515 } else blk: {
516 const name_index = self.imports.get(existing_loc).?.module_name;
517 break :blk self.string_table.get(name_index);
518 };
519
520 const module_index = object.findImport(symbol.tag.externalType(), symbol.index).module_name;
521 const module_name = object.string_table.get(module_index);
522 if (!mem.eql(u8, existing_name, module_name)) {
523 log.err("symbol '{s}' module name mismatch. Expected '{s}', but found '{s}'", .{
524 sym_name,
525 existing_name,
526 module_name,
527 });
528 log.err(" first definition in '{s}'", .{existing_file_path});
529 log.err(" next definition in '{s}'", .{object.name});
530 return error.ModuleNameMismatch;
531 }
532 }
533
534 if (existing_sym.tag == .global) {
535 const existing_ty = self.getGlobalType(existing_loc);
536 const new_ty = self.getGlobalType(location);
537 if (existing_ty.mutable != new_ty.mutable or existing_ty.valtype != new_ty.valtype) {
538 log.err("symbol '{s}' mismatching global types", .{sym_name});
539 log.err(" first definition in '{s}'", .{existing_file_path});
540 log.err(" next definition in '{s}'", .{object.name});
541 return error.GlobalTypeMismatch;
542 }
543 }
544
545 if (existing_sym.tag == .function) {
546 const existing_ty = self.getFunctionSignature(existing_loc);
547 const new_ty = self.getFunctionSignature(location);
548 if (!existing_ty.eql(new_ty)) {
549 log.err("symbol '{s}' mismatching function signatures.", .{sym_name});
550 log.err(" expected signature {}, but found signature {}", .{ existing_ty, new_ty });
551 log.err(" first definition in '{s}'", .{existing_file_path});
552 log.err(" next definition in '{s}'", .{object.name});
553 return error.FunctionSignatureMismatch;
554 }
555 }
556
505 // when both symbols are weak, we skip overwriting557 // when both symbols are weak, we skip overwriting
506 if (existing_sym.isWeak() and symbol.isWeak()) {558 if (existing_sym.isWeak() and symbol.isWeak()) {
507 try self.discarded.put(self.base.allocator, location, existing_loc);559 try self.discarded.put(self.base.allocator, location, existing_loc);
...@@ -543,8 +595,8 @@ fn resolveSymbolsInArchives(self: *Wasm) !void {...@@ -543,8 +595,8 @@ fn resolveSymbolsInArchives(self: *Wasm) !void {
543 // Parse object and and resolve symbols again before we check remaining595 // Parse object and and resolve symbols again before we check remaining
544 // undefined symbols.596 // undefined symbols.
545 const object_file_index = @intCast(u16, self.objects.items.len);597 const object_file_index = @intCast(u16, self.objects.items.len);
546 const object = try self.objects.addOne(self.base.allocator);598 var object = try archive.parseObject(self.base.allocator, offset.items[0]);
547 object.* = try archive.parseObject(self.base.allocator, offset.items[0]);599 try self.objects.append(self.base.allocator, object);
548 try self.resolveSymbolsInObject(object_file_index);600 try self.resolveSymbolsInObject(object_file_index);
549601
550 // continue loop for any remaining undefined symbols that still exist602 // continue loop for any remaining undefined symbols that still exist
...@@ -797,6 +849,49 @@ fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, code: []const u8) !void {...@@ -797,6 +849,49 @@ fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, code: []const u8) !void {
797 try self.resolved_symbols.put(self.base.allocator, atom.symbolLoc(), {});849 try self.resolved_symbols.put(self.base.allocator, atom.symbolLoc(), {});
798}850}
799851
852/// From a given symbol location, returns its `wasm.GlobalType`.
853/// Asserts the Symbol represents a global.
854fn getGlobalType(self: *const Wasm, loc: SymbolLoc) wasm.GlobalType {
855 const symbol = loc.getSymbol(self);
856 assert(symbol.tag == .global);
857 const is_undefined = symbol.isUndefined();
858 if (loc.file) |file_index| {
859 const obj: Object = self.objects.items[file_index];
860 if (is_undefined) {
861 return obj.findImport(.global, symbol.index).kind.global;
862 }
863 const import_global_count = obj.importedCountByKind(.global);
864 return obj.globals[symbol.index - import_global_count].global_type;
865 }
866 if (is_undefined) {
867 return self.imports.get(loc).?.kind.global;
868 }
869 return self.wasm_globals.items[symbol.index].global_type;
870}
871
872/// From a given symbol location, returns its `wasm.Type`.
873/// Asserts the Symbol represents a function.
874fn getFunctionSignature(self: *const Wasm, loc: SymbolLoc) wasm.Type {
875 const symbol = loc.getSymbol(self);
876 assert(symbol.tag == .function);
877 const is_undefined = symbol.isUndefined();
878 if (loc.file) |file_index| {
879 const obj: Object = self.objects.items[file_index];
880 if (is_undefined) {
881 const ty_index = obj.findImport(.function, symbol.index).kind.function;
882 return obj.func_types[ty_index];
883 }
884 const import_function_count = obj.importedCountByKind(.function);
885 const type_index = obj.functions[symbol.index - import_function_count].type_index;
886 return obj.func_types[type_index];
887 }
888 if (is_undefined) {
889 const ty_index = self.imports.get(loc).?.kind.function;
890 return self.func_types.items[ty_index];
891 }
892 return self.func_types.items[self.functions.get(.{ .file = loc.file, .index = loc.index }).?.type_index];
893}
894
800/// Lowers a constant typed value to a local symbol and atom.895/// Lowers a constant typed value to a local symbol and atom.
801/// Returns the symbol index of the local896/// Returns the symbol index of the local
802/// The given `decl` is the parent decl whom owns the constant.897/// The given `decl` is the parent decl whom owns the constant.
...@@ -2501,7 +2596,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -2501,7 +2596,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
2501 // If there is no Zig code to compile, then we should skip flushing the output file because it2596 // If there is no Zig code to compile, then we should skip flushing the output file because it
2502 // will not be part of the linker line anyway.2597 // will not be part of the linker line anyway.
2503 const module_obj_path: ?[]const u8 = if (self.base.options.module) |mod| blk: {2598 const module_obj_path: ?[]const u8 = if (self.base.options.module) |mod| blk: {
2504 const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1;2599 const use_stage1 = build_options.have_stage1 and self.base.options.use_stage1;
2505 if (use_stage1) {2600 if (use_stage1) {
2506 const obj_basename = try std.zig.binNameAlloc(arena, .{2601 const obj_basename = try std.zig.binNameAlloc(arena, .{
2507 .root_name = self.base.options.root_name,2602 .root_name = self.base.options.root_name,
...@@ -2711,7 +2806,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !...@@ -2711,7 +2806,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
2711 if (self.base.options.module) |mod| {2806 if (self.base.options.module) |mod| {
2712 // when we use stage1, we use the exports that stage1 provided us.2807 // when we use stage1, we use the exports that stage1 provided us.
2713 // For stage2, we can directly retrieve them from the module.2808 // For stage2, we can directly retrieve them from the module.
2714 const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1;2809 const use_stage1 = build_options.have_stage1 and self.base.options.use_stage1;
2715 if (use_stage1) {2810 if (use_stage1) {
2716 for (comp.export_symbol_names.items) |symbol_name| {2811 for (comp.export_symbol_names.items) |symbol_name| {
2717 try argv.append(try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name}));2812 try argv.append(try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name}));
...@@ -3040,12 +3135,12 @@ fn emitSegmentInfo(self: *Wasm, file: fs.File, arena: Allocator) !void {...@@ -3040,12 +3135,12 @@ fn emitSegmentInfo(self: *Wasm, file: fs.File, arena: Allocator) !void {
3040 for (self.segment_info.items) |segment_info| {3135 for (self.segment_info.items) |segment_info| {
3041 log.debug("Emit segment: {s} align({d}) flags({b})", .{3136 log.debug("Emit segment: {s} align({d}) flags({b})", .{
3042 segment_info.name,3137 segment_info.name,
3043 @ctz(u32, segment_info.alignment),3138 @ctz(segment_info.alignment),
3044 segment_info.flags,3139 segment_info.flags,
3045 });3140 });
3046 try leb.writeULEB128(writer, @intCast(u32, segment_info.name.len));3141 try leb.writeULEB128(writer, @intCast(u32, segment_info.name.len));
3047 try writer.writeAll(segment_info.name);3142 try writer.writeAll(segment_info.name);
3048 try leb.writeULEB128(writer, @ctz(u32, segment_info.alignment));3143 try leb.writeULEB128(writer, @ctz(segment_info.alignment));
3049 try leb.writeULEB128(writer, segment_info.flags);3144 try leb.writeULEB128(writer, segment_info.flags);
3050 }3145 }
30513146
src/link/Wasm/Archive.zig+69-52
...@@ -15,6 +15,12 @@ name: []const u8,...@@ -15,6 +15,12 @@ name: []const u8,
1515
16header: ar_hdr = undefined,16header: ar_hdr = undefined,
1717
18/// A list of long file names, delimited by a LF character (0x0a).
19/// This is stored as a single slice of bytes, as the header-names
20/// point to the character index of a file name, rather than the index
21/// in the list.
22long_file_names: []const u8 = undefined,
23
18/// Parsed table of contents.24/// Parsed table of contents.
19/// Each symbol name points to a list of all definition25/// Each symbol name points to a list of all definition
20/// sites within the current static archive.26/// sites within the current static archive.
...@@ -53,32 +59,33 @@ const ar_hdr = extern struct {...@@ -53,32 +59,33 @@ const ar_hdr = extern struct {
53 /// Always contains ARFMAG.59 /// Always contains ARFMAG.
54 ar_fmag: [2]u8,60 ar_fmag: [2]u8,
5561
56 const NameOrLength = union(enum) {62 const NameOrIndex = union(enum) {
57 Name: []const u8,63 name: []const u8,
58 Length: u32,64 index: u32,
59 };65 };
60 fn nameOrLength(self: ar_hdr) !NameOrLength {66
61 const value = getValue(&self.ar_name);67 fn nameOrIndex(archive: ar_hdr) !NameOrIndex {
68 const value = getValue(&archive.ar_name);
62 const slash_index = mem.indexOfScalar(u8, value, '/') orelse return error.MalformedArchive;69 const slash_index = mem.indexOfScalar(u8, value, '/') orelse return error.MalformedArchive;
63 const len = value.len;70 const len = value.len;
64 if (slash_index == len - 1) {71 if (slash_index == len - 1) {
65 // Name stored directly72 // Name stored directly
66 return NameOrLength{ .Name = value };73 return NameOrIndex{ .name = value };
67 } else {74 } else {
68 // Name follows the header directly and its length is encoded in75 // Name follows the header directly and its length is encoded in
69 // the name field.76 // the name field.
70 const length = try std.fmt.parseInt(u32, value[slash_index + 1 ..], 10);77 const index = try std.fmt.parseInt(u32, value[slash_index + 1 ..], 10);
71 return NameOrLength{ .Length = length };78 return NameOrIndex{ .index = index };
72 }79 }
73 }80 }
7481
75 fn date(self: ar_hdr) !u64 {82 fn date(archive: ar_hdr) !u64 {
76 const value = getValue(&self.ar_date);83 const value = getValue(&archive.ar_date);
77 return std.fmt.parseInt(u64, value, 10);84 return std.fmt.parseInt(u64, value, 10);
78 }85 }
7986
80 fn size(self: ar_hdr) !u32 {87 fn size(archive: ar_hdr) !u32 {
81 const value = getValue(&self.ar_size);88 const value = getValue(&archive.ar_size);
82 return std.fmt.parseInt(u32, value, 10);89 return std.fmt.parseInt(u32, value, 10);
83 }90 }
8491
...@@ -87,18 +94,19 @@ const ar_hdr = extern struct {...@@ -87,18 +94,19 @@ const ar_hdr = extern struct {
87 }94 }
88};95};
8996
90pub fn deinit(self: *Archive, allocator: Allocator) void {97pub fn deinit(archive: *Archive, allocator: Allocator) void {
91 for (self.toc.keys()) |*key| {98 for (archive.toc.keys()) |*key| {
92 allocator.free(key.*);99 allocator.free(key.*);
93 }100 }
94 for (self.toc.values()) |*value| {101 for (archive.toc.values()) |*value| {
95 value.deinit(allocator);102 value.deinit(allocator);
96 }103 }
97 self.toc.deinit(allocator);104 archive.toc.deinit(allocator);
105 allocator.free(archive.long_file_names);
98}106}
99107
100pub fn parse(self: *Archive, allocator: Allocator) !void {108pub fn parse(archive: *Archive, allocator: Allocator) !void {
101 const reader = self.file.reader();109 const reader = archive.file.reader();
102110
103 const magic = try reader.readBytesNoEof(SARMAG);111 const magic = try reader.readBytesNoEof(SARMAG);
104 if (!mem.eql(u8, &magic, ARMAG)) {112 if (!mem.eql(u8, &magic, ARMAG)) {
...@@ -106,38 +114,31 @@ pub fn parse(self: *Archive, allocator: Allocator) !void {...@@ -106,38 +114,31 @@ pub fn parse(self: *Archive, allocator: Allocator) !void {
106 return error.NotArchive;114 return error.NotArchive;
107 }115 }
108116
109 self.header = try reader.readStruct(ar_hdr);117 archive.header = try reader.readStruct(ar_hdr);
110 if (!mem.eql(u8, &self.header.ar_fmag, ARFMAG)) {118 if (!mem.eql(u8, &archive.header.ar_fmag, ARFMAG)) {
111 log.debug("invalid header delimiter: expected '{s}', found '{s}'", .{ ARFMAG, self.header.ar_fmag });119 log.debug("invalid header delimiter: expected '{s}', found '{s}'", .{ ARFMAG, archive.header.ar_fmag });
112 return error.NotArchive;120 return error.NotArchive;
113 }121 }
114122
115 try self.parseTableOfContents(allocator, reader);123 try archive.parseTableOfContents(allocator, reader);
124 try archive.parseNameTable(allocator, reader);
116}125}
117126
118fn parseName(allocator: Allocator, header: ar_hdr, reader: anytype) ![]u8 {127fn parseName(archive: *const Archive, header: ar_hdr) ![]const u8 {
119 const name_or_length = try header.nameOrLength();128 const name_or_index = try header.nameOrIndex();
120 var name: []u8 = undefined;129 switch (name_or_index) {
121 switch (name_or_length) {130 .name => |name| return name,
122 .Name => |n| {131 .index => |index| {
123 name = try allocator.dupe(u8, n);132 const name = mem.sliceTo(archive.long_file_names[index..], 0x0a);
124 },133 return mem.trimRight(u8, name, "/");
125 .Length => |len| {
126 var n = try allocator.alloc(u8, len);
127 defer allocator.free(n);
128 try reader.readNoEof(n);
129 const actual_len = mem.indexOfScalar(u8, n, @as(u8, 0)) orelse n.len;
130 name = try allocator.dupe(u8, n[0..actual_len]);
131 },134 },
132 }135 }
133 return name;
134}136}
135137
136fn parseTableOfContents(self: *Archive, allocator: Allocator, reader: anytype) !void {138fn parseTableOfContents(archive: *Archive, allocator: Allocator, reader: anytype) !void {
137 log.debug("parsing table of contents for archive file '{s}'", .{self.name});
138 // size field can have extra spaces padded in front as well as the end,139 // size field can have extra spaces padded in front as well as the end,
139 // so we trim those first before parsing the ASCII value.140 // so we trim those first before parsing the ASCII value.
140 const size_trimmed = std.mem.trim(u8, &self.header.ar_size, " ");141 const size_trimmed = mem.trim(u8, &archive.header.ar_size, " ");
141 const sym_tab_size = try std.fmt.parseInt(u32, size_trimmed, 10);142 const sym_tab_size = try std.fmt.parseInt(u32, size_trimmed, 10);
142143
143 const num_symbols = try reader.readIntBig(u32);144 const num_symbols = try reader.readIntBig(u32);
...@@ -157,7 +158,7 @@ fn parseTableOfContents(self: *Archive, allocator: Allocator, reader: anytype) !...@@ -157,7 +158,7 @@ fn parseTableOfContents(self: *Archive, allocator: Allocator, reader: anytype) !
157158
158 var i: usize = 0;159 var i: usize = 0;
159 while (i < sym_tab.len) {160 while (i < sym_tab.len) {
160 const string = std.mem.sliceTo(sym_tab[i..], 0);161 const string = mem.sliceTo(sym_tab[i..], 0);
161 if (string.len == 0) {162 if (string.len == 0) {
162 i += 1;163 i += 1;
163 continue;164 continue;
...@@ -165,7 +166,7 @@ fn parseTableOfContents(self: *Archive, allocator: Allocator, reader: anytype) !...@@ -165,7 +166,7 @@ fn parseTableOfContents(self: *Archive, allocator: Allocator, reader: anytype) !
165 i += string.len;166 i += string.len;
166 const name = try allocator.dupe(u8, string);167 const name = try allocator.dupe(u8, string);
167 errdefer allocator.free(name);168 errdefer allocator.free(name);
168 const gop = try self.toc.getOrPut(allocator, name);169 const gop = try archive.toc.getOrPut(allocator, name);
169 if (gop.found_existing) {170 if (gop.found_existing) {
170 allocator.free(name);171 allocator.free(name);
171 } else {172 } else {
...@@ -175,33 +176,49 @@ fn parseTableOfContents(self: *Archive, allocator: Allocator, reader: anytype) !...@@ -175,33 +176,49 @@ fn parseTableOfContents(self: *Archive, allocator: Allocator, reader: anytype) !
175 }176 }
176}177}
177178
179fn parseNameTable(archive: *Archive, allocator: Allocator, reader: anytype) !void {
180 const header: ar_hdr = try reader.readStruct(ar_hdr);
181 if (!mem.eql(u8, &header.ar_fmag, ARFMAG)) {
182 log.err("invalid header delimiter: expected '{s}', found '{s}'", .{ ARFMAG, header.ar_fmag });
183 return error.MalformedArchive;
184 }
185 if (!mem.eql(u8, header.ar_name[0..2], "//")) {
186 log.err("invalid archive. Long name table missing", .{});
187 return error.MalformedArchive;
188 }
189 const table_size = try header.size();
190 const long_file_names = try allocator.alloc(u8, table_size);
191 errdefer allocator.free(long_file_names);
192 try reader.readNoEof(long_file_names);
193 archive.long_file_names = long_file_names;
194}
195
178/// From a given file offset, starts reading for a file header.196/// From a given file offset, starts reading for a file header.
179/// When found, parses the object file into an `Object` and returns it.197/// When found, parses the object file into an `Object` and returns it.
180pub fn parseObject(self: Archive, allocator: Allocator, file_offset: u32) !Object {198pub fn parseObject(archive: Archive, allocator: Allocator, file_offset: u32) !Object {
181 try self.file.seekTo(file_offset);199 try archive.file.seekTo(file_offset);
182 const reader = self.file.reader();200 const reader = archive.file.reader();
183 const header = try reader.readStruct(ar_hdr);201 const header = try reader.readStruct(ar_hdr);
184 const current_offset = try self.file.getPos();202 const current_offset = try archive.file.getPos();
185 try self.file.seekTo(0);203 try archive.file.seekTo(0);
186204
187 if (!mem.eql(u8, &header.ar_fmag, ARFMAG)) {205 if (!mem.eql(u8, &header.ar_fmag, ARFMAG)) {
188 log.err("invalid header delimiter: expected '{s}', found '{s}'", .{ ARFMAG, header.ar_fmag });206 log.err("invalid header delimiter: expected '{s}', found '{s}'", .{ ARFMAG, header.ar_fmag });
189 return error.MalformedArchive;207 return error.MalformedArchive;
190 }208 }
191209
192 const object_name = try parseName(allocator, header, reader);210 const object_name = try archive.parseName(header);
193 defer allocator.free(object_name);
194
195 const name = name: {211 const name = name: {
196 var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;212 var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
197 const path = try std.os.realpath(self.name, &buffer);213 const path = try std.os.realpath(archive.name, &buffer);
198 break :name try std.fmt.allocPrint(allocator, "{s}({s})", .{ path, object_name });214 break :name try std.fmt.allocPrint(allocator, "{s}({s})", .{ path, object_name });
199 };215 };
200 defer allocator.free(name);216 defer allocator.free(name);
201217
202 const object_file = try std.fs.cwd().openFile(self.name, .{});218 const object_file = try std.fs.cwd().openFile(archive.name, .{});
203 errdefer object_file.close();219 errdefer object_file.close();
204220
221 const object_file_size = try header.size();
205 try object_file.seekTo(current_offset);222 try object_file.seekTo(current_offset);
206 return Object.create(allocator, object_file, name);223 return Object.create(allocator, object_file, name, object_file_size);
207}224}
src/link/Wasm/Object.zig+21-2
...@@ -105,14 +105,33 @@ pub const InitError = error{NotObjectFile} || ParseError || std.fs.File.ReadErro...@@ -105,14 +105,33 @@ pub const InitError = error{NotObjectFile} || ParseError || std.fs.File.ReadErro
105105
106/// Initializes a new `Object` from a wasm object file.106/// Initializes a new `Object` from a wasm object file.
107/// This also parses and verifies the object file.107/// This also parses and verifies the object file.
108pub fn create(gpa: Allocator, file: std.fs.File, name: []const u8) InitError!Object {108/// When a max size is given, will only parse up to the given size,
109/// else will read until the end of the file.
110pub fn create(gpa: Allocator, file: std.fs.File, name: []const u8, maybe_max_size: ?usize) InitError!Object {
109 var object: Object = .{111 var object: Object = .{
110 .file = file,112 .file = file,
111 .name = try gpa.dupe(u8, name),113 .name = try gpa.dupe(u8, name),
112 };114 };
113115
114 var is_object_file: bool = false;116 var is_object_file: bool = false;
115 try object.parse(gpa, file.reader(), &is_object_file);117 const size = maybe_max_size orelse size: {
118 errdefer gpa.free(object.name);
119 const stat = try file.stat();
120 break :size @intCast(usize, stat.size);
121 };
122
123 const file_contents = try gpa.alloc(u8, size);
124 defer gpa.free(file_contents);
125 var file_reader = file.reader();
126 var read: usize = 0;
127 while (read < size) {
128 const n = try file_reader.read(file_contents[read..]);
129 std.debug.assert(n != 0);
130 read += n;
131 }
132 var fbs = std.io.fixedBufferStream(file_contents);
133
134 try object.parse(gpa, fbs.reader(), &is_object_file);
116 errdefer object.deinit(gpa);135 errdefer object.deinit(gpa);
117 if (!is_object_file) return error.NotObjectFile;136 if (!is_object_file) return error.NotObjectFile;
118137
src/main.zig+44-33
...@@ -378,6 +378,8 @@ const usage_build_generic =...@@ -378,6 +378,8 @@ const usage_build_generic =
378 \\ -fno-lto Force-disable Link Time Optimization378 \\ -fno-lto Force-disable Link Time Optimization
379 \\ -fstack-check Enable stack probing in unsafe builds379 \\ -fstack-check Enable stack probing in unsafe builds
380 \\ -fno-stack-check Disable stack probing in safe builds380 \\ -fno-stack-check Disable stack probing in safe builds
381 \\ -fstack-protector Enable stack protection in unsafe builds
382 \\ -fno-stack-protector Disable stack protection in safe builds
381 \\ -fsanitize-c Enable C undefined behavior detection in unsafe builds383 \\ -fsanitize-c Enable C undefined behavior detection in unsafe builds
382 \\ -fno-sanitize-c Disable C undefined behavior detection in safe builds384 \\ -fno-sanitize-c Disable C undefined behavior detection in safe builds
383 \\ -fvalgrind Include valgrind client requests in release builds385 \\ -fvalgrind Include valgrind client requests in release builds
...@@ -668,6 +670,7 @@ fn buildOutputType(...@@ -668,6 +670,7 @@ fn buildOutputType(
668 var want_unwind_tables: ?bool = null;670 var want_unwind_tables: ?bool = null;
669 var want_sanitize_c: ?bool = null;671 var want_sanitize_c: ?bool = null;
670 var want_stack_check: ?bool = null;672 var want_stack_check: ?bool = null;
673 var want_stack_protector: ?u32 = null;
671 var want_red_zone: ?bool = null;674 var want_red_zone: ?bool = null;
672 var omit_frame_pointer: ?bool = null;675 var omit_frame_pointer: ?bool = null;
673 var want_valgrind: ?bool = null;676 var want_valgrind: ?bool = null;
...@@ -718,7 +721,7 @@ fn buildOutputType(...@@ -718,7 +721,7 @@ fn buildOutputType(
718 var test_filter: ?[]const u8 = null;721 var test_filter: ?[]const u8 = null;
719 var test_name_prefix: ?[]const u8 = null;722 var test_name_prefix: ?[]const u8 = null;
720 var override_local_cache_dir: ?[]const u8 = try optionalStringEnvVar(arena, "ZIG_LOCAL_CACHE_DIR");723 var override_local_cache_dir: ?[]const u8 = try optionalStringEnvVar(arena, "ZIG_LOCAL_CACHE_DIR");
721 var override_global_cache_dir: ?[]const u8 = null;724 var override_global_cache_dir: ?[]const u8 = try optionalStringEnvVar(arena, "ZIG_GLOBAL_CACHE_DIR");
722 var override_lib_dir: ?[]const u8 = try optionalStringEnvVar(arena, "ZIG_LIB_DIR");725 var override_lib_dir: ?[]const u8 = try optionalStringEnvVar(arena, "ZIG_LIB_DIR");
723 var main_pkg_path: ?[]const u8 = null;726 var main_pkg_path: ?[]const u8 = null;
724 var clang_preprocessor_mode: Compilation.ClangPreprocessorMode = .no;727 var clang_preprocessor_mode: Compilation.ClangPreprocessorMode = .no;
...@@ -1168,6 +1171,10 @@ fn buildOutputType(...@@ -1168,6 +1171,10 @@ fn buildOutputType(
1168 want_stack_check = true;1171 want_stack_check = true;
1169 } else if (mem.eql(u8, arg, "-fno-stack-check")) {1172 } else if (mem.eql(u8, arg, "-fno-stack-check")) {
1170 want_stack_check = false;1173 want_stack_check = false;
1174 } else if (mem.eql(u8, arg, "-fstack-protector")) {
1175 want_stack_protector = Compilation.default_stack_protector_buffer_size;
1176 } else if (mem.eql(u8, arg, "-fno-stack-protector")) {
1177 want_stack_protector = 0;
1171 } else if (mem.eql(u8, arg, "-mred-zone")) {1178 } else if (mem.eql(u8, arg, "-mred-zone")) {
1172 want_red_zone = true;1179 want_red_zone = true;
1173 } else if (mem.eql(u8, arg, "-mno-red-zone")) {1180 } else if (mem.eql(u8, arg, "-mno-red-zone")) {
...@@ -1521,6 +1528,12 @@ fn buildOutputType(...@@ -1521,6 +1528,12 @@ fn buildOutputType(
1521 .no_color_diagnostics => color = .off,1528 .no_color_diagnostics => color = .off,
1522 .stack_check => want_stack_check = true,1529 .stack_check => want_stack_check = true,
1523 .no_stack_check => want_stack_check = false,1530 .no_stack_check => want_stack_check = false,
1531 .stack_protector => {
1532 if (want_stack_protector == null) {
1533 want_stack_protector = Compilation.default_stack_protector_buffer_size;
1534 }
1535 },
1536 .no_stack_protector => want_stack_protector = 0,
1524 .unwind_tables => want_unwind_tables = true,1537 .unwind_tables => want_unwind_tables = true,
1525 .no_unwind_tables => want_unwind_tables = false,1538 .no_unwind_tables => want_unwind_tables = false,
1526 .nostdlib => ensure_libc_on_non_freestanding = false,1539 .nostdlib => ensure_libc_on_non_freestanding = false,
...@@ -1657,7 +1670,8 @@ fn buildOutputType(...@@ -1657,7 +1670,8 @@ fn buildOutputType(
1657 disable_c_depfile = true;1670 disable_c_depfile = true;
1658 try clang_argv.appendSlice(it.other_args);1671 try clang_argv.appendSlice(it.other_args);
1659 },1672 },
1660 .dep_file_mm => { // -MM1673 .dep_file_to_stdout => { // -M, -MM
1674 // "Like -MD, but also implies -E and writes to stdout by default"
1661 // "Like -MMD, but also implies -E and writes to stdout by default"1675 // "Like -MMD, but also implies -E and writes to stdout by default"
1662 c_out_mode = .preprocessor;1676 c_out_mode = .preprocessor;
1663 disable_c_depfile = true;1677 disable_c_depfile = true;
...@@ -2191,6 +2205,7 @@ fn buildOutputType(...@@ -2191,6 +2205,7 @@ fn buildOutputType(
2191 .arch_os_abi = target_arch_os_abi,2205 .arch_os_abi = target_arch_os_abi,
2192 .cpu_features = target_mcpu,2206 .cpu_features = target_mcpu,
2193 .dynamic_linker = target_dynamic_linker,2207 .dynamic_linker = target_dynamic_linker,
2208 .object_format = target_ofmt,
2194 };2209 };
21952210
2196 // Before passing the mcpu string in for parsing, we convert any -m flags that were2211 // Before passing the mcpu string in for parsing, we convert any -m flags that were
...@@ -2493,28 +2508,7 @@ fn buildOutputType(...@@ -2493,28 +2508,7 @@ fn buildOutputType(
2493 }2508 }
2494 }2509 }
24952510
2496 const object_format: std.Target.ObjectFormat = blk: {2511 const object_format = target_info.target.ofmt;
2497 const ofmt = target_ofmt orelse break :blk target_info.target.getObjectFormat();
2498 if (mem.eql(u8, ofmt, "elf")) {
2499 break :blk .elf;
2500 } else if (mem.eql(u8, ofmt, "c")) {
2501 break :blk .c;
2502 } else if (mem.eql(u8, ofmt, "coff")) {
2503 break :blk .coff;
2504 } else if (mem.eql(u8, ofmt, "macho")) {
2505 break :blk .macho;
2506 } else if (mem.eql(u8, ofmt, "wasm")) {
2507 break :blk .wasm;
2508 } else if (mem.eql(u8, ofmt, "hex")) {
2509 break :blk .hex;
2510 } else if (mem.eql(u8, ofmt, "raw")) {
2511 break :blk .raw;
2512 } else if (mem.eql(u8, ofmt, "spirv")) {
2513 break :blk .spirv;
2514 } else {
2515 fatal("unsupported object format: {s}", .{ofmt});
2516 }
2517 };
25182512
2519 if (output_mode == .Obj and (object_format == .coff or object_format == .macho)) {2513 if (output_mode == .Obj and (object_format == .coff or object_format == .macho)) {
2520 const total_obj_count = c_source_files.items.len +2514 const total_obj_count = c_source_files.items.len +
...@@ -2568,7 +2562,6 @@ fn buildOutputType(...@@ -2568,7 +2562,6 @@ fn buildOutputType(
2568 .target = target_info.target,2562 .target = target_info.target,
2569 .output_mode = output_mode,2563 .output_mode = output_mode,
2570 .link_mode = link_mode,2564 .link_mode = link_mode,
2571 .object_format = object_format,
2572 .version = optional_version,2565 .version = optional_version,
2573 }),2566 }),
2574 },2567 },
...@@ -2858,7 +2851,6 @@ fn buildOutputType(...@@ -2858,7 +2851,6 @@ fn buildOutputType(
2858 .emit_implib = emit_implib_resolved.data,2851 .emit_implib = emit_implib_resolved.data,
2859 .link_mode = link_mode,2852 .link_mode = link_mode,
2860 .dll_export_fns = dll_export_fns,2853 .dll_export_fns = dll_export_fns,
2861 .object_format = object_format,
2862 .optimize_mode = optimize_mode,2854 .optimize_mode = optimize_mode,
2863 .keep_source_files_loaded = false,2855 .keep_source_files_loaded = false,
2864 .clang_argv = clang_argv.items,2856 .clang_argv = clang_argv.items,
...@@ -2880,6 +2872,7 @@ fn buildOutputType(...@@ -2880,6 +2872,7 @@ fn buildOutputType(
2880 .want_unwind_tables = want_unwind_tables,2872 .want_unwind_tables = want_unwind_tables,
2881 .want_sanitize_c = want_sanitize_c,2873 .want_sanitize_c = want_sanitize_c,
2882 .want_stack_check = want_stack_check,2874 .want_stack_check = want_stack_check,
2875 .want_stack_protector = want_stack_protector,
2883 .want_red_zone = want_red_zone,2876 .want_red_zone = want_red_zone,
2884 .omit_frame_pointer = omit_frame_pointer,2877 .omit_frame_pointer = omit_frame_pointer,
2885 .want_valgrind = want_valgrind,2878 .want_valgrind = want_valgrind,
...@@ -2996,7 +2989,7 @@ fn buildOutputType(...@@ -2996,7 +2989,7 @@ fn buildOutputType(
2996 return std.io.getStdOut().writeAll(try comp.generateBuiltinZigSource(arena));2989 return std.io.getStdOut().writeAll(try comp.generateBuiltinZigSource(arena));
2997 }2990 }
2998 if (arg_mode == .translate_c) {2991 if (arg_mode == .translate_c) {
2999 const stage1_mode = use_stage1 orelse build_options.is_stage1;2992 const stage1_mode = use_stage1 orelse false;
3000 return cmdTranslateC(comp, arena, have_enable_cache, stage1_mode);2993 return cmdTranslateC(comp, arena, have_enable_cache, stage1_mode);
3001 }2994 }
30022995
...@@ -3172,11 +3165,11 @@ fn parseCrossTargetOrReportFatalError(...@@ -3172,11 +3165,11 @@ fn parseCrossTargetOrReportFatalError(
3172 for (diags.arch.?.allCpuModels()) |cpu| {3165 for (diags.arch.?.allCpuModels()) |cpu| {
3173 help_text.writer().print(" {s}\n", .{cpu.name}) catch break :help;3166 help_text.writer().print(" {s}\n", .{cpu.name}) catch break :help;
3174 }3167 }
3175 std.log.info("Available CPUs for architecture '{s}':\n{s}", .{3168 std.log.info("available CPUs for architecture '{s}':\n{s}", .{
3176 @tagName(diags.arch.?), help_text.items,3169 @tagName(diags.arch.?), help_text.items,
3177 });3170 });
3178 }3171 }
3179 fatal("Unknown CPU: '{s}'", .{diags.cpu_name.?});3172 fatal("unknown CPU: '{s}'", .{diags.cpu_name.?});
3180 },3173 },
3181 error.UnknownCpuFeature => {3174 error.UnknownCpuFeature => {
3182 help: {3175 help: {
...@@ -3185,11 +3178,26 @@ fn parseCrossTargetOrReportFatalError(...@@ -3185,11 +3178,26 @@ fn parseCrossTargetOrReportFatalError(
3185 for (diags.arch.?.allFeaturesList()) |feature| {3178 for (diags.arch.?.allFeaturesList()) |feature| {
3186 help_text.writer().print(" {s}: {s}\n", .{ feature.name, feature.description }) catch break :help;3179 help_text.writer().print(" {s}: {s}\n", .{ feature.name, feature.description }) catch break :help;
3187 }3180 }
3188 std.log.info("Available CPU features for architecture '{s}':\n{s}", .{3181 std.log.info("available CPU features for architecture '{s}':\n{s}", .{
3189 @tagName(diags.arch.?), help_text.items,3182 @tagName(diags.arch.?), help_text.items,
3190 });3183 });
3191 }3184 }
3192 fatal("Unknown CPU feature: '{s}'", .{diags.unknown_feature_name.?});3185 fatal("unknown CPU feature: '{s}'", .{diags.unknown_feature_name.?});
3186 },
3187 error.UnknownObjectFormat => {
3188 {
3189 var help_text = std.ArrayList(u8).init(allocator);
3190 defer help_text.deinit();
3191 inline for (@typeInfo(std.Target.ObjectFormat).Enum.fields) |field| {
3192 help_text.writer().print(" {s}\n", .{field.name}) catch
3193 // TODO change this back to `break :help`
3194 // this working around a stage1 bug.
3195 //break :help;
3196 @panic("out of memory");
3197 }
3198 std.log.info("available object formats:\n{s}", .{help_text.items});
3199 }
3200 fatal("unknown object format: '{s}'", .{opts.object_format.?});
3193 },3201 },
3194 else => |e| return e,3202 else => |e| return e,
3195 };3203 };
...@@ -3359,7 +3367,7 @@ fn updateModule(gpa: Allocator, comp: *Compilation, hook: AfterUpdateHook) !void...@@ -3359,7 +3367,7 @@ fn updateModule(gpa: Allocator, comp: *Compilation, hook: AfterUpdateHook) !void
33593367
3360 // If a .pdb file is part of the expected output, we must also copy3368 // If a .pdb file is part of the expected output, we must also copy
3361 // it into place here.3369 // it into place here.
3362 const is_coff = comp.bin_file.options.object_format == .coff;3370 const is_coff = comp.bin_file.options.target.ofmt == .coff;
3363 const have_pdb = is_coff and !comp.bin_file.options.strip;3371 const have_pdb = is_coff and !comp.bin_file.options.strip;
3364 if (have_pdb) {3372 if (have_pdb) {
3365 // Replace `.out` or `.exe` with `.pdb` on both the source and destination3373 // Replace `.out` or `.exe` with `.pdb` on both the source and destination
...@@ -4226,6 +4234,7 @@ const FmtError = error{...@@ -4226,6 +4234,7 @@ const FmtError = error{
4226 NotOpenForWriting,4234 NotOpenForWriting,
4227 UnsupportedEncoding,4235 UnsupportedEncoding,
4228 ConnectionResetByPeer,4236 ConnectionResetByPeer,
4237 LockViolation,
4229} || fs.File.OpenError;4238} || fs.File.OpenError;
42304239
4231fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: fs.Dir, sub_path: []const u8) FmtError!void {4240fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: fs.Dir, sub_path: []const u8) FmtError!void {
...@@ -4652,7 +4661,7 @@ pub const ClangArgIterator = struct {...@@ -4652,7 +4661,7 @@ pub const ClangArgIterator = struct {
4652 lib_dir,4661 lib_dir,
4653 mcpu,4662 mcpu,
4654 dep_file,4663 dep_file,
4655 dep_file_mm,4664 dep_file_to_stdout,
4656 framework_dir,4665 framework_dir,
4657 framework,4666 framework,
4658 nostdlibinc,4667 nostdlibinc,
...@@ -4668,6 +4677,8 @@ pub const ClangArgIterator = struct {...@@ -4668,6 +4677,8 @@ pub const ClangArgIterator = struct {
4668 no_color_diagnostics,4677 no_color_diagnostics,
4669 stack_check,4678 stack_check,
4670 no_stack_check,4679 no_stack_check,
4680 stack_protector,
4681 no_stack_protector,
4671 strip,4682 strip,
4672 exec_model,4683 exec_model,
4673 emit_llvm,4684 emit_llvm,
src/mingw.zig-6
...@@ -93,12 +93,6 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -93,12 +93,6 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
93 "-D_WIN32_WINNT=0x0f00",93 "-D_WIN32_WINNT=0x0f00",
94 "-D__MSVCRT_VERSION__=0x700",94 "-D__MSVCRT_VERSION__=0x700",
95 });95 });
96 if (std.mem.eql(u8, dep, "tlssup.c") and comp.bin_file.options.lto) {
97 // LLD will incorrectly drop the `_tls_index` symbol. Here we work
98 // around it by not using LTO for this one file.
99 // https://github.com/ziglang/zig/issues/8531
100 try args.append("-fno-lto");
101 }
102 c_source_files[i] = .{96 c_source_files[i] = .{
103 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{97 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
104 "libc", "mingw", "crt", dep,98 "libc", "mingw", "crt", dep,
src/musl.zig+1
...@@ -215,6 +215,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -215,6 +215,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
215 .optimize_mode = comp.compilerRtOptMode(),215 .optimize_mode = comp.compilerRtOptMode(),
216 .want_sanitize_c = false,216 .want_sanitize_c = false,
217 .want_stack_check = false,217 .want_stack_check = false,
218 .want_stack_protector = 0,
218 .want_red_zone = comp.bin_file.options.red_zone,219 .want_red_zone = comp.bin_file.options.red_zone,
219 .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer,220 .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer,
220 .want_valgrind = false,221 .want_valgrind = false,
src/print_air.zig+2
...@@ -170,6 +170,7 @@ const Writer = struct {...@@ -170,6 +170,7 @@ const Writer = struct {
170 .bool_to_int,170 .bool_to_int,
171 .ret,171 .ret,
172 .ret_load,172 .ret_load,
173 .is_named_enum_value,
173 .tag_name,174 .tag_name,
174 .error_name,175 .error_name,
175 .sqrt,176 .sqrt,
...@@ -242,6 +243,7 @@ const Writer = struct {...@@ -242,6 +243,7 @@ const Writer = struct {
242 .popcount,243 .popcount,
243 .byte_swap,244 .byte_swap,
244 .bit_reverse,245 .bit_reverse,
246 .error_set_has_value,
245 => try w.writeTyOp(s, inst),247 => try w.writeTyOp(s, inst),
246248
247 .block,249 .block,
src/print_zir.zig+76-29
...@@ -214,7 +214,6 @@ const Writer = struct {...@@ -214,7 +214,6 @@ const Writer = struct {
214 .trunc,214 .trunc,
215 .round,215 .round,
216 .tag_name,216 .tag_name,
217 .reify,
218 .type_name,217 .type_name,
219 .frame_type,218 .frame_type,
220 .frame_size,219 .frame_size,
...@@ -247,7 +246,6 @@ const Writer = struct {...@@ -247,7 +246,6 @@ const Writer = struct {
247246
248 .validate_array_init_ty => try self.writeValidateArrayInitTy(stream, inst),247 .validate_array_init_ty => try self.writeValidateArrayInitTy(stream, inst),
249 .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst),248 .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst),
250 .param_type => try self.writeParamType(stream, inst),
251 .ptr_type => try self.writePtrType(stream, inst),249 .ptr_type => try self.writePtrType(stream, inst),
252 .int => try self.writeInt(stream, inst),250 .int => try self.writeInt(stream, inst),
253 .int_big => try self.writeIntBig(stream, inst),251 .int_big => try self.writeIntBig(stream, inst),
...@@ -500,6 +498,7 @@ const Writer = struct {...@@ -500,6 +498,7 @@ const Writer = struct {
500 .wasm_memory_size,498 .wasm_memory_size,
501 .error_to_int,499 .error_to_int,
502 .int_to_error,500 .int_to_error,
501 .reify,
503 => {502 => {
504 const inst_data = self.code.extraData(Zir.Inst.UnNode, extended.operand).data;503 const inst_data = self.code.extraData(Zir.Inst.UnNode, extended.operand).data;
505 const src = LazySrcLoc.nodeOffset(inst_data.node);504 const src = LazySrcLoc.nodeOffset(inst_data.node);
...@@ -605,16 +604,6 @@ const Writer = struct {...@@ -605,16 +604,6 @@ const Writer = struct {
605 try self.writeSrc(stream, inst_data.src());604 try self.writeSrc(stream, inst_data.src());
606 }605 }
607606
608 fn writeParamType(
609 self: *Writer,
610 stream: anytype,
611 inst: Zir.Inst.Index,
612 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
613 const inst_data = self.code.instructions.items(.data)[inst].param_type;
614 try self.writeInstRef(stream, inst_data.callee);
615 try stream.print(", {d})", .{inst_data.param_index});
616 }
617
618 fn writePtrType(607 fn writePtrType(
619 self: *Writer,608 self: *Writer,
620 stream: anytype,609 stream: anytype,
...@@ -1158,7 +1147,8 @@ const Writer = struct {...@@ -1158,7 +1147,8 @@ const Writer = struct {
1158 fn writeCall(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {1147 fn writeCall(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1159 const inst_data = self.code.instructions.items(.data)[inst].pl_node;1148 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1160 const extra = self.code.extraData(Zir.Inst.Call, inst_data.payload_index);1149 const extra = self.code.extraData(Zir.Inst.Call, inst_data.payload_index);
1161 const args = self.code.refSlice(extra.end, extra.data.flags.args_len);1150 const args_len = extra.data.flags.args_len;
1151 const body = self.code.extra[extra.end..];
11621152
1163 if (extra.data.flags.ensure_result_used) {1153 if (extra.data.flags.ensure_result_used) {
1164 try stream.writeAll("nodiscard ");1154 try stream.writeAll("nodiscard ");
...@@ -1166,10 +1156,27 @@ const Writer = struct {...@@ -1166,10 +1156,27 @@ const Writer = struct {
1166 try stream.print(".{s}, ", .{@tagName(@intToEnum(std.builtin.CallOptions.Modifier, extra.data.flags.packed_modifier))});1156 try stream.print(".{s}, ", .{@tagName(@intToEnum(std.builtin.CallOptions.Modifier, extra.data.flags.packed_modifier))});
1167 try self.writeInstRef(stream, extra.data.callee);1157 try self.writeInstRef(stream, extra.data.callee);
1168 try stream.writeAll(", [");1158 try stream.writeAll(", [");
1169 for (args) |arg, i| {1159
1170 if (i != 0) try stream.writeAll(", ");1160 self.indent += 2;
1171 try self.writeInstRef(stream, arg);1161 if (args_len != 0) {
1162 try stream.writeAll("\n");
1172 }1163 }
1164 var i: usize = 0;
1165 var arg_start: u32 = args_len;
1166 while (i < args_len) : (i += 1) {
1167 try stream.writeByteNTimes(' ', self.indent);
1168 const arg_end = self.code.extra[extra.end + i];
1169 defer arg_start = arg_end;
1170 const arg_body = body[arg_start..arg_end];
1171 try self.writeBracedBody(stream, arg_body);
1172
1173 try stream.writeAll(",\n");
1174 }
1175 self.indent -= 2;
1176 if (args_len != 0) {
1177 try stream.writeByteNTimes(' ', self.indent);
1178 }
1179
1173 try stream.writeAll("]) ");1180 try stream.writeAll("]) ");
1174 try self.writeSrc(stream, inst_data.src());1181 try self.writeSrc(stream, inst_data.src());
1175 }1182 }
...@@ -1238,13 +1245,36 @@ const Writer = struct {...@@ -1238,13 +1245,36 @@ const Writer = struct {
12381245
1239 try self.writeFlag(stream, "known_non_opv, ", small.known_non_opv);1246 try self.writeFlag(stream, "known_non_opv, ", small.known_non_opv);
1240 try self.writeFlag(stream, "known_comptime_only, ", small.known_comptime_only);1247 try self.writeFlag(stream, "known_comptime_only, ", small.known_comptime_only);
1241 try stream.print("{s}, {s}, ", .{1248
1242 @tagName(small.name_strategy), @tagName(small.layout),1249 try stream.print("{s}, ", .{@tagName(small.name_strategy)});
1243 });1250
1251 if (small.layout == .Packed and small.has_backing_int) {
1252 const backing_int_body_len = self.code.extra[extra_index];
1253 extra_index += 1;
1254 try stream.writeAll("Packed(");
1255 if (backing_int_body_len == 0) {
1256 const backing_int_ref = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
1257 extra_index += 1;
1258 try self.writeInstRef(stream, backing_int_ref);
1259 } else {
1260 const body = self.code.extra[extra_index..][0..backing_int_body_len];
1261 extra_index += backing_int_body_len;
1262 self.indent += 2;
1263 try self.writeBracedDecl(stream, body);
1264 self.indent -= 2;
1265 }
1266 try stream.writeAll("), ");
1267 } else {
1268 try stream.print("{s}, ", .{@tagName(small.layout)});
1269 }
12441270
1245 if (decls_len == 0) {1271 if (decls_len == 0) {
1246 try stream.writeAll("{}, ");1272 try stream.writeAll("{}, ");
1247 } else {1273 } else {
1274 const prev_parent_decl_node = self.parent_decl_node;
1275 if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off);
1276 defer self.parent_decl_node = prev_parent_decl_node;
1277
1248 try stream.writeAll("{\n");1278 try stream.writeAll("{\n");
1249 self.indent += 2;1279 self.indent += 2;
1250 extra_index = try self.writeDecls(stream, decls_len, extra_index);1280 extra_index = try self.writeDecls(stream, decls_len, extra_index);
...@@ -1413,22 +1443,31 @@ const Writer = struct {...@@ -1413,22 +1443,31 @@ const Writer = struct {
1413 try self.writeFlag(stream, "autoenum, ", small.auto_enum_tag);1443 try self.writeFlag(stream, "autoenum, ", small.auto_enum_tag);
14141444
1415 if (decls_len == 0) {1445 if (decls_len == 0) {
1416 try stream.writeAll("{}, ");1446 try stream.writeAll("{}");
1417 } else {1447 } else {
1448 const prev_parent_decl_node = self.parent_decl_node;
1449 if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off);
1450 defer self.parent_decl_node = prev_parent_decl_node;
1451
1418 try stream.writeAll("{\n");1452 try stream.writeAll("{\n");
1419 self.indent += 2;1453 self.indent += 2;
1420 extra_index = try self.writeDecls(stream, decls_len, extra_index);1454 extra_index = try self.writeDecls(stream, decls_len, extra_index);
1421 self.indent -= 2;1455 self.indent -= 2;
1422 try stream.writeByteNTimes(' ', self.indent);1456 try stream.writeByteNTimes(' ', self.indent);
1423 try stream.writeAll("}, ");1457 try stream.writeAll("}");
1424 }1458 }
14251459
1426 assert(fields_len != 0);
1427
1428 if (tag_type_ref != .none) {1460 if (tag_type_ref != .none) {
1429 try self.writeInstRef(stream, tag_type_ref);
1430 try stream.writeAll(", ");1461 try stream.writeAll(", ");
1462 try self.writeInstRef(stream, tag_type_ref);
1463 }
1464
1465 if (fields_len == 0) {
1466 try stream.writeAll("})");
1467 try self.writeSrcNode(stream, src_node);
1468 return;
1431 }1469 }
1470 try stream.writeAll(", ");
14321471
1433 const body = self.code.extra[extra_index..][0..body_len];1472 const body = self.code.extra[extra_index..][0..body_len];
1434 extra_index += body.len;1473 extra_index += body.len;
...@@ -1662,6 +1701,10 @@ const Writer = struct {...@@ -1662,6 +1701,10 @@ const Writer = struct {
1662 if (decls_len == 0) {1701 if (decls_len == 0) {
1663 try stream.writeAll("{}, ");1702 try stream.writeAll("{}, ");
1664 } else {1703 } else {
1704 const prev_parent_decl_node = self.parent_decl_node;
1705 if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off);
1706 defer self.parent_decl_node = prev_parent_decl_node;
1707
1665 try stream.writeAll("{\n");1708 try stream.writeAll("{\n");
1666 self.indent += 2;1709 self.indent += 2;
1667 extra_index = try self.writeDecls(stream, decls_len, extra_index);1710 extra_index = try self.writeDecls(stream, decls_len, extra_index);
...@@ -1678,13 +1721,13 @@ const Writer = struct {...@@ -1678,13 +1721,13 @@ const Writer = struct {
1678 const body = self.code.extra[extra_index..][0..body_len];1721 const body = self.code.extra[extra_index..][0..body_len];
1679 extra_index += body.len;1722 extra_index += body.len;
16801723
1724 const prev_parent_decl_node = self.parent_decl_node;
1725 if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off);
1726 try self.writeBracedDecl(stream, body);
1681 if (fields_len == 0) {1727 if (fields_len == 0) {
1682 assert(body.len == 0);1728 try stream.writeAll(", {})");
1683 try stream.writeAll("{}, {})");1729 self.parent_decl_node = prev_parent_decl_node;
1684 } else {1730 } else {
1685 const prev_parent_decl_node = self.parent_decl_node;
1686 if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off);
1687 try self.writeBracedDecl(stream, body);
1688 try stream.writeAll(", {\n");1731 try stream.writeAll(", {\n");
16891732
1690 self.indent += 2;1733 self.indent += 2;
...@@ -1755,6 +1798,10 @@ const Writer = struct {...@@ -1755,6 +1798,10 @@ const Writer = struct {
1755 if (decls_len == 0) {1798 if (decls_len == 0) {
1756 try stream.writeAll("{})");1799 try stream.writeAll("{})");
1757 } else {1800 } else {
1801 const prev_parent_decl_node = self.parent_decl_node;
1802 if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off);
1803 defer self.parent_decl_node = prev_parent_decl_node;
1804
1758 try stream.writeAll("{\n");1805 try stream.writeAll("{\n");
1759 self.indent += 2;1806 self.indent += 2;
1760 _ = try self.writeDecls(stream, decls_len, extra_index);1807 _ = try self.writeDecls(stream, decls_len, extra_index);
src/stage1.zig+2-2
...@@ -18,7 +18,7 @@ const target_util = @import("target.zig");...@@ -18,7 +18,7 @@ const target_util = @import("target.zig");
1818
19comptime {19comptime {
20 assert(builtin.link_libc);20 assert(builtin.link_libc);
21 assert(build_options.is_stage1);21 assert(build_options.have_stage1);
22 assert(build_options.have_llvm);22 assert(build_options.have_llvm);
23 if (!builtin.is_test) {23 if (!builtin.is_test) {
24 @export(main, .{ .name = "main" });24 @export(main, .{ .name = "main" });
...@@ -416,7 +416,7 @@ export fn stage2_add_link_lib(...@@ -416,7 +416,7 @@ export fn stage2_add_link_lib(
416 const target = comp.getTarget();416 const target = comp.getTarget();
417 const is_libc = target_util.is_libc_lib_name(target, lib_name);417 const is_libc = target_util.is_libc_lib_name(target, lib_name);
418 if (is_libc) {418 if (is_libc) {
419 if (!comp.bin_file.options.link_libc) {419 if (!comp.bin_file.options.link_libc and !comp.bin_file.options.parent_compilation_link_libc) {
420 return "dependency on libc must be explicitly specified in the build command";420 return "dependency on libc must be explicitly specified in the build command";
421 }421 }
422 return null;422 return null;
src/stage1/all_types.hpp+1
...@@ -1116,6 +1116,7 @@ struct AstNodeContainerDecl {...@@ -1116,6 +1116,7 @@ struct AstNodeContainerDecl {
1116 ContainerLayout layout;1116 ContainerLayout layout;
11171117
1118 bool auto_enum, is_root; // union(enum)1118 bool auto_enum, is_root; // union(enum)
1119 bool unsupported_explicit_backing_int;
1119};1120};
11201121
1121struct AstNodeErrorSetField {1122struct AstNodeErrorSetField {
src/stage1/analyze.cpp+6
...@@ -3034,6 +3034,12 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {...@@ -3034,6 +3034,12 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
30343034
3035 AstNode *decl_node = struct_type->data.structure.decl_node;3035 AstNode *decl_node = struct_type->data.structure.decl_node;
30363036
3037 if (decl_node->data.container_decl.unsupported_explicit_backing_int) {
3038 add_node_error(g, decl_node, buf_create_from_str(
3039 "the stage1 compiler does not support explicit backing integer types on packed structs"));
3040 return ErrorSemanticAnalyzeFail;
3041 }
3042
3037 if (struct_type->data.structure.resolve_loop_flag_zero_bits) {3043 if (struct_type->data.structure.resolve_loop_flag_zero_bits) {
3038 if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) {3044 if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) {
3039 struct_type->data.structure.resolve_status = ResolveStatusInvalid;3045 struct_type->data.structure.resolve_status = ResolveStatusInvalid;
src/stage1/astgen.cpp+2-4
...@@ -5374,10 +5374,8 @@ static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, Ast...@@ -5374,10 +5374,8 @@ static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, Ast
5374 if (arg0_value == ag->codegen->invalid_inst_src)5374 if (arg0_value == ag->codegen->invalid_inst_src)
5375 return arg0_value;5375 return arg0_value;
53765376
5377 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);5377 Stage1ZirInst *arg1_value = arg0_value;
5378 Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope);5378 arg0_value = ir_build_typeof_1(ag, scope, arg0_node, arg1_value);
5379 if (arg1_value == ag->codegen->invalid_inst_src)
5380 return arg1_value;
53815379
5382 Stage1ZirInst *result;5380 Stage1ZirInst *result;
5383 switch (builtin_fn->id) {5381 switch (builtin_fn->id) {
src/stage1/codegen.cpp+6-6
...@@ -9977,11 +9977,11 @@ static void define_builtin_fns(CodeGen *g) {...@@ -9977,11 +9977,11 @@ static void define_builtin_fns(CodeGen *g) {
9977 create_builtin_fn(g, BuiltinFnIdCInclude, "cInclude", 1);9977 create_builtin_fn(g, BuiltinFnIdCInclude, "cInclude", 1);
9978 create_builtin_fn(g, BuiltinFnIdCDefine, "cDefine", 2);9978 create_builtin_fn(g, BuiltinFnIdCDefine, "cDefine", 2);
9979 create_builtin_fn(g, BuiltinFnIdCUndef, "cUndef", 1);9979 create_builtin_fn(g, BuiltinFnIdCUndef, "cUndef", 1);
9980 create_builtin_fn(g, BuiltinFnIdCtz, "ctz", 2);9980 create_builtin_fn(g, BuiltinFnIdCtz, "ctz", 1);
9981 create_builtin_fn(g, BuiltinFnIdClz, "clz", 2);9981 create_builtin_fn(g, BuiltinFnIdClz, "clz", 1);
9982 create_builtin_fn(g, BuiltinFnIdPopCount, "popCount", 2);9982 create_builtin_fn(g, BuiltinFnIdPopCount, "popCount", 1);
9983 create_builtin_fn(g, BuiltinFnIdBswap, "byteSwap", 2);9983 create_builtin_fn(g, BuiltinFnIdBswap, "byteSwap", 1);
9984 create_builtin_fn(g, BuiltinFnIdBitReverse, "bitReverse", 2);9984 create_builtin_fn(g, BuiltinFnIdBitReverse, "bitReverse", 1);
9985 create_builtin_fn(g, BuiltinFnIdImport, "import", 1);9985 create_builtin_fn(g, BuiltinFnIdImport, "import", 1);
9986 create_builtin_fn(g, BuiltinFnIdCImport, "cImport", 1);9986 create_builtin_fn(g, BuiltinFnIdCImport, "cImport", 1);
9987 create_builtin_fn(g, BuiltinFnIdErrName, "errorName", 1);9987 create_builtin_fn(g, BuiltinFnIdErrName, "errorName", 1);
...@@ -10261,13 +10261,13 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {...@@ -10261,13 +10261,13 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
10261 buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded));10261 buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded));
10262 buf_appendf(contents, "pub const abi = std.Target.Abi.%s;\n", cur_abi);10262 buf_appendf(contents, "pub const abi = std.Target.Abi.%s;\n", cur_abi);
10263 buf_appendf(contents, "pub const cpu = std.Target.Cpu.baseline(.%s);\n", cur_arch);10263 buf_appendf(contents, "pub const cpu = std.Target.Cpu.baseline(.%s);\n", cur_arch);
10264 buf_appendf(contents, "pub const stage2_arch: std.Target.Cpu.Arch = .%s;\n", cur_arch);
10265 buf_appendf(contents, "pub const os = std.Target.Os.Tag.defaultVersionRange(.%s, .%s);\n", cur_os, cur_arch);10264 buf_appendf(contents, "pub const os = std.Target.Os.Tag.defaultVersionRange(.%s, .%s);\n", cur_os, cur_arch);
10266 buf_appendf(contents,10265 buf_appendf(contents,
10267 "pub const target = std.Target{\n"10266 "pub const target = std.Target{\n"
10268 " .cpu = cpu,\n"10267 " .cpu = cpu,\n"
10269 " .os = os,\n"10268 " .os = os,\n"
10270 " .abi = abi,\n"10269 " .abi = abi,\n"
10270 " .ofmt = object_format,\n"
10271 "};\n"10271 "};\n"
10272 );10272 );
1027310273
src/stage1/ir.cpp+28-12
...@@ -18640,7 +18640,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *sour...@@ -18640,7 +18640,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *sour
18640 result->special = ConstValSpecialStatic;18640 result->special = ConstValSpecialStatic;
18641 result->type = ir_type_info_get_type(ira, "Struct", nullptr);18641 result->type = ir_type_info_get_type(ira, "Struct", nullptr);
1864218642
18643 ZigValue **fields = alloc_const_vals_ptrs(g, 4);18643 ZigValue **fields = alloc_const_vals_ptrs(g, 5);
18644 result->data.x_struct.fields = fields;18644 result->data.x_struct.fields = fields;
1864518645
18646 // layout: ContainerLayout18646 // layout: ContainerLayout
...@@ -18648,8 +18648,17 @@ static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *sour...@@ -18648,8 +18648,17 @@ static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *sour
18648 fields[0]->special = ConstValSpecialStatic;18648 fields[0]->special = ConstValSpecialStatic;
18649 fields[0]->type = ir_type_info_get_type(ira, "ContainerLayout", nullptr);18649 fields[0]->type = ir_type_info_get_type(ira, "ContainerLayout", nullptr);
18650 bigint_init_unsigned(&fields[0]->data.x_enum_tag, type_entry->data.structure.layout);18650 bigint_init_unsigned(&fields[0]->data.x_enum_tag, type_entry->data.structure.layout);
18651
18652 // backing_integer: ?type
18653 ensure_field_index(result->type, "backing_integer", 1);
18654 fields[1]->special = ConstValSpecialStatic;
18655 fields[1]->type = get_optional_type(g, g->builtin_types.entry_type);
18656 // This is always null in stage1, as stage1 does not support explicit backing integers
18657 // for packed structs.
18658 fields[1]->data.x_optional = nullptr;
18659
18651 // fields: []Type.StructField18660 // fields: []Type.StructField
18652 ensure_field_index(result->type, "fields", 1);18661 ensure_field_index(result->type, "fields", 2);
1865318662
18654 ZigType *type_info_struct_field_type = ir_type_info_get_type(ira, "StructField", nullptr);18663 ZigType *type_info_struct_field_type = ir_type_info_get_type(ira, "StructField", nullptr);
18655 if ((err = type_resolve(g, type_info_struct_field_type, ResolveStatusSizeKnown))) {18664 if ((err = type_resolve(g, type_info_struct_field_type, ResolveStatusSizeKnown))) {
...@@ -18663,7 +18672,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *sour...@@ -18663,7 +18672,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *sour
18663 struct_field_array->data.x_array.special = ConstArraySpecialNone;18672 struct_field_array->data.x_array.special = ConstArraySpecialNone;
18664 struct_field_array->data.x_array.data.s_none.elements = g->pass1_arena->allocate<ZigValue>(struct_field_count);18673 struct_field_array->data.x_array.data.s_none.elements = g->pass1_arena->allocate<ZigValue>(struct_field_count);
1866518674
18666 init_const_slice(g, fields[1], struct_field_array, 0, struct_field_count, false, nullptr);18675 init_const_slice(g, fields[2], struct_field_array, 0, struct_field_count, false, nullptr);
1866718676
18668 for (uint32_t struct_field_index = 0; struct_field_index < struct_field_count; struct_field_index++) {18677 for (uint32_t struct_field_index = 0; struct_field_index < struct_field_count; struct_field_index++) {
18669 TypeStructField *struct_field = type_entry->data.structure.fields[struct_field_index];18678 TypeStructField *struct_field = type_entry->data.structure.fields[struct_field_index];
...@@ -18710,18 +18719,18 @@ static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *sour...@@ -18710,18 +18719,18 @@ static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *sour
18710 struct_field_val->parent.data.p_array.elem_index = struct_field_index;18719 struct_field_val->parent.data.p_array.elem_index = struct_field_index;
18711 }18720 }
18712 // decls: []Type.Declaration18721 // decls: []Type.Declaration
18713 ensure_field_index(result->type, "decls", 2);18722 ensure_field_index(result->type, "decls", 3);
18714 if ((err = ir_make_type_info_decls(ira, source_node, fields[2],18723 if ((err = ir_make_type_info_decls(ira, source_node, fields[3],
18715 type_entry->data.structure.decls_scope, false)))18724 type_entry->data.structure.decls_scope, false)))
18716 {18725 {
18717 return err;18726 return err;
18718 }18727 }
1871918728
18720 // is_tuple: bool18729 // is_tuple: bool
18721 ensure_field_index(result->type, "is_tuple", 3);18730 ensure_field_index(result->type, "is_tuple", 4);
18722 fields[3]->special = ConstValSpecialStatic;18731 fields[4]->special = ConstValSpecialStatic;
18723 fields[3]->type = g->builtin_types.entry_bool;18732 fields[4]->type = g->builtin_types.entry_bool;
18724 fields[3]->data.x_bool = is_tuple(type_entry);18733 fields[4]->data.x_bool = is_tuple(type_entry);
1872518734
18726 break;18735 break;
18727 }18736 }
...@@ -19313,7 +19322,14 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_...@@ -19313,7 +19322,14 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_
19313 assert(layout_value->type == ir_type_info_get_type(ira, "ContainerLayout", nullptr));19322 assert(layout_value->type == ir_type_info_get_type(ira, "ContainerLayout", nullptr));
19314 ContainerLayout layout = (ContainerLayout)bigint_as_u32(&layout_value->data.x_enum_tag);19323 ContainerLayout layout = (ContainerLayout)bigint_as_u32(&layout_value->data.x_enum_tag);
1931519324
19316 ZigValue *fields_value = get_const_field(ira, source_node, payload, "fields", 1);19325 ZigType *tag_type = get_const_field_meta_type_optional(ira, source_node, payload, "backing_integer", 1);
19326 if (tag_type != nullptr) {
19327 ir_add_error_node(ira, source_node, buf_create_from_str(
19328 "the stage1 compiler does not support explicit backing integer types on packed structs"));
19329 return ira->codegen->invalid_inst_gen->value->type;
19330 }
19331
19332 ZigValue *fields_value = get_const_field(ira, source_node, payload, "fields", 2);
19317 if (fields_value == nullptr)19333 if (fields_value == nullptr)
19318 return ira->codegen->invalid_inst_gen->value->type;19334 return ira->codegen->invalid_inst_gen->value->type;
19319 assert(fields_value->special == ConstValSpecialStatic);19335 assert(fields_value->special == ConstValSpecialStatic);
...@@ -19322,7 +19338,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_...@@ -19322,7 +19338,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_
19322 ZigValue *fields_len_value = fields_value->data.x_struct.fields[slice_len_index];19338 ZigValue *fields_len_value = fields_value->data.x_struct.fields[slice_len_index];
19323 size_t fields_len = bigint_as_usize(&fields_len_value->data.x_bigint);19339 size_t fields_len = bigint_as_usize(&fields_len_value->data.x_bigint);
1932419340
19325 ZigValue *decls_value = get_const_field(ira, source_node, payload, "decls", 2);19341 ZigValue *decls_value = get_const_field(ira, source_node, payload, "decls", 3);
19326 if (decls_value == nullptr)19342 if (decls_value == nullptr)
19327 return ira->codegen->invalid_inst_gen->value->type;19343 return ira->codegen->invalid_inst_gen->value->type;
19328 assert(decls_value->special == ConstValSpecialStatic);19344 assert(decls_value->special == ConstValSpecialStatic);
...@@ -19335,7 +19351,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_...@@ -19335,7 +19351,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_
19335 }19351 }
1933619352
19337 bool is_tuple;19353 bool is_tuple;
19338 if ((err = get_const_field_bool(ira, source_node, payload, "is_tuple", 3, &is_tuple)))19354 if ((err = get_const_field_bool(ira, source_node, payload, "is_tuple", 4, &is_tuple)))
19339 return ira->codegen->invalid_inst_gen->value->type;19355 return ira->codegen->invalid_inst_gen->value->type;
1934019356
19341 ZigType *entry = new_type_table_entry(ZigTypeIdStruct);19357 ZigType *entry = new_type_table_entry(ZigTypeIdStruct);
src/stage1/parser.cpp+10-1
...@@ -2902,16 +2902,25 @@ static AstNode *ast_parse_container_decl_auto(ParseContext *pc) {...@@ -2902,16 +2902,25 @@ static AstNode *ast_parse_container_decl_auto(ParseContext *pc) {
2902}2902}
29032903
2904// ContainerDeclType2904// ContainerDeclType
2905// <- KEYWORD_struct2905// <- KEYWORD_struct (LPAREN Expr RPAREN)?
2906// / KEYWORD_enum (LPAREN Expr RPAREN)?2906// / KEYWORD_enum (LPAREN Expr RPAREN)?
2907// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?2907// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?
2908// / KEYWORD_opaque2908// / KEYWORD_opaque
2909static AstNode *ast_parse_container_decl_type(ParseContext *pc) {2909static AstNode *ast_parse_container_decl_type(ParseContext *pc) {
2910 TokenIndex first = eat_token_if(pc, TokenIdKeywordStruct);2910 TokenIndex first = eat_token_if(pc, TokenIdKeywordStruct);
2911 if (first != 0) {2911 if (first != 0) {
2912 bool explicit_backing_int = false;
2913 if (eat_token_if(pc, TokenIdLParen) != 0) {
2914 explicit_backing_int = true;
2915 ast_expect(pc, ast_parse_expr);
2916 expect_token(pc, TokenIdRParen);
2917 }
2912 AstNode *res = ast_create_node(pc, NodeTypeContainerDecl, first);2918 AstNode *res = ast_create_node(pc, NodeTypeContainerDecl, first);
2913 res->data.container_decl.init_arg_expr = nullptr;2919 res->data.container_decl.init_arg_expr = nullptr;
2914 res->data.container_decl.kind = ContainerKindStruct;2920 res->data.container_decl.kind = ContainerKindStruct;
2921 // We want this to be an error in semantic analysis not parsing to make sharing
2922 // the test suite between stage1 and self hosted easier.
2923 res->data.container_decl.unsupported_explicit_backing_int = explicit_backing_int;
2915 return res;2924 return res;
2916 }2925 }
29172926
src/target.zig+9
...@@ -321,6 +321,15 @@ pub fn supportsStackProbing(target: std.Target) bool {...@@ -321,6 +321,15 @@ pub fn supportsStackProbing(target: std.Target) bool {
321 (target.cpu.arch == .i386 or target.cpu.arch == .x86_64);321 (target.cpu.arch == .i386 or target.cpu.arch == .x86_64);
322}322}
323323
324pub fn supportsStackProtector(target: std.Target) bool {
325 // TODO: investigate whether stack-protector works on wasm
326 return !target.isWasm();
327}
328
329pub fn libcProvidesStackProtector(target: std.Target) bool {
330 return !target.isMinGW() and target.os.tag != .wasi;
331}
332
324pub fn supportsReturnAddress(target: std.Target) bool {333pub fn supportsReturnAddress(target: std.Target) bool {
325 return switch (target.cpu.arch) {334 return switch (target.cpu.arch) {
326 .wasm32, .wasm64 => target.os.tag == .emscripten,335 .wasm32, .wasm64 => target.os.tag == .emscripten,
src/test.zig+16-49
...@@ -25,7 +25,7 @@ const skip_stage1 = builtin.zig_backend != .stage1 or build_options.skip_stage1;...@@ -25,7 +25,7 @@ const skip_stage1 = builtin.zig_backend != .stage1 or build_options.skip_stage1;
25const hr = "=" ** 80;25const hr = "=" ** 80;
2626
27test {27test {
28 if (build_options.is_stage1) {28 if (build_options.have_stage1) {
29 @import("stage1.zig").os_init();29 @import("stage1.zig").os_init();
30 }30 }
3131
...@@ -606,7 +606,6 @@ pub const TestContext = struct {...@@ -606,7 +606,6 @@ pub const TestContext = struct {
606 output_mode: std.builtin.OutputMode,606 output_mode: std.builtin.OutputMode,
607 optimize_mode: std.builtin.Mode = .Debug,607 optimize_mode: std.builtin.Mode = .Debug,
608 updates: std.ArrayList(Update),608 updates: std.ArrayList(Update),
609 object_format: ?std.Target.ObjectFormat = null,
610 emit_h: bool = false,609 emit_h: bool = false,
611 is_test: bool = false,610 is_test: bool = false,
612 expect_exact: bool = false,611 expect_exact: bool = false,
...@@ -782,12 +781,13 @@ pub const TestContext = struct {...@@ -782,12 +781,13 @@ pub const TestContext = struct {
782 pub fn exeFromCompiledC(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case {781 pub fn exeFromCompiledC(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case {
783 const prefixed_name = std.fmt.allocPrint(ctx.arena, "CBE: {s}", .{name}) catch782 const prefixed_name = std.fmt.allocPrint(ctx.arena, "CBE: {s}", .{name}) catch
784 @panic("out of memory");783 @panic("out of memory");
784 var target_adjusted = target;
785 target_adjusted.ofmt = std.Target.ObjectFormat.c;
785 ctx.cases.append(Case{786 ctx.cases.append(Case{
786 .name = prefixed_name,787 .name = prefixed_name,
787 .target = target,788 .target = target_adjusted,
788 .updates = std.ArrayList(Update).init(ctx.cases.allocator),789 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
789 .output_mode = .Exe,790 .output_mode = .Exe,
790 .object_format = .c,
791 .files = std.ArrayList(File).init(ctx.arena),791 .files = std.ArrayList(File).init(ctx.arena),
792 }) catch @panic("out of memory");792 }) catch @panic("out of memory");
793 return &ctx.cases.items[ctx.cases.items.len - 1];793 return &ctx.cases.items[ctx.cases.items.len - 1];
...@@ -851,12 +851,13 @@ pub const TestContext = struct {...@@ -851,12 +851,13 @@ pub const TestContext = struct {
851851
852 /// Adds a test case for Zig or ZIR input, producing C code.852 /// Adds a test case for Zig or ZIR input, producing C code.
853 pub fn addC(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case {853 pub fn addC(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case {
854 var target_adjusted = target;
855 target_adjusted.ofmt = std.Target.ObjectFormat.c;
854 ctx.cases.append(Case{856 ctx.cases.append(Case{
855 .name = name,857 .name = name,
856 .target = target,858 .target = target_adjusted,
857 .updates = std.ArrayList(Update).init(ctx.cases.allocator),859 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
858 .output_mode = .Obj,860 .output_mode = .Obj,
859 .object_format = .c,
860 .files = std.ArrayList(File).init(ctx.arena),861 .files = std.ArrayList(File).init(ctx.arena),
861 }) catch @panic("out of memory");862 }) catch @panic("out of memory");
862 return &ctx.cases.items[ctx.cases.items.len - 1];863 return &ctx.cases.items[ctx.cases.items.len - 1];
...@@ -1224,10 +1225,6 @@ pub const TestContext = struct {...@@ -1224,10 +1225,6 @@ pub const TestContext = struct {
1224 try aux_thread_pool.init(self.gpa);1225 try aux_thread_pool.init(self.gpa);
1225 defer aux_thread_pool.deinit();1226 defer aux_thread_pool.deinit();
12261227
1227 var case_thread_pool: ThreadPool = undefined;
1228 try case_thread_pool.init(self.gpa);
1229 defer case_thread_pool.deinit();
1230
1231 // Use the same global cache dir for all the tests, such that we for example don't have to1228 // Use the same global cache dir for all the tests, such that we for example don't have to
1232 // rebuild musl libc for every case (when LLVM backend is enabled).1229 // rebuild musl libc for every case (when LLVM backend is enabled).
1233 var global_tmp = std.testing.tmpDir(.{});1230 var global_tmp = std.testing.tmpDir(.{});
...@@ -1245,9 +1242,6 @@ pub const TestContext = struct {...@@ -1245,9 +1242,6 @@ pub const TestContext = struct {
1245 defer self.gpa.free(global_cache_directory.path.?);1242 defer self.gpa.free(global_cache_directory.path.?);
12461243
1247 {1244 {
1248 var wait_group: WaitGroup = .{};
1249 defer wait_group.wait();
1250
1251 for (self.cases.items) |*case| {1245 for (self.cases.items) |*case| {
1252 if (build_options.skip_non_native) {1246 if (build_options.skip_non_native) {
1253 if (case.target.getCpuArch() != builtin.cpu.arch)1247 if (case.target.getCpuArch() != builtin.cpu.arch)
...@@ -1267,17 +1261,19 @@ pub const TestContext = struct {...@@ -1267,17 +1261,19 @@ pub const TestContext = struct {
1267 if (std.mem.indexOf(u8, case.name, test_filter) == null) continue;1261 if (std.mem.indexOf(u8, case.name, test_filter) == null) continue;
1268 }1262 }
12691263
1270 wait_group.start();1264 var prg_node = root_node.start(case.name, case.updates.items.len);
1271 try case_thread_pool.spawn(workerRunOneCase, .{1265 prg_node.activate();
1266 defer prg_node.end();
1267
1268 case.result = runOneCase(
1272 self.gpa,1269 self.gpa,
1273 root_node,1270 &prg_node,
1274 case,1271 case.*,
1275 zig_lib_directory,1272 zig_lib_directory,
1276 &aux_thread_pool,1273 &aux_thread_pool,
1277 global_cache_directory,1274 global_cache_directory,
1278 host,1275 host,
1279 &wait_group,1276 );
1280 });
1281 }1277 }
1282 }1278 }
12831279
...@@ -1295,33 +1291,6 @@ pub const TestContext = struct {...@@ -1295,33 +1291,6 @@ pub const TestContext = struct {
1295 }1291 }
1296 }1292 }
12971293
1298 fn workerRunOneCase(
1299 gpa: Allocator,
1300 root_node: *std.Progress.Node,
1301 case: *Case,
1302 zig_lib_directory: Compilation.Directory,
1303 thread_pool: *ThreadPool,
1304 global_cache_directory: Compilation.Directory,
1305 host: std.zig.system.NativeTargetInfo,
1306 wait_group: *WaitGroup,
1307 ) void {
1308 defer wait_group.finish();
1309
1310 var prg_node = root_node.start(case.name, case.updates.items.len);
1311 prg_node.activate();
1312 defer prg_node.end();
1313
1314 case.result = runOneCase(
1315 gpa,
1316 &prg_node,
1317 case.*,
1318 zig_lib_directory,
1319 thread_pool,
1320 global_cache_directory,
1321 host,
1322 );
1323 }
1324
1325 fn runOneCase(1294 fn runOneCase(
1326 allocator: Allocator,1295 allocator: Allocator,
1327 root_node: *std.Progress.Node,1296 root_node: *std.Progress.Node,
...@@ -1533,7 +1502,6 @@ pub const TestContext = struct {...@@ -1533,7 +1502,6 @@ pub const TestContext = struct {
1533 .root_name = "test_case",1502 .root_name = "test_case",
1534 .target = target,1503 .target = target,
1535 .output_mode = case.output_mode,1504 .output_mode = case.output_mode,
1536 .object_format = case.object_format,
1537 });1505 });
15381506
1539 const emit_directory: Compilation.Directory = .{1507 const emit_directory: Compilation.Directory = .{
...@@ -1569,7 +1537,6 @@ pub const TestContext = struct {...@@ -1569,7 +1537,6 @@ pub const TestContext = struct {
1569 .emit_h = emit_h,1537 .emit_h = emit_h,
1570 .main_pkg = &main_pkg,1538 .main_pkg = &main_pkg,
1571 .keep_source_files_loaded = true,1539 .keep_source_files_loaded = true,
1572 .object_format = case.object_format,
1573 .is_native_os = case.target.isNativeOs(),1540 .is_native_os = case.target.isNativeOs(),
1574 .is_native_abi = case.target.isNativeAbi(),1541 .is_native_abi = case.target.isNativeAbi(),
1575 .dynamic_linker = target_info.dynamic_linker.get(),1542 .dynamic_linker = target_info.dynamic_linker.get(),
...@@ -1814,7 +1781,7 @@ pub const TestContext = struct {...@@ -1814,7 +1781,7 @@ pub const TestContext = struct {
1814 ".." ++ ss ++ "{s}" ++ ss ++ "{s}",1781 ".." ++ ss ++ "{s}" ++ ss ++ "{s}",
1815 .{ &tmp.sub_path, bin_name },1782 .{ &tmp.sub_path, bin_name },
1816 );1783 );
1817 if (case.object_format != null and case.object_format.? == .c) {1784 if (case.target.ofmt != null and case.target.ofmt.? == .c) {
1818 if (host.getExternalExecutor(target_info, .{ .link_libc = true }) != .native) {1785 if (host.getExternalExecutor(target_info, .{ .link_libc = true }) != .native) {
1819 // We wouldn't be able to run the compiled C code.1786 // We wouldn't be able to run the compiled C code.
1820 continue :update; // Pass test.1787 continue :update; // Pass test.
src/translate_c.zig+39-12
...@@ -439,6 +439,24 @@ pub fn translate(...@@ -439,6 +439,24 @@ pub fn translate(
439 return ast.render(gpa, context.global_scope.nodes.items);439 return ast.render(gpa, context.global_scope.nodes.items);
440}440}
441441
442/// Determines whether macro is of the form: `#define FOO FOO` (Possibly with trailing tokens)
443/// Macros of this form will not be translated.
444fn isSelfDefinedMacro(unit: *const clang.ASTUnit, c: *const Context, macro: *const clang.MacroDefinitionRecord) bool {
445 const source = getMacroText(unit, c, macro);
446 var tokenizer = std.c.Tokenizer{
447 .buffer = source,
448 };
449 const name_tok = tokenizer.next();
450 const name = source[name_tok.start..name_tok.end];
451
452 const first_tok = tokenizer.next();
453 // We do not just check for `.Identifier` below because keyword tokens are preferentially matched first by
454 // the tokenizer.
455 // In other words we would miss `#define inline inline` (`inline` is a valid c89 identifier)
456 if (first_tok.id == .Eof) return false;
457 return mem.eql(u8, name, source[first_tok.start..first_tok.end]);
458}
459
442fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void {460fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void {
443 if (!ast_unit.visitLocalTopLevelDecls(c, declVisitorNamesOnlyC)) {461 if (!ast_unit.visitLocalTopLevelDecls(c, declVisitorNamesOnlyC)) {
444 return error.OutOfMemory;462 return error.OutOfMemory;
...@@ -455,7 +473,10 @@ fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void {...@@ -455,7 +473,10 @@ fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void {
455 const macro = @ptrCast(*clang.MacroDefinitionRecord, entity);473 const macro = @ptrCast(*clang.MacroDefinitionRecord, entity);
456 const raw_name = macro.getName_getNameStart();474 const raw_name = macro.getName_getNameStart();
457 const name = try c.str(raw_name);475 const name = try c.str(raw_name);
458 try c.global_names.put(c.gpa, name, {});476
477 if (!isSelfDefinedMacro(ast_unit, c, macro)) {
478 try c.global_names.put(c.gpa, name, {});
479 }
459 },480 },
460 else => {},481 else => {},
461 }482 }
...@@ -4001,8 +4022,7 @@ fn transCPtrCast(...@@ -4001,8 +4022,7 @@ fn transCPtrCast(
4001 // For opaque types a ptrCast is enough4022 // For opaque types a ptrCast is enough
4002 expr4023 expr
4003 else blk: {4024 else blk: {
4004 const child_type_node = try transQualType(c, scope, child_type, loc);4025 const alignof = try Tag.std_meta_alignment.create(c.arena, dst_type_node);
4005 const alignof = try Tag.std_meta_alignment.create(c.arena, child_type_node);
4006 const align_cast = try Tag.align_cast.create(c.arena, .{ .lhs = alignof, .rhs = expr });4026 const align_cast = try Tag.align_cast.create(c.arena, .{ .lhs = alignof, .rhs = expr });
4007 break :blk align_cast;4027 break :blk align_cast;
4008 };4028 };
...@@ -5447,6 +5467,16 @@ fn tokenizeMacro(source: []const u8, tok_list: *std.ArrayList(CToken)) Error!voi...@@ -5447,6 +5467,16 @@ fn tokenizeMacro(source: []const u8, tok_list: *std.ArrayList(CToken)) Error!voi
5447 }5467 }
5448}5468}
54495469
5470fn getMacroText(unit: *const clang.ASTUnit, c: *const Context, macro: *const clang.MacroDefinitionRecord) []const u8 {
5471 const begin_loc = macro.getSourceRange_getBegin();
5472 const end_loc = clang.Lexer.getLocForEndOfToken(macro.getSourceRange_getEnd(), c.source_manager, unit);
5473
5474 const begin_c = c.source_manager.getCharacterData(begin_loc);
5475 const end_c = c.source_manager.getCharacterData(end_loc);
5476 const slice_len = @ptrToInt(end_c) - @ptrToInt(begin_c);
5477 return begin_c[0..slice_len];
5478}
5479
5450fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {5480fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
5451 // TODO if we see #undef, delete it from the table5481 // TODO if we see #undef, delete it from the table
5452 var it = unit.getLocalPreprocessingEntities_begin();5482 var it = unit.getLocalPreprocessingEntities_begin();
...@@ -5463,22 +5493,18 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {...@@ -5463,22 +5493,18 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
5463 const macro = @ptrCast(*clang.MacroDefinitionRecord, entity);5493 const macro = @ptrCast(*clang.MacroDefinitionRecord, entity);
5464 const raw_name = macro.getName_getNameStart();5494 const raw_name = macro.getName_getNameStart();
5465 const begin_loc = macro.getSourceRange_getBegin();5495 const begin_loc = macro.getSourceRange_getBegin();
5466 const end_loc = clang.Lexer.getLocForEndOfToken(macro.getSourceRange_getEnd(), c.source_manager, unit);
54675496
5468 const name = try c.str(raw_name);5497 const name = try c.str(raw_name);
5469 if (scope.containsNow(name)) {5498 if (scope.containsNow(name)) {
5470 continue;5499 continue;
5471 }5500 }
54725501
5473 const begin_c = c.source_manager.getCharacterData(begin_loc);5502 const source = getMacroText(unit, c, macro);
5474 const end_c = c.source_manager.getCharacterData(end_loc);
5475 const slice_len = @ptrToInt(end_c) - @ptrToInt(begin_c);
5476 const slice = begin_c[0..slice_len];
54775503
5478 try tokenizeMacro(slice, &tok_list);5504 try tokenizeMacro(source, &tok_list);
54795505
5480 var macro_ctx = MacroCtx{5506 var macro_ctx = MacroCtx{
5481 .source = slice,5507 .source = source,
5482 .list = tok_list.items,5508 .list = tok_list.items,
5483 .name = name,5509 .name = name,
5484 .loc = begin_loc,5510 .loc = begin_loc,
...@@ -5491,7 +5517,8 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {...@@ -5491,7 +5517,8 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
5491 // if it equals itself, ignore. for example, from stdio.h:5517 // if it equals itself, ignore. for example, from stdio.h:
5492 // #define stdin stdin5518 // #define stdin stdin
5493 const tok = macro_ctx.list[1];5519 const tok = macro_ctx.list[1];
5494 if (mem.eql(u8, name, slice[tok.start..tok.end])) {5520 if (mem.eql(u8, name, source[tok.start..tok.end])) {
5521 assert(!c.global_names.contains(source[tok.start..tok.end]));
5495 continue;5522 continue;
5496 }5523 }
5497 },5524 },
...@@ -5648,7 +5675,7 @@ fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!Node {...@@ -5648,7 +5675,7 @@ fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!Node {
5648 switch (m.list[m.i].id) {5675 switch (m.list[m.i].id) {
5649 .IntegerLiteral => |suffix| {5676 .IntegerLiteral => |suffix| {
5650 var radix: []const u8 = "decimal";5677 var radix: []const u8 = "decimal";
5651 if (lit_bytes.len > 2 and lit_bytes[0] == '0') {5678 if (lit_bytes.len >= 2 and lit_bytes[0] == '0') {
5652 switch (lit_bytes[1]) {5679 switch (lit_bytes[1]) {
5653 '0'...'7' => {5680 '0'...'7' => {
5654 // Octal5681 // Octal
src/type.zig+180-132
...@@ -2310,6 +2310,8 @@ pub const Type = extern union {...@@ -2310,6 +2310,8 @@ pub const Type = extern union {
2310 /// fields will count towards the ABI size. For example, `struct {T: type, x: i32}`2310 /// fields will count towards the ABI size. For example, `struct {T: type, x: i32}`
2311 /// hasRuntimeBits()=true and abiSize()=42311 /// hasRuntimeBits()=true and abiSize()=4
2312 /// * the type has only one possible value, making its ABI size 0.2312 /// * the type has only one possible value, making its ABI size 0.
2313 /// - an enum with an explicit tag type has the ABI size of the integer tag type,
2314 /// making it one-possible-value only if the integer tag type has 0 bits.
2313 /// When `ignore_comptime_only` is true, then types that are comptime only2315 /// When `ignore_comptime_only` is true, then types that are comptime only
2314 /// may return false positives.2316 /// may return false positives.
2315 pub fn hasRuntimeBitsAdvanced(2317 pub fn hasRuntimeBitsAdvanced(
...@@ -2376,6 +2378,32 @@ pub const Type = extern union {...@@ -2376,6 +2378,32 @@ pub const Type = extern union {
2376 .error_set_merged,2378 .error_set_merged,
2377 => return true,2379 => return true,
23782380
2381 // Pointers to zero-bit types still have a runtime address; however, pointers
2382 // to comptime-only types do not, with the exception of function pointers.
2383 .anyframe_T,
2384 .optional_single_mut_pointer,
2385 .optional_single_const_pointer,
2386 .single_const_pointer,
2387 .single_mut_pointer,
2388 .many_const_pointer,
2389 .many_mut_pointer,
2390 .c_const_pointer,
2391 .c_mut_pointer,
2392 .const_slice,
2393 .mut_slice,
2394 .pointer,
2395 => {
2396 if (ignore_comptime_only) {
2397 return true;
2398 } else if (ty.childType().zigTypeTag() == .Fn) {
2399 return !ty.childType().fnInfo().is_generic;
2400 } else if (sema_kit) |sk| {
2401 return !(try sk.sema.typeRequiresComptime(sk.block, sk.src, ty));
2402 } else {
2403 return !comptimeOnly(ty);
2404 }
2405 },
2406
2379 // These are false because they are comptime-only types.2407 // These are false because they are comptime-only types.
2380 .single_const_pointer_to_comptime_int,2408 .single_const_pointer_to_comptime_int,
2381 .void,2409 .void,
...@@ -2399,30 +2427,6 @@ pub const Type = extern union {...@@ -2399,30 +2427,6 @@ pub const Type = extern union {
2399 .fn_ccc_void_no_args,2427 .fn_ccc_void_no_args,
2400 => return false,2428 => return false,
24012429
2402 // These types have more than one possible value, so the result is the same as
2403 // asking whether they are comptime-only types.
2404 .anyframe_T,
2405 .optional_single_mut_pointer,
2406 .optional_single_const_pointer,
2407 .single_const_pointer,
2408 .single_mut_pointer,
2409 .many_const_pointer,
2410 .many_mut_pointer,
2411 .c_const_pointer,
2412 .c_mut_pointer,
2413 .const_slice,
2414 .mut_slice,
2415 .pointer,
2416 => {
2417 if (ignore_comptime_only) {
2418 return true;
2419 } else if (sema_kit) |sk| {
2420 return !(try sk.sema.typeRequiresComptime(sk.block, sk.src, ty));
2421 } else {
2422 return !comptimeOnly(ty);
2423 }
2424 },
2425
2426 .optional => {2430 .optional => {
2427 var buf: Payload.ElemType = undefined;2431 var buf: Payload.ElemType = undefined;
2428 const child_ty = ty.optionalChild(&buf);2432 const child_ty = ty.optionalChild(&buf);
...@@ -2450,9 +2454,9 @@ pub const Type = extern union {...@@ -2450,9 +2454,9 @@ pub const Type = extern union {
2450 _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty);2454 _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty);
2451 }2455 }
2452 assert(struct_obj.haveFieldTypes());2456 assert(struct_obj.haveFieldTypes());
2453 for (struct_obj.fields.values()) |value| {2457 for (struct_obj.fields.values()) |field| {
2454 if (value.is_comptime) continue;2458 if (field.is_comptime) continue;
2455 if (try value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit))2459 if (try field.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit))
2456 return true;2460 return true;
2457 } else {2461 } else {
2458 return false;2462 return false;
...@@ -2461,7 +2465,7 @@ pub const Type = extern union {...@@ -2461,7 +2465,7 @@ pub const Type = extern union {
24612465
2462 .enum_full => {2466 .enum_full => {
2463 const enum_full = ty.castTag(.enum_full).?.data;2467 const enum_full = ty.castTag(.enum_full).?.data;
2464 return enum_full.fields.count() >= 2;2468 return enum_full.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit);
2465 },2469 },
2466 .enum_simple => {2470 .enum_simple => {
2467 const enum_simple = ty.castTag(.enum_simple).?.data;2471 const enum_simple = ty.castTag(.enum_simple).?.data;
...@@ -2491,6 +2495,7 @@ pub const Type = extern union {...@@ -2491,6 +2495,7 @@ pub const Type = extern union {
2491 if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit)) {2495 if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit)) {
2492 return true;2496 return true;
2493 }2497 }
2498
2494 if (sema_kit) |sk| {2499 if (sema_kit) |sk| {
2495 _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty);2500 _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty);
2496 }2501 }
...@@ -3000,9 +3005,17 @@ pub const Type = extern union {...@@ -3000,9 +3005,17 @@ pub const Type = extern union {
3000 .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) },3005 .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) },
3001 };3006 };
3002 if (struct_obj.layout == .Packed) {3007 if (struct_obj.layout == .Packed) {
3003 var buf: Type.Payload.Bits = undefined;3008 switch (strat) {
3004 const int_ty = struct_obj.packedIntegerType(target, &buf);3009 .sema_kit => |sk| try sk.sema.resolveTypeLayout(sk.block, sk.src, ty),
3005 return AbiAlignmentAdvanced{ .scalar = int_ty.abiAlignment(target) };3010 .lazy => |arena| {
3011 if (!struct_obj.haveLayout()) {
3012 return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) };
3013 }
3014 },
3015 .eager => {},
3016 }
3017 assert(struct_obj.haveLayout());
3018 return AbiAlignmentAdvanced{ .scalar = struct_obj.backing_int_ty.abiAlignment(target) };
3006 }3019 }
30073020
3008 const fields = ty.structFields();3021 const fields = ty.structFields();
...@@ -3021,6 +3034,15 @@ pub const Type = extern union {...@@ -3021,6 +3034,15 @@ pub const Type = extern union {
3021 },3034 },
3022 };3035 };
3023 big_align = @maximum(big_align, field_align);3036 big_align = @maximum(big_align, field_align);
3037
3038 // This logic is duplicated in Module.Struct.Field.alignment.
3039 if (struct_obj.layout == .Extern or target.ofmt == .c) {
3040 if (field.ty.isAbiInt() and field.ty.intInfo(target).bits >= 128) {
3041 // The C ABI requires 128 bit integer fields of structs
3042 // to be 16-bytes aligned.
3043 big_align = @maximum(big_align, 16);
3044 }
3045 }
3024 }3046 }
3025 return AbiAlignmentAdvanced{ .scalar = big_align };3047 return AbiAlignmentAdvanced{ .scalar = big_align };
3026 },3048 },
...@@ -3105,6 +3127,13 @@ pub const Type = extern union {...@@ -3105,6 +3127,13 @@ pub const Type = extern union {
3105 .sema_kit => unreachable, // handled above3127 .sema_kit => unreachable, // handled above
3106 .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) },3128 .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) },
3107 };3129 };
3130 if (union_obj.fields.count() == 0) {
3131 if (have_tag) {
3132 return abiAlignmentAdvanced(union_obj.tag_ty, target, strat);
3133 } else {
3134 return AbiAlignmentAdvanced{ .scalar = @boolToInt(union_obj.layout == .Extern) };
3135 }
3136 }
31083137
3109 var max_align: u32 = 0;3138 var max_align: u32 = 0;
3110 if (have_tag) max_align = union_obj.tag_ty.abiAlignment(target);3139 if (have_tag) max_align = union_obj.tag_ty.abiAlignment(target);
...@@ -3192,17 +3221,16 @@ pub const Type = extern union {...@@ -3192,17 +3221,16 @@ pub const Type = extern union {
3192 .Packed => {3221 .Packed => {
3193 const struct_obj = ty.castTag(.@"struct").?.data;3222 const struct_obj = ty.castTag(.@"struct").?.data;
3194 switch (strat) {3223 switch (strat) {
3195 .sema_kit => |sk| _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty),3224 .sema_kit => |sk| try sk.sema.resolveTypeLayout(sk.block, sk.src, ty),
3196 .lazy => |arena| {3225 .lazy => |arena| {
3197 if (!struct_obj.haveFieldTypes()) {3226 if (!struct_obj.haveLayout()) {
3198 return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) };3227 return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) };
3199 }3228 }
3200 },3229 },
3201 .eager => {},3230 .eager => {},
3202 }3231 }
3203 var buf: Type.Payload.Bits = undefined;3232 assert(struct_obj.haveLayout());
3204 const int_ty = struct_obj.packedIntegerType(target, &buf);3233 return AbiSizeAdvanced{ .scalar = struct_obj.backing_int_ty.abiSize(target) };
3205 return AbiSizeAdvanced{ .scalar = int_ty.abiSize(target) };
3206 },3234 },
3207 else => {3235 else => {
3208 switch (strat) {3236 switch (strat) {
...@@ -3253,8 +3281,8 @@ pub const Type = extern union {...@@ -3253,8 +3281,8 @@ pub const Type = extern union {
32533281
3254 .array_u8 => return AbiSizeAdvanced{ .scalar = ty.castTag(.array_u8).?.data },3282 .array_u8 => return AbiSizeAdvanced{ .scalar = ty.castTag(.array_u8).?.data },
3255 .array_u8_sentinel_0 => return AbiSizeAdvanced{ .scalar = ty.castTag(.array_u8_sentinel_0).?.data + 1 },3283 .array_u8_sentinel_0 => return AbiSizeAdvanced{ .scalar = ty.castTag(.array_u8_sentinel_0).?.data + 1 },
3256 .array, .vector => {3284 .array => {
3257 const payload = ty.cast(Payload.Array).?.data;3285 const payload = ty.castTag(.array).?.data;
3258 switch (try payload.elem_type.abiSizeAdvanced(target, strat)) {3286 switch (try payload.elem_type.abiSizeAdvanced(target, strat)) {
3259 .scalar => |elem_size| return AbiSizeAdvanced{ .scalar = payload.len * elem_size },3287 .scalar => |elem_size| return AbiSizeAdvanced{ .scalar = payload.len * elem_size },
3260 .val => switch (strat) {3288 .val => switch (strat) {
...@@ -3276,6 +3304,28 @@ pub const Type = extern union {...@@ -3276,6 +3304,28 @@ pub const Type = extern union {
3276 }3304 }
3277 },3305 },
32783306
3307 .vector => {
3308 const payload = ty.castTag(.vector).?.data;
3309 const sema_kit = switch (strat) {
3310 .sema_kit => |sk| sk,
3311 .eager => null,
3312 .lazy => |arena| return AbiSizeAdvanced{
3313 .val = try Value.Tag.lazy_size.create(arena, ty),
3314 },
3315 };
3316 const elem_bits = try payload.elem_type.bitSizeAdvanced(target, sema_kit);
3317 const total_bits = elem_bits * payload.len;
3318 const total_bytes = (total_bits + 7) / 8;
3319 const alignment = switch (try ty.abiAlignmentAdvanced(target, strat)) {
3320 .scalar => |x| x,
3321 .val => return AbiSizeAdvanced{
3322 .val = try Value.Tag.lazy_size.create(strat.lazy, ty),
3323 },
3324 };
3325 const result = std.mem.alignForwardGeneric(u64, total_bytes, alignment);
3326 return AbiSizeAdvanced{ .scalar = result };
3327 },
3328
3279 .isize,3329 .isize,
3280 .usize,3330 .usize,
3281 .@"anyframe",3331 .@"anyframe",
...@@ -3319,7 +3369,13 @@ pub const Type = extern union {...@@ -3319,7 +3369,13 @@ pub const Type = extern union {
3319 .f128 => return AbiSizeAdvanced{ .scalar = 16 },3369 .f128 => return AbiSizeAdvanced{ .scalar = 16 },
33203370
3321 .f80 => switch (target.cpu.arch) {3371 .f80 => switch (target.cpu.arch) {
3322 .i386 => return AbiSizeAdvanced{ .scalar = 12 },3372 .i386 => switch (target.os.tag) {
3373 .windows => switch (target.abi) {
3374 .msvc => return AbiSizeAdvanced{ .scalar = 16 },
3375 else => return AbiSizeAdvanced{ .scalar = 12 },
3376 },
3377 else => return AbiSizeAdvanced{ .scalar = 12 },
3378 },
3323 .x86_64 => return AbiSizeAdvanced{ .scalar = 16 },3379 .x86_64 => return AbiSizeAdvanced{ .scalar = 16 },
3324 else => {3380 else => {
3325 var payload: Payload.Bits = .{3381 var payload: Payload.Bits = .{
...@@ -4236,11 +4292,18 @@ pub const Type = extern union {...@@ -4236,11 +4292,18 @@ pub const Type = extern union {
42364292
4237 pub fn unionFieldType(ty: Type, enum_tag: Value, mod: *Module) Type {4293 pub fn unionFieldType(ty: Type, enum_tag: Value, mod: *Module) Type {
4238 const union_obj = ty.cast(Payload.Union).?.data;4294 const union_obj = ty.cast(Payload.Union).?.data;
4239 const index = union_obj.tag_ty.enumTagFieldIndex(enum_tag, mod).?;4295 const index = ty.unionTagFieldIndex(enum_tag, mod).?;
4240 assert(union_obj.haveFieldTypes());4296 assert(union_obj.haveFieldTypes());
4241 return union_obj.fields.values()[index].ty;4297 return union_obj.fields.values()[index].ty;
4242 }4298 }
42434299
4300 pub fn unionTagFieldIndex(ty: Type, enum_tag: Value, mod: *Module) ?usize {
4301 const union_obj = ty.cast(Payload.Union).?.data;
4302 const index = union_obj.tag_ty.enumTagFieldIndex(enum_tag, mod) orelse return null;
4303 const name = union_obj.tag_ty.enumFieldName(index);
4304 return union_obj.fields.getIndex(name);
4305 }
4306
4244 pub fn unionHasAllZeroBitFieldTypes(ty: Type) bool {4307 pub fn unionHasAllZeroBitFieldTypes(ty: Type) bool {
4245 return ty.cast(Payload.Union).?.data.hasAllZeroBitFieldTypes();4308 return ty.cast(Payload.Union).?.data.hasAllZeroBitFieldTypes();
4246 }4309 }
...@@ -4530,6 +4593,12 @@ pub const Type = extern union {...@@ -4530,6 +4593,12 @@ pub const Type = extern union {
45304593
4531 .vector => ty = ty.castTag(.vector).?.data.elem_type,4594 .vector => ty = ty.castTag(.vector).?.data.elem_type,
45324595
4596 .@"struct" => {
4597 const struct_obj = ty.castTag(.@"struct").?.data;
4598 assert(struct_obj.layout == .Packed);
4599 ty = struct_obj.backing_int_ty;
4600 },
4601
4533 else => unreachable,4602 else => unreachable,
4534 };4603 };
4535 }4604 }
...@@ -4910,33 +4979,38 @@ pub const Type = extern union {...@@ -4910,33 +4979,38 @@ pub const Type = extern union {
4910 const s = ty.castTag(.@"struct").?.data;4979 const s = ty.castTag(.@"struct").?.data;
4911 assert(s.haveFieldTypes());4980 assert(s.haveFieldTypes());
4912 for (s.fields.values()) |field| {4981 for (s.fields.values()) |field| {
4913 if (field.ty.onePossibleValue() == null) {4982 if (field.is_comptime) continue;
4914 return null;4983 if (field.ty.onePossibleValue() != null) continue;
4915 }4984 return null;
4916 }4985 }
4917 return Value.initTag(.empty_struct_value);4986 return Value.initTag(.empty_struct_value);
4918 },4987 },
49194988
4920 .tuple, .anon_struct => {4989 .tuple, .anon_struct => {
4921 const tuple = ty.tupleFields();4990 const tuple = ty.tupleFields();
4922 for (tuple.values) |val| {4991 for (tuple.values) |val, i| {
4923 if (val.tag() == .unreachable_value) {4992 const is_comptime = val.tag() != .unreachable_value;
4924 return null; // non-comptime field4993 if (is_comptime) continue;
4925 }4994 if (tuple.types[i].onePossibleValue() != null) continue;
4995 return null;
4926 }4996 }
4927 return Value.initTag(.empty_struct_value);4997 return Value.initTag(.empty_struct_value);
4928 },4998 },
49294999
4930 .enum_numbered => {5000 .enum_numbered => {
4931 const enum_numbered = ty.castTag(.enum_numbered).?.data;5001 const enum_numbered = ty.castTag(.enum_numbered).?.data;
4932 if (enum_numbered.fields.count() == 1) {5002 // An explicit tag type is always provided for enum_numbered.
4933 return enum_numbered.values.keys()[0];5003 if (enum_numbered.tag_ty.hasRuntimeBits()) {
4934 } else {
4935 return null;5004 return null;
4936 }5005 }
5006 assert(enum_numbered.fields.count() == 1);
5007 return enum_numbered.values.keys()[0];
4937 },5008 },
4938 .enum_full => {5009 .enum_full => {
4939 const enum_full = ty.castTag(.enum_full).?.data;5010 const enum_full = ty.castTag(.enum_full).?.data;
5011 if (enum_full.tag_ty.hasRuntimeBits()) {
5012 return null;
5013 }
4940 if (enum_full.fields.count() == 1) {5014 if (enum_full.fields.count() == 1) {
4941 if (enum_full.values.count() == 0) {5015 if (enum_full.values.count() == 0) {
4942 return Value.zero;5016 return Value.zero;
...@@ -5271,7 +5345,8 @@ pub const Type = extern union {...@@ -5271,7 +5345,8 @@ pub const Type = extern union {
5271 .enum_numbered => return ty.castTag(.enum_numbered).?.data.tag_ty,5345 .enum_numbered => return ty.castTag(.enum_numbered).?.data.tag_ty,
5272 .enum_simple => {5346 .enum_simple => {
5273 const enum_simple = ty.castTag(.enum_simple).?.data;5347 const enum_simple = ty.castTag(.enum_simple).?.data;
5274 const bits = std.math.log2_int_ceil(usize, enum_simple.fields.count());5348 const field_count = enum_simple.fields.count();
5349 const bits: u16 = if (field_count == 0) 0 else std.math.log2_int_ceil(usize, field_count);
5275 buffer.* = .{5350 buffer.* = .{
5276 .base = .{ .tag = .int_unsigned },5351 .base = .{ .tag = .int_unsigned },
5277 .data = bits,5352 .data = bits,
...@@ -5492,7 +5567,7 @@ pub const Type = extern union {...@@ -5492,7 +5567,7 @@ pub const Type = extern union {
5492 .@"struct" => {5567 .@"struct" => {
5493 const struct_obj = ty.castTag(.@"struct").?.data;5568 const struct_obj = ty.castTag(.@"struct").?.data;
5494 assert(struct_obj.layout != .Packed);5569 assert(struct_obj.layout != .Packed);
5495 return struct_obj.fields.values()[index].normalAlignment(target);5570 return struct_obj.fields.values()[index].alignment(target, struct_obj.layout);
5496 },5571 },
5497 .@"union", .union_safety_tagged, .union_tagged => {5572 .@"union", .union_safety_tagged, .union_tagged => {
5498 const union_obj = ty.cast(Payload.Union).?.data;5573 const union_obj = ty.cast(Payload.Union).?.data;
...@@ -5591,19 +5666,22 @@ pub const Type = extern union {...@@ -5591,19 +5666,22 @@ pub const Type = extern union {
5591 target: Target,5666 target: Target,
55925667
5593 pub fn next(it: *StructOffsetIterator) ?FieldOffset {5668 pub fn next(it: *StructOffsetIterator) ?FieldOffset {
5594 if (it.struct_obj.fields.count() <= it.field)5669 const i = it.field;
5670 if (it.struct_obj.fields.count() <= i)
5595 return null;5671 return null;
55965672
5597 const field = it.struct_obj.fields.values()[it.field];5673 const field = it.struct_obj.fields.values()[i];
5598 defer it.field += 1;5674 it.field += 1;
5599 if (!field.ty.hasRuntimeBits() or field.is_comptime)5675
5600 return FieldOffset{ .field = it.field, .offset = it.offset };5676 if (field.is_comptime or !field.ty.hasRuntimeBits()) {
5677 return FieldOffset{ .field = i, .offset = it.offset };
5678 }
56015679
5602 const field_align = field.normalAlignment(it.target);5680 const field_align = field.alignment(it.target, it.struct_obj.layout);
5603 it.big_align = @maximum(it.big_align, field_align);5681 it.big_align = @maximum(it.big_align, field_align);
5604 it.offset = std.mem.alignForwardGeneric(u64, it.offset, field_align);5682 const field_offset = std.mem.alignForwardGeneric(u64, it.offset, field_align);
5605 defer it.offset += field.ty.abiSize(it.target);5683 it.offset = field_offset + field.ty.abiSize(it.target);
5606 return FieldOffset{ .field = it.field, .offset = it.offset };5684 return FieldOffset{ .field = i, .offset = field_offset };
5607 }5685 }
5608 };5686 };
56095687
...@@ -5771,50 +5849,6 @@ pub const Type = extern union {...@@ -5771,50 +5849,6 @@ pub const Type = extern union {
5771 }5849 }
5772 }5850 }
57735851
5774 pub fn getNodeOffset(ty: Type) i32 {
5775 switch (ty.tag()) {
5776 .enum_full, .enum_nonexhaustive => {
5777 const enum_full = ty.cast(Payload.EnumFull).?.data;
5778 return enum_full.node_offset;
5779 },
5780 .enum_numbered => return ty.castTag(.enum_numbered).?.data.node_offset,
5781 .enum_simple => {
5782 const enum_simple = ty.castTag(.enum_simple).?.data;
5783 return enum_simple.node_offset;
5784 },
5785 .@"struct" => {
5786 const struct_obj = ty.castTag(.@"struct").?.data;
5787 return struct_obj.node_offset;
5788 },
5789 .error_set => {
5790 const error_set = ty.castTag(.error_set).?.data;
5791 return error_set.node_offset;
5792 },
5793 .@"union", .union_safety_tagged, .union_tagged => {
5794 const union_obj = ty.cast(Payload.Union).?.data;
5795 return union_obj.node_offset;
5796 },
5797 .@"opaque" => {
5798 const opaque_obj = ty.cast(Payload.Opaque).?.data;
5799 return opaque_obj.node_offset;
5800 },
5801 .atomic_order,
5802 .atomic_rmw_op,
5803 .calling_convention,
5804 .address_space,
5805 .float_mode,
5806 .reduce_op,
5807 .call_options,
5808 .prefetch_options,
5809 .export_options,
5810 .extern_options,
5811 .type_info,
5812 => unreachable, // These need to be resolved earlier.
5813
5814 else => unreachable,
5815 }
5816 }
5817
5818 /// This enum does not directly correspond to `std.builtin.TypeId` because5852 /// This enum does not directly correspond to `std.builtin.TypeId` because
5819 /// it has extra enum tags in it, as a way of using less memory. For example,5853 /// it has extra enum tags in it, as a way of using less memory. For example,
5820 /// even though Zig recognizes `*align(10) i32` and `*i32` both as Pointer types5854 /// even though Zig recognizes `*align(10) i32` and `*i32` both as Pointer types
...@@ -6345,6 +6379,8 @@ pub const Type = extern union {...@@ -6345,6 +6379,8 @@ pub const Type = extern union {
6345 pub const @"anyopaque" = initTag(.anyopaque);6379 pub const @"anyopaque" = initTag(.anyopaque);
6346 pub const @"null" = initTag(.@"null");6380 pub const @"null" = initTag(.@"null");
63476381
6382 pub const err_int = Type.u16;
6383
6348 pub fn ptr(arena: Allocator, mod: *Module, data: Payload.Pointer.Data) !Type {6384 pub fn ptr(arena: Allocator, mod: *Module, data: Payload.Pointer.Data) !Type {
6349 const target = mod.getTarget();6385 const target = mod.getTarget();
63506386
...@@ -6535,6 +6571,11 @@ pub const CType = enum {...@@ -6535,6 +6571,11 @@ pub const CType = enum {
6535 .long, .ulong => return 32,6571 .long, .ulong => return 32,
6536 .longlong, .ulonglong, .longdouble => return 64,6572 .longlong, .ulonglong, .longdouble => return 64,
6537 },6573 },
6574 .avr => switch (self) {
6575 .short, .ushort, .int, .uint => return 16,
6576 .long, .ulong, .longdouble => return 32,
6577 .longlong, .ulonglong => return 64,
6578 },
6538 else => switch (self) {6579 else => switch (self) {
6539 .short, .ushort => return 16,6580 .short, .ushort => return 16,
6540 .int, .uint => return 32,6581 .int, .uint => return 32,
...@@ -6573,31 +6614,42 @@ pub const CType = enum {...@@ -6573,31 +6614,42 @@ pub const CType = enum {
6573 .emscripten,6614 .emscripten,
6574 .plan9,6615 .plan9,
6575 .solaris,6616 .solaris,
6576 => switch (self) {6617 .haiku,
6577 .short, .ushort => return 16,6618 .ananas,
6578 .int, .uint => return 32,6619 .fuchsia,
6579 .long, .ulong => return target.cpu.arch.ptrBitWidth(),6620 .minix,
6580 .longlong, .ulonglong => return 64,6621 => switch (target.cpu.arch) {
6581 .longdouble => switch (target.cpu.arch) {6622 .avr => switch (self) {
6582 .i386, .x86_64 => return 80,6623 .short, .ushort, .int, .uint => return 16,
6624 .long, .ulong, .longdouble => return 32,
6625 .longlong, .ulonglong => return 64,
6626 },
6627 else => switch (self) {
6628 .short, .ushort => return 16,
6629 .int, .uint => return 32,
6630 .long, .ulong => return target.cpu.arch.ptrBitWidth(),
6631 .longlong, .ulonglong => return 64,
6632 .longdouble => switch (target.cpu.arch) {
6633 .i386, .x86_64 => return 80,
65836634
6584 .riscv64,6635 .riscv64,
6585 .aarch64,6636 .aarch64,
6586 .aarch64_be,6637 .aarch64_be,
6587 .aarch64_32,6638 .aarch64_32,
6588 .s390x,6639 .s390x,
6589 .mips64,6640 .mips64,
6590 .mips64el,6641 .mips64el,
6591 .sparc,6642 .sparc,
6592 .sparc64,6643 .sparc64,
6593 .sparcel,6644 .sparcel,
6594 .powerpc,6645 .powerpc,
6595 .powerpcle,6646 .powerpcle,
6596 .powerpc64,6647 .powerpc64,
6597 .powerpc64le,6648 .powerpc64le,
6598 => return 128,6649 => return 128,
65996650
6600 else => return 64,6651 else => return 64,
6652 },
6601 },6653 },
6602 },6654 },
66036655
...@@ -6617,14 +6669,10 @@ pub const CType = enum {...@@ -6617,14 +6669,10 @@ pub const CType = enum {
6617 },6669 },
6618 },6670 },
66196671
6620 .ananas,
6621 .cloudabi,6672 .cloudabi,
6622 .fuchsia,
6623 .kfreebsd,6673 .kfreebsd,
6624 .lv2,6674 .lv2,
6625 .zos,6675 .zos,
6626 .haiku,
6627 .minix,
6628 .rtems,6676 .rtems,
6629 .nacl,6677 .nacl,
6630 .aix,6678 .aix,
src/value.zig+75-66
...@@ -1194,6 +1194,16 @@ pub const Value = extern union {...@@ -1194,6 +1194,16 @@ pub const Value = extern union {
1194 return switch (self.tag()) {1194 return switch (self.tag()) {
1195 .bool_true, .one => true,1195 .bool_true, .one => true,
1196 .bool_false, .zero => false,1196 .bool_false, .zero => false,
1197 .int_u64 => switch (self.castTag(.int_u64).?.data) {
1198 0 => false,
1199 1 => true,
1200 else => unreachable,
1201 },
1202 .int_i64 => switch (self.castTag(.int_i64).?.data) {
1203 0 => false,
1204 1 => true,
1205 else => unreachable,
1206 },
1197 else => unreachable,1207 else => unreachable,
1198 };1208 };
1199 }1209 }
...@@ -1572,7 +1582,7 @@ pub const Value = extern union {...@@ -1572,7 +1582,7 @@ pub const Value = extern union {
1572 .one, .bool_true => return ty_bits - 1,1582 .one, .bool_true => return ty_bits - 1,
15731583
1574 .int_u64 => {1584 .int_u64 => {
1575 const big = @clz(u64, val.castTag(.int_u64).?.data);1585 const big = @clz(val.castTag(.int_u64).?.data);
1576 return big + ty_bits - 64;1586 return big + ty_bits - 64;
1577 },1587 },
1578 .int_i64 => {1588 .int_i64 => {
...@@ -1589,7 +1599,7 @@ pub const Value = extern union {...@@ -1589,7 +1599,7 @@ pub const Value = extern union {
1589 while (i != 0) {1599 while (i != 0) {
1590 i -= 1;1600 i -= 1;
1591 const limb = bigint.limbs[i];1601 const limb = bigint.limbs[i];
1592 const this_limb_lz = @clz(std.math.big.Limb, limb);1602 const this_limb_lz = @clz(limb);
1593 total_limb_lz += this_limb_lz;1603 total_limb_lz += this_limb_lz;
1594 if (this_limb_lz != bits_per_limb) break;1604 if (this_limb_lz != bits_per_limb) break;
1595 }1605 }
...@@ -1616,7 +1626,7 @@ pub const Value = extern union {...@@ -1616,7 +1626,7 @@ pub const Value = extern union {
1616 .one, .bool_true => return 0,1626 .one, .bool_true => return 0,
16171627
1618 .int_u64 => {1628 .int_u64 => {
1619 const big = @ctz(u64, val.castTag(.int_u64).?.data);1629 const big = @ctz(val.castTag(.int_u64).?.data);
1620 return if (big == 64) ty_bits else big;1630 return if (big == 64) ty_bits else big;
1621 },1631 },
1622 .int_i64 => {1632 .int_i64 => {
...@@ -1628,7 +1638,7 @@ pub const Value = extern union {...@@ -1628,7 +1638,7 @@ pub const Value = extern union {
1628 // Limbs are stored in little-endian order.1638 // Limbs are stored in little-endian order.
1629 var result: u64 = 0;1639 var result: u64 = 0;
1630 for (bigint.limbs) |limb| {1640 for (bigint.limbs) |limb| {
1631 const limb_tz = @ctz(std.math.big.Limb, limb);1641 const limb_tz = @ctz(limb);
1632 result += limb_tz;1642 result += limb_tz;
1633 if (limb_tz != @sizeOf(std.math.big.Limb) * 8) break;1643 if (limb_tz != @sizeOf(std.math.big.Limb) * 8) break;
1634 }1644 }
...@@ -1653,7 +1663,7 @@ pub const Value = extern union {...@@ -1653,7 +1663,7 @@ pub const Value = extern union {
1653 .zero, .bool_false => return 0,1663 .zero, .bool_false => return 0,
1654 .one, .bool_true => return 1,1664 .one, .bool_true => return 1,
16551665
1656 .int_u64 => return @popCount(u64, val.castTag(.int_u64).?.data),1666 .int_u64 => return @popCount(val.castTag(.int_u64).?.data),
16571667
1658 else => {1668 else => {
1659 const info = ty.intInfo(target);1669 const info = ty.intInfo(target);
...@@ -1994,6 +2004,10 @@ pub const Value = extern union {...@@ -1994,6 +2004,10 @@ pub const Value = extern union {
1994 return (try orderAgainstZeroAdvanced(lhs, sema_kit)).compare(op);2004 return (try orderAgainstZeroAdvanced(lhs, sema_kit)).compare(op);
1995 }2005 }
19962006
2007 pub fn eql(a: Value, b: Value, ty: Type, mod: *Module) bool {
2008 return eqlAdvanced(a, ty, b, ty, mod, null) catch unreachable;
2009 }
2010
1997 /// This function is used by hash maps and so treats floating-point NaNs as equal2011 /// This function is used by hash maps and so treats floating-point NaNs as equal
1998 /// to each other, and not equal to other floating-point values.2012 /// to each other, and not equal to other floating-point values.
1999 /// Similarly, it treats `undef` as a distinct value from all other values.2013 /// Similarly, it treats `undef` as a distinct value from all other values.
...@@ -2002,13 +2016,10 @@ pub const Value = extern union {...@@ -2002,13 +2016,10 @@ pub const Value = extern union {
2002 /// for `a`. This function must act *as if* `a` has been coerced to `ty`. This complication2016 /// for `a`. This function must act *as if* `a` has been coerced to `ty`. This complication
2003 /// is required in order to make generic function instantiation efficient - specifically2017 /// is required in order to make generic function instantiation efficient - specifically
2004 /// the insertion into the monomorphized function table.2018 /// the insertion into the monomorphized function table.
2005 pub fn eql(a: Value, b: Value, ty: Type, mod: *Module) bool {
2006 return eqlAdvanced(a, b, ty, mod, null) catch unreachable;
2007 }
2008
2009 /// If `null` is provided for `sema_kit` then it is guaranteed no error will be returned.2019 /// If `null` is provided for `sema_kit` then it is guaranteed no error will be returned.
2010 pub fn eqlAdvanced(2020 pub fn eqlAdvanced(
2011 a: Value,2021 a: Value,
2022 a_ty: Type,
2012 b: Value,2023 b: Value,
2013 ty: Type,2024 ty: Type,
2014 mod: *Module,2025 mod: *Module,
...@@ -2034,33 +2045,34 @@ pub const Value = extern union {...@@ -2034,33 +2045,34 @@ pub const Value = extern union {
2034 const a_payload = a.castTag(.opt_payload).?.data;2045 const a_payload = a.castTag(.opt_payload).?.data;
2035 const b_payload = b.castTag(.opt_payload).?.data;2046 const b_payload = b.castTag(.opt_payload).?.data;
2036 var buffer: Type.Payload.ElemType = undefined;2047 var buffer: Type.Payload.ElemType = undefined;
2037 return eqlAdvanced(a_payload, b_payload, ty.optionalChild(&buffer), mod, sema_kit);2048 const payload_ty = ty.optionalChild(&buffer);
2049 return eqlAdvanced(a_payload, payload_ty, b_payload, payload_ty, mod, sema_kit);
2038 },2050 },
2039 .slice => {2051 .slice => {
2040 const a_payload = a.castTag(.slice).?.data;2052 const a_payload = a.castTag(.slice).?.data;
2041 const b_payload = b.castTag(.slice).?.data;2053 const b_payload = b.castTag(.slice).?.data;
2042 if (!(try eqlAdvanced(a_payload.len, b_payload.len, Type.usize, mod, sema_kit))) {2054 if (!(try eqlAdvanced(a_payload.len, Type.usize, b_payload.len, Type.usize, mod, sema_kit))) {
2043 return false;2055 return false;
2044 }2056 }
20452057
2046 var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined;2058 var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined;
2047 const ptr_ty = ty.slicePtrFieldType(&ptr_buf);2059 const ptr_ty = ty.slicePtrFieldType(&ptr_buf);
20482060
2049 return eqlAdvanced(a_payload.ptr, b_payload.ptr, ptr_ty, mod, sema_kit);2061 return eqlAdvanced(a_payload.ptr, ptr_ty, b_payload.ptr, ptr_ty, mod, sema_kit);
2050 },2062 },
2051 .elem_ptr => {2063 .elem_ptr => {
2052 const a_payload = a.castTag(.elem_ptr).?.data;2064 const a_payload = a.castTag(.elem_ptr).?.data;
2053 const b_payload = b.castTag(.elem_ptr).?.data;2065 const b_payload = b.castTag(.elem_ptr).?.data;
2054 if (a_payload.index != b_payload.index) return false;2066 if (a_payload.index != b_payload.index) return false;
20552067
2056 return eqlAdvanced(a_payload.array_ptr, b_payload.array_ptr, ty, mod, sema_kit);2068 return eqlAdvanced(a_payload.array_ptr, ty, b_payload.array_ptr, ty, mod, sema_kit);
2057 },2069 },
2058 .field_ptr => {2070 .field_ptr => {
2059 const a_payload = a.castTag(.field_ptr).?.data;2071 const a_payload = a.castTag(.field_ptr).?.data;
2060 const b_payload = b.castTag(.field_ptr).?.data;2072 const b_payload = b.castTag(.field_ptr).?.data;
2061 if (a_payload.field_index != b_payload.field_index) return false;2073 if (a_payload.field_index != b_payload.field_index) return false;
20622074
2063 return eqlAdvanced(a_payload.container_ptr, b_payload.container_ptr, ty, mod, sema_kit);2075 return eqlAdvanced(a_payload.container_ptr, ty, b_payload.container_ptr, ty, mod, sema_kit);
2064 },2076 },
2065 .@"error" => {2077 .@"error" => {
2066 const a_name = a.castTag(.@"error").?.data.name;2078 const a_name = a.castTag(.@"error").?.data.name;
...@@ -2070,7 +2082,8 @@ pub const Value = extern union {...@@ -2070,7 +2082,8 @@ pub const Value = extern union {
2070 .eu_payload => {2082 .eu_payload => {
2071 const a_payload = a.castTag(.eu_payload).?.data;2083 const a_payload = a.castTag(.eu_payload).?.data;
2072 const b_payload = b.castTag(.eu_payload).?.data;2084 const b_payload = b.castTag(.eu_payload).?.data;
2073 return eqlAdvanced(a_payload, b_payload, ty.errorUnionPayload(), mod, sema_kit);2085 const payload_ty = ty.errorUnionPayload();
2086 return eqlAdvanced(a_payload, payload_ty, b_payload, payload_ty, mod, sema_kit);
2074 },2087 },
2075 .eu_payload_ptr => @panic("TODO: Implement more pointer eql cases"),2088 .eu_payload_ptr => @panic("TODO: Implement more pointer eql cases"),
2076 .opt_payload_ptr => @panic("TODO: Implement more pointer eql cases"),2089 .opt_payload_ptr => @panic("TODO: Implement more pointer eql cases"),
...@@ -2088,7 +2101,7 @@ pub const Value = extern union {...@@ -2088,7 +2101,7 @@ pub const Value = extern union {
2088 const types = ty.tupleFields().types;2101 const types = ty.tupleFields().types;
2089 assert(types.len == a_field_vals.len);2102 assert(types.len == a_field_vals.len);
2090 for (types) |field_ty, i| {2103 for (types) |field_ty, i| {
2091 if (!(try eqlAdvanced(a_field_vals[i], b_field_vals[i], field_ty, mod, sema_kit))) {2104 if (!(try eqlAdvanced(a_field_vals[i], field_ty, b_field_vals[i], field_ty, mod, sema_kit))) {
2092 return false;2105 return false;
2093 }2106 }
2094 }2107 }
...@@ -2099,7 +2112,7 @@ pub const Value = extern union {...@@ -2099,7 +2112,7 @@ pub const Value = extern union {
2099 const fields = ty.structFields().values();2112 const fields = ty.structFields().values();
2100 assert(fields.len == a_field_vals.len);2113 assert(fields.len == a_field_vals.len);
2101 for (fields) |field, i| {2114 for (fields) |field, i| {
2102 if (!(try eqlAdvanced(a_field_vals[i], b_field_vals[i], field.ty, mod, sema_kit))) {2115 if (!(try eqlAdvanced(a_field_vals[i], field.ty, b_field_vals[i], field.ty, mod, sema_kit))) {
2103 return false;2116 return false;
2104 }2117 }
2105 }2118 }
...@@ -2110,7 +2123,7 @@ pub const Value = extern union {...@@ -2110,7 +2123,7 @@ pub const Value = extern union {
2110 for (a_field_vals) |a_elem, i| {2123 for (a_field_vals) |a_elem, i| {
2111 const b_elem = b_field_vals[i];2124 const b_elem = b_field_vals[i];
21122125
2113 if (!(try eqlAdvanced(a_elem, b_elem, elem_ty, mod, sema_kit))) {2126 if (!(try eqlAdvanced(a_elem, elem_ty, b_elem, elem_ty, mod, sema_kit))) {
2114 return false;2127 return false;
2115 }2128 }
2116 }2129 }
...@@ -2122,7 +2135,7 @@ pub const Value = extern union {...@@ -2122,7 +2135,7 @@ pub const Value = extern union {
2122 switch (ty.containerLayout()) {2135 switch (ty.containerLayout()) {
2123 .Packed, .Extern => {2136 .Packed, .Extern => {
2124 const tag_ty = ty.unionTagTypeHypothetical();2137 const tag_ty = ty.unionTagTypeHypothetical();
2125 if (!(try a_union.tag.eqlAdvanced(b_union.tag, tag_ty, mod, sema_kit))) {2138 if (!(try eqlAdvanced(a_union.tag, tag_ty, b_union.tag, tag_ty, mod, sema_kit))) {
2126 // In this case, we must disregard mismatching tags and compare2139 // In this case, we must disregard mismatching tags and compare
2127 // based on the in-memory bytes of the payloads.2140 // based on the in-memory bytes of the payloads.
2128 @panic("TODO comptime comparison of extern union values with mismatching tags");2141 @panic("TODO comptime comparison of extern union values with mismatching tags");
...@@ -2130,13 +2143,13 @@ pub const Value = extern union {...@@ -2130,13 +2143,13 @@ pub const Value = extern union {
2130 },2143 },
2131 .Auto => {2144 .Auto => {
2132 const tag_ty = ty.unionTagTypeHypothetical();2145 const tag_ty = ty.unionTagTypeHypothetical();
2133 if (!(try a_union.tag.eqlAdvanced(b_union.tag, tag_ty, mod, sema_kit))) {2146 if (!(try eqlAdvanced(a_union.tag, tag_ty, b_union.tag, tag_ty, mod, sema_kit))) {
2134 return false;2147 return false;
2135 }2148 }
2136 },2149 },
2137 }2150 }
2138 const active_field_ty = ty.unionFieldType(a_union.tag, mod);2151 const active_field_ty = ty.unionFieldType(a_union.tag, mod);
2139 return a_union.val.eqlAdvanced(b_union.val, active_field_ty, mod, sema_kit);2152 return eqlAdvanced(a_union.val, active_field_ty, b_union.val, active_field_ty, mod, sema_kit);
2140 },2153 },
2141 else => {},2154 else => {},
2142 } else if (a_tag == .null_value or b_tag == .null_value) {2155 } else if (a_tag == .null_value or b_tag == .null_value) {
...@@ -2170,7 +2183,7 @@ pub const Value = extern union {...@@ -2170,7 +2183,7 @@ pub const Value = extern union {
2170 const b_val = b.enumToInt(ty, &buf_b);2183 const b_val = b.enumToInt(ty, &buf_b);
2171 var buf_ty: Type.Payload.Bits = undefined;2184 var buf_ty: Type.Payload.Bits = undefined;
2172 const int_ty = ty.intTagType(&buf_ty);2185 const int_ty = ty.intTagType(&buf_ty);
2173 return eqlAdvanced(a_val, b_val, int_ty, mod, sema_kit);2186 return eqlAdvanced(a_val, int_ty, b_val, int_ty, mod, sema_kit);
2174 },2187 },
2175 .Array, .Vector => {2188 .Array, .Vector => {
2176 const len = ty.arrayLen();2189 const len = ty.arrayLen();
...@@ -2181,17 +2194,44 @@ pub const Value = extern union {...@@ -2181,17 +2194,44 @@ pub const Value = extern union {
2181 while (i < len) : (i += 1) {2194 while (i < len) : (i += 1) {
2182 const a_elem = elemValueBuffer(a, mod, i, &a_buf);2195 const a_elem = elemValueBuffer(a, mod, i, &a_buf);
2183 const b_elem = elemValueBuffer(b, mod, i, &b_buf);2196 const b_elem = elemValueBuffer(b, mod, i, &b_buf);
2184 if (!(try eqlAdvanced(a_elem, b_elem, elem_ty, mod, sema_kit))) {2197 if (!(try eqlAdvanced(a_elem, elem_ty, b_elem, elem_ty, mod, sema_kit))) {
2185 return false;2198 return false;
2186 }2199 }
2187 }2200 }
2188 return true;2201 return true;
2189 },2202 },
2190 .Struct => {2203 .Struct => {
2191 // A tuple can be represented with .empty_struct_value,2204 // A struct can be represented with one of:
2192 // the_one_possible_value, .aggregate in which case we could2205 // .empty_struct_value,
2193 // end up here and the values are equal if the type has zero fields.2206 // .the_one_possible_value,
2194 return ty.isTupleOrAnonStruct() and ty.structFieldCount() != 0;2207 // .aggregate,
2208 // Note that we already checked above for matching tags, e.g. both .aggregate.
2209 return ty.onePossibleValue() != null;
2210 },
2211 .Union => {
2212 // Here we have to check for value equality, as-if `a` has been coerced to `ty`.
2213 if (ty.onePossibleValue() != null) {
2214 return true;
2215 }
2216 if (a_ty.castTag(.anon_struct)) |payload| {
2217 const tuple = payload.data;
2218 if (tuple.values.len != 1) {
2219 return false;
2220 }
2221 const field_name = tuple.names[0];
2222 const union_obj = ty.cast(Type.Payload.Union).?.data;
2223 const field_index = union_obj.fields.getIndex(field_name) orelse return false;
2224 const tag_and_val = b.castTag(.@"union").?.data;
2225 var field_tag_buf: Value.Payload.U32 = .{
2226 .base = .{ .tag = .enum_field_index },
2227 .data = @intCast(u32, field_index),
2228 };
2229 const field_tag = Value.initPayload(&field_tag_buf.base);
2230 const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, mod);
2231 if (!tag_matches) return false;
2232 return eqlAdvanced(tag_and_val.val, union_obj.tag_ty, tuple.values[0], tuple.types[0], mod, sema_kit);
2233 }
2234 return false;
2195 },2235 },
2196 .Float => {2236 .Float => {
2197 switch (ty.floatBits(target)) {2237 switch (ty.floatBits(target)) {
...@@ -2220,7 +2260,8 @@ pub const Value = extern union {...@@ -2220,7 +2260,8 @@ pub const Value = extern union {
2220 .base = .{ .tag = .opt_payload },2260 .base = .{ .tag = .opt_payload },
2221 .data = a,2261 .data = a,
2222 };2262 };
2223 return eqlAdvanced(Value.initPayload(&buffer.base), b, ty, mod, sema_kit);2263 const opt_val = Value.initPayload(&buffer.base);
2264 return eqlAdvanced(opt_val, ty, b, ty, mod, sema_kit);
2224 }2265 }
2225 },2266 },
2226 else => {},2267 else => {},
...@@ -2648,6 +2689,12 @@ pub const Value = extern union {...@@ -2648,6 +2689,12 @@ pub const Value = extern union {
2648 // to have only one possible value itself.2689 // to have only one possible value itself.
2649 .the_only_possible_value => return val,2690 .the_only_possible_value => return val,
26502691
2692 // pointer to integer casted to pointer of array
2693 .int_u64, .int_i64 => {
2694 assert(index == 0);
2695 return val;
2696 },
2697
2651 else => unreachable,2698 else => unreachable,
2652 }2699 }
2653 }2700 }
...@@ -3472,44 +3519,6 @@ pub const Value = extern union {...@@ -3472,44 +3519,6 @@ pub const Value = extern union {
3472 return fromBigInt(allocator, result_q.toConst());3519 return fromBigInt(allocator, result_q.toConst());
3473 }3520 }
34743521
3475 pub fn intRem(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value {
3476 if (ty.zigTypeTag() == .Vector) {
3477 const result_data = try allocator.alloc(Value, ty.vectorLen());
3478 for (result_data) |*scalar, i| {
3479 scalar.* = try intRemScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator, target);
3480 }
3481 return Value.Tag.aggregate.create(allocator, result_data);
3482 }
3483 return intRemScalar(lhs, rhs, allocator, target);
3484 }
3485
3486 pub fn intRemScalar(lhs: Value, rhs: Value, allocator: Allocator, target: Target) !Value {
3487 // TODO is this a performance issue? maybe we should try the operation without
3488 // resorting to BigInt first.
3489 var lhs_space: Value.BigIntSpace = undefined;
3490 var rhs_space: Value.BigIntSpace = undefined;
3491 const lhs_bigint = lhs.toBigInt(&lhs_space, target);
3492 const rhs_bigint = rhs.toBigInt(&rhs_space, target);
3493 const limbs_q = try allocator.alloc(
3494 std.math.big.Limb,
3495 lhs_bigint.limbs.len,
3496 );
3497 const limbs_r = try allocator.alloc(
3498 std.math.big.Limb,
3499 // TODO: consider reworking Sema to re-use Values rather than
3500 // always producing new Value objects.
3501 rhs_bigint.limbs.len,
3502 );
3503 const limbs_buffer = try allocator.alloc(
3504 std.math.big.Limb,
3505 std.math.big.int.calcDivLimbsBufferLen(lhs_bigint.limbs.len, rhs_bigint.limbs.len),
3506 );
3507 var result_q = BigIntMutable{ .limbs = limbs_q, .positive = undefined, .len = undefined };
3508 var result_r = BigIntMutable{ .limbs = limbs_r, .positive = undefined, .len = undefined };
3509 result_q.divTrunc(&result_r, lhs_bigint, rhs_bigint, limbs_buffer);
3510 return fromBigInt(allocator, result_r.toConst());
3511 }
3512
3513 pub fn intMod(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value {3522 pub fn intMod(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value {
3514 if (ty.zigTypeTag() == .Vector) {3523 if (ty.zigTypeTag() == .Vector) {
3515 const result_data = try allocator.alloc(Value, ty.vectorLen());3524 const result_data = try allocator.alloc(Value, ty.vectorLen());
test/behavior.zig+5-2
...@@ -26,7 +26,6 @@ test {...@@ -26,7 +26,6 @@ test {
26 _ = @import("behavior/bugs/920.zig");26 _ = @import("behavior/bugs/920.zig");
27 _ = @import("behavior/bugs/1025.zig");27 _ = @import("behavior/bugs/1025.zig");
28 _ = @import("behavior/bugs/1076.zig");28 _ = @import("behavior/bugs/1076.zig");
29 _ = @import("behavior/bugs/1111.zig");
30 _ = @import("behavior/bugs/1277.zig");29 _ = @import("behavior/bugs/1277.zig");
31 _ = @import("behavior/bugs/1310.zig");30 _ = @import("behavior/bugs/1310.zig");
32 _ = @import("behavior/bugs/1381.zig");31 _ = @import("behavior/bugs/1381.zig");
...@@ -84,6 +83,8 @@ test {...@@ -84,6 +83,8 @@ test {
84 _ = @import("behavior/bugs/11213.zig");83 _ = @import("behavior/bugs/11213.zig");
85 _ = @import("behavior/bugs/12003.zig");84 _ = @import("behavior/bugs/12003.zig");
86 _ = @import("behavior/bugs/12033.zig");85 _ = @import("behavior/bugs/12033.zig");
86 _ = @import("behavior/bugs/12430.zig");
87 _ = @import("behavior/bugs/12486.zig");
87 _ = @import("behavior/byteswap.zig");88 _ = @import("behavior/byteswap.zig");
88 _ = @import("behavior/byval_arg_var.zig");89 _ = @import("behavior/byval_arg_var.zig");
89 _ = @import("behavior/call.zig");90 _ = @import("behavior/call.zig");
...@@ -159,12 +160,14 @@ test {...@@ -159,12 +160,14 @@ test {
159 _ = @import("behavior/while.zig");160 _ = @import("behavior/while.zig");
160 _ = @import("behavior/widening.zig");161 _ = @import("behavior/widening.zig");
161162
162 if (builtin.stage2_arch == .wasm32) {163 if (builtin.cpu.arch == .wasm32) {
163 _ = @import("behavior/wasm.zig");164 _ = @import("behavior/wasm.zig");
164 }165 }
165166
166 if (builtin.zig_backend != .stage1) {167 if (builtin.zig_backend != .stage1) {
167 _ = @import("behavior/decltest.zig");168 _ = @import("behavior/decltest.zig");
169 _ = @import("behavior/packed_struct_explicit_backing_int.zig");
170 _ = @import("behavior/empty_union.zig");
168 }171 }
169172
170 if (builtin.os.tag != .wasi) {173 if (builtin.os.tag != .wasi) {
test/behavior/align.zig+42-15
...@@ -100,8 +100,8 @@ test "alignment and size of structs with 128-bit fields" {...@@ -100,8 +100,8 @@ test "alignment and size of structs with 128-bit fields" {
100 .a_align = 8,100 .a_align = 8,
101 .a_size = 16,101 .a_size = 16,
102102
103 .b_align = 8,103 .b_align = 16,
104 .b_size = 24,104 .b_size = 32,
105105
106 .u128_align = 8,106 .u128_align = 8,
107 .u128_size = 16,107 .u128_size = 16,
...@@ -114,8 +114,8 @@ test "alignment and size of structs with 128-bit fields" {...@@ -114,8 +114,8 @@ test "alignment and size of structs with 128-bit fields" {
114 .a_align = 8,114 .a_align = 8,
115 .a_size = 16,115 .a_size = 16,
116116
117 .b_align = 8,117 .b_align = 16,
118 .b_size = 24,118 .b_size = 32,
119119
120 .u128_align = 8,120 .u128_align = 8,
121 .u128_size = 16,121 .u128_size = 16,
...@@ -126,8 +126,8 @@ test "alignment and size of structs with 128-bit fields" {...@@ -126,8 +126,8 @@ test "alignment and size of structs with 128-bit fields" {
126 .a_align = 4,126 .a_align = 4,
127 .a_size = 16,127 .a_size = 16,
128128
129 .b_align = 4,129 .b_align = 16,
130 .b_size = 20,130 .b_size = 32,
131131
132 .u128_align = 4,132 .u128_align = 4,
133 .u128_size = 16,133 .u128_size = 16,
...@@ -140,12 +140,39 @@ test "alignment and size of structs with 128-bit fields" {...@@ -140,12 +140,39 @@ test "alignment and size of structs with 128-bit fields" {
140 .mips64el,140 .mips64el,
141 .powerpc64,141 .powerpc64,
142 .powerpc64le,142 .powerpc64le,
143 .riscv64,
144 .sparc64,143 .sparc64,
145 .x86_64,144 .x86_64,
145 => switch (builtin.object_format) {
146 .c => .{
147 .a_align = 16,
148 .a_size = 16,
149
150 .b_align = 16,
151 .b_size = 32,
152
153 .u128_align = 16,
154 .u128_size = 16,
155 .u129_align = 16,
156 .u129_size = 32,
157 },
158 else => .{
159 .a_align = 8,
160 .a_size = 16,
161
162 .b_align = 16,
163 .b_size = 32,
164
165 .u128_align = 8,
166 .u128_size = 16,
167 .u129_align = 8,
168 .u129_size = 24,
169 },
170 },
171
146 .aarch64,172 .aarch64,
147 .aarch64_be,173 .aarch64_be,
148 .aarch64_32,174 .aarch64_32,
175 .riscv64,
149 .bpfel,176 .bpfel,
150 .bpfeb,177 .bpfeb,
151 .nvptx,178 .nvptx,
...@@ -166,17 +193,17 @@ test "alignment and size of structs with 128-bit fields" {...@@ -166,17 +193,17 @@ test "alignment and size of structs with 128-bit fields" {
166 else => return error.SkipZigTest,193 else => return error.SkipZigTest,
167 };194 };
168 comptime {195 comptime {
169 std.debug.assert(@alignOf(A) == expected.a_align);196 assert(@alignOf(A) == expected.a_align);
170 std.debug.assert(@sizeOf(A) == expected.a_size);197 assert(@sizeOf(A) == expected.a_size);
171198
172 std.debug.assert(@alignOf(B) == expected.b_align);199 assert(@alignOf(B) == expected.b_align);
173 std.debug.assert(@sizeOf(B) == expected.b_size);200 assert(@sizeOf(B) == expected.b_size);
174201
175 std.debug.assert(@alignOf(u128) == expected.u128_align);202 assert(@alignOf(u128) == expected.u128_align);
176 std.debug.assert(@sizeOf(u128) == expected.u128_size);203 assert(@sizeOf(u128) == expected.u128_size);
177204
178 std.debug.assert(@alignOf(u129) == expected.u129_align);205 assert(@alignOf(u129) == expected.u129_align);
179 std.debug.assert(@sizeOf(u129) == expected.u129_size);206 assert(@sizeOf(u129) == expected.u129_size);
180 }207 }
181}208}
182209
test/behavior/basic.zig+21
...@@ -1104,3 +1104,24 @@ test "namespace lookup ignores decl causing the lookup" {...@@ -1104,3 +1104,24 @@ test "namespace lookup ignores decl causing the lookup" {
1104 };1104 };
1105 _ = S.foo();1105 _ = S.foo();
1106}1106}
1107
1108test "ambiguous reference error ignores current declaration" {
1109 const S = struct {
1110 const foo = 666;
1111
1112 const a = @This();
1113 const b = struct {
1114 const foo = a.foo;
1115 const bar = struct {
1116 bar: u32 = b.foo,
1117 };
1118
1119 comptime {
1120 _ = b.foo;
1121 }
1122 };
1123
1124 usingnamespace b;
1125 };
1126 try expect(S.b.foo == 666);
1127}
test/behavior/bitreverse.zig+47-47
...@@ -8,7 +8,7 @@ test "@bitReverse large exotic integer" {...@@ -8,7 +8,7 @@ test "@bitReverse large exotic integer" {
8 // Currently failing on stage1 for big-endian targets8 // Currently failing on stage1 for big-endian targets
9 if (builtin.zig_backend == .stage1) return error.SkipZigTest;9 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
1010
11 try expect(@bitReverse(u95, @as(u95, 0x123456789abcdef111213141)) == 0x4146424447bd9eac8f351624);11 try expect(@bitReverse(@as(u95, 0x123456789abcdef111213141)) == 0x4146424447bd9eac8f351624);
12}12}
1313
14test "@bitReverse" {14test "@bitReverse" {
...@@ -23,74 +23,74 @@ test "@bitReverse" {...@@ -23,74 +23,74 @@ test "@bitReverse" {
2323
24fn testBitReverse() !void {24fn testBitReverse() !void {
25 // using comptime_ints, unsigned25 // using comptime_ints, unsigned
26 try expect(@bitReverse(u0, @as(u0, 0)) == 0);26 try expect(@bitReverse(@as(u0, 0)) == 0);
27 try expect(@bitReverse(u5, @as(u5, 0x12)) == 0x9);27 try expect(@bitReverse(@as(u5, 0x12)) == 0x9);
28 try expect(@bitReverse(u8, @as(u8, 0x12)) == 0x48);28 try expect(@bitReverse(@as(u8, 0x12)) == 0x48);
29 try expect(@bitReverse(u16, @as(u16, 0x1234)) == 0x2c48);29 try expect(@bitReverse(@as(u16, 0x1234)) == 0x2c48);
30 try expect(@bitReverse(u24, @as(u24, 0x123456)) == 0x6a2c48);30 try expect(@bitReverse(@as(u24, 0x123456)) == 0x6a2c48);
31 try expect(@bitReverse(u32, @as(u32, 0x12345678)) == 0x1e6a2c48);31 try expect(@bitReverse(@as(u32, 0x12345678)) == 0x1e6a2c48);
32 try expect(@bitReverse(u40, @as(u40, 0x123456789a)) == 0x591e6a2c48);32 try expect(@bitReverse(@as(u40, 0x123456789a)) == 0x591e6a2c48);
33 try expect(@bitReverse(u48, @as(u48, 0x123456789abc)) == 0x3d591e6a2c48);33 try expect(@bitReverse(@as(u48, 0x123456789abc)) == 0x3d591e6a2c48);
34 try expect(@bitReverse(u56, @as(u56, 0x123456789abcde)) == 0x7b3d591e6a2c48);34 try expect(@bitReverse(@as(u56, 0x123456789abcde)) == 0x7b3d591e6a2c48);
35 try expect(@bitReverse(u64, @as(u64, 0x123456789abcdef1)) == 0x8f7b3d591e6a2c48);35 try expect(@bitReverse(@as(u64, 0x123456789abcdef1)) == 0x8f7b3d591e6a2c48);
36 try expect(@bitReverse(u96, @as(u96, 0x123456789abcdef111213141)) == 0x828c84888f7b3d591e6a2c48);36 try expect(@bitReverse(@as(u96, 0x123456789abcdef111213141)) == 0x828c84888f7b3d591e6a2c48);
37 try expect(@bitReverse(u128, @as(u128, 0x123456789abcdef11121314151617181)) == 0x818e868a828c84888f7b3d591e6a2c48);37 try expect(@bitReverse(@as(u128, 0x123456789abcdef11121314151617181)) == 0x818e868a828c84888f7b3d591e6a2c48);
3838
39 // using runtime uints, unsigned39 // using runtime uints, unsigned
40 var num0: u0 = 0;40 var num0: u0 = 0;
41 try expect(@bitReverse(u0, num0) == 0);41 try expect(@bitReverse(num0) == 0);
42 var num5: u5 = 0x12;42 var num5: u5 = 0x12;
43 try expect(@bitReverse(u5, num5) == 0x9);43 try expect(@bitReverse(num5) == 0x9);
44 var num8: u8 = 0x12;44 var num8: u8 = 0x12;
45 try expect(@bitReverse(u8, num8) == 0x48);45 try expect(@bitReverse(num8) == 0x48);
46 var num16: u16 = 0x1234;46 var num16: u16 = 0x1234;
47 try expect(@bitReverse(u16, num16) == 0x2c48);47 try expect(@bitReverse(num16) == 0x2c48);
48 var num24: u24 = 0x123456;48 var num24: u24 = 0x123456;
49 try expect(@bitReverse(u24, num24) == 0x6a2c48);49 try expect(@bitReverse(num24) == 0x6a2c48);
50 var num32: u32 = 0x12345678;50 var num32: u32 = 0x12345678;
51 try expect(@bitReverse(u32, num32) == 0x1e6a2c48);51 try expect(@bitReverse(num32) == 0x1e6a2c48);
52 var num40: u40 = 0x123456789a;52 var num40: u40 = 0x123456789a;
53 try expect(@bitReverse(u40, num40) == 0x591e6a2c48);53 try expect(@bitReverse(num40) == 0x591e6a2c48);
54 var num48: u48 = 0x123456789abc;54 var num48: u48 = 0x123456789abc;
55 try expect(@bitReverse(u48, num48) == 0x3d591e6a2c48);55 try expect(@bitReverse(num48) == 0x3d591e6a2c48);
56 var num56: u56 = 0x123456789abcde;56 var num56: u56 = 0x123456789abcde;
57 try expect(@bitReverse(u56, num56) == 0x7b3d591e6a2c48);57 try expect(@bitReverse(num56) == 0x7b3d591e6a2c48);
58 var num64: u64 = 0x123456789abcdef1;58 var num64: u64 = 0x123456789abcdef1;
59 try expect(@bitReverse(u64, num64) == 0x8f7b3d591e6a2c48);59 try expect(@bitReverse(num64) == 0x8f7b3d591e6a2c48);
60 var num128: u128 = 0x123456789abcdef11121314151617181;60 var num128: u128 = 0x123456789abcdef11121314151617181;
61 try expect(@bitReverse(u128, num128) == 0x818e868a828c84888f7b3d591e6a2c48);61 try expect(@bitReverse(num128) == 0x818e868a828c84888f7b3d591e6a2c48);
6262
63 // using comptime_ints, signed, positive63 // using comptime_ints, signed, positive
64 try expect(@bitReverse(u8, @as(u8, 0)) == 0);64 try expect(@bitReverse(@as(u8, 0)) == 0);
65 try expect(@bitReverse(i8, @bitCast(i8, @as(u8, 0x92))) == @bitCast(i8, @as(u8, 0x49)));65 try expect(@bitReverse(@bitCast(i8, @as(u8, 0x92))) == @bitCast(i8, @as(u8, 0x49)));
66 try expect(@bitReverse(i16, @bitCast(i16, @as(u16, 0x1234))) == @bitCast(i16, @as(u16, 0x2c48)));66 try expect(@bitReverse(@bitCast(i16, @as(u16, 0x1234))) == @bitCast(i16, @as(u16, 0x2c48)));
67 try expect(@bitReverse(i24, @bitCast(i24, @as(u24, 0x123456))) == @bitCast(i24, @as(u24, 0x6a2c48)));67 try expect(@bitReverse(@bitCast(i24, @as(u24, 0x123456))) == @bitCast(i24, @as(u24, 0x6a2c48)));
68 try expect(@bitReverse(i24, @bitCast(i24, @as(u24, 0x12345f))) == @bitCast(i24, @as(u24, 0xfa2c48)));68 try expect(@bitReverse(@bitCast(i24, @as(u24, 0x12345f))) == @bitCast(i24, @as(u24, 0xfa2c48)));
69 try expect(@bitReverse(i24, @bitCast(i24, @as(u24, 0xf23456))) == @bitCast(i24, @as(u24, 0x6a2c4f)));69 try expect(@bitReverse(@bitCast(i24, @as(u24, 0xf23456))) == @bitCast(i24, @as(u24, 0x6a2c4f)));
70 try expect(@bitReverse(i32, @bitCast(i32, @as(u32, 0x12345678))) == @bitCast(i32, @as(u32, 0x1e6a2c48)));70 try expect(@bitReverse(@bitCast(i32, @as(u32, 0x12345678))) == @bitCast(i32, @as(u32, 0x1e6a2c48)));
71 try expect(@bitReverse(i32, @bitCast(i32, @as(u32, 0xf2345678))) == @bitCast(i32, @as(u32, 0x1e6a2c4f)));71 try expect(@bitReverse(@bitCast(i32, @as(u32, 0xf2345678))) == @bitCast(i32, @as(u32, 0x1e6a2c4f)));
72 try expect(@bitReverse(i32, @bitCast(i32, @as(u32, 0x1234567f))) == @bitCast(i32, @as(u32, 0xfe6a2c48)));72 try expect(@bitReverse(@bitCast(i32, @as(u32, 0x1234567f))) == @bitCast(i32, @as(u32, 0xfe6a2c48)));
73 try expect(@bitReverse(i40, @bitCast(i40, @as(u40, 0x123456789a))) == @bitCast(i40, @as(u40, 0x591e6a2c48)));73 try expect(@bitReverse(@bitCast(i40, @as(u40, 0x123456789a))) == @bitCast(i40, @as(u40, 0x591e6a2c48)));
74 try expect(@bitReverse(i48, @bitCast(i48, @as(u48, 0x123456789abc))) == @bitCast(i48, @as(u48, 0x3d591e6a2c48)));74 try expect(@bitReverse(@bitCast(i48, @as(u48, 0x123456789abc))) == @bitCast(i48, @as(u48, 0x3d591e6a2c48)));
75 try expect(@bitReverse(i56, @bitCast(i56, @as(u56, 0x123456789abcde))) == @bitCast(i56, @as(u56, 0x7b3d591e6a2c48)));75 try expect(@bitReverse(@bitCast(i56, @as(u56, 0x123456789abcde))) == @bitCast(i56, @as(u56, 0x7b3d591e6a2c48)));
76 try expect(@bitReverse(i64, @bitCast(i64, @as(u64, 0x123456789abcdef1))) == @bitCast(i64, @as(u64, 0x8f7b3d591e6a2c48)));76 try expect(@bitReverse(@bitCast(i64, @as(u64, 0x123456789abcdef1))) == @bitCast(i64, @as(u64, 0x8f7b3d591e6a2c48)));
77 try expect(@bitReverse(i96, @bitCast(i96, @as(u96, 0x123456789abcdef111213141))) == @bitCast(i96, @as(u96, 0x828c84888f7b3d591e6a2c48)));77 try expect(@bitReverse(@bitCast(i96, @as(u96, 0x123456789abcdef111213141))) == @bitCast(i96, @as(u96, 0x828c84888f7b3d591e6a2c48)));
78 try expect(@bitReverse(i128, @bitCast(i128, @as(u128, 0x123456789abcdef11121314151617181))) == @bitCast(i128, @as(u128, 0x818e868a828c84888f7b3d591e6a2c48)));78 try expect(@bitReverse(@bitCast(i128, @as(u128, 0x123456789abcdef11121314151617181))) == @bitCast(i128, @as(u128, 0x818e868a828c84888f7b3d591e6a2c48)));
7979
80 // using signed, negative. Compare to runtime ints returned from llvm.80 // using signed, negative. Compare to runtime ints returned from llvm.
81 var neg8: i8 = -18;81 var neg8: i8 = -18;
82 try expect(@bitReverse(i8, @as(i8, -18)) == @bitReverse(i8, neg8));82 try expect(@bitReverse(@as(i8, -18)) == @bitReverse(neg8));
83 var neg16: i16 = -32694;83 var neg16: i16 = -32694;
84 try expect(@bitReverse(i16, @as(i16, -32694)) == @bitReverse(i16, neg16));84 try expect(@bitReverse(@as(i16, -32694)) == @bitReverse(neg16));
85 var neg24: i24 = -6773785;85 var neg24: i24 = -6773785;
86 try expect(@bitReverse(i24, @as(i24, -6773785)) == @bitReverse(i24, neg24));86 try expect(@bitReverse(@as(i24, -6773785)) == @bitReverse(neg24));
87 var neg32: i32 = -16773785;87 var neg32: i32 = -16773785;
88 try expect(@bitReverse(i32, @as(i32, -16773785)) == @bitReverse(i32, neg32));88 try expect(@bitReverse(@as(i32, -16773785)) == @bitReverse(neg32));
89}89}
9090
91fn vector8() !void {91fn vector8() !void {
92 var v = @Vector(2, u8){ 0x12, 0x23 };92 var v = @Vector(2, u8){ 0x12, 0x23 };
93 var result = @bitReverse(u8, v);93 var result = @bitReverse(v);
94 try expect(result[0] == 0x48);94 try expect(result[0] == 0x48);
95 try expect(result[1] == 0xc4);95 try expect(result[1] == 0xc4);
96}96}
...@@ -109,7 +109,7 @@ test "bitReverse vectors u8" {...@@ -109,7 +109,7 @@ test "bitReverse vectors u8" {
109109
110fn vector16() !void {110fn vector16() !void {
111 var v = @Vector(2, u16){ 0x1234, 0x2345 };111 var v = @Vector(2, u16){ 0x1234, 0x2345 };
112 var result = @bitReverse(u16, v);112 var result = @bitReverse(v);
113 try expect(result[0] == 0x2c48);113 try expect(result[0] == 0x2c48);
114 try expect(result[1] == 0xa2c4);114 try expect(result[1] == 0xa2c4);
115}115}
...@@ -128,7 +128,7 @@ test "bitReverse vectors u16" {...@@ -128,7 +128,7 @@ test "bitReverse vectors u16" {
128128
129fn vector24() !void {129fn vector24() !void {
130 var v = @Vector(2, u24){ 0x123456, 0x234567 };130 var v = @Vector(2, u24){ 0x123456, 0x234567 };
131 var result = @bitReverse(u24, v);131 var result = @bitReverse(v);
132 try expect(result[0] == 0x6a2c48);132 try expect(result[0] == 0x6a2c48);
133 try expect(result[1] == 0xe6a2c4);133 try expect(result[1] == 0xe6a2c4);
134}134}
...@@ -147,7 +147,7 @@ test "bitReverse vectors u24" {...@@ -147,7 +147,7 @@ test "bitReverse vectors u24" {
147147
148fn vector0() !void {148fn vector0() !void {
149 var v = @Vector(2, u0){ 0, 0 };149 var v = @Vector(2, u0){ 0, 0 };
150 var result = @bitReverse(u0, v);150 var result = @bitReverse(v);
151 try expect(result[0] == 0);151 try expect(result[0] == 0);
152 try expect(result[1] == 0);152 try expect(result[1] == 0);
153}153}
test/behavior/bugs/10147.zig+3-2
...@@ -2,6 +2,7 @@ const builtin = @import("builtin");...@@ -2,6 +2,7 @@ const builtin = @import("builtin");
2const std = @import("std");2const std = @import("std");
33
4test "uses correct LLVM builtin" {4test "uses correct LLVM builtin" {
5 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
5 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO6 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
6 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
...@@ -12,8 +13,8 @@ test "uses correct LLVM builtin" {...@@ -12,8 +13,8 @@ test "uses correct LLVM builtin" {
12 var y: @Vector(4, u32) = [_]u32{ 0x1, 0x1, 0x1, 0x1 };13 var y: @Vector(4, u32) = [_]u32{ 0x1, 0x1, 0x1, 0x1 };
13 // The stage1 compiler used to call the same builtin function for both14 // The stage1 compiler used to call the same builtin function for both
14 // scalar and vector inputs, causing the LLVM module verification to fail.15 // scalar and vector inputs, causing the LLVM module verification to fail.
15 var a = @clz(u32, x);16 var a = @clz(x);
16 var b = @clz(u32, y);17 var b = @clz(y);
17 try std.testing.expectEqual(@as(u6, 31), a);18 try std.testing.expectEqual(@as(u6, 31), a);
18 try std.testing.expectEqual([_]u6{ 31, 31, 31, 31 }, b);19 try std.testing.expectEqual([_]u6{ 31, 31, 31, 31 }, b);
19}20}
test/behavior/bugs/1111.zig deleted-11
...@@ -1,11 +0,0 @@
1const Foo = enum(c_int) {
2 Bar = -1,
3};
4
5test "issue 1111 fixed" {
6 const v = Foo.Bar;
7
8 switch (v) {
9 Foo.Bar => return,
10 }
11}
test/behavior/bugs/12430.zig created+11
...@@ -0,0 +1,11 @@
1const std = @import("std");
2
3test {
4 const T = comptime b: {
5 break :b @Type(.{ .Int = .{
6 .signedness = .unsigned,
7 .bits = 8,
8 } });
9 };
10 try std.testing.expect(T == u8);
11}
test/behavior/bugs/12486.zig created+49
...@@ -0,0 +1,49 @@
1const SomeEnum = union(enum) {
2 EnumVariant: u8,
3};
4
5const SomeStruct = struct {
6 struct_field: u8,
7};
8
9const OptEnum = struct {
10 opt_enum: ?SomeEnum,
11};
12
13const ErrEnum = struct {
14 err_enum: anyerror!SomeEnum,
15};
16
17const OptStruct = struct {
18 opt_struct: ?SomeStruct,
19};
20
21const ErrStruct = struct {
22 err_struct: anyerror!SomeStruct,
23};
24
25test {
26 _ = OptEnum{
27 .opt_enum = .{
28 .EnumVariant = 1,
29 },
30 };
31
32 _ = ErrEnum{
33 .err_enum = .{
34 .EnumVariant = 1,
35 },
36 };
37
38 _ = OptStruct{
39 .opt_struct = .{
40 .struct_field = 1,
41 },
42 };
43
44 _ = ErrStruct{
45 .err_struct = .{
46 .struct_field = 1,
47 },
48 };
49}
test/behavior/bugs/2114.zig+1-1
...@@ -4,7 +4,7 @@ const expect = std.testing.expect;...@@ -4,7 +4,7 @@ const expect = std.testing.expect;
4const math = std.math;4const math = std.math;
55
6fn ctz(x: anytype) usize {6fn ctz(x: anytype) usize {
7 return @ctz(@TypeOf(x), x);7 return @ctz(x);
8}8}
99
10test "fixed" {10test "fixed" {
test/behavior/byteswap.zig+10-5
...@@ -3,6 +3,7 @@ const builtin = @import("builtin");...@@ -3,6 +3,7 @@ const builtin = @import("builtin");
3const expect = std.testing.expect;3const expect = std.testing.expect;
44
5test "@byteSwap integers" {5test "@byteSwap integers" {
6 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
6 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;7 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
7 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;8 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
...@@ -46,7 +47,7 @@ test "@byteSwap integers" {...@@ -46,7 +47,7 @@ test "@byteSwap integers" {
46 );47 );
47 }48 }
48 fn t(comptime I: type, input: I, expected_output: I) !void {49 fn t(comptime I: type, input: I, expected_output: I) !void {
49 try std.testing.expect(expected_output == @byteSwap(I, input));50 try std.testing.expect(expected_output == @byteSwap(input));
50 }51 }
51 };52 };
52 comptime try ByteSwapIntTest.run();53 comptime try ByteSwapIntTest.run();
...@@ -55,12 +56,13 @@ test "@byteSwap integers" {...@@ -55,12 +56,13 @@ test "@byteSwap integers" {
5556
56fn vector8() !void {57fn vector8() !void {
57 var v = @Vector(2, u8){ 0x12, 0x13 };58 var v = @Vector(2, u8){ 0x12, 0x13 };
58 var result = @byteSwap(u8, v);59 var result = @byteSwap(v);
59 try expect(result[0] == 0x12);60 try expect(result[0] == 0x12);
60 try expect(result[1] == 0x13);61 try expect(result[1] == 0x13);
61}62}
6263
63test "@byteSwap vectors u8" {64test "@byteSwap vectors u8" {
65 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
64 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;66 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
65 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;67 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
66 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;68 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
...@@ -73,12 +75,13 @@ test "@byteSwap vectors u8" {...@@ -73,12 +75,13 @@ test "@byteSwap vectors u8" {
7375
74fn vector16() !void {76fn vector16() !void {
75 var v = @Vector(2, u16){ 0x1234, 0x2345 };77 var v = @Vector(2, u16){ 0x1234, 0x2345 };
76 var result = @byteSwap(u16, v);78 var result = @byteSwap(v);
77 try expect(result[0] == 0x3412);79 try expect(result[0] == 0x3412);
78 try expect(result[1] == 0x4523);80 try expect(result[1] == 0x4523);
79}81}
8082
81test "@byteSwap vectors u16" {83test "@byteSwap vectors u16" {
84 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
82 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;85 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
83 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;86 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
84 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;87 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
...@@ -91,12 +94,13 @@ test "@byteSwap vectors u16" {...@@ -91,12 +94,13 @@ test "@byteSwap vectors u16" {
9194
92fn vector24() !void {95fn vector24() !void {
93 var v = @Vector(2, u24){ 0x123456, 0x234567 };96 var v = @Vector(2, u24){ 0x123456, 0x234567 };
94 var result = @byteSwap(u24, v);97 var result = @byteSwap(v);
95 try expect(result[0] == 0x563412);98 try expect(result[0] == 0x563412);
96 try expect(result[1] == 0x674523);99 try expect(result[1] == 0x674523);
97}100}
98101
99test "@byteSwap vectors u24" {102test "@byteSwap vectors u24" {
103 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
100 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;104 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
101 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;105 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
102 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;106 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
...@@ -109,12 +113,13 @@ test "@byteSwap vectors u24" {...@@ -109,12 +113,13 @@ test "@byteSwap vectors u24" {
109113
110fn vector0() !void {114fn vector0() !void {
111 var v = @Vector(2, u0){ 0, 0 };115 var v = @Vector(2, u0){ 0, 0 };
112 var result = @byteSwap(u0, v);116 var result = @byteSwap(v);
113 try expect(result[0] == 0);117 try expect(result[0] == 0);
114 try expect(result[1] == 0);118 try expect(result[1] == 0);
115}119}
116120
117test "@byteSwap vectors u0" {121test "@byteSwap vectors u0" {
122 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
118 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;123 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
119 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;124 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
120 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;125 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
test/behavior/call.zig+15
...@@ -246,3 +246,18 @@ test "function call with 40 arguments" {...@@ -246,3 +246,18 @@ test "function call with 40 arguments" {
246 };246 };
247 try S.doTheTest(39);247 try S.doTheTest(39);
248}248}
249
250test "arguments to comptime parameters generated in comptime blocks" {
251 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
252
253 const S = struct {
254 fn fortyTwo() i32 {
255 return 42;
256 }
257
258 fn foo(comptime x: i32) void {
259 if (x != 42) @compileError("bad");
260 }
261 };
262 S.foo(S.fortyTwo());
263}
test/behavior/cast.zig+6-1
...@@ -1281,7 +1281,7 @@ test "*const [N]null u8 to ?[]const u8" {...@@ -1281,7 +1281,7 @@ test "*const [N]null u8 to ?[]const u8" {
1281test "cast between [*c]T and ?[*:0]T on fn parameter" {1281test "cast between [*c]T and ?[*:0]T on fn parameter" {
1282 const S = struct {1282 const S = struct {
1283 const Handler = ?fn ([*c]const u8) callconv(.C) void;1283 const Handler = ?fn ([*c]const u8) callconv(.C) void;
1284 fn addCallback(handler: Handler) void {1284 fn addCallback(comptime handler: Handler) void {
1285 _ = handler;1285 _ = handler;
1286 }1286 }
12871287
...@@ -1431,6 +1431,11 @@ test "coerce between pointers of compatible differently-named floats" {...@@ -1431,6 +1431,11 @@ test "coerce between pointers of compatible differently-named floats" {
1431 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1431 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1432 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1432 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
14331433
1434 if (builtin.os.tag == .windows) {
1435 // https://github.com/ziglang/zig/issues/12396
1436 return error.SkipZigTest;
1437 }
1438
1434 const F = switch (@typeInfo(c_longdouble).Float.bits) {1439 const F = switch (@typeInfo(c_longdouble).Float.bits) {
1435 16 => f16,1440 16 => f16,
1436 32 => f32,1441 32 => f32,
test/behavior/comptime_memory.zig+1-1
...@@ -82,7 +82,7 @@ test "type pun value and struct" {...@@ -82,7 +82,7 @@ test "type pun value and struct" {
82}82}
8383
84fn bigToNativeEndian(comptime T: type, v: T) T {84fn bigToNativeEndian(comptime T: type, v: T) T {
85 return if (endian == .Big) v else @byteSwap(T, v);85 return if (endian == .Big) v else @byteSwap(v);
86}86}
87test "type pun endianness" {87test "type pun endianness" {
88 if (builtin.zig_backend == .stage1) return error.SkipZigTest;88 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
test/behavior/empty_union.zig created+54
...@@ -0,0 +1,54 @@
1const builtin = @import("builtin");
2const std = @import("std");
3const expect = std.testing.expect;
4
5test "switch on empty enum" {
6 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
8
9 const E = enum {};
10 var e: E = undefined;
11 switch (e) {}
12}
13
14test "switch on empty enum with a specified tag type" {
15 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
16 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
17
18 const E = enum(u8) {};
19 var e: E = undefined;
20 switch (e) {}
21}
22
23test "switch on empty auto numbered tagged union" {
24 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
25 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
26 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
27
28 const U = union(enum(u8)) {};
29 var u: U = undefined;
30 switch (u) {}
31}
32
33test "switch on empty tagged union" {
34 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
35 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
36 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
37
38 const E = enum {};
39 const U = union(E) {};
40 var u: U = undefined;
41 switch (u) {}
42}
43
44test "empty union" {
45 const U = union {};
46 try expect(@sizeOf(U) == 0);
47 try expect(@alignOf(U) == 0);
48}
49
50test "empty extern union" {
51 const U = extern union {};
52 try expect(@sizeOf(U) == 0);
53 try expect(@alignOf(U) == 1);
54}
test/behavior/enum.zig+47
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
2const std = @import("std");2const std = @import("std");
3const expect = std.testing.expect;3const expect = std.testing.expect;
4const assert = std.debug.assert;
4const mem = std.mem;5const mem = std.mem;
5const Tag = std.meta.Tag;6const Tag = std.meta.Tag;
67
...@@ -1128,3 +1129,49 @@ test "tag name functions are unique" {...@@ -1128,3 +1129,49 @@ test "tag name functions are unique" {
1128 _ = a;1129 _ = a;
1129 }1130 }
1130}1131}
1132
1133test "size of enum with only one tag which has explicit integer tag type" {
1134 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1135 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1136 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1137
1138 const E = enum(u8) { nope = 10 };
1139 const S0 = struct { e: E };
1140 const S1 = extern struct { e: E };
1141 //const U = union(E) { nope: void };
1142 comptime assert(@sizeOf(E) == 1);
1143 comptime assert(@sizeOf(S0) == 1);
1144 comptime assert(@sizeOf(S1) == 1);
1145 //comptime assert(@sizeOf(U) == 1);
1146
1147 var s1: S1 = undefined;
1148 s1.e = .nope;
1149 try expect(s1.e == .nope);
1150 const ptr = @ptrCast(*u8, &s1);
1151 try expect(ptr.* == 10);
1152
1153 var s0: S0 = undefined;
1154 s0.e = .nope;
1155 try expect(s0.e == .nope);
1156}
1157
1158test "switch on an extern enum with negative value" {
1159 // TODO x86, wasm backends fail because they assume that enum tag types are unsigned
1160 if (@import("builtin").zig_backend == .stage2_x86_64) return error.SkipZigTest;
1161 if (@import("builtin").zig_backend == .stage2_wasm) return error.SkipZigTest;
1162
1163 const Foo = enum(c_int) {
1164 Bar = -1,
1165 };
1166
1167 const v = Foo.Bar;
1168
1169 switch (v) {
1170 Foo.Bar => return,
1171 }
1172}
1173
1174test "Non-exhaustive enum with nonstandard int size behaves correctly" {
1175 const E = enum(u15) { _ };
1176 try expect(@sizeOf(E) == @sizeOf(u15));
1177}
test/behavior/error.zig+78-2
...@@ -168,7 +168,7 @@ fn entryPtr() void {...@@ -168,7 +168,7 @@ fn entryPtr() void {
168 fooPtr(ptr);168 fooPtr(ptr);
169}169}
170170
171fn foo2(f: fn () anyerror!void) void {171fn foo2(comptime f: fn () anyerror!void) void {
172 const x = f();172 const x = f();
173 x catch {173 x catch {
174 @panic("fail");174 @panic("fail");
...@@ -725,7 +725,7 @@ test "simple else prong allowed even when all errors handled" {...@@ -725,7 +725,7 @@ test "simple else prong allowed even when all errors handled" {
725 try expect(value == 255);725 try expect(value == 255);
726}726}
727727
728test {728test "pointer to error union payload" {
729 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO729 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
730 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO730 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
731 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO731 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
...@@ -736,3 +736,79 @@ test {...@@ -736,3 +736,79 @@ test {
736 const payload_ptr = &(err_union catch unreachable);736 const payload_ptr = &(err_union catch unreachable);
737 try expect(payload_ptr.* == 15);737 try expect(payload_ptr.* == 15);
738}738}
739
740const NoReturn = struct {
741 var a: u32 = undefined;
742 fn someData() bool {
743 a -= 1;
744 return a == 0;
745 }
746 fn loop() !noreturn {
747 while (true) {
748 if (someData())
749 return error.GenericFailure;
750 }
751 }
752 fn testTry() anyerror {
753 try loop();
754 }
755 fn testCatch() anyerror {
756 loop() catch return error.OtherFailure;
757 @compileError("bad");
758 }
759};
760
761test "error union of noreturn used with if" {
762 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
763 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
764 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
765 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
766 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
767
768 NoReturn.a = 64;
769 if (NoReturn.loop()) {
770 @compileError("bad");
771 } else |err| {
772 try expect(err == error.GenericFailure);
773 }
774}
775
776test "error union of noreturn used with try" {
777 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
778 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
779 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
780 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
781 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
782
783 NoReturn.a = 64;
784 const err = NoReturn.testTry();
785 try expect(err == error.GenericFailure);
786}
787
788test "error union of noreturn used with catch" {
789 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
790 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
791 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
792 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
793 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
794
795 NoReturn.a = 64;
796 const err = NoReturn.testCatch();
797 try expect(err == error.OtherFailure);
798}
799
800test "alignment of wrapping an error union payload" {
801 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
802 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
803 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
804
805 const S = struct {
806 const I = extern struct { x: i128 };
807
808 fn foo() anyerror!I {
809 var i: I = .{ .x = 1234 };
810 return i;
811 }
812 };
813 try expect((S.foo() catch unreachable).x == 1234);
814}
test/behavior/eval.zig+54
...@@ -1293,3 +1293,57 @@ test "mutate through pointer-like optional at comptime" {...@@ -1293,3 +1293,57 @@ test "mutate through pointer-like optional at comptime" {
1293 try expect(payload_ptr.*.* == 16);1293 try expect(payload_ptr.*.* == 16);
1294 }1294 }
1295}1295}
1296
1297test "repeated value is correctly expanded" {
1298 const S = struct { x: [4]i8 = std.mem.zeroes([4]i8) };
1299 const M = struct { x: [4]S = std.mem.zeroes([4]S) };
1300
1301 comptime {
1302 var res = M{};
1303 for (.{ 1, 2, 3 }) |i| res.x[i].x[i] = i;
1304
1305 try expectEqual(M{ .x = .{
1306 .{ .x = .{ 0, 0, 0, 0 } },
1307 .{ .x = .{ 0, 1, 0, 0 } },
1308 .{ .x = .{ 0, 0, 2, 0 } },
1309 .{ .x = .{ 0, 0, 0, 3 } },
1310 } }, res);
1311 }
1312}
1313
1314test "value in if block is comptime known" {
1315 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
1316
1317 const first = blk: {
1318 const s = if (false) "a" else "b";
1319 break :blk "foo" ++ s;
1320 };
1321 const second = blk: {
1322 const S = struct { str: []const u8 };
1323 const s = if (false) S{ .str = "a" } else S{ .str = "b" };
1324 break :blk "foo" ++ s.str;
1325 };
1326 comptime try expect(std.mem.eql(u8, first, second));
1327}
1328
1329test "lazy sizeof is resolved in division" {
1330 const A = struct {
1331 a: u32,
1332 };
1333 const a = 2;
1334 try expect(@sizeOf(A) / a == 2);
1335 try expect(@sizeOf(A) - a == 2);
1336}
1337
1338test "lazy value is resolved as slice operand" {
1339 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1340 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1341
1342 const A = struct { a: u32 };
1343 var a: [512]u64 = undefined;
1344
1345 const ptr1 = a[0..@sizeOf(A)];
1346 const ptr2 = @ptrCast([*]u8, &a)[0..@sizeOf(A)];
1347 try expect(@ptrToInt(ptr1) == @ptrToInt(ptr2));
1348 try expect(ptr1.len == ptr2.len);
1349}
test/behavior/floatop.zig+4-4
...@@ -194,8 +194,8 @@ fn testSin() !void {...@@ -194,8 +194,8 @@ fn testSin() !void {
194 const eps = epsForType(ty);194 const eps = epsForType(ty);
195 try expect(@sin(@as(ty, 0)) == 0);195 try expect(@sin(@as(ty, 0)) == 0);
196 try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi)), 0, eps));196 try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi)), 0, eps));
197 try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi / 2)), 1, eps));197 try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi / 2.0)), 1, eps));
198 try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi / 4)), 0.7071067811865475, eps));198 try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi / 4.0)), 0.7071067811865475, eps));
199 }199 }
200200
201 {201 {
...@@ -228,8 +228,8 @@ fn testCos() !void {...@@ -228,8 +228,8 @@ fn testCos() !void {
228 const eps = epsForType(ty);228 const eps = epsForType(ty);
229 try expect(@cos(@as(ty, 0)) == 1);229 try expect(@cos(@as(ty, 0)) == 1);
230 try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi)), -1, eps));230 try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi)), -1, eps));
231 try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi / 2)), 0, eps));231 try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi / 2.0)), 0, eps));
232 try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi / 4)), 0.7071067811865475, eps));232 try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi / 4.0)), 0.7071067811865475, eps));
233 }233 }
234234
235 {235 {
test/behavior/fn.zig+22-1
...@@ -137,7 +137,7 @@ test "implicit cast function unreachable return" {...@@ -137,7 +137,7 @@ test "implicit cast function unreachable return" {
137 wantsFnWithVoid(fnWithUnreachable);137 wantsFnWithVoid(fnWithUnreachable);
138}138}
139139
140fn wantsFnWithVoid(f: fn () void) void {140fn wantsFnWithVoid(comptime f: fn () void) void {
141 _ = f;141 _ = f;
142}142}
143143
...@@ -422,3 +422,24 @@ test "import passed byref to function in return type" {...@@ -422,3 +422,24 @@ test "import passed byref to function in return type" {
422 var list = S.get();422 var list = S.get();
423 try expect(list.items.len == 0);423 try expect(list.items.len == 0);
424}424}
425
426test "implicit cast function to function ptr" {
427 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
428 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
429 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
430 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
431 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
432
433 const S1 = struct {
434 export fn someFunctionThatReturnsAValue() c_int {
435 return 123;
436 }
437 };
438 var fnPtr1: *const fn () callconv(.C) c_int = S1.someFunctionThatReturnsAValue;
439 try expect(fnPtr1() == 123);
440 const S2 = struct {
441 extern fn someFunctionThatReturnsAValue() c_int;
442 };
443 var fnPtr2: *const fn () callconv(.C) c_int = S2.someFunctionThatReturnsAValue;
444 try expect(fnPtr2() == 123);
445}
test/behavior/generics.zig+34
...@@ -323,3 +323,37 @@ test "generic function instantiation non-duplicates" {...@@ -323,3 +323,37 @@ test "generic function instantiation non-duplicates" {
323 S.copy(u8, &buffer, "hello");323 S.copy(u8, &buffer, "hello");
324 S.copy(u8, &buffer, "hello2");324 S.copy(u8, &buffer, "hello2");
325}325}
326
327test "generic instantiation of tagged union with only one field" {
328 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
329 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
330 if (builtin.os.tag == .wasi) return error.SkipZigTest;
331
332 const S = struct {
333 const U = union(enum) {
334 s: []const u8,
335 };
336
337 fn foo(comptime u: U) usize {
338 return u.s.len;
339 }
340 };
341
342 try expect(S.foo(.{ .s = "a" }) == 1);
343 try expect(S.foo(.{ .s = "ab" }) == 2);
344}
345
346test "nested generic function" {
347 const S = struct {
348 fn foo(comptime T: type, callback: *const fn (user_data: T) anyerror!void, data: T) anyerror!void {
349 try callback(data);
350 }
351 fn bar(a: u32) anyerror!void {
352 try expect(a == 123);
353 }
354
355 fn g(_: *const fn (anytype) void) void {}
356 };
357 try expect(@typeInfo(@TypeOf(S.g)).Fn.is_generic);
358 try S.foo(u32, S.bar, 123);
359}
test/behavior/math.zig+32-11
...@@ -90,10 +90,11 @@ fn testClzBigInts() !void {...@@ -90,10 +90,11 @@ fn testClzBigInts() !void {
90}90}
9191
92fn testOneClz(comptime T: type, x: T) u32 {92fn testOneClz(comptime T: type, x: T) u32 {
93 return @clz(T, x);93 return @clz(x);
94}94}
9595
96test "@clz vectors" {96test "@clz vectors" {
97 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
97 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO98 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO99 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
99 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO100 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
...@@ -120,7 +121,7 @@ fn testOneClzVector(...@@ -120,7 +121,7 @@ fn testOneClzVector(
120 x: @Vector(len, T),121 x: @Vector(len, T),
121 expected: @Vector(len, u32),122 expected: @Vector(len, u32),
122) !void {123) !void {
123 try expectVectorsEqual(@clz(T, x), expected);124 try expectVectorsEqual(@clz(x), expected);
124}125}
125126
126fn expectVectorsEqual(a: anytype, b: anytype) !void {127fn expectVectorsEqual(a: anytype, b: anytype) !void {
...@@ -151,19 +152,18 @@ fn testCtz() !void {...@@ -151,19 +152,18 @@ fn testCtz() !void {
151}152}
152153
153fn testOneCtz(comptime T: type, x: T) u32 {154fn testOneCtz(comptime T: type, x: T) u32 {
154 return @ctz(T, x);155 return @ctz(x);
155}156}
156157
157test "@ctz vectors" {158test "@ctz vectors" {
159 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
158 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO160 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
159 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO161 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
160 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO162 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
161 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO163 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
162 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO164 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
163165
164 if ((builtin.zig_backend == .stage1 or builtin.zig_backend == .stage2_llvm) and166 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) {
165 builtin.cpu.arch == .aarch64)
166 {
167 // This regressed with LLVM 14:167 // This regressed with LLVM 14:
168 // https://github.com/ziglang/zig/issues/12013168 // https://github.com/ziglang/zig/issues/12013
169 return error.SkipZigTest;169 return error.SkipZigTest;
...@@ -187,7 +187,7 @@ fn testOneCtzVector(...@@ -187,7 +187,7 @@ fn testOneCtzVector(
187 x: @Vector(len, T),187 x: @Vector(len, T),
188 expected: @Vector(len, u32),188 expected: @Vector(len, u32),
189) !void {189) !void {
190 try expectVectorsEqual(@ctz(T, x), expected);190 try expectVectorsEqual(@ctz(x), expected);
191}191}
192192
193test "const number literal" {193test "const number literal" {
...@@ -239,10 +239,9 @@ test "quad hex float literal parsing in range" {...@@ -239,10 +239,9 @@ test "quad hex float literal parsing in range" {
239}239}
240240
241test "underscore separator parsing" {241test "underscore separator parsing" {
242 try expect(0_0_0_0 == 0);
243 try expect(1_234_567 == 1234567);242 try expect(1_234_567 == 1234567);
244 try expect(001_234_567 == 1234567);243 try expect(1_234_567 == 1234567);
245 try expect(0_0_1_2_3_4_5_6_7 == 1234567);244 try expect(1_2_3_4_5_6_7 == 1234567);
246245
247 try expect(0b0_0_0_0 == 0);246 try expect(0b0_0_0_0 == 0);
248 try expect(0b1010_1010 == 0b10101010);247 try expect(0b1010_1010 == 0b10101010);
...@@ -260,7 +259,7 @@ test "underscore separator parsing" {...@@ -260,7 +259,7 @@ test "underscore separator parsing" {
260 try expect(0x1_0_1_0_1_0_1_0 == 0x10101010);259 try expect(0x1_0_1_0_1_0_1_0 == 0x10101010);
261260
262 try expect(123_456.789_000e1_0 == 123456.789000e10);261 try expect(123_456.789_000e1_0 == 123456.789000e10);
263 try expect(0_1_2_3_4_5_6.7_8_9_0_0_0e0_0_1_0 == 123456.789000e10);262 try expect(1_2_3_4_5_6.7_8_9_0_0_0e0_0_1_0 == 123456.789000e10);
264263
265 try expect(0x1234_5678.9ABC_DEF0p-1_0 == 0x12345678.9ABCDEF0p-10);264 try expect(0x1234_5678.9ABC_DEF0p-1_0 == 0x12345678.9ABCDEF0p-10);
266 try expect(0x1_2_3_4_5_6_7_8.9_A_B_C_D_E_F_0p-0_0_0_1_0 == 0x12345678.9ABCDEF0p-10);265 try expect(0x1_2_3_4_5_6_7_8.9_A_B_C_D_E_F_0p-0_0_0_1_0 == 0x12345678.9ABCDEF0p-10);
...@@ -1168,6 +1167,7 @@ test "remainder division" {...@@ -1168,6 +1167,7 @@ test "remainder division" {
1168 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1167 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1169 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1168 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1170 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1169 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1170 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/12602
11711171
1172 comptime try remdiv(f16);1172 comptime try remdiv(f16);
1173 comptime try remdiv(f32);1173 comptime try remdiv(f32);
...@@ -1199,6 +1199,7 @@ test "float remainder division using @rem" {...@@ -1199,6 +1199,7 @@ test "float remainder division using @rem" {
1199 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1199 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1200 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1200 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1201 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1201 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1202 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/12602
12021203
1203 comptime try frem(f16);1204 comptime try frem(f16);
1204 comptime try frem(f32);1205 comptime try frem(f32);
...@@ -1241,6 +1242,7 @@ test "float modulo division using @mod" {...@@ -1241,6 +1242,7 @@ test "float modulo division using @mod" {
1241 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1242 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1242 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1243 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1243 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1244 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1245 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/12602
12441246
1245 comptime try fmod(f16);1247 comptime try fmod(f16);
1246 comptime try fmod(f32);1248 comptime try fmod(f32);
...@@ -1368,6 +1370,7 @@ test "@floor f80" {...@@ -1368,6 +1370,7 @@ test "@floor f80" {
1368 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1370 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1369 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1371 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1370 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO1372 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1373 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/12602
13711374
1372 try testFloor(f80, 12.0);1375 try testFloor(f80, 12.0);
1373 comptime try testFloor(f80, 12.0);1376 comptime try testFloor(f80, 12.0);
...@@ -1416,6 +1419,7 @@ test "@ceil f80" {...@@ -1416,6 +1419,7 @@ test "@ceil f80" {
1416 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1419 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1417 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1420 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1418 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO1421 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1422 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/12602
14191423
1420 try testCeil(f80, 12.0);1424 try testCeil(f80, 12.0);
1421 comptime try testCeil(f80, 12.0);1425 comptime try testCeil(f80, 12.0);
...@@ -1464,6 +1468,7 @@ test "@trunc f80" {...@@ -1464,6 +1468,7 @@ test "@trunc f80" {
1464 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1468 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1465 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1469 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1466 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO1470 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1471 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/12602
14671472
1468 try testTrunc(f80, 12.0);1473 try testTrunc(f80, 12.0);
1469 comptime try testTrunc(f80, 12.0);1474 comptime try testTrunc(f80, 12.0);
...@@ -1526,6 +1531,7 @@ test "@round f80" {...@@ -1526,6 +1531,7 @@ test "@round f80" {
1526 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1531 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1527 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1532 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1528 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO1533 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1534 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/12602
15291535
1530 try testRound(f80, 12.0);1536 try testRound(f80, 12.0);
1531 comptime try testRound(f80, 12.0);1537 comptime try testRound(f80, 12.0);
...@@ -1721,3 +1727,18 @@ fn testAbsFloat() !void {...@@ -1721,3 +1727,18 @@ fn testAbsFloat() !void {
1721fn testAbsFloatOne(in: f32, out: f32) !void {1727fn testAbsFloatOne(in: f32, out: f32) !void {
1722 try expect(@fabs(@as(f32, in)) == @as(f32, out));1728 try expect(@fabs(@as(f32, in)) == @as(f32, out));
1723}1729}
1730
1731test "mod lazy values" {
1732 {
1733 const X = struct { x: u32 };
1734 const x = @sizeOf(X);
1735 const y = 1 % x;
1736 _ = y;
1737 }
1738 {
1739 const X = struct { x: u32 };
1740 const x = @sizeOf(X);
1741 const y = x % 1;
1742 _ = y;
1743 }
1744}
test/behavior/muladd.zig+2
...@@ -51,6 +51,7 @@ test "@mulAdd f80" {...@@ -51,6 +51,7 @@ test "@mulAdd f80" {
51 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO51 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
52 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO52 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
53 if (builtin.zig_backend == .stage1) return error.SkipZigTest;53 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
54 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/12602
5455
55 comptime try testMulAdd80();56 comptime try testMulAdd80();
56 try testMulAdd80();57 try testMulAdd80();
...@@ -182,6 +183,7 @@ test "vector f80" {...@@ -182,6 +183,7 @@ test "vector f80" {
182 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO183 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
183 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO184 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
184 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO185 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
186 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/12602
185187
186 comptime try vector80();188 comptime try vector80();
187 try vector80();189 try vector80();
test/behavior/optional.zig+59
...@@ -369,3 +369,62 @@ test "optional pointer to zero bit error union payload" {...@@ -369,3 +369,62 @@ test "optional pointer to zero bit error union payload" {
369 some.foo();369 some.foo();
370 } else |_| {}370 } else |_| {}
371}371}
372
373const NoReturn = struct {
374 var a: u32 = undefined;
375 fn someData() bool {
376 a -= 1;
377 return a == 0;
378 }
379 fn loop() ?noreturn {
380 while (true) {
381 if (someData()) return null;
382 }
383 }
384 fn testOrelse() u32 {
385 loop() orelse return 123;
386 @compileError("bad");
387 }
388};
389
390test "optional of noreturn used with if" {
391 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
392
393 NoReturn.a = 64;
394 if (NoReturn.loop()) |_| {
395 @compileError("bad");
396 } else {
397 try expect(true);
398 }
399}
400
401test "optional of noreturn used with orelse" {
402 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
403
404 NoReturn.a = 64;
405 const val = NoReturn.testOrelse();
406 try expect(val == 123);
407}
408
409test "orelse on C pointer" {
410 // TODO https://github.com/ziglang/zig/issues/6597
411 const foo: [*c]const u8 = "hey";
412 const d = foo orelse @compileError("bad");
413 try expectEqual([*c]const u8, @TypeOf(d));
414}
415
416test "alignment of wrapping an optional payload" {
417 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
418 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
419 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
420
421 const S = struct {
422 const I = extern struct { x: i128 };
423
424 fn foo() ?I {
425 var i: I = .{ .x = 1234 };
426 return i;
427 }
428 };
429 try expect(S.foo().?.x == 1234);
430}
test/behavior/packed-struct.zig+145
...@@ -434,3 +434,148 @@ test "@ptrToInt on a packed struct field" {...@@ -434,3 +434,148 @@ test "@ptrToInt on a packed struct field" {
434 };434 };
435 try expect(@ptrToInt(&S.p0.z) - @ptrToInt(&S.p0.x) == 2);435 try expect(@ptrToInt(&S.p0.z) - @ptrToInt(&S.p0.x) == 2);
436}436}
437
438test "optional pointer in packed struct" {
439 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
440 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
441 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
442 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
443
444 const T = packed struct { ptr: ?*const u8 };
445 var n: u8 = 0;
446 const x = T{ .ptr = &n };
447 try expect(x.ptr.? == &n);
448}
449
450test "nested packed struct field access test" {
451 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
452 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
453 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
454 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
455 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
456 //
457 const Vec2 = packed struct {
458 x: f32,
459 y: f32,
460 };
461
462 const Vec3 = packed struct {
463 x: f32,
464 y: f32,
465 z: f32,
466 };
467
468 const NestedVec2 = packed struct {
469 nested: Vec2,
470 };
471
472 const NestedVec3 = packed struct {
473 nested: Vec3,
474 };
475
476 const vec2 = Vec2{
477 .x = 1.0,
478 .y = 2.0,
479 };
480
481 try std.testing.expectEqual(vec2.x, 1.0);
482 try std.testing.expectEqual(vec2.y, 2.0);
483
484 var vec2_o: Vec2 = undefined;
485 const vec2_o_ptr: *Vec2 = &vec2_o;
486 vec2_o_ptr.* = vec2;
487
488 try std.testing.expectEqual(vec2_o.x, 1.0);
489 try std.testing.expectEqual(vec2_o.y, 2.0);
490
491 const nested_vec2 = NestedVec2{
492 .nested = Vec2{
493 .x = 1.0,
494 .y = 2.0,
495 },
496 };
497
498 try std.testing.expectEqual(nested_vec2.nested.x, 1.0);
499 try std.testing.expectEqual(nested_vec2.nested.y, 2.0);
500
501 var nested_o: NestedVec2 = undefined;
502 const nested_o_ptr: *NestedVec2 = &nested_o;
503 nested_o_ptr.* = nested_vec2;
504
505 try std.testing.expectEqual(nested_o.nested.x, 1.0);
506 try std.testing.expectEqual(nested_o.nested.y, 2.0);
507
508 const vec3 = Vec3{
509 .x = 1.0,
510 .y = 2.0,
511 .z = 3.0,
512 };
513
514 try std.testing.expectEqual(vec3.x, 1.0);
515 try std.testing.expectEqual(vec3.y, 2.0);
516 try std.testing.expectEqual(vec3.z, 3.0);
517
518 var vec3_o: Vec3 = undefined;
519 const vec3_o_ptr: *Vec3 = &vec3_o;
520 vec3_o_ptr.* = vec3;
521
522 try std.testing.expectEqual(vec3_o.x, 1.0);
523 try std.testing.expectEqual(vec3_o.y, 2.0);
524 try std.testing.expectEqual(vec3_o.z, 3.0);
525
526 const nested_vec3 = NestedVec3{
527 .nested = Vec3{
528 .x = 1.0,
529 .y = 2.0,
530 .z = 3.0,
531 },
532 };
533
534 try std.testing.expectEqual(nested_vec3.nested.x, 1.0);
535 try std.testing.expectEqual(nested_vec3.nested.y, 2.0);
536 try std.testing.expectEqual(nested_vec3.nested.z, 3.0);
537
538 var nested_vec3_o: NestedVec3 = undefined;
539 const nested_vec3_o_ptr: *NestedVec3 = &nested_vec3_o;
540 nested_vec3_o_ptr.* = nested_vec3;
541
542 try std.testing.expectEqual(nested_vec3_o.nested.x, 1.0);
543 try std.testing.expectEqual(nested_vec3_o.nested.y, 2.0);
544 try std.testing.expectEqual(nested_vec3_o.nested.z, 3.0);
545
546 const hld = packed struct {
547 c: u64,
548 d: u32,
549 };
550
551 const mld = packed struct {
552 h: u64,
553 i: u64,
554 };
555
556 const a = packed struct {
557 b: hld,
558 g: mld,
559 };
560
561 var arg = a{ .b = hld{ .c = 1, .d = 2 }, .g = mld{ .h = 6, .i = 8 } };
562 try std.testing.expect(arg.b.c == 1);
563 try std.testing.expect(arg.b.d == 2);
564 try std.testing.expect(arg.g.h == 6);
565 try std.testing.expect(arg.g.i == 8);
566}
567
568test "runtime init of unnamed packed struct type" {
569 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
570 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
571 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
572 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
573
574 var z: u8 = 123;
575 try (packed struct {
576 x: u8,
577 pub fn m(s: @This()) !void {
578 try expect(s.x == 123);
579 }
580 }{ .x = z }).m();
581}
test/behavior/packed_struct_explicit_backing_int.zig created+53
...@@ -0,0 +1,53 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const assert = std.debug.assert;
4const expectEqual = std.testing.expectEqual;
5const native_endian = builtin.cpu.arch.endian();
6
7test "packed struct explicit backing integer" {
8 assert(builtin.zig_backend != .stage1);
9 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14
15 const S1 = packed struct { a: u8, b: u8, c: u8 };
16
17 const S2 = packed struct(i24) { d: u8, e: u8, f: u8 };
18
19 const S3 = packed struct { x: S1, y: S2 };
20 const S3Padded = packed struct(u64) { s3: S3, pad: u16 };
21
22 try expectEqual(48, @bitSizeOf(S3));
23 try expectEqual(@sizeOf(u48), @sizeOf(S3));
24
25 try expectEqual(3, @offsetOf(S3, "y"));
26 try expectEqual(24, @bitOffsetOf(S3, "y"));
27
28 if (native_endian == .Little) {
29 const s3 = @bitCast(S3Padded, @as(u64, 0xe952d5c71ff4)).s3;
30 try expectEqual(@as(u8, 0xf4), s3.x.a);
31 try expectEqual(@as(u8, 0x1f), s3.x.b);
32 try expectEqual(@as(u8, 0xc7), s3.x.c);
33 try expectEqual(@as(u8, 0xd5), s3.y.d);
34 try expectEqual(@as(u8, 0x52), s3.y.e);
35 try expectEqual(@as(u8, 0xe9), s3.y.f);
36 }
37
38 const S4 = packed struct { a: i32, b: i8 };
39 const S5 = packed struct(u80) { a: i32, b: i8, c: S4 };
40 const S6 = packed struct(i80) { a: i32, b: S4, c: i8 };
41
42 const expectedBitSize = 80;
43 const expectedByteSize = @sizeOf(u80);
44 try expectEqual(expectedBitSize, @bitSizeOf(S5));
45 try expectEqual(expectedByteSize, @sizeOf(S5));
46 try expectEqual(expectedBitSize, @bitSizeOf(S6));
47 try expectEqual(expectedByteSize, @sizeOf(S6));
48
49 try expectEqual(5, @offsetOf(S5, "c"));
50 try expectEqual(40, @bitOffsetOf(S5, "c"));
51 try expectEqual(9, @offsetOf(S6, "c"));
52 try expectEqual(72, @bitOffsetOf(S6, "c"));
53}
test/behavior/popcount.zig+15-14
...@@ -18,53 +18,54 @@ test "@popCount 128bit integer" {...@@ -18,53 +18,54 @@ test "@popCount 128bit integer" {
18 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO18 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1919
20 comptime {20 comptime {
21 try expect(@popCount(u128, @as(u128, 0b11111111000110001100010000100001000011000011100101010001)) == 24);21 try expect(@popCount(@as(u128, 0b11111111000110001100010000100001000011000011100101010001)) == 24);
22 try expect(@popCount(i128, @as(i128, 0b11111111000110001100010000100001000011000011100101010001)) == 24);22 try expect(@popCount(@as(i128, 0b11111111000110001100010000100001000011000011100101010001)) == 24);
23 }23 }
2424
25 {25 {
26 var x: u128 = 0b11111111000110001100010000100001000011000011100101010001;26 var x: u128 = 0b11111111000110001100010000100001000011000011100101010001;
27 try expect(@popCount(u128, x) == 24);27 try expect(@popCount(x) == 24);
28 }28 }
2929
30 try expect(@popCount(i128, @as(i128, 0b11111111000110001100010000100001000011000011100101010001)) == 24);30 try expect(@popCount(@as(i128, 0b11111111000110001100010000100001000011000011100101010001)) == 24);
31}31}
3232
33fn testPopCountIntegers() !void {33fn testPopCountIntegers() !void {
34 {34 {
35 var x: u32 = 0xffffffff;35 var x: u32 = 0xffffffff;
36 try expect(@popCount(u32, x) == 32);36 try expect(@popCount(x) == 32);
37 }37 }
38 {38 {
39 var x: u5 = 0x1f;39 var x: u5 = 0x1f;
40 try expect(@popCount(u5, x) == 5);40 try expect(@popCount(x) == 5);
41 }41 }
42 {42 {
43 var x: u32 = 0xaa;43 var x: u32 = 0xaa;
44 try expect(@popCount(u32, x) == 4);44 try expect(@popCount(x) == 4);
45 }45 }
46 {46 {
47 var x: u32 = 0xaaaaaaaa;47 var x: u32 = 0xaaaaaaaa;
48 try expect(@popCount(u32, x) == 16);48 try expect(@popCount(x) == 16);
49 }49 }
50 {50 {
51 var x: u32 = 0xaaaaaaaa;51 var x: u32 = 0xaaaaaaaa;
52 try expect(@popCount(u32, x) == 16);52 try expect(@popCount(x) == 16);
53 }53 }
54 {54 {
55 var x: i16 = -1;55 var x: i16 = -1;
56 try expect(@popCount(i16, x) == 16);56 try expect(@popCount(x) == 16);
57 }57 }
58 {58 {
59 var x: i8 = -120;59 var x: i8 = -120;
60 try expect(@popCount(i8, x) == 2);60 try expect(@popCount(x) == 2);
61 }61 }
62 comptime {62 comptime {
63 try expect(@popCount(u8, @bitCast(u8, @as(i8, -120))) == 2);63 try expect(@popCount(@bitCast(u8, @as(i8, -120))) == 2);
64 }64 }
65}65}
6666
67test "@popCount vectors" {67test "@popCount vectors" {
68 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
68 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO69 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
69 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO70 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
70 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO71 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
...@@ -79,13 +80,13 @@ fn testPopCountVectors() !void {...@@ -79,13 +80,13 @@ fn testPopCountVectors() !void {
79 {80 {
80 var x: @Vector(8, u32) = [1]u32{0xffffffff} ** 8;81 var x: @Vector(8, u32) = [1]u32{0xffffffff} ** 8;
81 const expected = [1]u6{32} ** 8;82 const expected = [1]u6{32} ** 8;
82 const result: [8]u6 = @popCount(u32, x);83 const result: [8]u6 = @popCount(x);
83 try expect(std.mem.eql(u6, &expected, &result));84 try expect(std.mem.eql(u6, &expected, &result));
84 }85 }
85 {86 {
86 var x: @Vector(8, i16) = [1]i16{-1} ** 8;87 var x: @Vector(8, i16) = [1]i16{-1} ** 8;
87 const expected = [1]u5{16} ** 8;88 const expected = [1]u5{16} ** 8;
88 const result: [8]u5 = @popCount(i16, x);89 const result: [8]u5 = @popCount(x);
89 try expect(std.mem.eql(u5, &expected, &result));90 try expect(std.mem.eql(u5, &expected, &result));
90 }91 }
91}92}
test/behavior/struct.zig+2-2
...@@ -147,7 +147,7 @@ test "fn call of struct field" {...@@ -147,7 +147,7 @@ test "fn call of struct field" {
147 return 13;147 return 13;
148 }148 }
149149
150 fn callStructField(foo: Foo) i32 {150 fn callStructField(comptime foo: Foo) i32 {
151 return foo.ptr();151 return foo.ptr();
152 }152 }
153 };153 };
...@@ -963,7 +963,7 @@ test "tuple assigned to variable" {...@@ -963,7 +963,7 @@ test "tuple assigned to variable" {
963963
964test "comptime struct field" {964test "comptime struct field" {
965 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO965 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
966 if (builtin.stage2_arch == .arm) return error.SkipZigTest; // TODO966 if (builtin.cpu.arch == .arm) return error.SkipZigTest; // TODO
967967
968 const T = struct {968 const T = struct {
969 a: i32,969 a: i32,
test/behavior/switch.zig+1
...@@ -531,6 +531,7 @@ test "switch with null and T peer types and inferred result location type" {...@@ -531,6 +531,7 @@ test "switch with null and T peer types and inferred result location type" {
531test "switch prongs with cases with identical payload types" {531test "switch prongs with cases with identical payload types" {
532 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO532 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
533 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO533 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
534 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
534535
535 const Union = union(enum) {536 const Union = union(enum) {
536 A: usize,537 A: usize,
test/behavior/tuple.zig+38
...@@ -290,3 +290,41 @@ test "coerce tuple to tuple" {...@@ -290,3 +290,41 @@ test "coerce tuple to tuple" {
290 };290 };
291 try S.foo(.{123});291 try S.foo(.{123});
292}292}
293
294test "tuple type with void field" {
295 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
296 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
297 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
298 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
299
300 const T = std.meta.Tuple(&[_]type{void});
301 const x = T{{}};
302 try expect(@TypeOf(x[0]) == void);
303}
304
305test "zero sized struct in tuple handled correctly" {
306 const State = struct {
307 const Self = @This();
308 data: @Type(.{
309 .Struct = .{
310 .is_tuple = true,
311 .layout = .Auto,
312 .decls = &.{},
313 .fields = &.{.{
314 .name = "0",
315 .field_type = struct {},
316 .default_value = null,
317 .is_comptime = false,
318 .alignment = 0,
319 }},
320 },
321 }),
322
323 pub fn do(this: Self) usize {
324 return @sizeOf(@TypeOf(this));
325 }
326 };
327
328 var s: State = undefined;
329 try expect(s.do() == 0);
330}
test/behavior/type.zig+5
...@@ -513,6 +513,11 @@ test "Type.Fn" {...@@ -513,6 +513,11 @@ test "Type.Fn" {
513 if (builtin.zig_backend == .stage1) return error.SkipZigTest;513 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
514 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO514 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
515515
516 if (true) {
517 // https://github.com/ziglang/zig/issues/12360
518 return error.SkipZigTest;
519 }
520
516 const some_opaque = opaque {};521 const some_opaque = opaque {};
517 const some_ptr = *some_opaque;522 const some_ptr = *some_opaque;
518 const T = fn (c_int, some_ptr) callconv(.C) void;523 const T = fn (c_int, some_ptr) callconv(.C) void;
test/behavior/type_info.zig+3-1
...@@ -293,6 +293,7 @@ test "type info: struct info" {...@@ -293,6 +293,7 @@ test "type info: struct info" {
293fn testStruct() !void {293fn testStruct() !void {
294 const unpacked_struct_info = @typeInfo(TestStruct);294 const unpacked_struct_info = @typeInfo(TestStruct);
295 try expect(unpacked_struct_info.Struct.is_tuple == false);295 try expect(unpacked_struct_info.Struct.is_tuple == false);
296 try expect(unpacked_struct_info.Struct.backing_integer == null);
296 try expect(unpacked_struct_info.Struct.fields[0].alignment == @alignOf(u32));297 try expect(unpacked_struct_info.Struct.fields[0].alignment == @alignOf(u32));
297 try expect(@ptrCast(*const u32, unpacked_struct_info.Struct.fields[0].default_value.?).* == 4);298 try expect(@ptrCast(*const u32, unpacked_struct_info.Struct.fields[0].default_value.?).* == 4);
298 try expect(mem.eql(u8, "foobar", @ptrCast(*const *const [6:0]u8, unpacked_struct_info.Struct.fields[1].default_value.?).*));299 try expect(mem.eql(u8, "foobar", @ptrCast(*const *const [6:0]u8, unpacked_struct_info.Struct.fields[1].default_value.?).*));
...@@ -315,6 +316,7 @@ fn testPackedStruct() !void {...@@ -315,6 +316,7 @@ fn testPackedStruct() !void {
315 try expect(struct_info == .Struct);316 try expect(struct_info == .Struct);
316 try expect(struct_info.Struct.is_tuple == false);317 try expect(struct_info.Struct.is_tuple == false);
317 try expect(struct_info.Struct.layout == .Packed);318 try expect(struct_info.Struct.layout == .Packed);
319 try expect(struct_info.Struct.backing_integer == u128);
318 try expect(struct_info.Struct.fields.len == 4);320 try expect(struct_info.Struct.fields.len == 4);
319 try expect(struct_info.Struct.fields[0].alignment == 0);321 try expect(struct_info.Struct.fields[0].alignment == 0);
320 try expect(struct_info.Struct.fields[2].field_type == f32);322 try expect(struct_info.Struct.fields[2].field_type == f32);
...@@ -326,7 +328,7 @@ fn testPackedStruct() !void {...@@ -326,7 +328,7 @@ fn testPackedStruct() !void {
326}328}
327329
328const TestPackedStruct = packed struct {330const TestPackedStruct = packed struct {
329 fieldA: usize,331 fieldA: u64,
330 fieldB: void,332 fieldB: void,
331 fieldC: f32,333 fieldC: f32,
332 fieldD: u32 = 4,334 fieldD: u32 = 4,
test/behavior/typename.zig+11
...@@ -235,3 +235,14 @@ test "local variable" {...@@ -235,3 +235,14 @@ test "local variable" {
235 try expectEqualStrings("behavior.typename.test.local variable.Qux", @typeName(Qux));235 try expectEqualStrings("behavior.typename.test.local variable.Qux", @typeName(Qux));
236 try expectEqualStrings("behavior.typename.test.local variable.Quux", @typeName(Quux));236 try expectEqualStrings("behavior.typename.test.local variable.Quux", @typeName(Quux));
237}237}
238
239test "comptime parameters not converted to anytype in function type" {
240 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
241 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
242 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
243 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
244 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
245
246 const T = fn (fn (type) void, void) void;
247 try expectEqualStrings("fn(fn(type) void, void) void", @typeName(T));
248}
test/behavior/union.zig+74-6
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
2const std = @import("std");2const std = @import("std");
3const expect = std.testing.expect;3const expect = std.testing.expect;
4const assert = std.debug.assert;
4const expectEqual = std.testing.expectEqual;5const expectEqual = std.testing.expectEqual;
5const Tag = std.meta.Tag;6const Tag = std.meta.Tag;
67
...@@ -744,7 +745,7 @@ fn setAttribute(attr: Attribute) void {...@@ -744,7 +745,7 @@ fn setAttribute(attr: Attribute) void {
744 _ = attr;745 _ = attr;
745}746}
746747
747fn Setter(attr: Attribute) type {748fn Setter(comptime attr: Attribute) type {
748 return struct {749 return struct {
749 fn set() void {750 fn set() void {
750 setAttribute(attr);751 setAttribute(attr);
...@@ -1065,6 +1066,8 @@ test "@unionInit on union with tag but no fields" {...@@ -1065,6 +1066,8 @@ test "@unionInit on union with tag but no fields" {
1065 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO1066 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1066 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1067 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1067 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1068 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1069 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1070 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
10681071
1069 const S = struct {1072 const S = struct {
1070 const Type = enum(u8) { no_op = 105 };1073 const Type = enum(u8) { no_op = 105 };
...@@ -1079,11 +1082,7 @@ test "@unionInit on union with tag but no fields" {...@@ -1079,11 +1082,7 @@ test "@unionInit on union with tag but no fields" {
1079 };1082 };
10801083
1081 comptime {1084 comptime {
1082 if (builtin.zig_backend == .stage1) {1085 assert(@sizeOf(Data) == 1);
1083 // stage1 gets the wrong answer here
1084 } else {
1085 std.debug.assert(@sizeOf(Data) == 0);
1086 }
1087 }1086 }
10881087
1089 fn doTheTest() !void {1088 fn doTheTest() !void {
...@@ -1256,3 +1255,72 @@ test "return an extern union from C calling convention" {...@@ -1256,3 +1255,72 @@ test "return an extern union from C calling convention" {
1256 });1255 });
1257 try expect(u.d == 4.0);1256 try expect(u.d == 4.0);
1258}1257}
1258
1259test "noreturn field in union" {
1260 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
1261 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1262 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1263 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1264
1265 const U = union(enum) {
1266 a: u32,
1267 b: noreturn,
1268 c: noreturn,
1269 };
1270 var a = U{ .a = 1 };
1271 var count: u32 = 0;
1272 if (a == .b) @compileError("bad");
1273 switch (a) {
1274 .a => count += 1,
1275 .b => |val| {
1276 _ = val;
1277 @compileError("bad");
1278 },
1279 .c => @compileError("bad"),
1280 }
1281 switch (a) {
1282 .a => count += 1,
1283 .b, .c => @compileError("bad"),
1284 }
1285 switch (a) {
1286 .a, .b, .c => {
1287 count += 1;
1288 try expect(a == .a);
1289 },
1290 }
1291 switch (a) {
1292 .a => count += 1,
1293 else => @compileError("bad"),
1294 }
1295 switch (a) {
1296 else => {
1297 count += 1;
1298 try expect(a == .a);
1299 },
1300 }
1301 try expect(count == 5);
1302}
1303
1304test "union and enum field order doesn't match" {
1305 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
1306 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1307 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1308
1309 const MyTag = enum(u32) {
1310 b = 1337,
1311 a = 1666,
1312 };
1313 const MyUnion = union(MyTag) {
1314 a: f32,
1315 b: void,
1316 };
1317 var x: MyUnion = .{ .a = 666 };
1318 switch (x) {
1319 .a => |my_f32| {
1320 try expect(@TypeOf(my_f32) == f32);
1321 },
1322 .b => unreachable,
1323 }
1324 x = .b;
1325 try expect(x == .b);
1326}
test/behavior/vector.zig+40
...@@ -807,6 +807,23 @@ test "vector reduce operation" {...@@ -807,6 +807,23 @@ test "vector reduce operation" {
807 comptime try S.doTheTest();807 comptime try S.doTheTest();
808}808}
809809
810test "vector @reduce comptime" {
811 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
812 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
813 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
814 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
815 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
816 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
817
818 const value = @Vector(4, i32){ 1, -1, 1, -1 };
819 const result = value > @splat(4, @as(i32, 0));
820 // result is { true, false, true, false };
821 comptime try expect(@TypeOf(result) == @Vector(4, bool));
822 const is_all_true = @reduce(.And, result);
823 comptime try expect(@TypeOf(is_all_true) == bool);
824 try expect(is_all_true == false);
825}
826
810test "mask parameter of @shuffle is comptime scope" {827test "mask parameter of @shuffle is comptime scope" {
811 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO828 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
812 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO829 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
...@@ -1094,3 +1111,26 @@ test "loading the second vector from a slice of vectors" {...@@ -1094,3 +1111,26 @@ test "loading the second vector from a slice of vectors" {
1094 var a4 = a[1][1];1111 var a4 = a[1][1];
1095 try expect(a4 == 3);1112 try expect(a4 == 3);
1096}1113}
1114
1115test "array of vectors is copied" {
1116 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1117 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1118 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1119 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1120 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1121
1122 const Vec3 = @Vector(3, i32);
1123 var points = [_]Vec3{
1124 Vec3{ 404, -588, -901 },
1125 Vec3{ 528, -643, 409 },
1126 Vec3{ -838, 591, 734 },
1127 Vec3{ 390, -675, -793 },
1128 Vec3{ -537, -823, -458 },
1129 Vec3{ -485, -357, 347 },
1130 Vec3{ -345, -311, 381 },
1131 Vec3{ -661, -816, -575 },
1132 };
1133 var points2: [20]Vec3 = undefined;
1134 points2[0..points.len].* = points;
1135 try std.testing.expectEqual(points2[6], Vec3{ -345, -311, 381 });
1136}
test/behavior/void.zig+6
...@@ -45,3 +45,9 @@ test "void array as a local variable initializer" {...@@ -45,3 +45,9 @@ test "void array as a local variable initializer" {
45 var x = [_]void{{}} ** 1004;45 var x = [_]void{{}} ** 1004;
46 _ = x[0];46 _ = x[0];
47}47}
48
49const void_constant = {};
50test "reference to void constants" {
51 var a = void_constant;
52 _ = a;
53}
test/cases/compile_errors/AstGen_comptime_known_struct_is_resolved_before_error.zig created+19
...@@ -0,0 +1,19 @@
1const S1 = struct {
2 a: S2,
3};
4const S2 = struct {
5 b: fn () void,
6};
7pub export fn entry() void {
8 var s: S1 = undefined;
9 _ = s;
10}
11
12// error
13// backend=stage2
14// target=native
15//
16// :8:12: error: variable of type 'tmp.S1' must be const or comptime
17// :2:8: note: struct requires comptime because of this field
18// :5:8: note: struct requires comptime because of this field
19// :5:8: note: use '*const fn() void' for a function pointer type
test/cases/compile_errors/access_inactive_union_field_comptime.zig created+23
...@@ -0,0 +1,23 @@
1const Enum = enum(u32) { a, b };
2const TaggedUnion = union(Enum) {
3 b: []const u8,
4 a: []const u8,
5};
6pub export fn entry() void {
7 const result = TaggedUnion{ .b = "b" };
8 _ = result.b;
9 _ = result.a;
10}
11pub export fn entry1() void {
12 const result = TaggedUnion{ .b = "b" };
13 _ = &result.b;
14 _ = &result.a;
15}
16
17// error
18// backend=stage2
19// target=native
20//
21// :9:15: error: access of union field 'a' while field 'b' is active
22// :2:21: note: union declared here
23// :14:16: error: access of union field 'a' while field 'b' is active
test/cases/compile_errors/ambiguous_coercion_of_division_operands.zig created+23
...@@ -0,0 +1,23 @@
1export fn entry1() void {
2 var f: f32 = 54.0 / 5;
3 _ = f;
4}
5export fn entry2() void {
6 var f: f32 = 54 / 5.0;
7 _ = f;
8}
9export fn entry3() void {
10 var f: f32 = 55.0 / 5;
11 _ = f;
12}
13export fn entry4() void {
14 var f: f32 = 55 / 5.0;
15 _ = f;
16}
17
18// error
19// backend=stage2
20// target=native
21//
22// :2:23: error: ambiguous coercion of division operands 'comptime_float' and 'comptime_int'; non-zero remainder '4'
23// :6:21: error: ambiguous coercion of division operands 'comptime_int' and 'comptime_float'; non-zero remainder '4'
test/cases/compile_errors/bogus_method_call_on_slice.zig+8
...@@ -3,9 +3,17 @@ fn f(m: []const u8) void {...@@ -3,9 +3,17 @@ fn f(m: []const u8) void {
3 m.copy(u8, self[0..], m);3 m.copy(u8, self[0..], m);
4}4}
5export fn entry() usize { return @sizeOf(@TypeOf(&f)); }5export fn entry() usize { return @sizeOf(@TypeOf(&f)); }
6pub export fn entry1() void {
7 .{}.bar();
8}
9pub export fn entry2() void {
10 .{ .foo = 1 }.bar();
11}
612
7// error13// error
8// backend=stage214// backend=stage2
9// target=native15// target=native
10//16//
17// :7:8: error: no field or member function named 'bar' in '@TypeOf(.{})'
18// :10:18: error: no field or member function named 'bar' in 'struct{comptime foo: comptime_int = 1}'
11// :3:6: error: no field or member function named 'copy' in '[]const u8'19// :3:6: error: no field or member function named 'copy' in '[]const u8'
test/cases/compile_errors/calling_function_with_naked_calling_convention.zig created+11
...@@ -0,0 +1,11 @@
1export fn entry() void {
2 foo();
3}
4fn foo() callconv(.Naked) void { }
5
6// error
7// backend=llvm
8// target=native
9//
10// :2:5: error: unable to call function with naked calling convention
11// :4:1: note: function declared here
test/cases/compile_errors/compile_time_null_ptr_cast.zig created+11
...@@ -0,0 +1,11 @@
1comptime {
2 var opt_ptr: ?*i32 = null;
3 const ptr = @ptrCast(*i32, opt_ptr);
4 _ = ptr;
5}
6
7// error
8// backend=llvm
9// target=native
10//
11// :3:32: error: null pointer casted to type *i32
test/cases/compile_errors/compile_time_undef_ptr_cast.zig created+11
...@@ -0,0 +1,11 @@
1comptime {
2 var undef_ptr: *i32 = undefined;
3 const ptr = @ptrCast(*i32, undef_ptr);
4 _ = ptr;
5}
6
7// error
8// backend=llvm
9// target=native
10//
11// :3:32: error: use of undefined value here causes undefined behavior
test/cases/compile_errors/comptime_parameter_not_declared_as_such.zig created+24
...@@ -0,0 +1,24 @@
1fn f(_: anytype) void {}
2const T = *const fn (anytype) void;
3fn g(h: T) void {
4 h({});
5}
6pub export fn entry() void {
7 g(f);
8}
9
10pub fn comptimeMod(num: anytype, denom: comptime_int) void {
11 _ = num;
12 _ = denom;
13}
14
15pub export fn entry1() void {
16 _ = comptimeMod(1, 2);
17}
18
19// error
20// backend=stage2
21// target=native
22//
23// :3:6: error: parameter of type '*const fn(anytype) void' must be declared comptime
24// :10:34: error: parameter of type 'comptime_int' must be declared comptime
test/cases/compile_errors/decl_shadows_local.zig created+22
...@@ -0,0 +1,22 @@
1fn foo(a: usize) void {
2 struct {
3 const a = 1;
4 };
5}
6fn bar(a: usize) void {
7 struct {
8 const b = struct {
9 const a = 1;
10 };
11 };
12 _ = a;
13}
14
15// error
16// backend=stage2
17// target=native
18//
19// :3:15: error: redeclaration of function parameter 'a'
20// :1:8: note: previous declaration here
21// :9:19: error: redeclaration of function parameter 'a'
22// :6:8: note: previous declaration here
test/cases/compile_errors/duplicate_field_in_discarded_anon_init.zig created+10
...@@ -0,0 +1,10 @@
1pub export fn entry() void {
2 _ = .{ .a = 0, .a = 1 };
3}
4
5// error
6// backend=stage2
7// target=native
8//
9// :2:21: error: duplicate field
10// :2:13: note: other field here
test/cases/compile_errors/enum_with_0_fields.zig deleted-7
...@@ -1,7 +0,0 @@
1const Foo = enum {};
2
3// error
4// backend=stage2
5// target=native
6//
7// :1:13: error: enum declarations must have at least one tag
test/cases/compile_errors/error_in_typeof_param.zig created+14
...@@ -0,0 +1,14 @@
1fn getSize() usize {
2 return 2;
3}
4pub fn expectEqual(expected: anytype, _: @TypeOf(expected)) !void {}
5pub export fn entry() void {
6 try expectEqual(2, getSize());
7}
8
9// error
10// backend=stage2
11// target=native
12//
13// :6:31: error: unable to resolve comptime value
14// :6:31: note: argument to parameter with comptime only type must be comptime known
test/cases/compile_errors/errors_in_for_loop_bodies_are_propagated.zig+2-2
...@@ -1,10 +1,10 @@...@@ -1,10 +1,10 @@
1pub export fn entry() void {1pub export fn entry() void {
2 var arr: [100]u8 = undefined;2 var arr: [100]u8 = undefined;
3 for (arr) |bits| _ = @popCount(bits);3 for (arr) |bits| _ = @popCount(u8, bits);
4}4}
55
6// error6// error
7// backend=stage27// backend=stage2
8// target=native8// target=native
9//9//
10// :3:26: error: expected 2 arguments, found 110// :3:26: error: expected 1 argument, found 2
test/cases/compile_errors/exact division failure.zig created+10
...@@ -0,0 +1,10 @@
1comptime {
2 const x = @divExact(10, 3);
3 _ = x;
4}
5
6// error
7// backend=llvm
8// target=native
9//
10// :2:15: error: exact division produced remainder
test/cases/compile_errors/explain_why_fn_is_called_at_comptime.zig created+23
...@@ -0,0 +1,23 @@
1const S = struct {
2 fnPtr: fn () void,
3 a: u8,
4};
5fn bar() void {}
6
7fn foo(comptime a: *u8) S {
8 return .{ .fnPtr = bar, .a = a.* };
9}
10pub export fn entry() void {
11 var a: u8 = 1;
12 _ = foo(&a);
13}
14
15// error
16// backend=stage2
17// target=native
18//
19// :12:13: error: unable to resolve comptime value
20// :12:13: note: argument to function being called at comptime must be comptime known
21// :7:25: note: function is being called at comptime because it returns a comptime only type 'tmp.S'
22// :2:12: note: struct requires comptime because of this field
23// :2:12: note: use '*const fn() void' for a function pointer type
test/cases/compile_errors/explain_why_generic_fn_is_called_at_comptime.zig created+22
...@@ -0,0 +1,22 @@
1fn S(comptime PtrTy: type) type {
2 return struct {
3 fnPtr: PtrTy,
4 a: u8,
5 };
6}
7fn bar() void {}
8
9fn foo(a: u8, comptime PtrTy: type) S(PtrTy) {
10 return .{ .fnPtr = bar, .a = a };
11}
12pub export fn entry() void {
13 var a: u8 = 1;
14 _ = foo(a, fn () void);
15}
16// error
17// backend=stage2
18// target=native
19//
20// :14:13: error: unable to resolve comptime value
21// :14:13: note: argument to function being called at comptime must be comptime known
22// :9:38: note: generic function is instantiated with a comptime only return type
test/cases/compile_errors/export_function_with_comptime_parameter.zig+1-1
...@@ -6,4 +6,4 @@ export fn foo(comptime x: anytype, y: i32) i32{...@@ -6,4 +6,4 @@ export fn foo(comptime x: anytype, y: i32) i32{
6// backend=stage26// backend=stage2
7// target=native7// target=native
8//8//
9// :1:15: error: generic parameters not allowed in function with calling convention 'C'9// :1:15: error: comptime parameters not allowed in function with calling convention 'C'
test/cases/compile_errors/extern_function_with_comptime_parameter.zig+3-6
...@@ -12,9 +12,6 @@ comptime { _ = entry2; }...@@ -12,9 +12,6 @@ comptime { _ = entry2; }
12// backend=stage212// backend=stage2
13// target=native13// target=native
14//14//
15// :5:12: error: extern function cannot be generic15// :1:15: error: comptime parameters not allowed in function with calling convention 'C'
16// :5:30: note: function is generic because of this parameter16// :5:30: error: comptime parameters not allowed in function with calling convention 'C'
17// :6:12: error: extern function cannot be generic17// :6:30: error: generic parameters not allowed in function with calling convention 'C'
18// :6:30: note: function is generic because of this parameter
19// :1:8: error: extern function cannot be generic
20// :1:15: note: function is generic because of this parameter
test/cases/compile_errors/float exact division failure.zig created+10
...@@ -0,0 +1,10 @@
1comptime {
2 const x = @divExact(10.0, 3.0);
3 _ = x;
4}
5
6// error
7// backend=llvm
8// target=native
9//
10// :2:15: error: exact division produced remainder
test/cases/compile_errors/function_type_named.zig created+7
...@@ -0,0 +1,7 @@
1const aFunc = fn someFunc(x: i32) void;
2
3// error
4// backend=stage2
5// target=native
6//
7// :1:18: error: function type cannot have a name
test/cases/compile_errors/int_literal_passed_as_variadic_arg.zig created+11
...@@ -0,0 +1,11 @@
1extern fn printf([*:0]const u8, ...) c_int;
2
3pub export fn entry() void {
4 _ = printf("%d %d %d %d\n", 1, 2, 3, 4);
5}
6
7// error
8// backend=stage2
9// target=native
10//
11// :4:33: error: integer and float literals in var args function must be casted
test/cases/compile_errors/invalid_error_union_payload_type.zig created+13
...@@ -0,0 +1,13 @@
1comptime {
2 _ = anyerror!anyopaque;
3}
4comptime {
5 _ = anyerror!anyerror;
6}
7
8// error
9// backend=stage2
10// target=native
11//
12// :2:18: error: error union with payload of opaque type 'anyopaque' not allowed
13// :5:18: error: error union with payload of error set type 'anyerror' not allowed
test/cases/compile_errors/invalid_optional_payload_type.zig created+13
...@@ -0,0 +1,13 @@
1comptime {
2 _ = ?anyopaque;
3}
4comptime {
5 _ = ?@TypeOf(null);
6}
7
8// error
9// backend=stage2
10// target=native
11//
12// :2:10: error: opaque type 'anyopaque' cannot be optional
13// :5:10: error: type '@TypeOf(null)' cannot be optional
test/cases/compile_errors/invalid_underscore_placement_in_int_literal-1.zig+2-2
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1fn main() void {1fn main() void {
2 var bad: u128 = 0010_;2 var bad: u128 = 10_;
3 _ = bad;3 _ = bad;
4}4}
55
...@@ -8,4 +8,4 @@ fn main() void {...@@ -8,4 +8,4 @@ fn main() void {
8// target=native8// target=native
9//9//
10// :2:21: error: expected expression, found 'invalid bytes'10// :2:21: error: expected expression, found 'invalid bytes'
11// :2:26: note: invalid byte: ';'11// :2:24: note: invalid byte: ';'
test/cases/compile_errors/leading_zero_in_integer.zig created+27
...@@ -0,0 +1,27 @@
1export fn entry1() void {
2 const T = u000123;
3 _ = T;
4}
5export fn entry2() void {
6 _ = i0;
7 _ = u0;
8 var x: i01 = 1;
9 _ = x;
10}
11export fn entry3() void {
12 _ = 000123;
13}
14export fn entry4() void {
15 _ = 01;
16}
17
18// error
19// backend=llvm
20// target=native
21//
22// :2:15: error: primitive integer type 'u000123' has leading zero
23// :8:12: error: primitive integer type 'i01' has leading zero
24// :12:9: error: integer literal '000123' has leading zero
25// :12:9: note: use '0o' prefix for octal literals
26// :15:9: error: integer literal '01' has leading zero
27// :15:9: note: use '0o' prefix for octal literals
test/cases/compile_errors/member_function_arg_mismatch.zig created+15
...@@ -0,0 +1,15 @@
1const S = struct {
2 a: u32,
3 fn foo(_: *S, _: u32, _: bool) void {}
4};
5pub export fn entry() void {
6 var s: S = undefined;
7 s.foo(true);
8}
9
10// error
11// backend=stage2
12// target=native
13//
14// :7:6: error: member function expected 2 argument(s), found 1
15// :3:5: note: function declared here
test/cases/compile_errors/non_comptime_param_in_comptime_function.zig created+36
...@@ -0,0 +1,36 @@
1fn F(val: anytype) type {
2 _ = val;
3 return struct {};
4}
5export fn entry() void {
6 _ = F(void{});
7}
8const S = struct {
9 foo: fn () void,
10};
11fn bar(_: u32) S {
12 return undefined;
13}
14export fn entry1() void {
15 _ = bar();
16}
17// prioritize other return type errors
18fn foo(a: u32) callconv(.C) comptime_int {
19 return a;
20}
21export fn entry2() void {
22 _ = foo(1);
23}
24
25// error
26// backend=stage2
27// target=native
28//
29// :1:20: error: function with comptime only return type 'type' requires all parameters to be comptime
30// :1:20: note: types are not available at runtime
31// :1:6: note: param 'val' is required to be comptime
32// :11:16: error: function with comptime only return type 'tmp.S' requires all parameters to be comptime
33// :9:10: note: struct requires comptime because of this field
34// :9:10: note: use '*const fn() void' for a function pointer type
35// :11:8: note: param is required to be comptime
36// :18:29: error: return type 'comptime_int' not allowed in function with calling convention 'C'
test/cases/compile_errors/non_constant_expression_in_array_size.zig+1-1
...@@ -11,4 +11,4 @@ export fn entry() usize { return @offsetOf(Foo, "y"); }...@@ -11,4 +11,4 @@ export fn entry() usize { return @offsetOf(Foo, "y"); }
11// target=native11// target=native
12//12//
13// :5:25: error: cannot load runtime value in comptime block13// :5:25: error: cannot load runtime value in comptime block
14// :2:15: note: called from here14// :2:12: note: called from here
test/cases/compile_errors/noreturn_struct_field.zig created+12
...@@ -0,0 +1,12 @@
1const S = struct {
2 s: noreturn,
3};
4comptime {
5 _ = @typeInfo(S);
6}
7
8// error
9// backend=stage2
10// target=native
11//
12// :2:5: error: struct fields cannot be 'noreturn'
test/cases/compile_errors/not_an_enum_type.zig+1-1
...@@ -17,4 +17,4 @@ const ExpectedVarDeclOrFn = struct {};...@@ -17,4 +17,4 @@ const ExpectedVarDeclOrFn = struct {};
17// target=native17// target=native
18//18//
19// :4:9: error: expected type '@typeInfo(tmp.Error).Union.tag_type.?', found 'type'19// :4:9: error: expected type '@typeInfo(tmp.Error).Union.tag_type.?', found 'type'
20// :8:1: note: enum declared here20// :8:15: note: enum declared here
test/cases/compile_errors/packed_struct_backing_int_wrong.zig created+55
...@@ -0,0 +1,55 @@
1export fn entry1() void {
2 _ = @sizeOf(packed struct(u32) {
3 x: u1,
4 y: u24,
5 z: u4,
6 });
7}
8export fn entry2() void {
9 _ = @sizeOf(packed struct(i31) {
10 x: u4,
11 y: u24,
12 z: u4,
13 });
14}
15
16export fn entry3() void {
17 _ = @sizeOf(packed struct(void) {
18 x: void,
19 });
20}
21
22export fn entry4() void {
23 _ = @sizeOf(packed struct(void) {});
24}
25
26export fn entry5() void {
27 _ = @sizeOf(packed struct(noreturn) {});
28}
29
30export fn entry6() void {
31 _ = @sizeOf(packed struct(f64) {
32 x: u32,
33 y: f32,
34 });
35}
36
37export fn entry7() void {
38 _ = @sizeOf(packed struct(*u32) {
39 x: u4,
40 y: u24,
41 z: u4,
42 });
43}
44
45// error
46// backend=llvm
47// target=native
48//
49// :2:31: error: backing integer type 'u32' has bit size 32 but the struct fields have a total bit size of 29
50// :9:31: error: backing integer type 'i31' has bit size 31 but the struct fields have a total bit size of 32
51// :17:31: error: expected backing integer type, found 'void'
52// :23:31: error: expected backing integer type, found 'void'
53// :27:31: error: expected backing integer type, found 'noreturn'
54// :31:31: error: expected backing integer type, found 'f64'
55// :38:31: error: expected backing integer type, found '*u32'
test/cases/compile_errors/popCount-non-integer.zig+2-2
...@@ -1,9 +1,9 @@...@@ -1,9 +1,9 @@
1export fn entry(x: f32) u32 {1export fn entry(x: f32) u32 {
2 return @popCount(f32, x);2 return @popCount(x);
3}3}
44
5// error5// error
6// backend=stage26// backend=stage2
7// target=native7// target=native
8//8//
9// :2:27: error: expected integer or vector, found 'f32'9// :2:22: error: expected integer or vector, found 'f32'
test/cases/compile_errors/reify_type_for_exhaustive_enum_with_zero_fields.zig deleted-18
...@@ -1,18 +0,0 @@
1const Tag = @Type(.{
2 .Enum = .{
3 .layout = .Auto,
4 .tag_type = u1,
5 .fields = &.{},
6 .decls = &.{},
7 .is_exhaustive = true,
8 },
9});
10export fn entry() void {
11 _ = @intToEnum(Tag, 0);
12}
13
14// error
15// backend=stage2
16// target=native
17//
18// :1:13: error: enums must have at least one field
test/cases/compile_errors/reify_type_for_tagged_union_with_extra_union_field.zig+1-1
...@@ -31,5 +31,5 @@ export fn entry() void {...@@ -31,5 +31,5 @@ export fn entry() void {
31// backend=stage231// backend=stage2
32// target=native32// target=native
33//33//
34// :13:16: error: no field named 'arst' in enum 'tmp.Tag__enum_266'34// :13:16: error: no field named 'arst' in enum 'tmp.Tag'
35// :1:13: note: enum declared here35// :1:13: note: enum declared here
test/cases/compile_errors/reify_type_for_union_with_zero_fields.zig deleted-17
...@@ -1,17 +0,0 @@
1const Untagged = @Type(.{
2 .Union = .{
3 .layout = .Auto,
4 .tag_type = null,
5 .fields = &.{},
6 .decls = &.{},
7 },
8});
9export fn entry() void {
10 _ = Untagged{};
11}
12
13// error
14// backend=stage2
15// target=native
16//
17// :1:18: error: unions must have at least one field
test/cases/compile_errors/runtime_cast_to_union_which_has_non-void_fields.zig-2
...@@ -18,6 +18,4 @@ fn foo(l: Letter) void {...@@ -18,6 +18,4 @@ fn foo(l: Letter) void {
18//18//
19// :11:20: error: runtime coercion from enum 'tmp.Letter' to union 'tmp.Value' which has non-void fields19// :11:20: error: runtime coercion from enum 'tmp.Letter' to union 'tmp.Value' which has non-void fields
20// :3:5: note: field 'A' has type 'i32'20// :3:5: note: field 'A' has type 'i32'
21// :4:5: note: field 'B' has type 'void'
22// :5:5: note: field 'C' has type 'void'
23// :2:15: note: union declared here21// :2:15: note: union declared here
test/cases/compile_errors/self_referential_struct_requires_comptime.zig created+18
...@@ -0,0 +1,18 @@
1const S = struct {
2 a: fn () void,
3 b: *S,
4};
5pub export fn entry() void {
6 var s: S = undefined;
7 _ = s;
8}
9
10
11// error
12// backend=stage2
13// target=native
14//
15// :6:12: error: variable of type 'tmp.S' must be const or comptime
16// :2:8: note: struct requires comptime because of this field
17// :2:8: note: use '*const fn() void' for a function pointer type
18// :3:8: note: struct requires comptime because of this field
test/cases/compile_errors/self_referential_union_requires_comptime.zig created+17
...@@ -0,0 +1,17 @@
1const U = union {
2 a: fn () void,
3 b: *U,
4};
5pub export fn entry() void {
6 var u: U = undefined;
7 _ = u;
8}
9
10// error
11// backend=stage2
12// target=native
13//
14// :6:12: error: variable of type 'tmp.U' must be const or comptime
15// :2:8: note: union requires comptime because of this field
16// :2:8: note: use '*const fn() void' for a function pointer type
17// :3:8: note: union requires comptime because of this field
test/cases/compile_errors/shlExact_shifts_out_1_bits.zig created+10
...@@ -0,0 +1,10 @@
1comptime {
2 const x = @shlExact(@as(u8, 0b01010101), 2);
3 _ = x;
4}
5
6// error
7// backend=llvm
8// target=native
9//
10// :2:15: error: operation caused overflow
test/cases/compile_errors/shrExact_shifts_out_1_bits.zig created+10
...@@ -0,0 +1,10 @@
1comptime {
2 const x = @shrExact(@as(u8, 0b10101010), 2);
3 _ = x;
4}
5
6// error
7// backend=llvm
8// target=native
9//
10// :2:15: error: exact shift shifted out 1 bits
test/cases/compile_errors/signed_integer_division.zig created+9
...@@ -0,0 +1,9 @@
1export fn foo(a: i32, b: i32) i32 {
2 return a / b;
3}
4
5// error
6// backend=stage2
7// target=native
8//
9// :2:14: error: division with 'i32' and 'i32': signed integers must use @divTrunc, @divFloor, or @divExact
test/cases/compile_errors/slice_of_non_array_type.zig created+9
...@@ -0,0 +1,9 @@
1comptime {
2 _ = 1[0..];
3}
4
5// error
6// backend=stage2
7// target=native
8//
9// :2:10: error: slice of non-array type 'comptime_int'
test/cases/compile_errors/stage1/obj/calling_function_with_naked_calling_convention.zig deleted-11
...@@ -1,11 +0,0 @@
1export fn entry() void {
2 foo();
3}
4fn foo() callconv(.Naked) void { }
5
6// error
7// backend=stage1
8// target=native
9//
10// tmp.zig:2:5: error: unable to call function with naked calling convention
11// tmp.zig:4:1: note: declared here
test/cases/compile_errors/stage1/obj/shlExact_shifts_out_1_bits.zig deleted-10
...@@ -1,10 +0,0 @@
1comptime {
2 const x = @shlExact(@as(u8, 0b01010101), 2);
3 _ = x;
4}
5
6// error
7// backend=stage1
8// target=native
9//
10// tmp.zig:2:15: error: operation caused overflow
test/cases/compile_errors/stage1/obj/shrExact_shifts_out_1_bits.zig deleted-10
...@@ -1,10 +0,0 @@
1comptime {
2 const x = @shrExact(@as(u8, 0b10101010), 2);
3 _ = x;
4}
5
6// error
7// backend=stage1
8// target=native
9//
10// tmp.zig:2:15: error: exact shift shifted out 1 bits
test/cases/compile_errors/stage1/obj/signed_integer_division.zig deleted-9
...@@ -1,9 +0,0 @@
1export fn foo(a: i32, b: i32) i32 {
2 return a / b;
3}
4
5// error
6// backend=stage1
7// target=native
8//
9// tmp.zig:2:14: error: division with 'i32' and 'i32': signed integers must use @divTrunc, @divFloor, or @divExact
test/cases/compile_errors/stage1/obj/wrong_number_of_arguments_for_method_fn_call.zig deleted-14
...@@ -1,14 +0,0 @@
1const Foo = struct {
2 fn method(self: *const Foo, a: i32) void {_ = self; _ = a;}
3};
4fn f(foo: *const Foo) void {
5
6 foo.method(1, 2);
7}
8export fn entry() usize { return @sizeOf(@TypeOf(f)); }
9
10// error
11// backend=stage1
12// target=native
13//
14// tmp.zig:6:15: error: expected 2 argument(s), found 3
test/cases/compile_errors/struct_init_passed_to_type_param.zig created+14
...@@ -0,0 +1,14 @@
1const MyStruct = struct { x: i32 };
2
3fn hi(comptime T: type) usize {
4 return @sizeOf(T);
5}
6
7export const value = hi(MyStruct{ .x = 12 });
8
9// error
10// backend=stage2
11// target=native
12//
13// :7:33: error: expected type 'type', found 'tmp.MyStruct'
14// :1:18: note: struct declared here
test/cases/compile_errors/switch_on_slice.zig created+13
...@@ -0,0 +1,13 @@
1pub export fn entry() void {
2 var a: [:0]const u8 = "foo";
3 switch (a) {
4 "--version", "version" => unreachable,
5 else => {},
6 }
7}
8
9// error
10// backend=stage2
11// target=native
12//
13// :3:13: error: switch on type '[:0]const u8'
test/cases/compile_errors/tagName_on_invalid_value_of_non-exhaustive_enum.zig+1-1
...@@ -9,4 +9,4 @@ test "enum" {...@@ -9,4 +9,4 @@ test "enum" {
9// is_test=19// is_test=1
10//10//
11// :3:9: error: no field with value '5' in enum 'test.enum.E'11// :3:9: error: no field with value '5' in enum 'test.enum.E'
12// :1:1: note: declared here12// :2:15: note: declared here
test/cases/compile_errors/union_fields_with_value_assignments.zig deleted-7
...@@ -1,7 +0,0 @@
1const Foo = union {};
2
3// error
4// backend=stage2
5// target=native
6//
7// :1:13: error: union declarations must have at least one tag
test/cases/compile_errors/union_noreturn_field_initialized.zig created+43
...@@ -0,0 +1,43 @@
1pub export fn entry1() void {
2 const U = union(enum) {
3 a: u32,
4 b: noreturn,
5 fn foo(_: @This()) void {}
6 fn bar() noreturn {
7 unreachable;
8 }
9 };
10
11 var a = U{ .b = undefined };
12 _ = a;
13}
14pub export fn entry2() void {
15 const U = union(enum) {
16 a: noreturn,
17 };
18 var u: U = undefined;
19 u = .a;
20}
21pub export fn entry3() void {
22 const U = union(enum) {
23 a: noreturn,
24 b: void,
25 };
26 var e = @typeInfo(U).Union.tag_type.?.a;
27 var u: U = undefined;
28 u = e;
29}
30
31// error
32// backend=stage2
33// target=native
34//
35// :11:21: error: cannot initialize 'noreturn' field of union
36// :4:9: note: field 'b' declared here
37// :2:15: note: union declared here
38// :19:10: error: cannot initialize 'noreturn' field of union
39// :16:9: note: field 'a' declared here
40// :15:15: note: union declared here
41// :28:9: error: runtime coercion from enum '@typeInfo(tmp.entry3.U).Union.tag_type.?' to union 'tmp.entry3.U' which has a 'noreturn' field
42// :23:9: note: 'noreturn' field here
43// :22:15: note: union declared here
test/cases/compile_errors/union_with_0_fields.zig deleted-7
...@@ -1,7 +0,0 @@
1const Foo = union {};
2
3// error
4// backend=stage2
5// target=native
6//
7// :1:13: error: union declarations must have at least one tag
test/cases/compile_errors/using_invalid_types_in_function_call_raises_an_error.zig deleted-11
...@@ -1,11 +0,0 @@
1const MenuEffect = enum {};
2fn func(effect: MenuEffect) void { _ = effect; }
3export fn entry() void {
4 func(MenuEffect.ThisDoesNotExist);
5}
6
7// error
8// backend=stage2
9// target=native
10//
11// :1:20: error: enum declarations must have at least one tag
test/cases/compile_errors/wrong_number_of_arguments.zig+2-1
...@@ -7,4 +7,5 @@ fn c(d: i32, e: i32, f: i32) void { _ = d; _ = e; _ = f; }...@@ -7,4 +7,5 @@ fn c(d: i32, e: i32, f: i32) void { _ = d; _ = e; _ = f; }
7// backend=stage27// backend=stage2
8// target=native8// target=native
9//9//
10// :2:6: error: expected 3 argument(s), found 110// :2:5: error: expected 3 argument(s), found 1
11// :4:1: note: function declared here
test/cases/compile_errors/wrong_number_of_arguments_for_method_fn_call.zig created+15
...@@ -0,0 +1,15 @@
1const Foo = struct {
2 fn method(self: *const Foo, a: i32) void {_ = self; _ = a;}
3};
4fn f(foo: *const Foo) void {
5
6 foo.method(1, 2);
7}
8export fn entry() usize { return @sizeOf(@TypeOf(&f)); }
9
10// error
11// backend=stage2
12// target=native
13//
14// :6:8: error: member function expected 1 argument(s), found 2
15// :2:5: note: function declared here
test/cases/error_in_nested_declaration.zig created+31
...@@ -0,0 +1,31 @@
1const S = struct {
2 b: u32,
3 c: i32,
4 a: struct {
5 pub fn str(_: @This(), extra: []u32) []i32 {
6 return @bitCast([]i32, extra);
7 }
8 },
9};
10
11pub export fn entry() void {
12 var s: S = undefined;
13 _ = s.a.str(undefined);
14}
15
16const S2 = struct {
17 a: [*c]anyopaque,
18};
19
20pub export fn entry2() void {
21 var s: S2 = undefined;
22 _ = s;
23}
24
25// error
26// backend=llvm
27// target=native
28//
29// :17:12: error: C pointers cannot point to opaque types
30// :6:29: error: cannot @bitCast to '[]i32'
31// :6:29: note: use @ptrCast to cast from '[]u32'
test/cases/riscv64-linux/hello_world_with_updates.0.zig deleted-21
...@@ -1,21 +0,0 @@
1pub fn main() void {
2 print();
3}
4
5fn print() void {
6 asm volatile ("ecall"
7 :
8 : [number] "{a7}" (64),
9 [arg1] "{a0}" (1),
10 [arg2] "{a1}" (@ptrToInt("Hello, World!\n")),
11 [arg3] "{a2}" ("Hello, World!\n".len),
12 : "rcx", "r11", "memory"
13 );
14 return;
15}
16
17// run
18// target=riscv64-linux
19//
20// Hello, World!
21//
test/cases/riscv64-linux/hello_world_with_updates.1.zig deleted-27
...@@ -1,27 +0,0 @@
1pub fn main() void {
2 print();
3 print();
4 print();
5 print();
6}
7
8fn print() void {
9 asm volatile ("ecall"
10 :
11 : [number] "{a7}" (64),
12 [arg1] "{a0}" (1),
13 [arg2] "{a1}" (@ptrToInt("Hello, World!\n")),
14 [arg3] "{a2}" ("Hello, World!\n".len),
15 : "rcx", "r11", "memory"
16 );
17 return;
18}
19
20// run
21// target=riscv64-linux
22//
23// Hello, World!
24// Hello, World!
25// Hello, World!
26// Hello, World!
27//
test/cases/safety/@intToEnum - no matching tag value.zig +6-3
...@@ -1,9 +1,11 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = stack_trace;
6 std.process.exit(0);5 if (std.mem.eql(u8, message, "invalid enum value")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
7}9}
8const Foo = enum {10const Foo = enum {
9 A,11 A,
...@@ -18,6 +20,7 @@ fn bar(a: u2) Foo {...@@ -18,6 +20,7 @@ fn bar(a: u2) Foo {
18 return @intToEnum(Foo, a);20 return @intToEnum(Foo, a);
19}21}
20fn baz(_: Foo) void {}22fn baz(_: Foo) void {}
23
21// run24// run
22// backend=stage125// backend=llvm
23// target=native26// target=native
test/cases/safety/@tagName on corrupted enum value.zig +2-1
...@@ -10,6 +10,7 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noretur...@@ -10,6 +10,7 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noretur
1010
11const E = enum(u32) {11const E = enum(u32) {
12 X = 1,12 X = 1,
13 Y = 2,
13};14};
1415
15pub fn main() !void {16pub fn main() !void {
...@@ -21,5 +22,5 @@ pub fn main() !void {...@@ -21,5 +22,5 @@ pub fn main() !void {
21}22}
2223
23// run24// run
24// backend=stage125// backend=llvm
25// target=native26// target=native
test/cases/safety/@tagName on corrupted union value.zig +2-1
...@@ -10,6 +10,7 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noretur...@@ -10,6 +10,7 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noretur
1010
11const U = union(enum(u32)) {11const U = union(enum(u32)) {
12 X: u8,12 X: u8,
13 Y: i8,
13};14};
1415
15pub fn main() !void {16pub fn main() !void {
...@@ -22,5 +23,5 @@ pub fn main() !void {...@@ -22,5 +23,5 @@ pub fn main() !void {
22}23}
2324
24// run25// run
25// backend=stage126// backend=llvm
26// target=native27// target=native
test/cases/safety/cast []u8 to bigger slice of wrong size.zig +6-4
...@@ -1,9 +1,11 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = stack_trace;
6 std.process.exit(0);5 if (std.mem.eql(u8, message, "exact division produced remainder")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
7}9}
810
9pub fn main() !void {11pub fn main() !void {
...@@ -15,5 +17,5 @@ fn widenSlice(slice: []align(1) const u8) []align(1) const i32 {...@@ -15,5 +17,5 @@ fn widenSlice(slice: []align(1) const u8) []align(1) const i32 {
15 return std.mem.bytesAsSlice(i32, slice);17 return std.mem.bytesAsSlice(i32, slice);
16}18}
17// run19// run
18// backend=stage1
19// target=native
\ No newline at end of file
20// backend=llvm
21// target=native
test/cases/safety/empty slice with sentinel out of bounds.zig +2-2
...@@ -2,7 +2,7 @@ const std = @import("std");...@@ -2,7 +2,7 @@ const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = stack_trace;4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "index out of bounds")) {5 if (std.mem.eql(u8, message, "index out of bounds: index 1, len 0")) {
6 std.process.exit(0);6 std.process.exit(0);
7 }7 }
8 std.process.exit(1);8 std.process.exit(1);
...@@ -17,5 +17,5 @@ pub fn main() !void {...@@ -17,5 +17,5 @@ pub fn main() !void {
17}17}
1818
19// run19// run
20// backend=stage120// backend=llvm
21// target=native21// target=native
test/cases/safety/modrem by zero.zig created+20
...@@ -0,0 +1,20 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "division by zero")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10pub fn main() !void {
11 const x = div0(999, 0);
12 _ = x;
13 return error.TestFailed;
14}
15fn div0(a: u32, b: u32) u32 {
16 return a / b;
17}
18// run
19// backend=llvm
20// target=native
test/cases/safety/modulus by zero.zig created+20
...@@ -0,0 +1,20 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "division by zero")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10pub fn main() !void {
11 const x = mod0(999, 0);
12 _ = x;
13 return error.TestFailed;
14}
15fn mod0(a: i32, b: i32) i32 {
16 return @mod(a, b);
17}
18// run
19// backend=llvm
20// target=native
test/cases/safety/out of bounds slice access.zig +3-3
...@@ -2,20 +2,20 @@ const std = @import("std");...@@ -2,20 +2,20 @@ const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = stack_trace;4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "attempt to index out of bound: index 4, len 4")) {5 if (std.mem.eql(u8, message, "index out of bounds: index 4, len 4")) {
6 std.process.exit(0);6 std.process.exit(0);
7 }7 }
8 std.process.exit(1);8 std.process.exit(1);
9}9}
10pub fn main() !void {10pub fn main() !void {
11 const a = [_]i32{1, 2, 3, 4};11 const a = [_]i32{ 1, 2, 3, 4 };
12 baz(bar(&a));12 baz(bar(&a));
13 return error.TestFailed;13 return error.TestFailed;
14}14}
15fn bar(a: []const i32) i32 {15fn bar(a: []const i32) i32 {
16 return a[4];16 return a[4];
17}17}
18fn baz(_: i32) void { }18fn baz(_: i32) void {}
19// run19// run
20// backend=llvm20// backend=llvm
21// target=native21// target=native
test/cases/safety/pointer casting null to non-optional pointer.zig +7-3
...@@ -1,16 +1,20 @@...@@ -1,16 +1,20 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = stack_trace;
6 std.process.exit(0);5 if (std.mem.eql(u8, message, "cast causes pointer to be null")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
7}9}
10
8pub fn main() !void {11pub fn main() !void {
9 var c_ptr: [*c]u8 = 0;12 var c_ptr: [*c]u8 = 0;
10 var zig_ptr: *u8 = c_ptr;13 var zig_ptr: *u8 = c_ptr;
11 _ = zig_ptr;14 _ = zig_ptr;
12 return error.TestFailed;15 return error.TestFailed;
13}16}
17
14// run18// run
15// backend=stage119// backend=llvm
16// target=native20// target=native
test/cases/safety/pointer slice sentinel mismatch.zig +3-3
...@@ -2,14 +2,14 @@ const std = @import("std");...@@ -2,14 +2,14 @@ const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = stack_trace;4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "sentinel mismatch")) {5 if (std.mem.eql(u8, message, "sentinel mismatch: expected 0, found 4")) {
6 std.process.exit(0);6 std.process.exit(0);
7 }7 }
8 std.process.exit(1);8 std.process.exit(1);
9}9}
1010
11pub fn main() !void {11pub fn main() !void {
12 var buf: [4]u8 = undefined;12 var buf: [4]u8 = .{ 1, 2, 3, 4 };
13 const ptr: [*]u8 = &buf;13 const ptr: [*]u8 = &buf;
14 const slice = ptr[0..3 :0];14 const slice = ptr[0..3 :0];
15 _ = slice;15 _ = slice;
...@@ -17,5 +17,5 @@ pub fn main() !void {...@@ -17,5 +17,5 @@ pub fn main() !void {
17}17}
1818
19// run19// run
20// backend=stage120// backend=llvm
21// target=native21// target=native
test/cases/safety/remainder division by negative number.zig deleted-20
...@@ -1,20 +0,0 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "remainder division by zero or negative value")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10pub fn main() !void {
11 const x = div0(999, -1);
12 _ = x;
13 return error.TestFailed;
14}
15fn div0(a: i32, b: i32) i32 {
16 return @rem(a, b);
17}
18// run
19// backend=llvm
20// target=native
test/cases/safety/remainder division by zero.zig created+20
...@@ -0,0 +1,20 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "division by zero")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10pub fn main() !void {
11 const x = rem0(999, 0);
12 _ = x;
13 return error.TestFailed;
14}
15fn rem0(a: i32, b: i32) i32 {
16 return @rem(a, b);
17}
18// run
19// backend=llvm
20// target=native
test/cases/safety/shift left by huge amount.zig +1-1
...@@ -17,5 +17,5 @@ pub fn main() !void {...@@ -17,5 +17,5 @@ pub fn main() !void {
17}17}
1818
19// run19// run
20// backend=stage120// backend=llvm
21// target=native21// target=native
test/cases/safety/shift right by huge amount.zig +1-1
...@@ -17,5 +17,5 @@ pub fn main() !void {...@@ -17,5 +17,5 @@ pub fn main() !void {
17}17}
1818
19// run19// run
20// backend=stage120// backend=llvm
21// target=native21// target=native
test/cases/safety/signed integer division overflow - vectors.zig +6-4
...@@ -1,9 +1,11 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = stack_trace;
6 std.process.exit(0);5 if (std.mem.eql(u8, message, "integer overflow")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
7}9}
810
9pub fn main() !void {11pub fn main() !void {
...@@ -17,5 +19,5 @@ fn div(a: @Vector(4, i16), b: @Vector(4, i16)) @Vector(4, i16) {...@@ -17,5 +19,5 @@ fn div(a: @Vector(4, i16), b: @Vector(4, i16)) @Vector(4, i16) {
17 return @divTrunc(a, b);19 return @divTrunc(a, b);
18}20}
19// run21// run
20// backend=stage1
21// target=native
\ No newline at end of file
22// backend=llvm
23// target=native
test/cases/safety/signed integer division overflow.zig +6-4
...@@ -1,9 +1,11 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = stack_trace;
6 std.process.exit(0);5 if (std.mem.eql(u8, message, "integer overflow")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
7}9}
810
9pub fn main() !void {11pub fn main() !void {
...@@ -15,5 +17,5 @@ fn div(a: i16, b: i16) i16 {...@@ -15,5 +17,5 @@ fn div(a: i16, b: i16) i16 {
15 return @divTrunc(a, b);17 return @divTrunc(a, b);
16}18}
17// run19// run
18// backend=stage1
19// target=native
\ No newline at end of file
20// backend=llvm
21// target=native
test/cases/safety/slice sentinel mismatch - floats.zig +3-3
...@@ -2,19 +2,19 @@ const std = @import("std");...@@ -2,19 +2,19 @@ const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = stack_trace;4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "sentinel mismatch")) {5 if (std.mem.eql(u8, message, "sentinel mismatch: expected 1.20000004e+00, found 4.0e+00")) {
6 std.process.exit(0);6 std.process.exit(0);
7 }7 }
8 std.process.exit(1);8 std.process.exit(1);
9}9}
1010
11pub fn main() !void {11pub fn main() !void {
12 var buf: [4]f32 = undefined;12 var buf: [4]f32 = .{ 1, 2, 3, 4 };
13 const slice = buf[0..3 :1.2];13 const slice = buf[0..3 :1.2];
14 _ = slice;14 _ = slice;
15 return error.TestFailed;15 return error.TestFailed;
16}16}
1717
18// run18// run
19// backend=stage119// backend=llvm
20// target=native20// target=native
test/cases/safety/slice sentinel mismatch - optional pointers.zig +3-3
...@@ -2,19 +2,19 @@ const std = @import("std");...@@ -2,19 +2,19 @@ const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = stack_trace;4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "sentinel mismatch")) {5 if (std.mem.eql(u8, message, "sentinel mismatch: expected null, found i32@10")) {
6 std.process.exit(0);6 std.process.exit(0);
7 }7 }
8 std.process.exit(1);8 std.process.exit(1);
9}9}
1010
11pub fn main() !void {11pub fn main() !void {
12 var buf: [4]?*i32 = undefined;12 var buf: [4]?*i32 = .{ @intToPtr(*i32, 4), @intToPtr(*i32, 8), @intToPtr(*i32, 12), @intToPtr(*i32, 16) };
13 const slice = buf[0..3 :null];13 const slice = buf[0..3 :null];
14 _ = slice;14 _ = slice;
15 return error.TestFailed;15 return error.TestFailed;
16}16}
1717
18// run18// run
19// backend=stage119// backend=llvm
20// target=native20// target=native
test/cases/safety/slice slice sentinel mismatch.zig +3-3
...@@ -2,18 +2,18 @@ const std = @import("std");...@@ -2,18 +2,18 @@ const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = stack_trace;4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "sentinel mismatch")) {5 if (std.mem.eql(u8, message, "sentinel mismatch: expected 0, found 4")) {
6 std.process.exit(0);6 std.process.exit(0);
7 }7 }
8 std.process.exit(1);8 std.process.exit(1);
9}9}
10pub fn main() !void {10pub fn main() !void {
11 var buf: [4]u8 = undefined;11 var buf: [4]u8 = .{ 1, 2, 3, 4 };
12 const slice = buf[0..];12 const slice = buf[0..];
13 const slice2 = slice[0..3 :0];13 const slice2 = slice[0..3 :0];
14 _ = slice2;14 _ = slice2;
15 return error.TestFailed;15 return error.TestFailed;
16}16}
17// run17// run
18// backend=stage118// backend=llvm
19// target=native19// target=native
test/cases/safety/slice with sentinel out of bounds - runtime len.zig created+22
...@@ -0,0 +1,22 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "index out of bounds: index 5, len 4")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10
11pub fn main() !void {
12 var buf = [4]u8{ 'a', 'b', 'c', 0 };
13 const input: []u8 = &buf;
14 var len: usize = 4;
15 const slice = input[0..len :0];
16 _ = slice;
17 return error.TestFailed;
18}
19
20// run
21// backend=llvm
22// target=native
test/cases/safety/slice with sentinel out of bounds.zig +2-2
...@@ -2,7 +2,7 @@ const std = @import("std");...@@ -2,7 +2,7 @@ const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = stack_trace;4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "index out of bounds")) {5 if (std.mem.eql(u8, message, "index out of bounds: index 5, len 4")) {
6 std.process.exit(0);6 std.process.exit(0);
7 }7 }
8 std.process.exit(1);8 std.process.exit(1);
...@@ -17,5 +17,5 @@ pub fn main() !void {...@@ -17,5 +17,5 @@ pub fn main() !void {
17}17}
1818
19// run19// run
20// backend=stage120// backend=llvm
21// target=native21// target=native
test/cases/safety/slicing null C pointer - runtime len.zig created+20
...@@ -0,0 +1,20 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "attempt to use null value")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10
11pub fn main() !void {
12 var ptr: [*c]const u32 = null;
13 var len: usize = 3;
14 var slice = ptr[0..len];
15 _ = slice;
16 return error.TestFailed;
17}
18// run
19// backend=llvm
20// target=native
test/cases/safety/slicing null C pointer.zig +6-4
...@@ -1,9 +1,11 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = stack_trace;
6 std.process.exit(0);5 if (std.mem.eql(u8, message, "attempt to use null value")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
7}9}
810
9pub fn main() !void {11pub fn main() !void {
...@@ -13,5 +15,5 @@ pub fn main() !void {...@@ -13,5 +15,5 @@ pub fn main() !void {
13 return error.TestFailed;15 return error.TestFailed;
14}16}
15// run17// run
16// backend=stage1
17// target=native
\ No newline at end of file
18// backend=llvm
19// target=native
test/cases/safety/switch on corrupted enum value.zig +4-3
...@@ -2,7 +2,7 @@ const std = @import("std");...@@ -2,7 +2,7 @@ const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = stack_trace;4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "reached unreachable code")) {5 if (std.mem.eql(u8, message, "switch on corrupt value")) {
6 std.process.exit(0);6 std.process.exit(0);
7 }7 }
8 std.process.exit(1);8 std.process.exit(1);
...@@ -10,17 +10,18 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noretur...@@ -10,17 +10,18 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noretur
1010
11const E = enum(u32) {11const E = enum(u32) {
12 X = 1,12 X = 1,
13 Y = 2,
13};14};
1415
15pub fn main() !void {16pub fn main() !void {
16 var e: E = undefined;17 var e: E = undefined;
17 @memset(@ptrCast([*]u8, &e), 0x55, @sizeOf(E));18 @memset(@ptrCast([*]u8, &e), 0x55, @sizeOf(E));
18 switch (e) {19 switch (e) {
19 .X => @breakpoint(),20 .X, .Y => @breakpoint(),
20 }21 }
21 return error.TestFailed;22 return error.TestFailed;
22}23}
2324
24// run25// run
25// backend=stage126// backend=llvm
26// target=native27// target=native
test/cases/safety/switch on corrupted union value.zig +4-3
...@@ -2,7 +2,7 @@ const std = @import("std");...@@ -2,7 +2,7 @@ const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = stack_trace;4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "reached unreachable code")) {5 if (std.mem.eql(u8, message, "switch on corrupt value")) {
6 std.process.exit(0);6 std.process.exit(0);
7 }7 }
8 std.process.exit(1);8 std.process.exit(1);
...@@ -10,17 +10,18 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noretur...@@ -10,17 +10,18 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noretur
1010
11const U = union(enum(u32)) {11const U = union(enum(u32)) {
12 X: u8,12 X: u8,
13 Y: i8,
13};14};
1415
15pub fn main() !void {16pub fn main() !void {
16 var u: U = undefined;17 var u: U = undefined;
17 @memset(@ptrCast([*]u8, &u), 0x55, @sizeOf(U));18 @memset(@ptrCast([*]u8, &u), 0x55, @sizeOf(U));
18 switch (u) {19 switch (u) {
19 .X => @breakpoint(),20 .X, .Y => @breakpoint(),
20 }21 }
21 return error.TestFailed;22 return error.TestFailed;
22}23}
2324
24// run25// run
25// backend=stage126// backend=llvm
26// target=native27// target=native
test/cases/safety/zero casted to error.zig created+19
...@@ -0,0 +1,19 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "invalid error code")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10pub fn main() !void {
11 bar(0) catch {};
12 return error.TestFailed;
13}
14fn bar(x: u16) anyerror {
15 return @intToError(x);
16}
17// run
18// backend=llvm
19// target=native
test/compile_errors.zig+19-1
...@@ -184,7 +184,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -184,7 +184,7 @@ pub fn addCases(ctx: *TestContext) !void {
184 }184 }
185185
186 {186 {
187 const case = ctx.obj("argument causes error ", .{});187 const case = ctx.obj("argument causes error", .{});
188 case.backend = .stage2;188 case.backend = .stage2;
189189
190 case.addSourceFile("b.zig",190 case.addSourceFile("b.zig",
...@@ -204,6 +204,24 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -204,6 +204,24 @@ pub fn addCases(ctx: *TestContext) !void {
204 , &[_][]const u8{204 , &[_][]const u8{
205 ":3:12: error: unable to resolve comptime value",205 ":3:12: error: unable to resolve comptime value",
206 ":3:12: note: argument to function being called at comptime must be comptime known",206 ":3:12: note: argument to function being called at comptime must be comptime known",
207 ":2:55: note: generic function is instantiated with a comptime only return type",
208 });
209 }
210
211 {
212 const case = ctx.obj("astgen failure in file struct", .{});
213 case.backend = .stage2;
214
215 case.addSourceFile("b.zig",
216 \\bad
217 );
218
219 case.addError(
220 \\pub export fn entry() void {
221 \\ _ = (@sizeOf(@import("b.zig")));
222 \\}
223 , &[_][]const u8{
224 ":1:1: error: struct field missing type",
207 });225 });
208 }226 }
209227
test/link.zig+32-22
...@@ -23,11 +23,12 @@ pub fn addCases(cases: *tests.StandaloneContext) void {...@@ -23,11 +23,12 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
23 .build_modes = true,23 .build_modes = true,
24 });24 });
2525
26 cases.addBuildFile("test/link/tls/build.zig", .{26 addWasmCases(cases);
27 .build_modes = true,27 addMachOCases(cases);
28 });28}
2929
30 cases.addBuildFile("test/link/wasm/type/build.zig", .{30fn addWasmCases(cases: *tests.StandaloneContext) void {
31 cases.addBuildFile("test/link/wasm/bss/build.zig", .{
31 .build_modes = true,32 .build_modes = true,
32 .requires_stage2 = true,33 .requires_stage2 = true,
33 });34 });
...@@ -42,23 +43,18 @@ pub fn addCases(cases: *tests.StandaloneContext) void {...@@ -42,23 +43,18 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
42 .requires_stage2 = true,43 .requires_stage2 = true,
43 });44 });
4445
45 cases.addBuildFile("test/link/wasm/bss/build.zig", .{46 cases.addBuildFile("test/link/wasm/type/build.zig", .{
46 .build_modes = true,47 .build_modes = true,
47 .requires_stage2 = true,48 .requires_stage2 = true,
48 });49 });
4950
50 cases.addBuildFile("test/link/macho/entry/build.zig", .{51 cases.addBuildFile("test/link/wasm/archive/build.zig", .{
51 .build_modes = true,
52 });
53
54 cases.addBuildFile("test/link/macho/pagezero/build.zig", .{
55 .build_modes = false,
56 });
57
58 cases.addBuildFile("test/link/macho/dylib/build.zig", .{
59 .build_modes = true,52 .build_modes = true,
53 .requires_stage2 = true,
60 });54 });
55}
6156
57fn addMachOCases(cases: *tests.StandaloneContext) void {
62 cases.addBuildFile("test/link/macho/dead_strip/build.zig", .{58 cases.addBuildFile("test/link/macho/dead_strip/build.zig", .{
63 .build_modes = false,59 .build_modes = false,
64 });60 });
...@@ -68,45 +64,59 @@ pub fn addCases(cases: *tests.StandaloneContext) void {...@@ -68,45 +64,59 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
68 .requires_macos_sdk = true,64 .requires_macos_sdk = true,
69 });65 });
7066
71 cases.addBuildFile("test/link/macho/needed_library/build.zig", .{67 cases.addBuildFile("test/link/macho/dylib/build.zig", .{
72 .build_modes = true,68 .build_modes = true,
73 });69 });
7470
75 cases.addBuildFile("test/link/macho/weak_library/build.zig", .{71 cases.addBuildFile("test/link/macho/entry/build.zig", .{
76 .build_modes = true,72 .build_modes = true,
77 });73 });
7874
79 cases.addBuildFile("test/link/macho/needed_framework/build.zig", .{75 cases.addBuildFile("test/link/macho/headerpad/build.zig", .{
80 .build_modes = true,76 .build_modes = true,
81 .requires_macos_sdk = true,77 .requires_macos_sdk = true,
82 });78 });
8379
84 cases.addBuildFile("test/link/macho/weak_framework/build.zig", .{80 cases.addBuildFile("test/link/macho/needed_framework/build.zig", .{
85 .build_modes = true,81 .build_modes = true,
86 .requires_macos_sdk = true,82 .requires_macos_sdk = true,
87 });83 });
8884
89 // Try to build and run an Objective-C executable.85 cases.addBuildFile("test/link/macho/needed_library/build.zig", .{
86 .build_modes = true,
87 });
88
90 cases.addBuildFile("test/link/macho/objc/build.zig", .{89 cases.addBuildFile("test/link/macho/objc/build.zig", .{
91 .build_modes = true,90 .build_modes = true,
92 .requires_macos_sdk = true,91 .requires_macos_sdk = true,
93 });92 });
9493
95 // Try to build and run an Objective-C++ executable.
96 cases.addBuildFile("test/link/macho/objcpp/build.zig", .{94 cases.addBuildFile("test/link/macho/objcpp/build.zig", .{
97 .build_modes = true,95 .build_modes = true,
98 .requires_macos_sdk = true,96 .requires_macos_sdk = true,
99 });97 });
10098
99 cases.addBuildFile("test/link/macho/pagezero/build.zig", .{
100 .build_modes = false,
101 });
102
103 cases.addBuildFile("test/link/macho/search_strategy/build.zig", .{
104 .build_modes = true,
105 });
106
101 cases.addBuildFile("test/link/macho/stack_size/build.zig", .{107 cases.addBuildFile("test/link/macho/stack_size/build.zig", .{
102 .build_modes = true,108 .build_modes = true,
103 });109 });
104110
105 cases.addBuildFile("test/link/macho/search_strategy/build.zig", .{111 cases.addBuildFile("test/link/macho/tls/build.zig", .{
106 .build_modes = true,112 .build_modes = true,
107 });113 });
108114
109 cases.addBuildFile("test/link/macho/headerpad/build.zig", .{115 cases.addBuildFile("test/link/macho/weak_library/build.zig", .{
116 .build_modes = true,
117 });
118
119 cases.addBuildFile("test/link/macho/weak_framework/build.zig", .{
110 .build_modes = true,120 .build_modes = true,
111 .requires_macos_sdk = true,121 .requires_macos_sdk = true,
112 });122 });
test/link/macho/dead_strip/build.zig+5-3
...@@ -4,13 +4,14 @@ const LibExeObjectStep = std.build.LibExeObjStep;...@@ -4,13 +4,14 @@ const LibExeObjectStep = std.build.LibExeObjStep;
44
5pub fn build(b: *Builder) void {5pub fn build(b: *Builder) void {
6 const mode = b.standardReleaseOptions();6 const mode = b.standardReleaseOptions();
7 const target: std.zig.CrossTarget = .{ .os_tag = .macos };
78
8 const test_step = b.step("test", "Test the program");9 const test_step = b.step("test", "Test the program");
9 test_step.dependOn(b.getInstallStep());10 test_step.dependOn(b.getInstallStep());
1011
11 {12 {
12 // Without -dead_strip, we expect `iAmUnused` symbol present13 // Without -dead_strip, we expect `iAmUnused` symbol present
13 const exe = createScenario(b, mode);14 const exe = createScenario(b, mode, target);
1415
15 const check = exe.checkObject(.macho);16 const check = exe.checkObject(.macho);
16 check.checkInSymtab();17 check.checkInSymtab();
...@@ -23,7 +24,7 @@ pub fn build(b: *Builder) void {...@@ -23,7 +24,7 @@ pub fn build(b: *Builder) void {
2324
24 {25 {
25 // With -dead_strip, no `iAmUnused` symbol should be present26 // With -dead_strip, no `iAmUnused` symbol should be present
26 const exe = createScenario(b, mode);27 const exe = createScenario(b, mode, target);
27 exe.link_gc_sections = true;28 exe.link_gc_sections = true;
2829
29 const check = exe.checkObject(.macho);30 const check = exe.checkObject(.macho);
...@@ -36,10 +37,11 @@ pub fn build(b: *Builder) void {...@@ -36,10 +37,11 @@ pub fn build(b: *Builder) void {
36 }37 }
37}38}
3839
39fn createScenario(b: *Builder, mode: std.builtin.Mode) *LibExeObjectStep {40fn createScenario(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarget) *LibExeObjectStep {
40 const exe = b.addExecutable("test", null);41 const exe = b.addExecutable("test", null);
41 exe.addCSourceFile("main.c", &[0][]const u8{});42 exe.addCSourceFile("main.c", &[0][]const u8{});
42 exe.setBuildMode(mode);43 exe.setBuildMode(mode);
44 exe.setTarget(target);
43 exe.linkLibC();45 exe.linkLibC();
44 return exe;46 return exe;
45}47}
test/link/macho/pagezero/build.zig+3-2
...@@ -3,13 +3,14 @@ const Builder = std.build.Builder;...@@ -3,13 +3,14 @@ const Builder = std.build.Builder;
33
4pub fn build(b: *Builder) void {4pub fn build(b: *Builder) void {
5 const mode = b.standardReleaseOptions();5 const mode = b.standardReleaseOptions();
6 const target: std.zig.CrossTarget = .{ .os_tag = .macos };
67
7 const test_step = b.step("test", "Test");8 const test_step = b.step("test", "Test");
8 test_step.dependOn(b.getInstallStep());9 test_step.dependOn(b.getInstallStep());
910
10 {11 {
11 const exe = b.addExecutable("pagezero", null);12 const exe = b.addExecutable("pagezero", null);
12 exe.setTarget(.{ .os_tag = .macos });13 exe.setTarget(target);
13 exe.setBuildMode(mode);14 exe.setBuildMode(mode);
14 exe.addCSourceFile("main.c", &.{});15 exe.addCSourceFile("main.c", &.{});
15 exe.linkLibC();16 exe.linkLibC();
...@@ -29,7 +30,7 @@ pub fn build(b: *Builder) void {...@@ -29,7 +30,7 @@ pub fn build(b: *Builder) void {
2930
30 {31 {
31 const exe = b.addExecutable("no_pagezero", null);32 const exe = b.addExecutable("no_pagezero", null);
32 exe.setTarget(.{ .os_tag = .macos });33 exe.setTarget(target);
33 exe.setBuildMode(mode);34 exe.setBuildMode(mode);
34 exe.addCSourceFile("main.c", &.{});35 exe.addCSourceFile("main.c", &.{});
35 exe.linkLibC();36 exe.linkLibC();
test/link/macho/search_strategy/build.zig+4-4
...@@ -1,17 +1,17 @@...@@ -1,17 +1,17 @@
1const std = @import("std");1const std = @import("std");
2const Builder = std.build.Builder;2const Builder = std.build.Builder;
3const LibExeObjectStep = std.build.LibExeObjStep;3const LibExeObjectStep = std.build.LibExeObjStep;
4const target: std.zig.CrossTarget = .{ .os_tag = .macos };
54
6pub fn build(b: *Builder) void {5pub fn build(b: *Builder) void {
7 const mode = b.standardReleaseOptions();6 const mode = b.standardReleaseOptions();
7 const target: std.zig.CrossTarget = .{ .os_tag = .macos };
88
9 const test_step = b.step("test", "Test");9 const test_step = b.step("test", "Test");
10 test_step.dependOn(b.getInstallStep());10 test_step.dependOn(b.getInstallStep());
1111
12 {12 {
13 // -search_dylibs_first13 // -search_dylibs_first
14 const exe = createScenario(b, mode);14 const exe = createScenario(b, mode, target);
15 exe.search_strategy = .dylibs_first;15 exe.search_strategy = .dylibs_first;
1616
17 const check = exe.checkObject(.macho);17 const check = exe.checkObject(.macho);
...@@ -26,7 +26,7 @@ pub fn build(b: *Builder) void {...@@ -26,7 +26,7 @@ pub fn build(b: *Builder) void {
2626
27 {27 {
28 // -search_paths_first28 // -search_paths_first
29 const exe = createScenario(b, mode);29 const exe = createScenario(b, mode, target);
30 exe.search_strategy = .paths_first;30 exe.search_strategy = .paths_first;
3131
32 const run = std.build.EmulatableRunStep.create(b, "run", exe);32 const run = std.build.EmulatableRunStep.create(b, "run", exe);
...@@ -36,7 +36,7 @@ pub fn build(b: *Builder) void {...@@ -36,7 +36,7 @@ pub fn build(b: *Builder) void {
36 }36 }
37}37}
3838
39fn createScenario(b: *Builder, mode: std.builtin.Mode) *LibExeObjectStep {39fn createScenario(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarget) *LibExeObjectStep {
40 const static = b.addStaticLibrary("a", null);40 const static = b.addStaticLibrary("a", null);
41 static.setTarget(target);41 static.setTarget(target);
42 static.setBuildMode(mode);42 static.setBuildMode(mode);
test/link/macho/stack_size/build.zig+2-1
...@@ -3,12 +3,13 @@ const Builder = std.build.Builder;...@@ -3,12 +3,13 @@ const Builder = std.build.Builder;
33
4pub fn build(b: *Builder) void {4pub fn build(b: *Builder) void {
5 const mode = b.standardReleaseOptions();5 const mode = b.standardReleaseOptions();
6 const target: std.zig.CrossTarget = .{ .os_tag = .macos };
67
7 const test_step = b.step("test", "Test");8 const test_step = b.step("test", "Test");
8 test_step.dependOn(b.getInstallStep());9 test_step.dependOn(b.getInstallStep());
910
10 const exe = b.addExecutable("main", null);11 const exe = b.addExecutable("main", null);
11 exe.setTarget(.{ .os_tag = .macos });12 exe.setTarget(target);
12 exe.setBuildMode(mode);13 exe.setBuildMode(mode);
13 exe.addCSourceFile("main.c", &.{});14 exe.addCSourceFile("main.c", &.{});
14 exe.linkLibC();15 exe.linkLibC();
test/link/macho/tls/a.c created+5
...@@ -0,0 +1,5 @@
1_Thread_local int a;
2
3int getA() {
4 return a;
5}
test/link/macho/tls/build.zig created+22
...@@ -0,0 +1,22 @@
1const std = @import("std");
2const Builder = std.build.Builder;
3
4pub fn build(b: *Builder) void {
5 const mode = b.standardReleaseOptions();
6 const target: std.zig.CrossTarget = .{ .os_tag = .macos };
7
8 const lib = b.addSharedLibrary("a", null, b.version(1, 0, 0));
9 lib.setBuildMode(mode);
10 lib.setTarget(target);
11 lib.addCSourceFile("a.c", &.{});
12 lib.linkLibC();
13
14 const test_exe = b.addTest("main.zig");
15 test_exe.setBuildMode(mode);
16 test_exe.setTarget(target);
17 test_exe.linkLibrary(lib);
18 test_exe.linkLibC();
19
20 const test_step = b.step("test", "Test it");
21 test_step.dependOn(&test_exe.step);
22}
test/link/macho/tls/main.zig created+15
...@@ -0,0 +1,15 @@
1const std = @import("std");
2
3extern threadlocal var a: i32;
4extern fn getA() i32;
5
6fn getA2() i32 {
7 return a;
8}
9
10test {
11 a = 2;
12 try std.testing.expect(getA() == 2);
13 try std.testing.expect(2 == getA2());
14 try std.testing.expect(getA() == getA2());
15}
test/link/tls/a.c deleted-5
...@@ -1,5 +0,0 @@
1_Thread_local int a;
2
3int getA() {
4 return a;
5}
test/link/tls/build.zig deleted-18
...@@ -1,18 +0,0 @@
1const Builder = @import("std").build.Builder;
2
3pub fn build(b: *Builder) void {
4 const mode = b.standardReleaseOptions();
5
6 const lib = b.addSharedLibrary("a", null, b.version(1, 0, 0));
7 lib.setBuildMode(mode);
8 lib.addCSourceFile("a.c", &.{});
9 lib.linkLibC();
10
11 const test_exe = b.addTest("main.zig");
12 test_exe.setBuildMode(mode);
13 test_exe.linkLibrary(lib);
14 test_exe.linkLibC();
15
16 const test_step = b.step("test", "Test it");
17 test_step.dependOn(&test_exe.step);
18}
test/link/tls/main.zig deleted-15
...@@ -1,15 +0,0 @@
1const std = @import("std");
2
3extern threadlocal var a: i32;
4extern fn getA() i32;
5
6fn getA2() i32 {
7 return a;
8}
9
10test {
11 a = 2;
12 try std.testing.expect(getA() == 2);
13 try std.testing.expect(2 == getA2());
14 try std.testing.expect(getA() == getA2());
15}
test/link/wasm/archive/build.zig created+27
...@@ -0,0 +1,27 @@
1const std = @import("std");
2const Builder = std.build.Builder;
3
4pub fn build(b: *Builder) void {
5 const mode = b.standardReleaseOptions();
6
7 const test_step = b.step("test", "Test");
8 test_step.dependOn(b.getInstallStep());
9
10 // The code in question will pull-in compiler-rt,
11 // and therefore link with its archive file.
12 const lib = b.addSharedLibrary("main", "main.zig", .unversioned);
13 lib.setBuildMode(mode);
14 lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding });
15 lib.use_llvm = false;
16 lib.use_stage1 = false;
17 lib.use_lld = false;
18
19 const check = lib.checkObject(.wasm);
20 check.checkStart("Section import");
21 check.checkNext("entries 1"); // __truncsfhf2 should have been resolved, so only 1 import (compiler-rt's memcpy).
22
23 check.checkStart("Section custom");
24 check.checkNext("name __truncsfhf2"); // Ensure it was imported and resolved
25
26 test_step.dependOn(&check.step);
27}
test/link/wasm/archive/main.zig created+6
...@@ -0,0 +1,6 @@
1export fn foo() void {
2 var a: f16 = 2.2;
3 // this will pull-in compiler-rt
4 var b = @trunc(a);
5 _ = b;
6}
test/stack_traces.zig+5-4
...@@ -21,7 +21,8 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -21,7 +21,8 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
21 },21 },
22 .ReleaseSafe = .{22 .ReleaseSafe = .{
23 .exclude_os = .{23 .exclude_os = .{
24 .windows, // segfault24 .windows, // TODO
25 .linux, // defeated by aggressive inlining
25 },26 },
26 .expect = 27 .expect =
27 \\error: TheSkyIsFalling28 \\error: TheSkyIsFalling
...@@ -70,7 +71,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -70,7 +71,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
70 },71 },
71 .ReleaseSafe = .{72 .ReleaseSafe = .{
72 .exclude_os = .{73 .exclude_os = .{
73 .windows, // segfault74 .windows, // TODO
74 },75 },
75 .expect = 76 .expect =
76 \\error: TheSkyIsFalling77 \\error: TheSkyIsFalling
...@@ -136,7 +137,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -136,7 +137,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
136 },137 },
137 .ReleaseSafe = .{138 .ReleaseSafe = .{
138 .exclude_os = .{139 .exclude_os = .{
139 .windows, // segfault140 .windows, // TODO
140 },141 },
141 .expect = 142 .expect =
142 \\error: TheSkyIsFalling143 \\error: TheSkyIsFalling
...@@ -172,7 +173,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -172,7 +173,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
172 cases.addCase(.{173 cases.addCase(.{
173 .exclude_os = .{174 .exclude_os = .{
174 .openbsd, // integer overflow175 .openbsd, // integer overflow
175 .windows,176 .windows, // TODO intermittent failures
176 },177 },
177 .name = "dumpCurrentStackTrace",178 .name = "dumpCurrentStackTrace",
178 .source = 179 .source =
test/stage2/cbe.zig-9
...@@ -704,15 +704,6 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -704,15 +704,6 @@ pub fn addCases(ctx: *TestContext) !void {
704 ":5:9: error: '_' is used to mark an enum as non-exhaustive and cannot be assigned a value",704 ":5:9: error: '_' is used to mark an enum as non-exhaustive and cannot be assigned a value",
705 });705 });
706706
707 case.addError(
708 \\const E1 = enum {};
709 \\export fn foo() void {
710 \\ _ = E1.a;
711 \\}
712 , &.{
713 ":1:12: error: enum declarations must have at least one tag",
714 });
715
716 case.addError(707 case.addError(
717 \\const E1 = enum { a, b, _ };708 \\const E1 = enum { a, b, _ };
718 \\export fn foo() void {709 \\export fn foo() void {
test/standalone.zig+6-2
...@@ -9,6 +9,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void {...@@ -9,6 +9,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
9 if (builtin.zig_backend == .stage1) { // https://github.com/ziglang/zig/issues/60259 if (builtin.zig_backend == .stage1) { // https://github.com/ziglang/zig/issues/6025
10 cases.add("test/standalone/issue_9693/main.zig");10 cases.add("test/standalone/issue_9693/main.zig");
11 }11 }
12 cases.add("test/standalone/issue_12471/main.zig");
12 cases.add("test/standalone/guess_number/main.zig");13 cases.add("test/standalone/guess_number/main.zig");
13 cases.add("test/standalone/main_return_error/error_u8.zig");14 cases.add("test/standalone/main_return_error/error_u8.zig");
14 cases.add("test/standalone/main_return_error/error_u8_non_zero.zig");15 cases.add("test/standalone/main_return_error/error_u8_non_zero.zig");
...@@ -34,13 +35,16 @@ pub fn addCases(cases: *tests.StandaloneContext) void {...@@ -34,13 +35,16 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
34 if (builtin.zig_backend == .stage1) { // https://github.com/ziglang/zig/issues/1219435 if (builtin.zig_backend == .stage1) { // https://github.com/ziglang/zig/issues/12194
35 cases.addBuildFile("test/standalone/issue_9812/build.zig", .{});36 cases.addBuildFile("test/standalone/issue_9812/build.zig", .{});
36 }37 }
37 cases.addBuildFile("test/standalone/issue_11595/build.zig", .{});38 if (builtin.os.tag != .windows) {
39 // https://github.com/ziglang/zig/issues/12419
40 cases.addBuildFile("test/standalone/issue_11595/build.zig", .{});
41 }
38 if (builtin.os.tag != .wasi) {42 if (builtin.os.tag != .wasi) {
39 cases.addBuildFile("test/standalone/load_dynamic_library/build.zig", .{});43 cases.addBuildFile("test/standalone/load_dynamic_library/build.zig", .{});
40 }44 }
41 // C ABI compatibility issue: https://github.com/ziglang/zig/issues/148145 // C ABI compatibility issue: https://github.com/ziglang/zig/issues/1481
42 if (builtin.cpu.arch == .x86_64) {46 if (builtin.cpu.arch == .x86_64) {
43 if (builtin.zig_backend == .stage1) { // https://github.com/ziglang/zig/issues/1222247 if (builtin.zig_backend == .stage1 or builtin.zig_backend == .stage2_llvm) { // https://github.com/ziglang/zig/issues/12222
44 cases.addBuildFile("test/c_abi/build.zig", .{});48 cases.addBuildFile("test/c_abi/build.zig", .{});
45 }49 }
46 }50 }
test/standalone/issue_12471/main.zig created+12
...@@ -0,0 +1,12 @@
1const c = @cImport({
2 @cDefine("FOO", "FOO");
3 @cDefine("BAR", "FOO");
4
5 @cDefine("BAZ", "QUX");
6 @cDefine("QUX", "QUX");
7});
8
9pub fn main() u8 {
10 _ = c;
11 return 0;
12}
test/tests.zig+13-6
...@@ -605,7 +605,6 @@ pub fn addPkgTests(...@@ -605,7 +605,6 @@ pub fn addPkgTests(
605 skip_libc: bool,605 skip_libc: bool,
606 skip_stage1: bool,606 skip_stage1: bool,
607 skip_stage2: bool,607 skip_stage2: bool,
608 is_stage1: bool,
609) *build.Step {608) *build.Step {
610 const step = b.step(b.fmt("test-{s}", .{name}), desc);609 const step = b.step(b.fmt("test-{s}", .{name}), desc);
611610
...@@ -633,14 +632,22 @@ pub fn addPkgTests(...@@ -633,14 +632,22 @@ pub fn addPkgTests(
633632
634 if (test_target.backend) |backend| switch (backend) {633 if (test_target.backend) |backend| switch (backend) {
635 .stage1 => if (skip_stage1) continue,634 .stage1 => if (skip_stage1) continue,
635 .stage2_llvm => {},
636 else => if (skip_stage2) continue,636 else => if (skip_stage2) continue,
637 } else if (is_stage1 and skip_stage1) continue;637 };
638638
639 const want_this_mode = for (modes) |m| {639 const want_this_mode = for (modes) |m| {
640 if (m == test_target.mode) break true;640 if (m == test_target.mode) break true;
641 } else false;641 } else false;
642 if (!want_this_mode) continue;642 if (!want_this_mode) continue;
643643
644 if (test_target.backend) |backend| {
645 if (backend == .stage2_c and builtin.os.tag == .windows) {
646 // https://github.com/ziglang/zig/issues/12415
647 continue;
648 }
649 }
650
644 const libc_prefix = if (test_target.target.getOs().requiresLibC())651 const libc_prefix = if (test_target.target.getOs().requiresLibC())
645 ""652 ""
646 else if (test_target.link_libc)653 else if (test_target.link_libc)
...@@ -917,7 +924,7 @@ pub const StackTracesContext = struct {...@@ -917,7 +924,7 @@ pub const StackTracesContext = struct {
917 pos = marks[i] + delim.len;924 pos = marks[i] + delim.len;
918 }925 }
919 // locate source basename926 // locate source basename
920 pos = mem.lastIndexOfScalar(u8, line[0..marks[0]], fs.path.sep) orelse {927 pos = mem.lastIndexOfAny(u8, line[0..marks[0]], "\\/") orelse {
921 // unexpected pattern: emit raw line and cont928 // unexpected pattern: emit raw line and cont
922 try buf.appendSlice(line);929 try buf.appendSlice(line);
923 try buf.appendSlice("\n");930 try buf.appendSlice("\n");
...@@ -929,9 +936,9 @@ pub const StackTracesContext = struct {...@@ -929,9 +936,9 @@ pub const StackTracesContext = struct {
929 try buf.appendSlice(line[pos + 1 .. marks[2] + delims[2].len]);936 try buf.appendSlice(line[pos + 1 .. marks[2] + delims[2].len]);
930 try buf.appendSlice(" [address]");937 try buf.appendSlice(" [address]");
931 if (self.mode == .Debug) {938 if (self.mode == .Debug) {
932 if (mem.lastIndexOfScalar(u8, line[marks[4]..marks[5]], '.')) |idot| {939 // On certain platforms (windows) or possibly depending on how we choose to link main
933 // On certain platforms (windows) or possibly depending on how we choose to link main940 // the object file extension may be present so we simply strip any extension.
934 // the object file extension may be present so we simply strip any extension.941 if (mem.indexOfScalar(u8, line[marks[4]..marks[5]], '.')) |idot| {
935 try buf.appendSlice(line[marks[3] .. marks[4] + idot]);942 try buf.appendSlice(line[marks[3] .. marks[4] + idot]);
936 try buf.appendSlice(line[marks[5]..]);943 try buf.appendSlice(line[marks[5]..]);
937 } else {944 } else {
test/translate_c.zig+33-9
...@@ -1485,7 +1485,19 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1485,7 +1485,19 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1485 , &[_][]const u8{1485 , &[_][]const u8{
1486 \\pub export fn ptrcast() [*c]f32 {1486 \\pub export fn ptrcast() [*c]f32 {
1487 \\ var a: [*c]c_int = undefined;1487 \\ var a: [*c]c_int = undefined;
1488 \\ return @ptrCast([*c]f32, @alignCast(@import("std").meta.alignment(f32), a));1488 \\ return @ptrCast([*c]f32, @alignCast(@import("std").meta.alignment([*c]f32), a));
1489 \\}
1490 });
1491
1492 cases.add("casting pointer to pointer",
1493 \\float **ptrptrcast() {
1494 \\ int **a;
1495 \\ return (float **)a;
1496 \\}
1497 , &[_][]const u8{
1498 \\pub export fn ptrptrcast() [*c][*c]f32 {
1499 \\ var a: [*c][*c]c_int = undefined;
1500 \\ return @ptrCast([*c][*c]f32, @alignCast(@import("std").meta.alignment([*c][*c]f32), a));
1489 \\}1501 \\}
1490 });1502 });
14911503
...@@ -1509,23 +1521,23 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1509,23 +1521,23 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1509 \\pub export fn test_ptr_cast() void {1521 \\pub export fn test_ptr_cast() void {
1510 \\ var p: ?*anyopaque = undefined;1522 \\ var p: ?*anyopaque = undefined;
1511 \\ {1523 \\ {
1512 \\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@import("std").meta.alignment(u8), p));1524 \\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@import("std").meta.alignment([*c]u8), p));
1513 \\ _ = to_char;1525 \\ _ = to_char;
1514 \\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@import("std").meta.alignment(c_short), p));1526 \\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@import("std").meta.alignment([*c]c_short), p));
1515 \\ _ = to_short;1527 \\ _ = to_short;
1516 \\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@import("std").meta.alignment(c_int), p));1528 \\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@import("std").meta.alignment([*c]c_int), p));
1517 \\ _ = to_int;1529 \\ _ = to_int;
1518 \\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@import("std").meta.alignment(c_longlong), p));1530 \\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@import("std").meta.alignment([*c]c_longlong), p));
1519 \\ _ = to_longlong;1531 \\ _ = to_longlong;
1520 \\ }1532 \\ }
1521 \\ {1533 \\ {
1522 \\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@import("std").meta.alignment(u8), p));1534 \\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@import("std").meta.alignment([*c]u8), p));
1523 \\ _ = to_char;1535 \\ _ = to_char;
1524 \\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@import("std").meta.alignment(c_short), p));1536 \\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@import("std").meta.alignment([*c]c_short), p));
1525 \\ _ = to_short;1537 \\ _ = to_short;
1526 \\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@import("std").meta.alignment(c_int), p));1538 \\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@import("std").meta.alignment([*c]c_int), p));
1527 \\ _ = to_int;1539 \\ _ = to_int;
1528 \\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@import("std").meta.alignment(c_longlong), p));1540 \\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@import("std").meta.alignment([*c]c_longlong), p));
1529 \\ _ = to_longlong;1541 \\ _ = to_longlong;
1530 \\ }1542 \\ }
1531 \\}1543 \\}
...@@ -3830,4 +3842,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -3830,4 +3842,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
3830 , &[_][]const u8{3842 , &[_][]const u8{
3831 \\pub const FOO = "";3843 \\pub const FOO = "";
3832 });3844 });
3845
3846 cases.add("leading zeroes",
3847 \\#define O_RDONLY 00
3848 \\#define HELLO 000
3849 \\#define ZERO 0
3850 \\#define WORLD 00000123
3851 , &[_][]const u8{
3852 \\pub const O_RDONLY = @as(c_int, 0o0);
3853 \\pub const HELLO = @as(c_int, 0o00);
3854 \\pub const ZERO = @as(c_int, 0);
3855 \\pub const WORLD = @as(c_int, 0o0000123);
3856 });
3833}3857}
tools/gen_spirv_spec.zig+2-2
...@@ -299,11 +299,11 @@ fn renderBitEnum(...@@ -299,11 +299,11 @@ fn renderBitEnum(
299 for (enumerants) |enumerant, i| {299 for (enumerants) |enumerant, i| {
300 if (enumerant.value != .bitflag) return error.InvalidRegistry;300 if (enumerant.value != .bitflag) return error.InvalidRegistry;
301 const value = try parseHexInt(enumerant.value.bitflag);301 const value = try parseHexInt(enumerant.value.bitflag);
302 if (@popCount(u32, value) == 0) {302 if (@popCount(value) == 0) {
303 continue; // Skip 'none' items303 continue; // Skip 'none' items
304 }304 }
305305
306 std.debug.assert(@popCount(u32, value) == 1);306 std.debug.assert(@popCount(value) == 1);
307307
308 var bitpos = std.math.log2_int(u32, value);308 var bitpos = std.math.log2_int(u32, value);
309 if (flags_by_bitpos[bitpos]) |*existing| {309 if (flags_by_bitpos[bitpos]) |*existing| {
tools/gen_stubs.zig+1-1
...@@ -389,7 +389,7 @@ fn parseElf(parse: Parse, comptime is_64: bool, comptime endian: builtin.Endian)...@@ -389,7 +389,7 @@ fn parseElf(parse: Parse, comptime is_64: bool, comptime endian: builtin.Endian)
389 const S = struct {389 const S = struct {
390 fn endianSwap(x: anytype) @TypeOf(x) {390 fn endianSwap(x: anytype) @TypeOf(x) {
391 if (endian != native_endian) {391 if (endian != native_endian) {
392 return @byteSwap(@TypeOf(x), x);392 return @byteSwap(x);
393 } else {393 } else {
394 return x;394 return x;
395 }395 }
tools/update_clang_options.zig+32-8
...@@ -352,6 +352,26 @@ const known_options = [_]KnownOpt{...@@ -352,6 +352,26 @@ const known_options = [_]KnownOpt{
352 .name = "fno-stack-check",352 .name = "fno-stack-check",
353 .ident = "no_stack_check",353 .ident = "no_stack_check",
354 },354 },
355 .{
356 .name = "stack-protector",
357 .ident = "stack_protector",
358 },
359 .{
360 .name = "fstack-protector",
361 .ident = "stack_protector",
362 },
363 .{
364 .name = "fno-stack-protector",
365 .ident = "no_stack_protector",
366 },
367 .{
368 .name = "fstack-protector-strong",
369 .ident = "stack_protector",
370 },
371 .{
372 .name = "fstack-protector-all",
373 .ident = "stack_protector",
374 },
355 .{375 .{
356 .name = "MD",376 .name = "MD",
357 .ident = "dep_file",377 .ident = "dep_file",
...@@ -386,11 +406,15 @@ const known_options = [_]KnownOpt{...@@ -386,11 +406,15 @@ const known_options = [_]KnownOpt{
386 },406 },
387 .{407 .{
388 .name = "MM",408 .name = "MM",
389 .ident = "dep_file_mm",409 .ident = "dep_file_to_stdout",
410 },
411 .{
412 .name = "M",
413 .ident = "dep_file_to_stdout",
390 },414 },
391 .{415 .{
392 .name = "user-dependencies",416 .name = "user-dependencies",
393 .ident = "dep_file_mm",417 .ident = "dep_file_to_stdout",
394 },418 },
395 .{419 .{
396 .name = "MMD",420 .name = "MMD",
...@@ -648,9 +672,9 @@ pub fn main() anyerror!void {...@@ -648,9 +672,9 @@ pub fn main() anyerror!void {
648 \\ .name = "{s}",672 \\ .name = "{s}",
649 \\ .syntax = {s},673 \\ .syntax = {s},
650 \\ .zig_equivalent = .{s},674 \\ .zig_equivalent = .{s},
651 \\ .pd1 = {any},675 \\ .pd1 = {},
652 \\ .pd2 = {any},676 \\ .pd2 = {},
653 \\ .psl = {any},677 \\ .psl = {},
654 \\}},678 \\}},
655 \\679 \\
656 , .{ name, final_syntax, ident, pd1, pd2, pslash });680 , .{ name, final_syntax, ident, pd1, pd2, pslash });
...@@ -678,9 +702,9 @@ pub fn main() anyerror!void {...@@ -678,9 +702,9 @@ pub fn main() anyerror!void {
678 \\ .name = "{s}",702 \\ .name = "{s}",
679 \\ .syntax = {s},703 \\ .syntax = {s},
680 \\ .zig_equivalent = .other,704 \\ .zig_equivalent = .other,
681 \\ .pd1 = {any},705 \\ .pd1 = {},
682 \\ .pd2 = {any},706 \\ .pd2 = {},
683 \\ .psl = {any},707 \\ .psl = {},
684 \\}},708 \\}},
685 \\709 \\
686 , .{ name, syntax, pd1, pd2, pslash });710 , .{ name, syntax, pd1, pd2, pslash });