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)
1212endif()
1313
1414if(NOT CMAKE_INSTALL_PREFIX)
15 set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/stage1" CACHE STRING
15 set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/stage3" CACHE STRING
1616 "Directory to install zig to" FORCE)
1717endif()
1818
......@@ -65,6 +65,9 @@ if("${ZIG_VERSION}" STREQUAL "")
6565endif()
6666message(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
6871set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)")
6972set(ZIG_SHARED_LLVM off CACHE BOOL "Prefer linking against shared LLVM libraries")
7073set(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")
333336set(ZIG_CONFIG_ZIG_OUT "${CMAKE_BINARY_DIR}/config.zig")
334337
335338# This is our shim which will be replaced by stage1.zig.
336set(ZIG0_SOURCES
339set(ZIG1_SOURCES
337340 "${CMAKE_SOURCE_DIR}/src/stage1/zig0.cpp"
338341)
339342
......@@ -373,9 +376,9 @@ set(ZIG_CPP_SOURCES
373376 # https://github.com/ziglang/zig/issues/6363
374377 "${CMAKE_SOURCE_DIR}/src/windows_sdk.cpp"
375378)
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.
377380# 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 looking
381# then manually running the build-obj command (see BUILD_ZIG2_ARGS), and then looking
379382# in the zig-cache directory for the compiler-generated list of zig file dependencies.
380383set(ZIG_STAGE2_SOURCES
381384 "${ZIG_CONFIG_ZIG_OUT}"
......@@ -942,40 +945,51 @@ if(MSVC OR MINGW)
942945endif()
943946
944947if("${ZIG_EXECUTABLE}" STREQUAL "")
945 add_executable(zig0 ${ZIG0_SOURCES})
946 set_target_properties(zig0 PROPERTIES
948 add_executable(zig1 ${ZIG1_SOURCES})
949 set_target_properties(zig1 PROPERTIES
947950 COMPILE_FLAGS ${EXE_CFLAGS}
948951 LINK_FLAGS ${EXE_LDFLAGS}
949952 )
950 target_link_libraries(zig0 zigstage1)
953 target_link_libraries(zig1 zigstage1)
951954endif()
952955
953956if(MSVC)
954 set(ZIG1_OBJECT "${CMAKE_BINARY_DIR}/zig1.obj")
957 set(ZIG2_OBJECT "${CMAKE_BINARY_DIR}/zig2.obj")
955958else()
956 set(ZIG1_OBJECT "${CMAKE_BINARY_DIR}/zig1.o")
959 set(ZIG2_OBJECT "${CMAKE_BINARY_DIR}/zig2.o")
957960endif()
958961if("${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)
960965else()
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")
962972endif()
963973if(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")
965980else()
966 set(ZIG1_SINGLE_THREADED_ARG "")
981 set(ZIG_STATIC_ARG "")
967982endif()
968983
969set(BUILD_ZIG1_ARGS
984set(BUILD_ZIG2_ARGS
970985 "src/stage1.zig"
971 -target "${ZIG_TARGET_TRIPLE}"
972 "-mcpu=${ZIG_TARGET_MCPU}"
973 --name zig1
986 --name zig2
974987 --zig-lib-dir "${CMAKE_SOURCE_DIR}/lib"
975 "-femit-bin=${ZIG1_OBJECT}"
988 "-femit-bin=${ZIG2_OBJECT}"
976989 -fcompiler-rt
977 "${ZIG1_RELEASE_ARG}"
978 "${ZIG1_SINGLE_THREADED_ARG}"
990 ${ZIG_SINGLE_THREADED_ARG}
991 -target "${ZIG_TARGET_TRIPLE}"
992 -mcpu "${ZIG_TARGET_MCPU}"
979993 -lc
980994 --pkg-begin build_options "${ZIG_CONFIG_ZIG_OUT}"
981995 --pkg-end
......@@ -985,68 +999,64 @@ set(BUILD_ZIG1_ARGS
985999
9861000if("${ZIG_EXECUTABLE}" STREQUAL "")
9871001 add_custom_command(
988 OUTPUT "${ZIG1_OBJECT}"
989 COMMAND zig0 ${BUILD_ZIG1_ARGS}
990 DEPENDS zig0 "${ZIG_STAGE2_SOURCES}"
991 COMMENT STATUS "Building self-hosted component ${ZIG1_OBJECT}"
992 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
1002 OUTPUT "${ZIG2_OBJECT}"
1003 COMMAND zig1 ${BUILD_ZIG2_ARGS}
1004 DEPENDS zig1 "${ZIG_STAGE2_SOURCES}"
1005 COMMENT STATUS "Building stage2 object ${ZIG2_OBJECT}"
1006 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
9931007 )
994 set(ZIG_EXECUTABLE "${zig_BINARY_DIR}/zig")
9951008 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")
9971012 endif()
9981013else()
9991014 add_custom_command(
1000 OUTPUT "${ZIG1_OBJECT}"
1001 COMMAND "${ZIG_EXECUTABLE}" "build-obj" ${BUILD_ZIG1_ARGS}
1002 DEPENDS ${ZIG_STAGE2_SOURCES}
1003 COMMENT STATUS "Building self-hosted component ${ZIG1_OBJECT}"
1004 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
1015 OUTPUT "${ZIG2_OBJECT}"
1016 COMMAND "${ZIG_EXECUTABLE}" "build-obj" ${BUILD_ZIG2_ARGS}
1017 DEPENDS ${ZIG_STAGE2_SOURCES}
1018 COMMENT STATUS "Building stage2 component ${ZIG2_OBJECT}"
1019 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
10051020 )
10061021endif()
10071022
10081023# 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 PROPERTIES
1026set_target_properties(zig2 PROPERTIES
10121027 COMPILE_FLAGS ${EXE_CFLAGS}
10131028 LINK_FLAGS ${EXE_LDFLAGS}
10141029)
1015target_link_libraries(zig zigstage1)
1030target_link_libraries(zig2 zigstage1)
10161031if(MSVC)
1017 target_link_libraries(zig ntdll.lib)
1032 target_link_libraries(zig2 ntdll.lib)
10181033elseif(MINGW)
1019 target_link_libraries(zig ntdll)
1034 target_link_libraries(zig2 ntdll)
10201035endif()
10211036
1022install(TARGETS zig DESTINATION bin)
1023
1024set(ZIG_SKIP_INSTALL_LIB_FILES off CACHE BOOL
1025 "Disable copying lib/ files to install prefix during the build phase")
1026
1037# Dummy install command so that the "install" target is not missing.
1038# This is redundant from the "stage3" custom target below.
10271039if(NOT ZIG_SKIP_INSTALL_LIB_FILES)
1028 set(ZIG_INSTALL_ARGS "build"
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()
1040 install(FILES "lib/compiler_rt.zig" DESTINATION "lib/zig")
10521041endif()
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;
1515
1616pub fn build(b: *Builder) !void {
1717 b.setPreferredReleaseMode(.ReleaseFast);
18 const test_step = b.step("test", "Run all the tests");
1819 const mode = b.standardReleaseOptions();
1920 const target = b.standardTargetOptions(.{});
2021 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 {
3940 const docs_step = b.step("docs", "Build documentation");
4041 docs_step.dependOn(&docgen_cmd.step);
4142
42 const toolchain_step = b.step("test-toolchain", "Run the tests for the toolchain");
43
4443 var test_cases = b.addTest("src/test.zig");
4544 test_cases.stack_size = stack_size;
4645 test_cases.setBuildMode(mode);
......@@ -64,10 +63,9 @@ pub fn build(b: *Builder) !void {
6463
6564 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;
68 const omit_stage2 = b.option(bool, "omit-stage2", "Do not include stage2 behind a feature flag inside stage1") orelse false;
66 const have_stage1 = b.option(bool, "enable-stage1", "Include the stage1 compiler behind a feature flag") orelse false;
6967 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);
7169 const llvm_has_m68k = b.option(
7270 bool,
7371 "llvm-has-m68k",
......@@ -137,7 +135,7 @@ pub fn build(b: *Builder) !void {
137135 };
138136
139137 const main_file: ?[]const u8 = mf: {
140 if (!is_stage1) break :mf "src/main.zig";
138 if (!have_stage1) break :mf "src/main.zig";
141139 if (use_zig0) break :mf null;
142140 break :mf "src/stage1.zig";
143141 };
......@@ -150,7 +148,7 @@ pub fn build(b: *Builder) !void {
150148 exe.setBuildMode(mode);
151149 exe.setTarget(target);
152150 if (!skip_stage2_tests) {
153 toolchain_step.dependOn(&exe.step);
151 test_step.dependOn(&exe.step);
154152 }
155153
156154 b.default_step.dependOn(&exe.step);
......@@ -248,7 +246,7 @@ pub fn build(b: *Builder) !void {
248246 }
249247 };
250248
251 if (is_stage1) {
249 if (have_stage1) {
252250 const softfloat = b.addStaticLibrary("softfloat", null);
253251 softfloat.setBuildMode(.ReleaseFast);
254252 softfloat.setTarget(target);
......@@ -360,8 +358,7 @@ pub fn build(b: *Builder) !void {
360358 exe_options.addOption(bool, "enable_tracy_callstack", tracy_callstack);
361359 exe_options.addOption(bool, "enable_tracy_allocation", tracy_allocation);
362360 exe_options.addOption(bool, "value_tracing", value_tracing);
363 exe_options.addOption(bool, "is_stage1", is_stage1);
364 exe_options.addOption(bool, "omit_stage2", omit_stage2);
361 exe_options.addOption(bool, "have_stage1", have_stage1);
365362 if (tracy) |tracy_path| {
366363 const client_cpp = fs.path.join(
367364 b.allocator,
......@@ -396,8 +393,7 @@ pub fn build(b: *Builder) !void {
396393 test_cases_options.addOption(bool, "enable_link_snapshots", enable_link_snapshots);
397394 test_cases_options.addOption(bool, "skip_non_native", skip_non_native);
398395 test_cases_options.addOption(bool, "skip_stage1", skip_stage1);
399 test_cases_options.addOption(bool, "is_stage1", is_stage1);
400 test_cases_options.addOption(bool, "omit_stage2", omit_stage2);
396 test_cases_options.addOption(bool, "have_stage1", have_stage1);
401397 test_cases_options.addOption(bool, "have_llvm", enable_llvm);
402398 test_cases_options.addOption(bool, "llvm_has_m68k", llvm_has_m68k);
403399 test_cases_options.addOption(bool, "llvm_has_csky", llvm_has_csky);
......@@ -418,7 +414,7 @@ pub fn build(b: *Builder) !void {
418414 const test_cases_step = b.step("test-cases", "Run the main compiler test cases");
419415 test_cases_step.dependOn(&test_cases.step);
420416 if (!skip_stage2_tests) {
421 toolchain_step.dependOn(test_cases_step);
417 test_step.dependOn(test_cases_step);
422418 }
423419
424420 var chosen_modes: [4]builtin.Mode = undefined;
......@@ -442,11 +438,11 @@ pub fn build(b: *Builder) !void {
442438 const modes = chosen_modes[0..chosen_mode_index];
443439
444440 // 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);
446442 const fmt_step = b.step("test-fmt", "Run zig fmt against build.zig to make sure it works");
447443 fmt_step.dependOn(&fmt_build_zig.step);
448444
449 toolchain_step.dependOn(tests.addPkgTests(
445 test_step.dependOn(tests.addPkgTests(
450446 b,
451447 test_filter,
452448 "test/behavior.zig",
......@@ -457,11 +453,10 @@ pub fn build(b: *Builder) !void {
457453 skip_non_native,
458454 skip_libc,
459455 skip_stage1,
460 omit_stage2,
461 is_stage1,
456 skip_stage2_tests,
462457 ));
463458
464 toolchain_step.dependOn(tests.addPkgTests(
459 test_step.dependOn(tests.addPkgTests(
465460 b,
466461 test_filter,
467462 "lib/compiler_rt.zig",
......@@ -472,11 +467,10 @@ pub fn build(b: *Builder) !void {
472467 skip_non_native,
473468 true, // skip_libc
474469 skip_stage1,
475 omit_stage2 or true, // TODO get these all passing
476 is_stage1,
470 skip_stage2_tests or true, // TODO get these all passing
477471 ));
478472
479 toolchain_step.dependOn(tests.addPkgTests(
473 test_step.dependOn(tests.addPkgTests(
480474 b,
481475 test_filter,
482476 "lib/c.zig",
......@@ -487,37 +481,36 @@ pub fn build(b: *Builder) !void {
487481 skip_non_native,
488482 true, // skip_libc
489483 skip_stage1,
490 omit_stage2 or true, // TODO get these all passing
491 is_stage1,
484 skip_stage2_tests or true, // TODO get these all passing
492485 ));
493486
494 toolchain_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes));
495 toolchain_step.dependOn(tests.addStandaloneTests(
487 test_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes));
488 test_step.dependOn(tests.addStandaloneTests(
496489 b,
497490 test_filter,
498491 modes,
499492 skip_non_native,
500493 enable_macos_sdk,
501494 target,
502 omit_stage2,
495 skip_stage2_tests,
503496 b.enable_darling,
504497 b.enable_qemu,
505498 b.enable_rosetta,
506499 b.enable_wasmtime,
507500 b.enable_wine,
508501 ));
509 toolchain_step.dependOn(tests.addLinkTests(b, test_filter, modes, enable_macos_sdk, omit_stage2));
510 toolchain_step.dependOn(tests.addStackTraceTests(b, test_filter, modes));
511 toolchain_step.dependOn(tests.addCliTests(b, test_filter, modes));
512 toolchain_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes));
513 toolchain_step.dependOn(tests.addTranslateCTests(b, test_filter));
502 test_step.dependOn(tests.addLinkTests(b, test_filter, modes, enable_macos_sdk, skip_stage2_tests));
503 test_step.dependOn(tests.addStackTraceTests(b, test_filter, modes));
504 test_step.dependOn(tests.addCliTests(b, test_filter, modes));
505 test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes));
506 test_step.dependOn(tests.addTranslateCTests(b, test_filter));
514507 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));
516509 }
517510 // 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(
521514 b,
522515 test_filter,
523516 "lib/std/std.zig",
......@@ -528,14 +521,8 @@ pub fn build(b: *Builder) !void {
528521 skip_non_native,
529522 skip_libc,
530523 skip_stage1,
531 omit_stage2 or true, // TODO get these all passing
532 is_stage1,
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);
524 true, // TODO get these all passing
525 ));
539526}
540527
541528const 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
3434mkdir build
3535cd build
3636cmake .. \
37 -DCMAKE_INSTALL_PREFIX="$(pwd)/release" \
37 -DCMAKE_INSTALL_PREFIX="stage3-release" \
3838 -DCMAKE_PREFIX_PATH="$PREFIX" \
3939 -DCMAKE_BUILD_TYPE=Release \
4040 -DZIG_TARGET_TRIPLE="$TARGET" \
4141 -DZIG_TARGET_MCPU="$MCPU" \
42 -DZIG_STATIC=ON \
43 -DZIG_OMIT_STAGE2=ON
42 -DZIG_STATIC=ON
4443
4544# Now cmake will use zig as the C/C++ compiler. We reset the environment variables
4645# so that installation and testing do not get affected by them.
......@@ -49,45 +48,21 @@ unset CXX
4948
5049make $JOBS install
5150
52# Here we rebuild zig but this time using the Zig binary we just now produced to
53# build zig1.o rather than relying on the one built with stage0. See
54# https://github.com/ziglang/zig/issues/6830 for more details.
55cmake .. -DZIG_EXECUTABLE="$(pwd)/release/bin/zig"
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
51stage3-release/bin/zig build test docs \
52 -Denable-macos-sdk \
53 -Dstatic-llvm \
54 --search-prefix "$PREFIX"
8055
8156if [ "${BUILD_REASON}" != "PullRequest" ]; then
82 mv ../LICENSE release/
83 mv ../zig-cache/langref.html release/
84 mv release/bin/zig release/
85 rmdir release/bin
57 mv ../LICENSE stage3-release/
58 mv ../zig-cache/langref.html stage3-release/
59 mv stage3-release/bin/zig stage3-release/
60 rmdir stage3-release/bin
8661
87 VERSION=$(release/zig version)
62 VERSION=$(stage3-release/zig version)
8863 DIRNAME="zig-macos-$ARCH-$VERSION"
8964 TARBALL="$DIRNAME.tar.xz"
90 mv release "$DIRNAME"
65 mv stage3-release "$DIRNAME"
9166 tar cfJ "$TARBALL" "$DIRNAME"
9267
9368 mv "$DOWNLOADSECUREFILE_SECUREFILEPATH" "$HOME/.s3cfg"
ci/azure/pipelines.yml+36-61
......@@ -10,24 +10,13 @@ jobs:
1010 - script: ci/azure/macos_script
1111 name: main
1212 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'
2413- job: BuildWindows
2514 timeoutInMinutes: 360
2615 pool:
2716 vmImage: 'windows-2019'
2817 variables:
2918 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'
3120 ZIG_LLVM_CLANG_LLD_URL: 'https://ziglang.org/deps/${{ variables.ZIG_LLVM_CLANG_LLD_NAME }}.zip'
3221 steps:
3322 - pwsh: |
......@@ -37,10 +26,17 @@ jobs:
3726 displayName: 'Install ZIG/LLVM/CLANG/LLD'
3827
3928 - pwsh: |
40 Set-Variable -Name ZIGBUILDDIR -Value "$(Get-Location)\build"
41 Set-Variable -Name ZIGINSTALLDIR -Value "${ZIGBUILDDIR}\dist"
29 Set-Variable -Name ZIGLIBDIR -Value "$(Get-Location)\lib"
30 Set-Variable -Name ZIGINSTALLDIR -Value "$(Get-Location)\stage3-release"
4231 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
4440 # Make the `zig version` number consistent.
4541 # This will affect the `zig build` command below which uses `git describe`.
4642 git config core.abbrev 9
......@@ -49,64 +45,45 @@ jobs:
4945 git fetch --unshallow # `git describe` won't work on a shallow repo
5046 }
5147
52 # The dev kit zip file that we have here is old, and may be incompatible with
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 `
48 & "$ZIGPREFIXPATH\bin\zig.exe" build `
6249 --prefix "$ZIGINSTALLDIR" `
6350 --search-prefix "$ZIGPREFIXPATH" `
64 -Dstage1 `
65 <# stage2 is omitted until we resolve https://github.com/ziglang/zig/issues/6485 #> `
66 -Domit-stage2 `
51 --zig-lib-dir "$ZIGLIBDIR" `
52 -Denable-stage1 `
6753 -Dstatic-llvm `
6854 -Drelease `
6955 -Dstrip `
7056 -Duse-zig-libcxx `
7157 -Dtarget=$(TARGET)
72
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
58 CheckLastExitCode
8059 name: build
8160 displayName: 'Build'
8261
8362 - 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 is
87 # built with itself and does not gobble as much memory, we can enable these tests.
88 #& "$ZIGINSTALLDIR\bin\zig.exe" test "..\test\behavior.zig" -fno-stage1 -fLLVM -I "..\test" 2>&1
65 function CheckLastExitCode {
66 if (!$?) {
67 exit 1
68 }
69 return 0
70 }
8971
90 & "$ZIGINSTALLDIR\bin\zig.exe" build test-toolchain -Dskip-non-native -Dskip-stage2-tests 2>&1
91 & "$ZIGINSTALLDIR\bin\zig.exe" build test-std -Dskip-non-native 2>&1
72 & "$ZIGINSTALLDIR\bin\zig.exe" build test docs `
73 --search-prefix "$ZIGPREFIXPATH" `
74 -Dstatic-llvm `
75 -Dskip-non-native `
76 -Dskip-stage2-tests
77 CheckLastExitCode
9278 name: test
9379 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
10381 - task: DownloadSecureFile@1
10482 inputs:
10583 name: aws_credentials
10684 secureFile: aws_credentials
10785
10886 - pwsh: |
109 Set-Variable -Name ZIGBUILDDIR -Value "$(Get-Location)\build"
11087 $Env:AWS_SHARED_CREDENTIALS_FILE = "$Env:DOWNLOADSECUREFILE_SECUREFILEPATH"
11188
11289 # Workaround Azure networking issue
......@@ -114,21 +91,20 @@ jobs:
11491 $Env:AWS_EC2_METADATA_DISABLED = "true"
11592 $Env:AWS_REGION = "us-west-2"
11693
117 cd "$ZIGBUILDDIR"
118 mv ../LICENSE dist/
119 mv ../zig-cache/langref.html dist/
120 mv dist/bin/zig.exe dist/
121 rmdir dist/bin
94 mv LICENSE stage3-release/
95 mv zig-cache/langref.html stage3-release/
96 mv stage3-release/bin/zig.exe stage3-release/
97 rmdir stage3-release/bin
12298
12399 # Remove the unnecessary zig dir in $prefix/lib/zig/std/std.zig
124 mv dist/lib/zig dist/lib2
125 rmdir dist/lib
126 mv dist/lib2 dist/lib
100 mv stage3-release/lib/zig stage3-release/lib2
101 rmdir stage3-release/lib
102 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)
129105 Set-Variable -Name DIRNAME -Value "zig-windows-x86_64-$VERSION"
130106 Set-Variable -Name TARBALL -Value "$DIRNAME.zip"
131 mv dist "$DIRNAME"
107 mv stage3-release "$DIRNAME"
132108 7z a "$TARBALL" "$DIRNAME"
133109
134110 aws s3 cp `
......@@ -168,7 +144,6 @@ jobs:
168144- job: OnMasterSuccess
169145 dependsOn:
170146 - BuildMacOS
171 - BuildMacOS_arm64
172147 - BuildWindows
173148 condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
174149 strategy:
ci/drone/drone.yml+21-21
......@@ -13,65 +13,65 @@ steps:
1313 commands:
1414 - ./ci/drone/linux_script_build
1515
16- name: test-1
16- name: behavior
1717 depends_on:
1818 - build
1919 image: ziglang/static-base:llvm14-aarch64-3
2020 commands:
21 - ./ci/drone/linux_script_test 1
21 - ./ci/drone/test_linux_behavior
2222
23- name: test-2
23- name: std_Debug
2424 depends_on:
2525 - build
2626 image: ziglang/static-base:llvm14-aarch64-3
2727 commands:
28 - ./ci/drone/linux_script_test 2
28 - ./ci/drone/test_linux_std_Debug
2929
30- name: test-3
30- name: std_ReleaseSafe
3131 depends_on:
3232 - build
3333 image: ziglang/static-base:llvm14-aarch64-3
3434 commands:
35 - ./ci/drone/linux_script_test 3
35 - ./ci/drone/test_linux_std_ReleaseSafe
3636
37- name: test-4
37- name: std_ReleaseFast
3838 depends_on:
3939 - build
4040 image: ziglang/static-base:llvm14-aarch64-3
4141 commands:
42 - ./ci/drone/linux_script_test 4
42 - ./ci/drone/test_linux_std_ReleaseFast
4343
44- name: test-5
44- name: std_ReleaseSmall
4545 depends_on:
4646 - build
4747 image: ziglang/static-base:llvm14-aarch64-3
4848 commands:
49 - ./ci/drone/linux_script_test 5
49 - ./ci/drone/test_linux_std_ReleaseSmall
5050
51- name: test-6
51- name: misc
5252 depends_on:
5353 - build
5454 image: ziglang/static-base:llvm14-aarch64-3
5555 commands:
56 - ./ci/drone/linux_script_test 6
56 - ./ci/drone/test_linux_misc
5757
58- name: test-7
58- name: cases
5959 depends_on:
6060 - build
6161 image: ziglang/static-base:llvm14-aarch64-3
6262 commands:
63 - ./ci/drone/linux_script_test 7
63 - ./ci/drone/test_linux_cases
6464
6565- name: finalize
6666 depends_on:
6767 - build
68 - test-1
69 - test-2
70 - test-3
71 - test-4
72 - test-5
73 - test-6
74 - test-7
68 - behavior
69 - std_Debug
70 - std_ReleaseSafe
71 - std_ReleaseFast
72 - std_ReleaseSmall
73 - misc
74 - cases
7575 image: ziglang/static-base:llvm14-aarch64-3
7676 environment:
7777 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 @@
11#!/bin/sh
22
3. ./ci/drone/linux_script_base
3set -x
4set -e
45
5# Probe CPU/brand details.
6# TODO: `lscpu` is changing package names in EDGE to `util-linux-misc`
7apk update
8apk add util-linux
9echo "lscpu:"
10lscpu | sed 's,^, : ,'
6ARCH="$(uname -m)"
7INSTALL_PREFIX="$DRONE_WORKSPACE/stage3-release"
8
9export ZIG_GLOBAL_CACHE_DIR="$DRONE_WORKSPACE/zig-cache"
1110
1211PREFIX="/deps/local"
1312ZIG="$PREFIX/bin/zig"
14TARGET="$TRIPLEARCH-linux-musl"
13TARGET="$ARCH-linux-musl"
1514MCPU="baseline"
1615
1716export CC="$ZIG cc -target $TARGET -mcpu=$MCPU"
......@@ -30,8 +29,8 @@ cat <<'ENDFILE' >$PREFIX/bin/ranlib
3029/deps/local/bin/zig ranlib $@
3130ENDFILE
3231
33chmod +x $PREFIX/bin/ar
34chmod +x $PREFIX/bin/ranlib
32chmod +x "$PREFIX/bin/ar"
33chmod +x "$PREFIX/bin/ranlib"
3534
3635# Make the `zig version` number consistent.
3736# This will affect the cmake command below.
......@@ -42,8 +41,8 @@ git fetch --tags
4241mkdir build
4342cd build
4443cmake .. \
45 -DCMAKE_INSTALL_PREFIX="$DISTDIR" \
4644 -DCMAKE_PREFIX_PATH="$PREFIX" \
45 -DCMAKE_INSTALL_PREFIX="$INSTALL_PREFIX" \
4746 -DCMAKE_BUILD_TYPE=Release \
4847 -DCMAKE_AR="$PREFIX/bin/ar" \
4948 -DCMAKE_RANLIB="$PREFIX/bin/ranlib" \
......@@ -57,9 +56,3 @@ cmake .. \
5756unset CC
5857unset CXX
5958samu 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 @@
11#!/bin/sh
22
3. ./ci/drone/linux_script_base
3set -x
4set -e
5
6ARCH="$(uname -m)"
7INSTALL_PREFIX="$DRONE_WORKSPACE/stage3-release"
8
9export ZIG_GLOBAL_CACHE_DIR="$DRONE_WORKSPACE/zig-cache"
410
511if [ -n "$DRONE_PULL_REQUEST" ]; then
612 exit 0
......@@ -12,16 +18,16 @@ pip3 install s3cmd
1218
1319cd build
1420
15mv ../LICENSE "$DISTDIR/"
16mv ../zig-cache/langref.html "$DISTDIR/"
17mv "$DISTDIR/bin/zig" "$DISTDIR/"
18rmdir "$DISTDIR/bin"
21mv ../LICENSE "$INSTALL_PREFIX/"
22mv ../zig-cache/langref.html "$INSTALL_PREFIX/"
23mv "$INSTALL_PREFIX/bin/zig" "$INSTALL_PREFIX/"
24rmdir "$INSTALL_PREFIX/bin"
1925
2026GITBRANCH="$DRONE_BRANCH"
21VERSION="$("$DISTDIR/zig" version)"
22DIRNAME="zig-linux-$TRIPLEARCH-$VERSION"
27VERSION="$("$INSTALL_PREFIX/zig" version)"
28DIRNAME="zig-linux-$ARCH-$VERSION"
2329TARBALL="$DIRNAME.tar.xz"
24mv "$DISTDIR" "$DIRNAME"
30mv "$INSTALL_PREFIX" "$DIRNAME"
2531tar cfJ "$TARBALL" "$DIRNAME"
2632
2733s3cmd put -P --add-header="cache-control: public, max-age=31536000, immutable" "$TARBALL" s3://ziglang.org/builds/
......@@ -35,7 +41,7 @@ echo "{\"tarball\": \"$TARBALL\"," >>$JSONFILE
3541echo "\"shasum\": \"$SHASUM\"," >>$JSONFILE
3642echo "\"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"
3945if [ "$GITBRANCH" = "master" ]; then
4046 # avoid leaking oauth token
4147 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
77sudo pkg install -y cmake py39-s3cmd wget curl jq samurai
88
99ZIGDIR="$(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"
1113PREFIX="$HOME/$CACHE_BASENAME"
1214
1315cd $HOME
......@@ -29,34 +31,47 @@ export TERM=dumb
2931
3032mkdir build
3133cd build
34
35
3236cmake .. \
33 -DCMAKE_BUILD_TYPE=Release \
34 -DCMAKE_PREFIX_PATH=$PREFIX \
35 "-DCMAKE_INSTALL_PREFIX=$(pwd)/release" \
36 -DZIG_STATIC=ON \
37 -DZIG_TARGET_TRIPLE=x86_64-freebsd-gnu \
38 -GNinja
39samu install
40
41# TODO ld.lld: error: undefined symbol: main
42# >>> referenced by crt1_c.c:75 (/usr/src/lib/csu/amd64/crt1_c.c:75)
43# >>> /usr/lib/crt1.o:(_start)
44#release/bin/zig test ../test/behavior.zig -fno-stage1 -fLLVM -I ../test
37 -DCMAKE_BUILD_TYPE=Release \
38 -DCMAKE_PREFIX_PATH=$PREFIX \
39 -DZIG_TARGET_TRIPLE="$TARGET" \
40 -DZIG_TARGET_MCPU="$MCPU" \
41 -DZIG_STATIC=ON \
42 -GNinja
43
44# TODO: eliminate this workaround. Without this, zig does not end up passing
45# -isystem /usr/include when building libc++, resulting in #include <sys/endian.h>
46# "file not found" errors.
47echo "include_dir=/usr/include" >>libc.txt
48echo "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
4657# Here we skip some tests to save time.
47release/bin/zig build test -Dskip-stage1 -Dskip-non-native
58stage3/bin/zig build test docs \
59 -Dstatic-llvm \
60 --search-prefix "$PREFIX" \
61 -Dskip-stage1 \
62 -Dskip-non-native
4863
4964if [ -f ~/.s3cfg ]; then
50 mv ../LICENSE release/
51 mv ../zig-cache/langref.html release/
52 mv release/bin/zig release/
53 rmdir release/bin
65 mv ../LICENSE stage3/
66 mv ../zig-cache/langref.html stage3/
67 mv stage3/bin/zig stage3/
68 rmdir stage3/bin
5469
5570 GITBRANCH=$(basename $GITHUB_REF)
56 VERSION=$(release/zig version)
71 VERSION=$(stage3/zig version)
5772 DIRNAME="zig-freebsd-x86_64-$VERSION"
5873 TARBALL="$DIRNAME.tar.xz"
59 mv release "$DIRNAME"
74 mv stage3 "$DIRNAME"
6075 tar cfJ "$TARBALL" "$DIRNAME"
6176
6277 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"
100100CIDIR="$(pwd)"
101101
102102cd "$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
103124git clone --depth 1 git@github.com:ziglang/www.ziglang.org.git
104125cd www.ziglang.org
105126WWWDIR="$(pwd)"
......@@ -108,12 +129,6 @@ $S3CMD put -P --no-mime-magic --add-header="cache-control: public, max-age=31536
108129
109130cd "$WWWDIR"
110131cp "$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
116132git add data/releases.json
117git add content/
118git commit -m "CI: update releases and docs"
133git commit -m "CI: update releases"
119134git 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:
99 path: /workspace
1010
1111steps:
12- name: test
13 image: ci/debian-amd64:11.1-6
12- name: configure_git
13 image: ci/debian-amd64:11.1-9
1414 commands:
15 - ./ci/zinc/linux_test.sh
15 - ./ci/zinc/configure_git
1616
17- name: package
17- name: test_stage3_debug
1818 depends_on:
19 - test
19 - 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
2060 when:
2161 branch:
2262 - master
2363 event:
2464 - push
25 image: ci/debian-amd64:11.1-6
65 image: ci/debian-amd64:11.1-9
2666 environment:
2767 AWS_ACCESS_KEY_ID:
2868 from_secret: AWS_ACCESS_KEY_ID
2969 AWS_SECRET_ACCESS_KEY:
3070 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:
3180 SRHT_OAUTH_TOKEN:
3281 from_secret: SRHT_OAUTH_TOKEN
3382 commands:
34 - ./ci/zinc/linux_package.sh
83 - ./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 {
285285 link_objects: []const []const u8,
286286 target_str: ?[]const u8,
287287 link_libc: bool,
288 backend_stage1: bool,
288289 link_mode: ?std.builtin.LinkMode,
289290 disable_cache: bool,
290291 verbose_cimport: bool,
......@@ -554,6 +555,7 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {
554555 var link_mode: ?std.builtin.LinkMode = null;
555556 var disable_cache = false;
556557 var verbose_cimport = false;
558 var backend_stage1 = false;
557559
558560 const source_token = while (true) {
559561 const content_tok = try eatToken(tokenizer, Token.Id.Content);
......@@ -586,6 +588,8 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {
586588 link_libc = true;
587589 } else if (mem.eql(u8, end_tag_name, "link_mode_dynamic")) {
588590 link_mode = .Dynamic;
591 } else if (mem.eql(u8, end_tag_name, "backend_stage1")) {
592 backend_stage1 = true;
589593 } else if (mem.eql(u8, end_tag_name, "code_end")) {
590594 _ = try eatToken(tokenizer, Token.Id.BracketClose);
591595 break content_tok;
......@@ -609,6 +613,7 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {
609613 .link_objects = link_objects.toOwnedSlice(),
610614 .target_str = target_str,
611615 .link_libc = link_libc,
616 .backend_stage1 = backend_stage1,
612617 .link_mode = link_mode,
613618 .disable_cache = disable_cache,
614619 .verbose_cimport = verbose_cimport,
......@@ -1187,6 +1192,9 @@ fn printShell(out: anytype, shell_content: []const u8) !void {
11871192 try out.writeAll("</samp></pre></figure>");
11881193}
11891194
1195// Override this to skip to later tests
1196const debug_start_line = 0;
1197
11901198fn genHtml(
11911199 allocator: Allocator,
11921200 tokenizer: *Tokenizer,
......@@ -1266,6 +1274,13 @@ fn genHtml(
12661274 continue;
12671275 }
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
12691284 const raw_source = tokenizer.buffer[code.source_token.start..code.source_token.end];
12701285 const trimmed_raw_source = mem.trim(u8, raw_source, " \n");
12711286 const tmp_source_file_name = try fs.path.join(
......@@ -1311,6 +1326,10 @@ fn genHtml(
13111326 try build_args.append("-lc");
13121327 try shell_out.print("-lc ", .{});
13131328 }
1329 if (code.backend_stage1) {
1330 try build_args.append("-fstage1");
1331 try shell_out.print("-fstage1", .{});
1332 }
13141333 const target = try std.zig.CrossTarget.parse(.{
13151334 .arch_os_abi = code.target_str orelse "native",
13161335 });
......@@ -1443,6 +1462,10 @@ fn genHtml(
14431462 try test_args.append("-lc");
14441463 try shell_out.print("-lc ", .{});
14451464 }
1465 if (code.backend_stage1) {
1466 try test_args.append("-fstage1");
1467 try shell_out.print("-fstage1", .{});
1468 }
14461469 if (code.target_str) |triple| {
14471470 try test_args.appendSlice(&[_][]const u8{ "-target", triple });
14481471 try shell_out.print("-target {s} ", .{triple});
......@@ -1490,6 +1513,14 @@ fn genHtml(
14901513 try shell_out.print("-O {s} ", .{@tagName(code.mode)});
14911514 },
14921515 }
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 }
14931524 const result = try ChildProcess.exec(.{
14941525 .allocator = allocator,
14951526 .argv = test_args.items,
doc/langref.html.in+87-126
......@@ -535,8 +535,8 @@ const Timestamp = struct {
535535 {#header_close#}
536536 {#header_open|Top-Level Doc Comments#}
537537 <p>User documentation that doesn't belong to whatever
538 immediately follows it, like container level documentation, goes
539 in top level doc comments. A top level doc comment is one that
538 immediately follows it, like container-level documentation, goes
539 in top-level doc comments. A top-level doc comment is one that
540540 begins with two slashes and an exclamation point:
541541 {#syntax#}//!{#endsyntax#}.</p>
542542 {#code_begin|syntax|tldoc_comments#}
......@@ -1188,6 +1188,7 @@ test "this will be skipped" {
11881188 (The evented IO mode is enabled using the <kbd>--test-evented-io</kbd> command line parameter.)
11891189 </p>
11901190 {#code_begin|test|async_skip#}
1191 {#backend_stage1#}
11911192const std = @import("std");
11921193
11931194test "async skip test" {
......@@ -1520,7 +1521,8 @@ fn divide(a: i32, b: i32) i32 {
15201521 Zig supports arbitrary bit-width integers, referenced by using
15211522 an identifier of <code>i</code> or <code>u</code> followed by digits. For example, the identifier
15221523 {#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.
15241526 </p>
15251527 {#see_also|Wrapping Operations#}
15261528 {#header_close#}
......@@ -2768,7 +2770,7 @@ test "comptime @intToPtr" {
27682770 }
27692771}
27702772 {#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#}
27722774 {#header_open|volatile#}
27732775 <p>Loads and stores are assumed to not have side effects. If a given load or store
27742776 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;
28622864test "global variable alignment" {
28632865 try expect(@typeInfo(@TypeOf(&foo)).Pointer.alignment == 4);
28642866 try expect(@TypeOf(&foo) == *align(4) u8);
2865 const as_pointer_to_array: *[1]u8 = &foo;
2866 const as_slice: []u8 = as_pointer_to_array;
2867 try expect(@TypeOf(as_slice) == []align(4) u8);
2867 const as_pointer_to_array: *align(4) [1]u8 = &foo;
2868 const as_slice: []align(4) u8 = as_pointer_to_array;
2869 const as_unaligned_slice: []u8 = as_slice;
2870 try expect(as_unaligned_slice[0] == 100);
28682871}
28692872
2870fn derp() align(@sizeOf(usize) * 2) i32 { return 1234; }
2873fn derp() align(@sizeOf(usize) * 2) i32 {
2874 return 1234;
2875}
28712876fn noop1() align(1) void {}
28722877fn noop4() align(4) void {}
28732878
28742879test "function alignment" {
28752880 try expect(derp() == 1234);
2876 try expect(@TypeOf(noop1) == fn() align(1) void);
2877 try expect(@TypeOf(noop4) == fn() align(4) void);
2881 try expect(@TypeOf(noop1) == fn () align(1) void);
2882 try expect(@TypeOf(noop4) == fn () align(4) void);
28782883 noop1();
28792884 noop4();
28802885}
......@@ -3336,6 +3341,7 @@ fn doTheTest() !void {
33363341 Zig allows the address to be taken of a non-byte-aligned field:
33373342 </p>
33383343 {#code_begin|test|pointer_to_non-byte_aligned_field#}
3344 {#backend_stage1#}
33393345const std = @import("std");
33403346const expect = std.testing.expect;
33413347
......@@ -3391,7 +3397,8 @@ fn bar(x: *const u3) u3 {
33913397 <p>
33923398 Pointers to non-ABI-aligned fields share the same address as the other fields within their host integer:
33933399 </p>
3394 {#code_begin|test|pointer_to_non-bit_aligned_field#}
3400 {#code_begin|test|packed_struct_field_addrs#}
3401 {#backend_stage1#}
33953402const std = @import("std");
33963403const expect = std.testing.expect;
33973404
......@@ -3407,7 +3414,7 @@ var bit_field = BitField{
34073414 .c = 3,
34083415};
34093416
3410test "pointer to non-bit-aligned field" {
3417test "pointers of sub-byte-aligned fields share addresses" {
34113418 try expect(@ptrToInt(&bit_field.a) == @ptrToInt(&bit_field.b));
34123419 try expect(@ptrToInt(&bit_field.a) == @ptrToInt(&bit_field.c));
34133420}
......@@ -3438,20 +3445,22 @@ test "pointer to non-bit-aligned field" {
34383445}
34393446 {#code_end#}
34403447 <p>
3441 Packed structs have 1-byte alignment. However if you have an overaligned pointer to a packed struct,
3442 Zig should correctly understand the alignment of fields. However there is
3443 <a href="https://github.com/ziglang/zig/issues/1994">a bug</a>:
3448 Packed structs have the same alignment as their backing integer, however, overaligned
3449 pointers to packed structs can override this:
34443450 </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
34463455const S = packed struct {
34473456 a: u32,
34483457 b: u32,
34493458};
34503459test "overaligned pointer to packed struct" {
3451 var foo: S align(4) = undefined;
3460 var foo: S align(4) = .{ .a = 1, .b = 2 };
34523461 const ptr: *align(4) S = &foo;
34533462 const ptr_to_b: *u32 = &ptr.b;
3454 _ = ptr_to_b;
3463 try expect(ptr_to_b.* == 2);
34553464}
34563465 {#code_end#}
34573466 <p>When this bug is fixed, the above test in the documentation will unexpectedly pass, which will
......@@ -3698,7 +3707,7 @@ test "@tagName" {
36983707 <p>
36993708 By default, enums are not guaranteed to be compatible with the C ABI:
37003709 </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'#}
37023711const Foo = enum { a, b, c };
37033712export fn entry(foo: Foo) void { _ = foo; }
37043713 {#code_end#}
......@@ -4004,7 +4013,7 @@ fn makeNumber() Number {
40044013 This is typically used for type safety when interacting with C code that does not expose struct details.
40054014 Example:
40064015 </p>
4007 {#code_begin|test_err|expected type '*Derp', found '*Wat'#}
4016 {#code_begin|test_err|expected type '*test.Derp', found '*test.Wat'#}
40084017const Derp = opaque {};
40094018const Wat = opaque {};
40104019
......@@ -4203,7 +4212,7 @@ test "switch on tagged union" {
42034212 When a {#syntax#}switch{#endsyntax#} expression does not have an {#syntax#}else{#endsyntax#} clause,
42044213 it must exhaustively list all the possible values. Failure to do so is a compile error:
42054214 </p>
4206 {#code_begin|test_err|not handled in switch#}
4215 {#code_begin|test_err|unhandled enumeration value#}
42074216const Color = enum {
42084217 auto,
42094218 off,
......@@ -5015,8 +5024,8 @@ fn shiftLeftOne(a: u32) callconv(.Inline) u32 {
50155024// Another file can use @import and call sub2
50165025pub fn sub2(a: i8, b: i8) i8 { return a - b; }
50175026
5018// Functions can be used as values and are equivalent to pointers.
5019const call2_op = fn (a: i8, b: i8) i8;
5027// Function pointers are prefixed with `*const `.
5028const call2_op = *const fn (a: i8, b: i8) i8;
50205029fn do_op(fn_call: call2_op, op1: i8, op2: i8) i8 {
50215030 return fn_call(op1, op2);
50225031}
......@@ -5026,17 +5035,9 @@ test "function" {
50265035 try expect(do_op(sub2, 5, 6) == -1);
50275036}
50285037 {#code_end#}
5029 <p>Function values are like pointers:</p>
5030 {#code_begin|obj#}
5031const assert = @import("std").debug.assert;
5032
5033comptime {
5034 assert(@TypeOf(foo) == fn()void);
5035 assert(@sizeOf(fn()void) == @sizeOf(?fn()void));
5036}
5037
5038fn foo() void { }
5039 {#code_end#}
5038 <p>There is a difference between a function <em>body</em> and a function <em>pointer</em>.
5039 Function bodies are {#link|comptime#}-only types while function {#link|Pointers#} may be
5040 runtime-known.</p>
50405041 {#header_open|Pass-by-value Parameters#}
50415042 <p>
50425043 Primitive types such as {#link|Integers#} and {#link|Floats#} passed as parameters
......@@ -6123,10 +6124,11 @@ test "float widening" {
61236124 two choices about the coercion.
61246125 </p>
61256126 <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#}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>
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>
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>
61286129 </ul>
61296130 {#code_begin|test_err#}
6131 {#backend_stage1#}
61306132// Compile time coercion of float to int
61316133test "implicit cast to comptime_int" {
61326134 var f: f32 = 54.0 / 5;
......@@ -6302,19 +6304,6 @@ test "coercion between unions and enums" {
63026304 {#code_end#}
63036305 {#see_also|union|enum#}
63046306 {#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#}
63186307 {#header_open|Type Coercion: undefined#}
63196308 <p>{#link|undefined#} can be cast to any type.</p>
63206309 {#header_close#}
......@@ -6467,7 +6456,6 @@ test "peer type resolution: *const T and ?*T" {
64676456 <li>An {#link|enum#} with only 1 tag.</li>
64686457 <li>A {#link|struct#} with all fields being zero bit types.</li>
64696458 <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>
64716459 </ul>
64726460 <p>
64736461 These types can only ever have one possible value, and thus
......@@ -6527,7 +6515,7 @@ test "turn HashMap into a set with void" {
65276515 <p>
65286516 Expressions of type {#syntax#}void{#endsyntax#} are the only ones whose value can be ignored. For example:
65296517 </p>
6530 {#code_begin|test_err|expression value is ignored#}
6518 {#code_begin|test_err|ignored#}
65316519test "ignoring expression value" {
65326520 foo();
65336521}
......@@ -6553,37 +6541,6 @@ fn foo() i32 {
65536541}
65546542 {#code_end#}
65556543 {#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#}
65876544 {#header_close#}
65886545
65896546 {#header_open|Result Location Semantics#}
......@@ -6666,7 +6623,7 @@ fn gimmeTheBiggerInteger(a: u64, b: u64) u64 {
66666623 <p>
66676624 For example, if we were to introduce another function to the above snippet:
66686625 </p>
6669 {#code_begin|test_err|values of type 'type' must be comptime known#}
6626 {#code_begin|test_err|unable to resolve comptime value#}
66706627fn max(comptime T: type, a: T, b: T) T {
66716628 return if (a > b) a else b;
66726629}
......@@ -6692,7 +6649,7 @@ fn foo(condition: bool) void {
66926649 <p>
66936650 For example:
66946651 </p>
6695 {#code_begin|test_err|operator not allowed for type 'bool'#}
6652 {#code_begin|test_err|operator > not allowed for type 'bool'#}
66966653fn max(comptime T: type, a: T, b: T) T {
66976654 return if (a > b) a else b;
66986655}
......@@ -6837,7 +6794,7 @@ fn performFn(start_value: i32) i32 {
68376794 use a {#syntax#}comptime{#endsyntax#} expression to guarantee that the expression will be evaluated at compile-time.
68386795 If this cannot be accomplished, the compiler will emit an error. For example:
68396796 </p>
6840 {#code_begin|test_err|unable to evaluate constant expression#}
6797 {#code_begin|test_err|comptime call of extern function#}
68416798extern fn exit() noreturn;
68426799
68436800test "foo" {
......@@ -6889,7 +6846,7 @@ test "fibonacci" {
68896846 <p>
68906847 Imagine if we had forgotten the base case of the recursive function and tried to run the tests:
68916848 </p>
6892 {#code_begin|test_err|operation caused overflow#}
6849 {#code_begin|test_err|overflow of integer type#}
68936850const expect = @import("std").testing.expect;
68946851
68956852fn fibonacci(index: u32) u32 {
......@@ -6913,7 +6870,8 @@ test "fibonacci" {
69136870 But what would have happened if we used a signed integer?
69146871 </p>
69156872 {#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
69186876fn fibonacci(index: i32) i32 {
69196877 //if (index < 2) return index;
......@@ -6922,7 +6880,7 @@ fn fibonacci(index: i32) i32 {
69226880
69236881test "fibonacci" {
69246882 comptime {
6925 try expect(fibonacci(7) == 13);
6883 try assert(fibonacci(7) == 13);
69266884 }
69276885}
69286886 {#code_end#}
......@@ -6935,8 +6893,8 @@ test "fibonacci" {
69356893 <p>
69366894 What if we fix the base case, but put the wrong value in the {#syntax#}expect{#endsyntax#} line?
69376895 </p>
6938 {#code_begin|test_err|test "fibonacci"... FAIL (TestUnexpectedResult)#}
6939const expect = @import("std").testing.expect;
6896 {#code_begin|test_err|reached unreachable#}
6897const assert = @import("std").debug.assert;
69406898
69416899fn fibonacci(index: i32) i32 {
69426900 if (index < 2) return index;
......@@ -6945,16 +6903,10 @@ fn fibonacci(index: i32) i32 {
69456903
69466904test "fibonacci" {
69476905 comptime {
6948 try expect(fibonacci(7) == 99999);
6906 try assert(fibonacci(7) == 99999);
69496907 }
69506908}
69516909 {#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
69596911 <p>
69606912 At container level (outside of any function), all expressions are implicitly
......@@ -7280,6 +7232,7 @@ pub fn main() void {
72807232 </p>
72817233 {#code_begin|exe#}
72827234 {#target_linux_x86_64#}
7235 {#backend_stage1#}
72837236pub fn main() noreturn {
72847237 const msg = "hello world\n";
72857238 _ = syscall3(SYS_write, STDOUT_FILENO, @ptrToInt(msg), msg.len);
......@@ -7497,6 +7450,7 @@ test "global assembly" {
74977450 or resumer (in the case of subsequent suspensions).
74987451 </p>
74997452 {#code_begin|test|suspend_no_resume#}
7453 {#backend_stage1#}
75007454const std = @import("std");
75017455const expect = std.testing.expect;
75027456
......@@ -7524,6 +7478,7 @@ fn func() void {
75247478 {#link|@frame#} provides access to the async function frame pointer.
75257479 </p>
75267480 {#code_begin|test|async_suspend_block#}
7481 {#backend_stage1#}
75277482const std = @import("std");
75287483const expect = std.testing.expect;
75297484
......@@ -7562,6 +7517,7 @@ fn testSuspendBlock() void {
75627517 never returns to its resumer and continues executing.
75637518 </p>
75647519 {#code_begin|test|resume_from_suspend#}
7520 {#backend_stage1#}
75657521const std = @import("std");
75667522const expect = std.testing.expect;
75677523
......@@ -7598,6 +7554,7 @@ fn testResumeFromSuspend(my_result: *i32) void {
75987554 and the return value of the async function would be lost.
75997555 </p>
76007556 {#code_begin|test|async_await#}
7557 {#backend_stage1#}
76017558const std = @import("std");
76027559const expect = std.testing.expect;
76037560
......@@ -7642,6 +7599,7 @@ fn func() void {
76427599 return value directly from the target function's frame.
76437600 </p>
76447601 {#code_begin|test|async_await_sequence#}
7602 {#backend_stage1#}
76457603const std = @import("std");
76467604const expect = std.testing.expect;
76477605
......@@ -7695,6 +7653,7 @@ fn seq(c: u8) void {
76957653 {#syntax#}async{#endsyntax#}/{#syntax#}await{#endsyntax#} usage:
76967654 </p>
76977655 {#code_begin|exe|async#}
7656 {#backend_stage1#}
76987657const std = @import("std");
76997658const Allocator = std.mem.Allocator;
77007659
......@@ -7773,6 +7732,7 @@ fn readFile(allocator: Allocator, filename: []const u8) ![]u8 {
77737732 observe the same behavior, with one tiny difference:
77747733 </p>
77757734 {#code_begin|exe|blocking#}
7735 {#backend_stage1#}
77767736const std = @import("std");
77777737const Allocator = std.mem.Allocator;
77787738
......@@ -7910,6 +7870,7 @@ comptime {
79107870 {#syntax#}await{#endsyntax#} will copy the result from {#syntax#}result_ptr{#endsyntax#}.
79117871 </p>
79127872 {#code_begin|test|async_struct_field_fn_pointer#}
7873 {#backend_stage1#}
79137874const std = @import("std");
79147875const expect = std.testing.expect;
79157876
......@@ -8071,8 +8032,8 @@ fn func(y: *i32) void {
80718032 {#header_close#}
80728033
80738034 {#header_open|@byteSwap#}
8074 <pre>{#syntax#}@byteSwap(comptime T: type, operand: T) T{#endsyntax#}</pre>
8075 <p>{#syntax#}T{#endsyntax#} must be an integer type with bit count evenly divisible by 8.</p>
8035 <pre>{#syntax#}@byteSwap(operand: anytype) T{#endsyntax#}</pre>
8036 <p>{#syntax#}@TypeOf(operand){#endsyntax#} must be an integer type or an integer vector type with bit count evenly divisible by 8.</p>
80768037 <p>{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.</p>
80778038 <p>
80788039 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 {
80898050 {#header_close#}
80908051
80918052 {#header_open|@bitReverse#}
8092 <pre>{#syntax#}@bitReverse(comptime T: type, integer: T) T{#endsyntax#}</pre>
8093 <p>{#syntax#}T{#endsyntax#} accepts any integer type.</p>
8053 <pre>{#syntax#}@bitReverse(integer: anytype) T{#endsyntax#}</pre>
8054 <p>{#syntax#}@TypeOf(anytype){#endsyntax#} accepts any integer type or integer vector type.</p>
80948055 <p>
80958056 Reverses the bitpattern of an integer value, including the sign bit if applicable.
80968057 </p>
......@@ -8229,8 +8190,8 @@ pub const CallOptions = struct {
82298190 {#header_close#}
82308191
82318192 {#header_open|@clz#}
8232 <pre>{#syntax#}@clz(comptime T: type, operand: T){#endsyntax#}</pre>
8233 <p>{#syntax#}T{#endsyntax#} must be an integer type.</p>
8193 <pre>{#syntax#}@clz(operand: anytype){#endsyntax#}</pre>
8194 <p>{#syntax#}@TypeOf(operand){#endsyntax#} must be an integer type or an integer vector type.</p>
82348195 <p>{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.</p>
82358196 <p>
82368197 This function counts the number of most-significant (leading in a big-Endian sense) zeroes in an integer.
......@@ -8375,8 +8336,8 @@ test "main" {
83758336 {#header_close#}
83768337
83778338 {#header_open|@ctz#}
8378 <pre>{#syntax#}@ctz(comptime T: type, operand: T){#endsyntax#}</pre>
8379 <p>{#syntax#}T{#endsyntax#} must be an integer type.</p>
8339 <pre>{#syntax#}@ctz(operand: anytype){#endsyntax#}</pre>
8340 <p>{#syntax#}@TypeOf(operand){#endsyntax#} must be an integer type or an integer vector type.</p>
83808341 <p>{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.</p>
83818342 <p>
83828343 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" {
86778638 allows one to, for example, heap-allocate an async function frame:
86788639 </p>
86798640 {#code_begin|test|heap_allocated_frame#}
8641 {#backend_stage1#}
86808642const std = @import("std");
86818643
86828644test "heap allocated frame" {
......@@ -9011,8 +8973,8 @@ test "@wasmMemoryGrow" {
90118973 {#header_close#}
90128974
90138975 {#header_open|@popCount#}
9014 <pre>{#syntax#}@popCount(comptime T: type, operand: T){#endsyntax#}</pre>
9015 <p>{#syntax#}T{#endsyntax#} must be an integer type.</p>
8976 <pre>{#syntax#}@popCount(operand: anytype){#endsyntax#}</pre>
8977 <p>{#syntax#}@TypeOf(operand){#endsyntax#} must be an integer type.</p>
90168978 <p>{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.</p>
90178979 <p>Counts the number of bits set in an integer.</p>
90188980 <p>
......@@ -9423,12 +9385,6 @@ const std = @import("std");
94239385const expect = std.testing.expect;
94249386
94259387test "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
94329388 const value = @Vector(4, i32){ 1, -1, 1, -1 };
94339389 const result = value > @splat(4, @as(i32, 0));
94349390 // result is { true, false, true, false };
......@@ -9938,7 +9894,7 @@ pub fn main() void {
99389894 {#header_close#}
99399895 {#header_open|Index out of Bounds#}
99409896 <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#}
99429898comptime {
99439899 const array: [5]u8 = "hello".*;
99449900 const garbage = array[5];
......@@ -9959,9 +9915,9 @@ fn foo(x: []const u8) u8 {
99599915 {#header_close#}
99609916 {#header_open|Cast Negative Number to Unsigned Integer#}
99619917 <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'#}
99639919comptime {
9964 const value: i32 = -1;
9920 var value: i32 = -1;
99659921 const unsigned = @intCast(u32, value);
99669922 _ = unsigned;
99679923}
......@@ -9982,7 +9938,7 @@ pub fn main() void {
99829938 {#header_close#}
99839939 {#header_open|Cast Truncates Data#}
99849940 <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'#}
99869942comptime {
99879943 const spartan_count: u16 = 300;
99889944 const byte = @intCast(u8, spartan_count);
......@@ -10017,7 +9973,7 @@ pub fn main() void {
100179973 <li>{#link|@divExact#} (division)</li>
100189974 </ul>
100199975 <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'#}
100219977comptime {
100229978 var byte: u8 = 255;
100239979 byte += 1;
......@@ -10118,6 +10074,7 @@ test "wraparound addition and subtraction" {
1011810074 {#header_open|Exact Left Shift Overflow#}
1011910075 <p>At compile-time:</p>
1012010076 {#code_begin|test_err|operation caused overflow#}
10077 {#backend_stage1#}
1012110078comptime {
1012210079 const x = @shlExact(@as(u8, 0b01010101), 2);
1012310080 _ = x;
......@@ -10137,6 +10094,7 @@ pub fn main() void {
1013710094 {#header_open|Exact Right Shift Overflow#}
1013810095 <p>At compile-time:</p>
1013910096 {#code_begin|test_err|exact shift shifted out 1 bits#}
10097 {#backend_stage1#}
1014010098comptime {
1014110099 const x = @shrExact(@as(u8, 0b10101010), 2);
1014210100 _ = x;
......@@ -10200,6 +10158,7 @@ pub fn main() void {
1020010158 {#header_open|Exact Division Remainder#}
1020110159 <p>At compile-time:</p>
1020210160 {#code_begin|test_err|exact division had a remainder#}
10161 {#backend_stage1#}
1020310162comptime {
1020410163 const a: u32 = 10;
1020510164 const b: u32 = 3;
......@@ -10302,7 +10261,7 @@ fn getNumberOrFail() !i32 {
1030210261 {#header_close#}
1030310262 {#header_open|Invalid Error Code#}
1030410263 <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#}
1030610265comptime {
1030710266 const err = error.AnError;
1030810267 const number = @errorToInt(err) + 10;
......@@ -10324,7 +10283,7 @@ pub fn main() void {
1032410283 {#header_close#}
1032510284 {#header_open|Invalid Enum Cast#}
1032610285 <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'#}
1032810287const Foo = enum {
1032910288 a,
1033010289 b,
......@@ -10356,7 +10315,7 @@ pub fn main() void {
1035610315
1035710316 {#header_open|Invalid Error Set Cast#}
1035810317 <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}'#}
1036010319const Set1 = error{
1036110320 A,
1036210321 B,
......@@ -10417,7 +10376,7 @@ fn foo(bytes: []u8) u32 {
1041710376 {#header_close#}
1041810377 {#header_open|Wrong Union Field Access#}
1041910378 <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#}
1042110380comptime {
1042210381 var f = Foo{ .int = 42 };
1042310382 f.float = 12.34;
......@@ -10509,6 +10468,7 @@ fn bar(f: *Foo) void {
1050910468 </p>
1051010469 <p>At compile-time:</p>
1051110470 {#code_begin|test_err|null pointer casted to type#}
10471 {#backend_stage1#}
1051210472comptime {
1051310473 const opt_ptr: ?*i32 = null;
1051410474 const ptr = @ptrCast(*i32, opt_ptr);
......@@ -10551,7 +10511,8 @@ const expect = std.testing.expect;
1055110511
1055210512test "using an allocator" {
1055310513 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();
1055510516 const result = try concat(allocator, "foo", "bar");
1055610517 try expect(std.mem.eql(u8, "foobar", result));
1055710518}
......@@ -10647,7 +10608,7 @@ pub fn main() !void {
1064710608 <p>String literals such as {#syntax#}"foo"{#endsyntax#} are in the global constant data section.
1064810609 This is why it is an error to pass a string literal to a mutable slice, like this:
1064910610 </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'#}
1065110612fn foo(s: []u8) void {
1065210613 _ = s;
1065310614}
......@@ -11832,8 +11793,8 @@ fn readU32Be() u32 {}
1183211793 <pre>{#syntax#}anytype{#endsyntax#}</pre>
1183311794 </th>
1183411795 <td>
11835 Function parameters and struct fields 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.
11796 Function parameters can be declared with {#syntax#}anytype{#endsyntax#} in place of the type.
11797 The type will be inferred where the function is called.
1183711798 <ul>
1183811799 <li>See also {#link|Function Parameter Type Inference#}</li>
1183911800 </ul>
lib/compiler_rt/addf3.zig+2-2
......@@ -9,7 +9,7 @@ const normalize = common.normalize;
99pub inline fn addf3(comptime T: type, a: T, b: T) T {
1010 const bits = @typeInfo(T).Float.bits;
1111 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
1414 const typeWidth = bits;
1515 const significandBits = math.floatMantissaBits(T);
......@@ -118,7 +118,7 @@ pub inline fn addf3(comptime T: type, a: T, b: T) T {
118118 // If partial cancellation occured, we need to left-shift the result
119119 // and adjust the exponent:
120120 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));
122122 aSignificand <<= @intCast(S, shift);
123123 aExponent -= shift;
124124 }
lib/compiler_rt/common.zig+1-1
......@@ -199,7 +199,7 @@ pub fn normalize(comptime T: type, significand: *std.meta.Int(.unsigned, @typeIn
199199 const Z = std.meta.Int(.unsigned, @typeInfo(T).Float.bits);
200200 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);
203203 significand.* <<= @intCast(std.math.Log2Int(Z), shift);
204204 return @as(i32, 1) - shift;
205205}
lib/compiler_rt/divxf3.zig+2
......@@ -206,5 +206,7 @@ pub fn __divxf3(a: f80, b: f80) callconv(.C) f80 {
206206}
207207
208208test {
209 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/12603
210
209211 _ = @import("divxf3_test.zig");
210212}
lib/compiler_rt/extendf.zig+4-4
......@@ -56,8 +56,8 @@ pub inline fn extendf(
5656 // a is denormal.
5757 // renormalize the significand and clear the leading bit, then insert
5858 // the correct adjusted exponent in the destination type.
59 const scale: u32 = @clz(src_rep_t, aAbs) -
60 @clz(src_rep_t, @as(src_rep_t, srcMinNormal));
59 const scale: u32 = @clz(aAbs) -
60 @clz(@as(src_rep_t, srcMinNormal));
6161 absResult = @as(dst_rep_t, aAbs) << @intCast(DstShift, dstSigBits - srcSigBits + scale);
6262 absResult ^= dstMinNormal;
6363 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
119119 // a is denormal.
120120 // renormalize the significand and clear the leading bit, then insert
121121 // the correct adjusted exponent in the destination type.
122 const scale: u16 = @clz(src_rep_t, a_abs) -
123 @clz(src_rep_t, @as(src_rep_t, src_min_normal));
122 const scale: u16 = @clz(a_abs) -
123 @clz(@as(src_rep_t, src_min_normal));
124124
125125 dst.fraction = @as(u64, a_abs) << @intCast(u6, dst_sig_bits - src_sig_bits + scale);
126126 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 {
3838 // a is denormal
3939 // renormalize the significand and clear the leading bit and integer part,
4040 // 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);
4242 abs_result = @as(u128, a_rep.fraction) << @intCast(u7, dst_sig_bits - src_sig_bits + scale + 1);
4343 abs_result ^= dst_min_normal;
4444 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 {
243243 // special cases
244244 if (d == 0) return 0; // ?!
245245 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)));
247247 // 0 <= sr <= n_uword_bits - 1 or sr large
248248 if (sr > n_uword_bits - 1) {
249249 // d > r
lib/compiler_rt/int_to_float.zig+2-2
......@@ -23,7 +23,7 @@ pub fn intToFloat(comptime T: type, x: anytype) T {
2323 var result: uT = sign_bit;
2424
2525 // Compute significand
26 var exp = int_bits - @clz(Z, abs_val) - 1;
26 var exp = int_bits - @clz(abs_val) - 1;
2727 if (int_bits <= fractional_bits or exp <= fractional_bits) {
2828 const shift_amt = fractional_bits - @intCast(math.Log2Int(uT), exp);
2929
......@@ -32,7 +32,7 @@ pub fn intToFloat(comptime T: type, x: anytype) T {
3232 result ^= implicit_bit; // Remove implicit integer bit
3333 } else {
3434 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
3737 // Shift down result and remove implicit integer bit
3838 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 {
186186 const Z = PowerOfTwoSignificandZ(T);
187187 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);
190190 significand.* <<= @intCast(math.Log2Int(Z), shift);
191191 return @as(i32, 1) - shift;
192192}
lib/compiler_rt/udivmod.zig+5-5
......@@ -75,12 +75,12 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
7575 r[high] = n[high] & (d[high] - 1);
7676 rem.* = @ptrCast(*align(@alignOf(SingleInt)) DoubleInt, &r[0]).*; // TODO issue #421
7777 }
78 return n[high] >> @intCast(Log2SingleInt, @ctz(SingleInt, d[high]));
78 return n[high] >> @intCast(Log2SingleInt, @ctz(d[high]));
7979 }
8080 // K K
8181 // ---
8282 // 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])));
8484 // 0 <= sr <= single_int_bits - 2 or sr large
8585 if (sr > single_int_bits - 2) {
8686 if (maybe_rem) |rem| {
......@@ -110,7 +110,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
110110 if (d[low] == 1) {
111111 return a;
112112 }
113 sr = @ctz(SingleInt, d[low]);
113 sr = @ctz(d[low]);
114114 q[high] = n[high] >> @intCast(Log2SingleInt, sr);
115115 q[low] = (n[high] << @intCast(Log2SingleInt, single_int_bits - sr)) | (n[low] >> @intCast(Log2SingleInt, sr));
116116 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:
118118 // K X
119119 // ---
120120 // 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]));
122122 // 2 <= sr <= double_int_bits - 1
123123 // q.all = a << (double_int_bits - sr);
124124 // r.all = a >> sr;
......@@ -144,7 +144,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
144144 // K X
145145 // ---
146146 // 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])));
148148 // 0 <= sr <= single_int_bits - 1 or sr large
149149 if (sr > single_int_bits - 1) {
150150 if (maybe_rem) |rem| {
lib/docs/index.html+91-72
......@@ -25,9 +25,10 @@
2525 --search-bg-color-focus: #ffffff;
2626 --search-sh-color: rgba(0, 0, 0, 0.18);
2727 --help-sh-color: rgba(0, 0, 0, 0.75);
28 --help-bg-color: #aaa;
2829 }
2930
30 html, body { margin: 0; padding:0; height: 100%; }
31 html, body { margin: 0; padding: 0; height: 100%; }
3132
3233 a {
3334 text-decoration: none;
......@@ -168,8 +169,8 @@
168169 width: 100%;
169170 margin-bottom: 0.8rem;
170171 padding: 0.5rem;
171 font-size: 1rem;
172172 font-family: var(--ui);
173 font-size: 1rem;
173174 color: var(--tx-color);
174175 background-color: var(--search-bg-color);
175176 border-top: 0;
......@@ -190,11 +191,11 @@
190191 box-shadow: 0 0.3em 1em 0.125em var(--search-sh-color);
191192 }
192193
193 .docs .search::placeholder {
194 font-size: 1rem;
195 font-family: var(--ui);
196 color: var(--tx-color);
197 opacity: 0.5;
194 #searchPlaceholder {
195 position: absolute;
196 pointer-events: none;
197 top: 5px;
198 left: 5px;
198199 }
199200
200201 .docs a {
......@@ -207,9 +208,9 @@
207208
208209 .docs pre {
209210 font-family: var(--mono);
210 font-size:1em;
211 background-color:#F5F5F5;
212 padding:1em;
211 font-size: 1em;
212 background-color: #F5F5F5;
213 padding: 1em;
213214 overflow-x: auto;
214215 }
215216
......@@ -225,7 +226,7 @@
225226 border-bottom: 0.0625rem dashed;
226227 }
227228
228 .docs h2 {
229 .docs h2 {
229230 font-size: 1.3em;
230231 margin: 0.5em 0;
231232 padding: 0;
......@@ -289,12 +290,12 @@
289290 }
290291
291292 .fieldDocs {
292 border: 1px solid #2A2A2A;
293 border: 1px solid #F5F5F5;
293294 border-top: 0px;
294295 padding: 1px 1em;
295296 }
296297
297 /* help dialog */
298 /* help modal */
298299 .help-modal {
299300 display: flex;
300301 width: 100%;
......@@ -308,13 +309,13 @@
308309 backdrop-filter: blur(0.3em);
309310 }
310311
311 .help-modal > .dialog {
312 .help-modal > .modal {
312313 max-width: 97vw;
313314 max-height: 97vh;
314315 overflow: auto;
315316 font-size: 1rem;
316317 color: #fff;
317 background-color: #333;
318 background-color: var(--help-bg-color);
318319 border: 0.125rem solid #000;
319320 box-shadow: 0 0.5rem 2.5rem 0.3rem var(--help-sh-color);
320321 }
......@@ -335,11 +336,11 @@
335336 margin-right: 0.5em;
336337 }
337338
338 .help-modal kbd {
339 kbd {
339340 display: inline-block;
340341 padding: 0.3em 0.2em;
341 font-size: 1.2em;
342 font-size: var(--mono);
342 font-family: var(--mono);
343 font-size: 1em;
343344 line-height: 0.8em;
344345 vertical-align: middle;
345346 color: #000;
......@@ -348,16 +349,20 @@
348349 border-bottom-color: #c6cbd1;
349350 border: solid 0.0625em;
350351 border-radius: 0.1875em;
351 box-shadow: inset 0 -0.0625em 0 #c6cbd1;
352 box-shadow: inset 0 -0.2em 0 #c6cbd1;
352353 cursor: default;
353354 }
355
356 #listFns > div {
357 padding-bottom: 10px;
358 }
354359
355 #listFns dt {
356 font-family: var(--mono);
357 }
358 .argBreaker {
359 display: none;
360 }
360 #listFns dt {
361 font-family: var(--mono);
362 }
363 .argBreaker {
364 display: none;
365 }
361366
362367 /* tokens */
363368 .tok-kw {
......@@ -391,7 +396,6 @@
391396
392397 /* dark mode */
393398 @media (prefers-color-scheme: dark) {
394
395399 :root {
396400 --tx-color: #bbb;
397401 --bg-color: #111;
......@@ -408,11 +412,15 @@
408412 --search-bg-color-focus: #000;
409413 --search-sh-color: rgba(255, 255, 255, 0.28);
410414 --help-sh-color: rgba(142, 142, 142, 0.5);
415 --help-bg-color: #333;
411416 }
412417
413418 .docs pre {
414419 background-color:#2A2A2A;
415420 }
421 .fieldDocs {
422 border-color:#2A2A2A;
423 }
416424 #listNav {
417425 background-color: #333;
418426 }
......@@ -457,7 +465,6 @@
457465 .tok-type {
458466 color: #68f;
459467 }
460
461468 }
462469
463470 @media only screen and (max-width: 750px) {
......@@ -544,7 +551,7 @@
544551 <body class="canvas">
545552 <div class="banner">
546553 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>,
548555 <a href="https://github.com/ziglang/zig/wiki/How-to-contribute-to-Autodoc">Contribute</a>,
549556 <a href="https://github.com/ziglang/zig/wiki/How-to-read-the-standard-library-source-code">Learn more about stdlib source code</a>.
550557 </div>
......@@ -555,43 +562,43 @@
555562 <div class="logo">
556563 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 140">
557564 <g fill="#F7A41D">
558 <g>
559 <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"/>
561 <polygon points="31,95 12,117 4,106"/>
562 </g>
563 <g>
564 <polygon points="56,22 62,36 37,44"/>
565 <polygon points="56,22 111,22 111,44 37,44 56,32" shape-rendering="crispEdges"/>
566 <polygon points="116,95 97,117 90,104"/>
567 <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"/>
569 </g>
570 <g>
571 <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"/>
573 <polygon points="125,95 130,110 106,117"/>
574 </g>
565 <g>
566 <polygon points="46,22 28,44 19,30"/>
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"/>
568 <polygon points="31,95 12,117 4,106"/>
569 </g>
570 <g>
571 <polygon points="56,22 62,36 37,44"/>
572 <polygon points="56,22 111,22 111,44 37,44 56,32" shape-rendering="crispEdges"/>
573 <polygon points="116,95 97,117 90,104"/>
574 <polygon points="116,95 100,104 97,117 42,117 42,95" shape-rendering="crispEdges"/>
575 <polygon points="150,0 52,117 3,140 101,22"/>
576 </g>
577 <g>
578 <polygon points="141,22 140,40 122,45"/>
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"/>
580 <polygon points="125,95 130,110 106,117"/>
581 </g>
575582 </g>
576583 <style>
577584 #text { fill: #121212 }
578585 @media (prefers-color-scheme: dark) { #text { fill: #f2f2f2 } }
579586 </style>
580587 <g id="text">
581 <g>
582 <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"/>
584 <polygon points="261,99 261,117 176,117 176,103 206,99" shape-rendering="crispEdges"/>
585 </g>
586 <rect x="272" y="22" shape-rendering="crispEdges" width="22" height="95"/>
587 <g>
588 <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"/>
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"/>
591 </g>
588 <g>
589 <polygon points="260,22 260,37 229,40 177,40 177,22" shape-rendering="crispEdges"/>
590 <polygon points="260,37 207,99 207,103 176,103 229,40 229,37"/>
591 <polygon points="261,99 261,117 176,117 176,103 206,99" shape-rendering="crispEdges"/>
592 </g>
593 <rect x="272" y="22" shape-rendering="crispEdges" width="22" height="95"/>
594 <g>
595 <polygon points="394,67 394,106 376,106 376,81 360,70 346,67" shape-rendering="crispEdges"/>
596 <polygon points="360,68 376,81 346,67"/>
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"/>
598 </g>
592599 </g>
593600 </svg>
594 </div>
601 </div>
595602 <div id="sectMainPkg" class="hidden">
596603 <h2><span>Main Package</span></h2>
597604 <ul class="packages">
......@@ -606,16 +613,19 @@
606613 <h2><span>Zig Version</span></h2>
607614 <p class="str" id="tdZigVer"></p>
608615 </div>
609 <div>
610 <input id="privDeclsBox" type="checkbox"/>
611 <label for="privDeclsBox">Internal Doc Mode</label>
612 </div>
616 <div>
617 <input id="privDeclsBox" type="checkbox"/>
618 <label for="privDeclsBox">Internal Doc Mode</label>
619 </div>
613620 </nav>
614621 </div>
615 <div class="flex-right">
622 <div id="docs" class="flex-right">
616623 <div class="wrap">
617624 <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>
619629 <p id="status">Loading...</p>
620630 <div id="sectNav" class="hidden"><ul id="listNav"></ul></div>
621631 <div id="fnProto" class="hidden">
......@@ -647,10 +657,17 @@
647657 <div id="sectSearchResults" class="hidden">
648658 <h2>Search Results</h2>
649659 <ul id="listSearchResults"></ul>
660 <p id="sectSearchAllResultsLink" class="hidden"><a href="">show all results</a></p>
650661 </div>
651662 <div id="sectSearchNoResults" class="hidden">
652663 <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>
654671 </div>
655672 <div id="sectFields" class="hidden">
656673 <h2>Fields</h2>
......@@ -702,21 +719,23 @@
702719 </table>
703720 </div>
704721 </div>
705 </section>
722 </section>
706723 </div>
707724 <div class="flex-filler"></div>
708725 </div>
709726 </div>
710 <div id="helpDialog" class="hidden">
727 <div id="helpModal" class="hidden">
711728 <div class="help-modal">
712 <div class="dialog">
729 <div class="modal">
713730 <h1>Keyboard Shortcuts</h1>
714 <dl><dt><kbd>?</kbd></dt><dd>Show this help dialog</dd></dl>
715 <dl><dt><kbd>Esc</kbd></dt><dd>Clear focus; close this dialog</dd></dl>
731 <dl><dt><kbd>?</kbd></dt><dd>Show this help modal</dd></dl>
716732 <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>
718 <dl><dt><kbd>↓</kbd></dt><dd>Move down in search results</dd></dl>
719 <dl><dt><kbd>⏎</kbd></dt><dd>Go to active search result</dd></dl>
733 <div style="margin-left: 1em">
734 <dl><dt><kbd>↑</kbd></dt><dd>Move up in search results</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>
720739 </div>
721740 </div>
722741 </div>
lib/docs/main.js+3178-2966
......@@ -1,3259 +1,3471 @@
1'use strict';
1"use strict";
22
33var zigAnalysis;
44
5(function() {
6 let domStatus = (document.getElementById("status"));
7 let domSectNav = (document.getElementById("sectNav"));
8 let domListNav = (document.getElementById("listNav"));
9 let domSectMainPkg = (document.getElementById("sectMainPkg"));
10 let domSectPkgs = (document.getElementById("sectPkgs"));
11 let domListPkgs = (document.getElementById("listPkgs"));
12 let domSectTypes = (document.getElementById("sectTypes"));
13 let domListTypes = (document.getElementById("listTypes"));
14 let domSectTests = (document.getElementById("sectTests"));
15 let domListTests = (document.getElementById("listTests"));
16 let domSectNamespaces = (document.getElementById("sectNamespaces"));
17 let domListNamespaces = (document.getElementById("listNamespaces"));
18 let domSectErrSets = (document.getElementById("sectErrSets"));
19 let domListErrSets = (document.getElementById("listErrSets"));
20 let domSectFns = (document.getElementById("sectFns"));
21 let domListFns = (document.getElementById("listFns"));
22 let domSectFields = (document.getElementById("sectFields"));
23 let domListFields = (document.getElementById("listFields"));
24 let domSectGlobalVars = (document.getElementById("sectGlobalVars"));
25 let domListGlobalVars = (document.getElementById("listGlobalVars"));
26 let domSectValues = (document.getElementById("sectValues"));
27 let domListValues = (document.getElementById("listValues"));
28 let domFnProto = (document.getElementById("fnProto"));
29 let domFnProtoCode = (document.getElementById("fnProtoCode"));
30 let domSectParams = (document.getElementById("sectParams"));
31 let domListParams = (document.getElementById("listParams"));
32 let domTldDocs = (document.getElementById("tldDocs"));
33 let domSectFnErrors = (document.getElementById("sectFnErrors"));
34 let domListFnErrors = (document.getElementById("listFnErrors"));
35 let domTableFnErrors =(document.getElementById("tableFnErrors"));
36 let domFnErrorsAnyError = (document.getElementById("fnErrorsAnyError"));
37 let domFnExamples = (document.getElementById("fnExamples"));
38 // let domListFnExamples = (document.getElementById("listFnExamples"));
39 let domFnNoExamples = (document.getElementById("fnNoExamples"));
40 let domDeclNoRef = (document.getElementById("declNoRef"));
41 let domSearch = (document.getElementById("search"));
42 let domSectSearchResults = (document.getElementById("sectSearchResults"));
43
44 let domListSearchResults = (document.getElementById("listSearchResults"));
45 let domSectSearchNoResults = (document.getElementById("sectSearchNoResults"));
46 let domSectInfo = (document.getElementById("sectInfo"));
47 // let domTdTarget = (document.getElementById("tdTarget"));
48 let domPrivDeclsBox = (document.getElementById("privDeclsBox"));
49 let domTdZigVer = (document.getElementById("tdZigVer"));
50 let domHdrName = (document.getElementById("hdrName"));
51 let domHelpModal = (document.getElementById("helpDialog"));
52
53
54 let searchTimer = null;
55
56
57 let escapeHtmlReplacements = { "&": "&amp;", '"': "&quot;", "<": "&lt;", ">": "&gt;" };
58
59 let typeKinds = (indexTypeKinds());
60 let typeTypeId = (findTypeTypeId());
61 let pointerSizeEnum = { One: 0, Many: 1, Slice: 2, C: 3 };
62
63 // for each package, is an array with packages to get to this one
64 let canonPkgPaths = computeCanonicalPackagePaths();
65
66
67
68 // for each decl, is an array with {declNames, pkgNames} to get to this one
69
70 let canonDeclPaths = null; // lazy; use getCanonDeclPath
71
72 // for each type, is an array with {declNames, pkgNames} to get to this one
73
74 let canonTypeDecls = null; // lazy; use getCanonTypeDecl
75
76
77
78
79 let curNav = {
80 showPrivDecls: false,
81 // each element is a package name, e.g. @import("a") then within there @import("b")
82 // starting implicitly from root package
83 pkgNames: [],
84 // same as above except actual packages, not names
85 pkgObjs: [],
86 // Each element is a decl name, `a.b.c`, a is 0, b is 1, c is 2, etc.
87 // empty array means refers to the package itself
88 declNames: [],
89 // these will be all types, except the last one may be a type or a decl
90 declObjs: [],
91
92 // (a, b, c, d) comptime call; result is the value the docs refer to
93 callName: null,
94 };
95
96 let curNavSearch = "";
97 let curSearchIndex = -1;
98 let imFeelingLucky = false;
99
100 let rootIsStd = detectRootIsStd();
101
102 // map of decl index to list of non-generic fn indexes
103 // let nodesToFnsMap = indexNodesToFns();
104 // map of decl index to list of comptime fn calls
105 // let nodesToCallsMap = indexNodesToCalls();
106
107 domSearch.addEventListener('keydown', onSearchKeyDown, false);
108 domPrivDeclsBox.addEventListener('change', function() {
109 if (this.checked != curNav.showPrivDecls) {
110 if (this.checked && location.hash.length > 1 && location.hash[1] != '*'){
111 location.hash = "#*" + location.hash.substring(1);
112 return;
113 }
114 if (!this.checked && location.hash.length > 1 && location.hash[1] == '*') {
115 location.hash = "#" + location.hash.substring(2);
116 return;
117 }
118 }
119 }, false);
120
121 if (location.hash == "") {
122 location.hash = "#root";
123 }
124
125 window.addEventListener('hashchange', onHashChange, false);
126 window.addEventListener('keydown', onWindowKeyDown, false);
5(function () {
6 const domStatus = document.getElementById("status");
7 const domSectNav = document.getElementById("sectNav");
8 const domListNav = document.getElementById("listNav");
9 const domSectMainPkg = document.getElementById("sectMainPkg");
10 const domSectPkgs = document.getElementById("sectPkgs");
11 const domListPkgs = document.getElementById("listPkgs");
12 const domSectTypes = document.getElementById("sectTypes");
13 const domListTypes = document.getElementById("listTypes");
14 const domSectTests = document.getElementById("sectTests");
15 const domListTests = document.getElementById("listTests");
16 const domSectNamespaces = document.getElementById("sectNamespaces");
17 const domListNamespaces = document.getElementById("listNamespaces");
18 const domSectErrSets = document.getElementById("sectErrSets");
19 const domListErrSets = document.getElementById("listErrSets");
20 const domSectFns = document.getElementById("sectFns");
21 const domListFns = document.getElementById("listFns");
22 const domSectFields = document.getElementById("sectFields");
23 const domListFields = document.getElementById("listFields");
24 const domSectGlobalVars = document.getElementById("sectGlobalVars");
25 const domListGlobalVars = document.getElementById("listGlobalVars");
26 const domSectValues = document.getElementById("sectValues");
27 const domListValues = document.getElementById("listValues");
28 const domFnProto = document.getElementById("fnProto");
29 const domFnProtoCode = document.getElementById("fnProtoCode");
30 const domSectParams = document.getElementById("sectParams");
31 const domListParams = document.getElementById("listParams");
32 const domTldDocs = document.getElementById("tldDocs");
33 const domSectFnErrors = document.getElementById("sectFnErrors");
34 const domListFnErrors = document.getElementById("listFnErrors");
35 const domTableFnErrors = document.getElementById("tableFnErrors");
36 const domFnErrorsAnyError = document.getElementById("fnErrorsAnyError");
37 const domFnExamples = document.getElementById("fnExamples");
38 // const domListFnExamples = (document.getElementById("listFnExamples"));
39 const domFnNoExamples = document.getElementById("fnNoExamples");
40 const domDeclNoRef = document.getElementById("declNoRef");
41 const domSearch = document.getElementById("search");
42 const domSectSearchResults = document.getElementById("sectSearchResults");
43 const domSectSearchAllResultsLink = document.getElementById("sectSearchAllResultsLink");
44 const domDocs = document.getElementById("docs");
45 const domListSearchResults = document.getElementById("listSearchResults");
46 const domSectSearchNoResults = document.getElementById("sectSearchNoResults");
47 const domSectInfo = document.getElementById("sectInfo");
48 // const domTdTarget = (document.getElementById("tdTarget"));
49 const domPrivDeclsBox = document.getElementById("privDeclsBox");
50 const domTdZigVer = document.getElementById("tdZigVer");
51 const domHdrName = document.getElementById("hdrName");
52 const domHelpModal = document.getElementById("helpModal");
53 const domSearchPlaceholder = document.getElementById("searchPlaceholder");
54 const sourceFileUrlTemplate = "src/{{file}}#L{{line}}"
55 const domLangRefLink = document.getElementById("langRefLink");
56
57 let searchTimer = null;
58 let searchTrimResults = true;
59
60 let escapeHtmlReplacements = {
61 "&": "&amp;",
62 '"': "&quot;",
63 "<": "&lt;",
64 ">": "&gt;",
65 };
66
67 let typeKinds = indexTypeKinds();
68 let typeTypeId = findTypeTypeId();
69 let pointerSizeEnum = { One: 0, Many: 1, Slice: 2, C: 3 };
70
71 // for each package, is an array with packages to get to this one
72 let canonPkgPaths = computeCanonicalPackagePaths();
73
74 // for each decl, is an array with {declNames, pkgNames} to get to this one
75
76 let canonDeclPaths = null; // lazy; use getCanonDeclPath
77
78 // for each type, is an array with {declNames, pkgNames} to get to this one
79
80 let canonTypeDecls = null; // lazy; use getCanonTypeDecl
81
82 let curNav = {
83 showPrivDecls: false,
84 // each element is a package name, e.g. @import("a") then within there @import("b")
85 // starting implicitly from root package
86 pkgNames: [],
87 // same as above except actual packages, not names
88 pkgObjs: [],
89 // Each element is a decl name, `a.b.c`, a is 0, b is 1, c is 2, etc.
90 // empty array means refers to the package itself
91 declNames: [],
92 // these will be all types, except the last one may be a type or a decl
93 declObjs: [],
94
95 // (a, b, c, d) comptime call; result is the value the docs refer to
96 callName: null,
97 };
98
99 let curNavSearch = "";
100 let curSearchIndex = -1;
101 let imFeelingLucky = false;
102
103 let rootIsStd = detectRootIsStd();
104
105 // map of decl index to list of non-generic fn indexes
106 // let nodesToFnsMap = indexNodesToFns();
107 // map of decl index to list of comptime fn calls
108 // let nodesToCallsMap = indexNodesToCalls();
109
110 domSearch.disabled = false;
111 domSearch.addEventListener("keydown", onSearchKeyDown, false);
112 domSearch.addEventListener("focus", ev => {
113 domSearchPlaceholder.classList.add("hidden");
114 });
115 domSearch.addEventListener("blur", ev => {
116 if (domSearch.value.length == 0)
117 domSearchPlaceholder.classList.remove("hidden");
118 });
119 domSectSearchAllResultsLink.addEventListener('click', onClickSearchShowAllResults, false);
120 function onClickSearchShowAllResults(ev) {
121 ev.preventDefault();
122 ev.stopPropagation();
123 searchTrimResults = false;
127124 onHashChange();
128
129 function renderTitle() {
130 let list = curNav.pkgNames.concat(curNav.declNames);
131 let suffix = " - Zig";
132 if (list.length === 0) {
133 if (rootIsStd) {
134 document.title = "std" + suffix;
135 } else {
136 document.title = zigAnalysis.params.rootName + suffix;
137 }
138 } else {
139 document.title = list.join('.') + suffix;
125 }
126
127 domPrivDeclsBox.addEventListener(
128 "change",
129 function () {
130 if (this.checked != curNav.showPrivDecls) {
131 if (
132 this.checked &&
133 location.hash.length > 1 &&
134 location.hash[1] != "*"
135 ) {
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;
140146 }
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;
141184 }
185 }
142186
143
144 function isDecl(x) {
145 return "value" in x;
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
187 function isDecl(x) {
188 return "value" in x;
189 }
185190
191 function isType(x) {
192 return "kind" in x && !("value" in x);
193 }
186194
187 let name = undefined;
188 if (type.kind === typeKinds.Struct) {
189 name = "struct";
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 }
195 function isContainerType(x) {
196 return isType(x) && typeKindIsContainer(x.kind);
197 }
198198
199 return escapeHtml(name);
199 function typeShorthandName(expr) {
200 let resolvedExpr = resolveValue({ expr: expr });
201 if (!("type" in resolvedExpr)) {
202 return null;
200203 }
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
203 function typeKindIsContainer(typeKind) {
204 return typeKind === typeKinds.Struct ||
205 typeKind === typeKinds.Union ||
206 typeKind === typeKinds.Enum;
222 if (i == 9999) throw "Exhausted typeShorthandName quota";
207223 }
208224
209
210 function declCanRepresentTypeKind(typeKind) {
211 return typeKind === typeKinds.ErrorSet || typeKindIsContainer(typeKind);
225 let name = undefined;
226 if (type.kind === typeKinds.Struct) {
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;
212235 }
213236
214 //
215 // function findCteInRefPath(path) {
216 // for (let i = path.length - 1; i >= 0; i -= 1) {
217 // const ref = path[i];
218 // if ("string" in ref) continue;
219 // if ("comptimeExpr" in ref) return ref;
220 // if ("refPath" in ref) return findCteInRefPath(ref.refPath);
221 // return null;
222 // }
223
224 // return null;
225 // }
226
227
228 function resolveValue(value) {
229 let i = 0;
230 while(i < 1000) {
231 i += 1;
232
233 if ("refPath" in value.expr) {
234 value = {expr: value.expr.refPath[value.expr.refPath.length -1]};
235 continue;
236 }
237
238 if ("declRef" in value.expr) {
239 value = zigAnalysis.decls[value.expr.declRef].value;
240 continue;
241 }
242
243 if ("as" in value.expr) {
244 value = {
245 typeRef: zigAnalysis.exprs[value.expr.as.typeRefArg],
246 expr: zigAnalysis.exprs[value.expr.as.exprArg],
247 };
248 continue;
249 }
250
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 }
237 return escapeHtml(name);
238 }
239
240 function typeKindIsContainer(typeKind) {
241 return (
242 typeKind === typeKinds.Struct ||
243 typeKind === typeKinds.Union ||
244 typeKind === typeKinds.Enum
245 );
246 }
247
248 function declCanRepresentTypeKind(typeKind) {
249 return typeKind === typeKinds.ErrorSet || typeKindIsContainer(typeKind);
250 }
251
252 //
253 // function findCteInRefPath(path) {
254 // for (let i = path.length - 1; i >= 0; i -= 1) {
255 // const ref = path[i];
256 // if ("string" in ref) continue;
257 // if ("comptimeExpr" in ref) return ref;
258 // if ("refPath" in ref) return findCteInRefPath(ref.refPath);
259 // return null;
260 // }
261
262 // return null;
263 // }
264
265 function resolveValue(value) {
266 let i = 0;
267 while (i < 1000) {
268 i += 1;
269
270 if ("refPath" in value.expr) {
271 value = { expr: value.expr.refPath[value.expr.refPath.length - 1] };
272 continue;
273 }
411274
412 currentType = (childDecl);
413 curNav.declObjs.push(currentType);
414 }
275 if ("declRef" in value.expr) {
276 value = zigAnalysis.decls[value.expr.declRef].value;
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];
419 let lastIsDecl = isDecl(last);
420 let lastIsType = isType(last);
421 let lastIsContainerType = isContainerType(last);
288 return value;
289 }
290 console.assert(false);
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) {
428 return renderUnknownDecl((last));
429 }
417 let rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg];
418 let pkg = rootPkg;
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) {
432 return renderType((last));
433 }
429 let currentType = zigAnalysis.types[pkg.main];
430 curNav.declObjs = [currentType];
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') {
436 return renderVar((last));
437 let childDeclValue = resolveValue(childDecl.value).expr;
438 if ("type" in childDeclValue) {
439 const t = zigAnalysis.types[childDeclValue.type];
440 if (t.kind != typeKinds.Fn) {
441 childDecl = t;
437442 }
443 }
438444
439 if (lastIsDecl && last.kind === 'const') {
440 let typeObj = zigAnalysis.types[resolveValue((last).value).expr.type];
441 if (typeObj && typeObj.kind === typeKinds.Fn) {
442 return renderFn((last));
443 }
444
445 return renderValue((last));
446 }
445 currentType = childDecl;
446 curNav.declObjs.push(currentType);
447447 }
448448
449
450 function renderUnknownDecl(decl) {
451 domDeclNoRef.classList.remove("hidden");
449 renderNav();
452450
453 let docs = zigAnalysis.astNodes[decl.src].docs;
454 if (docs != null) {
455 domTldDocs.innerHTML = markdown(docs);
456 } else {
457 domTldDocs.innerHTML = '<p>There are no doc comments for this declaration.</p>';
458 }
459 domTldDocs.classList.remove("hidden");
460 }
451 let last = curNav.declObjs[curNav.declObjs.length - 1];
452 let lastIsDecl = isDecl(last);
453 let lastIsType = isType(last);
454 let lastIsContainerType = isContainerType(last);
461455
462
463 function typeIsErrSet(typeIndex) {
464 let typeObj = zigAnalysis.types[typeIndex];
465 return typeObj.kind === typeKinds.ErrorSet;
456 if (lastIsContainerType) {
457 return renderContainer(last);
466458 }
467459
468
469 function typeIsStructWithNoFields(typeIndex) {
470 let typeObj = zigAnalysis.types[typeIndex];
471 if (typeObj.kind !== typeKinds.Struct)
472 return false;
473 return (typeObj).fields.length == 0;
460 if (!lastIsDecl && !lastIsType) {
461 return renderUnknownDecl(last);
474462 }
475463
476
477 function typeIsGenericFn(typeIndex) {
478 let typeObj = zigAnalysis.types[typeIndex];
479 if (typeObj.kind !== typeKinds.Fn) {
480 return false;
481 }
482 return (typeObj).generic_ret != null;
464 if (lastIsType) {
465 return renderType(last);
483466 }
484467
485
486 function renderFn(fnDecl) {
487 if ("refPath" in fnDecl.value.expr) {
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 }
468 if (lastIsDecl && last.kind === "var") {
469 return renderVar(last);
470 }
541471
542 // TODO: see if unwrapping the `as` here is a good idea or not.
543 if ("as" in resolvedGenericRet.expr) {
544 resolvedGenericRet = {
545 expr: zigAnalysis.exprs[resolvedGenericRet.expr.as.exprArg]
546 };
547 }
472 if (lastIsDecl && last.kind === "const") {
473 let typeObj = zigAnalysis.types[resolveValue(last.value).expr.type];
474 if (typeObj && typeObj.kind === typeKinds.Fn) {
475 return renderFn(last);
476 }
548477
549 if (!("type" in resolvedGenericRet.expr)) return;
550 const genericType = zigAnalysis.types[resolvedGenericRet.expr.type];
551 if (isContainerType(genericType)) {
552 renderContainer(genericType)
553 }
478 return renderValue(last);
479 }
480 }
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 code
560 // let instantiations = nodesToFnsMap[protoSrcIndex];
561 // let calls = nodesToCallsMap[protoSrcIndex];
562 // if (instantiations == null && calls == null) {
563 // domFnNoExamples.classList.remove("hidden");
564 // } else if (calls != null) {
565 // // if (fnObj.combined === undefined) fnObj.combined = allCompTimeFnCallsResult(calls);
566 // if (fnObj.combined != null) renderContainer(fnObj.combined);
532 let docsSource = null;
533 let srcNode = zigAnalysis.astNodes[fnDecl.src];
534 if (srcNode.docs != null) {
535 docsSource = srcNode.docs;
536 }
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) {
571 // let liDom = domListFnExamples.children[callI];
572 // liDom.innerHTML = getCallHtml(fnDecl, calls[callI]);
573 // }
556 let protoSrcIndex = fnDecl.src;
557 if (typeIsGenericFn(value.expr.type)) {
558 // does the generic_ret contain a container?
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");
576 // } else if (instantiations != null) {
577 // // TODO
578 // }
579 } else {
570 // TODO: see if unwrapping the `as` here is a good idea or not.
571 if ("as" in resolvedGenericRet.expr) {
572 resolvedGenericRet = {
573 expr: zigAnalysis.exprs[resolvedGenericRet.expr.as.exprArg],
574 };
575 }
580576
581 domFnExamples.classList.add("hidden");
582 domFnNoExamples.classList.add("hidden");
583 }
577 if (!("type" in resolvedGenericRet.expr)) return;
578 const genericType = zigAnalysis.types[resolvedGenericRet.expr.type];
579 if (isContainerType(genericType)) {
580 renderContainer(genericType);
581 }
584582
585 let protoSrcNode = zigAnalysis.astNodes[protoSrcIndex];
586 if (docsSource == null && protoSrcNode != null && protoSrcNode.docs != null) {
587 docsSource = protoSrcNode.docs;
588 }
589 if (docsSource != null) {
590 domTldDocs.innerHTML = markdown(docsSource);
591 domTldDocs.classList.remove("hidden");
592 }
593 domFnProto.classList.remove("hidden");
583 // old code
584 // let instantiations = nodesToFnsMap[protoSrcIndex];
585 // let calls = nodesToCallsMap[protoSrcIndex];
586 // if (instantiations == null && calls == null) {
587 // domFnNoExamples.classList.remove("hidden");
588 // } else if (calls != null) {
589 // // if (fnObj.combined === undefined) fnObj.combined = allCompTimeFnCallsResult(calls);
590 // if (fnObj.combined != null) renderContainer(fnObj.combined);
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");
594606 }
595607
596
597 function renderFnParamDocs(fnDecl, typeObj) {
598 let docCount = 0;
599
600 let fnNode = zigAnalysis.astNodes[fnDecl.src];
601 let fields = (fnNode.fields);
602 let isVarArgs = fnNode.varArgs;
603
604 for (let i = 0; i < fields.length; i += 1) {
605 let field = fields[i];
606 let fieldNode = zigAnalysis.astNodes[field];
607 if (fieldNode.docs != null) {
608 docCount += 1;
609 }
610 }
611 if (docCount == 0) {
612 return;
613 }
614
615 resizeDomList(domListParams, docCount, '<div></div>');
616 let domIndex = 0;
608 let protoSrcNode = zigAnalysis.astNodes[protoSrcIndex];
609 if (
610 docsSource == null &&
611 protoSrcNode != null &&
612 protoSrcNode.docs != null
613 ) {
614 docsSource = protoSrcNode.docs;
615 }
616 if (docsSource != null) {
617 domTldDocs.innerHTML = markdown(docsSource);
618 domTldDocs.classList.remove("hidden");
619 }
620 domFnProto.classList.remove("hidden");
621 }
617622
618 for (let i = 0; i < fields.length; i += 1) {
619 let field = fields[i];
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;
623 function renderFnParamDocs(fnDecl, typeObj) {
624 let docCount = 0;
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];
631 let preClass = docsNonEmpty ? ' class="fieldHasDocs"' : "";
632 let html = '<pre' + preClass + '>' + escapeHtml((fieldNode.name)) + ": ";
633 if (isVarArgs && i === typeObj.params.length - 1) {
634 html += '...';
635 } else {
636 let name = exprName(value, {wantHtml: false, wantLink: false});
637 html += '<span class="tok-kw">' + name + '</span>';
638 }
630 for (let i = 0; i < fields.length; i += 1) {
631 let field = fields[i];
632 let fieldNode = zigAnalysis.astNodes[field];
633 if (fieldNode.docs != null) {
634 docCount += 1;
635 }
636 }
637 if (docCount == 0) {
638 return;
639 }
639640
640 html += ',</pre>';
641 resizeDomList(domListParams, docCount, "<div></div>");
642 let domIndex = 0;
641643
642 if (docsNonEmpty) {
643 html += '<div class="fieldDocs">' + markdown(docs) + '</div>';
644 }
645 divDom.innerHTML = html;
646 }
647 domSectParams.classList.remove("hidden");
648 }
649
650 function renderNav() {
651 let len = curNav.pkgNames.length + curNav.declNames.length;
652 resizeDomList(domListNav, len, '<li><a href="#"></a></li>');
653 let list = [];
654 let hrefPkgNames = [];
655 let hrefDeclNames = ([]);
656 for (let i = 0; i < curNav.pkgNames.length; i += 1) {
657 hrefPkgNames.push(curNav.pkgNames[i]);
658 let name = curNav.pkgNames[i];
659 if (name == "root") name = zigAnalysis.rootPkgName;
660 list.push({
661 name: name,
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 }
644 for (let i = 0; i < fields.length; i += 1) {
645 let field = fields[i];
646 let fieldNode = zigAnalysis.astNodes[field];
647 let docs = fieldNode.docs;
648 if (fieldNode.docs == null) {
649 continue;
650 }
651 let docsNonEmpty = docs !== "";
652 let divDom = domListParams.children[domIndex];
653 domIndex += 1;
654
655 let value = typeObj.params[i];
656 let preClass = docsNonEmpty ? ' class="fieldHasDocs"' : "";
657 let html = "<pre" + preClass + ">" + escapeHtml(fieldNode.name) + ": ";
658 if (isVarArgs && i === typeObj.params.length - 1) {
659 html += "...";
660 } else {
661 let name = exprName(value, { wantHtml: false, wantLink: false });
662 html += '<span class="tok-kw">' + name + "</span>";
663 }
672664
673 for (let i = 0; i < list.length; i += 1) {
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 }
665 html += ",</pre>";
684666
685 domSectNav.classList.remove("hidden");
667 if (docsNonEmpty) {
668 html += '<div class="fieldDocs">' + markdown(docs) + "</div>";
669 }
670 divDom.innerHTML = html;
686671 }
687
688 function renderInfo() {
689 domTdZigVer.textContent = zigAnalysis.params.zigVersion;
690 //domTdTarget.textContent = zigAnalysis.params.builds[0].target;
691
692 domSectInfo.classList.remove("hidden");
672 domSectParams.classList.remove("hidden");
673 }
674
675 function renderNav() {
676 let len = curNav.pkgNames.length + curNav.declNames.length;
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 });
693689 }
694
695 function render404() {
696 domStatus.textContent = "404 Not Found";
697 domStatus.classList.remove("hidden");
690 for (let i = 0; i < curNav.declNames.length; i += 1) {
691 hrefDeclNames.push(curNav.declNames[i]);
692 list.push({
693 name: curNav.declNames[i],
694 link: navLink(hrefPkgNames, hrefDeclNames),
695 });
698696 }
699697
700 function renderPkgList() {
701 let rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg];
702 let list = [];
703 for (let key in rootPkg.table) {
704 let pkgIndex = rootPkg.table[key];
705 if (zigAnalysis.packages[pkgIndex] == null) continue;
706 if (key == zigAnalysis.params.rootName) continue;
707 list.push({
708 name: key,
709 pkg: pkgIndex,
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 }
698 for (let i = 0; i < list.length; i += 1) {
699 let liDom = domListNav.children[i];
700 let aDom = liDom.children[0];
701 aDom.textContent = list[i].name;
702 aDom.setAttribute("href", list[i].link);
703 if (i + 1 == list.length) {
704 aDom.classList.add("active");
705 } else {
706 aDom.classList.remove("active");
707 }
745708 }
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) {
750 let base = '#';
751 if (curNav.showPrivDecls) {
752 base += "*";
753 }
738 {
739 let aDom = domSectMainPkg.children[1].children[0].children[0];
740 aDom.textContent = zigAnalysis.rootPkgName;
741 aDom.setAttribute("href", navLinkPkg(zigAnalysis.rootPkg));
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) {
756 return base;
757 } else if (declNames.length === 0 && callName == null) {
758 return base + pkgNames.join('.');
759 } else if (callName == null) {
760 return base + pkgNames.join('.') + ';' + declNames.join('.');
750 list.sort(function (a, b) {
751 return operatorCompare(a.name.toLowerCase(), b.name.toLowerCase());
752 });
753
754 if (list.length !== 0) {
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");
761763 } else {
762 return base + pkgNames.join('.') + ';' + declNames.join('.') + ';' + callName;
764 aDom.classList.remove("active");
763765 }
764 }
766 }
765767
766
767 function navLinkPkg(pkgIndex) {
768 return navLink(canonPkgPaths[pkgIndex], []);
768 domSectPkgs.classList.remove("hidden");
769769 }
770 }
770771
771
772 function navLinkDecl(childName) {
773 return navLink(curNav.pkgNames, curNav.declNames.concat([childName]));
772 function navLink(pkgNames, declNames, callName) {
773 let base = "#";
774 if (curNav.showPrivDecls) {
775 base += "*";
774776 }
775777
776 //
777 // function navLinkCall(callObj) {
778 // let declNamesCopy = curNav.declNames.concat([]);
779 // let callName = (declNamesCopy.pop());
780
781 // callName += '(';
782 // for (let arg_i = 0; arg_i < callObj.args.length; arg_i += 1) {
783 // if (arg_i !== 0) callName += ',';
784 // let argObj = callObj.args[arg_i];
785 // callName += getValueText(argObj, argObj, false, false);
786 // }
787 // callName += ')';
788
789 // declNamesCopy.push(callName);
790 // return navLink(curNav.pkgNames, declNamesCopy);
791 // }
778 if (pkgNames.length === 0 && declNames.length === 0) {
779 return base;
780 } else if (declNames.length === 0 && callName == null) {
781 return base + pkgNames.join(".");
782 } else if (callName == null) {
783 return base + pkgNames.join(".") + ";" + declNames.join(".");
784 } else {
785 return (
786 base + pkgNames.join(".") + ";" + declNames.join(".") + ";" + callName
787 );
788 }
789 }
790
791 function navLinkPkg(pkgIndex) {
792 return navLink(canonPkgPaths[pkgIndex], []);
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
794 function resizeDomListDl(dlDom, desiredLen) {
795 // add the missing dom entries
796 for (let i = dlDom.childElementCount / 2; i < desiredLen; i += 1) {
797 dlDom.insertAdjacentHTML('beforeend', '<dt></dt><dd></dd>');
798 }
799 // remove extra dom entries
800 while (desiredLen < dlDom.childElementCount / 2) {
801 dlDom.removeChild(dlDom.lastChild);
802 dlDom.removeChild(dlDom.lastChild);
803 }
828 function resizeDomList(listDom, desiredLen, templateHtml) {
829 // add the missing dom entries
830 for (let i = listDom.childElementCount; i < desiredLen; i += 1) {
831 listDom.insertAdjacentHTML("beforeend", templateHtml);
832 }
833 // remove extra dom entries
834 while (desiredLen < listDom.childElementCount) {
835 listDom.removeChild(listDom.lastChild);
804836 }
837 }
805838
806
807 function resizeDomList(listDom, desiredLen, templateHtml) {
808 // add the missing dom entries
809 for (let i = listDom.childElementCount; i < desiredLen; i += 1) {
810 listDom.insertAdjacentHTML('beforeend', templateHtml);
839 function walkResultTypeRef(wr) {
840 if (wr.typeRef) return wr.typeRef;
841 let resolved = resolveValue(wr);
842 if (wr === resolved) {
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 }
811927 }
812 // remove extra dom entries
813 while (desiredLen < listDom.childElementCount) {
814 listDom.removeChild(listDom.lastChild);
928
929 return (
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;
8151009 }
816 }
817
818 function walkResultTypeRef(wr) {
819 if (wr.typeRef) return wr.typeRef;
820 let resolved = resolveValue(wr);
821 if (wr === resolved) {
822 return {type: 0};
823 }
824 return walkResultTypeRef(resolved);
825 }
826
827 function exprName(expr, opts) {
828 switch (Object.keys(expr)[0]) {
829 default: throw "this expression is not implemented yet";
830 case "bool": {
831 if (expr.bool) {
832 return "true";
833 }
834 return "false";
1010 return name;
1011 }
1012 case "fieldRef": {
1013 const enumObj = exprName({ type: expr.fieldRef.type }, opts);
1014 const field =
1015 zigAnalysis.astNodes[enumObj.ast].fields[expr.fieldRef.index];
1016 const name = zigAnalysis.astNodes[field].name;
1017 return name;
1018 }
1019 case "enumToInt": {
1020 const enumToInt = zigAnalysis.exprs[expr.enumToInt];
1021 return "@enumToInt(" + exprName(enumToInt, opts) + ")";
1022 }
1023 case "bitSizeOf": {
1024 const bitSizeOf = zigAnalysis.exprs[expr.bitSizeOf];
1025 return "@bitSizeOf(" + exprName(bitSizeOf, opts) + ")";
1026 }
1027 case "sizeOf": {
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;
8351044 }
836 case "&": {
837 return "&" + exprName(zigAnalysis.exprs[expr["&"]]);
1045 case "bool_to_int": {
1046 payloadHtml += "boolToInt";
1047 break;
8381048 }
839 case "compileError": {
840 let compileError = expr.compileError;
841 return compileError;
1049 case "embed_file": {
1050 payloadHtml += "embedFile";
1051 break;
8421052 }
843 case "enumLiteral": {
844 let literal = expr.enumLiteral;
845 return "." + literal;
1053 case "error_name": {
1054 payloadHtml += "errorName";
1055 break;
8461056 }
847 case "void": {
848 return "void";
1057 case "panic": {
1058 payloadHtml += "panic";
1059 break;
8491060 }
850 case "slice":{
851 let payloadHtml = "";
852 const lhsExpr = zigAnalysis.exprs[expr.slice.lhs];
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;
1061 case "set_cold": {
1062 payloadHtml += "setCold";
1063 break;
8701064 }
871 case "sliceIndex": {
872 const sliceIndex = zigAnalysis.exprs[expr.sliceIndex];
873 return exprName(sliceIndex, opts);
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;
1065 case "set_runtime_safety": {
1066 payloadHtml += "setRuntimeSafety";
1067 break;
9341068 }
935 case "switchIndex": {
936 const switchIndex = zigAnalysis.exprs[expr.switchIndex];
937 return exprName(switchIndex, opts);
1069 case "sqrt": {
1070 payloadHtml += "sqrt";
1071 break;
9381072 }
939 case "refPath" : {
940 let name = exprName(expr.refPath[0]);
941 for (let i = 1; i < expr.refPath.length; i++) {
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;
1073 case "sin": {
1074 payloadHtml += "sin";
1075 break;
9511076 }
952 case "fieldRef" : {
953 const enumObj = exprName({"type":expr.fieldRef.type} ,opts);
954 const field = zigAnalysis.astNodes[enumObj.ast].fields[expr.fieldRef.index];
955 const name = zigAnalysis.astNodes[field].name;
956 return name
1077 case "cos": {
1078 payloadHtml += "cos";
1079 break;
9571080 }
958 case "enumToInt" : {
959 const enumToInt = zigAnalysis.exprs[expr.enumToInt];
960 return "@enumToInt(" + exprName(enumToInt, opts) + ")";
1081 case "tan": {
1082 payloadHtml += "tan";
1083 break;
9611084 }
962 case "bitSizeOf" : {
963 const bitSizeOf = zigAnalysis.exprs[expr.bitSizeOf];
964 return "@bitSizeOf(" + exprName(bitSizeOf, opts) + ")";
1085 case "exp": {
1086 payloadHtml += "exp";
1087 break;
9651088 }
966 case "sizeOf" : {
967 const sizeOf = zigAnalysis.exprs[expr.sizeOf];
968 return "@sizeOf(" + exprName(sizeOf, opts) + ")";
1089 case "exp2": {
1090 payloadHtml += "exp2";
1091 break;
9691092 }
970 case "builtinIndex" : {
971 const builtinIndex = zigAnalysis.exprs[expr.builtinIndex];
972 return exprName(builtinIndex, opts);
1093 case "log": {
1094 payloadHtml += "log";
1095 break;
9731096 }
974 case "builtin": {
975 const param_expr = zigAnalysis.exprs[expr.builtin.param];
976 let param = exprName(param_expr, opts);
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
1097 case "log2": {
1098 payloadHtml += "log2";
1099 break;
11271100 }
1128 case "builtinBinIndex" : {
1129 const builtinBinIndex = zigAnalysis.exprs[expr.builtinBinIndex];
1130 return exprName(builtinBinIndex, opts);
1101 case "log10": {
1102 payloadHtml += "log10";
1103 break;
11311104 }
1132 case "builtinBin": {
1133 const lhsOp = zigAnalysis.exprs[expr.builtinBin.lhs];
1134 const rhsOp = zigAnalysis.exprs[expr.builtinBin.rhs];
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
1105 case "fabs": {
1106 payloadHtml += "fabs";
1107 break;
12521108 }
1253 case "binOpIndex" : {
1254 const binOpIndex = zigAnalysis.exprs[expr.binOpIndex];
1255 return exprName(binOpIndex, opts);
1109 case "floor": {
1110 payloadHtml += "floor";
1111 break;
12561112 }
1257 case "binOp": {
1258 const lhsOp = zigAnalysis.exprs[expr.binOp.lhs];
1259 const rhsOp = zigAnalysis.exprs[expr.binOp.rhs];
1260 let lhs = exprName(lhsOp, opts);
1261 let rhs = exprName(rhsOp, opts);
1262
1263 let print_lhs = "";
1264 let print_rhs = "";
1265
1266 if (lhsOp['binOpIndex']) {
1267 print_lhs = "(" + lhs + ")";
1268 } else {
1269 print_lhs = lhs;
1270 }
1271 if (rhsOp['binOpIndex']) {
1272 print_rhs = "(" + rhs + ")";
1273 } else {
1274 print_rhs = rhs;
1275 }
1113 case "ceil": {
1114 payloadHtml += "ceil";
1115 break;
1116 }
1117 case "trunc": {
1118 payloadHtml += "trunc";
1119 break;
1120 }
1121 case "round": {
1122 payloadHtml += "round";
1123 break;
1124 }
1125 case "tag_name": {
1126 payloadHtml += "tagName";
1127 break;
1128 }
1129 case "reify": {
1130 payloadHtml += "Type";
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) {
1280 case "add": {
1281 operator += "+";
1282 break;
1283 }
1284 case "addwrap": {
1285 operator += "+%";
1286 break;
1287 }
1288 case "add_sat": {
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 };
1326 if (lhsOp["binOpIndex"]) {
1327 print_lhs = "(" + lhs + ")";
1328 } else {
1329 print_lhs = lhs;
1330 }
1331 if (rhsOp["binOpIndex"]) {
1332 print_rhs = "(" + rhs + ")";
1333 } else {
1334 print_rhs = rhs;
1335 }
13501336
1351 return print_lhs + " " + operator + " " + print_rhs;
1337 let operator = "";
13521338
1339 switch (expr.binOp.name) {
1340 case "add": {
1341 operator += "+";
1342 break;
13531343 }
1354 case "errorSets": {
1355 const errUnionObj = zigAnalysis.types[expr.errorSets];
1356 let lhs = exprName(errUnionObj.lhs, opts);
1357 let rhs = exprName(errUnionObj.rhs, opts);
1358 return lhs + " || " + rhs;
1359
1344 case "addwrap": {
1345 operator += "+%";
1346 break;
13601347 }
1361 case "errorUnion": {
1362 const errUnionObj = zigAnalysis.types[expr.errorUnion];
1363 let lhs = exprName(errUnionObj.lhs, opts);
1364 let rhs = exprName(errUnionObj.rhs, opts);
1365 return lhs + "!" + rhs;
1366
1348 case "add_sat": {
1349 operator += "+|";
1350 break;
13671351 }
1368 case "struct": {
1369 const struct_name = zigAnalysis.decls[expr.struct[0].val.typeRef.refPath[0].declRef].name;
1370 let struct_body = "";
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
1352 case "sub": {
1353 operator += "-";
1354 break;
14011355 }
1402 case "alignOf": {
1403 const alignRefArg = zigAnalysis.exprs[expr.alignOf];
1404 let payloadHtml = "@alignOf(" + exprName(alignRefArg, {wantHtml: true, wantLink:true}) + ")";
1405 return payloadHtml;
1356 case "subwrap": {
1357 operator += "-%";
1358 break;
14061359 }
1407 case "typeOf": {
1408 const typeRefArg = zigAnalysis.exprs[expr.typeOf];
1409 let payloadHtml = "@TypeOf(" + exprName(typeRefArg, {wantHtml: true, wantLink:true}) + ")";
1410 return payloadHtml;
1360 case "sub_sat": {
1361 operator += "-|";
1362 break;
14111363 }
1412 case "typeInfo": {
1413 const typeRefArg = zigAnalysis.exprs[expr.typeInfo];
1414 let payloadHtml = "@typeInfo(" + exprName(typeRefArg, {wantHtml: true, wantLink:true}) + ")";
1415 return payloadHtml;
1364 case "mul": {
1365 operator += "*";
1366 break;
14161367 }
1417 case "null": {
1418 return "null";
1368 case "mulwrap": {
1369 operator += "*%";
1370 break;
14191371 }
1420 case "array": {
1421 let payloadHtml = ".{";
1422 for (let i = 0; i < expr.array.length; i++) {
1423 if (i != 0) payloadHtml += ", ";
1424 let elem = zigAnalysis.exprs[expr.array[i]];
1425 payloadHtml += exprName(elem, opts);
1426 }
1427 return payloadHtml + "}";
1372 case "mul_sat": {
1373 operator += "*|";
1374 break;
1375 }
1376 case "div": {
1377 operator += "/";
1378 break;
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;
14281407 }
1429 case "comptimeExpr": {
1430 return zigAnalysis.comptimeExprs[expr.comptimeExpr].code;
1408 default:
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;
14311516 }
1432 case "call": {
1433 let call = zigAnalysis.calls[expr.call];
1434 let payloadHtml = "";
1517 }
1518 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]){
1438 default: throw "TODO";
1439 case "declRef":
1440 case "refPath": {
1441 payloadHtml += exprName(call.func, opts);
1442 break;
1443 }
1444 }
1445 payloadHtml += "(";
1525 payloadHtml += ")";
1526 return payloadHtml;
1527 }
1528 case "as": {
1529 // @Check : this should be done in backend because there are legit @as() calls
1530 // const typeRefArg = zigAnalysis.exprs[expr.as.typeRefArg];
1531 const exprArg = zigAnalysis.exprs[expr.as.exprArg];
1532 // return "@as(" + exprName(typeRefArg, opts) +
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++) {
1448 if (i != 0) payloadHtml += ", ";
1449 payloadHtml += exprName(call.args[i], opts);
1450 }
1558 case "anytype": {
1559 return "anytype";
1560 }
1561
1562 case "this": {
1563 return "@This()";
1564 }
14511565
1452 payloadHtml += ")";
1453 return payloadHtml;
1566 case "type": {
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;
14541577 }
1455 case "as": {
1456 // @Check : this should be done in backend because there are legit @as() calls
1457 // const typeRefArg = zigAnalysis.exprs[expr.as.typeRefArg];
1458 const exprArg = zigAnalysis.exprs[expr.as.exprArg];
1459 // return "@as(" + exprName(typeRefArg, opts) +
1460 // ", " + exprName(exprArg, opts) + ")";
1461 return exprName(exprArg, opts);
1578 case typeKinds.Enum: {
1579 let enumObj = typeObj;
1580 return enumObj;
14621581 }
1463 case "declRef": {
1464 return zigAnalysis.decls[expr.declRef].name;
1582 case typeKinds.Opaque: {
1583 let opaqueObj = typeObj;
1584
1585 return opaqueObj.name;
14651586 }
1466 case "refPath": {
1467 return expr.refPath.map(x => exprName(x, opts)).join(".");
1587 case typeKinds.ComptimeExpr: {
1588 return "anyopaque";
14681589 }
1469 case "int": {
1470 return "" + expr.int;
1590 case typeKinds.Array: {
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;
14711609 }
1472 case "float": {
1473 return "" + expr.float.toFixed(2);
1610 case typeKinds.Optional:
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;
14741704 }
1475 case "float128": {
1476 return "" + expr.float128.toFixed(2);
1705 case typeKinds.Float: {
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 }
14771713 }
1478 case "undefined": {
1479 return "undefined";
1714 case typeKinds.Int: {
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 }
14801722 }
1481 case "string": {
1482 return "\"" + escapeHtml(expr.string) + "\"";
1723 case typeKinds.ComptimeInt:
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 }
14831780 }
14841781
1485 case "anytype": {
1486 return "anytype";
1782 case typeKinds.ErrorUnion: {
1783 let errUnionObj = typeObj;
1784 let lhs = exprName(errUnionObj.lhs, opts);
1785 let rhs = exprName(errUnionObj.rhs, opts);
1786 return lhs + "!" + rhs;
14871787 }
1488
1489 case "this":{
1490 return "@This()";
1788 case typeKinds.InferredErrorUnion: {
1789 let errUnionObj = typeObj;
1790 let payload = exprName(errUnionObj.payload, opts);
1791 return "!" + payload;
14911792 }
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": {
1494 let name = "";
1834 payloadHtml +=
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;
1497 if (typeof typeObj === 'number') typeObj = zigAnalysis.types[typeObj];
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);
1839 if (fields != null) {
1840 let paramNode = zigAnalysis.astNodes[fields[i]];
15131841
1514 return opaqueObj.name;
1842 if (paramNode.varArgs) {
1843 payloadHtml += "...";
1844 continue;
15151845 }
1516 case typeKinds.ComptimeExpr:
1517 {
1518 return "anyopaque";
1846
1847 if (paramNode.noalias) {
1848 if (opts.wantHtml) {
1849 payloadHtml += '<span class="tok-kw">noalias</span> ';
1850 } else {
1851 payloadHtml += "noalias ";
1852 }
15191853 }
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) {
15281856 if (opts.wantHtml) {
1529 name +=
1530 '<span class="tok-number">' + lenName + sentinel + "</span>";
1857 payloadHtml += '<span class="tok-kw">comptime</span> ';
15311858 } else {
1532 name += lenName + sentinel;
1859 payloadHtml += "comptime ";
15331860 }
1534 name += "]";
1535 // name += is_mutable;
1536 name += exprName(arrayObj.child, opts);
1537 return name;
15381861 }
1539 case typeKinds.Optional:
1540 return "?" + exprName((typeObj).child, opts);
1541 case typeKinds.Pointer:
1542 {
1543 let ptrObj = (typeObj);
1544 let sentinel = ptrObj.sentinel ? ":"+exprName(ptrObj.sentinel, opts) : "";
1545 let is_mutable = !ptrObj.is_mutable ? "const " : "";
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;
1862
1863 let paramName = paramNode.name;
1864 if (paramName != null) {
1865 // skip if it matches the type name
1866 if (!shouldSkipParamName(paramValue, paramName)) {
1867 payloadHtml += paramName + ": ";
1868 }
16261869 }
1627 case typeKinds.Float:
1628 {
1629 let floatObj = (typeObj);
1630
1631 if (opts.wantHtml) {
1632 return '<span class="tok-type">' + floatObj.name + '</span>';
1633 } else {
1634 return floatObj.name;
1635 }
1870 }
1871
1872 if (isVarArgs && i === fnObj.params.length - 1) {
1873 payloadHtml += "...";
1874 } else if ("alignOf" in value) {
1875 if (opts.wantHtml) {
1876 payloadHtml += '<a href="">';
1877 payloadHtml +=
1878 '<span class="tok-kw" style="color:lightblue;">' +
1879 exprName(value, opts) +
1880 "</span>";
1881 payloadHtml += "</a>";
1882 } else {
1883 payloadHtml += exprName(value, opts);
16361884 }
1637 case typeKinds.Int:
1638 {
1639 let intObj = (typeObj);
1640 let name = intObj.name;
1641 if (opts.wantHtml) {
1642 return '<span class="tok-type">' + name + '</span>';
1643 } else {
1644 return name;
1645 }
1885 } else if ("typeOf" in value) {
1886 if (opts.wantHtml) {
1887 payloadHtml += '<a href="">';
1888 payloadHtml +=
1889 '<span class="tok-kw" style="color:lightblue;">' +
1890 exprName(value, opts) +
1891 "</span>";
1892 payloadHtml += "</a>";
1893 } else {
1894 payloadHtml += exprName(value, opts);
16461895 }
1647 case typeKinds.ComptimeInt:
1648 if (opts.wantHtml) {
1649 return '<span class="tok-type">comptime_int</span>';
1650 } else {
1651 return "comptime_int";
1652 }
1653 case typeKinds.ComptimeFloat:
1654 if (opts.wantHtml) {
1655 return '<span class="tok-type">comptime_float</span>';
1656 } else {
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 }
1896 } else if ("typeOf_peer" in value) {
1897 if (opts.wantHtml) {
1898 payloadHtml += '<a href="">';
1899 payloadHtml +=
1900 '<span class="tok-kw" style="color:lightblue;">' +
1901 exprName(value, opts) +
1902 "</span>";
1903 payloadHtml += "</a>";
1904 } else {
1905 payloadHtml += exprName(value, opts);
16991906 }
1700
1701 case typeKinds.ErrorUnion:
1702 {
1703 let errUnionObj = (typeObj);
1704 let lhs = exprName(errUnionObj.lhs, opts);
1705 let rhs = exprName(errUnionObj.rhs, opts);
1706 return lhs + "!" + rhs;
1907 } else if ("declRef" in value) {
1908 if (opts.wantHtml) {
1909 payloadHtml += '<a href="">';
1910 payloadHtml +=
1911 '<span class="tok-kw" style="color:lightblue;">' +
1912 exprName(value, opts) +
1913 "</span>";
1914 payloadHtml += "</a>";
1915 } else {
1916 payloadHtml += exprName(value, opts);
17071917 }
1708 case typeKinds.InferredErrorUnion:
1709 {
1710 let errUnionObj = (typeObj);
1711 let payload = exprName(errUnionObj.payload, opts);
1712 return "!" + payload;
1918 } else if ("call" in value) {
1919 if (opts.wantHtml) {
1920 payloadHtml += '<a href="">';
1921 payloadHtml +=
1922 '<span class="tok-kw" style="color:lightblue;">' +
1923 exprName(value, opts) +
1924 "</span>";
1925 payloadHtml += "</a>";
1926 } else {
1927 payloadHtml += exprName(value, opts);
17131928 }
1714 case typeKinds.Fn:
1715 {
1716 let fnObj = (typeObj);
1717 let payloadHtml = "";
1718 if (opts.wantHtml) {
1719 if (fnObj.is_extern) {
1720 payloadHtml += "pub extern ";
1721 }
1722 if (fnObj.has_lib_name) {
1723 payloadHtml += "\"" + fnObj.lib_name +"\" ";
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;
1929 } else if ("refPath" in value) {
1930 if (opts.wantHtml) {
1931 payloadHtml += '<a href="">';
1932 payloadHtml +=
1933 '<span class="tok-kw" style="color:lightblue;">' +
1934 exprName(value, opts) +
1935 "</span>";
1936 payloadHtml += "</a>";
1937 } else {
1938 payloadHtml += exprName(value, opts);
19111939 }
1912 // if (wantHtml) {
1913 // return escapeHtml(typeObj.name);
1914 // } else {
1915 // return typeObj.name;
1916 // }
1917 }
1918 }
1919
1920 }
1921 }
1922
1923
1924
1925 function shouldSkipParamName(typeRef, paramName) {
1926 let resolvedTypeRef = resolveValue({expr: typeRef});
1927 if ("type" in resolvedTypeRef) {
1928 let typeObj = zigAnalysis.types[resolvedTypeRef.type];
1929 if (typeObj.kind === typeKinds.Pointer){
1930 let ptrObj = (typeObj);
1931 if (getPtrSize(ptrObj) === pointerSizeEnum.One) {
1932 const value = resolveValue(ptrObj.child);
1933 return typeValueName(value, false, true).toLowerCase() === paramName;
1940 } else if ("type" in value) {
1941 let name = exprName(value, {
1942 wantHtml: false,
1943 wantLink: false,
1944 fnDecl: opts.fnDecl,
1945 linkFnNameDecl: opts.linkFnNameDecl,
1946 });
1947 payloadHtml += '<span class="tok-kw">' + name + "</span>";
1948 } else if ("binOpIndex" in value) {
1949 payloadHtml += exprName(value, opts);
1950 } else if ("comptimeExpr" in value) {
1951 let comptimeExpr =
1952 zigAnalysis.comptimeExprs[value.comptimeExpr].code;
1953 if (opts.wantHtml) {
1954 payloadHtml +=
1955 '<span class="tok-kw">' + comptimeExpr + "</span>";
1956 } else {
1957 payloadHtml += comptimeExpr;
1958 }
1959 } else if (opts.wantHtml) {
1960 payloadHtml += '<span class="tok-kw">anytype</span>';
1961 } else {
1962 payloadHtml += "anytype";
19341963 }
1964 }
19351965 }
1936 }
1937 return false;
1938 }
1939
1940
1941 function getPtrSize(typeObj) {
1942 return (typeObj.size == null) ? pointerSizeEnum.One : typeObj.size;
1943 }
19441966
1945
1946 function renderType(typeObj) {
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 }
1967 payloadHtml += "<span class='argBreaker'>,<br></span>";
1968 payloadHtml += ") ";
19611969
1962
1963 function renderErrorSet(errSetType) {
1964 if (errSetType.fields == null) {
1965 domFnErrorsAnyError.classList.remove("hidden");
1966 } else {
1967 let errorList = [];
1968 for (let i = 0; i < errSetType.fields.length; i += 1) {
1969 let errObj = errSetType.fields[i];
1970 //let srcObj = zigAnalysis.astNodes[errObj.src];
1971 errorList.push(errObj);
1970 if (fnObj.has_align) {
1971 let align = zigAnalysis.exprs[fnObj.align];
1972 payloadHtml += "align(" + exprName(align, opts) + ") ";
1973 }
1974 if (fnObj.has_cc) {
1975 let cc = zigAnalysis.exprs[fnObj.cc];
1976 if (cc) {
1977 payloadHtml += "callconv(." + cc.enumLiteral + ") ";
1978 }
19721979 }
1973 errorList.sort(function(a, b) {
1974 return operatorCompare(a.name.toLowerCase(), b.name.toLowerCase());
1975 });
19761980
1977 resizeDomListDl(domListFnErrors, errorList.length);
1978 for (let i = 0; i < errorList.length; i += 1) {
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 }
1981 if (fnObj.is_inferred_error) {
1982 payloadHtml += "!";
19881983 }
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 // }
19901998 }
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}) + ";";
20881999 }
2089
2090 let docs = zigAnalysis.astNodes[decl.src].docs;
2091 if (docs != null) {
2092 domTldDocs.innerHTML = markdown(docs);
2093 domTldDocs.classList.remove("hidden");
2000 }
2001 }
2002
2003 function shouldSkipParamName(typeRef, paramName) {
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;
20942012 }
2095
2096 domFnProto.classList.remove("hidden");
2013 }
20972014 }
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
2100 function renderVar(decl) {
2101 let declTypeRef = typeOfDecl(decl);
2102 domFnProtoCode.innerHTML = '<span class="tok-kw">var</span> ' +
2103 escapeHtml(decl.name) + ': ' + typeValueName(declTypeRef, true, true);
2104
2105 let docs = zigAnalysis.astNodes[decl.src].docs;
2043 function renderErrorSet(errSetType) {
2044 if (errSetType.fields == null) {
2045 domFnErrorsAnyError.classList.remove("hidden");
2046 } else {
2047 let errorList = [];
2048 for (let i = 0; i < errSetType.fields.length; i += 1) {
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;
21062063 if (docs != null) {
2107 domTldDocs.innerHTML = markdown(docs);
2108 domTldDocs.classList.remove("hidden");
2064 descTdDom.innerHTML = markdown(docs);
2065 } else {
2066 descTdDom.textContent = "";
21092067 }
2110
2111 domFnProto.classList.remove("hidden");
2068 }
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 ";";
21122187 }
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
2116 function categorizeDecls(decls,
2117 typesList, namespacesList, errSetsList,
2118 fnsList, varsList, valsList, testsList) {
2119
2120 for (let i = 0; i < decls.length; i += 1) {
2121 let decl = zigAnalysis.decls[decls[i]];
2122 let declValue = resolveValue(decl.value);
2123
2124 if (decl.isTest) {
2125 testsList.push(decl);
2126 continue;
2127 }
2128
2129 if (decl.kind === 'var') {
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 }
2195 domFnProto.classList.remove("hidden");
2196 }
2197
2198 function renderVar(decl) {
2199 let declTypeRef = typeOfDecl(decl);
2200 domFnProtoCode.innerHTML =
2201 '<span class="tok-kw">var</span> ' +
2202 escapeHtml(decl.name) +
2203 ": " +
2204 typeValueName(declTypeRef, true, true);
2205
2206 let docs = zigAnalysis.astNodes[decl.src].docs;
2207 if (docs != null) {
2208 domTldDocs.innerHTML = markdown(docs);
2209 domTldDocs.classList.remove("hidden");
21742210 }
21752211
2176
2177 function renderContainer(container) {
2178
2179 let typesList = [];
2180
2181 let namespacesList = [];
2182
2183 let errSetsList = [];
2184
2185 let fnsList = [];
2186
2187 let varsList = [];
2188
2189 let valsList = [];
2190
2191 let testsList = [];
2192
2193 categorizeDecls(container.pubDecls,
2194 typesList, namespacesList, errSetsList,
2195 fnsList, varsList, valsList, testsList);
2196 if (curNav.showPrivDecls) categorizeDecls(container.privDecls,
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 }
2212 domFnProto.classList.remove("hidden");
2213 }
2214
2215 function categorizeDecls(
2216 decls,
2217 typesList,
2218 namespacesList,
2219 errSetsList,
2220 fnsList,
2221 varsList,
2222 valsList,
2223 testsList
2224 ) {
2225 for (let i = 0; i < decls.length; i += 1) {
2226 let decl = zigAnalysis.decls[decls[i]];
2227 let declValue = resolveValue(decl.value);
2228
2229 if (decl.isTest) {
2230 testsList.push(decl);
2231 continue;
2232 }
22162233
2217 if (typesList.length !== 0) {
2218 window.x = typesList;
2219 resizeDomList(domListTypes, typesList.length, '<li><a href="#"></a></li>');
2220 for (let i = 0; i < typesList.length; i += 1) {
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 }
2234 if (decl.kind === "var") {
2235 varsList.push(decl);
2236 continue;
2237 }
22402238
2241 if (errSetsList.length !== 0) {
2242 resizeDomList(domListErrSets, errSetsList.length, '<li><a href="#"></a></li>');
2243 for (let i = 0; i < errSetsList.length; i += 1) {
2244 let liDom = domListErrSets.children[i];
2245 let aDom = liDom.children[0];
2246 let decl = errSetsList[i];
2247 aDom.textContent = decl.name;
2248 aDom.setAttribute('href', navLinkDecl(decl.name));
2239 if (decl.kind === "const") {
2240 if ("type" in declValue.expr) {
2241 // We have the actual type expression at hand.
2242 const typeExpr = zigAnalysis.types[declValue.expr.type];
2243 if (typeExpr.kind == typeKinds.Fn) {
2244 const funcRetExpr = resolveValue({
2245 expr: typeExpr.ret,
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);
22492260 }
2250 domSectErrSets.classList.remove("hidden");
2251 }
2252
2253 if (fnsList.length !== 0) {
2254 resizeDomList(domListFns, fnsList.length, '<div><dt></dt><dd></dd></div>');
2255
2256 for (let i = 0; i < fnsList.length; i += 1) {
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 }
2261 } else {
2262 if (typeIsErrSet(declValue.expr.type)) {
2263 errSetsList.push(decl);
2264 } else if (typeIsStructWithNoFields(declValue.expr.type)) {
2265 namespacesList.push(decl);
2266 } else {
2267 typesList.push(decl);
22792268 }
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);
22812279 }
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];
2284 if (containerNode.fields && containerNode.fields.length > 0) {
2285 resizeDomList(domListFields, containerNode.fields.length, '<div></div>');
2344 if (typesList.length !== 0) {
2345 window.x = typesList;
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) {
2288 let fieldNode = zigAnalysis.astNodes[containerNode.fields[i]];
2289 let divDom = domListFields.children[i];
2290 let fieldName = (fieldNode.name);
2291 let docs = fieldNode.docs;
2292 let docsNonEmpty = docs != null && docs !== "";
2293 let extraPreClass = docsNonEmpty ? " fieldHasDocs" : "";
2376 if (errSetsList.length !== 0) {
2377 resizeDomList(
2378 domListErrSets,
2379 errSetsList.length,
2380 '<li><a href="#"></a></li>'
2381 );
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) {
2298 html += ' = <span class="tok-number">' + fieldName + '</span>';
2299 } else {
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>';
2399 for (let i = 0; i < fnsList.length; i += 1) {
2400 let decl = fnsList[i];
2401 let trDom = domListFns.children[i];
23072402
2308 }
2309 }
2403 let tdFnCode = trDom.children[0];
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) {
2314 html += '<div class="fieldDocs">' + markdown(docs) + '</div>';
2315 }
2316 divDom.innerHTML = html;
2317 }
2318 domSectFields.classList.remove("hidden");
2415 let docs = zigAnalysis.astNodes[decl.src].docs;
2416 if (docs != null) {
2417 tdDesc.innerHTML = shortDescMarkdown(docs);
2418 } else {
2419 tdDesc.textContent = "";
23192420 }
2421 }
2422 domSectFns.classList.remove("hidden");
2423 }
23202424
2321 if (varsList.length !== 0) {
2322 resizeDomList(domListGlobalVars, varsList.length,
2323 '<tr><td><a href="#"></a></td><td></td><td></td></tr>');
2324 for (let i = 0; i < varsList.length; i += 1) {
2325 let decl = varsList[i];
2326 let trDom = domListGlobalVars.children[i];
2327
2328 let tdName = trDom.children[0];
2329 let tdNameA = tdName.children[0];
2330 let tdType = trDom.children[1];
2331 let tdDesc = trDom.children[2];
2332
2333 tdNameA.setAttribute('href', navLinkDecl(decl.name));
2334 tdNameA.textContent = decl.name;
2335
2336 tdType.innerHTML = typeValueName(typeOfDecl(decl), true, true);
2337
2338 let docs = zigAnalysis.astNodes[decl.src].docs;
2339 if (docs != null) {
2340 tdDesc.innerHTML = shortDescMarkdown(docs);
2341 } else {
2342 tdDesc.textContent = "";
2343 }
2344 }
2345 domSectGlobalVars.classList.remove("hidden");
2425 let containerNode = zigAnalysis.astNodes[container.src];
2426 if (containerNode.fields && containerNode.fields.length > 0) {
2427 resizeDomList(domListFields, containerNode.fields.length, "<div></div>");
2428
2429 for (let i = 0; i < containerNode.fields.length; i += 1) {
2430 let fieldNode = zigAnalysis.astNodes[containerNode.fields[i]];
2431 let divDom = domListFields.children[i];
2432 let fieldName = fieldNode.name;
2433 let docs = fieldNode.docs;
2434 let docsNonEmpty = docs != null && docs !== "";
2435 let extraPreClass = docsNonEmpty ? " fieldHasDocs" : "";
2436
2437 let html =
2438 '<div class="mobile-scroll-container"><pre class="scroll-item' +
2439 extraPreClass +
2440 '">' +
2441 escapeHtml(fieldName);
2442
2443 if (container.kind === typeKinds.Enum) {
2444 html += ' = <span class="tok-number">' + fieldName + "</span>";
2445 } else {
2446 let fieldTypeExpr = container.fields[i];
2447 html += ": ";
2448 let name = exprName(fieldTypeExpr, false, false);
2449 html += '<span class="tok-kw">' + name + "</span>";
2450 let tsn = typeShorthandName(fieldTypeExpr);
2451 if (tsn) {
2452 html += "<span> (" + tsn + ")</span>";
2453 }
23462454 }
23472455
2348 if (valsList.length !== 0) {
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];
2456 html += ",</pre></div>";
23542457
2355 let tdName = trDom.children[0];
2356 let tdNameA = tdName.children[0];
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");
2458 if (docsNonEmpty) {
2459 html += '<div class="fieldDocs">' + markdown(docs) + "</div>";
23742460 }
2461 divDom.innerHTML = html;
2462 }
2463 domSectFields.classList.remove("hidden");
2464 }
23752465
2376 if (testsList.length !== 0) {
2377 resizeDomList(domListTests, testsList.length,
2378 '<tr><td><a href="#"></a></td><td></td><td></td></tr>');
2379 for (let i = 0; i < testsList.length; i += 1) {
2380 let decl = testsList[i];
2381 let trDom = domListTests.children[i];
2466 if (varsList.length !== 0) {
2467 resizeDomList(
2468 domListGlobalVars,
2469 varsList.length,
2470 '<tr><td><a href="#"></a></td><td></td><td></td></tr>'
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];
2384 let tdNameA = tdName.children[0];
2385 let tdType = trDom.children[1];
2386 let tdDesc = trDom.children[2];
2476 let tdName = trDom.children[0];
2477 let tdNameA = tdName.children[0];
2478 let tdType = trDom.children[1];
2479 let tdDesc = trDom.children[2];
23872480
2388 tdNameA.setAttribute('href', navLinkDecl(decl.name));
2389 tdNameA.textContent = decl.name;
2481 tdNameA.setAttribute("href", navLinkDecl(decl.name));
2482 tdNameA.textContent = decl.name;
23902483
2391 tdType.innerHTML = exprName(walkResultTypeRef(decl.value),
2392 {wantHtml:true, wantLink:true});
2484 tdType.innerHTML = typeValueName(typeOfDecl(decl), true, true);
23932485
2394 let docs = zigAnalysis.astNodes[decl.src].docs;
2395 if (docs != null) {
2396 tdDesc.innerHTML = shortDescMarkdown(docs);
2397 } else {
2398 tdDesc.textContent = "";
2399 }
2400 }
2401 domSectTests.classList.remove("hidden");
2486 let docs = zigAnalysis.astNodes[decl.src].docs;
2487 if (docs != null) {
2488 tdDesc.innerHTML = shortDescMarkdown(docs);
2489 } else {
2490 tdDesc.textContent = "";
24022491 }
2492 }
2493 domSectGlobalVars.classList.remove("hidden");
24032494 }
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
2407 function operatorCompare(a, b) {
2408 if (a === b) {
2409 return 0;
2410 } else if (a < b) {
2411 return -1;
2519 let docs = zigAnalysis.astNodes[decl.src].docs;
2520 if (docs != null) {
2521 tdDesc.innerHTML = shortDescMarkdown(docs);
24122522 } else {
2413 return 1;
2523 tdDesc.textContent = "";
24142524 }
2525 }
2526 domSectValues.classList.remove("hidden");
24152527 }
24162528
2417 function detectRootIsStd() {
2418 let rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg];
2419 if (rootPkg.table["std"] == null) {
2420 // no std mapped into the root package
2421 return false;
2422 }
2423 let stdPkg = zigAnalysis.packages[rootPkg.table["std"]];
2424 if (stdPkg == null) return false;
2425 return rootPkg.file === stdPkg.file;
2426 }
2529 if (testsList.length !== 0) {
2530 resizeDomList(
2531 domListTests,
2532 testsList.length,
2533 '<tr><td><a href="#"></a></td><td></td><td></td></tr>'
2534 );
2535 for (let i = 0; i < testsList.length; i += 1) {
2536 let decl = testsList[i];
2537 let trDom = domListTests.children[i];
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() {
2429 let map = ({});
2430 for (let i = 0; i < zigAnalysis.typeKinds.length; i += 1) {
2431 map[zigAnalysis.typeKinds[i]] = i;
2432 }
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");
2552 let docs = zigAnalysis.astNodes[decl.src].docs;
2553 if (docs != null) {
2554 tdDesc.innerHTML = shortDescMarkdown(docs);
2555 } else {
2556 tdDesc.textContent = "";
24392557 }
2440 return map;
2558 }
2559 domSectTests.classList.remove("hidden");
24412560 }
2561 }
24422562
2443 function findTypeTypeId() {
2444 for (let i = 0; i < zigAnalysis.types.length; i += 1) {
2445 if (zigAnalysis.types[i].kind == typeKinds.Type) {
2446 return i;
2447 }
2448 }
2449 throw new Error("No type 'type' found");
2563 function operatorCompare(a, b) {
2564 if (a === b) {
2565 return 0;
2566 } else if (a < b) {
2567 return -1;
2568 } else {
2569 return 1;
24502570 }
2571 }
24512572
2452 function updateCurNav() {
2453
2454 curNav = {
2455 showPrivDecls: false,
2456 pkgNames: [],
2457 pkgObjs: [],
2458 declNames: [],
2459 declObjs: [],
2460 callName: null,
2461 };
2462 curNavSearch = "";
2463
2464 if (location.hash[0] === '#' && location.hash.length > 1) {
2465 let query = location.hash.substring(1);
2466 if (query[0] === '*') {
2467 curNav.showPrivDecls = true;
2468 query = query.substring(1);
2469 }
2470
2471 let qpos = query.indexOf("?");
2472 let nonSearchPart;
2473 if (qpos === -1) {
2474 nonSearchPart = query;
2475 } else {
2476 nonSearchPart = query.substring(0, qpos);
2477 curNavSearch = decodeURIComponent(query.substring(qpos + 1));
2478 }
2479
2480 let parts = nonSearchPart.split(";");
2481 curNav.pkgNames = decodeURIComponent(parts[0]).split(".");
2482 if (parts[1] != null) {
2483 curNav.declNames = decodeURIComponent(parts[1]).split(".");
2484 }
2485 }
2573 function detectRootIsStd() {
2574 let rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg];
2575 if (rootPkg.table["std"] == null) {
2576 // no std mapped into the root package
2577 return false;
2578 }
2579 let stdPkg = zigAnalysis.packages[rootPkg.table["std"]];
2580 if (stdPkg == null) return false;
2581 return rootPkg.file === stdPkg.file;
2582 }
2583
2584 function indexTypeKinds() {
2585 let map = {};
2586 for (let i = 0; i < zigAnalysis.typeKinds.length; i += 1) {
2587 map[zigAnalysis.typeKinds[i]] = i;
2588 }
2589 // This is just for debugging purposes, not needed to function
2590 let assertList = [
2591 "Type",
2592 "Void",
2593 "Bool",
2594 "NoReturn",
2595 "Int",
2596 "Float",
2597 "Pointer",
2598 "Array",
2599 "Struct",
2600 "ComptimeFloat",
2601 "ComptimeInt",
2602 "Undefined",
2603 "Null",
2604 "Optional",
2605 "ErrorUnion",
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");
24862620 }
2621 return map;
2622 }
24872623
2488 function onHashChange() {
2489 updateCurNav();
2490 if (domSearch.value !== curNavSearch) {
2491 domSearch.value = curNavSearch;
2492 }
2493 render();
2494 if (imFeelingLucky) {
2495 imFeelingLucky = false;
2496 activateSelectedResult();
2497 }
2624 function findTypeTypeId() {
2625 for (let i = 0; i < zigAnalysis.types.length; i += 1) {
2626 if (zigAnalysis.types[i].kind == typeKinds.Type) {
2627 return i;
2628 }
24982629 }
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
2501 function findSubDecl(parentType, childName) {
2502 {
2503 // Generic functions
2504 if ("value" in parentType) {
2505 const rv = resolveValue(parentType.value);
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 }
2644 if (location.hash[0] === "#" && location.hash.length > 1) {
2645 let query = location.hash.substring(1);
2646 if (query[0] === "*") {
2647 curNav.showPrivDecls = true;
2648 query = query.substring(1);
2649 }
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;
2520 for (let i = 0; i < parentType.pubDecls.length; i += 1) {
2521 let declIndex = parentType.pubDecls[i];
2522 let childDecl = zigAnalysis.decls[declIndex];
2523 if (childDecl.name === childName) {
2524 return childDecl;
2525 }
2526 }
2527 if (!parentType.privDecls) return null;
2528 for (let i = 0; i < parentType.privDecls.length; i += 1) {
2529 let declIndex = parentType.privDecls[i];
2530 let childDecl = zigAnalysis.decls[declIndex];
2531 if (childDecl.name === childName) {
2532 return childDecl;
2660 let parts = nonSearchPart.split(";");
2661 curNav.pkgNames = decodeURIComponent(parts[0]).split(".");
2662 if (parts[1] != null) {
2663 curNav.declNames = decodeURIComponent(parts[1]).split(".");
2664 }
2665 }
2666 }
2667
2668 function onHashChange() {
2669 updateCurNav();
2670 if (domSearch.value !== curNavSearch) {
2671 domSearch.value = curNavSearch;
2672 if (domSearch.value.length == 0)
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];
25332695 }
2696 }
25342697 }
2535 return null;
2698 }
25362699 }
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() {
2542 let list = new Array(zigAnalysis.packages.length);
2543 // Now we try to find all the packages from root.
2544 let rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg];
2545 // Breadth-first to keep the path shortest possible.
2546 let stack = [{
2547 path: ([]),
2548 pkg: rootPkg,
2549 }];
2550 while (stack.length !== 0) {
2551 let item = (stack.shift());
2552 for (let key in item.pkg.table) {
2553 let childPkgIndex = item.pkg.table[key];
2554 if (list[childPkgIndex] != null) continue;
2555 let childPkg = zigAnalysis.packages[childPkgIndex];
2556 if (childPkg == null) continue;
2760 let stack = [
2761 {
2762 declNames: [],
2763 type: zigAnalysis.types[pkg.main],
2764 },
2765 ];
2766 while (stack.length !== 0) {
2767 let item = stack.shift();
2768
2769 if (isContainerType(item.type)) {
2770 let t = item.type;
2771
2772 let len = t.pubDecls ? t.pubDecls.length : 0;
2773 for (let declI = 0; declI < len; declI += 1) {
2774 let mainDeclIndex = t.pubDecls[declI];
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])
2559 list[childPkgIndex] = newPath;
2790 if (isContainerType(value)) {
25602791 stack.push({
2561 path: newPath,
2562 pkg: childPkg,
2792 declNames: declNames,
2793 type: value,
25632794 });
2564 }
2565 }
2566 return list;
2567 }
2568
2569
2570
2571 function computeCanonDeclPaths() {
2572 let list = new Array(zigAnalysis.decls.length);
2573 canonTypeDecls = new Array(zigAnalysis.types.length);
2574
2575 for (let pkgI = 0; pkgI < zigAnalysis.packages.length; pkgI += 1) {
2576 if (pkgI === zigAnalysis.rootPkg && rootIsStd) continue;
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 }
2795 }
2796
2797 // Generic function
2798 if (value.kind == typeKinds.Fn && value.generic_ret != null) {
2799 let resolvedVal = resolveValue({ expr: value.generic_ret });
2800 if ("type" in resolvedVal.expr) {
2801 let generic_type = zigAnalysis.types[resolvedVal.expr.type];
2802 if (isContainerType(generic_type)) {
2803 stack.push({
2804 declNames: declNames,
2805 type: generic_type,
2806 });
2807 }
26332808 }
2809 }
26342810 }
2811 }
26352812 }
2636 return list;
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];
2813 }
26532814 }
2815 return list;
2816 }
26542817
2655
2656 function escapeHtml(text) {
2657 return text.replace(/[&"<>]/g, function (m) {
2658 return escapeHtmlReplacements[m];
2659 });
2818 function getCanonDeclPath(index) {
2819 if (canonDeclPaths == null) {
2820 canonDeclPaths = computeCanonDeclPaths();
26602821 }
2661
2662
2663 function shortDescMarkdown(docs) {
2664 const trimmed_docs = docs.trim();
2665 let index = trimmed_docs.indexOf('.');
2666 if (index < 0) {
2667 index = trimmed_docs.indexOf('\n');
2668 if (index < 0) {
2669 index = trimmed_docs.length;
2670 }
2822 //let cd = (canonDeclPaths);
2823 return canonDeclPaths[index];
2824 }
2825
2826 function getCanonTypeDecl(index) {
2827 getCanonDeclPath(0);
2828 //let ct = (canonTypeDecls);
2829 return canonTypeDecls[index];
2830 }
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;
26712847 } else {
2672 index += 1; // include the period
2848 index = trimmed_docs.length;
26732849 }
2674 const slice = trimmed_docs.slice(0, index);
2675 return markdown(slice);
26762850 }
26772851
2678
2679 function markdown(input) {
2680 const raw_lines = input.split('\n'); // zig allows no '\r', so we don't need to split on CR
2681
2682 const lines = [];
2683
2684 // PHASE 1:
2685 // Dissect lines and determine the type for each line.
2686 // Also computes indentation level and removes unnecessary whitespace
2687
2688 let is_reading_code = false;
2689 let code_indent = 0;
2690 for (let line_no = 0; line_no < raw_lines.length; line_no++) {
2691 const raw_line = raw_lines[line_no];
2692
2693 const line = {
2694 indent: 0,
2695 raw_text: raw_line,
2696 text: raw_line.trim(),
2697 type: "p", // p, h1 … h6, code, ul, ol, blockquote, skip, empty
2698 ordered_number: -1, // NOTE: hack to make the type checker happy
2699 };
2700
2701 if (!is_reading_code) {
2702 while ((line.indent < line.raw_text.length) && line.raw_text[line.indent] == ' ') {
2703 line.indent += 1;
2704 }
2705
2706 if (line.text.startsWith("######")) {
2707 line.type = "h6";
2708 line.text = line.text.substr(6);
2709 }
2710 else if (line.text.startsWith("#####")) {
2711 line.type = "h5";
2712 line.text = line.text.substr(5);
2713 }
2714 else if (line.text.startsWith("####")) {
2715 line.type = "h4";
2716 line.text = line.text.substr(4);
2717 }
2718 else if (line.text.startsWith("###")) {
2719 line.type = "h3";
2720 line.text = line.text.substr(3);
2721 }
2722 else if (line.text.startsWith("##")) {
2723 line.type = "h2";
2724 line.text = line.text.substr(2);
2725 }
2726 else if (line.text.startsWith("#")) {
2727 line.type = "h1";
2728 line.text = line.text.substr(1);
2729 }
2730 else if (line.text.startsWith("-")) {
2731 line.type = "ul";
2732 line.text = line.text.substr(1);
2733 }
2734 else if (line.text.match(/^\d+\..*$/)) { // if line starts with {number}{dot}
2735 const match = (line.text.match(/(\d+)\./));
2736 line.type = "ul";
2737 line.text = line.text.substr(match[0].length);
2738 line.ordered_number = Number(match[1].length);
2739 }
2740 else if (line.text == "```") {
2741 line.type = "skip";
2742 is_reading_code = true;
2743 code_indent = line.indent;
2744 }
2745 else if (line.text == "") {
2746 line.type = "empty";
2747 }
2748 }
2749 else {
2750 if (line.text == "```") {
2751 is_reading_code = false;
2752 line.type = "skip";
2753 } else {
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 }
2852 let slice = trimmed_docs.slice(0, index);
2853 if (cut) slice += "...";
2854 return markdown(slice);
2855 }
2856
2857 function markdown(input) {
2858 const raw_lines = input.split("\n"); // zig allows no '\r', so we don't need to split on CR
2859
2860 const lines = [];
2861
2862 // PHASE 1:
2863 // Dissect lines and determine the type for each line.
2864 // Also computes indentation level and removes unnecessary whitespace
2865
2866 let is_reading_code = false;
2867 let code_indent = 0;
2868 for (let line_no = 0; line_no < raw_lines.length; line_no++) {
2869 const raw_line = raw_lines[line_no];
2870
2871 const line = {
2872 indent: 0,
2873 raw_text: raw_line,
2874 text: raw_line.trim(),
2875 type: "p", // p, h1 … h6, code, ul, ol, blockquote, skip, empty
2876 ordered_number: -1, // NOTE: hack to make the type checker happy
2877 };
2878
2879 if (!is_reading_code) {
2880 while (
2881 line.indent < line.raw_text.length &&
2882 line.raw_text[line.indent] == " "
2883 ) {
2884 line.indent += 1;
2885 }
2886
2887 if (line.text.startsWith("######")) {
2888 line.type = "h6";
2889 line.text = line.text.substr(6);
2890 } else if (line.text.startsWith("#####")) {
2891 line.type = "h5";
2892 line.text = line.text.substr(5);
2893 } else if (line.text.startsWith("####")) {
2894 line.type = "h4";
2895 line.text = line.text.substr(4);
2896 } else if (line.text.startsWith("###")) {
2897 line.type = "h3";
2898 line.text = line.text.substr(3);
2899 } else if (line.text.startsWith("##")) {
2900 line.type = "h2";
2901 line.text = line.text.substr(2);
2902 } else if (line.text.startsWith("#")) {
2903 line.type = "h1";
2904 line.text = line.text.substr(1);
2905 } else if (line.text.startsWith("-")) {
2906 line.type = "ul";
2907 line.text = line.text.substr(1);
2908 } else if (line.text.match(/^\d+\..*$/)) {
2909 // if line starts with {number}{dot}
2910 const match = line.text.match(/(\d+)\./);
2911 line.type = "ul";
2912 line.text = line.text.substr(match[0].length);
2913 line.ordered_number = Number(match[1].length);
2914 } else if (line.text == "```") {
2915 line.type = "skip";
2916 is_reading_code = true;
2917 code_indent = line.indent;
2918 } else if (line.text == "") {
2919 line.type = "empty";
2920 }
2921 } else {
2922 if (line.text == "```") {
2923 is_reading_code = false;
2924 line.type = "skip";
2925 } else {
2926 line.type = "code";
2927 line.text = line.raw_text.substr(code_indent); // remove the indent of the ``` from all the code block
27622928 }
2929 }
27632930
2764 // PHASE 2:
2765 // Render HTML from markdown lines.
2766 // Look at each line and emit fitting HTML code
2767
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 ];
2931 if (line.type != "skip") {
2932 lines.push(line);
2933 }
2934 }
28022935
2803
2804 const stack = [];
2936 // PHASE 2:
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 = "";
2807 let currentRun = "";
2971 const stack = [];
28082972
2809 function flushRun() {
2810 if (currentRun != "") {
2811 innerHTML += escapeHtml(currentRun);
2812 }
2813 currentRun = "";
2814 }
2973 let innerHTML = "";
2974 let currentRun = "";
28152975
2816 let parsing_code = false;
2817 let codetag = "";
2818 let in_code = false;
2819
2820 for (let i = 0; i < innerText.length; i++) {
2821
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 }
2976 function flushRun() {
2977 if (currentRun != "") {
2978 innerHTML += escapeHtml(currentRun);
2979 }
2980 currentRun = "";
2981 }
28392982
2840 if (innerText[i] == "`") {
2841 flushRun();
2842 if (!parsing_code) {
2843 innerHTML += "<code>";
2844 }
2845 parsing_code = true;
2846 codetag += "`";
2847 continue;
2848 }
2983 let parsing_code = false;
2984 let codetag = "";
2985 let in_code = false;
28492986
2850 if (parsing_code) {
2851 currentRun += innerText[i];
2852 in_code = true;
2853 } else {
2854 let any = false;
2855 for (let idx = (stack.length > 0 ? -1 : 0); idx < formats.length; idx++) {
2856 const fmt = idx >= 0 ? formats[idx] : stack[stack.length - 1];
2857 if (innerText.substr(i, fmt.marker.length) == fmt.marker) {
2858 flushRun();
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 }
2987 for (let i = 0; i < innerText.length; i++) {
2988 if (parsing_code && in_code) {
2989 if (innerText.substr(i, codetag.length) == codetag) {
2990 // remove leading and trailing whitespace if string both starts and ends with one.
2991 if (
2992 currentRun[0] == " " &&
2993 currentRun[currentRun.length - 1] == " "
2994 ) {
2995 currentRun = currentRun.substr(1, currentRun.length - 2);
28752996 }
28762997 flushRun();
2877
2878 while (stack.length > 0) {
2879 const fmt = (stack.pop());
2880 innerHTML += "</" + fmt.tag + ">";
2881 }
2882
2883 return innerHTML;
2884 }
2885
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 }
2998 i += codetag.length - 1;
2999 in_code = false;
3000 parsing_code = false;
3001 innerHTML += "</code>";
3002 codetag = "";
3003 } else {
3004 currentRun += innerText[i];
3005 }
3006 continue;
28933007 }
28943008
2895
2896 function nextLineIs(type, line_no) {
2897 if (line_no < (lines.length - 1)) {
2898 return (lines[line_no + 1].type == type);
2899 } else {
2900 return false;
2901 }
3009 if (innerText[i] == "`") {
3010 flushRun();
3011 if (!parsing_code) {
3012 innerHTML += "<code>";
3013 }
3014 parsing_code = true;
3015 codetag += "`";
3016 continue;
29023017 }
29033018
2904
2905 function getPreviousLineIndent(line_no) {
2906 if (line_no > 0) {
2907 return lines[line_no - 1].indent;
2908 } else {
2909 return 0;
3019 if (parsing_code) {
3020 currentRun += innerText[i];
3021 in_code = true;
3022 } else {
3023 let any = false;
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;
29103042 }
3043 }
3044 if (!any) {
3045 currentRun += innerText[i];
3046 }
29113047 }
3048 }
3049 flushRun();
29123050
2913
2914 function getNextLineIndent(line_no) {
2915 if (line_no < (lines.length - 1)) {
2916 return lines[line_no + 1].indent;
2917 } else {
2918 return 0;
2919 }
2920 }
3051 while (stack.length > 0) {
3052 const fmt = stack.pop();
3053 innerHTML += "</" + fmt.tag + ">";
3054 }
29213055
2922 let html = "";
2923 for (let line_no = 0; line_no < lines.length; line_no++) {
2924 const line = lines[line_no];
3056 return innerHTML;
3057 }
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) {
2929 case "h1":
2930 case "h2":
2931 case "h3":
2932 case "h4":
2933 case "h5":
2934 case "h6":
2935 html += "<" + line.type + ">" + markdownInlines(line.text) + "</" + line.type + ">\n";
2936 break;
3075 function getPreviousLineIndent(line_no) {
3076 if (line_no > 0) {
3077 return lines[line_no - 1].indent;
3078 } else {
3079 return 0;
3080 }
3081 }
29373082
2938 case "ul":
2939 case "ol":
2940 if (!previousLineIs("ul", line_no) || getPreviousLineIndent(line_no) < line.indent) {
2941 html += "<" + line.type + ">\n";
2942 }
3083 function getNextLineIndent(line_no) {
3084 if (line_no < lines.length - 1) {
3085 return lines[line_no + 1].indent;
3086 } else {
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) {
2947 html += "</" + line.type + ">\n";
2948 }
2949 break;
3121 html += "<li>" + markdownInlines(line.text) + "</li>\n";
29503122
2951 case "p":
2952 if (!previousLineIs("p", line_no)) {
2953 html += "<p>\n";
2954 }
2955 html += markdownInlines(line.text) + "\n";
2956 if (!nextLineIs("p", line_no)) {
2957 html += "</p>\n";
2958 }
2959 break;
3123 if (
3124 !nextLineIs("ul", line_no) ||
3125 getNextLineIndent(line_no) < line.indent
3126 ) {
3127 html += "</" + line.type + ">\n";
3128 }
3129 break;
29603130
2961 case "code":
2962 if (!previousLineIs("code", line_no)) {
2963 html += "<pre><code>";
2964 }
2965 html += escapeHtml(line.text) + "\n";
2966 if (!nextLineIs("code", line_no)) {
2967 html += "</code></pre>\n";
2968 }
2969 break;
2970 }
2971 }
3131 case "p":
3132 if (!previousLineIs("p", line_no)) {
3133 html += "<p>\n";
3134 }
3135 html += markdownInlines(line.text) + "\n";
3136 if (!nextLineIs("p", line_no)) {
3137 html += "</p>\n";
3138 }
3139 break;
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 }
29743151 }
29753152
2976 function activateSelectedResult() {
2977 if (domSectSearchResults.classList.contains("hidden")) {
2978 return;
2979 }
3153 return html;
3154 }
29803155
2981 let liDom = domListSearchResults.children[curSearchIndex];
2982 if (liDom == null && domListSearchResults.children.length !== 0) {
2983 liDom = domListSearchResults.children[0];
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 }
3156 function activateSelectedResult() {
3157 if (domSectSearchResults.classList.contains("hidden")) {
3158 return;
30353159 }
30363160
3037
3038
3039 function moveSearchCursor(dir) {
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();
3161 let liDom = domListSearchResults.children[curSearchIndex];
3162 if (liDom == null && domListSearchResults.children.length !== 0) {
3163 liDom = domListSearchResults.children[0];
30563164 }
3057
3058
3059 function getKeyString(ev) {
3060 let name;
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;
3165 if (liDom != null) {
3166 let aDom = liDom.children[0];
3167 location.href = aDom.getAttribute("href");
3168 curSearchIndex = -1;
30833169 }
3084
3085
3086 function onWindowKeyDown(ev) {
3087 switch (getKeyString(ev)) {
3088 case "Esc":
3089 if (!domHelpModal.classList.contains("hidden")) {
3090 domHelpModal.classList.add("hidden");
3091 ev.preventDefault();
3092 ev.stopPropagation();
3093 }
3094 break;
3095 case "s":
3096 domSearch.focus();
3097 domSearch.select();
3098 ev.preventDefault();
3099 ev.stopPropagation();
3100 startAsyncSearch();
3101 break;
3102 case "?":
3103 ev.preventDefault();
3104 ev.stopPropagation();
3105 showHelpModal();
3106 break;
3107 }
3170 domSearch.blur();
3171 }
3172
3173 // hide the modal if it's visible or return to the previous result page and unfocus the search
3174 function onEscape(ev) {
3175 if (!domHelpModal.classList.contains("hidden")) {
3176 domHelpModal.classList.add("hidden");
3177 ev.preventDefault();
3178 ev.stopPropagation();
3179 } else {
3180 domSearch.value = "";
3181 domSearch.blur();
3182 domSearchPlaceholder.classList.remove("hidden");
3183 curSearchIndex = -1;
3184 ev.preventDefault();
3185 ev.stopPropagation();
3186 startSearch();
3187 }
3188 }
3189
3190 function onSearchKeyDown(ev) {
3191 switch (getKeyString(ev)) {
3192 case "Enter":
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;
31083241 }
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() {
31113306 domHelpModal.classList.remove("hidden");
3112 domHelpModal.style.left = (window.innerWidth / 2 - domHelpModal.clientWidth / 2) + "px";
3113 domHelpModal.style.top = (window.innerHeight / 2 - domHelpModal.clientHeight / 2) + "px";
3307 domHelpModal.style.left =
3308 window.innerWidth / 2 - domHelpModal.clientWidth / 2 + "px";
3309 domHelpModal.style.top =
3310 window.innerHeight / 2 - domHelpModal.clientHeight / 2 + "px";
31143311 domHelpModal.focus();
3115}
3312 domSearch.blur();
3313 }
31163314
3117function clearAsyncSearch() {
3315 function clearAsyncSearch() {
31183316 if (searchTimer != null) {
3119 clearTimeout(searchTimer);
3120 searchTimer = null;
3317 clearTimeout(searchTimer);
3318 searchTimer = null;
31213319 }
3122}
3320 }
31233321
3124function startAsyncSearch() {
3322 function startAsyncSearch() {
31253323 clearAsyncSearch();
31263324 searchTimer = setTimeout(startSearch, 100);
3127}
3128function startSearch() {
3325 }
3326 function startSearch() {
31293327 clearAsyncSearch();
31303328 let oldHash = location.hash;
31313329 let parts = oldHash.split("?");
3132 let newPart2 = (domSearch.value === "") ? "" : ("?" + domSearch.value);
3133 location.hash = (parts.length === 1) ? (oldHash + newPart2) : (parts[0] + newPart2);
3134}
3135function getSearchTerms() {
3330 let newPart2 = domSearch.value === "" ? "" : "?" + domSearch.value;
3331 location.replace(parts.length === 1 ? oldHash + newPart2 : parts[0] + newPart2);
3332 }
3333 function getSearchTerms() {
31363334 let list = curNavSearch.trim().split(/[ \r\n\t]+/);
31373335 list.sort();
31383336 return list;
3139}
3140function renderSearch() {
3337 }
3338
3339 function renderSearch() {
31413340 let matchedItems = [];
3142 let ignoreCase = (curNavSearch.toLowerCase() === curNavSearch);
3341 let ignoreCase = curNavSearch.toLowerCase() === curNavSearch;
31433342 let terms = getSearchTerms();
31443343
3145 decl_loop: for (let declIndex = 0; declIndex < zigAnalysis.decls.length; declIndex += 1) {
3146 let canonPath = getCanonDeclPath(declIndex);
3147 if (canonPath == null) continue;
3148
3149 let decl = zigAnalysis.decls[declIndex];
3150 let lastPkgName = canonPath.pkgNames[canonPath.pkgNames.length - 1];
3151 let fullPathSearchText = lastPkgName + "." + canonPath.declNames.join('.');
3152 let astNode = zigAnalysis.astNodes[decl.src];
3153 let fileAndDocs = "" //zigAnalysis.files[astNode.file];
3154 // TODO: understand what this piece of code is trying to achieve
3155 // also right now `files` are expressed as a hashmap.
3156 if (astNode.docs != null) {
3157 fileAndDocs += "\n" + astNode.docs;
3158 }
3159 let fullPathSearchTextLower = fullPathSearchText;
3160 if (ignoreCase) {
3161 fullPathSearchTextLower = fullPathSearchTextLower.toLowerCase();
3162 fileAndDocs = fileAndDocs.toLowerCase();
3163 }
3164
3165 let points = 0;
3166 for (let termIndex = 0; termIndex < terms.length; termIndex += 1) {
3167 let term = terms[termIndex];
3344 decl_loop: for (
3345 let declIndex = 0;
3346 declIndex < zigAnalysis.decls.length;
3347 declIndex += 1
3348 ) {
3349 let canonPath = getCanonDeclPath(declIndex);
3350 if (canonPath == null) continue;
3351
3352 let decl = zigAnalysis.decls[declIndex];
3353 let lastPkgName = canonPath.pkgNames[canonPath.pkgNames.length - 1];
3354 let fullPathSearchText =
3355 lastPkgName + "." + canonPath.declNames.join(".");
3356 let astNode = zigAnalysis.astNodes[decl.src];
3357 let fileAndDocs = ""; //zigAnalysis.files[astNode.file];
3358 // TODO: understand what this piece of code is trying to achieve
3359 // also right now `files` are expressed as a hashmap.
3360 if (astNode.docs != null) {
3361 fileAndDocs += "\n" + astNode.docs;
3362 }
3363 let fullPathSearchTextLower = fullPathSearchText;
3364 if (ignoreCase) {
3365 fullPathSearchTextLower = fullPathSearchTextLower.toLowerCase();
3366 fileAndDocs = fileAndDocs.toLowerCase();
3367 }
31683368
3169 // exact, case sensitive match of full decl path
3170 if (fullPathSearchText === term) {
3171 points += 4;
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 }
3369 let points = 0;
3370 for (let termIndex = 0; termIndex < terms.length; termIndex += 1) {
3371 let term = terms[termIndex];
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;
31903391 }
31913392
3192 matchedItems.push({
3193 decl: decl,
3194 path: canonPath,
3195 points: points,
3196 });
3393 continue decl_loop;
3394 }
3395
3396 matchedItems.push({
3397 decl: decl,
3398 path: canonPath,
3399 points: points,
3400 });
31973401 }
31983402
31993403 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) {
3203 let cmp = operatorCompare(b.points, a.points);
3204 if (cmp != 0) return cmp;
3205 return operatorCompare(a.decl.name, b.decl.name);
3206 });
3417 // Build up the list of search results
3418 let matchedItemsHTML = "";
32073419
3208 for (let i = 0; i < matchedItems.length; i += 1) {
3209 let liDom = domListSearchResults.children[i];
3210 let aDom = liDom.children[0];
3211 let match = matchedItems[i];
3212 let lastPkgName = match.path.pkgNames[match.path.pkgNames.length - 1];
3213 aDom.textContent = lastPkgName + "." + match.path.declNames.join('.');
3214 aDom.setAttribute('href', navLink(match.path.pkgNames, match.path.declNames));
3215 }
3216 renderSearchCursor();
3420 for (let i = 0; i < matchedItems.length; i += 1) {
3421 const match = matchedItems[i];
3422 const lastPkgName = match.path.pkgNames[match.path.pkgNames.length - 1];
3423
3424 const text = lastPkgName + "." + match.path.declNames.join(".");
3425 const href = navLink(match.path.pkgNames, match.path.declNames);
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");
32193438 } else {
3220 domSectSearchNoResults.classList.remove("hidden");
3439 domSectSearchNoResults.classList.remove("hidden");
32213440 }
3222}
3441 }
32233442
3224function renderSearchCursor() {
3443 function renderSearchCursor() {
32253444 for (let i = 0; i < domListSearchResults.children.length; i += 1) {
3226 let liDom = (domListSearchResults.children[i]);
3227 if (curSearchIndex === i) {
3228 liDom.classList.add("selected");
3229 } else {
3230 liDom.classList.remove("selected");
3231 }
3445 let liDom = domListSearchResults.children[i];
3446 if (curSearchIndex === i) {
3447 liDom.classList.add("selected");
3448 } else {
3449 liDom.classList.remove("selected");
3450 }
32323451 }
3233}
3234
3235
3236
3237// function indexNodesToCalls() {
3238// let map = {};
3239// for (let i = 0; i < zigAnalysis.calls.length; i += 1) {
3240// let call = zigAnalysis.calls[i];
3241// let fn = zigAnalysis.fns[call.fn];
3242// if (map[fn.src] == null) {
3243// map[fn.src] = [i];
3244// } else {
3245// map[fn.src].push(i);
3246// }
3247// }
3248// return map;
3249// }
3250
3251
3252
3253function byNameProperty(a, b) {
3452 }
3453
3454 // function indexNodesToCalls() {
3455 // let map = {};
3456 // for (let i = 0; i < zigAnalysis.calls.length; i += 1) {
3457 // let call = zigAnalysis.calls[i];
3458 // let fn = zigAnalysis.fns[call.fn];
3459 // if (map[fn.src] == null) {
3460 // map[fn.src] = [i];
3461 // } else {
3462 // map[fn.src].push(i);
3463 // }
3464 // }
3465 // return map;
3466 // }
3467
3468 function byNameProperty(a, b) {
32543469 return operatorCompare(a.name, b.name);
3255}
3256
3257
3258
3470 }
32593471})();
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 {
703703 const max_multiplier_bits = @bitSizeOf(usize);
704704 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);
707707 comptime assert(std.math.isPowerOfTwo(buckets.len));
708708
709709 const index = (address *% fibonacci_multiplier) >> (max_multiplier_bits - max_bucket_bits);
......@@ -721,7 +721,7 @@ const PosixImpl = struct {
721721 // then cut off the zero bits from the alignment to get the unique address.
722722 const addr = @ptrToInt(ptr);
723723 assert(addr & (alignment - 1) == 0);
724 return addr >> @ctz(usize, alignment);
724 return addr >> @ctz(alignment);
725725 }
726726 };
727727
lib/std/Thread/Mutex.zig+1-1
......@@ -140,7 +140,7 @@ const FutexImpl = struct {
140140 // - they both seem to mark the cache-line as modified regardless: https://stackoverflow.com/a/63350048
141141 // - `lock bts` is smaller instruction-wise which makes it better for inlining
142142 if (comptime builtin.target.cpu.arch.isX86()) {
143 const locked_bit = @ctz(u32, @as(u32, locked));
143 const locked_bit = @ctz(@as(u32, locked));
144144 return self.state.bitSet(locked_bit, .Acquire) == 0;
145145 }
146146
lib/std/Thread/RwLock.zig+2-2
......@@ -168,8 +168,8 @@ pub const DefaultRwLock = struct {
168168 const IS_WRITING: usize = 1;
169169 const WRITER: usize = 1 << 1;
170170 const READER: usize = 1 << (1 + @bitSizeOf(Count));
171 const WRITER_MASK: usize = std.math.maxInt(Count) << @ctz(usize, WRITER);
172 const READER_MASK: usize = std.math.maxInt(Count) << @ctz(usize, READER);
171 const WRITER_MASK: usize = std.math.maxInt(Count) << @ctz(WRITER);
172 const READER_MASK: usize = std.math.maxInt(Count) << @ctz(READER);
173173 const Count = std.meta.Int(.unsigned, @divFloor(@bitSizeOf(usize) - 1, 2));
174174
175175 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 {
221221 mem.copy(T, self.items[old_len..], items);
222222 }
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
224248 pub const Writer = if (T != u8)
225249 @compileError("The Writer interface is only defined for ArrayList(u8) " ++
226250 "but the given type is ArrayList(" ++ @typeName(T) ++ ")")
......@@ -592,6 +616,29 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
592616 mem.copy(T, self.items[old_len..], items);
593617 }
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
595642 pub const WriterContext = struct {
596643 self: *Self,
597644 allocator: Allocator,
......@@ -899,6 +946,14 @@ test "std.ArrayList/ArrayListUnmanaged.basic" {
899946 try testing.expect(list.pop() == 1);
900947 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
902957 list.appendSlice(&[_]i32{}) catch unreachable;
903958 try testing.expect(list.items.len == 9);
904959
......@@ -941,6 +996,14 @@ test "std.ArrayList/ArrayListUnmanaged.basic" {
941996 try testing.expect(list.pop() == 1);
942997 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
9441007 list.appendSlice(a, &[_]i32{}) catch unreachable;
9451008 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 {
9191
9292 /// Returns the total number of set bits in this bit set.
9393 pub fn count(self: Self) usize {
94 return @popCount(MaskInt, self.mask);
94 return @popCount(self.mask);
9595 }
9696
9797 /// Changes the value of the specified bit of the bit
......@@ -179,7 +179,7 @@ pub fn IntegerBitSet(comptime size: u16) type {
179179 pub fn findFirstSet(self: Self) ?usize {
180180 const mask = self.mask;
181181 if (mask == 0) return null;
182 return @ctz(MaskInt, mask);
182 return @ctz(mask);
183183 }
184184
185185 /// Finds the index of the first set bit, and unsets it.
......@@ -187,7 +187,7 @@ pub fn IntegerBitSet(comptime size: u16) type {
187187 pub fn toggleFirstSet(self: *Self) ?usize {
188188 const mask = self.mask;
189189 if (mask == 0) return null;
190 const index = @ctz(MaskInt, mask);
190 const index = @ctz(mask);
191191 self.mask = mask & (mask - 1);
192192 return index;
193193 }
......@@ -222,12 +222,12 @@ pub fn IntegerBitSet(comptime size: u16) type {
222222
223223 switch (direction) {
224224 .forward => {
225 const next_index = @ctz(MaskInt, self.bits_remain);
225 const next_index = @ctz(self.bits_remain);
226226 self.bits_remain &= self.bits_remain - 1;
227227 return next_index;
228228 },
229229 .reverse => {
230 const leading_zeroes = @clz(MaskInt, self.bits_remain);
230 const leading_zeroes = @clz(self.bits_remain);
231231 const top_bit = (@bitSizeOf(MaskInt) - 1) - leading_zeroes;
232232 self.bits_remain &= (@as(MaskInt, 1) << @intCast(ShiftInt, top_bit)) - 1;
233233 return top_bit;
......@@ -347,7 +347,7 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type {
347347 pub fn count(self: Self) usize {
348348 var total: usize = 0;
349349 for (self.masks) |mask| {
350 total += @popCount(MaskInt, mask);
350 total += @popCount(mask);
351351 }
352352 return total;
353353 }
......@@ -475,7 +475,7 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type {
475475 if (mask != 0) break mask;
476476 offset += @bitSizeOf(MaskInt);
477477 } else return null;
478 return offset + @ctz(MaskInt, mask);
478 return offset + @ctz(mask);
479479 }
480480
481481 /// 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 {
486486 if (mask.* != 0) break mask;
487487 offset += @bitSizeOf(MaskInt);
488488 } else return null;
489 const index = @ctz(MaskInt, mask.*);
489 const index = @ctz(mask.*);
490490 mask.* &= (mask.* - 1);
491491 return offset + index;
492492 }
......@@ -657,7 +657,7 @@ pub const DynamicBitSetUnmanaged = struct {
657657 var total: usize = 0;
658658 for (self.masks[0..num_masks]) |mask| {
659659 // Note: This is where we depend on padding bits being zero
660 total += @popCount(MaskInt, mask);
660 total += @popCount(mask);
661661 }
662662 return total;
663663 }
......@@ -795,7 +795,7 @@ pub const DynamicBitSetUnmanaged = struct {
795795 mask += 1;
796796 offset += @bitSizeOf(MaskInt);
797797 } else return null;
798 return offset + @ctz(MaskInt, mask[0]);
798 return offset + @ctz(mask[0]);
799799 }
800800
801801 /// Finds the index of the first set bit, and unsets it.
......@@ -808,7 +808,7 @@ pub const DynamicBitSetUnmanaged = struct {
808808 mask += 1;
809809 offset += @bitSizeOf(MaskInt);
810810 } else return null;
811 const index = @ctz(MaskInt, mask[0]);
811 const index = @ctz(mask[0]);
812812 mask[0] &= (mask[0] - 1);
813813 return offset + index;
814814 }
......@@ -1067,12 +1067,12 @@ fn BitSetIterator(comptime MaskInt: type, comptime options: IteratorOptions) typ
10671067
10681068 switch (direction) {
10691069 .forward => {
1070 const next_index = @ctz(MaskInt, self.bits_remain) + self.bit_offset;
1070 const next_index = @ctz(self.bits_remain) + self.bit_offset;
10711071 self.bits_remain &= self.bits_remain - 1;
10721072 return next_index;
10731073 },
10741074 .reverse => {
1075 const leading_zeroes = @clz(MaskInt, self.bits_remain);
1075 const leading_zeroes = @clz(self.bits_remain);
10761076 const top_bit = (@bitSizeOf(MaskInt) - 1) - leading_zeroes;
10771077 const no_top_bit_mask = (@as(MaskInt, 1) << @intCast(ShiftInt, top_bit)) - 1;
10781078 self.bits_remain &= no_top_bit_mask;
lib/std/bounded_array.zig+8-8
......@@ -15,16 +15,16 @@ const testing = std.testing;
1515/// var slice = a.slice(); // a slice of the 64-byte array
1616/// var a_clone = a; // creates a copy - the structure doesn't use any internal pointers
1717/// ```
18pub fn BoundedArray(comptime T: type, comptime capacity: usize) type {
18pub fn BoundedArray(comptime T: type, comptime buffer_capacity: usize) type {
1919 return struct {
2020 const Self = @This();
21 buffer: [capacity]T = undefined,
21 buffer: [buffer_capacity]T = undefined,
2222 len: usize = 0,
2323
2424 /// Set the actual length of the slice.
2525 /// Returns error.Overflow if it exceeds the length of the backing array.
2626 pub fn init(len: usize) error{Overflow}!Self {
27 if (len > capacity) return error.Overflow;
27 if (len > buffer_capacity) return error.Overflow;
2828 return Self{ .len = len };
2929 }
3030
......@@ -41,7 +41,7 @@ pub fn BoundedArray(comptime T: type, comptime capacity: usize) type {
4141 /// Adjust the slice's length to `len`.
4242 /// Does not initialize added items if any.
4343 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;
4545 self.len = len;
4646 }
4747
......@@ -69,7 +69,7 @@ pub fn BoundedArray(comptime T: type, comptime capacity: usize) type {
6969
7070 /// Check that the slice can hold at least `additional_count` items.
7171 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) {
7373 return error.Overflow;
7474 }
7575 }
......@@ -83,7 +83,7 @@ pub fn BoundedArray(comptime T: type, comptime capacity: usize) type {
8383 /// Increase length by 1, returning pointer to the new item.
8484 /// Asserts that there is space for the new item.
8585 pub fn addOneAssumeCapacity(self: *Self) *T {
86 assert(self.len < capacity);
86 assert(self.len < buffer_capacity);
8787 self.len += 1;
8888 return &self.slice()[self.len - 1];
8989 }
......@@ -236,7 +236,7 @@ pub fn BoundedArray(comptime T: type, comptime capacity: usize) type {
236236 pub fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void {
237237 const old_len = self.len;
238238 self.len += n;
239 assert(self.len <= capacity);
239 assert(self.len <= buffer_capacity);
240240 mem.set(T, self.slice()[old_len..self.len], value);
241241 }
242242
......@@ -275,7 +275,7 @@ test "BoundedArray" {
275275 try testing.expectEqualSlices(u8, &x, a.constSlice());
276276
277277 var a2 = a;
278 try testing.expectEqualSlices(u8, a.constSlice(), a.constSlice());
278 try testing.expectEqualSlices(u8, a.constSlice(), a2.constSlice());
279279 a2.set(0, 0);
280280 try testing.expect(a.get(0) != a2.get(0));
281281
lib/std/build.zig+11-4
......@@ -1495,6 +1495,7 @@ pub const LibExeObjStep = struct {
14951495 emit_h: bool = false,
14961496 bundle_compiler_rt: ?bool = null,
14971497 single_threaded: ?bool = null,
1498 stack_protector: ?bool = null,
14981499 disable_stack_probing: bool,
14991500 disable_sanitize_c: bool,
15001501 sanitize_thread: bool,
......@@ -1896,13 +1897,12 @@ pub const LibExeObjStep = struct {
18961897 /// When a binary cannot be ran through emulation or the option is disabled, a warning
18971898 /// will be printed and the binary will *NOT* be ran.
18981899 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);
19021903 if (exe.vcpkg_bin_path) |path| {
1903 run_step.addPathDir(path);
1904 RunStep.addPathDirInternal(&run_step.step, exe.builder, path);
19041905 }
1905
19061906 return run_step;
19071907 }
19081908
......@@ -2826,6 +2826,13 @@ pub const LibExeObjStep = struct {
28262826 if (self.disable_stack_probing) {
28272827 try zig_args.append("-fno-stack-check");
28282828 }
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 }
28292836 if (self.red_zone) |red_zone| {
28302837 if (red_zone) {
28312838 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 {
171171 .Void,
172172 .Bool,
173173 .Int,
174 .ComptimeInt,
174175 .Float,
175176 .Null,
176177 => try out.print("{any}", .{val}),
......@@ -302,6 +303,7 @@ test "OptionsStep" {
302303 options.addOption(usize, "option1", 1);
303304 options.addOption(?usize, "option2", null);
304305 options.addOption(?usize, "option3", 3);
306 options.addOption(comptime_int, "option4", 4);
305307 options.addOption([]const u8, "string", "zigisthebest");
306308 options.addOption(?[]const u8, "optional_string", null);
307309 options.addOption([2][2]u16, "nested_array", nested_array);
......@@ -314,6 +316,7 @@ test "OptionsStep" {
314316 \\pub const option1: usize = 1;
315317 \\pub const option2: ?usize = null;
316318 \\pub const option3: ?usize = 3;
319 \\pub const option4: comptime_int = 4;
317320 \\pub const string: []const u8 = "zigisthebest";
318321 \\pub const optional_string: ?[]const u8 = null;
319322 \\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 {
101101}
102102
103103/// 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 {
105105 const env_map = getEnvMapInternal(step, builder.allocator);
106106
107107 const key = "PATH";
lib/std/build/TranslateCStep.zig+14
......@@ -21,6 +21,7 @@ output_dir: ?[]const u8,
2121out_basename: []const u8,
2222target: CrossTarget = CrossTarget{},
2323output_file: build.GeneratedFile,
24use_stage1: ?bool = null,
2425
2526pub fn create(builder: *Builder, source: build.FileSource) *TranslateCStep {
2627 const self = builder.allocator.create(TranslateCStep) catch unreachable;
......@@ -91,6 +92,19 @@ fn make(step: *Step) !void {
9192 try argv_list.append("-D");
9293 try argv_list.append(c_macro);
9394 }
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
95109 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) {
294294 /// therefore must be kept in sync with the compiler implementation.
295295 pub const Struct = struct {
296296 layout: ContainerLayout,
297 /// Only valid if layout is .Packed
298 backing_integer: ?type = null,
297299 fields: []const StructField,
298300 decls: []const Declaration,
299301 is_tuple: bool,
......@@ -864,13 +866,12 @@ pub fn panicUnwrapError(st: ?*StackTrace, err: anyerror) noreturn {
864866
865867pub fn panicOutOfBounds(index: usize, len: usize) noreturn {
866868 @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 });
868870}
869871
870pub noinline fn returnError(maybe_st: ?*StackTrace) void {
872pub noinline fn returnError(st: *StackTrace) void {
871873 @setCold(true);
872874 @setRuntimeSafety(false);
873 const st = maybe_st orelse return;
874875 addErrRetTraceAddr(st, @returnAddress());
875876}
876877
lib/std/c.zig+6-2
......@@ -20,7 +20,7 @@ pub const Tokenizer = tokenizer.Tokenizer;
2020/// If linking gnu libc (glibc), the `ok` value will be true if the target
2121/// version is greater than or equal to `glibc_version`.
2222/// 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 {
2424 return struct {
2525 pub const ok = blk: {
2626 if (!builtin.link_libc) break :blk false;
......@@ -263,7 +263,11 @@ const PThreadForkFn = if (builtin.zig_backend == .stage1)
263263 fn () callconv(.C) void
264264else
265265 *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;
267271pub extern "c" fn pthread_key_delete(key: c.pthread_key_t) c.E;
268272pub extern "c" fn pthread_getspecific(key: c.pthread_key_t) ?*anyopaque;
269273pub 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;
814814pub const empty_sigset: sigset_t = 0;
815815
816816pub const SIG = struct {
817 pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));
818 pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0);
819 pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1);
820 pub const HOLD = @intToPtr(?Sigaction.sigaction_fn, 5);
817 pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
818 pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
819 pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
820 pub const HOLD = @intToPtr(?Sigaction.handler_fn, 5);
821821
822822 /// block specified signal set
823823 pub const _BLOCK = 1;
lib/std/c/dragonfly.zig+3-3
......@@ -609,9 +609,9 @@ pub const S = struct {
609609pub const BADSIG = SIG.ERR;
610610
611611pub const SIG = struct {
612 pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0);
613 pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1);
614 pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));
612 pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
613 pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
614 pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
615615
616616 pub const BLOCK = 1;
617617 pub const UNBLOCK = 2;
lib/std/c/freebsd.zig+3-3
......@@ -670,9 +670,9 @@ pub const SIG = struct {
670670 pub const UNBLOCK = 2;
671671 pub const SETMASK = 3;
672672
673 pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0);
674 pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1);
675 pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));
673 pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
674 pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
675 pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
676676
677677 pub const WORDS = 4;
678678 pub const MAXSIG = 128;
lib/std/c/haiku.zig+2-2
......@@ -702,7 +702,7 @@ pub const T = struct {
702702 pub const CSETAF = 0x8002;
703703 pub const CSETAW = 0x8003;
704704 pub const CWAITEVENT = 0x8004;
705 pub const CSBRK = 08005;
705 pub const CSBRK = 0x8005;
706706 pub const CFLSH = 0x8006;
707707 pub const CXONC = 0x8007;
708708 pub const CQUERYCONNECTED = 0x8008;
......@@ -874,7 +874,7 @@ pub const S = struct {
874874 pub const IFDIR = 0o040000;
875875 pub const IFCHR = 0o020000;
876876 pub const IFIFO = 0o010000;
877 pub const INDEX_DIR = 04000000000;
877 pub const INDEX_DIR = 0o4000000000;
878878
879879 pub const IUMSK = 0o7777;
880880 pub const ISUID = 0o4000;
lib/std/c/netbsd.zig+3-3
......@@ -910,9 +910,9 @@ pub const winsize = extern struct {
910910const NSIG = 32;
911911
912912pub const SIG = struct {
913 pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0);
914 pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1);
915 pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));
913 pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
914 pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
915 pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
916916
917917 pub const WORDS = 4;
918918 pub const MAXSIG = 128;
lib/std/c/openbsd.zig+6-21
......@@ -982,11 +982,11 @@ pub const winsize = extern struct {
982982const NSIG = 33;
983983
984984pub const SIG = struct {
985 pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0);
986 pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1);
987 pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));
988 pub const CATCH = @intToPtr(?Sigaction.sigaction_fn, 2);
989 pub const HOLD = @intToPtr(?Sigaction.sigaction_fn, 3);
985 pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
986 pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
987 pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
988 pub const CATCH = @intToPtr(?Sigaction.handler_fn, 2);
989 pub const HOLD = @intToPtr(?Sigaction.handler_fn, 3);
990990
991991 pub const HUP = 1;
992992 pub const INT = 2;
......@@ -1119,26 +1119,11 @@ pub usingnamespace switch (builtin.cpu.arch) {
11191119 sc_rsp: c_long,
11201120 sc_ss: c_long,
11211121
1122 sc_fpstate: fxsave64,
1122 sc_fpstate: *anyopaque, // struct fxsave64 *
11231123 __sc_unused: c_int,
11241124 sc_mask: c_int,
11251125 sc_cookie: c_long,
11261126 };
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 };
11421127 },
11431128 else => struct {},
11441129};
lib/std/c/solaris.zig+4-4
......@@ -879,10 +879,10 @@ pub const winsize = extern struct {
879879const NSIG = 75;
880880
881881pub const SIG = struct {
882 pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0);
883 pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));
884 pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1);
885 pub const HOLD = @intToPtr(?Sigaction.sigaction_fn, 2);
882 pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
883 pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
884 pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
885 pub const HOLD = @intToPtr(?Sigaction.handler_fn, 2);
886886
887887 pub const WORDS = 4;
888888 pub const MAXSIG = 75;
lib/std/coff.zig+973-248
......@@ -1,14 +1,731 @@
11const std = @import("std.zig");
2const assert = std.debug.assert;
23const io = std.io;
34const mem = std.mem;
45const os = std.os;
5const File = std.fs.File;
6const fs = std.fs;
67
7// CoffHeader.machine values
8// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms680313(v=vs.85).aspx
9const IMAGE_FILE_MACHINE_I386 = 0x014c;
10const IMAGE_FILE_MACHINE_IA64 = 0x0200;
11const IMAGE_FILE_MACHINE_AMD64 = 0x8664;
8pub const CoffHeaderFlags = packed struct {
9 /// Image only, Windows CE, and Microsoft Windows NT and later.
10 /// This indicates that the file does not contain base relocations
11 /// and must therefore be loaded at its preferred base address.
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
13730pub const MachineType = enum(u16) {
14731 Unknown = 0x0,
......@@ -77,25 +794,6 @@ pub const MachineType = enum(u16) {
77794 }
78795};
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
99797const IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;
100798const IMAGE_DEBUG_TYPE_CODEVIEW = 2;
101799const DEBUG_DIRECTORY = 6;
......@@ -104,166 +802,87 @@ pub const CoffError = error{
104802 InvalidPEMagic,
105803 InvalidPEHeader,
106804 InvalidMachine,
805 MissingPEHeader,
107806 MissingCoffSection,
108807 MissingStringTable,
109808};
110809
111810// Official documentation of the format: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
112811pub const Coff = struct {
113 in_file: File,
114812 allocator: mem.Allocator,
813 data: []const u8 = undefined,
814 is_image: bool = false,
815 coff_header_offset: usize = 0,
115816
116 coff_header: CoffHeader,
117 pe_header: OptionalHeader,
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 }
817 guid: [16]u8 = undefined,
818 age: u32 = undefined,
133819
134820 pub fn deinit(self: *Coff) void {
135 self.sections.deinit(self.allocator);
821 self.allocator.free(self.data);
136822 }
137823
138 pub fn loadHeader(self: *Coff) !void {
139 const pe_pointer_offset = 0x3C;
140
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 };
824 /// Takes ownership of `data`.
825 pub fn parse(self: *Coff, data: []const u8) !void {
826 self.data = data;
167827
168 switch (self.coff_header.machine) {
169 IMAGE_FILE_MACHINE_I386, IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_IA64 => {},
170 else => return error.InvalidMachine,
171 }
828 const pe_pointer_offset = 0x3C;
829 const pe_magic = "PE\x00\x00";
172830
173 try self.loadOptionalHeader();
174 }
831 var stream = std.io.fixedBufferStream(self.data);
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 {
177 if (self.coff_header.pointer_to_symbol_table == 0) {
178 // No symbol table therefore no string table
179 return error.MissingStringTable;
180 }
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;
840 // Do some basic validation upfront
841 if (self.is_image) {
842 self.coff_header_offset = coff_header_offset + 4;
843 const coff_header = self.getCoffHeader();
844 if (coff_header.size_of_optional_header == 0) return error.MissingPEHeader;
189845 }
190846
191 const str = try in.readUntilDelimiterOrEof(buf, 0);
192 return str orelse "";
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 }
847 // JK: we used to check for architecture here and throw an error if not x86 or derivative.
848 // However I am willing to take a leap of faith and let aarch64 have a shot also.
232849 }
233850
234851 pub fn getPdbPath(self: *Coff, buffer: []u8) !usize {
235 try self.loadSections();
852 assert(self.is_image);
236853
237854 const header = blk: {
238 if (self.getSection(".buildid")) |section| {
239 break :blk section.header;
240 } else if (self.getSection(".rdata")) |section| {
241 break :blk section.header;
855 if (self.getSectionByName(".buildid")) |hdr| {
856 break :blk hdr;
857 } else if (self.getSectionByName(".rdata")) |hdr| {
858 break :blk hdr;
242859 } else {
243860 return error.MissingCoffSection;
244861 }
245862 };
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];
248866 const file_offset = debug_dir.virtual_address - header.virtual_address + header.pointer_to_raw_data;
249867
250 const in = self.in_file.reader();
251 try self.in_file.seekTo(file_offset);
868 var stream = std.io.fixedBufferStream(self.data);
869 const reader = stream.reader();
870 try stream.seekTo(file_offset);
252871
253872 // Find the correct DebugDirectoryEntry, and where its data is stored.
254873 // It can be in any section.
255874 const debug_dir_entry_count = debug_dir.size / @sizeOf(DebugDirectoryEntry);
256875 var i: u32 = 0;
257876 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);
259878 if (debug_dir_entry.type == IMAGE_DEBUG_TYPE_CODEVIEW) {
260 for (self.sections.items) |*section| {
261 const section_start = section.header.virtual_address;
262 const section_size = section.header.misc.virtual_size;
879 for (self.getSectionHeaders()) |*section| {
880 const section_start = section.virtual_address;
881 const section_size = section.virtual_size;
263882 const rva = debug_dir_entry.address_of_raw_data;
264883 const offset = rva - section_start;
265884 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);
267886 break :blk;
268887 }
269888 }
......@@ -271,19 +890,19 @@ pub const Coff = struct {
271890 }
272891
273892 var cv_signature: [4]u8 = undefined; // CodeView signature
274 try in.readNoEof(cv_signature[0..]);
893 try reader.readNoEof(cv_signature[0..]);
275894 // 'RSDS' indicates PDB70 format, used by lld.
276895 if (!mem.eql(u8, &cv_signature, "RSDS"))
277896 return error.InvalidPEMagic;
278 try in.readNoEof(self.guid[0..]);
279 self.age = try in.readIntLittle(u32);
897 try reader.readNoEof(self.guid[0..]);
898 self.age = try reader.readIntLittle(u32);
280899
281900 // Finally read the null-terminated string.
282 var byte = try in.readByte();
901 var byte = try reader.readByte();
283902 i = 0;
284903 while (byte != 0 and i < buffer.len) : (i += 1) {
285904 buffer[i] = byte;
286 byte = try in.readByte();
905 byte = try reader.readByte();
287906 }
288907
289908 if (byte != 0 and i == buffer.len)
......@@ -292,126 +911,232 @@ pub const Coff = struct {
292911 return @as(usize, i);
293912 }
294913
295 pub fn loadSections(self: *Coff) !void {
296 if (self.sections.items.len == self.coff_header.number_of_sections)
297 return;
914 pub fn getCoffHeader(self: Coff) CoffHeader {
915 return @ptrCast(*align(1) const CoffHeader, self.data[self.coff_header_offset..][0..@sizeOf(CoffHeader)]).*;
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;
306 while (i < self.coff_header.number_of_sections) : (i += 1) {
307 try in.readNoEof(name[0..8]);
936 pub fn getImageBase(self: Coff) u64 {
937 const hdr = self.getOptionalHeader();
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] == '/') {
310 // This is a long name and stored in the string table
311 const offset_len = mem.indexOfScalar(u8, name[1..], 0) orelse 7;
945 pub fn getNumberOfDataDirectories(self: Coff) u32 {
946 const hdr = self.getOptionalHeader();
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);
314 const str = try self.readStringFromTable(str_offset, &name);
315 std.mem.set(u8, name[str.len..], 0);
316 } else {
317 std.mem.set(u8, name[8..], 0);
318 }
954 pub fn getDataDirectories(self: *const Coff) []align(1) const ImageDataDirectory {
955 const hdr = self.getOptionalHeader();
956 const size: usize = switch (hdr.magic) {
957 IMAGE_NT_OPTIONAL_HDR32_MAGIC => @sizeOf(OptionalHeaderPE32),
958 IMAGE_NT_OPTIONAL_HDR64_MAGIC => @sizeOf(OptionalHeaderPE64),
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{
321 .header = SectionHeader{
322 .name = name,
323 .misc = SectionHeader.Misc{ .virtual_size = try in.readIntLittle(u32) },
324 .virtual_address = try in.readIntLittle(u32),
325 .size_of_raw_data = try in.readIntLittle(u32),
326 .pointer_to_raw_data = try in.readIntLittle(u32),
327 .pointer_to_relocations = try in.readIntLittle(u32),
328 .pointer_to_line_numbers = try in.readIntLittle(u32),
329 .number_of_relocations = try in.readIntLittle(u16),
330 .number_of_line_numbers = try in.readIntLittle(u16),
331 .characteristics = try in.readIntLittle(u32),
332 },
333 });
334 }
965 pub fn getSymtab(self: *const Coff) ?Symtab {
966 const coff_header = self.getCoffHeader();
967 if (coff_header.pointer_to_symbol_table == 0) return null;
968
969 const offset = coff_header.pointer_to_symbol_table;
970 const size = coff_header.number_of_symbols * Symbol.sizeOf();
971 return .{ .buffer = self.data[offset..][0..size] };
972 }
973
974 pub fn getStrtab(self: *const Coff) ?Strtab {
975 const coff_header = self.getCoffHeader();
976 if (coff_header.pointer_to_symbol_table == 0) return null;
977
978 const offset = coff_header.pointer_to_symbol_table + Symbol.sizeOf() * coff_header.number_of_symbols;
979 const size = mem.readIntLittle(u32, self.data[offset..][0..4]);
980 return Strtab{ .buffer = self.data[offset..][0..size] };
335981 }
336982
337 pub fn getSection(self: *Coff, comptime name: []const u8) ?*Section {
338 for (self.sections.items) |*sec| {
339 if (mem.eql(u8, sec.header.name[0..name.len], name)) {
340 return sec;
983 pub fn getSectionHeaders(self: *const Coff) []align(1) const SectionHeader {
984 const coff_header = self.getCoffHeader();
985 const offset = self.coff_header_offset + @sizeOf(CoffHeader) + coff_header.size_of_optional_header;
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;
3411002 }
3421003 }
3431004 return null;
3441005 }
3451006
3461007 // Return an owned slice full of the section data
347 pub fn getSectionData(self: *Coff, comptime name: []const u8, allocator: mem.Allocator) ![]u8 {
348 const sec = for (self.sections.items) |*sec| {
349 if (mem.eql(u8, sec.header.name[0..name.len], name)) {
350 break sec;
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);
1008 pub fn getSectionDataAlloc(self: *const Coff, comptime name: []const u8, allocator: mem.Allocator) ![]u8 {
1009 const sec = self.getSectionByName(name) orelse return error.MissingCoffSection;
1010 const out_buff = try allocator.alloc(u8, sec.virtual_size);
1011 mem.copy(u8, out_buff, self.data[sec.pointer_to_raw_data..][0..sec.virtual_size]);
3591012 return out_buff;
3601013 }
361};
3621014
363const CoffHeader = struct {
364 machine: u16,
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};
1015 pub const Symtab = struct {
1016 buffer: []const u8,
3721017
373const OptionalHeader = struct {
374 const DataDirectory = struct {
375 virtual_address: u32,
376 size: u32,
377 };
1018 fn len(self: Symtab) usize {
1019 return @divExact(self.buffer.len, Symbol.sizeOf());
1020 }
3781021
379 magic: u16,
380 data_directory: [IMAGE_NUMBEROF_DIRECTORY_ENTRIES]DataDirectory,
381 entry_addr: u32,
382 code_base: u32,
383 image_base: u64,
384};
1022 const Tag = enum {
1023 symbol,
1024 func_def,
1025 debug_info,
1026 weak_ext,
1027 file_def,
1028 sect_def,
1029 };
3851030
386const DebugDirectoryEntry = packed struct {
387 characteristiccs: u32,
388 time_date_stamp: u32,
389 major_version: u16,
390 minor_version: u16,
391 @"type": u32,
392 size_of_data: u32,
393 address_of_raw_data: u32,
394 pointer_to_raw_data: u32,
395};
1031 const Record = union(Tag) {
1032 symbol: Symbol,
1033 debug_info: DebugInfoDefinition,
1034 func_def: FunctionDefinition,
1035 weak_ext: WeakExternalDefinition,
1036 file_def: FileDefinition,
1037 sect_def: SectionDefinition,
1038 };
3961039
397pub const Section = struct {
398 header: SectionHeader,
399};
1040 /// Lives as long as Symtab instance.
1041 fn at(self: Symtab, index: usize, tag: Tag) Record {
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 {
402 const Misc = union {
403 physical_address: u32,
404 virtual_size: u32,
1126 fn slice(self: Symtab, start: usize, end: ?usize) Slice {
1127 const offset = start * Symbol.sizeOf();
1128 const llen = if (end) |e| e * Symbol.sizeOf() else self.buffer.len;
1129 const num = @divExact(llen - offset, Symbol.sizeOf());
1130 return Slice{ .buffer = self.buffer[offset..][0..llen], .num = num };
1131 }
4051132 };
4061133
407 name: [32]u8,
408 misc: Misc,
409 virtual_address: u32,
410 size_of_raw_data: u32,
411 pointer_to_raw_data: u32,
412 pointer_to_relocations: u32,
413 pointer_to_line_numbers: u32,
414 number_of_relocations: u16,
415 number_of_line_numbers: u16,
416 characteristics: u32,
1134 pub const Strtab = struct {
1135 buffer: []const u8,
1136
1137 fn get(self: Strtab, off: u32) []const u8 {
1138 assert(off < self.buffer.len);
1139 return mem.sliceTo(@ptrCast([*:0]const u8, self.buffer.ptr + off), 0);
1140 }
1141 };
4171142};
lib/std/compress/deflate/bits_utils.zig+1-1
......@@ -2,7 +2,7 @@ const math = @import("std").math;
22
33// Reverse bit-by-bit a N-bit code.
44pub fn bitReverse(comptime T: type, value: T, N: usize) T {
5 const r = @bitReverse(T, value);
5 const r = @bitReverse(value);
66 return r >> @intCast(math.Log2Int(T), @typeInfo(T).Int.bits - N);
77}
88
lib/std/crypto/25519/ed25519.zig+3-1
......@@ -355,7 +355,9 @@ test "ed25519 batch verification" {
355355 try Ed25519.verifyBatch(2, signature_batch);
356356
357357 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));
359361 }
360362}
361363
lib/std/crypto/aes_ocb.zig+5-5
......@@ -66,7 +66,7 @@ fn AesOcb(comptime Aes: anytype) type {
6666 var offset = [_]u8{0} ** 16;
6767 var i: usize = 0;
6868 while (i < full_blocks) : (i += 1) {
69 xorWith(&offset, lt[@ctz(usize, i + 1)]);
69 xorWith(&offset, lt[@ctz(i + 1)]);
7070 var e = xorBlocks(offset, a[i * 16 ..][0..16].*);
7171 aes_enc_ctx.encrypt(&e, &e);
7272 xorWith(&sum, e);
......@@ -129,7 +129,7 @@ fn AesOcb(comptime Aes: anytype) type {
129129 var es: [16 * wb]u8 align(16) = undefined;
130130 var j: usize = 0;
131131 while (j < wb) : (j += 1) {
132 xorWith(&offset, lt[@ctz(usize, i + 1 + j)]);
132 xorWith(&offset, lt[@ctz(i + 1 + j)]);
133133 offsets[j] = offset;
134134 const p = m[(i + j) * 16 ..][0..16].*;
135135 mem.copy(u8, es[j * 16 ..][0..16], &xorBlocks(p, offsets[j]));
......@@ -143,7 +143,7 @@ fn AesOcb(comptime Aes: anytype) type {
143143 }
144144 }
145145 while (i < full_blocks) : (i += 1) {
146 xorWith(&offset, lt[@ctz(usize, i + 1)]);
146 xorWith(&offset, lt[@ctz(i + 1)]);
147147 const p = m[i * 16 ..][0..16].*;
148148 var e = xorBlocks(p, offset);
149149 aes_enc_ctx.encrypt(&e, &e);
......@@ -193,7 +193,7 @@ fn AesOcb(comptime Aes: anytype) type {
193193 var es: [16 * wb]u8 align(16) = undefined;
194194 var j: usize = 0;
195195 while (j < wb) : (j += 1) {
196 xorWith(&offset, lt[@ctz(usize, i + 1 + j)]);
196 xorWith(&offset, lt[@ctz(i + 1 + j)]);
197197 offsets[j] = offset;
198198 const q = c[(i + j) * 16 ..][0..16].*;
199199 mem.copy(u8, es[j * 16 ..][0..16], &xorBlocks(q, offsets[j]));
......@@ -207,7 +207,7 @@ fn AesOcb(comptime Aes: anytype) type {
207207 }
208208 }
209209 while (i < full_blocks) : (i += 1) {
210 xorWith(&offset, lt[@ctz(usize, i + 1)]);
210 xorWith(&offset, lt[@ctz(i + 1)]);
211211 const q = c[i * 16 ..][0..16].*;
212212 var e = xorBlocks(q, offset);
213213 aes_dec_ctx.decrypt(&e, &e);
lib/std/crypto/ghash.zig+16-16
......@@ -41,8 +41,8 @@ pub const Ghash = struct {
4141 pub fn init(key: *const [key_length]u8) Ghash {
4242 const h1 = mem.readIntBig(u64, key[0..8]);
4343 const h0 = mem.readIntBig(u64, key[8..16]);
44 const h1r = @bitReverse(u64, h1);
45 const h0r = @bitReverse(u64, h0);
44 const h1r = @bitReverse(h1);
45 const h0r = @bitReverse(h0);
4646 const h2 = h0 ^ h1;
4747 const h2r = h0r ^ h1r;
4848
......@@ -68,8 +68,8 @@ pub const Ghash = struct {
6868 hh.update(key);
6969 const hh1 = hh.y1;
7070 const hh0 = hh.y0;
71 const hh1r = @bitReverse(u64, hh1);
72 const hh0r = @bitReverse(u64, hh0);
71 const hh1r = @bitReverse(hh1);
72 const hh0r = @bitReverse(hh0);
7373 const hh2 = hh0 ^ hh1;
7474 const hh2r = hh0r ^ hh1r;
7575
......@@ -156,8 +156,8 @@ pub const Ghash = struct {
156156 y1 ^= mem.readIntBig(u64, msg[i..][0..8]);
157157 y0 ^= mem.readIntBig(u64, msg[i..][8..16]);
158158
159 const y1r = @bitReverse(u64, y1);
160 const y0r = @bitReverse(u64, y0);
159 const y1r = @bitReverse(y1);
160 const y0r = @bitReverse(y0);
161161 const y2 = y0 ^ y1;
162162 const y2r = y0r ^ y1r;
163163
......@@ -172,8 +172,8 @@ pub const Ghash = struct {
172172 const sy1 = mem.readIntBig(u64, msg[i..][16..24]);
173173 const sy0 = mem.readIntBig(u64, msg[i..][24..32]);
174174
175 const sy1r = @bitReverse(u64, sy1);
176 const sy0r = @bitReverse(u64, sy0);
175 const sy1r = @bitReverse(sy1);
176 const sy0r = @bitReverse(sy0);
177177 const sy2 = sy0 ^ sy1;
178178 const sy2r = sy0r ^ sy1r;
179179
......@@ -191,9 +191,9 @@ pub const Ghash = struct {
191191 z0h ^= sz0h;
192192 z1h ^= sz1h;
193193 z2h ^= sz2h;
194 z0h = @bitReverse(u64, z0h) >> 1;
195 z1h = @bitReverse(u64, z1h) >> 1;
196 z2h = @bitReverse(u64, z2h) >> 1;
194 z0h = @bitReverse(z0h) >> 1;
195 z1h = @bitReverse(z1h) >> 1;
196 z2h = @bitReverse(z2h) >> 1;
197197
198198 var v3 = z1h;
199199 var v2 = z1 ^ z2h;
......@@ -217,8 +217,8 @@ pub const Ghash = struct {
217217 y1 ^= mem.readIntBig(u64, msg[i..][0..8]);
218218 y0 ^= mem.readIntBig(u64, msg[i..][8..16]);
219219
220 const y1r = @bitReverse(u64, y1);
221 const y0r = @bitReverse(u64, y0);
220 const y1r = @bitReverse(y1);
221 const y0r = @bitReverse(y0);
222222 const y2 = y0 ^ y1;
223223 const y2r = y0r ^ y1r;
224224
......@@ -228,9 +228,9 @@ pub const Ghash = struct {
228228 var z0h = clmul(y0r, st.h0r);
229229 var z1h = clmul(y1r, st.h1r);
230230 var z2h = clmul(y2r, st.h2r) ^ z0h ^ z1h;
231 z0h = @bitReverse(u64, z0h) >> 1;
232 z1h = @bitReverse(u64, z1h) >> 1;
233 z2h = @bitReverse(u64, z2h) >> 1;
231 z0h = @bitReverse(z0h) >> 1;
232 z1h = @bitReverse(z1h) >> 1;
233 z2h = @bitReverse(z2h) >> 1;
234234
235235 // shift & reduce
236236 var v3 = z1h;
lib/std/debug.zig+186-128
......@@ -816,11 +816,11 @@ pub fn openSelfDebugInfo(allocator: mem.Allocator) anyerror!DebugInfo {
816816/// TODO it's weird to take ownership even on error, rework this code.
817817fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo {
818818 nosuspend {
819 errdefer coff_file.close();
819 defer coff_file.close();
820820
821821 const coff_obj = try allocator.create(coff.Coff);
822822 errdefer allocator.destroy(coff_obj);
823 coff_obj.* = coff.Coff.init(allocator, coff_file);
823 coff_obj.* = .{ .allocator = allocator };
824824
825825 var di = ModuleDebugInfo{
826826 .base_address = undefined,
......@@ -828,27 +828,42 @@ fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo
828828 .debug_data = undefined,
829829 };
830830
831 try di.coff.loadHeader();
832 try di.coff.loadSections();
833 if (di.coff.getSection(".debug_info")) |sec| {
831 // TODO convert to Windows' memory-mapped file API
832 const file_len = math.cast(usize, try coff_file.getEndPos()) orelse math.maxInt(usize);
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| {
834837 // This coff file has embedded DWARF debug info
835838 _ = sec;
836839 // TODO: free the section data slices
837 const debug_info_data = di.coff.getSectionData(".debug_info", allocator) catch null;
838 const debug_abbrev_data = di.coff.getSectionData(".debug_abbrev", allocator) catch null;
839 const debug_str_data = di.coff.getSectionData(".debug_str", allocator) catch null;
840 const debug_line_data = di.coff.getSectionData(".debug_line", allocator) catch null;
841 const debug_line_str_data = di.coff.getSectionData(".debug_line_str", allocator) catch null;
842 const debug_ranges_data = di.coff.getSectionData(".debug_ranges", allocator) catch null;
840 const debug_info = di.coff.getSectionDataAlloc(".debug_info", allocator) catch null;
841 const debug_abbrev = di.coff.getSectionDataAlloc(".debug_abbrev", allocator) catch null;
842 const debug_str = di.coff.getSectionDataAlloc(".debug_str", allocator) catch null;
843 const debug_str_offsets = di.coff.getSectionDataAlloc(".debug_str_offsets", allocator) catch null;
844 const debug_line = di.coff.getSectionDataAlloc(".debug_line", 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
844853 var dwarf = DW.DwarfInfo{
845854 .endian = native_endian,
846 .debug_info = debug_info_data orelse return error.MissingDebugInfo,
847 .debug_abbrev = debug_abbrev_data orelse return error.MissingDebugInfo,
848 .debug_str = debug_str_data orelse return error.MissingDebugInfo,
849 .debug_line = debug_line_data orelse return error.MissingDebugInfo,
850 .debug_line_str = debug_line_str_data,
851 .debug_ranges = debug_ranges_data,
855 .debug_info = debug_info orelse return error.MissingDebugInfo,
856 .debug_abbrev = debug_abbrev orelse return error.MissingDebugInfo,
857 .debug_str = debug_str orelse return error.MissingDebugInfo,
858 .debug_str_offsets = debug_str_offsets,
859 .debug_line = debug_line orelse return error.MissingDebugInfo,
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,
852867 };
853868 try DW.openDwarfDebugInfo(&dwarf, allocator);
854869 di.debug_data = PdbOrDwarf{ .dwarf = dwarf };
......@@ -863,7 +878,10 @@ fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo
863878 defer allocator.free(path);
864879
865880 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 };
867885 try di.debug_data.pdb.parseInfoStream();
868886 try di.debug_data.pdb.parseDbiStream();
869887
......@@ -912,9 +930,15 @@ pub fn readElfDebugInfo(allocator: mem.Allocator, elf_file: File) !ModuleDebugIn
912930 var opt_debug_info: ?[]const u8 = null;
913931 var opt_debug_abbrev: ?[]const u8 = null;
914932 var opt_debug_str: ?[]const u8 = null;
933 var opt_debug_str_offsets: ?[]const u8 = null;
915934 var opt_debug_line: ?[]const u8 = null;
916935 var opt_debug_line_str: ?[]const u8 = null;
917936 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
919943 for (shdrs) |*shdr| {
920944 if (shdr.sh_type == elf.SHT_NULL) continue;
......@@ -926,12 +950,24 @@ pub fn readElfDebugInfo(allocator: mem.Allocator, elf_file: File) !ModuleDebugIn
926950 opt_debug_abbrev = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
927951 } else if (mem.eql(u8, name, ".debug_str")) {
928952 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);
929955 } else if (mem.eql(u8, name, ".debug_line")) {
930956 opt_debug_line = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
931957 } else if (mem.eql(u8, name, ".debug_line_str")) {
932958 opt_debug_line_str = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
933959 } else if (mem.eql(u8, name, ".debug_ranges")) {
934960 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);
935971 }
936972 }
937973
......@@ -940,9 +976,15 @@ pub fn readElfDebugInfo(allocator: mem.Allocator, elf_file: File) !ModuleDebugIn
940976 .debug_info = opt_debug_info orelse return error.MissingDebugInfo,
941977 .debug_abbrev = opt_debug_abbrev orelse return error.MissingDebugInfo,
942978 .debug_str = opt_debug_str orelse return error.MissingDebugInfo,
979 .debug_str_offsets = opt_debug_str_offsets,
943980 .debug_line = opt_debug_line orelse return error.MissingDebugInfo,
944981 .debug_line_str = opt_debug_line_str,
945982 .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,
946988 };
947989
948990 try DW.openDwarfDebugInfo(&di, allocator);
......@@ -968,24 +1010,20 @@ fn readMachODebugInfo(allocator: mem.Allocator, macho_file: File) !ModuleDebugIn
9681010 if (hdr.magic != macho.MH_MAGIC_64)
9691011 return error.InvalidDebugInfo;
9701012
971 const hdr_base = @ptrCast([*]const u8, hdr);
972 var ptr = hdr_base + @sizeOf(macho.mach_header_64);
973 var ncmd: u32 = hdr.ncmds;
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;
1013 var it = macho.LoadCommandIterator{
1014 .ncmds = hdr.ncmds,
1015 .buffer = mapped_mem[@sizeOf(macho.mach_header_64)..][0..hdr.sizeofcmds],
9831016 };
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
9841022 const syms = @ptrCast(
9851023 [*]const macho.nlist_64,
986 @alignCast(@alignOf(macho.nlist_64), hdr_base + symtab.symoff),
1024 @alignCast(@alignOf(macho.nlist_64), &mapped_mem[symtab.symoff]),
9871025 )[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
9901028 const symbols_buf = try allocator.alloc(MachoSymbol, syms.len);
9911029
......@@ -1200,48 +1238,46 @@ pub const DebugInfo = struct {
12001238 if (address < base_address) continue;
12011239
12021240 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(
1216 *const std.macho.segment_command_64,
1217 @alignCast(@alignOf(std.macho.segment_command_64), lc),
1218 );
1242 var it = macho.LoadCommandIterator{
1243 .ncmds = header.ncmds,
1244 .buffer = @alignCast(@alignOf(u64), @intToPtr(
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;
1221 const seg_start = segment_cmd.vmaddr;
1222 const seg_end = seg_start + segment_cmd.vmsize;
1274 try self.address_map.putNoClobber(base_address, obj_di);
12231275
1224 if (rebased_address >= seg_start and rebased_address < seg_end) {
1225 if (self.address_map.get(base_address)) |obj_di| {
12261276 return obj_di;
12271277 }
1228
1229 const obj_di = try self.allocator.create(ModuleDebugInfo);
1230 errdefer self.allocator.destroy(obj_di);
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 }
1278 },
1279 else => {},
1280 };
12451281 }
12461282
12471283 return error.MissingDebugInfo;
......@@ -1445,44 +1481,31 @@ pub const ModuleDebugInfo = switch (native_os) {
14451481 if (hdr.magic != std.macho.MH_MAGIC_64)
14461482 return error.InvalidDebugInfo;
14471483
1448 const hdr_base = @ptrCast([*]const u8, hdr);
1449 var ptr = hdr_base + @sizeOf(macho.mach_header_64);
1450 var segptr = ptr;
1451 var ncmd: u32 = hdr.ncmds;
1452 var segcmd: ?*const macho.segment_command_64 = null;
1453 var symtabcmd: ?*const macho.symtab_command = null;
1454
1455 while (ncmd != 0) : (ncmd -= 1) {
1456 const lc = @ptrCast(*const std.macho.load_command, ptr);
1457 switch (lc.cmd) {
1458 .SEGMENT_64 => {
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 }
1484 var segcmd: ?macho.LoadCommandIterator.LoadCommand = null;
1485 var symtabcmd: ?macho.symtab_command = null;
1486 var it = macho.LoadCommandIterator{
1487 .ncmds = hdr.ncmds,
1488 .buffer = mapped_mem[@sizeOf(macho.mach_header_64)..][0..hdr.sizeofcmds],
1489 };
1490 while (it.next()) |cmd| switch (cmd.cmd()) {
1491 .SEGMENT_64 => segcmd = cmd,
1492 .SYMTAB => symtabcmd = cmd.cast(macho.symtab_command).?,
1493 else => {},
1494 };
14751495
14761496 if (segcmd == null or symtabcmd == null) return error.MissingDebugInfo;
14771497
14781498 // Parse symbols
14791499 const strtab = @ptrCast(
14801500 [*]const u8,
1481 hdr_base + symtabcmd.?.stroff,
1501 &mapped_mem[symtabcmd.?.stroff],
14821502 )[0 .. symtabcmd.?.strsize - 1 :0];
14831503 const symtab = @ptrCast(
14841504 [*]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 ),
14861509 )[0..symtabcmd.?.nsyms];
14871510
14881511 // TODO handle tentative (common) symbols
......@@ -1496,25 +1519,21 @@ pub const ModuleDebugInfo = switch (native_os) {
14961519 addr_table.putAssumeCapacityNoClobber(sym_name, sym.n_value);
14971520 }
14981521
1499 var opt_debug_line: ?*const macho.section_64 = null;
1500 var opt_debug_info: ?*const macho.section_64 = null;
1501 var opt_debug_abbrev: ?*const macho.section_64 = null;
1502 var opt_debug_str: ?*const macho.section_64 = null;
1503 var opt_debug_line_str: ?*const macho.section_64 = null;
1504 var opt_debug_ranges: ?*const macho.section_64 = null;
1505
1506 const sections = @ptrCast(
1507 [*]const macho.section_64,
1508 @alignCast(@alignOf(macho.section_64), segptr + @sizeOf(std.macho.segment_command_64)),
1509 )[0..segcmd.?.nsects];
1510 for (sections) |*sect| {
1511 // The section name may not exceed 16 chars and a trailing null may
1512 // not be present
1513 const name = if (mem.indexOfScalar(u8, sect.sectname[0..], 0)) |last|
1514 sect.sectname[0..last]
1515 else
1516 sect.sectname[0..];
1517
1522 var opt_debug_line: ?macho.section_64 = null;
1523 var opt_debug_info: ?macho.section_64 = null;
1524 var opt_debug_abbrev: ?macho.section_64 = null;
1525 var opt_debug_str: ?macho.section_64 = null;
1526 var opt_debug_str_offsets: ?macho.section_64 = null;
1527 var opt_debug_line_str: ?macho.section_64 = null;
1528 var opt_debug_ranges: ?macho.section_64 = null;
1529 var opt_debug_loclists: ?macho.section_64 = null;
1530 var opt_debug_rnglists: ?macho.section_64 = null;
1531 var opt_debug_addr: ?macho.section_64 = null;
1532 var opt_debug_names: ?macho.section_64 = null;
1533 var opt_debug_frame: ?macho.section_64 = null;
1534
1535 for (segcmd.?.getSections()) |sect| {
1536 const name = sect.sectName();
15181537 if (mem.eql(u8, name, "__debug_line")) {
15191538 opt_debug_line = sect;
15201539 } else if (mem.eql(u8, name, "__debug_info")) {
......@@ -1523,10 +1542,22 @@ pub const ModuleDebugInfo = switch (native_os) {
15231542 opt_debug_abbrev = sect;
15241543 } else if (mem.eql(u8, name, "__debug_str")) {
15251544 opt_debug_str = sect;
1545 } else if (mem.eql(u8, name, "__debug_str_offsets")) {
1546 opt_debug_str_offsets = sect;
15261547 } else if (mem.eql(u8, name, "__debug_line_str")) {
15271548 opt_debug_line_str = sect;
15281549 } else if (mem.eql(u8, name, "__debug_ranges")) {
15291550 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;
15301561 }
15311562 }
15321563
......@@ -1544,6 +1575,10 @@ pub const ModuleDebugInfo = switch (native_os) {
15441575 .debug_info = try chopSlice(mapped_mem, debug_info.offset, debug_info.size),
15451576 .debug_abbrev = try chopSlice(mapped_mem, debug_abbrev.offset, debug_abbrev.size),
15461577 .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,
15471582 .debug_line = try chopSlice(mapped_mem, debug_line.offset, debug_line.size),
15481583 .debug_line_str = if (opt_debug_line_str) |debug_line_str|
15491584 try chopSlice(mapped_mem, debug_line_str.offset, debug_line_str.size)
......@@ -1553,6 +1588,26 @@ pub const ModuleDebugInfo = switch (native_os) {
15531588 try chopSlice(mapped_mem, debug_ranges.offset, debug_ranges.size)
15541589 else
15551590 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,
15561611 };
15571612
15581613 try DW.openDwarfDebugInfo(&di, allocator);
......@@ -1607,6 +1662,8 @@ pub const ModuleDebugInfo = switch (native_os) {
16071662 .compile_unit_name = compile_unit.die.getAttrString(
16081663 o_file_di,
16091664 DW.AT.name,
1665 o_file_di.debug_str,
1666 compile_unit.*,
16101667 ) catch |err| switch (err) {
16111668 error.MissingDebugInfo, error.InvalidDebugInfo => "???",
16121669 },
......@@ -1647,7 +1704,7 @@ pub const ModuleDebugInfo = switch (native_os) {
16471704
16481705 switch (self.debug_data) {
16491706 .dwarf => |*dwarf| {
1650 const dwarf_address = relocated_address + self.coff.pe_header.image_base;
1707 const dwarf_address = relocated_address + self.coff.getImageBase();
16511708 return getSymbolFromDwarf(allocator, dwarf_address, dwarf);
16521709 },
16531710 .pdb => {
......@@ -1655,13 +1712,14 @@ pub const ModuleDebugInfo = switch (native_os) {
16551712 },
16561713 }
16571714
1658 var coff_section: *coff.Section = undefined;
1715 var coff_section: *align(1) const coff.SectionHeader = undefined;
16591716 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;
16611719 // 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;
16651723 const vaddr_end = vaddr_start + sect_contrib.Size;
16661724 if (relocated_address >= vaddr_start and relocated_address < vaddr_end) {
16671725 break sect_contrib.ModuleIndex;
......@@ -1677,11 +1735,11 @@ pub const ModuleDebugInfo = switch (native_os) {
16771735
16781736 const symbol_name = self.debug_data.pdb.getSymbolName(
16791737 module,
1680 relocated_address - coff_section.header.virtual_address,
1738 relocated_address - coff_section.virtual_address,
16811739 ) orelse "???";
16821740 const opt_line_info = try self.debug_data.pdb.getLineNumberInfo(
16831741 module,
1684 relocated_address - coff_section.header.virtual_address,
1742 relocated_address - coff_section.virtual_address,
16851743 );
16861744
16871745 return SymbolInfo{
......@@ -1727,7 +1785,7 @@ fn getSymbolFromDwarf(allocator: mem.Allocator, address: u64, di: *DW.DwarfInfo)
17271785 if (nosuspend di.findCompileUnit(address)) |compile_unit| {
17281786 return SymbolInfo{
17291787 .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) {
17311789 error.MissingDebugInfo, error.InvalidDebugInfo => "???",
17321790 },
17331791 .line_info = nosuspend di.getLineNumberInfo(allocator, compile_unit.*, address) catch |err| switch (err) {
......@@ -1816,7 +1874,7 @@ fn resetSegfaultHandler() void {
18161874 return;
18171875 }
18181876 var act = os.Sigaction{
1819 .handler = .{ .sigaction = os.SIG.DFL },
1877 .handler = .{ .handler = os.SIG.DFL },
18201878 .mask = os.empty_sigset,
18211879 .flags = 0,
18221880 };
......@@ -1976,7 +2034,7 @@ noinline fn showMyTrace() usize {
19762034/// For more advanced usage, see `ConfigurableTrace`.
19772035pub 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 {
19802038 return struct {
19812039 addrs: [actual_size][stack_frame_count]usize = undefined,
19822040 notes: [actual_size][]const u8 = undefined,
......@@ -1985,7 +2043,7 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize
19852043 const actual_size = if (enabled) size else 0;
19862044 const Index = if (enabled) usize else u0;
19872045
1988 pub const enabled = enabled;
2046 pub const enabled = is_enabled;
19892047
19902048 pub const add = if (enabled) addNoInline else addNoOp;
19912049
lib/std/dwarf.zig+383-156
......@@ -168,6 +168,11 @@ const CompileUnit = struct {
168168 is_64: bool,
169169 die: *Die,
170170 pc_range: ?PcRange,
171
172 str_offsets_base: usize,
173 addr_base: usize,
174 rnglists_base: usize,
175 loclists_base: usize,
171176};
172177
173178const AbbrevTable = std.ArrayList(AbbrevTableEntry);
......@@ -205,6 +210,7 @@ const AbbrevAttr = struct {
205210
206211const FormValue = union(enum) {
207212 Address: u64,
213 AddrOffset: usize,
208214 Block: []u8,
209215 Const: Constant,
210216 ExprLoc: []u8,
......@@ -214,15 +220,46 @@ const FormValue = union(enum) {
214220 RefAddr: u64,
215221 String: []const u8,
216222 StrPtr: u64,
223 StrOffset: usize,
217224 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 }
218255};
219256
220257const Constant = struct {
221258 payload: u64,
222259 signed: bool,
223260
224 fn asUnsignedLe(self: *const Constant) !u64 {
225 if (self.signed) return error.InvalidDebugInfo;
261 fn asUnsignedLe(self: Constant) !u64 {
262 if (self.signed) return badDwarf();
226263 return self.payload;
227264 }
228265};
......@@ -251,21 +288,46 @@ const Die = struct {
251288 return null;
252289 }
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 {
255297 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
256298 return switch (form_value.*) {
257299 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 },
258324 else => error.InvalidDebugInfo,
259325 };
260326 }
261327
262328 fn getAttrSecOffset(self: *const Die, id: u64) !u64 {
263329 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
264 return switch (form_value.*) {
265 FormValue.Const => |value| value.asUnsignedLe(),
266 FormValue.SecOffset => |value| value,
267 else => error.InvalidDebugInfo,
268 };
330 return form_value.getUInt(u64);
269331 }
270332
271333 fn getAttrUnsignedLe(self: *const Die, id: u64) !u64 {
......@@ -284,22 +346,44 @@ const Die = struct {
284346 };
285347 }
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 {
288356 const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
289 return switch (form_value.*) {
290 FormValue.String => |value| value,
291 FormValue.StrPtr => |offset| di.getString(offset),
292 FormValue.LineStrPtr => |offset| di.getLineString(offset),
293 else => error.InvalidDebugInfo,
294 };
357 switch (form_value.*) {
358 FormValue.String => |value| return value,
359 FormValue.StrPtr => |offset| return di.getString(offset),
360 FormValue.StrOffset => |index| {
361 const debug_str_offsets = di.debug_str_offsets orelse return badDwarf();
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 }
295378 }
296379};
297380
298381const FileEntry = struct {
299 file_name: []const u8,
300 dir_index: usize,
301 mtime: usize,
302 len_bytes: usize,
382 path: []const u8,
383 dir_index: u32 = 0,
384 mtime: u64 = 0,
385 size: u64 = 0,
386 md5: [16]u8 = [1]u8{0} ** 16,
303387};
304388
305389const LineNumberProgram = struct {
......@@ -307,13 +391,14 @@ const LineNumberProgram = struct {
307391 file: usize,
308392 line: i64,
309393 column: u64,
394 version: u16,
310395 is_stmt: bool,
311396 basic_block: bool,
312397 end_sequence: bool,
313398
314399 default_is_stmt: bool,
315400 target_address: u64,
316 include_dirs: []const []const u8,
401 include_dirs: []const FileEntry,
317402
318403 prev_valid: bool,
319404 prev_address: u64,
......@@ -344,12 +429,18 @@ const LineNumberProgram = struct {
344429 self.prev_end_sequence = undefined;
345430 }
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 {
348438 return LineNumberProgram{
349439 .address = 0,
350440 .file = 1,
351441 .line = 1,
352442 .column = 0,
443 .version = version,
353444 .is_stmt = is_stmt,
354445 .basic_block = false,
355446 .end_sequence = false,
......@@ -372,18 +463,24 @@ const LineNumberProgram = struct {
372463 allocator: mem.Allocator,
373464 file_entries: []const FileEntry,
374465 ) !?debug.LineInfo {
375 if (self.prev_valid and self.target_address >= self.prev_address and self.target_address < self.address) {
376 const file_entry = if (self.prev_file == 0) {
377 return error.MissingDebugInfo;
378 } else if (self.prev_file - 1 >= file_entries.len) {
379 return error.InvalidDebugInfo;
380 } else &file_entries[self.prev_file - 1];
466 if (self.prev_valid and
467 self.target_address >= self.prev_address and
468 self.target_address < self.address)
469 {
470 const file_index = if (self.version >= 5) self.prev_file else i: {
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) {
383 return error.InvalidDebugInfo;
384 } else self.include_dirs[file_entry.dir_index];
475 if (file_index >= file_entries.len) return badDwarf();
476 const file_entry = &file_entries[file_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
388485 return debug.LineInfo{
389486 .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)
410507 if (is_64.*) {
411508 return in_stream.readInt(u64, endian);
412509 } else {
413 if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
510 if (first_32_bits >= 0xfffffff0) return badDwarf();
414511 // TODO this cast should not be needed
415512 return @as(u64, first_32_bits);
416513 }
......@@ -487,6 +584,12 @@ fn parseFormValueRef(in_stream: anytype, endian: std.builtin.Endian, size: i32)
487584fn parseFormValue(allocator: mem.Allocator, in_stream: anytype, form_id: u64, endian: std.builtin.Endian, is_64: bool) anyerror!FormValue {
488585 return switch (form_id) {
489586 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
490593 FORM.block1 => parseFormValueBlock(allocator, in_stream, endian, 1),
491594 FORM.block2 => parseFormValueBlock(allocator, in_stream, endian, 2),
492595 FORM.block4 => parseFormValueBlock(allocator, in_stream, endian, 4),
......@@ -498,6 +601,11 @@ fn parseFormValue(allocator: mem.Allocator, in_stream: anytype, form_id: u64, en
498601 FORM.data2 => parseFormValueConstant(in_stream, false, endian, 2),
499602 FORM.data4 => parseFormValueConstant(in_stream, false, endian, 4),
500603 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 },
501609 FORM.udata, FORM.sdata => {
502610 const signed = form_id == FORM.sdata;
503611 return parseFormValueConstant(in_stream, signed, endian, -1);
......@@ -522,6 +630,11 @@ fn parseFormValue(allocator: mem.Allocator, in_stream: anytype, form_id: u64, en
522630
523631 FORM.string => FormValue{ .String = try in_stream.readUntilDelimiterAlloc(allocator, 0, math.maxInt(usize)) },
524632 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) },
525638 FORM.line_strp => FormValue{ .LineStrPtr = try readAddress(in_stream, endian, is_64) },
526639 FORM.indirect => {
527640 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
534647 return await @asyncCall(frame, {}, parseFormValue, .{ allocator, in_stream, child_form_id, endian, is_64 });
535648 },
536649 FORM.implicit_const => FormValue{ .Const = Constant{ .signed = true, .payload = undefined } },
537
650 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) },
538652 else => {
539 return error.InvalidDebugInfo;
653 //std.debug.print("unrecognized form id: {x}\n", .{form_id});
654 return badDwarf();
540655 },
541656 };
542657}
......@@ -554,9 +669,15 @@ pub const DwarfInfo = struct {
554669 debug_info: []const u8,
555670 debug_abbrev: []const u8,
556671 debug_str: []const u8,
672 debug_str_offsets: ?[]const u8,
557673 debug_line: []const u8,
558674 debug_line_str: ?[]const u8,
559675 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,
560681 // Filled later by the initializer
561682 abbrev_table_list: std.ArrayListUnmanaged(AbbrevTableHeader) = .{},
562683 compile_unit_list: std.ArrayListUnmanaged(CompileUnit) = .{},
......@@ -592,7 +713,7 @@ pub const DwarfInfo = struct {
592713
593714 fn scanAllFunctions(di: *DwarfInfo, allocator: mem.Allocator) !void {
594715 var stream = io.fixedBufferStream(di.debug_info);
595 const in = &stream.reader();
716 const in = stream.reader();
596717 const seekable = &stream.seekableStream();
597718 var this_unit_offset: u64 = 0;
598719
......@@ -609,29 +730,26 @@ pub const DwarfInfo = struct {
609730 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
610731
611732 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
614735 var address_size: u8 = undefined;
615736 var debug_abbrev_offset: u64 = undefined;
616 switch (version) {
617 5 => {
618 const unit_type = try in.readInt(u8, di.endian);
619 if (unit_type != UT.compile) return error.InvalidDebugInfo;
620 address_size = try in.readByte();
621 debug_abbrev_offset = if (is_64)
622 try in.readInt(u64, di.endian)
623 else
624 try in.readInt(u32, di.endian);
625 },
626 else => {
627 debug_abbrev_offset = if (is_64)
628 try in.readInt(u64, di.endian)
629 else
630 try in.readInt(u32, di.endian);
631 address_size = try in.readByte();
632 },
737 if (version >= 5) {
738 const unit_type = try in.readInt(u8, di.endian);
739 if (unit_type != UT.compile) return badDwarf();
740 address_size = try in.readByte();
741 debug_abbrev_offset = if (is_64)
742 try in.readInt(u64, di.endian)
743 else
744 try in.readInt(u32, di.endian);
745 } else {
746 debug_abbrev_offset = if (is_64)
747 try in.readInt(u64, di.endian)
748 else
749 try in.readInt(u32, di.endian);
750 address_size = try in.readByte();
633751 }
634 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
752 if (address_size != @sizeOf(usize)) return badDwarf();
635753
636754 const compile_unit_pos = try seekable.getPos();
637755 const abbrev_table = try di.getAbbrevTable(allocator, debug_abbrev_offset);
......@@ -640,11 +758,26 @@ pub const DwarfInfo = struct {
640758
641759 const next_unit_pos = this_unit_offset + next_offset;
642760
761 var compile_unit: CompileUnit = undefined;
762
643763 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;
645765 const after_die_offset = try seekable.getPos();
646766
647767 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 },
648781 TAG.subprogram, TAG.inlined_subroutine, TAG.subroutine, TAG.entry_point => {
649782 const fn_name = x: {
650783 var depth: i32 = 3;
......@@ -652,30 +785,30 @@ pub const DwarfInfo = struct {
652785 // Prevent endless loops
653786 while (depth > 0) : (depth -= 1) {
654787 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);
656789 break :x try allocator.dupe(u8, name);
657790 } else if (this_die_obj.getAttr(AT.abstract_origin)) |_| {
658791 // Follow the DIE it points to and repeat
659792 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();
661794 try seekable.seekTo(this_unit_offset + ref_offset);
662795 this_die_obj = (try di.parseDie(
663796 arena,
664797 in,
665798 abbrev_table,
666799 is_64,
667 )) orelse return error.InvalidDebugInfo;
800 )) orelse return badDwarf();
668801 } else if (this_die_obj.getAttr(AT.specification)) |_| {
669802 // Follow the DIE it points to and repeat
670803 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();
672805 try seekable.seekTo(this_unit_offset + ref_offset);
673806 this_die_obj = (try di.parseDie(
674807 arena,
675808 in,
676809 abbrev_table,
677810 is_64,
678 )) orelse return error.InvalidDebugInfo;
811 )) orelse return badDwarf();
679812 } else {
680813 break :x null;
681814 }
......@@ -685,7 +818,7 @@ pub const DwarfInfo = struct {
685818 };
686819
687820 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| {
689822 if (die_obj.getAttr(AT.high_pc)) |high_pc_value| {
690823 const pc_end = switch (high_pc_value.*) {
691824 FormValue.Address => |value| value,
......@@ -693,7 +826,7 @@ pub const DwarfInfo = struct {
693826 const offset = try value.asUnsignedLe();
694827 break :b (low_pc + offset);
695828 },
696 else => return error.InvalidDebugInfo,
829 else => return badDwarf(),
697830 };
698831 break :x PcRange{
699832 .start = low_pc,
......@@ -738,29 +871,26 @@ pub const DwarfInfo = struct {
738871 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
739872
740873 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
743876 var address_size: u8 = undefined;
744877 var debug_abbrev_offset: u64 = undefined;
745 switch (version) {
746 5 => {
747 const unit_type = try in.readInt(u8, di.endian);
748 if (unit_type != UT.compile) return error.InvalidDebugInfo;
749 address_size = try in.readByte();
750 debug_abbrev_offset = if (is_64)
751 try in.readInt(u64, di.endian)
752 else
753 try in.readInt(u32, di.endian);
754 },
755 else => {
756 debug_abbrev_offset = if (is_64)
757 try in.readInt(u64, di.endian)
758 else
759 try in.readInt(u32, di.endian);
760 address_size = try in.readByte();
761 },
878 if (version >= 5) {
879 const unit_type = try in.readInt(u8, di.endian);
880 if (unit_type != UT.compile) return badDwarf();
881 address_size = try in.readByte();
882 debug_abbrev_offset = if (is_64)
883 try in.readInt(u64, di.endian)
884 else
885 try in.readInt(u32, di.endian);
886 } else {
887 debug_abbrev_offset = if (is_64)
888 try in.readInt(u64, di.endian)
889 else
890 try in.readInt(u32, di.endian);
891 address_size = try in.readByte();
762892 }
763 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
893 if (address_size != @sizeOf(usize)) return badDwarf();
764894
765895 const compile_unit_pos = try seekable.getPos();
766896 const abbrev_table = try di.getAbbrevTable(allocator, debug_abbrev_offset);
......@@ -770,12 +900,23 @@ pub const DwarfInfo = struct {
770900 const compile_unit_die = try allocator.create(Die);
771901 errdefer allocator.destroy(compile_unit_die);
772902 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: {
778 if (compile_unit_die.getAttrAddr(AT.low_pc)) |low_pc| {
907 var compile_unit: CompileUnit = .{
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| {
779920 if (compile_unit_die.getAttr(AT.high_pc)) |high_pc_value| {
780921 const pc_end = switch (high_pc_value.*) {
781922 FormValue.Address => |value| value,
......@@ -783,7 +924,7 @@ pub const DwarfInfo = struct {
783924 const offset = try value.asUnsignedLe();
784925 break :b (low_pc + offset);
785926 },
786 else => return error.InvalidDebugInfo,
927 else => return badDwarf(),
787928 };
788929 break :x PcRange{
789930 .start = low_pc,
......@@ -798,12 +939,7 @@ pub const DwarfInfo = struct {
798939 }
799940 };
800941
801 try di.compile_unit_list.append(allocator, CompileUnit{
802 .version = version,
803 .is_64 = is_64,
804 .pc_range = pc_range,
805 .die = compile_unit_die,
806 });
942 try di.compile_unit_list.append(allocator, compile_unit);
807943
808944 this_unit_offset += next_offset;
809945 }
......@@ -824,7 +960,7 @@ pub const DwarfInfo = struct {
824960 // specified by DW_AT.low_pc or to some other value encoded
825961 // in the list itself.
826962 // 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) {
828964 error.MissingDebugInfo => @as(u64, 0), // TODO https://github.com/ziglang/zig/issues/11135
829965 else => return err,
830966 };
......@@ -852,7 +988,7 @@ pub const DwarfInfo = struct {
852988 }
853989 }
854990 }
855 return error.MissingDebugInfo;
991 return missingDwarf();
856992 }
857993
858994 /// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
......@@ -919,7 +1055,7 @@ pub const DwarfInfo = struct {
9191055 ) !?Die {
9201056 const abbrev_code = try leb.readULEB128(u64, in_stream);
9211057 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
9241060 var result = Die{
9251061 // Lives as long as the Die.
......@@ -956,7 +1092,7 @@ pub const DwarfInfo = struct {
9561092 const in = &stream.reader();
9571093 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);
9601096 const line_info_offset = try compile_unit.die.getAttrSecOffset(AT.stmt_list);
9611097
9621098 try seekable.seekTo(line_info_offset);
......@@ -964,18 +1100,25 @@ pub const DwarfInfo = struct {
9641100 var is_64: bool = undefined;
9651101 const unit_length = try readUnitLength(in, di.endian, &is_64);
9661102 if (unit_length == 0) {
967 return error.MissingDebugInfo;
1103 return missingDwarf();
9681104 }
9691105 const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
9701106
9711107 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
9741117 const prologue_length = if (is_64) try in.readInt(u64, di.endian) else try in.readInt(u32, di.endian);
9751118 const prog_start_offset = (try seekable.getPos()) + prologue_length;
9761119
9771120 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
9801123 if (version >= 4) {
9811124 // maximum_operations_per_instruction
......@@ -986,7 +1129,7 @@ pub const DwarfInfo = struct {
9861129 const line_base = try in.readByteSigned();
9871130
9881131 const line_range = try in.readByte();
989 if (line_range == 0) return error.InvalidDebugInfo;
1132 if (line_range == 0) return badDwarf();
9901133
9911134 const opcode_base = try in.readByte();
9921135
......@@ -1004,36 +1147,120 @@ pub const DwarfInfo = struct {
10041147 defer tmp_arena.deinit();
10051148 const arena = tmp_arena.allocator();
10061149
1007 var include_directories = std.ArrayList([]const u8).init(arena);
1008 try include_directories.append(compile_unit_cwd);
1150 var include_directories = std.ArrayList(FileEntry).init(arena);
1151 var file_entries = std.ArrayList(FileEntry).init(arena);
10091152
1010 while (true) {
1011 const dir = try in.readUntilDelimiterAlloc(arena, 0, math.maxInt(usize));
1012 if (dir.len == 0) break;
1013 try include_directories.append(dir);
1153 if (version < 5) {
1154 try include_directories.append(.{ .path = compile_unit_cwd });
1155
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 }
10141255 }
10151256
1016 var file_entries = std.ArrayList(FileEntry).init(arena);
10171257 var prog = LineNumberProgram.init(
10181258 default_is_stmt,
10191259 include_directories.items,
10201260 target_address,
1261 version,
10211262 );
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
10371264 try seekable.seekTo(prog_start_offset);
10381265
10391266 const next_unit_pos = line_info_offset + next_offset;
......@@ -1043,7 +1270,7 @@ pub const DwarfInfo = struct {
10431270
10441271 if (opcode == LNS.extended_op) {
10451272 const op_size = try leb.readULEB128(u64, in);
1046 if (op_size < 1) return error.InvalidDebugInfo;
1273 if (op_size < 1) return badDwarf();
10471274 var sub_op = try in.readByte();
10481275 switch (sub_op) {
10491276 LNE.end_sequence => {
......@@ -1056,19 +1283,19 @@ pub const DwarfInfo = struct {
10561283 prog.address = addr;
10571284 },
10581285 LNE.define_file => {
1059 const file_name = try in.readUntilDelimiterAlloc(arena, 0, math.maxInt(usize));
1060 const dir_index = try leb.readULEB128(usize, in);
1061 const mtime = try leb.readULEB128(usize, in);
1062 const len_bytes = try leb.readULEB128(usize, in);
1286 const path = try in.readUntilDelimiterAlloc(arena, 0, math.maxInt(usize));
1287 const dir_index = try leb.readULEB128(u32, in);
1288 const mtime = try leb.readULEB128(u64, in);
1289 const size = try leb.readULEB128(u64, in);
10631290 try file_entries.append(FileEntry{
1064 .file_name = file_name,
1291 .path = path,
10651292 .dir_index = dir_index,
10661293 .mtime = mtime,
1067 .len_bytes = len_bytes,
1294 .size = size,
10681295 });
10691296 },
10701297 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();
10721299 try seekable.seekBy(fwd_amt);
10731300 },
10741301 }
......@@ -1119,7 +1346,7 @@ pub const DwarfInfo = struct {
11191346 },
11201347 LNS.set_prologue_end => {},
11211348 else => {
1122 if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
1349 if (opcode - 1 >= standard_opcode_lengths.len) return badDwarf();
11231350 const len_bytes = standard_opcode_lengths[opcode - 1];
11241351 try seekable.seekBy(len_bytes);
11251352 },
......@@ -1127,36 +1354,15 @@ pub const DwarfInfo = struct {
11271354 }
11281355 }
11291356
1130 return error.MissingDebugInfo;
1357 return missingDwarf();
11311358 }
11321359
1133 fn getString(di: *DwarfInfo, offset: u64) ![]const u8 {
1134 if (offset > di.debug_str.len)
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;
1360 fn getString(di: DwarfInfo, offset: u64) ![]const u8 {
1361 return getStringGeneric(di.debug_str, offset);
11451362 }
11461363
1147 fn getLineString(di: *DwarfInfo, offset: u64) ![]const u8 {
1148 const debug_line_str = di.debug_line_str orelse return error.InvalidDebugInfo;
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;
1364 fn getLineString(di: DwarfInfo, offset: u64) ![]const u8 {
1365 return getStringGeneric(di.debug_line_str, offset);
11601366 }
11611367};
11621368
......@@ -1166,3 +1372,24 @@ pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: mem.Allocator) !void {
11661372 try di.scanAllFunctions(allocator);
11671373 try di.scanAllCompileUnits(allocator);
11681374}
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;
33const os = std.os;
44const math = std.math;
55const mem = std.mem;
6const debug = std.debug;
6const assert = std.debug.assert;
77const File = std.fs.File;
88const native_endian = @import("builtin").target.cpu.arch.endian();
99
......@@ -387,7 +387,7 @@ pub const Header = struct {
387387
388388 const machine = if (need_bswap) blk: {
389389 const value = @enumToInt(hdr32.e_machine);
390 break :blk @intToEnum(EM, @byteSwap(@TypeOf(value), value));
390 break :blk @intToEnum(EM, @byteSwap(value));
391391 } else hdr32.e_machine;
392392
393393 return @as(Header, .{
......@@ -406,7 +406,7 @@ pub const Header = struct {
406406 }
407407};
408408
409pub fn ProgramHeaderIterator(ParseSource: anytype) type {
409pub fn ProgramHeaderIterator(comptime ParseSource: anytype) type {
410410 return struct {
411411 elf_header: Header,
412412 parse_source: ParseSource,
......@@ -456,7 +456,7 @@ pub fn ProgramHeaderIterator(ParseSource: anytype) type {
456456 };
457457}
458458
459pub fn SectionHeaderIterator(ParseSource: anytype) type {
459pub fn SectionHeaderIterator(comptime ParseSource: anytype) type {
460460 return struct {
461461 elf_header: Header,
462462 parse_source: ParseSource,
......@@ -511,7 +511,7 @@ pub fn SectionHeaderIterator(ParseSource: anytype) type {
511511pub fn int(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @TypeOf(int_64) {
512512 if (is_64) {
513513 if (need_bswap) {
514 return @byteSwap(@TypeOf(int_64), int_64);
514 return @byteSwap(int_64);
515515 } else {
516516 return int_64;
517517 }
......@@ -522,7 +522,7 @@ pub fn int(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @Typ
522522
523523pub fn int32(need_bswap: bool, int_32: anytype, comptime Int64: anytype) Int64 {
524524 if (need_bswap) {
525 return @byteSwap(@TypeOf(int_32), int_32);
525 return @byteSwap(int_32);
526526 } else {
527527 return int_32;
528528 }
......@@ -872,14 +872,14 @@ pub const Elf_MIPS_ABIFlags_v0 = extern struct {
872872};
873873
874874comptime {
875 debug.assert(@sizeOf(Elf32_Ehdr) == 52);
876 debug.assert(@sizeOf(Elf64_Ehdr) == 64);
875 assert(@sizeOf(Elf32_Ehdr) == 52);
876 assert(@sizeOf(Elf64_Ehdr) == 64);
877877
878 debug.assert(@sizeOf(Elf32_Phdr) == 32);
879 debug.assert(@sizeOf(Elf64_Phdr) == 56);
878 assert(@sizeOf(Elf32_Phdr) == 32);
879 assert(@sizeOf(Elf64_Phdr) == 56);
880880
881 debug.assert(@sizeOf(Elf32_Shdr) == 40);
882 debug.assert(@sizeOf(Elf64_Shdr) == 64);
881 assert(@sizeOf(Elf32_Shdr) == 40);
882 assert(@sizeOf(Elf64_Shdr) == 64);
883883}
884884
885885pub const Auxv = switch (@sizeOf(usize)) {
lib/std/enums.zig+1-1
......@@ -57,7 +57,7 @@ pub fn values(comptime E: type) []const E {
5757/// the total number of items which have no matching enum key (holes in the enum
5858/// numbering). So for example, if an enum has values 1, 2, 5, and 6, max_unused_slots
5959/// 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 {
6161 var max_value: comptime_int = -1;
6262 const max_usize: comptime_int = ~@as(usize, 0);
6363 const fields = std.meta.fields(E);
lib/std/event/channel.zig+1-1
......@@ -56,7 +56,7 @@ pub fn Channel(comptime T: type) type {
5656 pub fn init(self: *SelfChannel, buffer: []T) void {
5757 // The ring buffer implementation only works with power of 2 buffer sizes
5858 // 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
6161 self.* = SelfChannel{
6262 .buffer_len = 0,
lib/std/fmt.zig+2-2
......@@ -195,7 +195,7 @@ pub fn format(
195195 }
196196
197197 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);
199199 switch (missing_count) {
200200 0 => unreachable,
201201 1 => @compileError("unused argument in '" ++ fmt ++ "'"),
......@@ -380,7 +380,7 @@ const ArgState = struct {
380380 args_len: usize,
381381
382382 fn hasUnusedArgs(self: *@This()) bool {
383 return @popCount(ArgSetType, self.used_args) != self.args_len;
383 return @popCount(self.used_args) != self.args_len;
384384 }
385385
386386 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) {
3636 }
3737
3838 // 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));
4040 w = math.shl(u64, w, lz);
4141
4242 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 {
877877 /// a reference to the path.
878878 pub fn next(self: *Walker) !?WalkerEntry {
879879 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`
881881 var top = &self.stack.items[self.stack.items.len - 1];
882 var containing = top;
882883 var dirname_len = top.dirname_len;
883884 if (try top.iter.next()) |base| {
884885 self.name_buffer.shrinkRetainingCapacity(dirname_len);
......@@ -899,10 +900,11 @@ pub const IterableDir = struct {
899900 .dirname_len = self.name_buffer.items.len,
900901 });
901902 top = &self.stack.items[self.stack.items.len - 1];
903 containing = &self.stack.items[self.stack.items.len - 2];
902904 }
903905 }
904906 return WalkerEntry{
905 .dir = top.iter.dir,
907 .dir = containing.iter.dir,
906908 .basename = self.name_buffer.items[dirname_len..],
907909 .path = self.name_buffer.items,
908910 .kind = base.kind,
lib/std/fs/path.zig+1-1
......@@ -42,7 +42,7 @@ pub fn isSep(byte: u8) bool {
4242
4343/// This is different from mem.join in that the separator will not be repeated if
4444/// 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 {
4646 if (paths.len == 0) return if (zero) try allocator.dupe(u8, &[1]u8{0}) else &[0]u8{};
4747
4848 // Find first non-empty path index.
lib/std/fs/test.zig+3
......@@ -1058,6 +1058,9 @@ test "walker" {
10581058 std.debug.print("found unexpected path: {s}\n", .{std.fmt.fmtSliceEscapeLower(entry.path)});
10591059 return err;
10601060 };
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();
10611064 num_walked += 1;
10621065 }
10631066 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)
3030 .DeepRecursive => hash(hasher, key.*, .DeepRecursive),
3131 },
3232
33 .Slice => switch (strat) {
34 .Shallow => {
35 hashPointer(hasher, key.ptr, .Shallow);
36 hash(hasher, key.len, .Shallow);
37 },
38 .Deep => hashArray(hasher, key, .Shallow),
39 .DeepRecursive => hashArray(hasher, key, .DeepRecursive),
33 .Slice => {
34 switch (strat) {
35 .Shallow => {
36 hashPointer(hasher, key.ptr, .Shallow);
37 },
38 .Deep => hashArray(hasher, key, .Shallow),
39 .DeepRecursive => hashArray(hasher, key, .DeepRecursive),
40 }
41 hash(hasher, key.len, .Shallow);
4042 },
4143
4244 .Many,
......@@ -53,17 +55,8 @@ pub fn hashPointer(hasher: anytype, key: anytype, comptime strat: HashStrategy)
5355
5456/// Helper function to hash a set of contiguous objects, from an array or slice.
5557pub fn hashArray(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {
56 switch (strat) {
57 .Shallow => {
58 for (key) |element| {
59 hash(hasher, element, .Shallow);
60 }
61 },
62 else => {
63 for (key) |element| {
64 hash(hasher, element, strat);
65 }
66 },
58 for (key) |element| {
59 hash(hasher, element, strat);
6760 }
6861}
6962
......@@ -193,8 +186,8 @@ fn typeContainsSlice(comptime K: type) bool {
193186pub fn autoHash(hasher: anytype, key: anytype) void {
194187 const Key = @TypeOf(key);
195188 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) ++
197 ") because the intent is unclear. Consider using std.auto_hash.hash or providing your own hash function instead.");
189 @compileError("std.hash.autoHash does not allow slices as well as unions and structs containing slices here (" ++ @typeName(Key) ++
190 ") because the intent is unclear. Consider using std.hash.autoHashStrat or providing your own hash function instead.");
198191 }
199192
200193 hash(hasher, key, .Shallow);
......@@ -359,6 +352,12 @@ test "testHash array" {
359352 try testing.expectEqual(h, hasher.final());
360353}
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
362361test "testHash struct" {
363362 const Foo = struct {
364363 a: u32 = 1,
lib/std/hash/cityhash.zig+5-5
......@@ -143,9 +143,9 @@ pub const CityHash32 = struct {
143143 h = rotr32(h, 19);
144144 h = h *% 5 +% 0xe6546b64;
145145 g ^= b4;
146 g = @byteSwap(u32, g) *% 5;
146 g = @byteSwap(g) *% 5;
147147 h +%= b4 *% 5;
148 h = @byteSwap(u32, h);
148 h = @byteSwap(h);
149149 f +%= b0;
150150 const t: u32 = h;
151151 h = f;
......@@ -252,11 +252,11 @@ pub const CityHash64 = struct {
252252
253253 const u: u64 = rotr64(a +% g, 43) +% (rotr64(b, 30) +% c) *% 9;
254254 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;
256256 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;
258258 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;
260260 const b1: u64 = shiftmix((z +% a1) *% mul +% d +% h) *% mul;
261261 return b1 +% x;
262262 }
lib/std/hash/murmur.zig+11-11
......@@ -19,7 +19,7 @@ pub const Murmur2_32 = struct {
1919 for (@ptrCast([*]align(1) const u32, str.ptr)[0..(len >> 2)]) |v| {
2020 var k1: u32 = v;
2121 if (native_endian == .Big)
22 k1 = @byteSwap(u32, k1);
22 k1 = @byteSwap(k1);
2323 k1 *%= m;
2424 k1 ^= k1 >> 24;
2525 k1 *%= m;
......@@ -104,7 +104,7 @@ pub const Murmur2_64 = struct {
104104 for (@ptrCast([*]align(1) const u64, str.ptr)[0..@intCast(usize, len >> 3)]) |v| {
105105 var k1: u64 = v;
106106 if (native_endian == .Big)
107 k1 = @byteSwap(u64, k1);
107 k1 = @byteSwap(k1);
108108 k1 *%= m;
109109 k1 ^= k1 >> 47;
110110 k1 *%= m;
......@@ -117,7 +117,7 @@ pub const Murmur2_64 = struct {
117117 var k1: u64 = 0;
118118 @memcpy(@ptrCast([*]u8, &k1), @ptrCast([*]const u8, &str[@intCast(usize, offset)]), @intCast(usize, rest));
119119 if (native_endian == .Big)
120 k1 = @byteSwap(u64, k1);
120 k1 = @byteSwap(k1);
121121 h1 ^= k1;
122122 h1 *%= m;
123123 }
......@@ -184,7 +184,7 @@ pub const Murmur3_32 = struct {
184184 for (@ptrCast([*]align(1) const u32, str.ptr)[0..(len >> 2)]) |v| {
185185 var k1: u32 = v;
186186 if (native_endian == .Big)
187 k1 = @byteSwap(u32, k1);
187 k1 = @byteSwap(k1);
188188 k1 *%= c1;
189189 k1 = rotl32(k1, 15);
190190 k1 *%= c2;
......@@ -296,7 +296,7 @@ fn SMHasherTest(comptime hash_fn: anytype, comptime hashbits: u32) u32 {
296296
297297 var h = hash_fn(key[0..i], 256 - i);
298298 if (native_endian == .Big)
299 h = @byteSwap(@TypeOf(h), h);
299 h = @byteSwap(h);
300300 @memcpy(@ptrCast([*]u8, &hashes[i * hashbytes]), @ptrCast([*]u8, &h), hashbytes);
301301 }
302302
......@@ -310,8 +310,8 @@ test "murmur2_32" {
310310 var v0le: u32 = v0;
311311 var v1le: u64 = v1;
312312 if (native_endian == .Big) {
313 v0le = @byteSwap(u32, v0le);
314 v1le = @byteSwap(u64, v1le);
313 v0le = @byteSwap(v0le);
314 v1le = @byteSwap(v1le);
315315 }
316316 try testing.expectEqual(Murmur2_32.hash(@ptrCast([*]u8, &v0le)[0..4]), Murmur2_32.hashUint32(v0));
317317 try testing.expectEqual(Murmur2_32.hash(@ptrCast([*]u8, &v1le)[0..8]), Murmur2_32.hashUint64(v1));
......@@ -324,8 +324,8 @@ test "murmur2_64" {
324324 var v0le: u32 = v0;
325325 var v1le: u64 = v1;
326326 if (native_endian == .Big) {
327 v0le = @byteSwap(u32, v0le);
328 v1le = @byteSwap(u64, v1le);
327 v0le = @byteSwap(v0le);
328 v1le = @byteSwap(v1le);
329329 }
330330 try testing.expectEqual(Murmur2_64.hash(@ptrCast([*]u8, &v0le)[0..4]), Murmur2_64.hashUint32(v0));
331331 try testing.expectEqual(Murmur2_64.hash(@ptrCast([*]u8, &v1le)[0..8]), Murmur2_64.hashUint64(v1));
......@@ -338,8 +338,8 @@ test "murmur3_32" {
338338 var v0le: u32 = v0;
339339 var v1le: u64 = v1;
340340 if (native_endian == .Big) {
341 v0le = @byteSwap(u32, v0le);
342 v1le = @byteSwap(u64, v1le);
341 v0le = @byteSwap(v0le);
342 v1le = @byteSwap(v1le);
343343 }
344344 try testing.expectEqual(Murmur3_32.hash(@ptrCast([*]u8, &v0le)[0..4]), Murmur3_32.hashUint32(v0));
345345 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 {
479479 @setCold(true);
480480 for (self.data) |segment, i| {
481481 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
484484 if (!spills_into_next and !has_enough_bits) continue;
485485
......@@ -1185,7 +1185,7 @@ pub fn testAllocatorLargeAlignment(base_allocator: mem.Allocator) !void {
11851185 const large_align = @as(u29, mem.page_size << 2);
11861186
11871187 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
11901190 var slice = try allocator.alignedAlloc(u8, large_align, 500);
11911191 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;
77const math = std.math;
88
99/// 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 {
1111 return struct {
1212 forward_reader: ReaderType,
1313 bit_buffer: u7,
lib/std/io/bit_writer.zig+1-1
......@@ -7,7 +7,7 @@ const meta = std.meta;
77const math = std.math;
88
99/// 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 {
1111 return struct {
1212 forward_writer: WriterType,
1313 bit_buffer: u8,
lib/std/io/reader.zig+21
......@@ -247,6 +247,27 @@ pub fn Reader(
247247 return bytes;
248248 }
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
250271 /// Reads a native-endian integer
251272 pub fn readIntNative(self: Self, comptime T: type) !T {
252273 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 {
317317 const bytes_needed = bn: {
318318 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);
321321 const used_bits: u16 = (@typeInfo(T).Int.bits - unused_bits) + @boolToInt(t_signed);
322322 if (used_bits <= 7) break :bn @as(u16, 1);
323323 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(
11461146 assert(value != 0);
11471147 const PromotedType = std.meta.Int(@typeInfo(T).Int.signedness, @typeInfo(T).Int.bits + 1);
11481148 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));
11501150}
11511151
11521152/// 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) {
12121212 if (@typeInfo(T) != .Int or @typeInfo(T).Int.signedness != .unsigned)
12131213 @compileError("log2_int requires an unsigned integer, found " ++ @typeName(T));
12141214 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));
12161216}
12171217
12181218/// Return the log base 2 of integer value x, rounding up to the
......@@ -1548,7 +1548,7 @@ test "boolMask" {
15481548}
15491549
15501550/// 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) {
15521552 return @intCast(IntFittingRange(0, denom - 1), @mod(num, denom));
15531553}
15541554
lib/std/math/big/int.zig+7-7
......@@ -887,7 +887,7 @@ pub const Mutable = struct {
887887
888888 var sum: Limb = 0;
889889 for (r.limbs[0..r.len]) |limb| {
890 sum += @popCount(Limb, limb);
890 sum += @popCount(limb);
891891 }
892892 r.set(sum);
893893 }
......@@ -1520,7 +1520,7 @@ pub const Mutable = struct {
15201520 ) void {
15211521 // 0.
15221522 // 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]);
15241524 const norm_shift = if (lz == 0 and y.toConst().isOdd())
15251525 limb_bits // Force an extra limb so that y is even.
15261526 else
......@@ -1917,7 +1917,7 @@ pub const Const = struct {
19171917
19181918 /// Returns the number of bits required to represent the absolute value of an integer.
19191919 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]));
19211921 }
19221922
19231923 /// Returns the number of bits required to represent the integer in twos-complement form.
......@@ -1936,9 +1936,9 @@ pub const Const = struct {
19361936 if (!self.positive) block: {
19371937 bits += 1;
19381938
1939 if (@popCount(Limb, self.limbs[self.limbs.len - 1]) == 1) {
1939 if (@popCount(self.limbs[self.limbs.len - 1]) == 1) {
19401940 for (self.limbs[0 .. self.limbs.len - 1]) |limb| {
1941 if (@popCount(Limb, limb) != 0) {
1941 if (@popCount(limb) != 0) {
19421942 break :block;
19431943 }
19441944 }
......@@ -3895,8 +3895,8 @@ fn llpow(r: []Limb, a: []const Limb, b: u32, tmp_limbs: []Limb) void {
38953895 // The initial assignment makes the result end in `r` so an extra memory
38963896 // copy is saved, each 1 flips the index twice so it's only the zeros that
38973897 // matter.
3898 const b_leading_zeros = @clz(u32, b);
3899 const exp_zeros = @popCount(u32, ~b) - b_leading_zeros;
3898 const b_leading_zeros = @clz(b);
3899 const exp_zeros = @popCount(~b) - b_leading_zeros;
39003900 if (exp_zeros & 1 != 0) {
39013901 tmp1 = tmp_limbs;
39023902 tmp2 = r;
lib/std/math/float.zig+1-1
......@@ -8,7 +8,7 @@ inline fn mantissaOne(comptime T: type) comptime_int {
88}
99
1010/// 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 {
1212 const TBits = @Type(.{ .Int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } });
1313 const biased_exponent = @as(TBits, exponent + floatExponentMax(T));
1414 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 {
267267 return null;
268268 },
269269 .Struct => |struct_info| {
270 if (@sizeOf(T) == 0) return T{};
270 if (@sizeOf(T) == 0) return undefined;
271271 if (struct_info.layout == .Extern) {
272272 var item: T = undefined;
273273 set(u8, asBytes(&item), 0);
......@@ -424,6 +424,9 @@ test "zeroes" {
424424
425425 comptime var comptime_union = zeroes(C_union);
426426 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 });
427430}
428431
429432/// 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
13161319/// This function cannot fail and cannot cause undefined behavior.
13171320/// Assumes the endianness of memory is foreign, so it must byte-swap.
13181321pub 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));
13201323}
13211324
13221325pub const readIntLittle = switch (native_endian) {
......@@ -1345,7 +1348,7 @@ pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T {
13451348/// The bit count of T must be evenly divisible by 8.
13461349/// Assumes the endianness of memory is foreign, so it must byte-swap.
13471350pub fn readIntSliceForeign(comptime T: type, bytes: []const u8) T {
1348 return @byteSwap(T, readIntSliceNative(T, bytes));
1351 return @byteSwap(readIntSliceNative(T, bytes));
13491352}
13501353
13511354pub const readIntSliceLittle = switch (native_endian) {
......@@ -1427,7 +1430,7 @@ pub fn writeIntNative(comptime T: type, buf: *[(@typeInfo(T).Int.bits + 7) / 8]u
14271430/// the integer bit width must be divisible by 8.
14281431/// This function stores in foreign endian, which means it does a @byteSwap first.
14291432pub 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));
14311434}
14321435
14331436pub const writeIntLittle = switch (native_endian) {
......@@ -1572,7 +1575,7 @@ pub const bswapAllFields = @compileError("bswapAllFields has been renamed to byt
15721575pub fn byteSwapAllFields(comptime S: type, ptr: *S) void {
15731576 if (@typeInfo(S) != .Struct) @compileError("byteSwapAllFields expects a struct as the first argument");
15741577 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));
15761579 }
15771580}
15781581
......@@ -2749,14 +2752,14 @@ test "replaceOwned" {
27492752pub fn littleToNative(comptime T: type, x: T) T {
27502753 return switch (native_endian) {
27512754 .Little => x,
2752 .Big => @byteSwap(T, x),
2755 .Big => @byteSwap(x),
27532756 };
27542757}
27552758
27562759/// Converts a big-endian integer to host endianness.
27572760pub fn bigToNative(comptime T: type, x: T) T {
27582761 return switch (native_endian) {
2759 .Little => @byteSwap(T, x),
2762 .Little => @byteSwap(x),
27602763 .Big => x,
27612764 };
27622765}
......@@ -2781,14 +2784,14 @@ pub fn nativeTo(comptime T: type, x: T, desired_endianness: Endian) T {
27812784pub fn nativeToLittle(comptime T: type, x: T) T {
27822785 return switch (native_endian) {
27832786 .Little => x,
2784 .Big => @byteSwap(T, x),
2787 .Big => @byteSwap(x),
27852788 };
27862789}
27872790
27882791/// Converts an integer which has host endianness to big endian.
27892792pub fn nativeToBig(comptime T: type, x: T) T {
27902793 return switch (native_endian) {
2791 .Little => @byteSwap(T, x),
2794 .Little => @byteSwap(x),
27922795 .Big => x,
27932796 };
27942797}
......@@ -2800,7 +2803,7 @@ pub fn nativeToBig(comptime T: type, x: T) T {
28002803/// - The delta required to align the pointer is not a multiple of the pointee's
28012804/// type.
28022805pub 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
28052808 const T = @TypeOf(ptr);
28062809 const info = @typeInfo(T);
......@@ -3249,13 +3252,13 @@ test "sliceAsBytes preserves pointer attributes" {
32493252 try testing.expectEqual(in.alignment, out.alignment);
32503253}
32513254
3252/// Round an address up to the nearest aligned address
3255/// Round an address up to the next (or current) aligned address.
32533256/// The alignment must be a power of 2 and greater than 0.
32543257pub fn alignForward(addr: usize, alignment: usize) usize {
32553258 return alignForwardGeneric(usize, addr, alignment);
32563259}
32573260
3258/// Round an address up to the nearest aligned address
3261/// Round an address up to the next (or current) aligned address.
32593262/// The alignment must be a power of 2 and greater than 0.
32603263pub fn alignForwardGeneric(comptime T: type, addr: T, alignment: T) T {
32613264 return alignBackwardGeneric(T, addr + (alignment - 1), alignment);
......@@ -3287,25 +3290,25 @@ test "alignForward" {
32873290 try testing.expect(alignForward(17, 8) == 24);
32883291}
32893292
3290/// Round an address up to the previous aligned address
3293/// Round an address down to the previous (or current) aligned address.
32913294/// Unlike `alignBackward`, `alignment` can be any positive number, not just a power of 2.
32923295pub fn alignBackwardAnyAlign(i: usize, alignment: usize) usize {
3293 if (@popCount(usize, alignment) == 1)
3296 if (@popCount(alignment) == 1)
32943297 return alignBackward(i, alignment);
32953298 assert(alignment != 0);
32963299 return i - @mod(i, alignment);
32973300}
32983301
3299/// Round an address up to the previous aligned address
3302/// Round an address down to the previous (or current) aligned address.
33003303/// The alignment must be a power of 2 and greater than 0.
33013304pub fn alignBackward(addr: usize, alignment: usize) usize {
33023305 return alignBackwardGeneric(usize, addr, alignment);
33033306}
33043307
3305/// Round an address up to the previous aligned address
3308/// Round an address down to the previous (or current) aligned address.
33063309/// The alignment must be a power of 2 and greater than 0.
33073310pub fn alignBackwardGeneric(comptime T: type, addr: T, alignment: T) T {
3308 assert(@popCount(T, alignment) == 1);
3311 assert(@popCount(alignment) == 1);
33093312 // 000010000 // example alignment
33103313 // 000001111 // subtract 1
33113314 // 111110000 // binary not
......@@ -3315,11 +3318,11 @@ pub fn alignBackwardGeneric(comptime T: type, addr: T, alignment: T) T {
33153318/// Returns whether `alignment` is a valid alignment, meaning it is
33163319/// a positive power of 2.
33173320pub fn isValidAlign(alignment: u29) bool {
3318 return @popCount(u29, alignment) == 1;
3321 return @popCount(alignment) == 1;
33193322}
33203323
33213324pub fn isAlignedAnyAlign(i: usize, alignment: usize) bool {
3322 if (@popCount(usize, alignment) == 1)
3325 if (@popCount(alignment) == 1)
33233326 return isAligned(i, alignment);
33243327 assert(alignment != 0);
33253328 return 0 == @mod(i, alignment);
lib/std/meta.zig+58-19
......@@ -764,7 +764,7 @@ const TagPayloadType = TagPayload;
764764
765765///Given a tagged union type, and an enum, return the type of the union
766766/// 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 {
768768 comptime debug.assert(trait.is(.Union)(U));
769769
770770 const info = @typeInfo(U).Union;
......@@ -1024,28 +1024,13 @@ pub fn ArgsTuple(comptime Function: type) type {
10241024 if (function_info.is_var_args)
10251025 @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;
10281028 inline for (function_info.args) |arg, i| {
10291029 const T = arg.arg_type.?;
1030 @setEvalBranchQuota(10_000);
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 };
1030 argument_field_list[i] = T;
10391031 }
10401032
1041 return @Type(.{
1042 .Struct = .{
1043 .is_tuple = true,
1044 .layout = .Auto,
1045 .decls = &.{},
1046 .fields = &argument_field_list,
1047 },
1048 });
1033 return CreateUniqueTuple(argument_field_list.len, argument_field_list);
10491034}
10501035
10511036/// For a given anonymous list of types, returns a new tuple type
......@@ -1056,6 +1041,10 @@ pub fn ArgsTuple(comptime Function: type) type {
10561041/// - `Tuple(&[_]type {f32})` ⇒ `tuple { f32 }`
10571042/// - `Tuple(&[_]type {f32,u32})` ⇒ `tuple { f32, u32 }`
10581043pub 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 {
10591048 var tuple_fields: [types.len]std.builtin.Type.StructField = undefined;
10601049 inline for (types) |T, i| {
10611050 @setEvalBranchQuota(10_000);
......@@ -1118,6 +1107,32 @@ test "Tuple" {
11181107 TupleTester.assertTuple(.{ u32, f16, []const u8, void }, Tuple(&[_]type{ u32, f16, []const u8, void }));
11191108}
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
11211136/// TODO: https://github.com/ziglang/zig/issues/425
11221137pub fn globalOption(comptime name: []const u8, comptime T: type) ?T {
11231138 if (!@hasDecl(root, name))
......@@ -1134,3 +1149,27 @@ test "isError" {
11341149 try std.testing.expect(isError(math.absInt(@as(i8, -128))));
11351150 try std.testing.expect(!isError(math.absInt(@as(i8, -127))));
11361151}
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 {
459459 return self.bytes[0..capacityInBytes(self.capacity)];
460460 }
461461
462 fn FieldType(field: Field) type {
462 fn FieldType(comptime field: Field) type {
463463 return meta.fieldInfo(S, field).field_type;
464464 }
465465
lib/std/os.zig+11-11
......@@ -475,10 +475,9 @@ pub fn abort() noreturn {
475475
476476 // Install default handler so that the tkill below will terminate.
477477 const sigact = Sigaction{
478 .handler = .{ .sigaction = SIG.DFL },
479 .mask = undefined,
480 .flags = undefined,
481 .restorer = undefined,
478 .handler = .{ .handler = SIG.DFL },
479 .mask = empty_sigset,
480 .flags = 0,
482481 };
483482 sigaction(SIG.ABRT, &sigact, null) catch |err| switch (err) {
484483 error.OperationNotSupported => unreachable,
......@@ -953,6 +952,10 @@ pub const WriteError = error{
953952 OperationAborted,
954953 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
956959 /// This error occurs when no global event loop is configured,
957960 /// and reading from the file descriptor would block.
958961 WouldBlock,
......@@ -2648,6 +2651,7 @@ pub fn renameatW(
26482651 .creation = windows.FILE_OPEN,
26492652 .io_mode = .blocking,
26502653 .filter = .any, // This function is supposed to rename both files and directories.
2654 .follow_symlinks = false,
26512655 }) catch |err| switch (err) {
26522656 error.WouldBlock => unreachable, // Not possible without `.share_access_nonblocking = true`.
26532657 else => |e| return e,
......@@ -5443,11 +5447,7 @@ pub fn toPosixPath(file_path: []const u8) ![MAX_PATH_BYTES - 1:0]u8 {
54435447/// if this happens the fix is to add the error code to the corresponding
54445448/// switch expression, possibly introduce a new error in the error set, and
54455449/// send a patch to Zig.
5446/// The self-hosted compiler is not fully capable of handle the related code.
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;
5450pub const unexpected_error_tracing = (builtin.zig_backend == .stage1 or builtin.zig_backend == .stage2_llvm) and builtin.mode == .Debug;
54515451
54525452pub const UnexpectedError = error{
54535453 /// The Operating System returned an undocumented error code.
......@@ -6251,7 +6251,7 @@ pub const CopyFileRangeError = error{
62516251 NoSpaceLeft,
62526252 Unseekable,
62536253 PermissionDenied,
6254 FileBusy,
6254 SwapFile,
62556255} || PReadError || PWriteError || UnexpectedError;
62566256
62576257var 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
63056305 .NOSPC => return error.NoSpaceLeft,
63066306 .OVERFLOW => return error.Unseekable,
63076307 .PERM => return error.PermissionDenied,
6308 .TXTBSY => return error.FileBusy,
6308 .TXTBSY => return error.SwapFile,
63096309 // these may not be regular files, try fallback
63106310 .INVAL => {},
63116311 // 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 {
19451945 pub const SYS = 31;
19461946 pub const UNUSED = SIG.SYS;
19471947
1948 pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));
1949 pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0);
1950 pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1);
1948 pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
1949 pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
1950 pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
19511951} else if (is_sparc) struct {
19521952 pub const BLOCK = 1;
19531953 pub const UNBLOCK = 2;
......@@ -1989,9 +1989,9 @@ pub const SIG = if (is_mips) struct {
19891989 pub const PWR = LOST;
19901990 pub const IO = SIG.POLL;
19911991
1992 pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));
1993 pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0);
1994 pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1);
1992 pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
1993 pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
1994 pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
19951995} else struct {
19961996 pub const BLOCK = 0;
19971997 pub const UNBLOCK = 1;
......@@ -2032,9 +2032,9 @@ pub const SIG = if (is_mips) struct {
20322032 pub const SYS = 31;
20332033 pub const UNUSED = SIG.SYS;
20342034
2035 pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize));
2036 pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0);
2037 pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1);
2035 pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
2036 pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
2037 pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
20382038};
20392039
20402040pub const kernel_rwf = u32;
......@@ -3377,7 +3377,7 @@ pub const cpu_count_t = std.meta.Int(.unsigned, std.math.log2(CPU_SETSIZE * 8));
33773377pub fn CPU_COUNT(set: cpu_set_t) cpu_count_t {
33783378 var sum: cpu_count_t = 0;
33793379 for (set) |x| {
3380 sum += @popCount(usize, x);
3380 sum += @popCount(x);
33813381 }
33823382 return sum;
33833383}
lib/std/os/linux/bpf.zig+1-1
......@@ -458,7 +458,7 @@ pub const Insn = packed struct {
458458 else
459459 ImmOrReg{ .imm = src };
460460
461 const src_type = switch (imm_or_reg) {
461 const src_type: u8 = switch (imm_or_reg) {
462462 .imm => K,
463463 .reg => X,
464464 };
lib/std/os/linux/syscalls.zig+1
......@@ -3485,6 +3485,7 @@ pub const RiscV64 = enum(usize) {
34853485 landlock_create_ruleset = 444,
34863486 landlock_add_rule = 445,
34873487 landlock_restrict_self = 446,
3488 memfd_secret = 447,
34883489 process_mrelease = 448,
34893490 futex_waitv = 449,
34903491 set_mempolicy_home_node = 450,
lib/std/os/plan9.zig+1-1
......@@ -1,7 +1,7 @@
11const std = @import("../std.zig");
22const builtin = @import("builtin");
33
4pub const syscall_bits = switch (builtin.stage2_arch) {
4pub const syscall_bits = switch (builtin.cpu.arch) {
55 .x86_64 => @import("plan9/x86_64.zig"),
66 else => @compileError("more plan9 syscall implementations (needs more inline asm in stage2"),
77};
lib/std/os/test.zig+1-1
......@@ -785,7 +785,7 @@ test "sigaction" {
785785 try testing.expect(signal_test_failed == false);
786786 // Check if the handler has been correctly reset to SIG_DFL
787787 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);
789789}
790790
791791test "dup & dup2" {
lib/std/os/uefi.zig+3-3
......@@ -55,9 +55,9 @@ pub const Guid = extern struct {
5555 if (f.len == 0) {
5656 const fmt = std.fmt.fmtSliceHexLower;
5757
58 const time_low = @byteSwap(u32, self.time_low);
59 const time_mid = @byteSwap(u16, self.time_mid);
60 const time_high_and_version = @byteSwap(u16, self.time_high_and_version);
58 const time_low = @byteSwap(self.time_low);
59 const time_mid = @byteSwap(self.time_mid);
60 const time_high_and_version = @byteSwap(self.time_high_and_version);
6161
6262 return std.fmt.format(writer, "{:0>8}-{:0>4}-{:0>4}-{:0>2}{:0>2}-{:0>12}", .{
6363 fmt(std.mem.asBytes(&time_low)),
lib/std/os/windows.zig+5-1
......@@ -517,6 +517,9 @@ pub const WriteFileError = error{
517517 OperationAborted,
518518 BrokenPipe,
519519 NotOpenForWriting,
520 /// The process cannot access the file because another process has locked
521 /// a portion of the file.
522 LockViolation,
520523 Unexpected,
521524};
522525
......@@ -597,6 +600,7 @@ pub fn WriteFile(
597600 .IO_PENDING => unreachable,
598601 .BROKEN_PIPE => return error.BrokenPipe,
599602 .INVALID_HANDLE => return error.NotOpenForWriting,
603 .LOCK_VIOLATION => return error.LockViolation,
600604 else => |err| return unexpectedError(err),
601605 }
602606 }
......@@ -1798,7 +1802,7 @@ pub const PathSpace = struct {
17981802 data: [PATH_MAX_WIDE:0]u16,
17991803 len: usize,
18001804
1801 pub fn span(self: PathSpace) [:0]const u16 {
1805 pub fn span(self: *const PathSpace) [:0]const u16 {
18021806 return self.data[0..self.len :0];
18031807 }
18041808};
lib/std/packed_int_array.zig+3-3
......@@ -76,7 +76,7 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type {
7676 const value_ptr = @ptrCast(*align(1) const Container, &bytes[start_byte]);
7777 var value = value_ptr.*;
7878
79 if (endian != native_endian) value = @byteSwap(Container, value);
79 if (endian != native_endian) value = @byteSwap(value);
8080
8181 switch (endian) {
8282 .Big => {
......@@ -126,7 +126,7 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: Endian) type {
126126 const target_ptr = @ptrCast(*align(1) Container, &bytes[start_byte]);
127127 var target = target_ptr.*;
128128
129 if (endian != native_endian) target = @byteSwap(Container, target);
129 if (endian != native_endian) target = @byteSwap(target);
130130
131131 //zero the bits we want to replace in the existing bytes
132132 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 {
136136 //merge the new value
137137 target |= value;
138138
139 if (endian != native_endian) target = @byteSwap(Container, target);
139 if (endian != native_endian) target = @byteSwap(target);
140140
141141 //save it back
142142 target_ptr.* = target;
lib/std/pdb.zig+6-3
......@@ -310,6 +310,10 @@ pub const SymbolKind = enum(u16) {
310310
311311pub 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.
313317pub const ProcSym = extern struct {
314318 Parent: u32,
315319 End: u32,
......@@ -321,8 +325,7 @@ pub const ProcSym = extern struct {
321325 CodeOffset: u32,
322326 Segment: u16,
323327 Flags: ProcSymFlags,
324 // following is a null terminated string
325 // Name: [*]u8,
328 Name: [1]u8, // null-terminated
326329};
327330
328331pub const ProcSymFlags = packed struct {
......@@ -693,7 +696,7 @@ pub const Pdb = struct {
693696 .S_LPROC32, .S_GPROC32 => {
694697 const proc_sym = @ptrCast(*align(1) ProcSym, &module.symbols[symbol_i + @sizeOf(RecordPrefix)]);
695698 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);
697700 }
698701 },
699702 else => {},
lib/std/priority_dequeue.zig+1-1
......@@ -69,7 +69,7 @@ pub fn PriorityDequeue(comptime T: type, comptime Context: type, comptime compar
6969 // The first element is on a min layer;
7070 // next two are on a max layer;
7171 // 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);
7373 const highest_set_bit = @bitSizeOf(usize) - 1 - leading_zeros;
7474 return (highest_set_bit & 1) == 0;
7575 }
lib/std/rand.zig+41-5
......@@ -257,15 +257,15 @@ pub const Random = struct {
257257 // If all 41 bits are zero, generate additional random bits, until a
258258 // set bit is found, or 126 bits have been generated.
259259 const rand = r.int(u64);
260 var rand_lz = @clz(u64, rand);
260 var rand_lz = @clz(rand);
261261 if (rand_lz >= 41) {
262262 // TODO: when #5177 or #489 is implemented,
263263 // tell the compiler it is unlikely (1/2^41) to reach this point.
264264 // (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));
266266 if (rand_lz == 41 + 64) {
267267 // 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);
269269 }
270270 }
271271 const mantissa = @truncate(u23, rand);
......@@ -277,12 +277,12 @@ pub const Random = struct {
277277 // If all 12 bits are zero, generate additional random bits, until a
278278 // set bit is found, or 1022 bits have been generated.
279279 const rand = r.int(u64);
280 var rand_lz: u64 = @clz(u64, rand);
280 var rand_lz: u64 = @clz(rand);
281281 if (rand_lz >= 12) {
282282 rand_lz = 12;
283283 while (true) {
284284 // 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));
286286 rand_lz += addl_rand_lz;
287287 if (addl_rand_lz != 64) {
288288 break;
......@@ -337,6 +337,42 @@ pub const Random = struct {
337337 mem.swap(T, &buf[i], &buf[j]);
338338 }
339339 }
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 }
340376};
341377
342378/// Convert a random integer 0 <= random_int <= maxValue(T),
lib/std/rand/test.zig+26
......@@ -445,3 +445,29 @@ test "CSPRNG" {
445445 const c = random.int(u64);
446446 try expect(a ^ b ^ c != 0);
447447}
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 {
131131
132132fn exit2(code: usize) noreturn {
133133 switch (native_os) {
134 .linux => switch (builtin.stage2_arch) {
134 .linux => switch (builtin.cpu.arch) {
135135 .x86_64 => {
136136 asm volatile ("syscall"
137137 :
......@@ -175,7 +175,7 @@ fn exit2(code: usize) noreturn {
175175 else => @compileError("TODO"),
176176 },
177177 // exits(0)
178 .plan9 => switch (builtin.stage2_arch) {
178 .plan9 => switch (builtin.cpu.arch) {
179179 .x86_64 => {
180180 asm volatile (
181181 \\push $0
lib/std/target.zig+26-24
......@@ -9,6 +9,7 @@ pub const Target = struct {
99 cpu: Cpu,
1010 os: Os,
1111 abi: Abi,
12 ofmt: ObjectFormat,
1213
1314 pub const Os = struct {
1415 tag: Tag,
......@@ -624,6 +625,20 @@ pub const Target = struct {
624625 .dxcontainer => @panic("TODO what's the extension for these?"),
625626 };
626627 }
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 }
627642 };
628643
629644 pub const SubSystem = enum {
......@@ -1426,24 +1441,6 @@ pub const Target = struct {
14261441 return libPrefix_os_abi(self.os.tag, self.abi);
14271442 }
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
14471444 pub fn isMinGW(self: Target) bool {
14481445 return self.os.tag == .windows and self.isGnu();
14491446 }
......@@ -1801,10 +1798,11 @@ pub const Target = struct {
18011798 else => false,
18021799 },
18031800 f64 => switch (target.cpu.arch) {
1801 .aarch64 => target.isDarwin(),
1802
18041803 .x86_64,
18051804 .i386,
18061805 .riscv64,
1807 .aarch64,
18081806 .aarch64_be,
18091807 .aarch64_32,
18101808 .s390x,
......@@ -1856,24 +1854,28 @@ pub const Target = struct {
18561854 else => 4,
18571855 },
18581856
1859 // For x86_64, LLVMABIAlignmentOfType(i128) reports 8. However I think 16
1860 // is a better number for two reasons:
1861 // 1. Better machine code when loading into SIMD register.
1857 // For these, LLVMABIAlignmentOfType(i128) reports 8. Note that 16
1858 // is a relevant number in three cases:
1859 // 1. Different machine code instruction when loading into SIMD register.
18621860 // 2. The C ABI wants 16 for extern structs.
18631861 // 3. 16-byte cmpxchg needs 16-byte alignment.
1864 // Same logic for riscv64, powerpc64, mips64, sparc64.
1862 // Same logic for powerpc64, mips64, sparc64.
18651863 .x86_64,
1866 .riscv64,
18671864 .powerpc64,
18681865 .powerpc64le,
18691866 .mips64,
18701867 .mips64el,
18711868 .sparc64,
1869 => return switch (target.ofmt) {
1870 .c => 16,
1871 else => 8,
1872 },
18721873
18731874 // Even LLVMABIAlignmentOfType(i128) agrees on these targets.
18741875 .aarch64,
18751876 .aarch64_be,
18761877 .aarch64_32,
1878 .riscv64,
18771879 .bpfel,
18781880 .bpfeb,
18791881 .nvptx,
lib/std/valgrind/callgrind.zig+1-1
......@@ -2,7 +2,7 @@ const std = @import("../std.zig");
22const valgrind = std.valgrind;
33
44pub const CallgrindClientRequest = enum(usize) {
5 DumpStats = valgrind.ToolBase("CT"),
5 DumpStats = valgrind.ToolBase("CT".*),
66 ZeroStats,
77 ToggleCollect,
88 DumpStatsAt,
lib/std/zig.zig+7-5
......@@ -103,7 +103,6 @@ pub const BinNameOptions = struct {
103103 target: std.Target,
104104 output_mode: std.builtin.OutputMode,
105105 link_mode: ?std.builtin.LinkMode = null,
106 object_format: ?std.Target.ObjectFormat = null,
107106 version: ?std.builtin.Version = null,
108107};
109108
......@@ -111,8 +110,7 @@ pub const BinNameOptions = struct {
111110pub fn binNameAlloc(allocator: std.mem.Allocator, options: BinNameOptions) error{OutOfMemory}![]u8 {
112111 const root_name = options.root_name;
113112 const target = options.target;
114 const ofmt = options.object_format orelse target.getObjectFormat();
115 switch (ofmt) {
113 switch (target.ofmt) {
116114 .coff => switch (options.output_mode) {
117115 .Exe => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, target.exeFileExt() }),
118116 .Lib => {
......@@ -186,8 +184,12 @@ pub fn binNameAlloc(allocator: std.mem.Allocator, options: BinNameOptions) error
186184 .raw => return std.fmt.allocPrint(allocator, "{s}.bin", .{root_name}),
187185 .plan9 => switch (options.output_mode) {
188186 .Exe => return allocator.dupe(u8, root_name),
189 .Obj => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, ofmt.fileExt(target.cpu.arch) }),
190 .Lib => return std.fmt.allocPrint(allocator, "{s}{s}.a", .{ target.libPrefix(), root_name }),
187 .Obj => return std.fmt.allocPrint(allocator, "{s}{s}", .{
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 }),
191193 },
192194 .nvptx => return std.fmt.allocPrint(allocator, "{s}", .{root_name}),
193195 .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 {
29672967 /// Same as ContainerDeclTwo except there is known to be a trailing comma
29682968 /// or semicolon before the rbrace.
29692969 container_decl_two_trailing,
2970 /// `union(lhs)` / `enum(lhs)`. `SubRange[rhs]`.
2970 /// `struct(lhs)` / `union(lhs)` / `enum(lhs)`. `SubRange[rhs]`.
29712971 container_decl_arg,
29722972 /// Same as container_decl_arg but there is known to be a trailing
29732973 /// comma or semicolon before the rbrace.
lib/std/zig/CrossTarget.zig+12-1
......@@ -42,6 +42,9 @@ abi: ?Target.Abi = null,
4242/// based on the `os_tag`.
4343dynamic_linker: DynamicLinker = DynamicLinker{},
4444
45/// `null` means default for the cpu/arch/os combo.
46ofmt: ?Target.ObjectFormat = null,
47
4548pub const CpuModel = union(enum) {
4649 /// Always native
4750 native,
......@@ -171,6 +174,7 @@ pub fn toTarget(self: CrossTarget) Target {
171174 .cpu = self.getCpu(),
172175 .os = self.getOs(),
173176 .abi = self.getAbi(),
177 .ofmt = self.getObjectFormat(),
174178 };
175179}
176180
......@@ -200,6 +204,8 @@ pub const ParseOptions = struct {
200204 /// detected path, or a standard path.
201205 dynamic_linker: ?[]const u8 = null,
202206
207 object_format: ?[]const u8 = null,
208
203209 /// If this is provided, the function will populate some information about parsing failures,
204210 /// so that user-friendly error messages can be delivered.
205211 diagnostics: ?*Diagnostics = null,
......@@ -324,6 +330,11 @@ pub fn parse(args: ParseOptions) !CrossTarget {
324330 }
325331 }
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
327338 return result;
328339}
329340
......@@ -623,7 +634,7 @@ pub fn setGnuLibCVersion(self: *CrossTarget, major: u32, minor: u32, patch: u32)
623634}
624635
625636pub 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());
627638}
628639
629640pub fn updateCpuFeatures(self: CrossTarget, set: *Target.Cpu.Feature.Set) void {
lib/std/zig/c_builtins.zig+6-6
......@@ -1,13 +1,13 @@
11const std = @import("std");
22
33pub inline fn __builtin_bswap16(val: u16) u16 {
4 return @byteSwap(u16, val);
4 return @byteSwap(val);
55}
66pub inline fn __builtin_bswap32(val: u32) u32 {
7 return @byteSwap(u32, val);
7 return @byteSwap(val);
88}
99pub inline fn __builtin_bswap64(val: u64) u64 {
10 return @byteSwap(u64, val);
10 return @byteSwap(val);
1111}
1212
1313pub inline fn __builtin_signbit(val: f64) c_int {
......@@ -20,19 +20,19 @@ pub inline fn __builtin_signbitf(val: f32) c_int {
2020pub inline fn __builtin_popcount(val: c_uint) c_int {
2121 // popcount of a c_uint will never exceed the capacity of a c_int
2222 @setRuntimeSafety(false);
23 return @bitCast(c_int, @as(c_uint, @popCount(c_uint, val)));
23 return @bitCast(c_int, @as(c_uint, @popCount(val)));
2424}
2525pub inline fn __builtin_ctz(val: c_uint) c_int {
2626 // Returns the number of trailing 0-bits in val, starting at the least significant bit position.
2727 // In C if `val` is 0, the result is undefined; in zig it's the number of bits in a c_uint
2828 @setRuntimeSafety(false);
29 return @bitCast(c_int, @as(c_uint, @ctz(c_uint, val)));
29 return @bitCast(c_int, @as(c_uint, @ctz(val)));
3030}
3131pub inline fn __builtin_clz(val: c_uint) c_int {
3232 // Returns the number of leading 0-bits in x, starting at the most significant bit position.
3333 // In C if `val` is 0, the result is undefined; in zig it's the number of bits in a c_uint
3434 @setRuntimeSafety(false);
35 return @bitCast(c_int, @as(c_uint, @clz(c_uint, val)));
35 return @bitCast(c_int, @as(c_uint, @clz(val)));
3636}
3737
3838pub inline fn __builtin_sqrt(val: f64) f64 {
lib/std/zig/c_translation.zig+1-1
......@@ -349,7 +349,7 @@ test "shuffleVectorIndex" {
349349
350350/// Constructs a [*c] pointer with the const and volatile annotations
351351/// 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 {
353353 switch (@typeInfo(SelfType)) {
354354 .Pointer => |ptr| {
355355 return @Type(.{ .Pointer = .{
lib/std/zig/parse.zig+7-5
......@@ -3356,16 +3356,18 @@ const Parser = struct {
33563356 }
33573357
33583358 /// Caller must have already verified the first token.
3359 /// ContainerDeclAuto <- ContainerDeclType LBRACE container_doc_comment? ContainerMembers RBRACE
3360 ///
33593361 /// ContainerDeclType
3360 /// <- KEYWORD_struct
3362 /// <- KEYWORD_struct (LPAREN Expr RPAREN)?
3363 /// / KEYWORD_opaque
33613364 /// / KEYWORD_enum (LPAREN Expr RPAREN)?
33623365 /// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?
3363 /// / KEYWORD_opaque
33643366 fn parseContainerDeclAuto(p: *Parser) !Node.Index {
33653367 const main_token = p.nextToken();
33663368 const arg_expr = switch (p.token_tags[main_token]) {
3367 .keyword_struct, .keyword_opaque => null_node,
3368 .keyword_enum => blk: {
3369 .keyword_opaque => null_node,
3370 .keyword_struct, .keyword_enum => blk: {
33693371 if (p.eatToken(.l_paren)) |_| {
33703372 const expr = try p.expectExpr();
33713373 _ = try p.expectToken(.r_paren);
......@@ -3668,7 +3670,7 @@ const Parser = struct {
36683670 }
36693671
36703672 /// 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 {
36723674 const if_token = p.eatToken(.keyword_if) orelse return null_node;
36733675 _ = try p.expectToken(.l_paren);
36743676 const condition = try p.expectExpr();
lib/std/zig/parser_test.zig+15-8
......@@ -3064,6 +3064,13 @@ test "zig fmt: struct declaration" {
30643064 \\ c: u8,
30653065 \\};
30663066 \\
3067 \\const Ps = packed struct(u32) {
3068 \\ a: u1,
3069 \\ b: u2,
3070 \\
3071 \\ c: u29,
3072 \\};
3073 \\
30673074 \\const Es = extern struct {
30683075 \\ a: u8,
30693076 \\ b: u8,
......@@ -4247,10 +4254,10 @@ test "zig fmt: integer literals with underscore separators" {
42474254 \\const
42484255 \\ x =
42494256 \\ 1_234_567
4250 \\ + (0b0_1-0o7_0+0xff_FF ) + 0_0;
4257 \\ + (0b0_1-0o7_0+0xff_FF ) + 1_0;
42514258 ,
42524259 \\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;
42544261 \\
42554262 );
42564263}
......@@ -4259,7 +4266,7 @@ test "zig fmt: hex literals with underscore separators" {
42594266 try testTransform(
42604267 \\pub fn orMask(a: [ 1_000 ]u64, b: [ 1_000] u64) [1_000]u64 {
42614268 \\ 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| {
42634270 \\ c[i] = (a[i] | b[i]) & 0xCCAA_CCAA_CCAA_CCAA;
42644271 \\ }
42654272 \\ return c;
......@@ -4269,7 +4276,7 @@ test "zig fmt: hex literals with underscore separators" {
42694276 ,
42704277 \\pub fn orMask(a: [1_000]u64, b: [1_000]u64) [1_000]u64 {
42714278 \\ 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| {
42734280 \\ c[i] = (a[i] | b[i]) & 0xCCAA_CCAA_CCAA_CCAA;
42744281 \\ }
42754282 \\ return c;
......@@ -4281,14 +4288,14 @@ test "zig fmt: hex literals with underscore separators" {
42814288test "zig fmt: decimal float literals with underscore separators" {
42824289 try testTransform(
42834290 \\pub fn main() void {
4284 \\ const a:f64=(10.0e-0+(10.0e+0))+10_00.00_00e-2+00_00.00_10e+4;
4285 \\ const b:f64=010.0--0_10.0+0_1_0.0_0+1e2;
4291 \\ const a:f64=(10.0e-0+(10.0e+0))+10_00.00_00e-2+20_00.00_10e+4;
4292 \\ const b:f64=1_0.0--10_10.0+1_0_0.0_0+1e2;
42864293 \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b });
42874294 \\}
42884295 ,
42894296 \\pub fn main() void {
4290 \\ const a: f64 = (10.0e-0 + (10.0e+0)) + 10_00.00_00e-2 + 00_00.00_10e+4;
4291 \\ const b: f64 = 010.0 - -0_10.0 + 0_1_0.0_0 + 1e2;
4297 \\ const a: f64 = (10.0e-0 + (10.0e+0)) + 10_00.00_00e-2 + 20_00.00_10e+4;
4298 \\ const b: f64 = 1_0.0 - -10_10.0 + 1_0_0.0_0 + 1e2;
42924299 \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b });
42934300 \\}
42944301 \\
lib/std/zig/system/NativePaths.zig+2
......@@ -109,6 +109,8 @@ pub fn detect(allocator: Allocator, native_info: NativeTargetInfo) !NativePaths
109109
110110 if (native_target.os.tag != .windows) {
111111 const triple = try native_target.linuxTriple(allocator);
112 defer allocator.free(triple);
113
112114 const qual = native_target.cpu.arch.ptrBitWidth();
113115
114116 // 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
237237
238238/// First we attempt to use the executable's own binary. If it is dynamically
239239/// 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, then
240/// 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
241241/// we fall back to the defaults.
242242/// TODO Remove the Allocator requirement from this function.
243243fn detectAbiAndDynamicLinker(
......@@ -276,6 +276,7 @@ fn detectAbiAndDynamicLinker(
276276 };
277277 var ld_info_list_buffer: [all_abis.len]LdInfo = undefined;
278278 var ld_info_list_len: usize = 0;
279 const ofmt = cross_target.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch);
279280
280281 for (all_abis) |abi| {
281282 // This may be a nonsensical parameter. We detect this with error.UnknownDynamicLinkerPath and
......@@ -284,6 +285,7 @@ fn detectAbiAndDynamicLinker(
284285 .cpu = cpu,
285286 .os = os,
286287 .abi = abi,
288 .ofmt = ofmt,
287289 };
288290 const ld = target.standardDynamicLinkerPath();
289291 if (ld.get() == null) continue;
......@@ -346,6 +348,7 @@ fn detectAbiAndDynamicLinker(
346348 .cpu = cpu,
347349 .os = os_adjusted,
348350 .abi = cross_target.abi orelse found_ld_info.abi,
351 .ofmt = cross_target.ofmt orelse Target.ObjectFormat.default(os_adjusted.tag, cpu.arch),
349352 },
350353 .dynamic_linker = if (cross_target.dynamic_linker.get() == null)
351354 DynamicLinker.init(found_ld_path)
......@@ -355,37 +358,77 @@ fn detectAbiAndDynamicLinker(
355358 return result;
356359 }
357360
358 const env_file = std.fs.openFileAbsoluteZ("/usr/bin/env", .{}) catch |err| switch (err) {
359 error.NoSpaceLeft => unreachable,
360 error.NameTooLong => unreachable,
361 error.PathAlreadyExists => unreachable,
362 error.SharingViolation => unreachable,
363 error.InvalidUtf8 => unreachable,
364 error.BadPathName => unreachable,
365 error.PipeBusy => unreachable,
366 error.FileLocksNotSupported => unreachable,
367 error.WouldBlock => unreachable,
368 error.FileBusy => unreachable, // opened without write permissions
369
370 error.IsDir,
371 error.NotDir,
372 error.InvalidHandle,
373 error.AccessDenied,
374 error.NoDevice,
375 error.FileNotFound,
376 error.FileTooBig,
377 error.Unexpected,
378 => return defaultAbiAndDynamicLinker(cpu, os, cross_target),
361 const elf_file = blk: {
362 // This block looks for a shebang line in /usr/bin/env,
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,
364 // doing the same logic recursively in case it finds another shebang line.
365
366 // Since /usr/bin/env is hard-coded into the shebang line of many portable scripts, it's a
367 // reasonably reliable path to start with.
368 var file_name: []const u8 = "/usr/bin/env";
369 // #! (2) + 255 (max length of shebang line since Linux 5.1) + \n (1)
370 var buffer: [258]u8 = undefined;
371 while (true) {
372 const file = std.fs.openFileAbsolute(file_name, .{}) catch |err| switch (err) {
373 error.NoSpaceLeft => unreachable,
374 error.NameTooLong => unreachable,
375 error.PathAlreadyExists => unreachable,
376 error.SharingViolation => unreachable,
377 error.InvalidUtf8 => unreachable,
378 error.BadPathName => unreachable,
379 error.PipeBusy => unreachable,
380 error.FileLocksNotSupported => unreachable,
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 }
381426 };
382 defer env_file.close();
427 defer elf_file.close();
383428
384429 // 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.
386 // Since that path is hard-coded into the shebang line of many portable scripts, it's a
387 // reasonably reliable path to check for.
388 return abiAndDynamicLinkerFromFile(env_file, cpu, os, ld_info_list, cross_target) catch |err| switch (err) {
430 // trick (block self_exe) won't work. The next thing we fall back to is the same thing, but for elf_file.
431 return abiAndDynamicLinkerFromFile(elf_file, cpu, os, ld_info_list, cross_target) catch |err| switch (err) {
389432 error.FileSystem,
390433 error.SystemResources,
391434 error.SymLinkLoop,
......@@ -403,7 +446,10 @@ fn detectAbiAndDynamicLinker(
403446 error.UnexpectedEndOfFile,
404447 error.NameTooLong,
405448 // 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 },
407453 };
408454}
409455
......@@ -496,6 +542,7 @@ pub fn abiAndDynamicLinkerFromFile(
496542 .cpu = cpu,
497543 .os = os,
498544 .abi = cross_target.abi orelse Target.Abi.default(cpu.arch, os),
545 .ofmt = cross_target.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch),
499546 },
500547 .dynamic_linker = cross_target.dynamic_linker,
501548 };
......@@ -786,6 +833,7 @@ fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os, cross_target: Cros
786833 .cpu = cpu,
787834 .os = os,
788835 .abi = cross_target.abi orelse Target.Abi.default(cpu.arch, os),
836 .ofmt = cross_target.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch),
789837 };
790838 return NativeTargetInfo{
791839 .target = target,
......@@ -804,13 +852,13 @@ pub const LdInfo = struct {
804852pub fn elfInt(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @TypeOf(int_64) {
805853 if (is_64) {
806854 if (need_bswap) {
807 return @byteSwap(@TypeOf(int_64), int_64);
855 return @byteSwap(int_64);
808856 } else {
809857 return int_64;
810858 }
811859 } else {
812860 if (need_bswap) {
813 return @byteSwap(@TypeOf(int_32), int_32);
861 return @byteSwap(int_32);
814862 } else {
815863 return int_32;
816864 }
lib/std/zig/tokenizer.zig+55-41
......@@ -1,5 +1,4 @@
11const std = @import("../std.zig");
2const mem = std.mem;
32
43pub const Token = struct {
54 tag: Tag,
......@@ -350,7 +349,7 @@ pub const Tokenizer = struct {
350349
351350 pub fn init(buffer: [:0]const u8) Tokenizer {
352351 // 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;
354353 return Tokenizer{
355354 .buffer = buffer,
356355 .index = src_start,
......@@ -797,6 +796,10 @@ pub const Tokenizer = struct {
797796 remaining_code_units = 3;
798797 state = .char_literal_unicode;
799798 },
799 '\n' => {
800 result.tag = .invalid;
801 break;
802 },
800803 else => {
801804 state = .char_literal_end;
802805 },
......@@ -1429,8 +1432,8 @@ pub const Tokenizer = struct {
14291432
14301433 fn getInvalidCharacterLength(self: *Tokenizer) u3 {
14311434 const c0 = self.buffer[self.index];
1432 if (c0 < 0x80) {
1433 if (c0 < 0x20 or c0 == 0x7f) {
1435 if (std.ascii.isASCII(c0)) {
1436 if (std.ascii.isCntrl(c0)) {
14341437 // ascii control codes are never allowed
14351438 // (note that \n was checked before we got here)
14361439 return 1;
......@@ -1465,8 +1468,8 @@ pub const Tokenizer = struct {
14651468 }
14661469};
14671470
1468test "tokenizer" {
1469 try testTokenize("test", &.{.keyword_test});
1471test "keywords" {
1472 try testTokenize("test const else", &.{ .keyword_test, .keyword_const, .keyword_else });
14701473}
14711474
14721475test "line comment followed by top-level comptime" {
......@@ -1481,7 +1484,7 @@ test "line comment followed by top-level comptime" {
14811484 });
14821485}
14831486
1484test "tokenizer - unknown length pointer and then c pointer" {
1487test "unknown length pointer and then c pointer" {
14851488 try testTokenize(
14861489 \\[*]u8
14871490 \\[*c]u8
......@@ -1498,7 +1501,7 @@ test "tokenizer - unknown length pointer and then c pointer" {
14981501 });
14991502}
15001503
1501test "tokenizer - code point literal with hex escape" {
1504test "code point literal with hex escape" {
15021505 try testTokenize(
15031506 \\'\x1b'
15041507 , &.{.char_literal});
......@@ -1507,7 +1510,21 @@ test "tokenizer - code point literal with hex escape" {
15071510 , &.{ .invalid, .invalid });
15081511}
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" {
15111528 // Valid unicode escapes
15121529 try testTokenize(
15131530 \\'\u{3}'
......@@ -1557,13 +1574,13 @@ test "tokenizer - code point literal with unicode escapes" {
15571574 , &.{ .invalid, .integer_literal, .invalid });
15581575}
15591576
1560test "tokenizer - code point literal with unicode code point" {
1577test "code point literal with unicode code point" {
15611578 try testTokenize(
15621579 \\'💩'
15631580 , &.{.char_literal});
15641581}
15651582
1566test "tokenizer - float literal e exponent" {
1583test "float literal e exponent" {
15671584 try testTokenize("a = 4.94065645841246544177e-324;\n", &.{
15681585 .identifier,
15691586 .equal,
......@@ -1572,7 +1589,7 @@ test "tokenizer - float literal e exponent" {
15721589 });
15731590}
15741591
1575test "tokenizer - float literal p exponent" {
1592test "float literal p exponent" {
15761593 try testTokenize("a = 0x1.a827999fcef32p+1022;\n", &.{
15771594 .identifier,
15781595 .equal,
......@@ -1581,11 +1598,11 @@ test "tokenizer - float literal p exponent" {
15811598 });
15821599}
15831600
1584test "tokenizer - chars" {
1601test "chars" {
15851602 try testTokenize("'c'", &.{.char_literal});
15861603}
15871604
1588test "tokenizer - invalid token characters" {
1605test "invalid token characters" {
15891606 try testTokenize("#", &.{.invalid});
15901607 try testTokenize("`", &.{.invalid});
15911608 try testTokenize("'c", &.{.invalid});
......@@ -1593,7 +1610,7 @@ test "tokenizer - invalid token characters" {
15931610 try testTokenize("''", &.{ .invalid, .invalid });
15941611}
15951612
1596test "tokenizer - invalid literal/comment characters" {
1613test "invalid literal/comment characters" {
15971614 try testTokenize("\"\x00\"", &.{
15981615 .string_literal,
15991616 .invalid,
......@@ -1609,12 +1626,12 @@ test "tokenizer - invalid literal/comment characters" {
16091626 });
16101627}
16111628
1612test "tokenizer - utf8" {
1629test "utf8" {
16131630 try testTokenize("//\xc2\x80", &.{});
16141631 try testTokenize("//\xf4\x8f\xbf\xbf", &.{});
16151632}
16161633
1617test "tokenizer - invalid utf8" {
1634test "invalid utf8" {
16181635 try testTokenize("//\x80", &.{
16191636 .invalid,
16201637 });
......@@ -1641,7 +1658,7 @@ test "tokenizer - invalid utf8" {
16411658 });
16421659}
16431660
1644test "tokenizer - illegal unicode codepoints" {
1661test "illegal unicode codepoints" {
16451662 // unicode newline characters.U+0085, U+2028, U+2029
16461663 try testTokenize("//\xc2\x84", &.{});
16471664 try testTokenize("//\xc2\x85", &.{
......@@ -1658,7 +1675,7 @@ test "tokenizer - illegal unicode codepoints" {
16581675 try testTokenize("//\xe2\x80\xaa", &.{});
16591676}
16601677
1661test "tokenizer - string identifier and builtin fns" {
1678test "string identifier and builtin fns" {
16621679 try testTokenize(
16631680 \\const @"if" = @import("std");
16641681 , &.{
......@@ -1673,7 +1690,7 @@ test "tokenizer - string identifier and builtin fns" {
16731690 });
16741691}
16751692
1676test "tokenizer - multiline string literal with literal tab" {
1693test "multiline string literal with literal tab" {
16771694 try testTokenize(
16781695 \\\\foo bar
16791696 , &.{
......@@ -1681,7 +1698,7 @@ test "tokenizer - multiline string literal with literal tab" {
16811698 });
16821699}
16831700
1684test "tokenizer - comments with literal tab" {
1701test "comments with literal tab" {
16851702 try testTokenize(
16861703 \\//foo bar
16871704 \\//!foo bar
......@@ -1697,14 +1714,14 @@ test "tokenizer - comments with literal tab" {
16971714 });
16981715}
16991716
1700test "tokenizer - pipe and then invalid" {
1717test "pipe and then invalid" {
17011718 try testTokenize("||=", &.{
17021719 .pipe_pipe,
17031720 .equal,
17041721 });
17051722}
17061723
1707test "tokenizer - line comment and doc comment" {
1724test "line comment and doc comment" {
17081725 try testTokenize("//", &.{});
17091726 try testTokenize("// a / b", &.{});
17101727 try testTokenize("// /", &.{});
......@@ -1715,7 +1732,7 @@ test "tokenizer - line comment and doc comment" {
17151732 try testTokenize("//!!", &.{.container_doc_comment});
17161733}
17171734
1718test "tokenizer - line comment followed by identifier" {
1735test "line comment followed by identifier" {
17191736 try testTokenize(
17201737 \\ Unexpected,
17211738 \\ // another
......@@ -1728,7 +1745,7 @@ test "tokenizer - line comment followed by identifier" {
17281745 });
17291746}
17301747
1731test "tokenizer - UTF-8 BOM is recognized and skipped" {
1748test "UTF-8 BOM is recognized and skipped" {
17321749 try testTokenize("\xEF\xBB\xBFa;\n", &.{
17331750 .identifier,
17341751 .semicolon,
......@@ -1770,7 +1787,7 @@ test "correctly parse pointer dereference followed by asterisk" {
17701787 });
17711788}
17721789
1773test "tokenizer - range literals" {
1790test "range literals" {
17741791 try testTokenize("0...9", &.{ .integer_literal, .ellipsis3, .integer_literal });
17751792 try testTokenize("'0'...'9'", &.{ .char_literal, .ellipsis3, .char_literal });
17761793 try testTokenize("0x00...0x09", &.{ .integer_literal, .ellipsis3, .integer_literal });
......@@ -1778,7 +1795,7 @@ test "tokenizer - range literals" {
17781795 try testTokenize("0o00...0o11", &.{ .integer_literal, .ellipsis3, .integer_literal });
17791796}
17801797
1781test "tokenizer - number literals decimal" {
1798test "number literals decimal" {
17821799 try testTokenize("0", &.{.integer_literal});
17831800 try testTokenize("1", &.{.integer_literal});
17841801 try testTokenize("2", &.{.integer_literal});
......@@ -1845,7 +1862,7 @@ test "tokenizer - number literals decimal" {
18451862 try testTokenize("1.0e0_+", &.{ .invalid, .plus });
18461863}
18471864
1848test "tokenizer - number literals binary" {
1865test "number literals binary" {
18491866 try testTokenize("0b0", &.{.integer_literal});
18501867 try testTokenize("0b1", &.{.integer_literal});
18511868 try testTokenize("0b2", &.{ .invalid, .integer_literal });
......@@ -1884,7 +1901,7 @@ test "tokenizer - number literals binary" {
18841901 try testTokenize("0b1_,", &.{ .invalid, .comma });
18851902}
18861903
1887test "tokenizer - number literals octal" {
1904test "number literals octal" {
18881905 try testTokenize("0o0", &.{.integer_literal});
18891906 try testTokenize("0o1", &.{.integer_literal});
18901907 try testTokenize("0o2", &.{.integer_literal});
......@@ -1923,7 +1940,7 @@ test "tokenizer - number literals octal" {
19231940 try testTokenize("0o_,", &.{ .invalid, .identifier, .comma });
19241941}
19251942
1926test "tokenizer - number literals hexadecimal" {
1943test "number literals hexadecimal" {
19271944 try testTokenize("0x0", &.{.integer_literal});
19281945 try testTokenize("0x1", &.{.integer_literal});
19291946 try testTokenize("0x2", &.{.integer_literal});
......@@ -2011,22 +2028,22 @@ test "tokenizer - number literals hexadecimal" {
20112028 try testTokenize("0x0.0p0_", &.{ .invalid, .eof });
20122029}
20132030
2014test "tokenizer - multi line string literal with only 1 backslash" {
2031test "multi line string literal with only 1 backslash" {
20152032 try testTokenize("x \\\n;", &.{ .identifier, .invalid, .semicolon });
20162033}
20172034
2018test "tokenizer - invalid builtin identifiers" {
2035test "invalid builtin identifiers" {
20192036 try testTokenize("@()", &.{ .invalid, .l_paren, .r_paren });
20202037 try testTokenize("@0()", &.{ .invalid, .integer_literal, .l_paren, .r_paren });
20212038}
20222039
2023test "tokenizer - invalid token with unfinished escape right before eof" {
2040test "invalid token with unfinished escape right before eof" {
20242041 try testTokenize("\"\\", &.{.invalid});
20252042 try testTokenize("'\\", &.{.invalid});
20262043 try testTokenize("'\\u", &.{.invalid});
20272044}
20282045
2029test "tokenizer - saturating" {
2046test "saturating operators" {
20302047 try testTokenize("<<", &.{.angle_bracket_angle_bracket_left});
20312048 try testTokenize("<<|", &.{.angle_bracket_angle_bracket_left_pipe});
20322049 try testTokenize("<<|=", &.{.angle_bracket_angle_bracket_left_pipe_equal});
......@@ -2044,17 +2061,14 @@ test "tokenizer - saturating" {
20442061 try testTokenize("-|=", &.{.minus_pipe_equal});
20452062}
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 {
20482065 var tokenizer = Tokenizer.init(source);
2049 for (expected_tokens) |expected_token_id| {
2066 for (expected_token_tags) |expected_token_tag| {
20502067 const token = tokenizer.next();
2051 if (token.tag != expected_token_id) {
2052 std.debug.panic("expected {s}, found {s}\n", .{
2053 @tagName(expected_token_id), @tagName(token.tag),
2054 });
2055 }
2068 try std.testing.expectEqual(expected_token_tag, token.tag);
20562069 }
20572070 const last_token = tokenizer.next();
20582071 try std.testing.expectEqual(Token.Tag.eof, last_token.tag);
20592072 try std.testing.expectEqual(source.len, last_token.loc.start);
2073 try std.testing.expectEqual(source.len, last_token.loc.end);
20602074}
src/Air.zig+10
......@@ -660,6 +660,10 @@ pub const Inst = struct {
660660 /// Uses the `pl_op` field with payload `AtomicRmw`. Operand is `ptr`.
661661 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
663667 /// Given an enum tag value, returns the tag name. The enum type may be non-exhaustive.
664668 /// Result type is always `[:0]const u8`.
665669 /// Uses the `un_op` field.
......@@ -669,6 +673,10 @@ pub const Inst = struct {
669673 /// Uses the `un_op` field.
670674 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
672680 /// Constructs a vector, tuple, struct, or array value out of runtime-known elements.
673681 /// Some of the elements may be comptime-known.
674682 /// 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 {
10571065 .is_non_err,
10581066 .is_err_ptr,
10591067 .is_non_err_ptr,
1068 .is_named_enum_value,
1069 .error_set_has_value,
10601070 => return Type.bool,
10611071
10621072 .const_ty => return Type.type,
src/AstGen.zig+270-63
......@@ -152,6 +152,7 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {
152152 0,
153153 tree.containerDeclRoot(),
154154 .Auto,
155 0,
155156 )) |struct_decl_ref| {
156157 assert(refToIndex(struct_decl_ref).? == 0);
157158 } else |err| switch (err) {
......@@ -859,7 +860,12 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
859860 },
860861 .enum_literal => return simpleStrTok(gz, rl, main_tokens[node], node, .enum_literal),
861862 .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 },
863869 .anyframe_type => {
864870 const return_type = try typeExpr(gz, scope, node_datas[node].rhs);
865871 const result = try gz.addUnNode(.anyframe_type, return_type, node);
......@@ -1158,6 +1164,10 @@ fn fnProtoExpr(
11581164 const tree = astgen.tree;
11591165 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
11611171 const is_extern = blk: {
11621172 const maybe_extern_token = fn_proto.extern_export_inline_token orelse break :blk false;
11631173 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
24492459 .trunc,
24502460 .round,
24512461 .tag_name,
2452 .reify,
24532462 .type_name,
24542463 .frame_type,
24552464 .frame_size,
......@@ -2496,7 +2505,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
24962505 .closure_get,
24972506 .array_base_ptr,
24982507 .field_base_ptr,
2499 .param_type,
25002508 .ret_ptr,
25012509 .ret_type,
25022510 .@"try",
......@@ -3066,6 +3074,19 @@ fn emitDbgNode(gz: *GenZir, node: Ast.Node.Index) !void {
30663074 const line = astgen.source_line - gz.decl_line;
30673075 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
30693090 _ = try gz.add(.{ .tag = .dbg_stmt, .data = .{
30703091 .dbg_stmt = .{
30713092 .line = line,
......@@ -4071,6 +4092,13 @@ fn testDecl(
40714092 true => .signed,
40724093 false => .unsigned,
40734094 };
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 }
40744102 _ = parseBitCount(ident_name_raw[1..]) catch |err| switch (err) {
40754103 error.Overflow => return astgen.failTok(
40764104 test_name_token,
......@@ -4207,15 +4235,18 @@ fn structDeclInner(
42074235 node: Ast.Node.Index,
42084236 container_decl: Ast.full.ContainerDecl,
42094237 layout: std.builtin.Type.ContainerLayout,
4238 backing_int_node: Ast.Node.Index,
42104239) InnerError!Zir.Inst.Ref {
42114240 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) {
42144243 try gz.setStruct(decl_inst, .{
42154244 .src_node = node,
42164245 .layout = layout,
42174246 .fields_len = 0,
42184247 .decls_len = 0,
4248 .backing_int_ref = .none,
4249 .backing_int_body_len = 0,
42194250 .known_non_opv = false,
42204251 .known_comptime_only = false,
42214252 });
......@@ -4238,10 +4269,13 @@ fn structDeclInner(
42384269 // are in scope, so that field types, alignments, and default value expressions
42394270 // can refer to decls within the struct itself.
42404271 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;
42414275 var block_scope: GenZir = .{
42424276 .parent = &namespace.base,
42434277 .decl_node_index = node,
4244 .decl_line = astgen.source_line,
4278 .decl_line = decl_line,
42454279 .astgen = astgen,
42464280 .force_comptime = true,
42474281 .in_defer = false,
......@@ -4250,6 +4284,35 @@ fn structDeclInner(
42504284 };
42514285 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
42534316 const decl_count = try astgen.scanDecls(&namespace, container_decl.ast.members);
42544317 const field_count = @intCast(u32, container_decl.ast.members.len - decl_count);
42554318
......@@ -4274,7 +4337,7 @@ fn structDeclInner(
42744337 var known_non_opv = false;
42754338 var known_comptime_only = false;
42764339 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)) {
42784341 .decl => continue,
42794342 .field => |field| field,
42804343 };
......@@ -4362,6 +4425,8 @@ fn structDeclInner(
43624425 .layout = layout,
43634426 .fields_len = field_count,
43644427 .decls_len = decl_count,
4428 .backing_int_ref = backing_int_ref,
4429 .backing_int_body_len = @intCast(u32, backing_int_body_len),
43654430 .known_non_opv = known_non_opv,
43664431 .known_comptime_only = known_comptime_only,
43674432 });
......@@ -4370,7 +4435,9 @@ fn structDeclInner(
43704435 const decls_slice = wip_members.declsSlice();
43714436 const fields_slice = wip_members.fieldsSlice();
43724437 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]);
43744441 astgen.extra.appendSliceAssumeCapacity(decls_slice);
43754442 astgen.extra.appendSliceAssumeCapacity(fields_slice);
43764443 astgen.extra.appendSliceAssumeCapacity(bodies_slice);
......@@ -4441,7 +4508,7 @@ fn unionDeclInner(
44414508 defer wip_members.deinit();
44424509
44434510 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)) {
44454512 .decl => continue,
44464513 .field => |field| field,
44474514 };
......@@ -4504,9 +4571,6 @@ fn unionDeclInner(
45044571 wip_members.appendToField(@enumToInt(tag_value));
45054572 }
45064573 }
4507 if (field_count == 0) {
4508 return astgen.failNode(node, "union declarations must have at least one tag", .{});
4509 }
45104574
45114575 if (!block_scope.isEmpty()) {
45124576 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
......@@ -4566,9 +4630,7 @@ fn containerDecl(
45664630 else => unreachable,
45674631 } else std.builtin.Type.ContainerLayout.Auto;
45684632
4569 assert(container_decl.ast.arg == 0);
4570
4571 const result = try structDeclInner(gz, scope, node, container_decl, layout);
4633 const result = try structDeclInner(gz, scope, node, container_decl, layout, container_decl.ast.arg);
45724634 return rvalue(gz, rl, result, node);
45734635 },
45744636 .keyword_union => {
......@@ -4664,12 +4726,6 @@ fn containerDecl(
46644726 .nonexhaustive_node = nonexhaustive_node,
46654727 };
46664728 };
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 }
46734729 if (counts.nonexhaustive_node != 0 and container_decl.ast.arg == 0) {
46744730 try astgen.appendErrorNodeNotes(
46754731 node,
......@@ -4728,7 +4784,7 @@ fn containerDecl(
47284784 for (container_decl.ast.members) |member_node| {
47294785 if (member_node == counts.nonexhaustive_node)
47304786 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)) {
47324788 .decl => continue,
47334789 .field => |field| field,
47344790 };
......@@ -4806,13 +4862,26 @@ fn containerDecl(
48064862 };
48074863 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
48094878 const decl_count = try astgen.scanDecls(&namespace, container_decl.ast.members);
48104879
48114880 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, 0, 0, 0);
48124881 defer wip_members.deinit();
48134882
48144883 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);
48164885 if (res == .field) {
48174886 return astgen.failNode(member_node, "opaque types cannot have fields", .{});
48184887 }
......@@ -5033,6 +5102,16 @@ fn tryExpr(
50335102
50345103 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
50365115 const operand_rl: ResultLoc = switch (rl) {
50375116 .ref => .ref,
50385117 else => .none,
......@@ -5062,6 +5141,7 @@ fn tryExpr(
50625141 };
50635142 const err_code = try else_scope.addUnNode(err_tag, operand, node);
50645143 try genDefers(&else_scope, &fn_block.base, scope, .{ .both = err_code });
5144 try emitDbgStmt(&else_scope, try_line, try_column);
50655145 _ = try else_scope.addUnNode(.ret_node, err_code, node);
50665146
50675147 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
65686648
65696649 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
65716661 const defer_outer = &astgen.fn_block.?.base;
65726662
65736663 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
65866676 const defer_counts = countDefers(astgen, defer_outer, scope);
65876677 if (!defer_counts.need_err_code) {
65886678 try genDefers(gz, defer_outer, scope, .both_sans_err);
6679 try emitDbgStmt(gz, ret_line, ret_column);
65896680 _ = try gz.addStrTok(.ret_err_value, err_name_str_index, ident_token);
65906681 return Zir.Inst.Ref.unreachable_value;
65916682 }
65926683 const err_code = try gz.addStrTok(.ret_err_value_code, err_name_str_index, ident_token);
65936684 try genDefers(gz, defer_outer, scope, .{ .both = err_code });
6685 try emitDbgStmt(gz, ret_line, ret_column);
65946686 _ = try gz.addUnNode(.ret_node, err_code, node);
65956687 return Zir.Inst.Ref.unreachable_value;
65966688 }
......@@ -6609,6 +6701,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
66096701 .never => {
66106702 // Returning a value that cannot be an error; skip error defers.
66116703 try genDefers(gz, defer_outer, scope, .normal_only);
6704 try emitDbgStmt(gz, ret_line, ret_column);
66126705 try gz.addRet(rl, operand, node);
66136706 return Zir.Inst.Ref.unreachable_value;
66146707 },
......@@ -6616,6 +6709,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
66166709 // Value is always an error. Emit both error defers and regular defers.
66176710 const err_code = if (rl == .ptr) try gz.addUnNode(.load, rl.ptr, node) else operand;
66186711 try genDefers(gz, defer_outer, scope, .{ .both = err_code });
6712 try emitDbgStmt(gz, ret_line, ret_column);
66196713 try gz.addRet(rl, operand, node);
66206714 return Zir.Inst.Ref.unreachable_value;
66216715 },
......@@ -6624,6 +6718,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
66246718 if (!defer_counts.have_err) {
66256719 // Only regular defers; no branch needed.
66266720 try genDefers(gz, defer_outer, scope, .normal_only);
6721 try emitDbgStmt(gz, ret_line, ret_column);
66276722 try gz.addRet(rl, operand, node);
66286723 return Zir.Inst.Ref.unreachable_value;
66296724 }
......@@ -6637,6 +6732,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
66376732 defer then_scope.unstack();
66386733
66396734 try genDefers(&then_scope, defer_outer, scope, .normal_only);
6735 try emitDbgStmt(&then_scope, ret_line, ret_column);
66406736 try then_scope.addRet(rl, operand, node);
66416737
66426738 var else_scope = gz.makeSubBlock(scope);
......@@ -6646,6 +6742,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
66466742 .both = try else_scope.addUnNode(.err_union_code, result, node),
66476743 };
66486744 try genDefers(&else_scope, defer_outer, scope, which_ones);
6745 try emitDbgStmt(&else_scope, ret_line, ret_column);
66496746 try else_scope.addRet(rl, operand, node);
66506747
66516748 try setCondBrPayload(condbr, is_non_err, &then_scope, 0, &else_scope, 0);
......@@ -6708,6 +6805,13 @@ fn identifier(
67086805 true => .signed,
67096806 false => .unsigned,
67106807 };
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 }
67116815 const bit_count = parseBitCount(ident_name_raw[1..]) catch |err| switch (err) {
67126816 error.Overflow => return astgen.failNode(
67136817 ident,
......@@ -6938,17 +7042,6 @@ fn integerLiteral(gz: *GenZir, rl: ResultLoc, node: Ast.Node.Index) InnerError!Z
69387042 const main_tokens = tree.nodes.items(.main_token);
69397043 const int_token = main_tokens[node];
69407044 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
69537046 var base: u8 = 10;
69547047 var non_prefixed: []const u8 = prefixed_bytes;
......@@ -6963,6 +7056,24 @@ fn integerLiteral(gz: *GenZir, rl: ResultLoc, node: Ast.Node.Index) InnerError!Z
69637056 non_prefixed = prefixed_bytes[2..];
69647057 }
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
69667077 const gpa = astgen.gpa;
69677078 var big_int = try std.math.big.int.Managed.init(gpa);
69687079 defer big_int.deinit();
......@@ -7548,7 +7659,6 @@ fn builtinCall(
75487659 .trunc => return simpleUnOp(gz, scope, rl, node, .none, params[0], .trunc),
75497660 .round => return simpleUnOp(gz, scope, rl, node, .none, params[0], .round),
75507661 .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),
75527662 .type_name => return simpleUnOp(gz, scope, rl, node, .none, params[0], .type_name),
75537663 .Frame => return simpleUnOp(gz, scope, rl, node, .none, params[0], .frame_type),
75547664 .frame_size => return simpleUnOp(gz, scope, rl, node, .none, params[0], .frame_size),
......@@ -7563,6 +7673,31 @@ fn builtinCall(
75637673 .truncate => return typeCast(gz, scope, rl, node, params[0], params[1], .truncate),
75647674 // 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 },
75667701 .panic => {
75677702 try emitDbgNode(gz, node);
75687703 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(
76057740 .has_decl => return hasDeclOrField(gz, scope, rl, node, params[0], params[1], .has_decl),
76067741 .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),
7609 .ctz => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .ctz),
7610 .pop_count => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .pop_count),
7611 .byte_swap => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .byte_swap),
7612 .bit_reverse => return bitBuiltin(gz, scope, rl, node, params[0], params[1], .bit_reverse),
7743 .clz => return bitBuiltin(gz, scope, rl, node, params[0], .clz),
7744 .ctz => return bitBuiltin(gz, scope, rl, node, params[0], .ctz),
7745 .pop_count => return bitBuiltin(gz, scope, rl, node, params[0], .pop_count),
7746 .byte_swap => return bitBuiltin(gz, scope, rl, node, params[0], .byte_swap),
7747 .bit_reverse => return bitBuiltin(gz, scope, rl, node, params[0], .bit_reverse),
76137748
76147749 .div_exact => return divBuiltin(gz, scope, rl, node, params[0], params[1], .div_exact),
76157750 .div_floor => return divBuiltin(gz, scope, rl, node, params[0], params[1], .div_floor),
......@@ -7972,17 +8107,9 @@ fn bitBuiltin(
79728107 scope: *Scope,
79738108 rl: ResultLoc,
79748109 node: Ast.Node.Index,
7975 int_type_node: Ast.Node.Index,
79768110 operand_node: Ast.Node.Index,
79778111 tag: Zir.Inst.Tag,
79788112) 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
79868113 const operand = try expr(gz, scope, .none, operand_node);
79878114 const result = try gz.addUnNode(tag, operand, node);
79888115 return rvalue(gz, rl, result, node);
......@@ -8147,6 +8274,33 @@ fn callExpr(
81478274 assert(callee != .none);
81488275 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
81508304 const payload_index = try addExtra(astgen, Zir.Inst.Call{
81518305 .callee = callee,
81528306 .flags = .{
......@@ -8154,22 +8308,16 @@ fn callExpr(
81548308 .args_len = @intCast(Zir.Inst.Call.Flags.PackedArgsLen, call.ast.params.len),
81558309 },
81568310 });
8157 var extra_index = try reserveExtra(astgen, call.ast.params.len);
8158
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;
8311 if (call.ast.params.len != 0) {
8312 try astgen.extra.appendSlice(astgen.gpa, astgen.scratch.items[scratch_top..]);
81708313 }
8171
8172 const call_inst = try gz.addPlNodePayloadIndex(.call, node, payload_index);
8314 gz.astgen.instructions.set(call_index, .{
8315 .tag = .call,
8316 .data = .{ .pl_node = .{
8317 .src_node = gz.nodeIndexToRelative(node),
8318 .payload_index = payload_index,
8319 } },
8320 });
81738321 return rvalue(gz, rl, call_inst, node); // TODO function call with result location
81748322}
81758323
......@@ -11153,6 +11301,8 @@ const GenZir = struct {
1115311301 src_node: Ast.Node.Index,
1115411302 fields_len: u32,
1115511303 decls_len: u32,
11304 backing_int_ref: Zir.Inst.Ref,
11305 backing_int_body_len: u32,
1115611306 layout: std.builtin.Type.ContainerLayout,
1115711307 known_non_opv: bool,
1115811308 known_comptime_only: bool,
......@@ -11160,7 +11310,7 @@ const GenZir = struct {
1116011310 const astgen = gz.astgen;
1116111311 const gpa = astgen.gpa;
1116211312
11163 try astgen.extra.ensureUnusedCapacity(gpa, 4);
11313 try astgen.extra.ensureUnusedCapacity(gpa, 6);
1116411314 const payload_index = @intCast(u32, astgen.extra.items.len);
1116511315
1116611316 if (args.src_node != 0) {
......@@ -11173,6 +11323,12 @@ const GenZir = struct {
1117311323 if (args.decls_len != 0) {
1117411324 astgen.extra.appendAssumeCapacity(args.decls_len);
1117511325 }
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 }
1117611332 astgen.instructions.set(inst, .{
1117711333 .tag = .extended,
1117811334 .data = .{ .extended = .{
......@@ -11181,6 +11337,7 @@ const GenZir = struct {
1118111337 .has_src_node = args.src_node != 0,
1118211338 .has_fields_len = args.fields_len != 0,
1118311339 .has_decls_len = args.decls_len != 0,
11340 .has_backing_int = args.backing_int_ref != .none,
1118411341 .known_non_opv = args.known_non_opv,
1118511342 .known_comptime_only = args.known_comptime_only,
1118611343 .name_strategy = gz.anon_name_strategy,
......@@ -11605,6 +11762,45 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast.
1160511762 error.OutOfMemory => return error.OutOfMemory,
1160611763 }
1160711764 }
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 };
1160811804 gop.value_ptr.* = member_node;
1160911805 }
1161011806 return decl_count;
......@@ -11662,3 +11858,14 @@ fn countBodyLenAfterFixups(astgen: *AstGen, body: []const Zir.Inst.Index) u32 {
1166211858 }
1166311859 return @intCast(u32, count);
1166411860}
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");
99const Zir = @import("Zir.zig");
1010const Ref = Zir.Inst.Ref;
1111const log = std.log.scoped(.autodoc);
12const Docgen = @import("autodoc/render_source.zig");
1213
1314module: *Module,
1415doc_location: Compilation.EmitLoc,
......@@ -68,6 +69,8 @@ pub fn generateZirData(self: *Autodoc) !void {
6869 }
6970 }
7071
72 log.debug("Ref map size: {}", .{Ref.typed_value_map.len});
73
7174 const root_src_dir = self.module.main_pkg.root_src_directory;
7275 const root_src_path = self.module.main_pkg.root_src_path;
7376 const joined_src_path = try root_src_dir.join(self.arena, &.{root_src_path});
......@@ -158,6 +161,9 @@ pub fn generateZirData(self: *Autodoc) !void {
158161 .void_type => .{
159162 .Void = .{ .name = tmpbuf.toOwnedSlice() },
160163 },
164 .type_info_type => .{
165 .ComptimeExpr = .{ .name = tmpbuf.toOwnedSlice() },
166 },
161167 .type_type => .{
162168 .Type = .{ .name = tmpbuf.toOwnedSlice() },
163169 },
......@@ -189,10 +195,14 @@ pub fn generateZirData(self: *Autodoc) !void {
189195 );
190196 }
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
193203 try self.ast_nodes.append(self.arena, .{ .name = "(root)" });
194204 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
197207 if (self.ref_paths_pending_on_decls.count() > 0) {
198208 @panic("some decl paths were never fully analized (pending on decls)");
......@@ -242,6 +252,7 @@ pub fn generateZirData(self: *Autodoc) !void {
242252 try d.handle.openDir(self.doc_location.basename, .{})
243253 else
244254 try self.module.zig_cache_artifact_directory.handle.openDir(self.doc_location.basename, .{});
255
245256 {
246257 const data_js_f = try output_dir.createFile("data.js", .{});
247258 defer data_js_f.close();
......@@ -266,6 +277,29 @@ pub fn generateZirData(self: *Autodoc) !void {
266277 try buffer.flush();
267278 }
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
269303 // copy main.js, index.html
270304 var docs_dir = try self.module.comp.zig_lib_directory.handle.openDir("docs", .{});
271305 defer docs_dir.close();
......@@ -273,6 +307,26 @@ pub fn generateZirData(self: *Autodoc) !void {
273307 try docs_dir.copyFile("index.html", output_dir, "index.html", .{});
274308}
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
276330/// Represents a chain of scopes, used to resolve decl references to the
277331/// corresponding entry in `self.decls`.
278332const Scope = struct {
......@@ -563,6 +617,7 @@ const DocData = struct {
563617 type: usize, // index in `types`
564618 this: usize, // index in `types`
565619 declRef: usize, // index in `decls`
620 builtinField: enum { len, ptr },
566621 fieldRef: FieldRef,
567622 refPath: []Expr,
568623 int: struct {
......@@ -587,7 +642,7 @@ const DocData = struct {
587642 sizeOf: usize, // index in `exprs`
588643 bitSizeOf: usize, // index in `exprs`
589644 enumToInt: usize, // index in `exprs`
590 compileError: []const u8,
645 compileError: usize, //index in `exprs`
591646 errorSets: usize,
592647 string: []const u8, // direct value
593648 sliceIndex: usize,
......@@ -652,20 +707,26 @@ const DocData = struct {
652707 var jsw = std.json.writeStream(w, 15);
653708 try jsw.beginObject();
654709 try jsw.objectField(@tagName(active_tag));
655 inline for (comptime std.meta.fields(Expr)) |case| {
656 if (@field(Expr, case.name) == active_tag) {
657 switch (active_tag) {
658 .int => {
659 if (self.int.negated) try w.writeAll("-");
660 try jsw.emitNumber(self.int.value);
661 },
662 .int_big => {
710 switch (self) {
711 .int => {
712 if (self.int.negated) try w.writeAll("-");
713 try jsw.emitNumber(self.int.value);
714 },
715 .int_big => {
663716
664 //@panic("TODO: json serialization of big ints!");
665 //if (v.negated) try w.writeAll("-");
666 //try jsw.emitNumber(v.value);
667 },
668 else => {
717 //@panic("TODO: json serialization of big ints!");
718 //if (v.negated) try w.writeAll("-");
719 //try jsw.emitNumber(v.value);
720 },
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) {
669730 try std.json.stringify(@field(self, case.name), opt, w);
670731 jsw.state_index -= 1;
671732 // TODO: we should not reach into the state of the
......@@ -674,9 +735,9 @@ const DocData = struct {
674735 // would be nice to have a proper integration
675736 // between the json writer and the generic
676737 // std.json.stringify implementation
677 },
738 }
678739 }
679 }
740 },
680741 }
681742 try jsw.endObject();
682743 }
......@@ -712,6 +773,7 @@ fn walkInstruction(
712773 self: *Autodoc,
713774 file: *File,
714775 parent_scope: *Scope,
776 parent_line: usize,
715777 inst_index: usize,
716778 need_type: bool, // true if the caller needs us to provide also a typeRef
717779) AutodocErrors!DocData.WalkResult {
......@@ -794,12 +856,16 @@ fn walkInstruction(
794856
795857 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 };
798863 try self.ast_nodes.append(self.arena, .{ .name = "(root)" });
799864 try self.files.put(self.arena, new_file, main_type_index);
800865 return self.walkInstruction(
801866 new_file,
802867 &root_scope,
868 1,
803869 Zir.main_struct_inst,
804870 false,
805871 );
......@@ -824,13 +890,14 @@ fn walkInstruction(
824890 return self.walkInstruction(
825891 new_file.file,
826892 &new_scope,
893 1,
827894 Zir.main_struct_inst,
828895 need_type,
829896 );
830897 },
831898 .ret_node => {
832899 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);
834901 },
835902 .ret_load => {
836903 const un_node = data[inst_index].un_node;
......@@ -861,7 +928,7 @@ fn walkInstruction(
861928 }
862929
863930 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);
865932 }
866933
867934 return DocData.WalkResult{
......@@ -870,11 +937,11 @@ fn walkInstruction(
870937 },
871938 .closure_get => {
872939 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);
874941 },
875942 .closure_capture => {
876943 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);
878945 },
879946 .cmpxchg_strong, .cmpxchg_weak => {
880947 const pl_node = data[inst_index].pl_node;
......@@ -889,6 +956,7 @@ fn walkInstruction(
889956 var ptr: DocData.WalkResult = try self.walkRef(
890957 file,
891958 parent_scope,
959 parent_line,
892960 extra.data.ptr,
893961 false,
894962 );
......@@ -898,6 +966,7 @@ fn walkInstruction(
898966 var expected_value: DocData.WalkResult = try self.walkRef(
899967 file,
900968 parent_scope,
969 parent_line,
901970 extra.data.expected_value,
902971 false,
903972 );
......@@ -907,6 +976,7 @@ fn walkInstruction(
907976 var new_value: DocData.WalkResult = try self.walkRef(
908977 file,
909978 parent_scope,
979 parent_line,
910980 extra.data.new_value,
911981 false,
912982 );
......@@ -916,6 +986,7 @@ fn walkInstruction(
916986 var success_order: DocData.WalkResult = try self.walkRef(
917987 file,
918988 parent_scope,
989 parent_line,
919990 extra.data.success_order,
920991 false,
921992 );
......@@ -925,6 +996,7 @@ fn walkInstruction(
925996 var failure_order: DocData.WalkResult = try self.walkRef(
926997 file,
927998 parent_scope,
999 parent_line,
9281000 extra.data.failure_order,
9291001 false,
9301002 );
......@@ -978,17 +1050,16 @@ fn walkInstruction(
9781050 var operand: DocData.WalkResult = try self.walkRef(
9791051 file,
9801052 parent_scope,
1053 parent_line,
9811054 un_node.operand,
9821055 false,
9831056 );
9841057
1058 const operand_index = self.exprs.items.len;
1059 try self.exprs.append(self.arena, operand.expr);
1060
9851061 return DocData.WalkResult{
986 .expr = .{
987 .compileError = switch (operand.expr) {
988 .string => |s| s,
989 else => "TODO: non-string @compileError arguments",
990 },
991 },
1062 .expr = .{ .compileError = operand_index },
9921063 };
9931064 },
9941065 .enum_literal => {
......@@ -1034,12 +1105,14 @@ fn walkInstruction(
10341105 var lhs: DocData.WalkResult = try self.walkRef(
10351106 file,
10361107 parent_scope,
1108 parent_line,
10371109 extra.data.lhs,
10381110 false,
10391111 );
10401112 var start: DocData.WalkResult = try self.walkRef(
10411113 file,
10421114 parent_scope,
1115 parent_line,
10431116 extra.data.start,
10441117 false,
10451118 );
......@@ -1065,18 +1138,21 @@ fn walkInstruction(
10651138 var lhs: DocData.WalkResult = try self.walkRef(
10661139 file,
10671140 parent_scope,
1141 parent_line,
10681142 extra.data.lhs,
10691143 false,
10701144 );
10711145 var start: DocData.WalkResult = try self.walkRef(
10721146 file,
10731147 parent_scope,
1148 parent_line,
10741149 extra.data.start,
10751150 false,
10761151 );
10771152 var end: DocData.WalkResult = try self.walkRef(
10781153 file,
10791154 parent_scope,
1155 parent_line,
10801156 extra.data.end,
10811157 false,
10821158 );
......@@ -1104,24 +1180,28 @@ fn walkInstruction(
11041180 var lhs: DocData.WalkResult = try self.walkRef(
11051181 file,
11061182 parent_scope,
1183 parent_line,
11071184 extra.data.lhs,
11081185 false,
11091186 );
11101187 var start: DocData.WalkResult = try self.walkRef(
11111188 file,
11121189 parent_scope,
1190 parent_line,
11131191 extra.data.start,
11141192 false,
11151193 );
11161194 var end: DocData.WalkResult = try self.walkRef(
11171195 file,
11181196 parent_scope,
1197 parent_line,
11191198 extra.data.end,
11201199 false,
11211200 );
11221201 var sentinel: DocData.WalkResult = try self.walkRef(
11231202 file,
11241203 parent_scope,
1204 parent_line,
11251205 extra.data.sentinel,
11261206 false,
11271207 );
......@@ -1171,12 +1251,14 @@ fn walkInstruction(
11711251 var lhs: DocData.WalkResult = try self.walkRef(
11721252 file,
11731253 parent_scope,
1254 parent_line,
11741255 extra.data.lhs,
11751256 false,
11761257 );
11771258 var rhs: DocData.WalkResult = try self.walkRef(
11781259 file,
11791260 parent_scope,
1261 parent_line,
11801262 extra.data.rhs,
11811263 false,
11821264 );
......@@ -1220,7 +1302,6 @@ fn walkInstruction(
12201302 .trunc,
12211303 .round,
12221304 .tag_name,
1223 .reify,
12241305 .type_name,
12251306 .frame_type,
12261307 .frame_size,
......@@ -1238,7 +1319,7 @@ fn walkInstruction(
12381319 const un_node = data[inst_index].un_node;
12391320 const bin_index = self.exprs.items.len;
12401321 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
12431324 const param_index = self.exprs.items.len;
12441325 try self.exprs.append(self.arena, param.expr);
......@@ -1287,12 +1368,14 @@ fn walkInstruction(
12871368 var lhs: DocData.WalkResult = try self.walkRef(
12881369 file,
12891370 parent_scope,
1371 parent_line,
12901372 extra.data.lhs,
12911373 false,
12921374 );
12931375 var rhs: DocData.WalkResult = try self.walkRef(
12941376 file,
12951377 parent_scope,
1378 parent_line,
12961379 extra.data.rhs,
12971380 false,
12981381 );
......@@ -1315,12 +1398,14 @@ fn walkInstruction(
13151398 var lhs: DocData.WalkResult = try self.walkRef(
13161399 file,
13171400 parent_scope,
1401 parent_line,
13181402 extra.data.lhs,
13191403 false,
13201404 );
13211405 var rhs: DocData.WalkResult = try self.walkRef(
13221406 file,
13231407 parent_scope,
1408 parent_line,
13241409 extra.data.rhs,
13251410 false,
13261411 );
......@@ -1343,12 +1428,14 @@ fn walkInstruction(
13431428 var lhs: DocData.WalkResult = try self.walkRef(
13441429 file,
13451430 parent_scope,
1431 parent_line,
13461432 extra.data.lhs,
13471433 false,
13481434 );
13491435 var rhs: DocData.WalkResult = try self.walkRef(
13501436 file,
13511437 parent_scope,
1438 parent_line,
13521439 extra.data.rhs,
13531440 false,
13541441 );
......@@ -1368,7 +1455,7 @@ fn walkInstruction(
13681455
13691456 // var operand: DocData.WalkResult = try self.walkRef(
13701457 // file,
1371 // parent_scope,
1458 // parent_scope, parent_line,
13721459 // un_node.operand,
13731460 // false,
13741461 // );
......@@ -1377,7 +1464,7 @@ fn walkInstruction(
13771464 // },
13781465 .overflow_arithmetic_ptr => {
13791466 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);
13811468 const type_slot_index = self.types.items.len;
13821469 try self.types.append(self.arena, .{
13831470 .Pointer = .{
......@@ -1402,6 +1489,7 @@ fn walkInstruction(
14021489 const elem_type_ref = try self.walkRef(
14031490 file,
14041491 parent_scope,
1492 parent_line,
14051493 extra.data.elem_type,
14061494 false,
14071495 );
......@@ -1411,7 +1499,7 @@ fn walkInstruction(
14111499 var sentinel: ?DocData.Expr = null;
14121500 if (ptr.flags.has_sentinel) {
14131501 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);
14151503 sentinel = ref_result.expr;
14161504 extra_index += 1;
14171505 }
......@@ -1419,21 +1507,21 @@ fn walkInstruction(
14191507 var @"align": ?DocData.Expr = null;
14201508 if (ptr.flags.has_align) {
14211509 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);
14231511 @"align" = ref_result.expr;
14241512 extra_index += 1;
14251513 }
14261514 var address_space: ?DocData.Expr = null;
14271515 if (ptr.flags.has_addrspace) {
14281516 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);
14301518 address_space = ref_result.expr;
14311519 extra_index += 1;
14321520 }
14331521 var bit_start: ?DocData.Expr = null;
14341522 if (ptr.flags.has_bit_range) {
14351523 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);
14371525 address_space = ref_result.expr;
14381526 extra_index += 1;
14391527 }
......@@ -1441,7 +1529,7 @@ fn walkInstruction(
14411529 var host_size: ?DocData.Expr = null;
14421530 if (ptr.flags.has_bit_range) {
14431531 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);
14451533 host_size = ref_result.expr;
14461534 }
14471535
......@@ -1471,8 +1559,8 @@ fn walkInstruction(
14711559 .array_type => {
14721560 const pl_node = data[inst_index].pl_node;
14731561 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);
1475 const child = try self.walkRef(file, parent_scope, bin.rhs, false);
1562 const len = try self.walkRef(file, parent_scope, parent_line, bin.lhs, false);
1563 const child = try self.walkRef(file, parent_scope, parent_line, bin.rhs, false);
14761564
14771565 const type_slot_index = self.types.items.len;
14781566 try self.types.append(self.arena, .{
......@@ -1490,9 +1578,9 @@ fn walkInstruction(
14901578 .array_type_sentinel => {
14911579 const pl_node = data[inst_index].pl_node;
14921580 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);
1494 const sentinel = try self.walkRef(file, parent_scope, extra.data.sentinel, false);
1495 const elem_type = try self.walkRef(file, parent_scope, extra.data.elem_type, false);
1581 const len = try self.walkRef(file, parent_scope, parent_line, extra.data.len, false);
1582 const sentinel = try self.walkRef(file, parent_scope, parent_line, extra.data.sentinel, false);
1583 const elem_type = try self.walkRef(file, parent_scope, parent_line, extra.data.elem_type, false);
14961584
14971585 const type_slot_index = self.types.items.len;
14981586 try self.types.append(self.arena, .{
......@@ -1514,10 +1602,10 @@ fn walkInstruction(
15141602 const array_data = try self.arena.alloc(usize, operands.len - 1);
15151603
15161604 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
15191607 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);
15211609 const expr_index = self.exprs.items.len;
15221610 try self.exprs.append(self.arena, wr.expr);
15231611 array_data[idx] = expr_index;
......@@ -1535,7 +1623,7 @@ fn walkInstruction(
15351623 const array_data = try self.arena.alloc(usize, operands.len);
15361624
15371625 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);
15391627 const expr_index = self.exprs.items.len;
15401628 try self.exprs.append(self.arena, wr.expr);
15411629 array_data[idx] = expr_index;
......@@ -1553,10 +1641,10 @@ fn walkInstruction(
15531641 const array_data = try self.arena.alloc(usize, operands.len - 1);
15541642
15551643 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
15581646 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);
15601648 const expr_index = self.exprs.items.len;
15611649 try self.exprs.append(self.arena, wr.expr);
15621650 array_data[idx] = expr_index;
......@@ -1585,7 +1673,7 @@ fn walkInstruction(
15851673 const array_data = try self.arena.alloc(usize, operands.len);
15861674
15871675 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);
15891677 const expr_index = self.exprs.items.len;
15901678 try self.exprs.append(self.arena, wr.expr);
15911679 array_data[idx] = expr_index;
......@@ -1620,6 +1708,7 @@ fn walkInstruction(
16201708 var operand: DocData.WalkResult = try self.walkRef(
16211709 file,
16221710 parent_scope,
1711 parent_line,
16231712 un_node.operand,
16241713 need_type,
16251714 );
......@@ -1641,6 +1730,7 @@ fn walkInstruction(
16411730 const operand = try self.walkRef(
16421731 file,
16431732 parent_scope,
1733 parent_line,
16441734 un_node.operand,
16451735 false,
16461736 );
......@@ -1657,6 +1747,7 @@ fn walkInstruction(
16571747 const operand = try self.walkRef(
16581748 file,
16591749 parent_scope,
1750 parent_line,
16601751 un_node.operand,
16611752 need_type,
16621753 );
......@@ -1674,6 +1765,7 @@ fn walkInstruction(
16741765 const operand = try self.walkRef(
16751766 file,
16761767 parent_scope,
1768 parent_line,
16771769 un_node.operand,
16781770 false,
16791771 );
......@@ -1690,7 +1782,7 @@ fn walkInstruction(
16901782 const pl_node = data[inst_index].pl_node;
16911783 const extra = file.zir.extraData(Zir.Inst.SwitchBlock, pl_node.payload_index);
16921784 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
16951787 const ast_index = self.ast_nodes.items.len;
16961788 const type_index = self.types.items.len - 1;
......@@ -1718,6 +1810,7 @@ fn walkInstruction(
17181810 const operand = try self.walkRef(
17191811 file,
17201812 parent_scope,
1813 parent_line,
17211814 un_node.operand,
17221815 need_type,
17231816 );
......@@ -1743,6 +1836,7 @@ fn walkInstruction(
17431836 const operand = try self.walkRef(
17441837 file,
17451838 parent_scope,
1839 parent_line,
17461840 un_node.operand,
17471841 need_type,
17481842 );
......@@ -1762,6 +1856,7 @@ fn walkInstruction(
17621856 var operand: DocData.WalkResult = try self.walkRef(
17631857 file,
17641858 parent_scope,
1859 parent_line,
17651860 data[body].@"break".operand,
17661861 false,
17671862 );
......@@ -1780,6 +1875,7 @@ fn walkInstruction(
17801875 const operand = try self.walkRef(
17811876 file,
17821877 parent_scope,
1878 parent_line,
17831879 un_node.operand,
17841880 need_type,
17851881 );
......@@ -1798,6 +1894,7 @@ fn walkInstruction(
17981894 const dest_type_walk = try self.walkRef(
17991895 file,
18001896 parent_scope,
1897 parent_line,
18011898 extra.data.dest_type,
18021899 false,
18031900 );
......@@ -1805,6 +1902,7 @@ fn walkInstruction(
18051902 const operand = try self.walkRef(
18061903 file,
18071904 parent_scope,
1905 parent_line,
18081906 extra.data.operand,
18091907 false,
18101908 );
......@@ -1832,6 +1930,7 @@ fn walkInstruction(
18321930 const operand: DocData.WalkResult = try self.walkRef(
18331931 file,
18341932 parent_scope,
1933 parent_line,
18351934 un_node.operand,
18361935 false,
18371936 );
......@@ -1863,31 +1962,60 @@ fn walkInstruction(
18631962 const extra = file.zir.extraData(Zir.Inst.Field, pl_node.payload_index);
18641963
18651964 var path: std.ArrayListUnmanaged(DocData.Expr) = .{};
1866 var lhs = @enumToInt(extra.data.lhs) - Ref.typed_value_map.len; // underflow = need to handle Refs
1867
18681965 try path.append(self.arena, .{
18691966 .string = file.zir.nullTerminatedString(extra.data.field_name_start),
18701967 });
1968
18711969 // Put inside path the starting index of each decl name that
1872 // we encounter as we navigate through all the field_vals
1873 while (tags[lhs] == .field_val or
1874 tags[lhs] == .field_call_bind or
1875 tags[lhs] == .field_ptr or
1876 tags[lhs] == .field_type)
1877 {
1878 const lhs_extra = file.zir.extraData(
1879 Zir.Inst.Field,
1880 data[lhs].pl_node.payload_index,
1881 );
1970 // we encounter as we navigate through all the field_*s
1971 const lhs_ref = blk: {
1972 var lhs_extra = extra;
1973 while (true) {
1974 if (@enumToInt(lhs_extra.data.lhs) < Ref.typed_value_map.len) {
1975 break :blk lhs_extra.data.lhs;
1976 }
18821977
1883 try path.append(self.arena, .{
1884 .string = file.zir.nullTerminatedString(lhs_extra.data.field_name_start),
1885 });
1886 lhs = @enumToInt(lhs_extra.data.lhs) - Ref.typed_value_map.len; // underflow = need to handle Refs
1887 }
1978 const lhs = @enumToInt(lhs_extra.data.lhs) - Ref.typed_value_map.len;
1979 if (tags[lhs] != .field_val and
1980 tags[lhs] != .field_call_bind and
1981 tags[lhs] != .field_ptr and
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.
18892003 // 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 };
18912019 try path.append(self.arena, wr.expr);
18922020
18932021 // This way the data in `path` has the same ordering that the ref
......@@ -1906,7 +2034,7 @@ fn walkInstruction(
19062034 // - (2) Paths can sometimes never resolve fully. This means that
19072035 // any value that depends on that will have to become a
19082036 // comptimeExpr.
1909 try self.tryResolveRefPath(file, lhs, path.items);
2037 try self.tryResolveRefPath(file, inst_index, path.items);
19102038 return DocData.WalkResult{ .expr = .{ .refPath = path.items } };
19112039 },
19122040 .int_type => {
......@@ -1937,6 +2065,7 @@ fn walkInstruction(
19372065 return self.walkRef(
19382066 file,
19392067 parent_scope,
2068 parent_line,
19402069 getBlockInlineBreak(file.zir, inst_index),
19412070 need_type,
19422071 );
......@@ -1969,6 +2098,7 @@ fn walkInstruction(
19692098 const wr = try self.walkRef(
19702099 file,
19712100 parent_scope,
2101 parent_line,
19722102 field_extra.data.container_type,
19732103 false,
19742104 );
......@@ -1979,6 +2109,7 @@ fn walkInstruction(
19792109 const value = try self.walkRef(
19802110 file,
19812111 parent_scope,
2112 parent_line,
19822113 init_extra.data.init,
19832114 need_type,
19842115 );
......@@ -1995,6 +2126,7 @@ fn walkInstruction(
19952126 var operand: DocData.WalkResult = try self.walkRef(
19962127 file,
19972128 parent_scope,
2129 parent_line,
19982130 un_node.operand,
19992131 false,
20002132 );
......@@ -2011,6 +2143,34 @@ fn walkInstruction(
20112143 );
20122144 return self.cteTodo(@tagName(tags[inst_index]));
20132145 },
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 },
20142174 .error_set_decl => {
20152175 const pl_node = data[inst_index].pl_node;
20162176 const extra = file.zir.extraData(Zir.Inst.ErrorSetDecl, pl_node.payload_index);
......@@ -2075,18 +2235,23 @@ fn walkInstruction(
20752235 const pl_node = data[inst_index].pl_node;
20762236 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
20802240 const args_len = extra.data.flags.args_len;
20812241 var args = try self.arena.alloc(DocData.Expr, args_len);
2082 const arg_refs = file.zir.refSlice(extra.end, args_len);
2083 for (arg_refs) |ref, idx| {
2242 const body = file.zir.extra[extra.end..];
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;
20842249 // TODO: consider toggling need_type to true if we ever want
20852250 // to show discrepancies between the types of provided
20862251 // arguments and the types declared in the function
20872252 // signature for its parameters.
2088 const wr = try self.walkRef(file, parent_scope, ref, false);
2089 args[idx] = wr.expr;
2253 const wr = try self.walkRef(file, parent_scope, parent_line, ref, false);
2254 args[i] = wr.expr;
20902255 }
20912256
20922257 const cte_slot_index = self.comptime_exprs.items.len;
......@@ -2116,6 +2281,7 @@ fn walkInstruction(
21162281 const result = self.analyzeFunction(
21172282 file,
21182283 parent_scope,
2284 parent_line,
21192285 inst_index,
21202286 self_ast_node_index,
21212287 type_slot_index,
......@@ -2131,6 +2297,7 @@ fn walkInstruction(
21312297 const result = self.analyzeFancyFunction(
21322298 file,
21332299 parent_scope,
2300 parent_line,
21342301 inst_index,
21352302 self_ast_node_index,
21362303 type_slot_index,
......@@ -2158,7 +2325,7 @@ fn walkInstruction(
21582325
21592326 var array_type: ?DocData.Expr = null;
21602327 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);
21622329 if (idx == 0) {
21632330 array_type = wr.typeRef;
21642331 }
......@@ -2303,6 +2470,7 @@ fn walkInstruction(
23032470 extra_index = try self.walkDecls(
23042471 file,
23052472 &scope,
2473 parent_line,
23062474 decls_first_index,
23072475 decls_len,
23082476 &decl_indexes,
......@@ -2323,6 +2491,7 @@ fn walkInstruction(
23232491 try self.collectUnionFieldInfo(
23242492 file,
23252493 &scope,
2494 parent_line,
23262495 fields_len,
23272496 &field_type_refs,
23282497 &field_name_indexes,
......@@ -2423,6 +2592,7 @@ fn walkInstruction(
24232592 extra_index = try self.walkDecls(
24242593 file,
24252594 &scope,
2595 parent_line,
24262596 decls_first_index,
24272597 decls_len,
24282598 &decl_indexes,
......@@ -2532,6 +2702,17 @@ fn walkInstruction(
25322702 break :blk decls_len;
25332703 } 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
25352716 var decl_indexes: std.ArrayListUnmanaged(usize) = .{};
25362717 var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};
25372718
......@@ -2555,6 +2736,7 @@ fn walkInstruction(
25552736 extra_index = try self.walkDecls(
25562737 file,
25572738 &scope,
2739 parent_line,
25582740 decls_first_index,
25592741 decls_len,
25602742 &decl_indexes,
......@@ -2567,6 +2749,7 @@ fn walkInstruction(
25672749 try self.collectStructFieldInfo(
25682750 file,
25692751 &scope,
2752 parent_line,
25702753 fields_len,
25712754 &field_type_refs,
25722755 &field_name_indexes,
......@@ -2605,11 +2788,12 @@ fn walkInstruction(
26052788 },
26062789 .error_to_int,
26072790 .int_to_error,
2791 .reify,
26082792 => {
26092793 const extra = file.zir.extraData(Zir.Inst.UnNode, extended.operand).data;
26102794 const bin_index = self.exprs.items.len;
26112795 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
26142798 const param_index = self.exprs.items.len;
26152799 try self.exprs.append(self.arena, param.expr);
......@@ -2637,6 +2821,7 @@ fn walkDecls(
26372821 self: *Autodoc,
26382822 file: *File,
26392823 scope: *Scope,
2824 parent_line: usize,
26402825 decls_first_index: usize,
26412826 decls_len: u32,
26422827 decl_indexes: *std.ArrayListUnmanaged(usize),
......@@ -2669,7 +2854,7 @@ fn walkDecls(
26692854
26702855 // const hash_u32s = file.zir.extra[extra_index..][0..4];
26712856 extra_index += 4;
2672 const line = file.zir.extra[extra_index];
2857 const line = parent_line + file.zir.extra[extra_index];
26732858 extra_index += 1;
26742859 const decl_name_index = file.zir.extra[extra_index];
26752860 extra_index += 1;
......@@ -2808,7 +2993,7 @@ fn walkDecls(
28082993 const ast_node_index = idx: {
28092994 const idx = self.ast_nodes.items.len;
28102995 try self.ast_nodes.append(self.arena, .{
2811 .file = 0,
2996 .file = self.files.getIndex(file) orelse unreachable,
28122997 .line = line,
28132998 .col = 0,
28142999 .docs = doc_comment,
......@@ -2820,7 +3005,7 @@ fn walkDecls(
28203005 const walk_result = if (is_test) // TODO: decide if tests should show up at all
28213006 DocData.WalkResult{ .expr = .{ .void = .{} } }
28223007 else
2823 try self.walkInstruction(file, scope, value_index, true);
3008 try self.walkInstruction(file, scope, line, value_index, true);
28243009
28253010 if (is_pub) {
28263011 try decl_indexes.append(self.arena, decls_slot_index);
......@@ -3013,6 +3198,10 @@ fn tryResolveRefPath(
30133198 .{ @tagName(self.types.items[t_index]), resolved_parent },
30143199 );
30153200 },
3201 .ComptimeExpr => {
3202 // Same as the comptimeExpr branch above
3203 break :outer;
3204 },
30163205 .Unanalyzed => {
30173206 // This decl path is pending completion
30183207 {
......@@ -3035,6 +3224,20 @@ fn tryResolveRefPath(
30353224
30363225 return;
30373226 },
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 },
30383241 .Enum => |t_enum| {
30393242 for (t_enum.pubDecls) |d| {
30403243 // TODO: this could be improved a lot
......@@ -3198,6 +3401,7 @@ fn analyzeFancyFunction(
31983401 self: *Autodoc,
31993402 file: *File,
32003403 scope: *Scope,
3404 parent_line: usize,
32013405 inst_index: usize,
32023406 self_ast_node_index: usize,
32033407 type_slot_index: usize,
......@@ -3262,7 +3466,7 @@ fn analyzeFancyFunction(
32623466
32633467 const break_index = file.zir.extra[extra.end..][extra.data.body_len - 1];
32643468 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
32673471 param_type_refs.appendAssumeCapacity(param_type_ref.expr);
32683472 },
......@@ -3286,7 +3490,7 @@ fn analyzeFancyFunction(
32863490 if (extra.data.bits.has_align_ref) {
32873491 const align_ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
32883492 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);
32903494 extra_index += 1;
32913495 } else if (extra.data.bits.has_align_body) {
32923496 const align_body_len = file.zir.extra[extra_index];
......@@ -3303,7 +3507,7 @@ fn analyzeFancyFunction(
33033507 if (extra.data.bits.has_addrspace_ref) {
33043508 const addrspace_ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
33053509 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);
33073511 extra_index += 1;
33083512 } else if (extra.data.bits.has_addrspace_body) {
33093513 const addrspace_body_len = file.zir.extra[extra_index];
......@@ -3320,7 +3524,7 @@ fn analyzeFancyFunction(
33203524 if (extra.data.bits.has_section_ref) {
33213525 const section_ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
33223526 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);
33243528 extra_index += 1;
33253529 } else if (extra.data.bits.has_section_body) {
33263530 const section_body_len = file.zir.extra[extra_index];
......@@ -3337,7 +3541,7 @@ fn analyzeFancyFunction(
33373541 if (extra.data.bits.has_cc_ref) {
33383542 const cc_ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
33393543 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);
33413545 extra_index += 1;
33423546 } else if (extra.data.bits.has_cc_body) {
33433547 const cc_body_len = file.zir.extra[extra_index];
......@@ -3356,14 +3560,14 @@ fn analyzeFancyFunction(
33563560 .none => DocData.Expr{ .void = .{} },
33573561 else => blk: {
33583562 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);
33603564 break :blk wr.expr;
33613565 },
33623566 },
33633567 else => blk: {
33643568 const last_instr_index = fn_info.ret_ty_body[fn_info.ret_ty_body.len - 1];
33653569 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);
33673571 break :blk wr.expr;
33683572 },
33693573 };
......@@ -3378,6 +3582,7 @@ fn analyzeFancyFunction(
33783582 break :blk try self.getGenericReturnType(
33793583 file,
33803584 scope,
3585 parent_line,
33813586 fn_info.body[fn_info.body.len - 1],
33823587 );
33833588 } else {
......@@ -3414,6 +3619,7 @@ fn analyzeFunction(
34143619 self: *Autodoc,
34153620 file: *File,
34163621 scope: *Scope,
3622 parent_line: usize,
34173623 inst_index: usize,
34183624 self_ast_node_index: usize,
34193625 type_slot_index: usize,
......@@ -3479,7 +3685,7 @@ fn analyzeFunction(
34793685
34803686 const break_index = file.zir.extra[extra.end..][extra.data.body_len - 1];
34813687 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
34843690 param_type_refs.appendAssumeCapacity(param_type_ref.expr);
34853691 },
......@@ -3492,14 +3698,14 @@ fn analyzeFunction(
34923698 .none => DocData.Expr{ .void = .{} },
34933699 else => blk: {
34943700 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);
34963702 break :blk wr.expr;
34973703 },
34983704 },
34993705 else => blk: {
35003706 const last_instr_index = fn_info.ret_ty_body[fn_info.ret_ty_body.len - 1];
35013707 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);
35033709 break :blk wr.expr;
35043710 },
35053711 };
......@@ -3514,6 +3720,7 @@ fn analyzeFunction(
35143720 break :blk try self.getGenericReturnType(
35153721 file,
35163722 scope,
3723 parent_line,
35173724 fn_info.body[fn_info.body.len - 1],
35183725 );
35193726 } else {
......@@ -3554,9 +3761,11 @@ fn getGenericReturnType(
35543761 self: *Autodoc,
35553762 file: *File,
35563763 scope: *Scope,
3764 parent_line: usize, // function decl line
35573765 body_end: usize,
35583766) !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);
35603769 return wr.expr;
35613770}
35623771
......@@ -3564,6 +3773,7 @@ fn collectUnionFieldInfo(
35643773 self: *Autodoc,
35653774 file: *File,
35663775 scope: *Scope,
3776 parent_line: usize,
35673777 fields_len: usize,
35683778 field_type_refs: *std.ArrayListUnmanaged(DocData.Expr),
35693779 field_name_indexes: *std.ArrayListUnmanaged(usize),
......@@ -3610,7 +3820,7 @@ fn collectUnionFieldInfo(
36103820
36113821 // type
36123822 {
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);
36143824 try field_type_refs.append(self.arena, walk_result.expr);
36153825 }
36163826
......@@ -3633,6 +3843,7 @@ fn collectStructFieldInfo(
36333843 self: *Autodoc,
36343844 file: *File,
36353845 scope: *Scope,
3846 parent_line: usize,
36363847 fields_len: usize,
36373848 field_type_refs: *std.ArrayListUnmanaged(DocData.Expr),
36383849 field_name_indexes: *std.ArrayListUnmanaged(usize),
......@@ -3706,7 +3917,7 @@ fn collectStructFieldInfo(
37063917 for (fields) |field| {
37073918 const type_expr = expr: {
37083919 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);
37103921 break :expr walk_result.expr;
37113922 }
37123923
......@@ -3716,7 +3927,7 @@ fn collectStructFieldInfo(
37163927
37173928 const break_inst = body[body.len - 1];
37183929 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);
37203931 break :expr walk_result.expr;
37213932 };
37223933
......@@ -3746,6 +3957,7 @@ fn walkRef(
37463957 self: *Autodoc,
37473958 file: *File,
37483959 parent_scope: *Scope,
3960 parent_line: usize,
37493961 ref: Ref,
37503962 need_type: bool, // true when the caller needs also a typeRef for the return value
37513963) AutodocErrors!DocData.WalkResult {
......@@ -3761,9 +3973,12 @@ fn walkRef(
37613973 } else if (enum_value < Ref.typed_value_map.len) {
37623974 switch (ref) {
37633975 else => {
3764 std.debug.panic("TODO: handle {s} in `walkRef`\n", .{
3765 @tagName(ref),
3766 });
3976 panicWithContext(
3977 file,
3978 0,
3979 "TODO: handle {s} in walkRef",
3980 .{@tagName(ref)},
3981 );
37673982 },
37683983 .undef => {
37693984 return DocData.WalkResult{ .expr = .@"undefined" };
......@@ -3854,7 +4069,7 @@ fn walkRef(
38544069 }
38554070 } else {
38564071 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);
38584073 }
38594074}
38604075
......@@ -3886,13 +4101,13 @@ fn cteTodo(self: *Autodoc, msg: []const u8) error{OutOfMemory}!DocData.WalkResul
38864101}
38874102
38884103fn writeFileTableToJson(map: std.AutoArrayHashMapUnmanaged(*File, usize), jsw: anytype) !void {
3889 try jsw.beginObject();
4104 try jsw.beginArray();
38904105 var it = map.iterator();
38914106 while (it.next()) |entry| {
3892 try jsw.objectField(entry.key_ptr.*.sub_file_path);
3893 try jsw.emitNumber(entry.value_ptr.*);
4107 try jsw.arrayElem();
4108 try jsw.emitString(entry.key_ptr.*.sub_file_path);
38944109 }
3895 try jsw.endObject();
4110 try jsw.endArray();
38964111}
38974112
38984113fn writePackageTableToJson(
src/BuiltinFn.zig+5-5
......@@ -250,14 +250,14 @@ pub const list = list: {
250250 "@byteSwap",
251251 .{
252252 .tag = .byte_swap,
253 .param_count = 2,
253 .param_count = 1,
254254 },
255255 },
256256 .{
257257 "@bitReverse",
258258 .{
259259 .tag = .bit_reverse,
260 .param_count = 2,
260 .param_count = 1,
261261 },
262262 },
263263 .{
......@@ -301,7 +301,7 @@ pub const list = list: {
301301 "@clz",
302302 .{
303303 .tag = .clz,
304 .param_count = 2,
304 .param_count = 1,
305305 },
306306 },
307307 .{
......@@ -336,7 +336,7 @@ pub const list = list: {
336336 "@ctz",
337337 .{
338338 .tag = .ctz,
339 .param_count = 2,
339 .param_count = 1,
340340 },
341341 },
342342 .{
......@@ -614,7 +614,7 @@ pub const list = list: {
614614 "@popCount",
615615 .{
616616 .tag = .pop_count,
617 .param_count = 2,
617 .param_count = 1,
618618 },
619619 },
620620 .{
src/Compilation.zig+151-114
......@@ -173,6 +173,7 @@ astgen_wait_group: WaitGroup = .{},
173173/// TODO: Remove this when Stage2 becomes the default compiler as it will already have this information.
174174export_symbol_names: std.ArrayListUnmanaged([]const u8) = .{},
175175
176pub const default_stack_protector_buffer_size = 4;
176177pub const SemaError = Module.SemaError;
177178
178179pub const CRTFile = struct {
......@@ -810,7 +811,6 @@ pub const InitOptions = struct {
810811 /// this flag would be set to disable this machinery to avoid false positives.
811812 disable_lld_caching: bool = false,
812813 cache_mode: CacheMode = .incremental,
813 object_format: ?std.Target.ObjectFormat = null,
814814 optimize_mode: std.builtin.Mode = .Debug,
815815 keep_source_files_loaded: bool = false,
816816 clang_argv: []const []const u8 = &[0][]const u8{},
......@@ -838,6 +838,10 @@ pub const InitOptions = struct {
838838 want_pie: ?bool = null,
839839 want_sanitize_c: ?bool = null,
840840 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,
841845 want_red_zone: ?bool = null,
842846 omit_frame_pointer: ?bool = null,
843847 want_valgrind: ?bool = null,
......@@ -1015,6 +1019,15 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
10151019 return error.ExportTableAndImportTableConflict;
10161020 }
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
10181031 const comp: *Compilation = comp: {
10191032 // For allocations that have the same lifetime as Compilation. This arena is used only during this
10201033 // initialization and then is freed in deinit().
......@@ -1027,22 +1040,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
10271040 const comp = try arena.create(Compilation);
10281041 const root_name = try arena.dupeZ(u8, options.root_name);
10291042
1030 const ofmt = options.object_format orelse options.target.getObjectFormat();
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 };
1043 const use_stage1 = options.use_stage1 orelse false;
10461044
10471045 const cache_mode = if (use_stage1 and !options.disable_lld_caching)
10481046 CacheMode.whole
......@@ -1068,7 +1066,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
10681066 break :blk true;
10691067
10701068 // 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))
10721070 break :blk false;
10731071
10741072 // Prefer LLVM for release builds.
......@@ -1111,7 +1109,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
11111109 if (!build_options.have_llvm)
11121110 break :blk false;
11131111
1114 if (ofmt == .c)
1112 if (options.target.ofmt == .c)
11151113 break :blk false;
11161114
11171115 if (options.want_lto) |lto| {
......@@ -1167,9 +1165,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
11671165 break :blk false;
11681166 } else if (options.c_source_files.len == 0) {
11691167 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;
11731168 } else if (options.target.cpu.arch.isRISCV()) {
11741169 // Clang and LLVM currently don't support RISC-V target-abi for LTO.
11751170 // Compiling with LTO may fail or produce undesired results.
......@@ -1233,7 +1228,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
12331228 break :blk lm;
12341229 } 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
12381233 const libc_dirs = try detectLibCIncludeDirs(
12391234 arena,
......@@ -1288,11 +1283,36 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
12881283
12891284 const sanitize_c = options.want_sanitize_c orelse is_safe_mode;
12901285
1291 const stack_check: bool = b: {
1292 if (!target_util.supportsStackProbing(options.target))
1293 break :b false;
1294 break :b options.want_stack_check orelse is_safe_mode;
1286 const stack_check: bool = options.want_stack_check orelse b: {
1287 if (!target_util.supportsStackProbing(options.target)) break :b false;
1288 break :b 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;
12951307 };
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
12971317 const valgrind: bool = b: {
12981318 if (!target_util.hasValgrindSupport(options.target))
......@@ -1370,13 +1390,14 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
13701390 cache.hash.add(options.target.os.getVersionRange());
13711391 cache.hash.add(options.is_native_os);
13721392 cache.hash.add(options.target.abi);
1373 cache.hash.add(ofmt);
1393 cache.hash.add(options.target.ofmt);
13741394 cache.hash.add(pic);
13751395 cache.hash.add(pie);
13761396 cache.hash.add(lto);
13771397 cache.hash.add(unwind_tables);
13781398 cache.hash.add(tsan);
13791399 cache.hash.add(stack_check);
1400 cache.hash.add(stack_protector);
13801401 cache.hash.add(red_zone);
13811402 cache.hash.add(omit_frame_pointer);
13821403 cache.hash.add(link_mode);
......@@ -1678,7 +1699,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
16781699 .sysroot = sysroot,
16791700 .output_mode = options.output_mode,
16801701 .link_mode = link_mode,
1681 .object_format = ofmt,
16821702 .optimize_mode = options.optimize_mode,
16831703 .use_lld = use_lld,
16841704 .use_llvm = use_llvm,
......@@ -1741,6 +1761,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
17411761 .valgrind = valgrind,
17421762 .tsan = tsan,
17431763 .stack_check = stack_check,
1764 .stack_protector = stack_protector,
17441765 .red_zone = red_zone,
17451766 .omit_frame_pointer = omit_frame_pointer,
17461767 .single_threaded = single_threaded,
......@@ -1769,6 +1790,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
17691790 .headerpad_size = options.headerpad_size,
17701791 .headerpad_max_install_names = options.headerpad_max_install_names,
17711792 .dead_strip_dylibs = options.dead_strip_dylibs,
1793 .force_undefined_symbols = .{},
17721794 });
17731795 errdefer bin_file.destroy();
17741796 comp.* = .{
......@@ -1822,6 +1844,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
18221844 };
18231845 errdefer comp.destroy();
18241846
1847 const target = comp.getTarget();
1848
18251849 // Add a `CObject` for each `c_source_files`.
18261850 try comp.c_object_table.ensureTotalCapacity(gpa, options.c_source_files.len);
18271851 for (options.c_source_files) |c_source_file| {
......@@ -1837,9 +1861,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
18371861
18381862 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) {
1841 if (comp.getTarget().isDarwin()) {
1842 switch (comp.getTarget().abi) {
1864 if (have_bin_emit and !comp.bin_file.options.skip_linker_dependencies and target.ofmt != .c) {
1865 if (target.isDarwin()) {
1866 switch (target.abi) {
18431867 .none,
18441868 .simulator,
18451869 .macabi,
......@@ -1850,9 +1874,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
18501874 // If we need to build glibc for the target, add work items for it.
18511875 // We go through the work queue so that building can be done in parallel.
18521876 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)) {
18561880 try comp.work_queue.write(&[_]Job{
18571881 .{ .glibc_crt_file = .crti_o },
18581882 .{ .glibc_crt_file = .crtn_o },
......@@ -1865,10 +1889,10 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
18651889 });
18661890 }
18671891 if (comp.wantBuildMuslFromSource()) {
1868 if (!target_util.canBuildLibC(comp.getTarget())) return error.LibCUnavailable;
1892 if (!target_util.canBuildLibC(target)) return error.LibCUnavailable;
18691893
18701894 try comp.work_queue.ensureUnusedCapacity(6);
1871 if (musl.needsCrtiCrtn(comp.getTarget())) {
1895 if (musl.needsCrtiCrtn(target)) {
18721896 comp.work_queue.writeAssumeCapacity(&[_]Job{
18731897 .{ .musl_crt_file = .crti_o },
18741898 .{ .musl_crt_file = .crtn_o },
......@@ -1885,7 +1909,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
18851909 });
18861910 }
18871911 if (comp.wantBuildWasiLibcFromSource()) {
1888 if (!target_util.canBuildLibC(comp.getTarget())) return error.LibCUnavailable;
1912 if (!target_util.canBuildLibC(target)) return error.LibCUnavailable;
18891913
18901914 const wasi_emulated_libs = comp.bin_file.options.wasi_emulated_libs;
18911915 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 {
19001924 });
19011925 }
19021926 if (comp.wantBuildMinGWFromSource()) {
1903 if (!target_util.canBuildLibC(comp.getTarget())) return error.LibCUnavailable;
1927 if (!target_util.canBuildLibC(target)) return error.LibCUnavailable;
19041928
19051929 const static_lib_jobs = [_]Job{
19061930 .{ .mingw_crt_file = .mingw32_lib },
......@@ -1917,9 +1941,13 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
19171941 for (mingw.always_link_libs) |name| {
19181942 try comp.bin_file.options.system_libs.put(comp.gpa, name, .{});
19191943 }
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", {});
19201948 }
19211949 // Generate Windows import libs.
1922 if (comp.getTarget().os.tag == .windows) {
1950 if (target.os.tag == .windows) {
19231951 const count = comp.bin_file.options.system_libs.count();
19241952 try comp.work_queue.ensureUnusedCapacity(count);
19251953 var i: usize = 0;
......@@ -1938,15 +1966,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
19381966 try comp.work_queue.writeItem(.libtsan);
19391967 }
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
19501969 if (comp.bin_file.options.include_compiler_rt and capable_of_building_compiler_rt) {
19511970 if (is_exe_or_dyn_lib) {
19521971 log.debug("queuing a job to build compiler_rt_lib", .{});
......@@ -1960,8 +1979,11 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
19601979 }
19611980 }
19621981 if (needs_c_symbols) {
1963 // MinGW provides no libssp, use our own implementation.
1964 if (comp.getTarget().isMinGW() and capable_of_building_ssp) {
1982 // Related: https://github.com/ziglang/zig/issues/7265.
1983 if (comp.bin_file.options.stack_protector != 0 and
1984 (!comp.bin_file.options.link_libc or
1985 !target_util.libcProvidesStackProtector(target)))
1986 {
19651987 try comp.work_queue.writeItem(.{ .libssp = {} });
19661988 }
19671989
......@@ -2176,8 +2198,7 @@ pub fn update(comp: *Compilation) !void {
21762198 comp.c_object_work_queue.writeItemAssumeCapacity(key);
21772199 }
21782200
2179 const use_stage1 = build_options.omit_stage2 or
2180 (build_options.is_stage1 and comp.bin_file.options.use_stage1);
2201 const use_stage1 = build_options.have_stage1 and comp.bin_file.options.use_stage1;
21812202 if (comp.bin_file.options.module) |module| {
21822203 module.compile_log_text.shrinkAndFree(module.gpa, 0);
21832204 module.generation += 1;
......@@ -2353,8 +2374,7 @@ fn flush(comp: *Compilation, prog_node: *std.Progress.Node) !void {
23532374 };
23542375 comp.link_error_flags = comp.bin_file.errorFlags();
23552376
2356 const use_stage1 = build_options.omit_stage2 or
2357 (build_options.is_stage1 and comp.bin_file.options.use_stage1);
2377 const use_stage1 = build_options.have_stage1 and comp.bin_file.options.use_stage1;
23582378 if (!use_stage1) {
23592379 if (comp.bin_file.options.module) |module| {
23602380 try link.File.C.flushEmitH(module);
......@@ -2812,7 +2832,7 @@ pub fn performAllTheWork(
28122832 comp.work_queue_wait_group.reset();
28132833 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
28172837 {
28182838 const astgen_frame = tracy.namedFrame("astgen");
......@@ -2915,9 +2935,6 @@ pub fn performAllTheWork(
29152935fn processOneJob(comp: *Compilation, job: Job) !void {
29162936 switch (job) {
29172937 .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
29212938 const module = comp.bin_file.options.module.?;
29222939 const decl = module.declPtr(decl_index);
29232940
......@@ -2952,9 +2969,6 @@ fn processOneJob(comp: *Compilation, job: Job) !void {
29522969 }
29532970 },
29542971 .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
29582972 const named_frame = tracy.namedFrame("codegen_func");
29592973 defer named_frame.end();
29602974
......@@ -2965,9 +2979,6 @@ fn processOneJob(comp: *Compilation, job: Job) !void {
29652979 };
29662980 },
29672981 .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
29712982 const module = comp.bin_file.options.module.?;
29722983 const decl = module.declPtr(decl_index);
29732984
......@@ -3026,9 +3037,6 @@ fn processOneJob(comp: *Compilation, job: Job) !void {
30263037 }
30273038 },
30283039 .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
30323040 const module = comp.bin_file.options.module.?;
30333041 module.ensureDeclAnalyzed(decl_index) catch |err| switch (err) {
30343042 error.OutOfMemory => return error.OutOfMemory,
......@@ -3036,9 +3044,6 @@ fn processOneJob(comp: *Compilation, job: Job) !void {
30363044 };
30373045 },
30383046 .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
30423047 const named_frame = tracy.namedFrame("update_embed_file");
30433048 defer named_frame.end();
30443049
......@@ -3049,9 +3054,6 @@ fn processOneJob(comp: *Compilation, job: Job) !void {
30493054 };
30503055 },
30513056 .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
30553057 const named_frame = tracy.namedFrame("update_line_number");
30563058 defer named_frame.end();
30573059
......@@ -3070,9 +3072,6 @@ fn processOneJob(comp: *Compilation, job: Job) !void {
30703072 };
30713073 },
30723074 .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
30763075 const named_frame = tracy.namedFrame("analyze_pkg");
30773076 defer named_frame.end();
30783077
......@@ -3418,7 +3417,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult {
34183417 var man = comp.obtainCObjectCacheManifest();
34193418 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
34233422 man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects
34243423 man.hash.add(use_stage1);
......@@ -3735,7 +3734,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
37353734 else
37363735 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);
37393739 const digest = if (!comp.disable_c_depfile and try man.hit()) man.final() else blk: {
37403740 var argv = std.ArrayList([]const u8).init(comp.gpa);
37413741 defer argv.deinit();
......@@ -3755,22 +3755,67 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
37553755 };
37563756 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
37583805 // We can't know the digest until we do the C compiler invocation,
37593806 // so we need a temporary filename.
37603807 const out_obj_path = try comp.tmpFilePath(arena, o_basename);
37613808 var zig_cache_tmp_dir = try comp.local_cache_directory.handle.makeOpenPath("tmp", .{});
37623809 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);
37673811 const out_dep_path: ?[]const u8 = if (comp.disable_c_depfile or !ext.clangSupportsDepFile())
37683812 null
37693813 else
37703814 try std.fmt.allocPrint(arena, "{s}.d", .{out_obj_path});
37713815 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);
37743819 switch (comp.clang_preprocessor_mode) {
37753820 .no => argv.appendSliceAssumeCapacity(&[_][]const u8{ "-c", "-o", out_obj_path }),
37763821 .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
37853830 argv.appendAssumeCapacity("-emit-llvm");
37863831 }
37873832 }
3788 argv.appendAssumeCapacity(c_object.src.src_path);
3789 argv.appendSliceAssumeCapacity(c_object.src.extra_flags);
37903833
37913834 if (comp.verbose_cc) {
37923835 dump_argv(argv.items);
......@@ -4087,10 +4130,10 @@ pub fn addCCArgs(
40874130 }
40884131
40894132 if (!comp.bin_file.options.strip) {
4090 try argv.append("-g");
4091 switch (comp.bin_file.options.object_format) {
4133 switch (target.ofmt) {
40924134 .coff => try argv.append("-gcodeview"),
4093 else => {},
4135 .elf, .macho => try argv.append("-gdwarf-4"),
4136 else => try argv.append("-g"),
40944137 }
40954138 }
40964139
......@@ -4120,6 +4163,17 @@ pub fn addCCArgs(
41204163 try argv.append("-fno-omit-frame-pointer");
41214164 }
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
41234177 switch (comp.bin_file.options.optimize_mode) {
41244178 .Debug => {
41254179 // windows c runtime requires -D_DEBUG if using debug libraries
......@@ -4128,27 +4182,12 @@ pub fn addCCArgs(
41284182 // to -O1. Besides potentially impairing debugging, -O1/-Og significantly
41294183 // increases compile times.
41304184 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 }
41394185 },
41404186 .ReleaseSafe => {
41414187 // See the comment in the BuildModeFastRelease case for why we pass -O2 rather
41424188 // than -O3 here.
41434189 try argv.append("-O2");
4144 if (comp.bin_file.options.link_libc and target.os.tag != .wasi) {
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 }
4190 try argv.append("-D_FORTIFY_SOURCE=2");
41524191 },
41534192 .ReleaseFast => {
41544193 try argv.append("-DNDEBUG");
......@@ -4158,12 +4197,10 @@ pub fn addCCArgs(
41584197 // Zig code than it is for C code. Also, C programmers are used to their code
41594198 // running in -O2 and thus the -O3 path has been tested less.
41604199 try argv.append("-O2");
4161 try argv.append("-fno-stack-protector");
41624200 },
41634201 .ReleaseSmall => {
41644202 try argv.append("-DNDEBUG");
41654203 try argv.append("-Os");
4166 try argv.append("-fno-stack-protector");
41674204 },
41684205 }
41694206
......@@ -4656,7 +4693,7 @@ fn wantBuildLibCFromSource(comp: Compilation) bool {
46564693 };
46574694 return comp.bin_file.options.link_libc and is_exe_or_dyn_lib and
46584695 comp.bin_file.options.libc_installation == null and
4659 comp.bin_file.options.object_format != .c;
4696 comp.bin_file.options.target.ofmt != .c;
46604697}
46614698
46624699fn wantBuildGLibCFromSource(comp: Compilation) bool {
......@@ -4684,7 +4721,7 @@ fn wantBuildLibUnwindFromSource(comp: *Compilation) bool {
46844721 .Exe => true,
46854722 };
46864723 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;
46884725}
46894726
46904727fn setAllocFailure(comp: *Compilation) void {
......@@ -4738,12 +4775,12 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca
47384775
47394776 const target = comp.getTarget();
47404777 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
47434780 const zig_backend: std.builtin.CompilerBackend = blk: {
47444781 if (use_stage1) break :blk .stage1;
47454782 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;
47474784 break :blk switch (target.cpu.arch) {
47484785 .wasm32, .wasm64 => std.builtin.CompilerBackend.stage2_wasm,
47494786 .arm, .armeb, .thumb, .thumbeb => .stage2_arm,
......@@ -4763,8 +4800,6 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca
47634800 \\/// feature detection (i.e. with `@hasDecl` or `@hasField`) over version checks.
47644801 \\pub const zig_version = std.SemanticVersion.parse("{s}") catch unreachable;
47654802 \\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 = .{};
47684803 \\
47694804 \\pub const output_mode = std.builtin.OutputMode.{};
47704805 \\pub const link_mode = std.builtin.LinkMode.{};
......@@ -4779,7 +4814,6 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca
47794814 , .{
47804815 build_options.version,
47814816 std.zig.fmtId(@tagName(zig_backend)),
4782 std.zig.fmtId(@tagName(target.cpu.arch)),
47834817 std.zig.fmtId(@tagName(comp.bin_file.options.output_mode)),
47844818 std.zig.fmtId(@tagName(comp.bin_file.options.link_mode)),
47854819 comp.bin_file.options.is_test,
......@@ -4894,6 +4928,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca
48944928 \\ .cpu = cpu,
48954929 \\ .os = os,
48964930 \\ .abi = abi,
4931 \\ .ofmt = object_format,
48974932 \\}};
48984933 \\pub const object_format = std.Target.ObjectFormat.{};
48994934 \\pub const mode = std.builtin.Mode.{};
......@@ -4908,7 +4943,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca
49084943 \\pub const code_model = std.builtin.CodeModel.{};
49094944 \\
49104945 , .{
4911 std.zig.fmtId(@tagName(comp.bin_file.options.object_format)),
4946 std.zig.fmtId(@tagName(target.ofmt)),
49124947 std.zig.fmtId(@tagName(comp.bin_file.options.optimize_mode)),
49134948 link_libc,
49144949 comp.bin_file.options.link_libcpp,
......@@ -5027,9 +5062,10 @@ fn buildOutputFromZig(
50275062 .link_mode = .Static,
50285063 .function_sections = true,
50295064 .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,
50315066 .want_sanitize_c = false,
50325067 .want_stack_check = false,
5068 .want_stack_protector = 0,
50335069 .want_red_zone = comp.bin_file.options.red_zone,
50345070 .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer,
50355071 .want_valgrind = false,
......@@ -5310,6 +5346,7 @@ pub fn build_crt_file(
53105346 .optimize_mode = comp.compilerRtOptMode(),
53115347 .want_sanitize_c = false,
53125348 .want_stack_check = false,
5349 .want_stack_protector = 0,
53135350 .want_red_zone = comp.bin_file.options.red_zone,
53145351 .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer,
53155352 .want_valgrind = false,
src/Liveness.zig+4
......@@ -267,6 +267,7 @@ pub fn categorizeOperand(
267267 .byte_swap,
268268 .bit_reverse,
269269 .splat,
270 .error_set_has_value,
270271 => {
271272 const o = air_datas[inst].ty_op;
272273 if (o.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
......@@ -291,6 +292,7 @@ pub fn categorizeOperand(
291292 .is_non_err_ptr,
292293 .ptrtoint,
293294 .bool_to_int,
295 .is_named_enum_value,
294296 .tag_name,
295297 .error_name,
296298 .sqrt,
......@@ -841,6 +843,7 @@ fn analyzeInst(
841843 .byte_swap,
842844 .bit_reverse,
843845 .splat,
846 .error_set_has_value,
844847 => {
845848 const o = inst_datas[inst].ty_op;
846849 return trackOperands(a, new_set, inst, main_tomb, .{ o.operand, .none, .none });
......@@ -858,6 +861,7 @@ fn analyzeInst(
858861 .bool_to_int,
859862 .ret,
860863 .ret_load,
864 .is_named_enum_value,
861865 .tag_name,
862866 .error_name,
863867 .sqrt,
src/Module.zig+117-83
......@@ -84,7 +84,6 @@ string_literal_bytes: std.ArrayListUnmanaged(u8) = .{},
8484/// The set of all the generic function instantiations. This is used so that when a generic
8585/// function is called twice with the same comptime parameter arguments, both calls dispatch
8686/// to the same function.
87/// TODO: remove functions from this set when they are destroyed.
8887monomorphed_funcs: MonomorphedFuncsSet = .{},
8988/// The set of all comptime function calls that have been cached so that future calls
9089/// with the same parameters will get the same return value.
......@@ -92,7 +91,6 @@ memoized_calls: MemoizedCallSet = .{},
9291/// Contains the values from `@setAlignStack`. A sparse table is used here
9392/// instead of a field of `Fn` because usage of `@setAlignStack` is rare, while
9493/// functions are many.
95/// TODO: remove functions from this set when they are destroyed.
9694align_stack_fns: std.AutoHashMapUnmanaged(*const Fn, SetAlignStack) = .{},
9795
9896/// We optimize memory usage for a compilation with no compile errors by storing the
......@@ -560,6 +558,10 @@ pub const Decl = struct {
560558 gpa.destroy(extern_fn);
561559 }
562560 if (decl.getFunction()) |func| {
561 _ = mod.align_stack_fns.remove(func);
562 if (func.comptime_args != null) {
563 _ = mod.monomorphed_funcs.remove(func);
564 }
563565 func.deinit(gpa);
564566 gpa.destroy(func);
565567 }
......@@ -853,8 +855,6 @@ pub const EmitH = struct {
853855pub const ErrorSet = struct {
854856 /// The Decl that corresponds to the error set itself.
855857 owner_decl: Decl.Index,
856 /// Offset from Decl node index, points to the error set AST node.
857 node_offset: i32,
858858 /// The string bytes are stored in the owner Decl arena.
859859 /// These must be in sorted order. See sortNames.
860860 names: NameMap,
......@@ -866,7 +866,7 @@ pub const ErrorSet = struct {
866866 return .{
867867 .file_scope = owner_decl.getFileScope(),
868868 .parent_decl_node = owner_decl.src_node,
869 .lazy = LazySrcLoc.nodeOffset(self.node_offset),
869 .lazy = LazySrcLoc.nodeOffset(0),
870870 };
871871 }
872872
......@@ -893,12 +893,15 @@ pub const Struct = struct {
893893 namespace: Namespace,
894894 /// The Decl that corresponds to the struct itself.
895895 owner_decl: Decl.Index,
896 /// Offset from `owner_decl`, points to the struct AST node.
897 node_offset: i32,
898896 /// Index of the struct_decl ZIR instruction.
899897 zir_index: Zir.Inst.Index,
900898
901899 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),
902905 status: enum {
903906 none,
904907 field_types_wip,
......@@ -934,13 +937,41 @@ pub const Struct = struct {
934937 /// If true then `default_val` is the comptime field value.
935938 is_comptime: bool,
936939
937 /// Returns the field alignment, assuming the struct is not packed.
938 pub fn normalAlignment(field: Field, target: Target) u32 {
939 if (field.abi_align == 0) {
940 return field.ty.abiAlignment(target);
941 } else {
940 /// Returns the field alignment. If the struct is packed, returns 0.
941 pub fn alignment(
942 field: Field,
943 target: Target,
944 layout: std.builtin.Type.ContainerLayout,
945 ) u32 {
946 if (field.abi_align != 0) {
947 assert(layout != .Packed);
942948 return field.abi_align;
943949 }
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;
944975 }
945976 };
946977
......@@ -953,7 +984,7 @@ pub const Struct = struct {
953984 return .{
954985 .file_scope = owner_decl.getFileScope(),
955986 .parent_decl_node = owner_decl.src_node,
956 .lazy = LazySrcLoc.nodeOffset(s.node_offset),
987 .lazy = LazySrcLoc.nodeOffset(0),
957988 };
958989 }
959990
......@@ -968,7 +999,7 @@ pub const Struct = struct {
968999 });
9691000 return s.srcLoc(mod);
9701001 };
971 const node = owner_decl.relativeToNodeIndex(s.node_offset);
1002 const node = owner_decl.relativeToNodeIndex(0);
9721003 const node_tags = tree.nodes.items(.tag);
9731004 switch (node_tags[node]) {
9741005 .container_decl,
......@@ -1029,7 +1060,7 @@ pub const Struct = struct {
10291060
10301061 pub fn packedFieldBitOffset(s: Struct, target: Target, index: usize) u16 {
10311062 assert(s.layout == .Packed);
1032 assert(s.haveFieldTypes());
1063 assert(s.haveLayout());
10331064 var bit_sum: u64 = 0;
10341065 for (s.fields.values()) |field, i| {
10351066 if (i == index) {
......@@ -1037,19 +1068,7 @@ pub const Struct = struct {
10371068 }
10381069 bit_sum += field.ty.bitSize(target);
10391070 }
1040 return @intCast(u16, bit_sum);
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);
1071 unreachable; // index out of bounds
10531072 }
10541073};
10551074
......@@ -1060,8 +1079,6 @@ pub const Struct = struct {
10601079pub const EnumSimple = struct {
10611080 /// The Decl that corresponds to the enum itself.
10621081 owner_decl: Decl.Index,
1063 /// Offset from `owner_decl`, points to the enum decl AST node.
1064 node_offset: i32,
10651082 /// Set of field names in declaration order.
10661083 fields: NameMap,
10671084
......@@ -1072,7 +1089,7 @@ pub const EnumSimple = struct {
10721089 return .{
10731090 .file_scope = owner_decl.getFileScope(),
10741091 .parent_decl_node = owner_decl.src_node,
1075 .lazy = LazySrcLoc.nodeOffset(self.node_offset),
1092 .lazy = LazySrcLoc.nodeOffset(0),
10761093 };
10771094 }
10781095};
......@@ -1083,8 +1100,6 @@ pub const EnumSimple = struct {
10831100pub const EnumNumbered = struct {
10841101 /// The Decl that corresponds to the enum itself.
10851102 owner_decl: Decl.Index,
1086 /// Offset from `owner_decl`, points to the enum decl AST node.
1087 node_offset: i32,
10881103 /// An integer type which is used for the numerical value of the enum.
10891104 /// Whether zig chooses this type or the user specifies it, it is stored here.
10901105 tag_ty: Type,
......@@ -1103,7 +1118,7 @@ pub const EnumNumbered = struct {
11031118 return .{
11041119 .file_scope = owner_decl.getFileScope(),
11051120 .parent_decl_node = owner_decl.src_node,
1106 .lazy = LazySrcLoc.nodeOffset(self.node_offset),
1121 .lazy = LazySrcLoc.nodeOffset(0),
11071122 };
11081123 }
11091124};
......@@ -1113,8 +1128,6 @@ pub const EnumNumbered = struct {
11131128pub const EnumFull = struct {
11141129 /// The Decl that corresponds to the enum itself.
11151130 owner_decl: Decl.Index,
1116 /// Offset from `owner_decl`, points to the enum decl AST node.
1117 node_offset: i32,
11181131 /// An integer type which is used for the numerical value of the enum.
11191132 /// Whether zig chooses this type or the user specifies it, it is stored here.
11201133 tag_ty: Type,
......@@ -1137,7 +1150,7 @@ pub const EnumFull = struct {
11371150 return .{
11381151 .file_scope = owner_decl.getFileScope(),
11391152 .parent_decl_node = owner_decl.src_node,
1140 .lazy = LazySrcLoc.nodeOffset(self.node_offset),
1153 .lazy = LazySrcLoc.nodeOffset(0),
11411154 };
11421155 }
11431156};
......@@ -1155,8 +1168,6 @@ pub const Union = struct {
11551168 namespace: Namespace,
11561169 /// The Decl that corresponds to the union itself.
11571170 owner_decl: Decl.Index,
1158 /// Offset from `owner_decl`, points to the union decl AST node.
1159 node_offset: i32,
11601171 /// Index of the union_decl ZIR instruction.
11611172 zir_index: Zir.Inst.Index,
11621173
......@@ -1203,7 +1214,7 @@ pub const Union = struct {
12031214 return .{
12041215 .file_scope = owner_decl.getFileScope(),
12051216 .parent_decl_node = owner_decl.src_node,
1206 .lazy = LazySrcLoc.nodeOffset(self.node_offset),
1217 .lazy = LazySrcLoc.nodeOffset(0),
12071218 };
12081219 }
12091220
......@@ -1218,7 +1229,7 @@ pub const Union = struct {
12181229 });
12191230 return u.srcLoc(mod);
12201231 };
1221 const node = owner_decl.relativeToNodeIndex(u.node_offset);
1232 const node = owner_decl.relativeToNodeIndex(0);
12221233 const node_tags = tree.nodes.items(.tag);
12231234 var buf: [2]Ast.Node.Index = undefined;
12241235 switch (node_tags[node]) {
......@@ -1357,18 +1368,20 @@ pub const Union = struct {
13571368 }
13581369 }
13591370 payload_align = @maximum(payload_align, 1);
1360 if (!have_tag or fields.len <= 1) return .{
1361 .abi_size = std.mem.alignForwardGeneric(u64, payload_size, payload_align),
1362 .abi_align = payload_align,
1363 .most_aligned_field = most_aligned_field,
1364 .most_aligned_field_size = most_aligned_field_size,
1365 .biggest_field = biggest_field,
1366 .payload_size = payload_size,
1367 .payload_align = payload_align,
1368 .tag_align = 0,
1369 .tag_size = 0,
1370 .padding = 0,
1371 };
1371 if (!have_tag or !u.tag_ty.hasRuntimeBits()) {
1372 return .{
1373 .abi_size = std.mem.alignForwardGeneric(u64, payload_size, payload_align),
1374 .abi_align = payload_align,
1375 .most_aligned_field = most_aligned_field,
1376 .most_aligned_field_size = most_aligned_field_size,
1377 .biggest_field = biggest_field,
1378 .payload_size = payload_size,
1379 .payload_align = payload_align,
1380 .tag_align = 0,
1381 .tag_size = 0,
1382 .padding = 0,
1383 };
1384 }
13721385 // Put the tag before or after the payload depending on which one's
13731386 // alignment is greater.
13741387 const tag_size = u.tag_ty.abiSize(target);
......@@ -1410,8 +1423,6 @@ pub const Union = struct {
14101423pub const Opaque = struct {
14111424 /// The Decl that corresponds to the opaque itself.
14121425 owner_decl: Decl.Index,
1413 /// Offset from `owner_decl`, points to the opaque decl AST node.
1414 node_offset: i32,
14151426 /// Represents the declarations inside this opaque.
14161427 namespace: Namespace,
14171428
......@@ -1420,7 +1431,7 @@ pub const Opaque = struct {
14201431 return .{
14211432 .file_scope = owner_decl.getFileScope(),
14221433 .parent_decl_node = owner_decl.src_node,
1423 .lazy = LazySrcLoc.nodeOffset(self.node_offset),
1434 .lazy = LazySrcLoc.nodeOffset(0),
14241435 };
14251436 }
14261437
......@@ -1464,25 +1475,14 @@ pub const Fn = struct {
14641475 /// These never have .generic_poison for the Type
14651476 /// because the Type is needed to pass to `Type.eql` and for inserting comptime arguments
14661477 /// 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`.
14681479 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
14821481 /// Precomputed hash for monomorphed_funcs.
14831482 /// This is important because it may be accessed when resizing monomorphed_funcs
14841483 /// while this Fn has already been added to the set, but does not have the
14851484 /// owner_decl, comptime_args, or other fields populated yet.
1485 /// This field is undefined if comptime_args == null.
14861486 hash: u64,
14871487
14881488 /// Relative to owner Decl.
......@@ -1590,18 +1590,43 @@ pub const Fn = struct {
15901590 gpa.destroy(node);
15911591 it = next;
15921592 }
1593 }
15931594
1594 for (func.param_names) |param_name| {
1595 gpa.free(param_name);
1596 }
1597 gpa.free(func.param_names);
1595 pub fn isAnytypeParam(func: Fn, mod: *Module, index: u32) bool {
1596 const file = mod.declPtr(func.owner_decl).getFileScope();
1597
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 };
15981608 }
15991609
1600 pub fn getParamName(func: Fn, index: u32) [:0]const u8 {
1601 // TODO rework ZIR of parameters so that this function looks up
1602 // param names in ZIR instead of redundantly saving them into Fn.
1603 // const zir = func.owner_decl.getFileScope().zir;
1604 return func.param_names[index];
1610 pub fn getParamName(func: Fn, mod: *Module, index: u32) [:0]const u8 {
1611 const file = mod.declPtr(func.owner_decl).getFileScope();
1612
1613 const tags = file.zir.instructions.items(.tag);
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 };
16051630 }
16061631
16071632 pub fn hasInferredErrorSet(func: Fn, mod: *Module) bool {
......@@ -4102,6 +4127,12 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
41024127 // The exports this Decl performs will be re-discovered, so we remove them here
41034128 // prior to re-analysis.
41044129 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
41054136 // Dependencies will be re-discovered, so we remove them here prior to re-analysis.
41064137 for (decl.dependencies.keys()) |dep_index| {
41074138 const dep = mod.declPtr(dep_index);
......@@ -4324,7 +4355,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
43244355 struct_obj.* = .{
43254356 .owner_decl = undefined, // set below
43264357 .fields = .{},
4327 .node_offset = 0, // it's the struct for the root file
43284358 .zir_index = undefined, // set below
43294359 .layout = .Auto,
43304360 .status = .none,
......@@ -6047,17 +6077,17 @@ pub fn paramSrc(
60476077 else => unreachable,
60486078 };
60496079 var it = full.iterate(tree);
6050 while (true) {
6051 if (it.param_i == param_i) {
6052 const param = it.next().?;
6080 var i: usize = 0;
6081 while (it.next()) |param| : (i += 1) {
6082 if (i == param_i) {
60536083 if (param.anytype_ellipsis3) |some| {
60546084 const main_token = tree.nodes.items(.main_token)[decl.src_node];
60556085 return .{ .token_offset_param = @bitCast(i32, some) - @bitCast(i32, main_token) };
60566086 }
60576087 return .{ .node_offset_param = decl.nodeIndexToRelative(param.type_expr) };
60586088 }
6059 _ = it.next();
60606089 }
6090 unreachable;
60616091}
60626092
60636093pub fn argSrc(
......@@ -6504,3 +6534,7 @@ pub fn addGlobalAssembly(mod: *Module, decl_index: Decl.Index, source: []const u
65046534
65056535 mod.global_assembly.putAssumeCapacityNoClobber(decl_index, duped_source);
65066536}
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) = .{},
7676post_hoc_blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, *LabeledBlock) = .{},
7777/// Populated with the last compile error created.
7878err: ?*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
8085const std = @import("std");
86const math = std.math;
8187const mem = std.mem;
8288const Allocator = std.mem.Allocator;
8389const assert = std.debug.assert;
......@@ -772,7 +778,6 @@ fn analyzeBodyInner(
772778 .optional_payload_unsafe => try sema.zirOptionalPayload(block, inst, false),
773779 .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false),
774780 .optional_type => try sema.zirOptionalType(block, inst),
775 .param_type => try sema.zirParamType(block, inst),
776781 .ptr_type => try sema.zirPtrType(block, inst),
777782 .overflow_arithmetic_ptr => try sema.zirOverflowArithmeticPtr(block, inst),
778783 .ref => try sema.zirRef(block, inst),
......@@ -816,7 +821,6 @@ fn analyzeBodyInner(
816821 .embed_file => try sema.zirEmbedFile(block, inst),
817822 .error_name => try sema.zirErrorName(block, inst),
818823 .tag_name => try sema.zirTagName(block, inst),
819 .reify => try sema.zirReify(block, inst),
820824 .type_name => try sema.zirTypeName(block, inst),
821825 .frame_type => try sema.zirFrameType(block, inst),
822826 .frame_size => try sema.zirFrameSize(block, inst),
......@@ -876,9 +880,6 @@ fn analyzeBodyInner(
876880 .add => try sema.zirArithmetic(block, inst, .add),
877881 .addwrap => try sema.zirArithmetic(block, inst, .addwrap),
878882 .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),
882883 .mul => try sema.zirArithmetic(block, inst, .mul),
883884 .mulwrap => try sema.zirArithmetic(block, inst, .mulwrap),
884885 .mul_sat => try sema.zirArithmetic(block, inst, .mul_sat),
......@@ -891,6 +892,10 @@ fn analyzeBodyInner(
891892 .div_floor => try sema.zirDivFloor(block, inst),
892893 .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
894899 .maximum => try sema.zirMinMax(block, inst, .max),
895900 .minimum => try sema.zirMinMax(block, inst, .min),
896901
......@@ -950,6 +955,7 @@ fn analyzeBodyInner(
950955 .select => try sema.zirSelect( block, extended),
951956 .error_to_int => try sema.zirErrorToInt( block, extended),
952957 .int_to_error => try sema.zirIntToError( block, extended),
958 .reify => try sema.zirReify( block, extended, inst),
953959 // zig fmt: on
954960 .fence => {
955961 try sema.zirFence(block, extended);
......@@ -1494,7 +1500,8 @@ pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref {
14941500
14951501 // Finally, the last section of indexes refers to the map of ZIR=>AIR.
14961502 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;
14981505 return inst;
14991506}
15001507
......@@ -1577,8 +1584,7 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize)
15771584
15781585 // st.index = 0;
15791586 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);
1581 try sema.storePtr2(&err_trace_block, src, index_field_ptr, src, zero, src, .store);
1587 try sema.storePtr2(&err_trace_block, src, index_field_ptr, src, .zero_usize, src, .store);
15821588
15831589 // @errorReturnTrace() = &st;
15841590 _ = try err_trace_block.addUnOp(.set_err_return_trace, st_ptr);
......@@ -1695,7 +1701,10 @@ fn resolveMaybeUndefValIntable(
16951701 .elem_ptr => check = check.castTag(.elem_ptr).?.data.array_ptr,
16961702 .eu_payload_ptr, .opt_payload_ptr => check = check.cast(Value.Payload.PayloadPtr).?.data.container_ptr,
16971703 .generic_poison => return error.GenericPoison,
1698 else => return val,
1704 else => {
1705 try sema.resolveLazyValue(block, src, val);
1706 return val;
1707 },
16991708 };
17001709}
17011710
......@@ -1818,10 +1827,21 @@ fn failWithInvalidComptimeFieldStore(sema: *Sema, block: *Block, init_src: LazyS
18181827
18191828 const tree = try sema.getAstTree(block);
18201829 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);
18221831 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", .{});
18251845 break :msg msg;
18261846 };
18271847 return sema.failWithOwnedErrorMsg(msg);
......@@ -1855,7 +1875,7 @@ fn addFieldErrNote(
18551875 const decl_index = container_ty.getOwnerDecl();
18561876 const decl = mod.declPtr(decl_index);
18571877 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);
18591879 try mod.errNoteNonLazy(field_src.toSrcLoc(decl), parent, format, args);
18601880}
18611881
......@@ -1895,8 +1915,6 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {
18951915 }
18961916
18971917 const mod = sema.mod;
1898 sema.err = err_msg;
1899
19001918 {
19011919 errdefer err_msg.destroy(mod.gpa);
19021920 if (err_msg.src_loc.lazy == .unneeded) {
......@@ -1914,8 +1932,10 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {
19141932 const gop = mod.failed_decls.getOrPutAssumeCapacity(sema.owner_decl_index);
19151933 if (gop.found_existing) {
19161934 // If there are multiple errors for the same Decl, prefer the first one added.
1935 sema.err = null;
19171936 err_msg.destroy(mod.gpa);
19181937 } else {
1938 sema.err = err_msg;
19191939 gop.value_ptr.* = err_msg;
19201940 }
19211941 return error.AnalysisFail;
......@@ -2228,6 +2248,16 @@ pub fn analyzeStructDecl(
22282248 break :blk decls_len;
22292249 } 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
22312261 _ = try sema.mod.scanNamespace(&struct_obj.namespace, extra_index, decls_len, new_decl);
22322262}
22332263
......@@ -2251,7 +2281,7 @@ fn zirStructDecl(
22512281 const struct_obj = try new_decl_arena_allocator.create(Module.Struct);
22522282 const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj);
22532283 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, .{
22552285 .ty = Type.type,
22562286 .val = struct_val,
22572287 }, small.name_strategy, "struct", inst);
......@@ -2261,7 +2291,6 @@ fn zirStructDecl(
22612291 struct_obj.* = .{
22622292 .owner_decl = new_decl_index,
22632293 .fields = .{},
2264 .node_offset = src.node_offset.x,
22652294 .zir_index = inst,
22662295 .layout = small.layout,
22672296 .status = .none,
......@@ -2283,6 +2312,7 @@ fn zirStructDecl(
22832312fn createAnonymousDeclTypeNamed(
22842313 sema: *Sema,
22852314 block: *Block,
2315 src: LazySrcLoc,
22862316 typed_value: TypedValue,
22872317 name_strategy: Zir.Inst.NameStrategy,
22882318 anon_prefix: []const u8,
......@@ -2292,7 +2322,8 @@ fn createAnonymousDeclTypeNamed(
22922322 const namespace = block.namespace;
22932323 const src_scope = block.wip_capture_scope;
22942324 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);
22962327 errdefer mod.destroyDecl(new_decl_index);
22972328
22982329 switch (name_strategy) {
......@@ -2367,7 +2398,7 @@ fn createAnonymousDeclTypeNamed(
23672398 },
23682399 else => {},
23692400 };
2370 return sema.createAnonymousDeclTypeNamed(block, typed_value, .anon, anon_prefix, null);
2401 return sema.createAnonymousDeclTypeNamed(block, src, typed_value, .anon, anon_prefix, null);
23712402 },
23722403 }
23732404}
......@@ -2431,7 +2462,7 @@ fn zirEnumDecl(
24312462 };
24322463 const enum_ty = Type.initPayload(&enum_ty_payload.base);
24332464 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, .{
24352466 .ty = Type.type,
24362467 .val = enum_val,
24372468 }, small.name_strategy, "enum", inst);
......@@ -2445,7 +2476,6 @@ fn zirEnumDecl(
24452476 .tag_ty_inferred = true,
24462477 .fields = .{},
24472478 .values = .{},
2448 .node_offset = src.node_offset.x,
24492479 .namespace = .{
24502480 .parent = block.namespace,
24512481 .ty = enum_ty,
......@@ -2467,18 +2497,6 @@ fn zirEnumDecl(
24672497 extra_index = try mod.scanNamespace(&enum_obj.namespace, extra_index, decls_len, new_decl);
24682498
24692499 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 }
24822500 extra_index += body.len;
24832501
24842502 const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
......@@ -2536,6 +2554,9 @@ fn zirEnumDecl(
25362554 }
25372555 enum_obj.tag_ty = try ty.copy(decl_arena_allocator);
25382556 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;
25392560 } else {
25402561 const bits = std.math.log2_int_ceil(usize, fields_len);
25412562 enum_obj.tag_ty = try Type.Tag.int_unsigned.create(decl_arena_allocator, bits);
......@@ -2673,7 +2694,7 @@ fn zirUnionDecl(
26732694 const union_ty = Type.initPayload(&union_payload.base);
26742695 const union_val = try Value.Tag.ty.create(new_decl_arena_allocator, union_ty);
26752696 const mod = sema.mod;
2676 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{
2697 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
26772698 .ty = Type.type,
26782699 .val = union_val,
26792700 }, small.name_strategy, "union", inst);
......@@ -2684,7 +2705,6 @@ fn zirUnionDecl(
26842705 .owner_decl = new_decl_index,
26852706 .tag_ty = Type.initTag(.@"null"),
26862707 .fields = .{},
2687 .node_offset = src.node_offset.x,
26882708 .zir_index = inst,
26892709 .layout = small.layout,
26902710 .status = .none,
......@@ -2742,7 +2762,7 @@ fn zirOpaqueDecl(
27422762 };
27432763 const opaque_ty = Type.initPayload(&opaque_ty_payload.base);
27442764 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, .{
27462766 .ty = Type.type,
27472767 .val = opaque_val,
27482768 }, small.name_strategy, "opaque", inst);
......@@ -2752,7 +2772,6 @@ fn zirOpaqueDecl(
27522772
27532773 opaque_obj.* = .{
27542774 .owner_decl = new_decl_index,
2755 .node_offset = src.node_offset.x,
27562775 .namespace = .{
27572776 .parent = block.namespace,
27582777 .ty = opaque_ty,
......@@ -2791,7 +2810,7 @@ fn zirErrorSetDecl(
27912810 const error_set_ty = try Type.Tag.error_set.create(new_decl_arena_allocator, error_set);
27922811 const error_set_val = try Value.Tag.ty.create(new_decl_arena_allocator, error_set_ty);
27932812 const mod = sema.mod;
2794 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{
2813 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
27952814 .ty = Type.type,
27962815 .val = error_set_val,
27972816 }, name_strategy, "error", inst);
......@@ -2816,7 +2835,6 @@ fn zirErrorSetDecl(
28162835
28172836 error_set.* = .{
28182837 .owner_decl = new_decl_index,
2819 .node_offset = inst_data.src_node,
28202838 .names = names,
28212839 };
28222840 try new_decl.finalizeNewArena(&new_decl_arena);
......@@ -3068,7 +3086,7 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
30683086
30693087 const candidate = block.instructions.items[search_index];
30703088 switch (air_tags[candidate]) {
3071 .dbg_stmt => continue,
3089 .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue,
30723090 .store => break candidate,
30733091 else => break :ct,
30743092 }
......@@ -3080,7 +3098,7 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
30803098
30813099 const candidate = block.instructions.items[search_index];
30823100 switch (air_tags[candidate]) {
3083 .dbg_stmt => continue,
3101 .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue,
30843102 .alloc => {
30853103 if (Air.indexToRef(candidate) != alloc) break :ct;
30863104 break;
......@@ -3298,7 +3316,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
32983316
32993317 const candidate = block.instructions.items[search_index];
33003318 switch (air_tags[candidate]) {
3301 .dbg_stmt => continue,
3319 .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue,
33023320 .store => break candidate,
33033321 else => break :ct,
33043322 }
......@@ -3310,7 +3328,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
33103328
33113329 const candidate = block.instructions.items[search_index];
33123330 switch (air_tags[candidate]) {
3313 .dbg_stmt => continue,
3331 .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue,
33143332 .bitcast => break candidate,
33153333 else => break :ct,
33163334 }
......@@ -3322,7 +3340,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
33223340
33233341 const candidate = block.instructions.items[search_index];
33243342 switch (air_tags[candidate]) {
3325 .dbg_stmt => continue,
3343 .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue,
33263344 .constant => break candidate,
33273345 else => break :ct,
33283346 }
......@@ -3596,8 +3614,6 @@ fn validateUnionInit(
35963614 union_ptr: Air.Inst.Ref,
35973615 is_comptime: bool,
35983616) CompileError!void {
3599 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
3600
36013617 if (instrs.len != 1) {
36023618 const msg = msg: {
36033619 const msg = try sema.errMsg(
......@@ -3631,7 +3647,8 @@ fn validateUnionInit(
36313647 const field_src: LazySrcLoc = .{ .node_offset_initializer = field_ptr_data.src_node };
36323648 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
36333649 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);
36353652 const air_tags = sema.air_instructions.items(.tag);
36363653 const air_datas = sema.air_instructions.items(.data);
36373654 const field_ptr_air_ref = sema.inst_map.get(field_ptr).?;
......@@ -3690,7 +3707,9 @@ fn validateUnionInit(
36903707 break;
36913708 }
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
36953714 if (init_val) |val| {
36963715 // Our task is to delete all the `field_ptr` and `store` instructions, and insert
......@@ -3707,7 +3726,7 @@ fn validateUnionInit(
37073726 }
37083727
37093728 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);
37113730 _ = try block.addBinOp(.set_union_tag, union_ptr, new_tag);
37123731}
37133732
......@@ -3754,11 +3773,13 @@ fn validateStructInit(
37543773 }
37553774
37563775 var root_msg: ?*Module.ErrorMsg = null;
3776 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
37573777
37583778 const struct_ptr = try sema.resolveInst(struct_ptr_zir_ref);
37593779 if ((is_comptime or block.is_comptime) and
37603780 (try sema.resolveDefinedValue(block, init_src, struct_ptr)) != null)
37613781 {
3782 try sema.resolveStructLayout(block, init_src, struct_ty);
37623783 // In this case the only thing we need to do is evaluate the implicit
37633784 // store instructions for default field values, and report any missing fields.
37643785 // Avoid the cost of the extra machinery for detecting a comptime struct init value.
......@@ -3929,6 +3950,7 @@ fn validateStructInit(
39293950 }
39303951
39313952 if (root_msg) |msg| {
3953 root_msg = null;
39323954 if (struct_ty.castTag(.@"struct")) |struct_obj| {
39333955 const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod);
39343956 defer gpa.free(fqn);
......@@ -3952,6 +3974,7 @@ fn validateStructInit(
39523974 try sema.storePtr2(block, init_src, struct_ptr, init_src, struct_init, init_src, .store);
39533975 return;
39543976 }
3977 try sema.resolveStructLayout(block, init_src, struct_ty);
39553978
39563979 // Our task is to insert `store` instructions for all the default field values.
39573980 for (found_fields) |field_ptr, i| {
......@@ -3987,6 +4010,8 @@ fn zirValidateArrayInit(
39874010 if (instrs.len != array_len and array_ty.isTuple()) {
39884011 const struct_obj = array_ty.castTag(.tuple).?.data;
39894012 var root_msg: ?*Module.ErrorMsg = null;
4013 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
4014
39904015 for (struct_obj.values) |default_val, i| {
39914016 if (i < instrs.len) continue;
39924017
......@@ -4001,6 +4026,7 @@ fn zirValidateArrayInit(
40014026 }
40024027
40034028 if (root_msg) |msg| {
4029 root_msg = null;
40044030 return sema.failWithOwnedErrorMsg(msg);
40054031 }
40064032 }
......@@ -4038,6 +4064,19 @@ fn zirValidateArrayInit(
40384064
40394065 // 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
40414080 const elem_ptr_air_ref = sema.inst_map.get(elem_ptr).?;
40424081 const elem_ptr_air_inst = Air.refToIndex(elem_ptr_air_ref).?;
40434082 // Find the block index of the elem_ptr so that we can look at the next
......@@ -4054,19 +4093,6 @@ fn zirValidateArrayInit(
40544093 }
40554094 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
40704096 // If the next instructon is a store with a comptime operand, this element
40714097 // is comptime.
40724098 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
44334459 return sema.storePtr2(block, src, ptr, src, operand, src, if (is_ret) .ret_ptr else .store);
44344460}
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
44734462fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
44744463 const tracy = trace(@src());
44754464 defer tracy.end();
......@@ -4775,7 +4764,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
47754764fn zirSuspendBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
47764765 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
47774766 const src = inst_data.src();
4778 return sema.fail(parent_block, src, "TODO: implement Sema.zirSuspendBlock", .{});
4767 return sema.failWithUseOfAsync(parent_block, src);
47794768}
47804769
47814770fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -5403,6 +5392,17 @@ fn lookupInNamespace(
54035392 }
54045393 }
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
54065406 switch (candidates.items.len) {
54075407 0 => {},
54085408 1 => {
......@@ -5439,6 +5439,19 @@ fn lookupInNamespace(
54395439 return null;
54405440}
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
54425455fn zirCall(
54435456 sema: *Sema,
54445457 block: *Block,
......@@ -5451,13 +5464,14 @@ fn zirCall(
54515464 const func_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node };
54525465 const call_src = inst_data.src();
54535466 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
54565469 const modifier = @intToEnum(std.builtin.CallOptions.Modifier, extra.data.flags.packed_modifier);
54575470 const ensure_result_used = extra.data.flags.ensure_result_used;
54585471
54595472 var func = try sema.resolveInst(extra.data.callee);
54605473 var resolved_args: []Air.Inst.Ref = undefined;
5474 var arg_index: u32 = 0;
54615475
54625476 const func_type = sema.typeOf(func);
54635477
......@@ -5468,16 +5482,93 @@ fn zirCall(
54685482 const bound_func = try sema.resolveValue(block, .unneeded, func, undefined);
54695483 const bound_data = &bound_func.cast(Value.Payload.BoundFn).?.data;
54705484 func = bound_data.func_inst;
5471 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args.len + 1);
5472 resolved_args[0] = bound_data.arg0_inst;
5473 for (args) |zir_arg, i| {
5474 resolved_args[i + 1] = try sema.resolveInst(zir_arg);
5475 }
5485 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len + 1);
5486 resolved_args[arg_index] = bound_data.arg0_inst;
5487 arg_index += 1;
54765488 } else {
5477 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args.len);
5478 for (args) |zir_arg, i| {
5479 resolved_args[i] = try sema.resolveInst(zir_arg);
5489 resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len);
5490 }
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;
54805566 }
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);
54815572 }
54825573
54835574 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 {
54875578 generic_fn: *Module.Fn,
54885579 precomputed_hash: u64,
54895580 func_ty_info: Type.Payload.Function.Data,
5490 /// Unlike comptime_args, the Type here is not always present.
5491 /// .generic_poison is used to communicate non-anytype parameters.
5492 comptime_tvs: []const TypedValue,
5581 args: []const Arg,
54935582 module: *Module,
54945583
5584 const Arg = struct {
5585 ty: Type,
5586 val: Value,
5587 is_anytype: bool,
5588 };
5589
54955590 pub fn eql(ctx: @This(), adapted_key: void, other_key: *Module.Fn) bool {
54965591 _ = adapted_key;
54975592 // The generic function Decl is guaranteed to be the first dependency
......@@ -5502,11 +5597,11 @@ const GenericCallAdapter = struct {
55025597
55035598 const other_comptime_args = other_key.comptime_args.?;
55045599 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];
55065601 const this_is_comptime = this_arg.val.tag() != .generic_poison;
55075602 const other_is_comptime = other_arg.val.tag() != .generic_poison;
5508 const this_is_anytype = this_arg.ty.tag() != .generic_poison;
5509 const other_is_anytype = other_key.anytype_args[i];
5603 const this_is_anytype = this_arg.is_anytype;
5604 const other_is_anytype = other_key.isAnytypeParam(ctx.module, @intCast(u32, i));
55105605
55115606 if (other_is_anytype != this_is_anytype) return false;
55125607 if (other_is_comptime != this_is_comptime) return false;
......@@ -5524,7 +5619,17 @@ const GenericCallAdapter = struct {
55245619 }
55255620 } else if (this_is_comptime) {
55265621 // 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) {
55285633 return false;
55295634 }
55305635 }
......@@ -5540,6 +5645,37 @@ const GenericCallAdapter = struct {
55405645 }
55415646};
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
55435679fn analyzeCall(
55445680 sema: *Sema,
55455681 block: *Block,
......@@ -5571,13 +5707,20 @@ fn analyzeCall(
55715707 const func_ty_info = func_ty.fnInfo();
55725708 const cc = func_ty_info.cc;
55735709 if (cc == .Naked) {
5574 // TODO add error note: declared here
5575 return sema.fail(
5576 block,
5577 func_src,
5578 "unable to call function with naked calling convention",
5579 .{},
5580 );
5710 const decl_src = try sema.funcDeclSrc(block, func_src, func);
5711 const msg = msg: {
5712 const msg = try sema.errMsg(
5713 block,
5714 func_src,
5715 "unable to call function with naked calling convention",
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);
55815724 }
55825725 const fn_params_len = func_ty_info.param_types.len;
55835726 if (func_ty_info.is_var_args) {
......@@ -5612,7 +5755,7 @@ fn analyzeCall(
56125755 .never_inline => Air.Inst.Tag.call_never_inline,
56135756 .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),
56165759 };
56175760
56185761 if (modifier == .never_inline and func_ty_info.cc == .Inline) {
......@@ -5623,9 +5766,11 @@ fn analyzeCall(
56235766
56245767 var is_generic_call = func_ty_info.is_generic;
56255768 var is_comptime_call = block.is_comptime or modifier == .compile_time;
5769 var comptime_only_ret_ty = false;
56265770 if (!is_comptime_call) {
56275771 if (sema.typeRequiresComptime(block, func_src, func_ty_info.return_type)) |ct| {
56285772 is_comptime_call = ct;
5773 comptime_only_ret_ty = ct;
56295774 } else |err| switch (err) {
56305775 error.GenericPoison => is_generic_call = true,
56315776 else => |e| return e,
......@@ -5654,6 +5799,7 @@ fn analyzeCall(
56545799 error.ComptimeReturn => {
56555800 is_inline_call = true;
56565801 is_comptime_call = true;
5802 comptime_only_ret_ty = true;
56575803 },
56585804 else => |e| return e,
56595805 }
......@@ -5664,8 +5810,12 @@ fn analyzeCall(
56645810 }
56655811
56665812 const result: Air.Inst.Ref = if (is_inline_call) res: {
5667 // TODO explain why function is being called at comptime
5668 const func_val = try sema.resolveConstValue(block, func_src, func, "function being called at comptime must be comptime known");
5813 const func_val = sema.resolveConstValue(block, func_src, func, "function being called at comptime must be comptime known") catch |err| {
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 };
56695819 const module_fn = switch (func_val.tag()) {
56705820 .decl_ref => mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data,
56715821 .function => func_val.castTag(.function).?.data,
......@@ -5777,12 +5927,16 @@ fn analyzeCall(
57775927 is_comptime_call,
57785928 &should_memoize,
57795929 memoized_call_key,
5930 // last 4 arguments are only used when reporting errors
5931 undefined,
5932 undefined,
5933 undefined,
5934 undefined,
57805935 ) catch |err| switch (err) {
57815936 error.NeededSourceLocation => {
5782 sema.inst_map.clearRetainingCapacity();
5937 _ = sema.inst_map.remove(inst);
57835938 const decl = sema.mod.declPtr(block.src_decl);
57845939 child_block.src_decl = block.src_decl;
5785 arg_i = 0;
57865940 try sema.analyzeInlineCallArg(
57875941 block,
57885942 &child_block,
......@@ -5794,6 +5948,10 @@ fn analyzeCall(
57945948 is_comptime_call,
57955949 &should_memoize,
57965950 memoized_call_key,
5951 func,
5952 func_src,
5953 func_ty_info.return_type,
5954 comptime_only_ret_ty,
57975955 );
57985956 return error.AnalysisFail;
57995957 },
......@@ -5956,7 +6114,18 @@ fn analyzeCall(
59566114 else => |e| return e,
59576115 };
59586116 } 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 };
59606129 }
59616130 }
59626131
......@@ -5998,6 +6167,10 @@ fn analyzeInlineCallArg(
59986167 is_comptime_call: bool,
59996168 should_memoize: *bool,
60006169 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,
60016174) !void {
60026175 const zir_tags = sema.code.instructions.items(.tag);
60036176 switch (zir_tags[inst]) {
......@@ -6013,14 +6186,23 @@ fn analyzeInlineCallArg(
60136186 new_fn_info.param_types[arg_i.*] = param_ty;
60146187 const uncasted_arg = uncasted_args[arg_i.*];
60156188 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 };
60176195 }
60186196 const casted_arg = try sema.coerce(arg_block, param_ty, uncasted_arg, arg_src);
60196197 try sema.inst_map.putNoClobber(sema.gpa, inst, casted_arg);
60206198
60216199 if (is_comptime_call) {
6022 // TODO explain why function is being called at comptime
6023 const arg_val = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, casted_arg, "argument to function being called at comptime must be comptime known");
6200 const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, casted_arg, "argument to function being called at comptime must be comptime known") catch |err| {
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 };
60246206 switch (arg_val.tag()) {
60256207 .generic_poison, .generic_poison_type => {
60266208 // This function is currently evaluated as part of an as-of-yet unresolvable
......@@ -6050,8 +6232,12 @@ fn analyzeInlineCallArg(
60506232 try sema.inst_map.putNoClobber(sema.gpa, inst, uncasted_arg);
60516233
60526234 if (is_comptime_call) {
6053 // TODO explain why function is being called at comptime
6054 const arg_val = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to function being called at comptime must be comptime known");
6235 const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to function being called at comptime must be comptime known") catch |err| {
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 };
60556241 switch (arg_val.tag()) {
60566242 .generic_poison, .generic_poison_type => {
60576243 // This function is currently evaluated as part of an as-of-yet unresolvable
......@@ -6157,8 +6343,7 @@ fn instantiateGenericCall(
61576343 var hasher = std.hash.Wyhash.init(0);
61586344 std.hash.autoHash(&hasher, @ptrToInt(module_fn));
61596345
6160 const comptime_tvs = try sema.arena.alloc(TypedValue, func_ty_info.param_types.len);
6161
6346 const generic_args = try sema.arena.alloc(GenericCallAdapter.Arg, func_ty_info.param_types.len);
61626347 {
61636348 var i: usize = 0;
61646349 for (fn_info.param_body) |inst| {
......@@ -6182,8 +6367,9 @@ fn instantiateGenericCall(
61826367 else => continue,
61836368 }
61846369
6370 const arg_ty = sema.typeOf(uncasted_args[i]);
6371
61856372 if (is_comptime) {
6186 const arg_ty = sema.typeOf(uncasted_args[i]);
61876373 const arg_val = sema.analyzeGenericCallArgVal(block, .unneeded, uncasted_args[i]) catch |err| switch (err) {
61886374 error.NeededSourceLocation => {
61896375 const decl = sema.mod.declPtr(block.src_decl);
......@@ -6196,27 +6382,30 @@ fn instantiateGenericCall(
61966382 arg_val.hash(arg_ty, &hasher, mod);
61976383 if (is_anytype) {
61986384 arg_ty.hashWithHasher(&hasher, mod);
6199 comptime_tvs[i] = .{
6385 generic_args[i] = .{
62006386 .ty = arg_ty,
62016387 .val = arg_val,
6388 .is_anytype = true,
62026389 };
62036390 } else {
6204 comptime_tvs[i] = .{
6205 .ty = Type.initTag(.generic_poison),
6391 generic_args[i] = .{
6392 .ty = arg_ty,
62066393 .val = arg_val,
6394 .is_anytype = false,
62076395 };
62086396 }
62096397 } else if (is_anytype) {
6210 const arg_ty = sema.typeOf(uncasted_args[i]);
62116398 arg_ty.hashWithHasher(&hasher, mod);
6212 comptime_tvs[i] = .{
6399 generic_args[i] = .{
62136400 .ty = arg_ty,
62146401 .val = Value.initTag(.generic_poison),
6402 .is_anytype = true,
62156403 };
62166404 } else {
6217 comptime_tvs[i] = .{
6218 .ty = Type.initTag(.generic_poison),
6405 generic_args[i] = .{
6406 .ty = arg_ty,
62196407 .val = Value.initTag(.generic_poison),
6408 .is_anytype = false,
62206409 };
62216410 }
62226411
......@@ -6230,7 +6419,7 @@ fn instantiateGenericCall(
62306419 .generic_fn = module_fn,
62316420 .precomputed_hash = precomputed_hash,
62326421 .func_ty_info = func_ty_info,
6233 .comptime_tvs = comptime_tvs,
6422 .args = generic_args,
62346423 .module = mod,
62356424 };
62366425 const gop = try mod.monomorphed_funcs.getOrPutAdapted(gpa, {}, adapter);
......@@ -6261,6 +6450,7 @@ fn instantiateGenericCall(
62616450 new_decl.is_exported = fn_owner_decl.is_exported;
62626451 new_decl.has_align = fn_owner_decl.has_align;
62636452 new_decl.has_linksection_or_addrspace = fn_owner_decl.has_linksection_or_addrspace;
6453 new_decl.@"linksection" = fn_owner_decl.@"linksection";
62646454 new_decl.@"addrspace" = fn_owner_decl.@"addrspace";
62656455 new_decl.zir_decl_index = fn_owner_decl.zir_decl_index;
62666456 new_decl.alive = true; // This Decl is called at runtime.
......@@ -6305,6 +6495,7 @@ fn instantiateGenericCall(
63056495 .comptime_args = try new_decl_arena_allocator.alloc(TypedValue, uncasted_args.len),
63066496 .comptime_args_fn_inst = module_fn.zir_body_inst,
63076497 .preallocated_new_func = new_module_func,
6498 .is_generic_instantiation = true,
63086499 };
63096500 defer child_sema.deinit();
63106501
......@@ -6386,12 +6577,9 @@ fn instantiateGenericCall(
63866577 errdefer new_func.deinit(gpa);
63876578 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;
63916580 arg_i = 0;
63926581 for (fn_info.param_body) |inst| {
63936582 var is_comptime = false;
6394 var is_anytype = false;
63956583 switch (zir_tags[inst]) {
63966584 .param => {
63976585 is_comptime = func_ty_info.paramIsComptime(arg_i);
......@@ -6400,11 +6588,9 @@ fn instantiateGenericCall(
64006588 is_comptime = true;
64016589 },
64026590 .param_anytype => {
6403 is_anytype = true;
64046591 is_comptime = func_ty_info.paramIsComptime(arg_i);
64056592 },
64066593 .param_anytype_comptime => {
6407 is_anytype = true;
64086594 is_comptime = true;
64096595 },
64106596 else => continue,
......@@ -6412,10 +6598,9 @@ fn instantiateGenericCall(
64126598
64136599 // We populate the Type here regardless because it is needed by
64146600 // `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`.
64166602 const arg = child_sema.inst_map.get(inst).?;
64176603 const copied_arg_ty = try child_sema.typeOf(arg).copy(new_decl_arena_allocator);
6418 anytype_args[arg_i] = is_anytype;
64196604
64206605 if (try sema.typeRequiresComptime(block, .unneeded, copied_arg_ty)) {
64216606 is_comptime = true;
......@@ -6588,8 +6773,13 @@ fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
65886773 defer tracy.end();
65896774
65906775 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
6591 const src = inst_data.src();
6592 const child_type = try sema.resolveType(block, src, inst_data.operand);
6776 const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node };
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 }
65936783 const opt_type = try Type.optional(sema.arena, child_type);
65946784
65956785 return sema.addType(opt_type);
......@@ -6662,6 +6852,9 @@ fn zirAnyframeType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
66626852 defer tracy.end();
66636853
66646854 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
6855 if (true) {
6856 return sema.failWithUseOfAsync(block, inst_data.src());
6857 }
66656858 const operand_src: LazySrcLoc = .{ .node_offset_anyframe_type = inst_data.src_node };
66666859 const return_type = try sema.resolveType(block, operand_src, inst_data.operand);
66676860 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
66856878 error_set.fmt(sema.mod),
66866879 });
66876880 }
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 }
66886890 const err_union_ty = try Type.errorUnion(sema.arena, error_set, payload, sema.mod);
66896891 return sema.addType(err_union_ty);
66906892}
......@@ -6716,11 +6918,10 @@ fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
67166918 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
67176919 const uncasted_operand = try sema.resolveInst(extra.operand);
67186920 const operand = try sema.coerce(block, Type.anyerror, uncasted_operand, operand_src);
6719 const result_ty = Type.u16;
67206921
67216922 if (try sema.resolveMaybeUndefVal(block, src, operand)) |val| {
67226923 if (val.isUndef()) {
6723 return sema.addConstUndef(result_ty);
6924 return sema.addConstUndef(Type.err_int);
67246925 }
67256926 switch (val.tag()) {
67266927 .@"error" => {
......@@ -6729,14 +6930,14 @@ fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
67296930 .base = .{ .tag = .int_u64 },
67306931 .data = (try sema.mod.getErrorValue(val.castTag(.@"error").?.data.name)).value,
67316932 };
6732 return sema.addConstant(result_ty, Value.initPayload(&payload.base));
6933 return sema.addConstant(Type.err_int, Value.initPayload(&payload.base));
67336934 },
67346935
67356936 // This is not a valid combination with the type `anyerror`.
67366937 .the_only_possible_value => unreachable,
67376938
67386939 // 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),
67406941 }
67416942 }
67426943
......@@ -6745,14 +6946,14 @@ fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
67456946 if (!op_ty.isAnyError()) {
67466947 const names = op_ty.errorSetNames();
67476948 switch (names.len) {
6748 0 => return sema.addConstant(result_ty, Value.zero),
6749 1 => return sema.addIntUnsigned(result_ty, sema.mod.global_error_set.get(names[0]).?),
6949 0 => return sema.addConstant(Type.err_int, Value.zero),
6950 1 => return sema.addIntUnsigned(Type.err_int, sema.mod.global_error_set.get(names[0]).?),
67506951 else => {},
67516952 }
67526953 }
67536954
67546955 try sema.requireRuntimeBlock(block, src, operand_src);
6755 return block.addBitCast(result_ty, operand);
6956 return block.addBitCast(Type.err_int, operand);
67566957}
67576958
67586959fn 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
67636964 const src = LazySrcLoc.nodeOffset(extra.node);
67646965 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
67656966 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);
67676968 const target = sema.mod.getTarget();
67686969
67696970 if (try sema.resolveDefinedValue(block, operand_src, operand)) |value| {
......@@ -6780,7 +6981,10 @@ fn zirIntToError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
67806981 try sema.requireRuntimeBlock(block, src, operand_src);
67816982 if (block.wantSafety()) {
67826983 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);
67846988 }
67856989 return block.addInst(.{
67866990 .tag = .bitcast,
......@@ -6940,8 +7144,12 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
69407144 }
69417145
69427146 try sema.requireRuntimeBlock(block, src, operand_src);
6943 // TODO insert safety check to make sure the value matches an enum value
6944 return block.addTyOp(.intcast, dest_ty, operand);
7147 const result = try 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;
69457153}
69467154
69477155/// Pointer in, pointer out.
......@@ -7048,6 +7256,8 @@ fn zirOptionalPayload(
70487256 if (operand_ty.ptrSize() != .C) {
70497257 return sema.failWithExpectedOptionalType(block, src, operand_ty);
70507258 }
7259 // TODO https://github.com/ziglang/zig/issues/6597
7260 if (true) break :t operand_ty;
70517261 const ptr_info = operand_ty.ptrInfo().data;
70527262 break :t try Type.ptr(sema.arena, sema.mod, .{
70537263 .pointee_type = try ptr_info.pointee_type.copy(sema.arena),
......@@ -7425,10 +7635,11 @@ fn handleExternLibName(
74257635) CompileError![:0]u8 {
74267636 blk: {
74277637 const mod = sema.mod;
7638 const comp = mod.comp;
74287639 const target = mod.getTarget();
74297640 log.debug("extern fn symbol expected in lib '{s}'", .{lib_name});
74307641 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) {
74327643 return sema.fail(
74337644 block,
74347645 src_loc,
......@@ -7436,11 +7647,11 @@ fn handleExternLibName(
74367647 .{},
74377648 );
74387649 }
7439 mod.comp.bin_file.options.link_libc = true;
7650 comp.bin_file.options.link_libc = true;
74407651 break :blk;
74417652 }
74427653 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) {
74447655 return sema.fail(
74457656 block,
74467657 src_loc,
......@@ -7448,14 +7659,14 @@ fn handleExternLibName(
74487659 .{},
74497660 );
74507661 }
7451 mod.comp.bin_file.options.link_libcpp = true;
7662 comp.bin_file.options.link_libcpp = true;
74527663 break :blk;
74537664 }
74547665 if (mem.eql(u8, lib_name, "unwind")) {
7455 mod.comp.bin_file.options.link_libunwind = true;
7666 comp.bin_file.options.link_libunwind = true;
74567667 break :blk;
74577668 }
7458 if (!target.isWasm() and !mod.comp.bin_file.options.pic) {
7669 if (!target.isWasm() and !comp.bin_file.options.pic) {
74597670 return sema.fail(
74607671 block,
74617672 src_loc,
......@@ -7463,7 +7674,7 @@ fn handleExternLibName(
74637674 .{ lib_name, lib_name },
74647675 );
74657676 }
7466 mod.comp.stage1AddLinkLib(lib_name) catch |err| {
7677 comp.stage1AddLinkLib(lib_name) catch |err| {
74677678 return sema.fail(block, src_loc, "unable to add link lib '{s}': {s}", .{
74687679 lib_name, @errorName(err),
74697680 });
......@@ -7502,7 +7713,6 @@ fn funcCommon(
75027713 noalias_bits: u32,
75037714 is_noinline: bool,
75047715) CompileError!Air.Inst.Ref {
7505 const fn_src = LazySrcLoc.nodeOffset(src_node_offset);
75067716 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };
75077717 const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = src_node_offset };
75087718
......@@ -7573,27 +7783,25 @@ fn funcCommon(
75737783 param_types[i] = param.ty;
75747784 sema.analyzeParameter(
75757785 block,
7576 fn_src,
75777786 .unneeded,
75787787 param,
75797788 comptime_params,
75807789 i,
75817790 &is_generic,
7582 is_extern,
75837791 cc_workaround,
7792 has_body,
75847793 ) catch |err| switch (err) {
75857794 error.NeededSourceLocation => {
75867795 const decl = sema.mod.declPtr(block.src_decl);
75877796 try sema.analyzeParameter(
75887797 block,
7589 fn_src,
75907798 Module.paramSrc(src_node_offset, sema.gpa, decl, i),
75917799 param,
75927800 comptime_params,
75937801 i,
75947802 &is_generic,
7595 is_extern,
75967803 cc_workaround,
7804 has_body,
75977805 );
75987806 return error.AnalysisFail;
75997807 },
......@@ -7601,18 +7809,17 @@ fn funcCommon(
76017809 };
76027810 }
76037811
7604 const ret_poison = if (!is_generic) rp: {
7605 if (sema.typeRequiresComptime(block, ret_ty_src, bare_return_type)) |ret_comptime| {
7606 is_generic = ret_comptime;
7607 break :rp bare_return_type.tag() == .generic_poison;
7608 } else |err| switch (err) {
7609 error.GenericPoison => {
7610 is_generic = true;
7611 break :rp true;
7612 },
7613 else => |e| return e,
7614 }
7615 } else bare_return_type.tag() == .generic_poison;
7812 var ret_ty_requires_comptime = false;
7813 const ret_poison = if (sema.typeRequiresComptime(block, ret_ty_src, bare_return_type)) |ret_comptime| rp: {
7814 ret_ty_requires_comptime = ret_comptime;
7815 break :rp bare_return_type.tag() == .generic_poison;
7816 } else |err| switch (err) {
7817 error.GenericPoison => rp: {
7818 is_generic = true;
7819 break :rp true;
7820 },
7821 else => |e| return e,
7822 };
76167823
76177824 const return_type = if (!inferred_error_set or ret_poison)
76187825 bare_return_type
......@@ -7657,6 +7864,41 @@ fn funcCommon(
76577864 return sema.failWithOwnedErrorMsg(msg);
76587865 }
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
76607902 const arch = sema.mod.getTarget().cpu.arch;
76617903 if (switch (cc_workaround) {
76627904 .Unspecified, .C, .Naked, .Async, .Inline => null,
......@@ -7699,6 +7941,9 @@ fn funcCommon(
76997941 if (cc_workaround == .Inline and is_noinline) {
77007942 return sema.fail(block, cc_src, "'noinline' function cannot have callconv 'Inline'", .{});
77017943 }
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
77037948 break :fn_ty try Type.Tag.function.create(sema.arena, .{
77047949 .param_types = param_types,
......@@ -7760,11 +8005,6 @@ fn funcCommon(
77608005 break :blk if (sema.comptime_args.len == 0) null else sema.comptime_args.ptr;
77618006 } 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
77688008 const hash = new_func.hash;
77698009 const fn_payload = try sema.arena.create(Value.Payload.Function);
77708010 new_func.* = .{
......@@ -7772,13 +8012,11 @@ fn funcCommon(
77728012 .zir_body_inst = func_inst,
77738013 .owner_decl = sema.owner_decl_index,
77748014 .comptime_args = comptime_args,
7775 .anytype_args = undefined,
77768015 .hash = hash,
77778016 .lbrace_line = src_locs.lbrace_line,
77788017 .rbrace_line = src_locs.rbrace_line,
77798018 .lbrace_column = @truncate(u16, src_locs.columns),
77808019 .rbrace_column = @truncate(u16, src_locs.columns >> 16),
7781 .param_names = param_names,
77828020 .branch_quota = default_branch_quota,
77838021 .is_noinline = is_noinline,
77848022 };
......@@ -7796,30 +8034,20 @@ fn funcCommon(
77968034fn analyzeParameter(
77978035 sema: *Sema,
77988036 block: *Block,
7799 func_src: LazySrcLoc,
78008037 param_src: LazySrcLoc,
78018038 param: Block.Param,
78028039 comptime_params: []bool,
78038040 i: usize,
78048041 is_generic: *bool,
7805 is_extern: bool,
78068042 cc: std.builtin.CallingConvention,
8043 has_body: bool,
78078044) !void {
78088045 const requires_comptime = try sema.typeRequiresComptime(block, param_src, param.ty);
78098046 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;
78118048 is_generic.* = is_generic.* or this_generic;
7812 if (is_extern and this_generic) {
7813 // TODO this check should exist somewhere for notes.
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);
8049 if (param.is_comptime and !Type.fnCallingConventionAllowsZigTypes(cc)) {
8050 return sema.fail(block, param_src, "comptime parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});
78238051 }
78248052 if (this_generic and !Type.fnCallingConventionAllowsZigTypes(cc)) {
78258053 return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});
......@@ -7852,9 +8080,9 @@ fn analyzeParameter(
78528080 };
78538081 return sema.failWithOwnedErrorMsg(msg);
78548082 }
7855 if (requires_comptime and !param.is_comptime) {
8083 if (!sema.is_generic_instantiation and requires_comptime and !param.is_comptime and has_body) {
78568084 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", .{
78588086 param.ty.fmt(sema.mod),
78598087 });
78608088 errdefer msg.destroy(sema.gpa);
......@@ -7885,25 +8113,19 @@ fn zirParam(
78858113 // Make sure any nested param instructions don't clobber our work.
78868114 const prev_params = block.params;
78878115 const prev_preallocated_new_func = sema.preallocated_new_func;
8116 const prev_no_partial_func_type = sema.no_partial_func_ty;
78888117 block.params = .{};
78898118 sema.preallocated_new_func = null;
8119 sema.no_partial_func_ty = true;
78908120 defer {
78918121 block.params.deinit(sema.gpa);
78928122 block.params = prev_params;
78938123 sema.preallocated_new_func = prev_preallocated_new_func;
8124 sema.no_partial_func_ty = prev_no_partial_func_type;
78948125 }
78958126
78968127 if (sema.resolveBody(block, body, inst)) |param_ty_inst| {
78978128 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 }
79078129 break :param_ty param_ty;
79088130 } else |err| break :err err;
79098131 } else |err| break :err err;
......@@ -7952,7 +8174,7 @@ fn zirParam(
79528174
79538175 try block.params.append(sema.gpa, .{
79548176 .ty = param_ty,
7955 .is_comptime = is_comptime,
8177 .is_comptime = comptime_syntax,
79568178 .name = param_name,
79578179 });
79588180 const result = try sema.addConstant(param_ty, Value.initTag(.generic_poison));
......@@ -8638,13 +8860,11 @@ fn zirSwitchCapture(
86388860 switch (operand_ty.zigTypeTag()) {
86398861 .Union => {
86408862 const union_obj = operand_ty.cast(Type.Payload.Union).?.data;
8641 const enum_ty = union_obj.tag_ty;
8642
86438863 const first_item = try sema.resolveInst(items[0]);
86448864 // Previous switch validation ensured this will succeed
86458865 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).?);
86488868 const first_field = union_obj.fields.values()[first_field_index];
86498869
86508870 for (items[1..]) |item, i| {
......@@ -8652,7 +8872,7 @@ fn zirSwitchCapture(
86528872 // Previous switch validation ensured this will succeed
86538873 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).?;
86568876 const field = union_obj.fields.values()[field_index];
86578877 if (!field.ty.eql(first_field.ty, sema.mod)) {
86588878 const msg = msg: {
......@@ -8776,6 +8996,9 @@ fn zirSwitchCond(
87768996 .ErrorSet,
87778997 .Enum,
87788998 => {
8999 if (operand_ty.isSlice()) {
9000 return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(sema.mod)});
9001 }
87799002 if ((try sema.typeHasOnePossibleValue(block, operand_src, operand_ty))) |opv| {
87809003 return sema.addConstant(operand_ty, opv);
87819004 }
......@@ -8852,12 +9075,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
88529075 },
88539076 };
88549077
8855 const union_originally = blk: {
9078 const maybe_union_ty = blk: {
88569079 const zir_data = sema.code.instructions.items(.data);
88579080 const cond_index = Zir.refToIndex(extra.data.operand).?;
88589081 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);
88609083 };
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
88629090 const operand_ty = sema.typeOf(operand);
88639091
......@@ -8892,7 +9120,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
88929120 .Union => unreachable, // handled in zirSwitchCond
88939121 .Enum => {
88949122 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;
88969126 mem.set(?Module.SwitchProngSrc, seen_fields, null);
88979127
88989128 // 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
94869716 }
94879717
94889718 if (scalar_cases_len + multi_cases_len == 0) {
9719 if (empty_enum) {
9720 return Air.Inst.Ref.void_value;
9721 }
94899722 if (special_prong == .none) {
94909723 return sema.fail(block, src, "switch must handle all possibilities", .{});
94919724 }
......@@ -9525,27 +9758,37 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
95259758 const item = try sema.resolveInst(item_ref);
95269759 // `item` is already guaranteed to be constant known.
95279760
9528 _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) {
9529 error.ComptimeBreak => {
9530 const zir_datas = sema.code.instructions.items(.data);
9531 const break_data = zir_datas[sema.comptime_break_inst].@"break";
9532 try sema.addRuntimeBreak(&case_block, .{
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();
9761 const analyze_body = if (union_originally) blk: {
9762 const item_val = sema.resolveConstValue(block, .unneeded, item, undefined) catch unreachable;
9763 const field_ty = maybe_union_ty.unionFieldType(item_val, sema.mod);
9764 break :blk field_ty.zigTypeTag() != .NoReturn;
9765 } else true;
95429766
9543 try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
9544 cases_extra.appendAssumeCapacity(1); // items_len
9545 cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
9546 cases_extra.appendAssumeCapacity(@enumToInt(item));
9547 cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
9548 }
9767 if (analyze_body) {
9768 _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) {
9769 error.ComptimeBreak => {
9770 const zir_datas = sema.code.instructions.items(.data);
9771 const break_data = zir_datas[sema.comptime_break_inst].@"break";
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
95509793 var is_first = true;
95519794 var prev_cond_br: Air.Inst.Index = undefined;
......@@ -9577,20 +9820,34 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
95779820 if (ranges_len == 0) {
95789821 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
95809833 const body = sema.code.extra[extra_index..][0..body_len];
95819834 extra_index += body_len;
9582 _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) {
9583 error.ComptimeBreak => {
9584 const zir_datas = sema.code.instructions.items(.data);
9585 const break_data = zir_datas[sema.comptime_break_inst].@"break";
9586 try sema.addRuntimeBreak(&case_block, .{
9587 .block_inst = break_data.block_inst,
9588 .operand = break_data.operand,
9589 .inst = sema.comptime_break_inst,
9590 });
9591 },
9592 else => |e| return e,
9593 };
9835 if (analyze_body) {
9836 _ = sema.analyzeBodyInner(&case_block, body) catch |err| switch (err) {
9837 error.ComptimeBreak => {
9838 const zir_datas = sema.code.instructions.items(.data);
9839 const break_data = zir_datas[sema.comptime_break_inst].@"break";
9840 try sema.addRuntimeBreak(&case_block, .{
9841 .block_inst = break_data.block_inst,
9842 .operand = break_data.operand,
9843 .inst = sema.comptime_break_inst,
9844 });
9845 },
9846 else => |e| return e,
9847 };
9848 } else {
9849 _ = try case_block.addNoOp(.unreach);
9850 }
95949851
95959852 try cases_extra.ensureUnusedCapacity(gpa, 2 + items.len +
95969853 case_block.instructions.items.len);
......@@ -9705,14 +9962,24 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
97059962 }
97069963
97079964 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()) {
97099966 var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope);
97109967 defer wip_captures.deinit();
97119968
97129969 case_block.instructions.shrinkRetainingCapacity(0);
97139970 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) {
97169983 _ = sema.analyzeBodyInner(&case_block, special.body) catch |err| switch (err) {
97179984 error.ComptimeBreak => {
97189985 const zir_datas = sema.code.instructions.items(.data);
......@@ -9728,9 +9995,11 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
97289995 } else {
97299996 // We still need a terminator in this block, but we have proven
97309997 // that it is unreachable.
9731 // TODO this should be a special safety panic other than unreachable, something
9732 // like "panic: switch operand had corrupt value not allowed by the type"
9733 try case_block.addUnreachable(src, true);
9998 if (case_block.wantSafety()) {
9999 _ = try sema.safetyPanic(&case_block, src, .corrupt_switch);
10000 } else {
10001 _ = try case_block.addNoOp(.unreach);
10002 }
973410003 }
973510004
973610005 try wip_captures.finalize();
......@@ -10194,16 +10463,14 @@ fn zirShl(
1019410463
1019510464 const val = switch (air_tag) {
1019610465 .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);
1019810467 if (scalar_ty.zigTypeTag() == .ComptimeInt) {
10199 break :val shifted;
10468 break :val shifted.wrapped_result;
1020010469 }
10201 const int_info = scalar_ty.intInfo(target);
10202 const truncated = try shifted.intTrunc(lhs_ty, sema.arena, int_info.signedness, int_info.bits, target);
10203 if (try sema.compare(block, src, truncated, .eq, shifted, lhs_ty)) {
10204 break :val shifted;
10470 if (shifted.overflowed.compareWithZero(.eq)) {
10471 break :val shifted.wrapped_result;
1020510472 }
10206 return sema.addConstUndef(lhs_ty);
10473 return sema.fail(block, src, "operation caused overflow", .{});
1020710474 },
1020810475
1020910476 .shl_sat => if (scalar_ty.zigTypeTag() == .ComptimeInt)
......@@ -10239,34 +10506,57 @@ fn zirShl(
1023910506 } else rhs;
1024010507
1024110508 try sema.requireRuntimeBlock(block, src, runtime_src);
10242 if (block.wantSafety() and air_tag == .shl_exact) {
10243 const op_ov_tuple_ty = try sema.overflowArithmeticTupleType(lhs_ty);
10244 const op_ov = try block.addInst(.{
10245 .tag = .shl_with_overflow,
10246 .data = .{ .ty_pl = .{
10247 .ty = try sema.addType(op_ov_tuple_ty),
10248 .payload = try sema.addExtra(Air.Bin{
10249 .lhs = lhs,
10250 .rhs = rhs,
10251 }),
10252 } },
10253 });
10254 const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty);
10255 const any_ov_bit = if (lhs_ty.zigTypeTag() == .Vector)
10256 try block.addInst(.{
10257 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
10258 .data = .{ .reduce = .{
10259 .operand = ov_bit,
10260 .operation = .Or,
10509 if (block.wantSafety()) {
10510 const bit_count = scalar_ty.intInfo(target).bits;
10511 if (!std.math.isPowerOfTwo(bit_count)) {
10512 const bit_count_val = try Value.Tag.int_u64.create(sema.arena, bit_count);
10513
10514 const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: {
10515 const bit_count_inst = try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, bit_count_val));
10516 const lt = try block.addCmpVector(rhs, bit_count_inst, .lt, try sema.addType(rhs_ty));
10517 break :ok try block.addInst(.{
10518 .tag = .reduce,
10519 .data = .{ .reduce = .{
10520 .operand = lt,
10521 .operation = .And,
10522 } },
10523 });
10524 } else ok: {
10525 const bit_count_inst = try sema.addConstant(rhs_ty, bit_count_val);
10526 break :ok try block.addBinOp(.cmp_lt, rhs, bit_count_inst);
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 }),
1026110541 } },
10262 })
10263 else
10264 ov_bit;
10265 const zero_ov = try sema.addConstant(Type.@"u1", Value.zero);
10266 const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov);
10542 });
10543 const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty);
10544 const any_ov_bit = if (lhs_ty.zigTypeTag() == .Vector)
10545 try block.addInst(.{
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);
10269 return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty);
10557 try sema.addSafetyCheck(block, no_ov, .shl_overflow);
10558 return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty);
10559 }
1027010560 }
1027110561 return block.addBinOp(air_tag, lhs, new_rhs);
1027210562}
......@@ -10333,7 +10623,7 @@ fn zirShr(
1033310623 // Detect if any ones would be shifted out.
1033410624 const truncated = try lhs_val.intTruncBitsAsValue(lhs_ty, sema.arena, .unsigned, rhs_val, target);
1033510625 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", .{});
1033710627 }
1033810628 }
1033910629 const val = try lhs_val.shr(rhs_val, lhs_ty, sema.arena, target);
......@@ -10345,20 +10635,43 @@ fn zirShr(
1034510635
1034610636 try sema.requireRuntimeBlock(block, src, runtime_src);
1034710637 const result = try block.addBinOp(air_tag, lhs, rhs);
10348 if (block.wantSafety() and air_tag == .shr_exact) {
10349 const back = try block.addBinOp(.shl, result, rhs);
10350
10351 const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: {
10352 const eql = try block.addCmpVector(lhs, back, .eq, try sema.addType(rhs_ty));
10353 break :ok try block.addInst(.{
10354 .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
10355 .data = .{ .reduce = .{
10356 .operand = eql,
10357 .operation = .And,
10358 } },
10359 });
10360 } else try block.addBinOp(.cmp_eq, lhs, back);
10361 try sema.addSafetyCheck(block, ok, .shr_overflow);
10638 if (block.wantSafety()) {
10639 const bit_count = scalar_ty.intInfo(target).bits;
10640 if (!std.math.isPowerOfTwo(bit_count)) {
10641 const bit_count_val = try Value.Tag.int_u64.create(sema.arena, bit_count);
10642
10643 const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: {
10644 const bit_count_inst = try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, bit_count_val));
10645 const lt = try block.addCmpVector(rhs, bit_count_inst, .lt, try sema.addType(rhs_ty));
10646 break :ok try block.addInst(.{
10647 .tag = .reduce,
10648 .data = .{ .reduce = .{
10649 .operand = lt,
10650 .operation = .And,
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 }
1036210675 }
1036310676 return result;
1036410677}
......@@ -11040,6 +11353,21 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
1104011353 const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(block, lhs_src, casted_lhs);
1104111354 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
1104311371 // TODO: emit compile error when .div is used on integers and there would be an
1104411372 // 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
1113011458 try sema.addDivByZeroSafety(block, resolved_type, maybe_rhs_val, casted_rhs, is_int);
1113111459 }
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) {
1113411467 .Optimized => Air.Inst.Tag.div_float_optimized,
1113511468 .Strict => Air.Inst.Tag.div_float,
1113611469 };
......@@ -11210,13 +11543,19 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1121011543 if (maybe_lhs_val) |lhs_val| {
1121111544 if (maybe_rhs_val) |rhs_val| {
1121211545 if (is_int) {
11213 // TODO: emit compile error if there is a remainder
11546 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 }
1121411550 return sema.addConstant(
1121511551 resolved_type,
1121611552 try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target),
1121711553 );
1121811554 } else {
11219 // TODO: emit compile error if there is a remainder
11555 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 }
1122011559 return sema.addConstant(
1122111560 resolved_type,
1122211561 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
1163411973 };
1163511974}
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
1163712365fn zirOverflowArithmetic(
1163812366 sema: *Sema,
1163912367 block: *Block,
......@@ -11894,9 +12622,7 @@ fn analyzeArithmetic(
1189412622
1189512623 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
1189612624 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
11897
11898 const lhs_scalar_ty = lhs_ty.scalarType();
11899 const rhs_scalar_ty = rhs_ty.scalarType();
12625
1190012626 const scalar_tag = resolved_type.scalarType().zigTypeTag();
1190112627
1190212628 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
......@@ -12242,206 +12968,6 @@ fn analyzeArithmetic(
1224212968 } else break :rs .{ .src = lhs_src, .air_tag = .mul_sat };
1224312969 } else break :rs .{ .src = rhs_src, .air_tag = .mul_sat };
1224412970 },
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 },
1244512971 else => unreachable,
1244612972 }
1244712973 };
......@@ -12485,33 +13011,6 @@ fn analyzeArithmetic(
1248513011 return sema.tupleFieldValByIndex(block, src, op_ov, 0, op_ov_tuple_ty);
1248613012 }
1248713013 }
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 }
1251513014 }
1251613015 return block.addBinOp(rs.air_tag, casted_lhs, casted_rhs);
1251713016}
......@@ -12557,7 +13056,7 @@ fn analyzePtrArithmetic(
1255713056 // The resulting pointer is aligned to the lcd between the offset (an
1255813057 // arbitrary number) and the alignment factor (always a power of two,
1255913058 // 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
1256213061 break :t try Type.ptr(sema.arena, sema.mod, .{
1256313062 .pointee_type = ptr_info.pointee_type,
......@@ -12896,6 +13395,14 @@ fn analyzeCmpUnionTag(
1289613395 const coerced_tag = try sema.coerce(block, union_tag_ty, tag, tag_src);
1289713396 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
1289913406 return sema.cmpSelf(block, src, coerced_union, coerced_tag, op, un_src, tag_src);
1290013407}
1290113408
......@@ -13961,10 +14468,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1396114468 else
1396214469 field.default_val;
1396314470 const default_val_ptr = try sema.optRefValue(block, src, field.ty, opt_default_val);
13964 const alignment = switch (layout) {
13965 .Auto, .Extern => field.normalAlignment(target),
13966 .Packed => 0,
13967 };
14471 const alignment = field.alignment(target, layout);
1396814472
1396914473 struct_field_fields.* = .{
1397014474 // name: []const u8,
......@@ -14003,13 +14507,27 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1400314507
1400414508 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);
1400714523 field_values.* = .{
1400814524 // layout: ContainerLayout,
1400914525 try Value.Tag.enum_field_index.create(
1401014526 sema.arena,
1401114527 @enumToInt(layout),
1401214528 ),
14529 // backing_integer: ?type,
14530 backing_integer_val,
1401314531 // fields: []const StructField,
1401414532 fields_val,
1401514533 // decls: []const Declaration,
......@@ -14047,8 +14565,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1404714565 );
1404814566 },
1404914567 .BoundFn => @panic("TODO remove this type from the language and compiler"),
14050 .Frame => return sema.fail(block, src, "TODO: implement zirTypeInfo for Frame", .{}),
14051 .AnyFrame => return sema.fail(block, src, "TODO: implement zirTypeInfo for AnyFrame", .{}),
14568 .Frame => return sema.failWithUseOfAsync(block, src),
14569 .AnyFrame => return sema.failWithUseOfAsync(block, src),
1405214570 }
1405314571}
1405414572
......@@ -14333,6 +14851,20 @@ fn zirBoolBr(
1433314851 const rhs_result = try sema.resolveBody(rhs_block, body, inst);
1433414852 _ = 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
1433614868 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len +
1433714869 then_block.instructions.items.len + else_block.instructions.items.len +
1433814870 @typeInfo(Air.Block).Struct.fields.len + child_block.instructions.items.len + 1);
......@@ -14345,7 +14877,7 @@ fn zirBoolBr(
1434514877 sema.air_extra.appendSliceAssumeCapacity(else_block.instructions.items);
1434614878
1434714879 _ = try child_block.addInst(.{ .tag = .cond_br, .data = .{ .pl_op = .{
14348 .operand = lhs,
14880 .operand = cond,
1434914881 .payload = cond_br_payload,
1435014882 } } });
1435114883
......@@ -14715,10 +15247,83 @@ fn zirRetLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir
1471515247 const operand = try sema.analyzeLoad(block, src, ret_ptr, src);
1471615248 return sema.analyzeRet(block, operand, src);
1471715249 }
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
1471815256 _ = try block.addUnOp(.ret_load, ret_ptr);
1471915257 return always_noreturn;
1472015258}
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
1472215327fn addToInferredErrorSet(sema: *Sema, uncasted_operand: Air.Inst.Ref) !void {
1472315328 assert(sema.fn_ret_ty.zigTypeTag() == .ErrorUnion);
1472415329
......@@ -14764,27 +15369,15 @@ fn analyzeRet(
1476415369 return always_noreturn;
1476515370 }
1476615371
14767 // TODO implement this feature in all the backends and then delete this check.
14768 const backend_supports_error_return_tracing =
14769 sema.mod.comp.bin_file.options.use_llvm;
15372 try sema.resolveTypeLayout(block, src, sema.fn_ret_ty);
1477015373
14771 if (sema.fn_ret_ty.isError() and
14772 sema.mod.comp.bin_file.options.error_return_tracing and
14773 backend_supports_error_return_tracing)
14774 ret_err: {
14775 if (try sema.resolveMaybeUndefVal(block, src, operand)) |ret_val| {
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);
15374 if (sema.wantErrorReturnTracing()) {
15375 // Avoid adding a frame to the error return trace in case the value is comptime-known
15376 // to be not an error.
15377 const is_non_err = try sema.analyzeIsNonErr(block, src, operand);
15378 return retWithErrTracing(sema, block, src, is_non_err, .ret, operand);
1478515379 }
1478615380
14787 try sema.resolveTypeLayout(block, src, sema.fn_ret_ty);
1478815381 _ = try block.addUnOp(.ret, operand);
1478915382 return always_noreturn;
1479015383}
......@@ -15015,7 +15608,9 @@ fn unionInit(
1501515608 const init = try sema.coerce(block, field.ty, uncasted_init, init_src);
1501615609
1501715610 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);
1501915614 return sema.addConstant(union_ty, try Value.Tag.@"union".create(sema.arena, .{
1502015615 .tag = tag_val,
1502115616 .val = init_val,
......@@ -15113,7 +15708,9 @@ fn zirStructInit(
1511315708 const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
1511415709 const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);
1511515710 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
1511815715 const init_inst = try sema.resolveInst(item.data.init);
1511915716 if (try sema.resolveMaybeUndefVal(block, field_src, init_inst)) |val| {
......@@ -15161,6 +15758,8 @@ fn finishStructInit(
1516115758 const gpa = sema.gpa;
1516215759
1516315760 var root_msg: ?*Module.ErrorMsg = null;
15761 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
15762
1516415763 if (struct_ty.isAnonStruct()) {
1516515764 const struct_obj = struct_ty.castTag(.anon_struct).?.data;
1516615765 for (struct_obj.values) |default_val, i| {
......@@ -15216,6 +15815,7 @@ fn finishStructInit(
1521615815 }
1521715816
1521815817 if (root_msg) |msg| {
15818 root_msg = null;
1521915819 if (struct_ty.castTag(.@"struct")) |struct_obj| {
1522015820 const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod);
1522115821 defer gpa.free(fqn);
......@@ -15245,6 +15845,7 @@ fn finishStructInit(
1524515845 }
1524615846
1524715847 if (is_ref) {
15848 try sema.resolveStructLayout(block, dest_src, struct_ty);
1524815849 const target = sema.mod.getTarget();
1524915850 const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{
1525015851 .pointee_type = struct_ty,
......@@ -15619,9 +16220,10 @@ fn fieldType(
1561916220 field_src: LazySrcLoc,
1562016221 ty_src: LazySrcLoc,
1562116222) CompileError!Air.Inst.Ref {
15622 const resolved_ty = try sema.resolveTypeFields(block, ty_src, aggregate_ty);
15623 var cur_ty = resolved_ty;
16223 var cur_ty = aggregate_ty;
1562416224 while (true) {
16225 const resolved_ty = try sema.resolveTypeFields(block, ty_src, cur_ty);
16226 cur_ty = resolved_ty;
1562516227 switch (cur_ty.zigTypeTag()) {
1562616228 .Struct => {
1562716229 if (cur_ty.isAnonStruct()) {
......@@ -15693,7 +16295,7 @@ fn zirFrame(
1569316295 extended: Zir.Inst.Extended.InstData,
1569416296) CompileError!Air.Inst.Ref {
1569516297 const src = LazySrcLoc.nodeOffset(@bitCast(i32, extended.operand));
15696 return sema.fail(block, src, "TODO: Sema.zirFrame", .{});
16298 return sema.failWithUseOfAsync(block, src);
1569716299}
1569816300
1569916301fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -15742,7 +16344,7 @@ fn zirUnaryMath(
1574216344 block: *Block,
1574316345 inst: Zir.Inst.Index,
1574416346 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,
1574616348) CompileError!Air.Inst.Ref {
1574716349 const tracy = trace(@src());
1574816350 defer tracy.end();
......@@ -15853,25 +16455,30 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1585316455 const field_name = enum_ty.enumFieldName(field_index);
1585416456 return sema.addStrLit(block, field_name);
1585516457 }
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 }
1585616463 // In case the value is runtime-known, we have an AIR instruction for this instead
1585716464 // of trying to lower it in Sema because an optimization pass may result in the operand
1585816465 // being comptime-known, which would let us elide the `tag_name` AIR instruction.
1585916466 return block.addUnOp(.tag_name, casted_operand);
1586016467}
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 {
1586316470 const mod = sema.mod;
15864 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
15865 const src = inst_data.src();
16471 const name_strategy = @intToEnum(Zir.Inst.NameStrategy, extended.small);
16472 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
16473 const src = LazySrcLoc.nodeOffset(extra.node);
1586616474 const type_info_ty = try sema.resolveBuiltinTypeFields(block, src, "Type");
15867 const uncasted_operand = try sema.resolveInst(inst_data.operand);
15868 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
16475 const uncasted_operand = try sema.resolveInst(extra.operand);
16476 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
1586916477 const type_info = try sema.coerce(block, type_info_ty, uncasted_operand, operand_src);
1587016478 const val = try sema.resolveConstValue(block, operand_src, type_info, "operand to @Type must be comptime known");
1587116479 const union_val = val.cast(Value.Payload.Union).?.data;
15872 const tag_ty = type_info_ty.unionTagType().?;
1587316480 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).?;
1587516482 if (union_val.val.anyUndef()) return sema.failWithUseOfUndef(block, src);
1587616483 switch (@intToEnum(std.builtin.TypeId, tag_index)) {
1587716484 .Type => return Air.Inst.Ref.type_type,
......@@ -15882,7 +16489,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
1588216489 .ComptimeInt => return Air.Inst.Ref.comptime_int_type,
1588316490 .Undefined => return Air.Inst.Ref.undefined_type,
1588416491 .Null => return Air.Inst.Ref.null_type,
15885 .AnyFrame => return Air.Inst.Ref.anyframe_type,
16492 .AnyFrame => return sema.failWithUseOfAsync(block, src),
1588616493 .EnumLiteral => return Air.Inst.Ref.enum_literal_type,
1588716494 .Int => {
1588816495 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
1594516552 if (!try sema.intFitsInType(block, src, alignment_val, Type.u32, null)) {
1594616553 return sema.fail(block, src, "alignment must fit in 'u32'", .{});
1594716554 }
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
1595016557 var buffer: Value.ToTypeBuffer = undefined;
1595116558 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
1611016717 const struct_val = union_val.val.castTag(.aggregate).?.data;
1611116718 // layout: containerlayout,
1611216719 const layout_val = struct_val[0];
16720 // backing_int: ?type,
16721 const backing_int_val = struct_val[1];
1611316722 // fields: []const enumfield,
16114 const fields_val = struct_val[1];
16723 const fields_val = struct_val[2];
1611516724 // decls: []const declaration,
16116 const decls_val = struct_val[2];
16725 const decls_val = struct_val[3];
1611716726 // 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
1612016732 // Decls
1612116733 if (decls_val.sliceLen(mod) > 0) {
1612216734 return sema.fail(block, src, "reified structs must have no decls", .{});
1612316735 }
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
1612516741 return if (is_tuple_val.toBool())
1612616742 try sema.reifyTuple(block, src, fields_val)
1612716743 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);
1612916745 },
1613016746 .Enum => {
1613116747 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
1617116787 };
1617216788 const enum_ty = Type.initPayload(&enum_ty_payload.base);
1617316789 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, .{
1617516791 .ty = Type.type,
1617616792 .val = enum_val,
16177 }, .anon, "enum", null);
16793 }, name_strategy, "enum", inst);
1617816794 const new_decl = mod.declPtr(new_decl_index);
1617916795 new_decl.owns_tv = true;
1618016796 errdefer mod.abortAnonDecl(new_decl_index);
......@@ -16185,7 +16801,6 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
1618516801 .tag_ty_inferred = false,
1618616802 .fields = .{},
1618716803 .values = .{},
16188 .node_offset = src.node_offset.x,
1618916804 .namespace = .{
1619016805 .parent = block.namespace,
1619116806 .ty = enum_ty,
......@@ -16204,43 +16819,39 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
1620416819
1620516820 // Fields
1620616821 const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod));
16207 if (fields_len > 0) {
16208 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
16209 try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{
16210 .ty = enum_obj.tag_ty,
16211 .mod = mod,
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 );
16822 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
16823 try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{
16824 .ty = enum_obj.tag_ty,
16825 .mod = mod,
16826 });
1622916827
16230 const gop = enum_obj.fields.getOrPutAssumeCapacity(field_name);
16231 if (gop.found_existing) {
16232 // TODO: better source location
16233 return sema.fail(block, src, "duplicate enum tag {s}", .{field_name});
16234 }
16828 var i: usize = 0;
16829 while (i < fields_len) : (i += 1) {
16830 const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i);
16831 const field_struct_val = elem_val.castTag(.aggregate).?.data;
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);
16237 enum_obj.values.putAssumeCapacityNoClobberContext(copied_tag_val, {}, .{
16238 .ty = enum_obj.tag_ty,
16239 .mod = mod,
16240 });
16844 const gop = enum_obj.fields.getOrPutAssumeCapacity(field_name);
16845 if (gop.found_existing) {
16846 // TODO: better source location
16847 return sema.fail(block, src, "duplicate enum tag {s}", .{field_name});
1624116848 }
16242 } else {
16243 return sema.fail(block, src, "enums must have at least one field", .{});
16849
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 });
1624416855 }
1624516856
1624616857 try new_decl.finalizeNewArena(&new_decl_arena);
......@@ -16268,17 +16879,16 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
1626816879 };
1626916880 const opaque_ty = Type.initPayload(&opaque_ty_payload.base);
1627016881 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, .{
1627216883 .ty = Type.type,
1627316884 .val = opaque_val,
16274 }, .anon, "opaque", null);
16885 }, name_strategy, "opaque", inst);
1627516886 const new_decl = mod.declPtr(new_decl_index);
1627616887 new_decl.owns_tv = true;
1627716888 errdefer mod.abortAnonDecl(new_decl_index);
1627816889
1627916890 opaque_obj.* = .{
1628016891 .owner_decl = new_decl_index,
16281 .node_offset = src.node_offset.x,
1628216892 .namespace = .{
1628316893 .parent = block.namespace,
1628416894 .ty = opaque_ty,
......@@ -16327,10 +16937,10 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
1632716937 };
1632816938 const union_ty = Type.initPayload(&union_payload.base);
1632916939 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, .{
1633116941 .ty = Type.type,
1633216942 .val = new_union_val,
16333 }, .anon, "union", null);
16943 }, name_strategy, "union", inst);
1633416944 const new_decl = mod.declPtr(new_decl_index);
1633516945 new_decl.owns_tv = true;
1633616946 errdefer mod.abortAnonDecl(new_decl_index);
......@@ -16338,7 +16948,6 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
1633816948 .owner_decl = new_decl_index,
1633916949 .tag_ty = Type.initTag(.@"null"),
1634016950 .fields = .{},
16341 .node_offset = src.node_offset.x,
1634216951 .zir_index = inst,
1634316952 .layout = layout,
1634416953 .status = .have_field_types,
......@@ -16367,58 +16976,54 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
1636716976 }
1636816977
1636916978 // Fields
16370 if (fields_len > 0) {
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];
16979 try union_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
1638416980
16385 const field_name = try name_val.toAllocatedBytes(
16386 Type.initTag(.const_slice_u8),
16387 new_decl_arena_allocator,
16388 sema.mod,
16389 );
16981 var i: usize = 0;
16982 while (i < fields_len) : (i += 1) {
16983 const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i);
16984 const field_struct_val = elem_val.castTag(.aggregate).?.data;
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| {
16392 set.putAssumeCapacity(field_name, {});
16393 }
16993 const field_name = try name_val.toAllocatedBytes(
16994 Type.initTag(.const_slice_u8),
16995 new_decl_arena_allocator,
16996 sema.mod,
16997 );
1639416998
16395 if (tag_ty_field_names) |*names| {
16396 const enum_has_field = names.orderedRemove(field_name);
16397 if (!enum_has_field) {
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 }
16999 if (enum_field_names) |set| {
17000 set.putAssumeCapacity(field_name, {});
17001 }
1640717002
16408 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);
16409 if (gop.found_existing) {
16410 // TODO: better source location
16411 return sema.fail(block, src, "duplicate union field {s}", .{field_name});
17003 if (tag_ty_field_names) |*names| {
17004 const enum_has_field = names.orderedRemove(field_name);
17005 if (!enum_has_field) {
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);
1641217013 }
17014 }
1641317015
16414 var buffer: Value.ToTypeBuffer = undefined;
16415 gop.value_ptr.* = .{
16416 .ty = try field_type_val.toType(&buffer).copy(new_decl_arena_allocator),
16417 .abi_align = @intCast(u32, alignment_val.toUnsignedInt(target)),
16418 };
17016 const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);
17017 if (gop.found_existing) {
17018 // TODO: better source location
17019 return sema.fail(block, src, "duplicate union field {s}", .{field_name});
1641917020 }
16420 } else {
16421 return sema.fail(block, src, "unions must have at least one field", .{});
17021
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 };
1642217027 }
1642317028
1642417029 if (tag_ty_field_names) |names| {
......@@ -16534,7 +17139,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
1653417139 return sema.addType(ty);
1653517140 },
1653617141 .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),
1653817143 }
1653917144}
1654017145
......@@ -16621,8 +17226,10 @@ fn reifyStruct(
1662117226 block: *Block,
1662217227 inst: Zir.Inst.Index,
1662317228 src: LazySrcLoc,
16624 layout_val: Value,
17229 layout: std.builtin.Type.ContainerLayout,
17230 backing_int_val: Value,
1662517231 fields_val: Value,
17232 name_strategy: Zir.Inst.NameStrategy,
1662617233) CompileError!Air.Inst.Ref {
1662717234 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
1662817235 errdefer new_decl_arena.deinit();
......@@ -16632,19 +17239,18 @@ fn reifyStruct(
1663217239 const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj);
1663317240 const new_struct_val = try Value.Tag.ty.create(new_decl_arena_allocator, struct_ty);
1663417241 const mod = sema.mod;
16635 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, .{
17242 const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
1663617243 .ty = Type.type,
1663717244 .val = new_struct_val,
16638 }, .anon, "struct", null);
17245 }, name_strategy, "struct", inst);
1663917246 const new_decl = mod.declPtr(new_decl_index);
1664017247 new_decl.owns_tv = true;
1664117248 errdefer mod.abortAnonDecl(new_decl_index);
1664217249 struct_obj.* = .{
1664317250 .owner_decl = new_decl_index,
1664417251 .fields = .{},
16645 .node_offset = src.node_offset.x,
1664617252 .zir_index = inst,
16647 .layout = layout_val.toEnum(std.builtin.Type.ContainerLayout),
17253 .layout = layout,
1664817254 .status = .have_field_types,
1664917255 .known_non_opv = false,
1665017256 .namespace = .{
......@@ -16710,6 +17316,41 @@ fn reifyStruct(
1671017316 };
1671117317 }
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
1671317354 try new_decl.finalizeNewArena(&new_decl_arena);
1671417355 return sema.analyzeDeclVal(block, src, new_decl_index);
1671517356}
......@@ -16736,13 +17377,13 @@ fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1673617377fn zirFrameType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
1673717378 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
1673817379 const src = inst_data.src();
16739 return sema.fail(block, src, "TODO: Sema.zirFrameType", .{});
17380 return sema.failWithUseOfAsync(block, src);
1674017381}
1674117382
1674217383fn zirFrameSize(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
1674317384 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
1674417385 const src = inst_data.src();
16745 return sema.fail(block, src, "TODO: Sema.zirFrameSize", .{});
17386 return sema.failWithUseOfAsync(block, src);
1674617387}
1674717388
1674817389fn 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
1683417475 }
1683517476
1683617477 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())) {
1683817479 if (!type_res.isAllowzeroPtr()) {
1683917480 const is_non_zero = try block.addBinOp(.cmp_neq, operand_coerced, .zero_usize);
1684017481 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
1693117572 }
1693217573
1693317574 try sema.requireRuntimeBlock(block, src, operand_src);
16934 if (block.wantSafety() and !dest_ty.isAnyError()) {
16935 const err_int_inst = try block.addBitCast(Type.u16, operand);
16936 // TODO: Output a switch instead of chained OR's.
16937 var found_match: Air.Inst.Ref = undefined;
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);
17575 if (block.wantSafety() and !dest_ty.isAnyError() and sema.mod.comp.bin_file.options.use_llvm) {
17576 const err_int_inst = try block.addBitCast(Type.err_int, operand);
17577 const ok = try block.addTyOp(.error_set_has_value, dest_ty, err_int_inst);
17578 try sema.addSafetyCheck(block, ok, .invalid_error_code);
1694517579 }
1694617580 return block.addBitCast(dest_ty, operand);
1694717581}
......@@ -16969,6 +17603,15 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1696917603 else
1697017604 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
1697217615 const dest_elem_ty = dest_ty.elemType2();
1697317616 try sema.resolveTypeLayout(block, dest_ty_src, dest_elem_ty);
1697417617 const dest_align = dest_ty.ptrAlignment(target);
......@@ -17126,7 +17769,9 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
1712617769 }
1712717770
1712817771 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 {
1713017775 const val_payload = try sema.arena.create(Value.Payload.U64);
1713117776 val_payload.* = .{
1713217777 .base = .{ .tag = .int_u64 },
......@@ -17145,7 +17790,7 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
1714517790 const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);
1714617791 const ok = if (ptr_ty.isSlice()) ok: {
1714717792 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);
1714917794 break :ok try block.addBinOp(.bit_or, len_zero, is_aligned);
1715017795 } else is_aligned;
1715117796 try sema.addSafetyCheck(block, ok, .incorrect_alignment);
......@@ -17158,11 +17803,11 @@ fn zirBitCount(
1715817803 block: *Block,
1715917804 inst: Zir.Inst.Index,
1716017805 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,
1716217807) CompileError!Air.Inst.Ref {
1716317808 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
1716417809 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 };
1716617811 const operand = try sema.resolveInst(inst_data.operand);
1716717812 const operand_ty = sema.typeOf(operand);
1716817813 _ = try checkIntOrVector(sema, block, operand, operand_src);
......@@ -17214,17 +17859,16 @@ fn zirBitCount(
1721417859fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
1721517860 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
1721617861 const src = inst_data.src();
17217 const ty_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 };
17862 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
1721917863 const operand = try sema.resolveInst(inst_data.operand);
1722017864 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);
1722217866 const target = sema.mod.getTarget();
1722317867 const bits = scalar_ty.intInfo(target).bits;
1722417868 if (bits % 8 != 0) {
1722517869 return sema.fail(
1722617870 block,
17227 ty_src,
17871 operand_src,
1722817872 "@byteSwap requires the number of bits to be evenly divisible by 8, but {} has {} bits",
1722917873 .{ scalar_ty.fmt(sema.mod), bits },
1723017874 );
......@@ -17235,7 +17879,7 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1723517879 }
1723617880
1723717881 switch (operand_ty.zigTypeTag()) {
17238 .Int, .ComptimeInt => {
17882 .Int => {
1723917883 const runtime_src = if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
1724017884 if (val.isUndef()) return sema.addConstUndef(operand_ty);
1724117885 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
1727317917fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
1727417918 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
1727517919 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 };
1727717921 const operand = try sema.resolveInst(inst_data.operand);
1727817922 const operand_ty = sema.typeOf(operand);
1727917923 _ = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src);
......@@ -18973,13 +19617,13 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
1897319617fn zirBuiltinAsyncCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
1897419618 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1897519619 const src = inst_data.src();
18976 return sema.fail(block, src, "TODO: Sema.zirBuiltinAsyncCall", .{});
19620 return sema.failWithUseOfAsync(block, src);
1897719621}
1897819622
1897919623fn zirResume(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
1898019624 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
1898119625 const src = inst_data.src();
18982 return sema.fail(block, src, "TODO: Sema.zirResume", .{});
19626 return sema.failWithUseOfAsync(block, src);
1898319627}
1898419628
1898519629fn zirAwait(
......@@ -18990,7 +19634,7 @@ fn zirAwait(
1899019634 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
1899119635 const src = inst_data.src();
1899219636
18993 return sema.fail(block, src, "TODO: Sema.zirAwait", .{});
19637 return sema.failWithUseOfAsync(block, src);
1899419638}
1899519639
1899619640fn zirAwaitNosuspend(
......@@ -19001,7 +19645,7 @@ fn zirAwaitNosuspend(
1900119645 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
1900219646 const src = LazySrcLoc.nodeOffset(extra.node);
1900319647
19004 return sema.fail(block, src, "TODO: Sema.zirAwaitNosuspend", .{});
19648 return sema.failWithUseOfAsync(block, src);
1900519649}
1900619650
1900719651fn zirVarExtended(
......@@ -19670,6 +20314,8 @@ fn validateRunTimeType(
1967020314 };
1967120315}
1967220316
20317const TypeSet = std.HashMapUnmanaged(Type, void, Type.HashContext64, std.hash_map.default_max_load_percentage);
20318
1967320319fn explainWhyTypeIsComptime(
1967420320 sema: *Sema,
1967520321 block: *Block,
......@@ -19677,6 +20323,22 @@ fn explainWhyTypeIsComptime(
1967720323 msg: *Module.ErrorMsg,
1967820324 src_loc: Module.SrcLoc,
1967920325 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,
1968020342) CompileError!void {
1968120343 const mod = sema.mod;
1968220344 switch (ty.zigTypeTag()) {
......@@ -19714,7 +20376,7 @@ fn explainWhyTypeIsComptime(
1971420376 },
1971520377
1971620378 .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);
1971820380 },
1971920381 .Pointer => {
1972020382 const elem_ty = ty.elemType2();
......@@ -19732,18 +20394,20 @@ fn explainWhyTypeIsComptime(
1973220394 }
1973320395 return;
1973420396 }
19735 try sema.explainWhyTypeIsComptime(block, src, msg, src_loc, ty.elemType());
20397 try sema.explainWhyTypeIsComptimeInner(block, src, msg, src_loc, ty.elemType(), type_set);
1973620398 },
1973720399
1973820400 .Optional => {
1973920401 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);
1974120403 },
1974220404 .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);
1974420406 },
1974520407
1974620408 .Struct => {
20409 if ((try type_set.getOrPutContext(sema.gpa, ty, .{ .mod = mod })).found_existing) return;
20410
1974720411 if (ty.castTag(.@"struct")) |payload| {
1974820412 const struct_obj = payload.data;
1974920413 for (struct_obj.fields.values()) |field, i| {
......@@ -19751,9 +20415,10 @@ fn explainWhyTypeIsComptime(
1975120415 .index = i,
1975220416 .range = .type,
1975320417 });
20418
1975420419 if (try sema.typeRequiresComptime(block, src, field.ty)) {
1975520420 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);
1975720422 }
1975820423 }
1975920424 }
......@@ -19761,6 +20426,8 @@ fn explainWhyTypeIsComptime(
1976120426 },
1976220427
1976320428 .Union => {
20429 if ((try type_set.getOrPutContext(sema.gpa, ty, .{ .mod = mod })).found_existing) return;
20430
1976420431 if (ty.cast(Type.Payload.Union)) |payload| {
1976520432 const union_obj = payload.data;
1976620433 for (union_obj.fields.values()) |field, i| {
......@@ -19768,9 +20435,10 @@ fn explainWhyTypeIsComptime(
1976820435 .index = i,
1976920436 .range = .type,
1977020437 });
20438
1977120439 if (try sema.typeRequiresComptime(block, src, field.ty)) {
1977220440 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);
1977420442 }
1977520443 }
1977620444 }
......@@ -19911,8 +20579,8 @@ fn validatePackedType(ty: Type) bool {
1991120579 .AnyFrame,
1991220580 .Fn,
1991320581 .Array,
19914 .Optional,
1991520582 => return false,
20583 .Optional => return ty.isPtrLikeOptional(),
1991620584 .Void,
1991720585 .Bool,
1991820586 .Float,
......@@ -19978,11 +20646,13 @@ pub const PanicId = enum {
1997820646 shl_overflow,
1997920647 shr_overflow,
1998020648 divide_by_zero,
19981 remainder_division_zero_negative,
1998220649 exact_division_remainder,
1998320650 /// TODO make this call `std.builtin.panicInactiveUnionField`.
1998420651 inactive_union_field,
1998520652 integer_part_out_of_bounds,
20653 corrupt_switch,
20654 shift_rhs_too_big,
20655 invalid_enum_value,
1998620656};
1998720657
1998820658fn addSafetyCheck(
......@@ -20076,7 +20746,7 @@ fn panicWithMsg(
2007620746 const arena = sema.arena;
2007720747
2007820748 const this_feature_is_implemented_in_the_backend =
20079 mod.comp.bin_file.options.object_format == .c or
20749 mod.comp.bin_file.options.target.ofmt == .c or
2008020750 mod.comp.bin_file.options.use_llvm;
2008120751 if (!this_feature_is_implemented_in_the_backend) {
2008220752 // TODO implement this feature in all the backends and then delete this branch
......@@ -20274,10 +20944,12 @@ fn safetyPanic(
2027420944 .shl_overflow => "left shift overflowed bits",
2027520945 .shr_overflow => "right shift overflowed bits",
2027620946 .divide_by_zero => "division by zero",
20277 .remainder_division_zero_negative => "remainder division by zero or negative value",
2027820947 .exact_division_remainder => "exact division produced remainder",
2027920948 .inactive_union_field => "access of inactive union field",
2028020949 .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",
2028120953 };
2028220954
2028320955 const msg_inst = msg_inst: {
......@@ -20736,14 +21408,30 @@ fn fieldCallBind(
2073621408 switch (concrete_ty.zigTypeTag()) {
2073721409 .Struct => {
2073821410 const struct_ty = try sema.resolveTypeFields(block, src, concrete_ty);
20739 const struct_obj = struct_ty.castTag(.@"struct").?.data;
20740
20741 const field_index_usize = struct_obj.fields.getIndex(field_name) orelse
20742 break :find_field;
20743 const field_index = @intCast(u32, field_index_usize);
20744 const field = struct_obj.fields.values()[field_index];
21411 if (struct_ty.castTag(.@"struct")) |struct_obj| {
21412 const field_index_usize = struct_obj.data.fields.getIndex(field_name) orelse
21413 break :find_field;
21414 const field_index = @intCast(u32, field_index_usize);
21415 const field = struct_obj.data.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 }
2074721435 },
2074821436 .Union => {
2074921437 const union_ty = try sema.resolveTypeFields(block, src, concrete_ty);
......@@ -21009,7 +21697,7 @@ fn structFieldPtrByIndex(
2100921697 const elem_size_bits = ptr_ty_data.pointee_type.bitSize(target);
2101021698 if (elem_size_bytes * 8 == elem_size_bits) {
2101121699 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));
2101321701 ptr_ty_data.bit_offset = 0;
2101421702 ptr_ty_data.host_size = 0;
2101521703 ptr_ty_data.@"align" = new_align;
......@@ -21184,6 +21872,18 @@ fn unionFieldPtr(
2118421872 .@"addrspace" = union_ptr_ty.ptrAddressSpace(),
2118521873 });
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
2118721887 if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| ct: {
2118821888 switch (union_obj.layout) {
2118921889 .Auto => if (!initializing) {
......@@ -21192,17 +21892,18 @@ fn unionFieldPtr(
2119221892 if (union_val.isUndef()) {
2119321893 return sema.failWithUseOfUndef(block, src);
2119421894 }
21895 const enum_field_index = union_obj.tag_ty.enumFieldIndex(field_name).?;
2119521896 const tag_and_val = union_val.castTag(.@"union").?.data;
2119621897 var field_tag_buf: Value.Payload.U32 = .{
2119721898 .base = .{ .tag = .enum_field_index },
21198 .data = field_index,
21899 .data = @intCast(u32, enum_field_index),
2119921900 };
2120021901 const field_tag = Value.initPayload(&field_tag_buf.base);
2120121902 const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod);
2120221903 if (!tag_matches) {
2120321904 const msg = msg: {
2120421905 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);
2120621907 const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name });
2120721908 errdefer msg.destroy(sema.gpa);
2120821909 try sema.addDeclaredHereNote(msg, union_ty);
......@@ -21227,15 +21928,18 @@ fn unionFieldPtr(
2122721928 if (!initializing and union_obj.layout == .Auto and block.wantSafety() and
2122821929 union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)
2122921930 {
21230 const enum_ty = union_ty.unionTagTypeHypothetical();
2123121931 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);
2123321933 // TODO would it be better if get_union_tag supported pointers to unions?
2123421934 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);
2123621936 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);
2123721937 try sema.addSafetyCheck(block, ok, .inactive_union_field);
2123821938 }
21939 if (field.ty.zigTypeTag() == .NoReturn) {
21940 _ = try block.addNoOp(.unreach);
21941 return Air.Inst.Ref.unreachable_value;
21942 }
2123921943 return block.addStructFieldPtr(union_ptr, field_index, ptr_field_ty);
2124021944}
2124121945
......@@ -21259,9 +21963,10 @@ fn unionFieldVal(
2125921963 if (union_val.isUndef()) return sema.addConstUndef(field.ty);
2126021964
2126121965 const tag_and_val = union_val.castTag(.@"union").?.data;
21966 const enum_field_index = union_obj.tag_ty.enumFieldIndex(field_name).?;
2126221967 var field_tag_buf: Value.Payload.U32 = .{
2126321968 .base = .{ .tag = .enum_field_index },
21264 .data = field_index,
21969 .data = @intCast(u32, enum_field_index),
2126521970 };
2126621971 const field_tag = Value.initPayload(&field_tag_buf.base);
2126721972 const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod);
......@@ -21272,7 +21977,7 @@ fn unionFieldVal(
2127221977 } else {
2127321978 const msg = msg: {
2127421979 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);
2127621981 const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name });
2127721982 errdefer msg.destroy(sema.gpa);
2127821983 try sema.addDeclaredHereNote(msg, union_ty);
......@@ -21297,13 +22002,16 @@ fn unionFieldVal(
2129722002 if (union_obj.layout == .Auto and block.wantSafety() and
2129822003 union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)
2129922004 {
21300 const enum_ty = union_ty.unionTagTypeHypothetical();
2130122005 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);
21303 const active_tag = try block.addTyOp(.get_union_tag, enum_ty, union_byval);
22006 const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val);
22007 const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_byval);
2130422008 const ok = try block.addBinOp(.cmp_eq, active_tag, wanted_tag);
2130522009 try sema.addSafetyCheck(block, ok, .inactive_union_field);
2130622010 }
22011 if (field.ty.zigTypeTag() == .NoReturn) {
22012 _ = try block.addNoOp(.unreach);
22013 return Air.Inst.Ref.unreachable_value;
22014 }
2130722015 return block.addStructFieldVal(union_byval, field_index, field.ty);
2130822016}
2130922017
......@@ -21543,8 +22251,7 @@ fn tupleField(
2154322251
2154422252 if (try sema.resolveMaybeUndefVal(block, tuple_src, tuple)) |tuple_val| {
2154522253 if (tuple_val.isUndef()) return sema.addConstUndef(field_ty);
21546 const field_values = tuple_val.castTag(.aggregate).?.data;
21547 return sema.addConstant(field_ty, field_values[field_index]);
22254 return sema.addConstant(field_ty, tuple_val.fieldValue(tuple_ty, field_index));
2154822255 }
2154922256
2155022257 try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src);
......@@ -21886,7 +22593,7 @@ fn coerceExtra(
2188622593 // Function body to function pointer.
2188722594 if (inst_ty.zigTypeTag() == .Fn) {
2188822595 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().?;
2189022597 const inst_as_ptr = try sema.analyzeDeclRef(fn_decl);
2189122598 return sema.coerce(block, dest_ty, inst_as_ptr, inst_src);
2189222599 }
......@@ -21966,7 +22673,6 @@ fn coerceExtra(
2196622673 .ok => {},
2196722674 else => break :src_c_ptr,
2196822675 }
21969 // TODO add safety check for null pointer
2197022676 return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
2197122677 }
2197222678
......@@ -23271,7 +23977,10 @@ fn coerceVarArgParam(
2327123977 inst_src: LazySrcLoc,
2327223978) !Air.Inst.Ref {
2327323979 const inst_ty = sema.typeOf(inst);
23980 if (block.is_typeof) return inst;
23981
2327423982 switch (inst_ty.zigTypeTag()) {
23983 // TODO consider casting to c_int/f64 if they fit
2327523984 .ComptimeInt, .ComptimeFloat => return sema.fail(block, inst_src, "integer and float literals in var args function must be casted", .{}),
2327623985 else => {},
2327723986 }
......@@ -23653,7 +24362,10 @@ fn beginComptimePtrMutation(
2365324362 const array_len_including_sentinel =
2365424363 try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel());
2365524364 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
2365824370 val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
2365924371
......@@ -24439,6 +25151,24 @@ fn coerceCompatiblePtrs(
2443925151 return sema.addConstant(dest_ty, val);
2444025152 }
2444125153 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 }
2444225172 return sema.bitCast(block, dest_ty, inst, inst_src);
2444325173}
2444425174
......@@ -24467,8 +25197,7 @@ fn coerceEnumToUnion(
2446725197
2446825198 const enum_tag = try sema.coerce(block, tag_ty, inst, inst_src);
2446925199 if (try sema.resolveDefinedValue(block, inst_src, enum_tag)) |val| {
24470 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
24471 const field_index = union_obj.tag_ty.enumTagFieldIndex(val, sema.mod) orelse {
25200 const field_index = union_ty.unionTagFieldIndex(val, sema.mod) orelse {
2447225201 const msg = msg: {
2447325202 const msg = try sema.errMsg(block, inst_src, "union '{}' has no tag with value '{}'", .{
2447425203 union_ty.fmt(sema.mod), val.fmtValue(tag_ty, sema.mod),
......@@ -24479,8 +25208,22 @@ fn coerceEnumToUnion(
2447925208 };
2448025209 return sema.failWithOwnedErrorMsg(msg);
2448125210 };
25211
25212 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
2448225213 const field = union_obj.fields.values()[field_index];
2448325214 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 }
2448425227 const opv = (try sema.typeHasOnePossibleValue(block, inst_src, field_ty)) orelse {
2448525228 const msg = msg: {
2448625229 const field_name = union_obj.fields.keys()[field_index];
......@@ -24516,13 +25259,37 @@ fn coerceEnumToUnion(
2451625259 return sema.failWithOwnedErrorMsg(msg);
2451725260 }
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
2451925287 // If the union has all fields 0 bits, the union value is just the enum value.
2452025288 if (union_ty.unionHasAllZeroBitFieldTypes()) {
2452125289 return block.addBitCast(union_ty, enum_tag);
2452225290 }
2452325291
2452425292 const msg = msg: {
24525 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
2452625293 const msg = try sema.errMsg(
2452725294 block,
2452825295 inst_src,
......@@ -24533,11 +25300,11 @@ fn coerceEnumToUnion(
2453325300
2453425301 var it = union_obj.fields.iterator();
2453525302 var field_index: usize = 0;
24536 while (it.next()) |field| {
25303 while (it.next()) |field| : (field_index += 1) {
2453725304 const field_name = field.key_ptr.*;
2453825305 const field_ty = field.value_ptr.ty;
25306 if (!field_ty.hasRuntimeBits()) continue;
2453925307 try sema.addFieldErrNote(block, union_ty, field_index, msg, "field '{s}' has type '{}'", .{ field_name, field_ty.fmt(sema.mod) });
24540 field_index += 1;
2454125308 }
2454225309 try sema.addDeclaredHereNote(msg, union_ty);
2454325310 break :msg msg;
......@@ -24840,6 +25607,7 @@ fn coerceTupleToStruct(
2484025607
2484125608 // Populate default field values and report errors for missing fields.
2484225609 var root_msg: ?*Module.ErrorMsg = null;
25610 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
2484325611
2484425612 for (field_refs) |*field_ref, i| {
2484525613 if (field_ref.* != .none) continue;
......@@ -24865,6 +25633,7 @@ fn coerceTupleToStruct(
2486525633 }
2486625634
2486725635 if (root_msg) |msg| {
25636 root_msg = null;
2486825637 try sema.addDeclaredHereNote(msg, struct_ty);
2486925638 return sema.failWithOwnedErrorMsg(msg);
2487025639 }
......@@ -24934,6 +25703,7 @@ fn coerceTupleToTuple(
2493425703
2493525704 // Populate default field values and report errors for missing fields.
2493625705 var root_msg: ?*Module.ErrorMsg = null;
25706 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
2493725707
2493825708 for (field_refs) |*field_ref, i| {
2493925709 if (field_ref.* != .none) continue;
......@@ -24969,6 +25739,7 @@ fn coerceTupleToTuple(
2496925739 }
2497025740
2497125741 if (root_msg) |msg| {
25742 root_msg = null;
2497225743 try sema.addDeclaredHereNote(msg, tuple_ty);
2497325744 return sema.failWithOwnedErrorMsg(msg);
2497425745 }
......@@ -25207,11 +25978,38 @@ fn analyzeIsNull(
2520725978 return Air.Inst.Ref.bool_false;
2520825979 }
2520925980 }
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 }
2521025987 try sema.requireRuntimeBlock(block, src, null);
2521125988 const air_tag: Air.Inst.Tag = if (invert_logic) .is_non_null else .is_null;
2521225989 return block.addUnOp(air_tag, operand);
2521325990}
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
2521526013fn analyzeIsNonErrComptimeOnly(
2521626014 sema: *Sema,
2521726015 block: *Block,
......@@ -25224,11 +26022,22 @@ fn analyzeIsNonErrComptimeOnly(
2522426022 if (ot == .ErrorSet) return Air.Inst.Ref.bool_false;
2522526023 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
2522726030 if (Air.refToIndex(operand)) |operand_inst| {
25228 const air_tags = sema.air_instructions.items(.tag);
25229 if (air_tags[operand_inst] == .wrap_errunion_payload) {
25230 return Air.Inst.Ref.bool_true;
26031 switch (sema.air_instructions.items(.tag)[operand_inst]) {
26032 .wrap_errunion_payload => return Air.Inst.Ref.bool_true,
26033 .wrap_errunion_err => return Air.Inst.Ref.bool_false,
26034 else => {},
2523126035 }
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;
2523226041 }
2523326042
2523426043 const maybe_operand_val = try sema.resolveMaybeUndefVal(block, src, operand);
......@@ -25304,6 +26113,21 @@ fn analyzeIsNonErr(
2530426113 }
2530526114}
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
2530726131fn analyzeSlice(
2530826132 sema: *Sema,
2530926133 block: *Block,
......@@ -25330,11 +26154,12 @@ fn analyzeSlice(
2533026154 var array_ty = ptr_ptr_child_ty;
2533126155 var slice_ty = ptr_ptr_ty;
2533226156 var ptr_or_slice = ptr_ptr;
25333 var elem_ty = ptr_ptr_child_ty.childType();
26157 var elem_ty: Type = undefined;
2533426158 var ptr_sentinel: ?Value = null;
2533526159 switch (ptr_ptr_child_ty.zigTypeTag()) {
2533626160 .Array => {
2533726161 ptr_sentinel = ptr_ptr_child_ty.sentinel();
26162 elem_ty = ptr_ptr_child_ty.childType();
2533826163 },
2533926164 .Pointer => switch (ptr_ptr_child_ty.ptrSize()) {
2534026165 .One => {
......@@ -25578,6 +26403,27 @@ fn analyzeSlice(
2557826403 const new_ptr_val = opt_new_ptr_val orelse {
2557926404 const result = try block.addBitCast(return_ty, new_ptr);
2558026405 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
2558126427 // requirement: result[new_len] == slice_sentinel
2558226428 try sema.panicSentinelMismatch(block, src, slice_sentinel, elem_ty, result, new_len);
2558326429 }
......@@ -25639,7 +26485,11 @@ fn analyzeSlice(
2563926485 break :blk try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src);
2564026486 } else null;
2564126487 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);
2564326493 }
2564426494
2564526495 // requirement: start <= end
......@@ -26616,9 +27466,6 @@ pub fn resolveTypeLayout(
2661627466 src: LazySrcLoc,
2661727467 ty: Type,
2661827468) 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
2662227469 switch (ty.zigTypeTag()) {
2662327470 .Struct => return sema.resolveStructLayout(block, src, ty),
2662427471 .Union => return sema.resolveUnionLayout(block, src, ty),
......@@ -26677,6 +27524,11 @@ fn resolveStructLayout(
2667727524 else => return err,
2667827525 };
2667927526 }
27527
27528 if (struct_obj.layout == .Packed) {
27529 try semaBackingIntType(sema.mod, struct_obj);
27530 }
27531
2668027532 struct_obj.status = .have_layout;
2668127533
2668227534 // In case of querying the ABI alignment of this struct, we will ask
......@@ -26696,6 +27548,109 @@ fn resolveStructLayout(
2669627548 // otherwise it's a tuple; no need to resolve anything
2669727549}
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
2669927654fn resolveUnionLayout(
2670027655 sema: *Sema,
2670127656 block: *Block,
......@@ -26849,8 +27804,6 @@ fn resolveUnionFully(
2684927804}
2685027805
2685127806pub 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");
2685427807 switch (ty.tag()) {
2685527808 .@"struct" => {
2685627809 const struct_obj = ty.castTag(.@"struct").?.data;
......@@ -26997,13 +27950,15 @@ fn resolveInferredErrorSetTy(
2699727950fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void {
2699827951 const gpa = mod.gpa;
2699927952 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;
2700127956 const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended;
2700227957 assert(extended.opcode == .struct_decl);
2700327958 const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
2700427959 var extra_index: usize = extended.operand;
2700527960
27006 const src = LazySrcLoc.nodeOffset(struct_obj.node_offset);
27961 const src = LazySrcLoc.nodeOffset(0);
2700727962 extra_index += @boolToInt(small.has_src_node);
2700827963
2700927964 const fields_len = if (small.has_fields_len) blk: {
......@@ -27018,12 +27973,26 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
2701827973 break :decls_len decls_len;
2701927974 } 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
2702127987 // Skip over decls.
2702227988 var decls_it = zir.declIteratorInner(extra_index, decls_len);
2702327989 while (decls_it.next()) |_| {}
2702427990 extra_index = decls_it.extra_index;
2702527991
2702627992 if (fields_len == 0) {
27993 if (struct_obj.layout == .Packed) {
27994 try semaBackingIntType(mod, struct_obj);
27995 }
2702727996 struct_obj.status = .have_layout;
2702827997 return;
2702927998 }
......@@ -27122,12 +28091,12 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
2712228091 if (gop.found_existing) {
2712328092 const msg = msg: {
2712428093 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);
2712628095 const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{s}'", .{field_name});
2712728096 errdefer msg.destroy(gpa);
2712828097
2712928098 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);
2713128100 try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl), msg, "other field here", .{});
2713228101 try sema.errNote(&block_scope, src, msg, "struct declared here", .{});
2713328102 break :msg msg;
......@@ -27184,7 +28153,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
2718428153 if (field_ty.zigTypeTag() == .Opaque) {
2718528154 const msg = msg: {
2718628155 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);
2718828157 const msg = try sema.errMsg(&block_scope, field_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
2718928158 errdefer msg.destroy(sema.gpa);
2719028159
......@@ -27193,10 +28162,22 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
2719328162 };
2719428163 return sema.failWithOwnedErrorMsg(msg);
2719528164 }
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 }
2719628177 if (struct_obj.layout == .Extern and !sema.validateExternType(field.ty, .other)) {
2719728178 const msg = msg: {
2719828179 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);
2720028181 const msg = try sema.errMsg(&block_scope, fields_src, "extern structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)});
2720128182 errdefer msg.destroy(sema.gpa);
2720228183
......@@ -27209,7 +28190,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
2720928190 } else if (struct_obj.layout == .Packed and !(validatePackedType(field.ty))) {
2721028191 const msg = msg: {
2721128192 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);
2721328194 const msg = try sema.errMsg(&block_scope, fields_src, "packed structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)});
2721428195 errdefer msg.destroy(sema.gpa);
2721528196
......@@ -27266,7 +28247,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
2726628247 const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small);
2726728248 var extra_index: usize = extended.operand;
2726828249
27269 const src = LazySrcLoc.nodeOffset(union_obj.node_offset);
28250 const src = LazySrcLoc.nodeOffset(0);
2727028251 extra_index += @boolToInt(small.has_src_node);
2727128252
2727228253 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 {
2729928280 extra_index = decls_it.extra_index;
2730028281
2730128282 const body = zir.extra[extra_index..][0..body_len];
27302 if (fields_len == 0) {
27303 assert(body.len == 0);
27304 return;
27305 }
2730628283 extra_index += body.len;
2730728284
2730828285 const decl = mod.declPtr(decl_index);
......@@ -27390,6 +28367,10 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
2739028367 enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields;
2739128368 }
2739228369
28370 if (fields_len == 0) {
28371 return;
28372 }
28373
2739328374 const bits_per_field = 4;
2739428375 const fields_per_u32 = 32 / bits_per_field;
2739528376 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 {
2749028471 if (gop.found_existing) {
2749128472 const msg = msg: {
2749228473 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);
2749428475 const msg = try sema.errMsg(&block_scope, field_src, "duplicate union field: '{s}'", .{field_name});
2749528476 errdefer msg.destroy(gpa);
2749628477
2749728478 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);
2749928480 try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl), msg, "other field here", .{});
2750028481 try sema.errNote(&block_scope, src, msg, "union declared here", .{});
2750128482 break :msg msg;
......@@ -27508,7 +28489,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
2750828489 if (!enum_has_field) {
2750928490 const msg = msg: {
2751028491 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);
2751228493 const msg = try sema.errMsg(&block_scope, field_src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(sema.mod) });
2751328494 errdefer msg.destroy(sema.gpa);
2751428495 try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
......@@ -27521,7 +28502,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
2752128502 if (field_ty.zigTypeTag() == .Opaque) {
2752228503 const msg = msg: {
2752328504 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);
2752528506 const msg = try sema.errMsg(&block_scope, field_src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{});
2752628507 errdefer msg.destroy(sema.gpa);
2752728508
......@@ -27533,7 +28514,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
2753328514 if (union_obj.layout == .Extern and !sema.validateExternType(field_ty, .union_field)) {
2753428515 const msg = msg: {
2753528516 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);
2753728518 const msg = try sema.errMsg(&block_scope, field_src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
2753828519 errdefer msg.destroy(sema.gpa);
2753928520
......@@ -27546,7 +28527,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
2754628527 } else if (union_obj.layout == .Packed and !(validatePackedType(field_ty))) {
2754728528 const msg = msg: {
2754828529 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);
2755028531 const msg = try sema.errMsg(&block_scope, fields_src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
2755128532 errdefer msg.destroy(sema.gpa);
2755228533
......@@ -27638,7 +28619,6 @@ fn generateUnionTagTypeNumbered(
2763828619 .tag_ty = int_ty,
2763928620 .fields = .{},
2764028621 .values = .{},
27641 .node_offset = 0,
2764228622 };
2764328623 // Here we pre-allocate the maps using the decl arena.
2764428624 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
2769628676 enum_obj.* = .{
2769728677 .owner_decl = new_decl_index,
2769828678 .fields = .{},
27699 .node_offset = 0,
2770028679 };
2770128680 // Here we pre-allocate the maps using the decl arena.
2770228681 try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
......@@ -27871,10 +28850,11 @@ pub fn typeHasOnePossibleValue(
2787128850
2787228851 .tuple, .anon_struct => {
2787328852 const tuple = ty.tupleFields();
27874 for (tuple.values) |val| {
27875 if (val.tag() == .unreachable_value) {
27876 return null; // non-comptime field
27877 }
28853 for (tuple.values) |val, i| {
28854 const is_comptime = val.tag() != .unreachable_value;
28855 if (is_comptime) continue;
28856 if ((try sema.typeHasOnePossibleValue(block, src, tuple.types[i])) != null) continue;
28857 return null;
2787828858 }
2787928859 return Value.initTag(.empty_struct_value);
2788028860 },
......@@ -27882,6 +28862,10 @@ pub fn typeHasOnePossibleValue(
2788228862 .enum_numbered => {
2788328863 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
2788428864 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 }
2788528869 if (enum_obj.fields.count() == 1) {
2788628870 if (enum_obj.values.count() == 0) {
2788728871 return Value.zero; // auto-numbered
......@@ -27895,6 +28879,9 @@ pub fn typeHasOnePossibleValue(
2789528879 .enum_full => {
2789628880 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
2789728881 const enum_obj = resolved_ty.castTag(.enum_full).?.data;
28882 if (enum_obj.tag_ty.hasRuntimeBits()) {
28883 return null;
28884 }
2789828885 if (enum_obj.fields.count() == 1) {
2789928886 if (enum_obj.values.count() == 0) {
2790028887 return Value.zero; // auto-numbered
......@@ -27927,7 +28914,9 @@ pub fn typeHasOnePossibleValue(
2792728914 const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;
2792828915 const tag_val = (try sema.typeHasOnePossibleValue(block, src, union_obj.tag_ty)) orelse
2792928916 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];
2793128920 if (only_field.ty.eql(resolved_ty, sema.mod)) {
2793228921 const msg = try Module.ErrorMsg.create(
2793328922 sema.gpa,
......@@ -28006,8 +28995,18 @@ fn enumFieldSrcLoc(
2800628995 .container_decl_arg_trailing,
2800728996 => 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
2800929008 // Container was constructed with `@Type`.
28010 else => return LazySrcLoc.nodeOffset(node_offset),
29009 else => return LazySrcLoc.nodeOffset(0),
2801129010 };
2801229011 var it_index: usize = 0;
2801329012 for (container_decl.ast.members) |member_node| {
......@@ -28437,8 +29436,6 @@ fn typePtrOrOptionalPtrTy(
2843729436/// TODO merge these implementations together with the "advanced"/sema_kit pattern seen
2843829437/// elsewhere in value.zig
2843929438pub 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");
2844229439 return switch (ty.tag()) {
2844329440 .u1,
2844429441 .u8,
......@@ -28543,7 +29540,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ
2854329540 => {
2854429541 const child_ty = ty.childType();
2854529542 if (child_ty.zigTypeTag() == .Fn) {
28546 return false;
29543 return child_ty.fnInfo().is_generic;
2854729544 } else {
2854829545 return sema.typeRequiresComptime(block, src, child_ty);
2854929546 }
......@@ -28656,7 +29653,9 @@ fn unionFieldAlignment(
2865629653 src: LazySrcLoc,
2865729654 field: Module.Union.Field,
2865829655) !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) {
2866029659 return sema.typeAbiAlignment(block, src, field.ty);
2866129660 } else {
2866229661 return field.abi_align;
......@@ -29430,7 +30429,7 @@ fn valuesEqual(
2943030429 rhs: Value,
2943130430 ty: Type,
2943230431) 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));
2943430433}
2943530434
2943630435/// Asserts the values are comparable vectors of type `ty`.
......@@ -29478,7 +30477,7 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {
2947830477 // The resulting pointer is aligned to the lcd between the offset (an
2947930478 // arbitrary number) and the alignment factor (always a power of two,
2948030479 // 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"));
2948230481 break :a new_align;
2948330482 };
2948430483 return try Type.ptr(sema.arena, sema.mod, .{
src/Zir.zig+53-29
......@@ -43,7 +43,11 @@ pub const Header = extern struct {
4343 instructions_len: u32,
4444 string_bytes_len: u32,
4545 extra_len: u32,
46
46 /// 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,
4751 stat_inode: std.fs.File.INode,
4852 stat_size: u64,
4953 stat_mtime: i128,
......@@ -490,14 +494,6 @@ pub const Inst = struct {
490494 /// Merge two error sets into one, `E1 || E2`.
491495 /// Uses the `pl_node` field with payload `Bin`.
492496 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,
501497 /// Turns an R-Value into a const L-Value. In other words, it takes a value,
502498 /// stores it in a memory location, and returns a const pointer to it. If the value
503499 /// is `comptime`, the memory location is global static constant data. Otherwise,
......@@ -839,8 +835,6 @@ pub const Inst = struct {
839835 round,
840836 /// Implement builtin `@tagName`. Uses `un_node`.
841837 tag_name,
842 /// Implement builtin `@Type`. Uses `un_node`.
843 reify,
844838 /// Implement builtin `@typeName`. Uses `un_node`.
845839 type_name,
846840 /// Implement builtin `@Frame`. Uses `un_node`.
......@@ -1097,7 +1091,6 @@ pub const Inst = struct {
10971091 .mul,
10981092 .mulwrap,
10991093 .mul_sat,
1100 .param_type,
11011094 .ref,
11021095 .shl,
11031096 .shl_sat,
......@@ -1197,7 +1190,6 @@ pub const Inst = struct {
11971190 .trunc,
11981191 .round,
11991192 .tag_name,
1200 .reify,
12011193 .type_name,
12021194 .frame_type,
12031195 .frame_size,
......@@ -1400,7 +1392,6 @@ pub const Inst = struct {
14001392 .mul,
14011393 .mulwrap,
14021394 .mul_sat,
1403 .param_type,
14041395 .ref,
14051396 .shl,
14061397 .shl_sat,
......@@ -1484,7 +1475,6 @@ pub const Inst = struct {
14841475 .trunc,
14851476 .round,
14861477 .tag_name,
1487 .reify,
14881478 .type_name,
14891479 .frame_type,
14901480 .frame_size,
......@@ -1573,7 +1563,6 @@ pub const Inst = struct {
15731563 .mulwrap = .pl_node,
15741564 .mul_sat = .pl_node,
15751565
1576 .param_type = .param_type,
15771566 .param = .pl_tok,
15781567 .param_comptime = .pl_tok,
15791568 .param_anytype = .str_tok,
......@@ -1759,7 +1748,6 @@ pub const Inst = struct {
17591748 .trunc = .un_node,
17601749 .round = .un_node,
17611750 .tag_name = .un_node,
1762 .reify = .un_node,
17631751 .type_name = .un_node,
17641752 .frame_type = .un_node,
17651753 .frame_size = .un_node,
......@@ -1980,6 +1968,10 @@ pub const Inst = struct {
19801968 /// Implement builtin `@intToError`.
19811969 /// `operand` is payload index to `UnNode`.
19821970 int_to_error,
1971 /// Implement builtin `@Type`.
1972 /// `operand` is payload index to `UnNode`.
1973 /// `small` contains `NameStrategy
1974 reify,
19831975
19841976 pub const InstData = struct {
19851977 opcode: Extended,
......@@ -2541,10 +2533,6 @@ pub const Inst = struct {
25412533 /// Points to a `Block`.
25422534 payload_index: u32,
25432535 },
2544 param_type: struct {
2545 callee: Ref,
2546 param_index: u32,
2547 },
25482536 @"unreachable": struct {
25492537 /// Offset from Decl AST node index.
25502538 /// `Tag` determines which kind of AST node this points to.
......@@ -2615,7 +2603,6 @@ pub const Inst = struct {
26152603 ptr_type,
26162604 int_type,
26172605 bool_br,
2618 param_type,
26192606 @"unreachable",
26202607 @"break",
26212608 switch_capture,
......@@ -2795,7 +2782,9 @@ pub const Inst = struct {
27952782 };
27962783
27972784 /// 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
27992788 pub const Call = struct {
28002789 // Note: Flags *must* come first so that unusedResultExpr
28012790 // can find it when it goes to modify them.
......@@ -3100,13 +3089,16 @@ pub const Inst = struct {
31003089 /// 0. src_node: i32, // if has_src_node
31013090 /// 1. fields_len: u32, // if has_fields_len
31023091 /// 2. decls_len: u32, // if has_decls_len
3103 /// 3. decl_bits: u32 // for every 8 decls
3092 /// 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
31043096 /// - sets of 4 bits:
31053097 /// 0b000X: whether corresponding decl is pub
31063098 /// 0b00X0: whether corresponding decl is exported
31073099 /// 0b0X00: whether corresponding decl has an align expression
31083100 /// 0bX000: whether corresponding decl has a linksection or an address space expression
3109 /// 4. decl: { // for every decls_len
3101 /// 7. decl: { // for every decls_len
31103102 /// src_hash: [4]u32, // hash of source bytes
31113103 /// line: u32, // line number of decl, relative to parent
31123104 /// name: u32, // null terminated string index
......@@ -3124,13 +3116,13 @@ pub const Inst = struct {
31243116 /// address_space: Ref,
31253117 /// }
31263118 /// }
3127 /// 5. flags: u32 // for every 8 fields
3119 /// 8. flags: u32 // for every 8 fields
31283120 /// - sets of 4 bits:
31293121 /// 0b000X: whether corresponding field has an align expression
31303122 /// 0b00X0: whether corresponding field has a default expression
31313123 /// 0b0X00: whether corresponding field is comptime
31323124 /// 0bX000: whether corresponding field has a type expression
3133 /// 6. fields: { // for every fields_len
3125 /// 9. fields: { // for every fields_len
31343126 /// field_name: u32,
31353127 /// doc_comment: u32, // 0 if no doc comment
31363128 /// field_type: Ref, // if corresponding bit is not set. none means anytype.
......@@ -3138,7 +3130,7 @@ pub const Inst = struct {
31383130 /// align_body_len: u32, // if corresponding bit is set
31393131 /// init_body_len: u32, // if corresponding bit is set
31403132 /// }
3141 /// 7. bodies: { // for every fields_len
3133 /// 10. bodies: { // for every fields_len
31423134 /// field_type_body_inst: Inst, // for each field_type_body_len
31433135 /// align_body_inst: Inst, // for each align_body_len
31443136 /// init_body_inst: Inst, // for each init_body_len
......@@ -3148,11 +3140,12 @@ pub const Inst = struct {
31483140 has_src_node: bool,
31493141 has_fields_len: bool,
31503142 has_decls_len: bool,
3143 has_backing_int: bool,
31513144 known_non_opv: bool,
31523145 known_comptime_only: bool,
31533146 name_strategy: NameStrategy,
31543147 layout: std.builtin.Type.ContainerLayout,
3155 _: u7 = undefined,
3148 _: u6 = undefined,
31563149 };
31573150 };
31583151
......@@ -3619,6 +3612,16 @@ pub fn declIterator(zir: Zir, decl_inst: u32) DeclIterator {
36193612 break :decls_len decls_len;
36203613 } 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
36223625 return declIteratorInner(zir, extra_index, decls_len);
36233626 },
36243627 .enum_decl => {
......@@ -3915,6 +3918,27 @@ pub const FnInfo = struct {
39153918 total_params_len: u32,
39163919};
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
39183942pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
39193943 const tags = zir.instructions.items(.tag);
39203944 const datas = zir.instructions.items(.data);
src/arch/aarch64/CodeGen.zig+703-161
......@@ -166,10 +166,12 @@ const MCValue = union(enum) {
166166 /// the type is u1) or true (if the type in bool) iff the
167167 /// specified condition is true.
168168 condition_flags: Condition,
169 /// The value is a function argument passed via the stack.
170 stack_argument_offset: u32,
169171
170172 fn isMemory(mcv: MCValue) bool {
171173 return switch (mcv) {
172 .memory, .stack_offset => true,
174 .memory, .stack_offset, .stack_argument_offset => true,
173175 else => false,
174176 };
175177 }
......@@ -192,6 +194,7 @@ const MCValue = union(enum) {
192194 .condition_flags,
193195 .ptr_stack_offset,
194196 .undef,
197 .stack_argument_offset,
195198 => false,
196199
197200 .register,
......@@ -337,6 +340,7 @@ pub fn generate(
337340 .prev_di_line = module_fn.lbrace_line,
338341 .prev_di_column = module_fn.lbrace_column,
339342 .stack_size = mem.alignForwardGeneric(u32, function.max_end_stack, function.stack_align),
343 .saved_regs_stack_space = function.saved_regs_stack_space,
340344 };
341345 defer emit.deinit();
342346
......@@ -414,6 +418,23 @@ fn gen(self: *Self) !void {
414418 // sub sp, sp, #reloc
415419 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
417438 _ = try self.addInst(.{
418439 .tag = .dbg_prologue_end,
419440 .data = .{ .nop = {} },
......@@ -540,33 +561,38 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
540561
541562 switch (air_tags[inst]) {
542563 // zig fmt: off
543 .add => try self.airBinOp(inst, .add),
544 .addwrap => try self.airBinOp(inst, .addwrap),
545 .sub => try self.airBinOp(inst, .sub),
546 .subwrap => try self.airBinOp(inst, .subwrap),
547 .mul => try self.airBinOp(inst, .mul),
548 .mulwrap => try self.airBinOp(inst, .mulwrap),
549 .shl => try self.airBinOp(inst, .shl),
550 .shl_exact => try self.airBinOp(inst, .shl_exact),
551 .bool_and => try self.airBinOp(inst, .bool_and),
552 .bool_or => try self.airBinOp(inst, .bool_or),
553 .bit_and => try self.airBinOp(inst, .bit_and),
554 .bit_or => try self.airBinOp(inst, .bit_or),
555 .xor => try self.airBinOp(inst, .xor),
556 .shr => try self.airBinOp(inst, .shr),
557 .shr_exact => try self.airBinOp(inst, .shr_exact),
558
559 .ptr_add => try self.airPtrArithmetic(inst, .ptr_add),
560 .ptr_sub => try self.airPtrArithmetic(inst, .ptr_sub),
564 .add => try self.airBinOp(inst, .add),
565 .addwrap => try self.airBinOp(inst, .addwrap),
566 .sub => try self.airBinOp(inst, .sub),
567 .subwrap => try self.airBinOp(inst, .subwrap),
568 .mul => try self.airBinOp(inst, .mul),
569 .mulwrap => try self.airBinOp(inst, .mulwrap),
570 .shl => try self.airBinOp(inst, .shl),
571 .shl_exact => try self.airBinOp(inst, .shl_exact),
572 .bool_and => try self.airBinOp(inst, .bool_and),
573 .bool_or => try self.airBinOp(inst, .bool_or),
574 .bit_and => try self.airBinOp(inst, .bit_and),
575 .bit_or => try self.airBinOp(inst, .bit_or),
576 .xor => try self.airBinOp(inst, .xor),
577 .shr => try self.airBinOp(inst, .shr),
578 .shr_exact => try self.airBinOp(inst, .shr_exact),
579 .div_float => try self.airBinOp(inst, .div_float),
580 .div_trunc => try self.airBinOp(inst, .div_trunc),
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
562592 .add_sat => try self.airAddSat(inst),
563593 .sub_sat => try self.airSubSat(inst),
564594 .mul_sat => try self.airMulSat(inst),
565 .rem => try self.airRem(inst),
566 .mod => try self.airMod(inst),
567595 .shl_sat => try self.airShlSat(inst),
568 .min => try self.airMin(inst),
569 .max => try self.airMax(inst),
570596 .slice => try self.airSlice(inst),
571597
572598 .sqrt,
......@@ -591,8 +617,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
591617 .mul_with_overflow => try self.airMulWithOverflow(inst),
592618 .shl_with_overflow => try self.airShlWithOverflow(inst),
593619
594 .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst),
595
596620 .cmp_lt => try self.airCmp(inst, .lt),
597621 .cmp_lte => try self.airCmp(inst, .lte),
598622 .cmp_eq => try self.airCmp(inst, .eq),
......@@ -753,6 +777,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
753777 .float_to_int_optimized,
754778 => 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
756783 .wasm_memory_size => unreachable,
757784 .wasm_memory_grow => unreachable,
758785 // zig fmt: on
......@@ -1008,17 +1035,43 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
10081035 if (self.liveness.isUnused(inst))
10091036 return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
10101037
1011 const operand_ty = self.air.typeOf(ty_op.operand);
1012 const operand = try self.resolveInst(ty_op.operand);
1013 const info_a = operand_ty.intInfo(self.target.*);
1014 const info_b = self.air.typeOfIndex(inst).intInfo(self.target.*);
1015 if (info_a.signedness != info_b.signedness)
1016 return self.fail("TODO gen intcast sign safety in semantic analysis", .{});
1038 const operand = ty_op.operand;
1039 const operand_mcv = try self.resolveInst(operand);
1040 const operand_ty = self.air.typeOf(operand);
1041 const operand_info = operand_ty.intInfo(self.target.*);
10171042
1018 if (info_a.bits == info_b.bits)
1019 return self.finishAir(inst, operand, .{ ty_op.operand, .none, .none });
1043 const dest_ty = self.air.typeOfIndex(inst);
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 });
10221075}
10231076
10241077fn truncRegister(
......@@ -1044,6 +1097,8 @@ fn truncRegister(
10441097 });
10451098 },
10461099 32, 64 => {
1100 assert(dest_reg.size() == operand_reg.size());
1101
10471102 _ = try self.addInst(.{
10481103 .tag = .mov_register,
10491104 .data = .{ .rr = .{
......@@ -1099,7 +1154,7 @@ fn trunc(
10991154
11001155 return MCValue{ .register = dest_reg };
11011156 } else {
1102 return self.fail("TODO: truncate to ints > 32 bits", .{});
1157 return self.fail("TODO: truncate to ints > 64 bits", .{});
11031158 }
11041159}
11051160
......@@ -1262,6 +1317,9 @@ fn binOpRegister(
12621317 const lhs_is_register = lhs == .register;
12631318 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
12651323 const lhs_lock: ?RegisterLock = if (lhs_is_register)
12661324 self.register_manager.lockReg(lhs.register)
12671325 else
......@@ -1291,13 +1349,22 @@ fn binOpRegister(
12911349 const new_lhs_lock = self.register_manager.lockReg(lhs_reg);
12921350 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: {
12951359 const track_inst: ?Air.Inst.Index = if (metadata) |md| inst: {
12961360 break :inst Air.refToIndex(md.rhs).?;
12971361 } else null;
12981362
12991363 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
13021369 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
13031370
......@@ -1348,6 +1415,8 @@ fn binOpRegister(
13481415 .lsl_register,
13491416 .asr_register,
13501417 .lsr_register,
1418 .sdiv,
1419 .udiv,
13511420 => .{ .rrr = .{
13521421 .rd = dest_reg,
13531422 .rn = lhs_reg,
......@@ -1404,6 +1473,8 @@ fn binOpImmediate(
14041473) !MCValue {
14051474 const lhs_is_register = lhs == .register;
14061475
1476 if (lhs_is_register) assert(lhs.register == registerAlias(lhs.register, lhs_ty.abiSize(self.target.*)));
1477
14071478 const lhs_lock: ?RegisterLock = if (lhs_is_register)
14081479 self.register_manager.lockReg(lhs.register)
14091480 else
......@@ -1586,6 +1657,151 @@ fn binOp(
15861657 else => unreachable,
15871658 }
15881659 },
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 },
15891805 .addwrap,
15901806 .subwrap,
15911807 .mulwrap,
......@@ -1869,7 +2085,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void {
18692085 try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits);
18702086
18712087 // 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
18742090 try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg });
18752091 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 {
22572473 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
22582474}
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
22782476fn airShlSat(self: *Self, inst: Air.Inst.Index) !void {
22792477 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
22802478 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
23132511 const err_offset = @intCast(u32, errUnionErrorOffset(payload_ty, self.target.*));
23142512 switch (error_union_mcv) {
23152513 .register => return self.fail("TODO errUnionErr for registers", .{}),
2514 .stack_argument_offset => |off| {
2515 return MCValue{ .stack_argument_offset = off + err_offset };
2516 },
23162517 .stack_offset => |off| {
23172518 return MCValue{ .stack_offset = off - err_offset };
23182519 },
......@@ -2347,6 +2548,9 @@ fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type)
23472548 const payload_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, self.target.*));
23482549 switch (error_union_mcv) {
23492550 .register => return self.fail("TODO errUnionPayload for registers", .{}),
2551 .stack_argument_offset => |off| {
2552 return MCValue{ .stack_argument_offset = off + payload_offset };
2553 },
23502554 .stack_offset => |off| {
23512555 return MCValue{ .stack_offset = off - payload_offset };
23522556 },
......@@ -2436,21 +2640,28 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
24362640 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
24372641}
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
24392660fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
24402661 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
24412662 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
24422663 const mcv = try self.resolveInst(ty_op.operand);
2443 switch (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 }
2664 break :result slicePtr(mcv);
24542665 };
24552666 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
24562667}
......@@ -2464,6 +2675,9 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
24642675 switch (mcv) {
24652676 .dead, .unreach, .none => unreachable,
24662677 .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 },
24672681 .stack_offset => |off| {
24682682 break :result MCValue{ .stack_offset = off - ptr_bytes };
24692683 },
......@@ -2514,6 +2728,9 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
25142728
25152729 if (!is_volatile and self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
25162730 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.*);
25172734 const slice_mcv = try self.resolveInst(bin_op.lhs);
25182735
25192736 // TODO optimize for the case where the index is a constant,
......@@ -2521,10 +2738,6 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
25212738 const index_mcv = try self.resolveInst(bin_op.rhs);
25222739 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
25282741 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
25292742 const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf);
25302743
......@@ -2534,15 +2747,17 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
25342747 null;
25352748 defer if (index_lock) |reg| self.register_manager.unlockReg(reg);
25362749
2537 const base_mcv: MCValue = switch (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);
2750 const base_mcv = slicePtr(slice_mcv);
25432751
25442752 switch (elem_size) {
25452753 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
25462761 const dest = try self.allocRegOrMem(inst, true);
25472762 const addr = try self.binOp(.ptr_add, base_mcv, index_mcv, slice_ptr_field_type, Type.usize, null);
25482763 try self.load(dest, addr, slice_ptr_field_type);
......@@ -2557,7 +2772,16 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
25572772fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {
25582773 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
25592774 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 };
25612785 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
25622786}
25632787
......@@ -2577,7 +2801,15 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
25772801fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
25782802 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
25792803 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 };
25812813 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
25822814}
25832815
......@@ -2726,6 +2958,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
27262958 },
27272959 .memory,
27282960 .stack_offset,
2961 .stack_argument_offset,
27292962 .got_load,
27302963 .direct_load,
27312964 => {
......@@ -2907,6 +3140,8 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
29073140 defer if (addr_reg_lock) |reg| self.register_manager.unlockReg(reg);
29083141
29093142 switch (value) {
3143 .dead => unreachable,
3144 .undef => unreachable,
29103145 .register => |value_reg| {
29113146 try self.genStrRegister(value_reg, addr_reg, value_ty);
29123147 },
......@@ -2920,13 +3155,48 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
29203155 try self.genSetReg(value_ty, tmp_reg, value);
29213156 try self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);
29223157 } 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);
29243193 }
29253194 },
29263195 }
29273196 },
29283197 .memory,
29293198 .stack_offset,
3199 .stack_argument_offset,
29303200 .got_load,
29313201 .direct_load,
29323202 => {
......@@ -3005,10 +3275,14 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
30053275 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
30063276 const mcv = try self.resolveInst(operand);
30073277 const struct_ty = self.air.typeOf(operand);
3278 const struct_field_ty = struct_ty.structFieldType(index);
30083279 const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*));
30093280
30103281 switch (mcv) {
30113282 .dead, .unreach => unreachable,
3283 .stack_argument_offset => |off| {
3284 break :result MCValue{ .stack_argument_offset = off + struct_field_offset };
3285 },
30123286 .stack_offset => |off| {
30133287 break :result MCValue{ .stack_offset = off - struct_field_offset };
30143288 },
......@@ -3016,29 +3290,28 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
30163290 break :result MCValue{ .memory = addr + struct_field_offset };
30173291 },
30183292 .register_with_overflow => |rwo| {
3019 switch (index) {
3020 0 => {
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();
3293 const reg_lock = self.register_manager.lockRegAssumeUnused(rwo.reg);
3294 defer self.register_manager.unlockReg(reg_lock);
30303295
3031 _ = try self.addInst(.{
3032 .tag = .cset,
3033 .data = .{ .r_cond = .{
3034 .rd = dest_reg,
3035 .cond = rwo.flag,
3036 } },
3037 });
3296 const field: MCValue = switch (index) {
3297 // get wrapped value: return register
3298 0 => MCValue{ .register = rwo.reg },
3299
3300 // get overflow bit: return C or V flag
3301 1 => MCValue{ .condition_flags = rwo.flag },
30383302
3039 break :result MCValue{ .register = dest_reg };
3040 },
30413303 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 };
30423315 }
30433316 },
30443317 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.
31433416 // saving compare flags may require a new caller-saved register
31443417 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
31463444 for (info.args) |mc_arg, arg_i| {
31473445 const arg = args[arg_i];
31483446 const arg_ty = self.air.typeOf(arg);
......@@ -3154,12 +3452,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
31543452 try self.register_manager.getReg(reg, null);
31553453 try self.genSetReg(arg_ty, reg, arg_mcv);
31563454 },
3157 .stack_offset => {
3158 return self.fail("TODO implement calling with parameters in memory", .{});
3159 },
3160 .ptr_stack_offset => {
3161 return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});
3162 },
3455 .stack_offset => unreachable,
3456 .stack_argument_offset => |offset| try self.genSetStackArgument(
3457 arg_ty,
3458 offset,
3459 arg_mcv,
3460 ),
31633461 else => unreachable,
31643462 }
31653463 }
......@@ -3303,8 +3601,15 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {
33033601 },
33043602 .stack_offset => {
33053603 // Return result by reference
3306 // TODO
3307 return self.fail("TODO implement airRet for {}", .{self.ret_mcv});
3604 //
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);
33083613 },
33093614 else => unreachable,
33103615 }
......@@ -3330,10 +3635,34 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
33303635 },
33313636 .stack_offset => {
33323637 // Return result by reference
3333 // TODO
3334 return self.fail("TODO implement airRetLoad for {}", .{self.ret_mcv});
3638 //
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 }
33353664 },
3336 else => unreachable,
3665 else => unreachable, // invalid return result
33373666 }
33383667
33393668 try self.exitlude_jump_relocs.append(self.gpa, try self.addNop());
......@@ -3635,40 +3964,14 @@ fn isNonNull(self: *Self, operand: MCValue) !MCValue {
36353964
36363965fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
36373966 const error_type = ty.errorUnionSet();
3638 const payload_type = ty.errorUnionPayload();
3967 const error_int_type = Type.initTag(.u16);
36393968
36403969 if (error_type.errorSetIsEmpty()) {
36413970 return MCValue{ .immediate = 0 }; // always false
36423971 }
36433972
3644 const err_off = errUnionErrorOffset(payload_type, self.target.*);
3645 switch (operand) {
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
3973 const error_mcv = try self.errUnionErr(operand, ty);
3974 _ = try self.binOp(.cmp_eq, error_mcv, .{ .immediate = 0 }, error_int_type, error_int_type, null);
36723975 return MCValue{ .condition_flags = .hi };
36733976}
36743977
......@@ -3886,7 +4189,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
38864189 block_data.mcv = switch (operand_mcv) {
38874190 .none, .dead, .unreach => unreachable,
38884191 .register, .stack_offset, .memory => operand_mcv,
3889 .immediate, .condition_flags => blk: {
4192 .immediate, .stack_argument_offset, .condition_flags => blk: {
38904193 const new_mcv = try self.allocRegOrMem(block, true);
38914194 try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv);
38924195 break :blk new_mcv;
......@@ -4128,6 +4431,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
41284431 .got_load,
41294432 .direct_load,
41304433 .memory,
4434 .stack_argument_offset,
41314435 .stack_offset,
41324436 => {
41334437 switch (mcv) {
......@@ -4166,6 +4470,15 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
41664470 // sub src_reg, fp, #off
41674471 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off });
41684472 },
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 },
41694482 .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = addr }),
41704483 .got_load,
41714484 .direct_load,
......@@ -4269,6 +4582,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
42694582 }
42704583 },
42714584 .register => |src_reg| {
4585 assert(src_reg.size() == reg.size());
4586
42724587 // If the registers are the same, nothing to do.
42734588 if (src_reg.id() == reg.id())
42744589 return;
......@@ -4330,6 +4645,196 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
43304645 else => unreachable,
43314646 }
43324647 },
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 },
43334838 }
43344839}
43354840
......@@ -4799,11 +5304,27 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
47995304 result.stack_align = 1;
48005305 return result;
48015306 },
4802 .Unspecified, .C => {
5307 .C => {
48035308 // ARM64 Procedure Call Standard
48045309 var ncrn: usize = 0; // Next Core Register Number
48055310 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
48075328 for (param_types) |ty, i| {
48085329 const param_size = @intCast(u32, ty.abiSize(self.target.*));
48095330 if (param_size == 0) {
......@@ -4837,7 +5358,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
48375358 }
48385359 }
48395360
4840 result.args[i] = .{ .stack_offset = nsaa };
5361 result.args[i] = .{ .stack_argument_offset = nsaa };
48415362 nsaa += param_size;
48425363 }
48435364 }
......@@ -4845,28 +5366,49 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
48455366 result.stack_byte_count = nsaa;
48465367 result.stack_align = 16;
48475368 },
4848 else => return self.fail("TODO implement function parameters for {} on aarch64", .{cc}),
4849 }
4850
4851 if (ret_ty.zigTypeTag() == .NoReturn) {
4852 result.return_value = .{ .unreach = {} };
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) };
5369 .Unspecified => {
5370 if (ret_ty.zigTypeTag() == .NoReturn) {
5371 result.return_value = .{ .unreach = {} };
5372 } else if (!ret_ty.hasRuntimeBitsIgnoreComptime() and !ret_ty.isError()) {
5373 result.return_value = .{ .none = {} };
48645374 } 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 }
48665389 }
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;
48675408 },
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}),
48695410 }
5411
48705412 return result;
48715413}
48725414
src/arch/aarch64/Emit.zig+111-12
......@@ -27,14 +27,21 @@ code: *std.ArrayList(u8),
2727
2828prev_di_line: u32,
2929prev_di_column: u32,
30
3031/// Relative to the beginning of `code`.
3132prev_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
3338/// The branch type of every branch
3439branch_types: std.AutoHashMapUnmanaged(Mir.Inst.Index, BranchType) = .{},
40
3541/// For every forward branch, maps the target instruction to a list of
3642/// branches which branch to this target instruction
3743branch_forward_origins: std.AutoHashMapUnmanaged(Mir.Inst.Index, std.ArrayListUnmanaged(Mir.Inst.Index)) = .{},
44
3845/// For backward branches: stores the code offset of the target
3946/// instruction
4047///
......@@ -42,6 +49,8 @@ branch_forward_origins: std.AutoHashMapUnmanaged(Mir.Inst.Index, std.ArrayListUn
4249/// instruction
4350code_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.
4554stack_size: u32,
4655
4756const InnerError = error{
......@@ -82,9 +91,11 @@ pub fn emitMir(
8291 .sub_immediate => try emit.mirAddSubtractImmediate(inst),
8392 .subs_immediate => try emit.mirAddSubtractImmediate(inst),
8493
85 .asr_register => try emit.mirShiftRegister(inst),
86 .lsl_register => try emit.mirShiftRegister(inst),
87 .lsr_register => try emit.mirShiftRegister(inst),
94 .asr_register => try emit.mirDataProcessing2Source(inst),
95 .lsl_register => try emit.mirDataProcessing2Source(inst),
96 .lsr_register => try emit.mirDataProcessing2Source(inst),
97 .sdiv => try emit.mirDataProcessing2Source(inst),
98 .udiv => try emit.mirDataProcessing2Source(inst),
8899
89100 .asr_immediate => try emit.mirShiftImmediate(inst),
90101 .lsl_immediate => try emit.mirShiftImmediate(inst),
......@@ -148,6 +159,13 @@ pub fn emitMir(
148159 .strb_stack => try emit.mirLoadStoreStack(inst),
149160 .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
151169 .ldr_register => try emit.mirLoadStoreRegisterRegister(inst),
152170 .ldrb_register => try emit.mirLoadStoreRegisterRegister(inst),
153171 .ldrh_register => try emit.mirLoadStoreRegisterRegister(inst),
......@@ -172,6 +190,7 @@ pub fn emitMir(
172190 .movk => try emit.mirMoveWideImmediate(inst),
173191 .movz => try emit.mirMoveWideImmediate(inst),
174192
193 .msub => try emit.mirDataProcessing3Source(inst),
175194 .mul => try emit.mirDataProcessing3Source(inst),
176195 .smulh => try emit.mirDataProcessing3Source(inst),
177196 .smull => try emit.mirDataProcessing3Source(inst),
......@@ -258,7 +277,7 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize {
258277 => return 2 * 4,
259278 .pop_regs, .push_regs => {
260279 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);
262281 const number_of_insts = std.math.divCeil(u6, number_of_regs, 2) catch unreachable;
263282 return number_of_insts * 4;
264283 },
......@@ -504,7 +523,7 @@ fn mirAddSubtractImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
504523 }
505524}
506525
507fn mirShiftRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
526fn mirDataProcessing2Source(emit: *Emit, inst: Mir.Inst.Index) !void {
508527 const tag = emit.mir.instructions.items(.tag)[inst];
509528 const rrr = emit.mir.instructions.items(.data)[inst].rrr;
510529 const rd = rrr.rd;
......@@ -515,6 +534,8 @@ fn mirShiftRegister(emit: *Emit, inst: Mir.Inst.Index) !void {
515534 .asr_register => try emit.writeInstruction(Instruction.asrRegister(rd, rn, rm)),
516535 .lsl_register => try emit.writeInstruction(Instruction.lslRegister(rd, rn, rm)),
517536 .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)),
518539 else => unreachable,
519540 }
520541}
......@@ -920,6 +941,67 @@ fn mirLoadStoreRegisterPair(emit: *Emit, inst: Mir.Inst.Index) !void {
920941 }
921942}
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
9231005fn mirLoadStoreStack(emit: *Emit, inst: Mir.Inst.Index) !void {
9241006 const tag = emit.mir.instructions.items(.tag)[inst];
9251007 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 {
10591141
10601142fn mirDataProcessing3Source(emit: *Emit, inst: Mir.Inst.Index) !void {
10611143 const tag = emit.mir.instructions.items(.tag)[inst];
1062 const rrr = emit.mir.instructions.items(.data)[inst].rrr;
10631144
10641145 switch (tag) {
1065 .mul => try emit.writeInstruction(Instruction.mul(rrr.rd, rrr.rn, rrr.rm)),
1066 .smulh => try emit.writeInstruction(Instruction.smulh(rrr.rd, rrr.rn, rrr.rm)),
1067 .smull => try emit.writeInstruction(Instruction.smull(rrr.rd, rrr.rn, rrr.rm)),
1068 .umulh => try emit.writeInstruction(Instruction.umulh(rrr.rd, rrr.rn, rrr.rm)),
1069 .umull => try emit.writeInstruction(Instruction.umull(rrr.rd, rrr.rn, rrr.rm)),
1146 .mul,
1147 .smulh,
1148 .smull,
1149 .umulh,
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 },
10701169 else => unreachable,
10711170 }
10721171}
......@@ -1084,7 +1183,7 @@ fn mirPushPopRegs(emit: *Emit, inst: Mir.Inst.Index) !void {
10841183 // sp must be aligned at all times, so we only use stp and ldp
10851184 // instructions for minimal instruction count. However, if we do
10861185 // 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
10891188 switch (tag) {
10901189 .pop_regs => {
src/arch/aarch64/Mir.zig+27
......@@ -92,20 +92,28 @@ pub const Inst = struct {
9292 load_memory_ptr_direct,
9393 /// Load Pair of Registers
9494 ldp,
95 /// Pseudo-instruction: Load pointer to stack argument
96 ldr_ptr_stack_argument,
9597 /// Pseudo-instruction: Load from stack
9698 ldr_stack,
99 /// Pseudo-instruction: Load from stack argument
100 ldr_stack_argument,
97101 /// Load Register (immediate)
98102 ldr_immediate,
99103 /// Load Register (register)
100104 ldr_register,
101105 /// Pseudo-instruction: Load byte from stack
102106 ldrb_stack,
107 /// Pseudo-instruction: Load byte from stack argument
108 ldrb_stack_argument,
103109 /// Load Register Byte (immediate)
104110 ldrb_immediate,
105111 /// Load Register Byte (register)
106112 ldrb_register,
107113 /// Pseudo-instruction: Load halfword from stack
108114 ldrh_stack,
115 /// Pseudo-instruction: Load halfword from stack argument
116 ldrh_stack_argument,
109117 /// Load Register Halfword (immediate)
110118 ldrh_immediate,
111119 /// Load Register Halfword (register)
......@@ -114,10 +122,14 @@ pub const Inst = struct {
114122 ldrsb_immediate,
115123 /// Pseudo-instruction: Load signed byte from stack
116124 ldrsb_stack,
125 /// Pseudo-instruction: Load signed byte from stack argument
126 ldrsb_stack_argument,
117127 /// Load Register Signed Halfword (immediate)
118128 ldrsh_immediate,
119129 /// Pseudo-instruction: Load signed halfword from stack
120130 ldrsh_stack,
131 /// Pseudo-instruction: Load signed halfword from stack argument
132 ldrsh_stack_argument,
121133 /// Load Register Signed Word (immediate)
122134 ldrsw_immediate,
123135 /// Logical Shift Left (immediate)
......@@ -136,6 +148,8 @@ pub const Inst = struct {
136148 movk,
137149 /// Move wide with zero
138150 movz,
151 /// Multiply-subtract
152 msub,
139153 /// Multiply
140154 mul,
141155 /// Bitwise NOT
......@@ -152,6 +166,8 @@ pub const Inst = struct {
152166 ret,
153167 /// Signed bitfield extract
154168 sbfx,
169 /// Signed divide
170 sdiv,
155171 /// Signed multiply high
156172 smulh,
157173 /// Signed multiply long
......@@ -200,6 +216,8 @@ pub const Inst = struct {
200216 tst_immediate,
201217 /// Unsigned bitfield extract
202218 ubfx,
219 /// Unsigned divide
220 udiv,
203221 /// Unsigned multiply high
204222 umulh,
205223 /// Unsigned multiply long
......@@ -430,6 +448,15 @@ pub const Inst = struct {
430448 rn: Register,
431449 offset: bits.Instruction.LoadStorePairOffset,
432450 },
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 },
433460 /// Debug info: line and column
434461 ///
435462 /// Used by e.g. dbg_line
src/arch/aarch64/bits.zig+8
......@@ -1698,6 +1698,14 @@ pub const Instruction = union(enum) {
16981698
16991699 // 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
17011709 pub fn lslv(rd: Register, rn: Register, rm: Register) Instruction {
17021710 return dataProcessing2Source(0b0, 0b001000, rd, rn, rm);
17031711 }
src/arch/arm/CodeGen.zig+168-31
......@@ -247,6 +247,31 @@ const BigTomb = struct {
247247 log.debug("%{d} => {}", .{ bt.inst, result });
248248 const branch = &bt.function.branch_stack.items[bt.function.branch_stack.items.len - 1];
249249 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 }
250275 }
251276 bt.function.finishAirBookkeeping();
252277 }
......@@ -332,7 +357,7 @@ pub fn generate(
332357 };
333358
334359 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);
336361 }
337362
338363 var mir = Mir{
......@@ -351,7 +376,8 @@ pub fn generate(
351376 .prev_di_pc = 0,
352377 .prev_di_line = module_fn.lbrace_line,
353378 .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,
355381 };
356382 defer emit.deinit();
357383
......@@ -464,6 +490,7 @@ fn gen(self: *Self) !void {
464490 const total_stack_size = self.max_end_stack + self.saved_regs_stack_space;
465491 const aligned_total_stack_end = mem.alignForwardGeneric(u32, total_stack_size, self.stack_align);
466492 const stack_size = aligned_total_stack_end - self.saved_regs_stack_space;
493 self.max_end_stack = stack_size;
467494 if (Instruction.Operand.fromU32(stack_size)) |op| {
468495 self.mir_instructions.set(sub_reloc, .{
469496 .tag = .sub,
......@@ -768,6 +795,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
768795 .float_to_int_optimized,
769796 => 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
771801 .wasm_memory_size => unreachable,
772802 .wasm_memory_grow => unreachable,
773803 // zig fmt: on
......@@ -1810,7 +1840,7 @@ fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCV
18101840 switch (error_union_mcv) {
18111841 .register => return self.fail("TODO errUnionErr for registers", .{}),
18121842 .stack_argument_offset => |off| {
1813 return MCValue{ .stack_argument_offset = off - err_offset };
1843 return MCValue{ .stack_argument_offset = off + err_offset };
18141844 },
18151845 .stack_offset => |off| {
18161846 return MCValue{ .stack_offset = off - err_offset };
......@@ -1847,7 +1877,7 @@ fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type)
18471877 switch (error_union_mcv) {
18481878 .register => return self.fail("TODO errUnionPayload for registers", .{}),
18491879 .stack_argument_offset => |off| {
1850 return MCValue{ .stack_argument_offset = off - payload_offset };
1880 return MCValue{ .stack_argument_offset = off + payload_offset };
18511881 },
18521882 .stack_offset => |off| {
18531883 return MCValue{ .stack_offset = off - payload_offset };
......@@ -1981,7 +2011,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
19812011 .dead, .unreach => unreachable,
19822012 .register => unreachable, // a slice doesn't fit in one register
19832013 .stack_argument_offset => |off| {
1984 break :result MCValue{ .stack_argument_offset = off - 4 };
2014 break :result MCValue{ .stack_argument_offset = off + 4 };
19852015 },
19862016 .stack_offset => |off| {
19872017 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
22572287 .register_c_flag,
22582288 .register_v_flag,
22592289 => unreachable, // cannot hold an address
2260 .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }),
2261 .ptr_stack_offset => |off| try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }),
2290 .immediate => |imm| {
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 },
22622296 .register => |reg| {
22632297 const reg_lock = self.register_manager.lockReg(reg);
22642298 defer if (reg_lock) |reg_locked| self.register_manager.unlockReg(reg_locked);
22652299
22662300 switch (dst_mcv) {
2267 .dead => unreachable,
2268 .undef => unreachable,
2269 .cpsr_flags => unreachable,
22702301 .register => |dst_reg| {
22712302 try self.genLdrRegister(dst_reg, reg, elem_ty);
22722303 },
......@@ -2302,7 +2333,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
23022333 try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg);
23032334 }
23042335 },
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
23062337 }
23072338 },
23082339 .memory,
......@@ -2399,7 +2430,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
23992430 // sub src_reg, fp, #off
24002431 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = off });
24012432 },
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) }),
24032434 .stack_argument_offset => |off| {
24042435 _ = try self.addInst(.{
24052436 .tag = .ldr_ptr_stack_argument,
......@@ -2505,7 +2536,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
25052536 switch (mcv) {
25062537 .dead, .unreach => unreachable,
25072538 .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 };
25092540 },
25102541 .stack_offset => |off| {
25112542 break :result MCValue{ .stack_offset = off - struct_field_offset };
......@@ -3345,6 +3376,102 @@ fn genInlineMemcpy(
33453376 // end:
33463377}
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
33483475/// Adds a Type to the .debug_info at the current position. The bytes will be populated later,
33493476/// after codegen for this symbol is done.
33503477fn addDbgInfoTypeReloc(self: *Self, ty: Type) error{OutOfMemory}!void {
......@@ -3367,12 +3494,10 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) error{OutOfMemory}!void {
33673494 }
33683495}
33693496
3370fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, arg_index: u32, stack_byte_count: u32) error{OutOfMemory}!void {
3371 const prologue_stack_space = stack_byte_count + self.saved_regs_stack_space;
3372
3497fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, arg_index: u32) error{OutOfMemory}!void {
33733498 const mcv = self.args[arg_index];
33743499 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);
33763501 const name_with_null = name.ptr[0 .. name.len + 1];
33773502
33783503 switch (mcv) {
......@@ -3402,7 +3527,7 @@ fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, arg_index: u32, stack_byte_c
34023527 // const abi_size = @intCast(u32, ty.abiSize(self.target.*));
34033528 const adjusted_stack_offset = switch (mcv) {
34043529 .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),
34063531 else => unreachable,
34073532 };
34083533
......@@ -3522,7 +3647,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
35223647 try self.register_manager.getReg(reg, null);
35233648 }
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: {
35263654 log.debug("airCall: return by reference", .{});
35273655 const ret_ty = fn_ty.fnReturnType();
35283656 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.
35383666 try self.genSetReg(ptr_ty, .r0, .{ .ptr_stack_offset = stack_offset });
35393667
35403668 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
35433674 // Make space for the arguments passed via the stack
35443675 self.max_end_stack += info.stack_byte_count;
......@@ -3557,7 +3688,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
35573688 .stack_offset => unreachable,
35583689 .stack_argument_offset => |offset| try self.genSetStackArgument(
35593690 arg_ty,
3560 info.stack_byte_count - offset,
3691 offset,
35613692 arg_mcv,
35623693 ),
35633694 else => unreachable,
......@@ -4619,11 +4750,15 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
46194750 if (!self.wantSafety())
46204751 return; // The already existing value will do just fine.
46214752 // TODO Upgrade this to a memset call when we have that available.
4622 switch (ty.abiSize(self.target.*)) {
4623 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }),
4624 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }),
4625 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }),
4626 else => return self.fail("TODO implement memset", .{}),
4753 switch (abi_size) {
4754 1 => try self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }),
4755 2 => try self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }),
4756 4 => try self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }),
4757 else => try self.genInlineMemset(
4758 .{ .ptr_stack_offset = stack_offset },
4759 .{ .immediate = 0xaa },
4760 .{ .immediate = abi_size },
4761 ),
46274762 }
46284763 },
46294764 .cpsr_flags,
......@@ -5035,9 +5170,9 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
50355170 return; // The already existing value will do just fine.
50365171 // TODO Upgrade this to a memset call when we have that available.
50375172 switch (abi_size) {
5038 1 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaa }),
5039 2 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaa }),
5040 4 => return self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }),
5173 1 => try self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaa }),
5174 2 => try self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaa }),
5175 4 => try self.genSetStackArgument(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }),
50415176 else => return self.fail("TODO implement memset", .{}),
50425177 }
50435178 },
......@@ -5651,8 +5786,8 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
56515786 if (ty.abiAlignment(self.target.*) == 8)
56525787 nsaa = std.mem.alignForwardGeneric(u32, nsaa, 8);
56535788
5654 nsaa += param_size;
56555789 result.args[i] = .{ .stack_argument_offset = nsaa };
5790 nsaa += param_size;
56565791 }
56575792 }
56585793
......@@ -5685,9 +5820,11 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
56855820 for (param_types) |ty, i| {
56865821 if (ty.abiSize(self.target.*) > 0) {
56875822 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);
56905826 result.args[i] = .{ .stack_argument_offset = stack_offset };
5827 stack_offset += param_size;
56915828 } else {
56925829 result.args[i] = .{ .none = {} };
56935830 }
src/arch/arm/Emit.zig+19-38
......@@ -33,9 +33,13 @@ prev_di_column: u32,
3333/// Relative to the beginning of `code`.
3434prev_di_pc: usize,
3535
36/// The amount of stack space consumed by all stack arguments as well
37/// as the saved callee-saved registers
38prologue_stack_space: u32,
36/// The amount of stack space consumed by the saved callee-saved
37/// registers in bytes
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
4044/// The branch type of every branch
4145branch_types: std.AutoHashMapUnmanaged(Mir.Inst.Index, BranchType) = .{},
......@@ -500,14 +504,15 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void {
500504 const tag = emit.mir.instructions.items(.tag)[inst];
501505 const cond = emit.mir.instructions.items(.cond)[inst];
502506 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;
505510 switch (tag) {
506511 .ldr_ptr_stack_argument => {
507512 const operand = Instruction.Operand.fromU32(raw_offset) orelse
508513 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));
511516 },
512517 .ldr_stack_argument,
513518 .ldrb_stack_argument,
......@@ -516,23 +521,11 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void {
516521 break :blk Instruction.Offset.imm(@intCast(u12, raw_offset));
517522 } else return emit.fail("TODO mirLoadStack larger offsets", .{});
518523
519 const ldr = switch (tag) {
520 .ldr_stack_argument => &Instruction.ldr,
521 .ldrb_stack_argument => &Instruction.ldrb,
524 switch (tag) {
525 .ldr_stack_argument => try emit.writeInstruction(Instruction.ldr(cond, rt, .sp, .{ .offset = offset })),
526 .ldrb_stack_argument => try emit.writeInstruction(Instruction.ldrb(cond, rt, .sp, .{ .offset = offset })),
522527 else => unreachable,
523 };
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 ));
528 }
536529 },
537530 .ldrh_stack_argument,
538531 .ldrsb_stack_argument,
......@@ -542,24 +535,12 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void {
542535 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, raw_offset));
543536 } else return emit.fail("TODO mirLoadStack larger offsets", .{});
544537
545 const ldr = switch (tag) {
546 .ldrh_stack_argument => &Instruction.ldrh,
547 .ldrsb_stack_argument => &Instruction.ldrsb,
548 .ldrsh_stack_argument => &Instruction.ldrsh,
538 switch (tag) {
539 .ldrh_stack_argument => try emit.writeInstruction(Instruction.ldrh(cond, rt, .sp, .{ .offset = offset })),
540 .ldrsb_stack_argument => try emit.writeInstruction(Instruction.ldrsb(cond, rt, .sp, .{ .offset = offset })),
541 .ldrsh_stack_argument => try emit.writeInstruction(Instruction.ldrsh(cond, rt, .sp, .{ .offset = offset })),
549542 else => unreachable,
550 };
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 ));
543 }
563544 },
564545 else => unreachable,
565546 }
src/arch/riscv64/CodeGen.zig+4-1
......@@ -693,6 +693,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
693693 .float_to_int_optimized,
694694 => 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
696699 .wasm_memory_size => unreachable,
697700 .wasm_memory_grow => unreachable,
698701 // zig fmt: on
......@@ -1619,7 +1622,7 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
16191622
16201623fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32) !void {
16211624 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);
16231626 const name_with_null = name.ptr[0 .. name.len + 1];
16241627
16251628 switch (mcv) {
src/arch/sparc64/CodeGen.zig+4-1
......@@ -705,6 +705,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
705705 .float_to_int_optimized,
706706 => @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
708711 .wasm_memory_size => unreachable,
709712 .wasm_memory_grow => unreachable,
710713 // zig fmt: on
......@@ -2959,7 +2962,7 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live
29592962
29602963fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32) !void {
29612964 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);
29632966 const name_with_null = name.ptr[0 .. name.len + 1];
29642967
29652968 switch (mcv) {
src/arch/wasm/CodeGen.zig+422-330
......@@ -29,6 +29,8 @@ const errUnionErrorOffset = codegen.errUnionErrorOffset;
2929const WValue = union(enum) {
3030 /// May be referenced but is unused
3131 none: void,
32 /// The value lives on top of the stack
33 stack: void,
3234 /// Index of the local variable
3335 local: u32,
3436 /// An immediate 32bit value
......@@ -55,7 +57,7 @@ const WValue = union(enum) {
5557 /// In wasm function pointers are indexes into a function table,
5658 /// rather than an address in the data section.
5759 function_index: u32,
58 /// Offset from the bottom of the stack, with the offset
60 /// Offset from the bottom of the virtual stack, with the offset
5961 /// pointing to where the value lives.
6062 stack_offset: u32,
6163
......@@ -71,6 +73,38 @@ const WValue = union(enum) {
7173 else => return 0,
7274 }
7375 }
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 }
74108};
75109
76110/// Wasm ops, but without input/output/signedness information
......@@ -601,6 +635,21 @@ stack_size: u32 = 0,
601635/// However, local variables or the usage of `@setAlignStack` can overwrite this default.
602636stack_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
604653const InnerError = error{
605654 OutOfMemory,
606655 /// An error occurred when trying to lower AIR to MIR.
......@@ -759,7 +808,7 @@ fn genBlockType(ty: Type, target: std.Target) u8 {
759808/// Writes the bytecode depending on the given `WValue` in `val`
760809fn emitWValue(self: *Self, value: WValue) InnerError!void {
761810 switch (value) {
762 .none => {}, // no-op
811 .none, .stack => {}, // no-op
763812 .local => |idx| try self.addLabel(.local_get, idx),
764813 .imm32 => |val| try self.addImm32(@bitCast(i32, val)),
765814 .imm64 => |val| try self.addImm64(val),
......@@ -781,9 +830,30 @@ fn emitWValue(self: *Self, value: WValue) InnerError!void {
781830/// Creates one locals for a given `Type`.
782831/// Returns a corresponding `Wvalue` with `local` as active tag
783832fn 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));
784856 const initial_index = self.local_index;
785 const valtype = genValtype(ty, self.target);
786 try self.locals.append(self.gpa, valtype);
787857 self.local_index += 1;
788858 return WValue{ .local = initial_index };
789859}
......@@ -1135,9 +1205,9 @@ fn initializeStack(self: *Self) !void {
11351205 // Reserve a local to store the current stack pointer
11361206 // We can later use this local to set the stack pointer back to the value
11371207 // we have stored here.
1138 self.initial_stack_value = try self.allocLocal(Type.usize);
1208 self.initial_stack_value = try self.ensureAllocLocal(Type.usize);
11391209 // 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);
11411211}
11421212
11431213/// 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 {
12681338 else => {
12691339 // TODO: We should probably lower this to a call to compiler_rt
12701340 // But for now, we implement it manually
1271 const offset = try self.allocLocal(Type.usize); // local for counter
1341 var offset = try self.ensureAllocLocal(Type.usize); // local for counter
1342 defer offset.free(self);
1343
12721344 // outer block to jump to when loop is done
12731345 try self.startBlock(.block, wasm.block_empty);
12741346 try self.startBlock(.loop, wasm.block_empty);
......@@ -1405,7 +1477,7 @@ fn buildPointerOffset(self: *Self, ptr_value: WValue, offset: u64, action: enum
14051477 // do not perform arithmetic when offset is 0.
14061478 if (offset == 0 and ptr_value.offset() == 0 and action == .modify) return ptr_value;
14071479 const result_ptr: WValue = switch (action) {
1408 .new => try self.allocLocal(Type.usize),
1480 .new => try self.ensureAllocLocal(Type.usize),
14091481 .modify => ptr_value,
14101482 };
14111483 try self.emitWValue(ptr_value);
......@@ -1621,6 +1693,8 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
16211693 .tag_name,
16221694 .err_return_trace,
16231695 .set_err_return_trace,
1696 .is_named_enum_value,
1697 .error_set_has_value,
16241698 => |tag| return self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}),
16251699
16261700 .add_optimized,
......@@ -1652,7 +1726,10 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
16521726fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
16531727 for (body) |inst| {
16541728 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 }
16561733 }
16571734}
16581735
......@@ -1726,8 +1803,8 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
17261803
17271804 const fn_info = self.decl.ty.fnInfo();
17281805 if (!firstParamSRet(fn_info.cc, fn_info.return_type, self.target)) {
1729 const result = try self.load(operand, ret_ty, 0);
1730 try self.emitWValue(result);
1806 // leave on the stack
1807 _ = try self.load(operand, ret_ty, 0);
17311808 }
17321809
17331810 try self.restoreStackPointer();
......@@ -1846,6 +1923,7 @@ fn airStore(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
18461923}
18471924
18481925fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerError!void {
1926 assert(!(lhs != .stack and rhs == .stack));
18491927 switch (ty.zigTypeTag()) {
18501928 .ErrorUnion => {
18511929 const pl_ty = ty.errorUnionPayload();
......@@ -1879,20 +1957,26 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
18791957 .Pointer => {
18801958 if (ty.isSlice()) {
18811959 // 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);
18821962 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
18851965 // retrieve length from rhs, and store that alongside lhs as well
1966 try self.emitWValue(lhs);
18861967 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());
18881969 return;
18891970 }
18901971 },
18911972 .Int => if (ty.intInfo(self.target).bits > 64) {
1973 try self.emitWValue(lhs);
18921974 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);
18931978 const msb = try self.load(rhs, Type.u64, 8);
1894 try self.store(lhs, lsb, Type.u64, 0);
1895 try self.store(lhs, msb, Type.u64, 8);
1979 try self.store(.{ .stack = {} }, msb, Type.u64, 8 + lhs.offset());
18961980 return;
18971981 },
18981982 else => {},
......@@ -1931,9 +2015,12 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
19312015 return new_local;
19322016 }
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);
19352020}
19362021
2022/// Loads an operand from the linear memory section.
2023/// NOTE: Leaves the value on the stack.
19372024fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue {
19382025 // load local's value from memory by its stack position
19392026 try self.emitWValue(operand);
......@@ -1951,10 +2038,7 @@ fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue {
19512038 .{ .offset = offset + operand.offset(), .alignment = ty.abiAlignment(self.target) },
19522039 );
19532040
1954 // store the result in a local
1955 const result = try self.allocLocal(ty);
1956 try self.addLabel(.local_set, result.local);
1957 return result;
2041 return WValue{ .stack = {} };
19582042}
19592043
19602044fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -1991,7 +2075,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
19912075 switch (self.debug_output) {
19922076 .dwarf => |dwarf| {
19932077 // 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);
19952079 const leb_size = link.File.Wasm.getULEB128Size(arg.local);
19962080 const dbg_info = &dwarf.dbg_info;
19972081 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 {
20242108 const rhs = try self.resolveInst(bin_op.rhs);
20252109 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);
20282113}
20292114
2115/// Performs a binary operation on the given `WValue`'s
2116/// NOTE: THis leaves the value on top of the stack.
20302117fn binOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {
2118 assert(!(lhs != .stack and rhs == .stack));
20312119 if (isByRef(ty, self.target)) {
20322120 if (ty.zigTypeTag() == .Int) {
20332121 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
20532141
20542142 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
20552143
2056 // save the result in a temporary
2057 const bin_local = try self.allocLocal(ty);
2058 try self.addLabel(.local_set, bin_local.local);
2059 return bin_local;
2144 return WValue{ .stack = {} };
20602145}
20612146
2147/// Performs a binary operation for 16-bit floats.
2148/// NOTE: Leaves the result value on the stack
20622149fn 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
20662150 const opcode: wasm.Opcode = buildOpcode(.{ .op = op, .valtype1 = .f32, .signedness = .unsigned });
2067 try self.emitWValue(ext_lhs);
2068 try self.emitWValue(ext_rhs);
2151 _ = try self.fpext(lhs, Type.f16, Type.f32);
2152 _ = try self.fpext(rhs, Type.f16, Type.f32);
20692153 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
20702154
2071 // re-use temporary local
2072 try self.addLabel(.local_set, ext_lhs.local);
2073 return self.fptrunc(ext_lhs, Type.f32, Type.f16);
2155 return self.fptrunc(.{ .stack = {} }, Type.f32, Type.f16);
20742156}
20752157
20762158fn 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
20832165 }
20842166
20852167 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
20872175 const lhs_low_bit = try self.load(lhs, Type.u64, 8);
2088 const rhs_high_bit = try self.load(rhs, Type.u64, 0);
20892176 const rhs_low_bit = try self.load(rhs, Type.u64, 8);
2090
20912177 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
20942179 const lt = if (op == .add) blk: {
20952180 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
20972182 break :blk try self.cmp(lhs_high_bit, rhs_high_bit, Type.u64, .lt);
20982183 } else unreachable;
20992184 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
21022188 try self.store(result, high_op_res, Type.u64, 0);
21032189 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 {
21142200 return self.fail("TODO: Implement wrapping arithmetic for vectors", .{});
21152201 }
21162202
2117 return self.wrapBinOp(lhs, rhs, ty, op);
2203 return (try self.wrapBinOp(lhs, rhs, ty, op)).toLocal(self, ty);
21182204}
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
21202209fn wrapBinOp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue {
2121 const bit_size = ty.intInfo(self.target).bits;
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
2210 const bin_local = try self.binOp(lhs, rhs, ty, op);
21432211 return self.wrapOperand(bin_local, ty);
21442212}
21452213
21462214/// Wraps an operand based on a given type's bitsize.
21472215/// Asserts `Type` is <= 128 bits.
2216/// NOTE: When the Type is <= 64 bits, leaves the value on top of the stack.
21482217fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue {
21492218 assert(ty.abiSize(self.target) <= 16);
2150 const result_local = try self.allocLocal(ty);
21512219 const bitsize = ty.intInfo(self.target).bits;
21522220 const wasm_bits = toWasmBits(bitsize) orelse {
21532221 return self.fail("TODO: Implement wrapOperand for bitsize '{d}'", .{bitsize});
......@@ -2156,14 +2224,15 @@ fn wrapOperand(self: *Self, operand: WValue, ty: Type) InnerError!WValue {
21562224 if (wasm_bits == bitsize) return operand;
21572225
21582226 if (wasm_bits == 128) {
2159 const msb = try self.load(operand, Type.u64, 0);
2227 assert(operand != .stack);
21602228 const lsb = try self.load(operand, Type.u64, 8);
21612229
21622230 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());
21642233 const result = (@as(u64, 1) << @intCast(u6, 64 - (wasm_bits - bitsize))) - 1;
21652234 try self.emitWValue(result_ptr);
2166 try self.emitWValue(msb);
2235 _ = try self.load(operand, Type.u64, 0);
21672236 try self.addImm64(result);
21682237 try self.addTag(.i64_and);
21692238 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 {
21802249 try self.addTag(.i64_and);
21812250 } else unreachable;
21822251
2183 try self.addLabel(.local_set, result_local.local);
2184 return result_local;
2252 return WValue{ .stack = {} };
21852253}
21862254
21872255fn 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
25932661 const lhs = try self.resolveInst(bin_op.lhs);
25942662 const rhs = try self.resolveInst(bin_op.rhs);
25952663 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
25972665}
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.
25992670fn cmp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOperator) InnerError!WValue {
2671 assert(!(lhs != .stack and rhs == .stack));
26002672 if (ty.zigTypeTag() == .Optional and !ty.optionalReprIsPayload()) {
26012673 var buf: Type.Payload.ElemType = undefined;
26022674 const payload_ty = ty.optionalChild(&buf);
......@@ -2638,15 +2710,12 @@ fn cmp(self: *Self, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOper
26382710 });
26392711 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
26402712
2641 const cmp_tmp = try self.allocLocal(Type.initTag(.i32)); // bool is always i32
2642 try self.addLabel(.local_set, cmp_tmp.local);
2643 return cmp_tmp;
2713 return WValue{ .stack = {} };
26442714}
26452715
2716/// Compares 16-bit floats
2717/// NOTE: The result value remains on top of the stack.
26462718fn 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
26502719 const opcode: wasm.Opcode = buildOpcode(.{
26512720 .op = switch (op) {
26522721 .lt => .lt,
......@@ -2659,13 +2728,11 @@ fn cmpFloat16(self: *Self, lhs: WValue, rhs: WValue, op: std.math.CompareOperato
26592728 .valtype1 = .f32,
26602729 .signedness = .unsigned,
26612730 });
2662 try self.emitWValue(ext_lhs);
2663 try self.emitWValue(ext_rhs);
2731 _ = try self.fpext(lhs, Type.f16, Type.f32);
2732 _ = try self.fpext(rhs, Type.f16, Type.f32);
26642733 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
26652734
2666 const result = try self.allocLocal(Type.initTag(.i32)); // bool is always i32
2667 try self.addLabel(.local_set, result.local);
2668 return result;
2735 return WValue{ .stack = {} };
26692736}
26702737
26712738fn airCmpVector(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -2726,21 +2793,23 @@ fn airNot(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
27262793 switch (wasm_bits) {
27272794 32 => {
27282795 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);
27302797 },
27312798 64 => {
27322799 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);
27342801 },
27352802 128 => {
27362803 const result_ptr = try self.allocStack(operand_ty);
2804 try self.emitWValue(result_ptr);
27372805 const msb = try self.load(operand, Type.u64, 0);
2738 const lsb = try self.load(operand, Type.u64, 8);
2739
27402806 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);
27412811 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);
2743 try self.store(result_ptr, lsb_xor, Type.u64, 8);
2812 try self.store(result_ptr, lsb_xor, Type.u64, 8 + result_ptr.offset());
27442813 return result_ptr;
27452814 },
27462815 else => unreachable,
......@@ -2828,7 +2897,8 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
28282897 }
28292898 }
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);
28322902}
28332903
28342904fn 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)
30383108 if (op_is_ptr or isByRef(payload_ty, self.target)) {
30393109 return self.buildPointerOffset(operand, pl_offset, .new);
30403110 }
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);
30423114}
30433115
30443116fn 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
30583130 return operand;
30593131 }
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);
30623135}
30633136
30643137fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -3124,12 +3197,13 @@ fn airIntcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
31243197 return self.fail("todo Wasm intcast for bitsize > 128", .{});
31253198 }
31263199
3127 return self.intcast(operand, operand_ty, ty);
3200 return (try self.intcast(operand, operand_ty, ty)).toLocal(self, ty);
31283201}
31293202
31303203/// Upcasts or downcasts an integer based on the given and wanted types,
31313204/// and stores the result in a new operand.
31323205/// Asserts type's bitsize <= 128
3206/// NOTE: May leave the result on the top of the stack.
31333207fn intcast(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WValue {
31343208 const given_info = given.intInfo(self.target);
31353209 const wanted_info = wanted.intInfo(self.target);
......@@ -3152,25 +3226,22 @@ fn intcast(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!W
31523226 } else if (wanted_bits == 128) {
31533227 // for 128bit integers we store the integer in the virtual stack, rather than a local
31543228 const stack_ptr = try self.allocStack(wanted);
3229 try self.emitWValue(stack_ptr);
31553230
31563231 // for 32 bit integers, we first coerce the value into a 64 bit integer before storing it
31573232 // meaning less store operations are required.
31583233 const lhs = if (op_bits == 32) blk: {
3159 const tmp = try self.intcast(
3160 operand,
3161 given,
3162 if (wanted.isSignedInt()) Type.i64 else Type.u64,
3163 );
3164 break :blk tmp;
3234 break :blk try self.intcast(operand, given, if (wanted.isSignedInt()) Type.i64 else Type.u64);
31653235 } else operand;
31663236
31673237 // 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
31703240 // For signed integers we shift msb by 63 (64bit integer - 1 sign bit) and store remaining value
31713241 if (wanted.isSignedInt()) {
3242 try self.emitWValue(stack_ptr);
31723243 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());
31743245 } else {
31753246 // Ensure memory of lsb is zero'd
31763247 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
31783249 return stack_ptr;
31793250 } else return self.load(operand, wanted, 0);
31803251
3181 const result = try self.allocLocal(wanted);
3182 try self.addLabel(.local_set, result.local);
3183 return result;
3252 return WValue{ .stack = {} };
31843253}
31853254
31863255fn 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
31893258
31903259 const op_ty = self.air.typeOf(un_op);
31913260 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);
31933263}
31943264
3265/// For a given type and operand, checks if it's considered `null`.
3266/// NOTE: Leaves the result on the stack
31953267fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode) InnerError!WValue {
31963268 try self.emitWValue(operand);
31973269 if (!optional_ty.optionalReprIsPayload()) {
......@@ -3208,9 +3280,7 @@ fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode)
32083280 try self.addImm32(0);
32093281 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
32103282
3211 const is_null_tmp = try self.allocLocal(Type.initTag(.i32));
3212 try self.addLabel(.local_set, is_null_tmp.local);
3213 return is_null_tmp;
3283 return WValue{ .stack = {} };
32143284}
32153285
32163286fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -3228,7 +3298,8 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
32283298 return self.buildPointerOffset(operand, offset, .new);
32293299 }
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);
32323303}
32333304
32343305fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -3331,7 +3402,8 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
33313402 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
33323403 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);
33353407}
33363408
33373409fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -3345,8 +3417,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
33453417 const elem_size = elem_ty.abiSize(self.target);
33463418
33473419 // load pointer onto stack
3348 const slice_ptr = try self.load(slice, Type.usize, 0);
3349 try self.addLabel(.local_get, slice_ptr.local);
3420 _ = try self.load(slice, Type.usize, 0);
33503421
33513422 // calculate index into slice
33523423 try self.emitWValue(index);
......@@ -3360,7 +3431,9 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
33603431 if (isByRef(elem_ty, self.target)) {
33613432 return result;
33623433 }
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);
33643437}
33653438
33663439fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -3373,8 +3446,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
33733446 const slice = try self.resolveInst(bin_op.lhs);
33743447 const index = try self.resolveInst(bin_op.rhs);
33753448
3376 const slice_ptr = try self.load(slice, Type.usize, 0);
3377 try self.addLabel(.local_get, slice_ptr.local);
3449 _ = try self.load(slice, Type.usize, 0);
33783450
33793451 // calculate index into slice
33803452 try self.emitWValue(index);
......@@ -3382,7 +3454,7 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
33823454 try self.addTag(.i32_mul);
33833455 try self.addTag(.i32_add);
33843456
3385 const result = try self.allocLocal(Type.initTag(.i32));
3457 const result = try self.allocLocal(Type.i32);
33863458 try self.addLabel(.local_set, result.local);
33873459 return result;
33883460}
......@@ -3391,7 +3463,8 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
33913463 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
33923464 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
33933465 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);
33953468}
33963469
33973470fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -3406,13 +3479,13 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
34063479 return self.fail("TODO: Implement wasm integer truncation for integer bitsize: {d}", .{int_info.bits});
34073480 }
34083481
3409 const result = try self.intcast(operand, op_ty, wanted_ty);
3482 var result = try self.intcast(operand, op_ty, wanted_ty);
34103483 const wanted_bits = wanted_ty.intInfo(self.target).bits;
34113484 const wasm_bits = toWasmBits(wanted_bits).?;
34123485 if (wasm_bits != wanted_bits) {
3413 return self.wrapOperand(result, wanted_ty);
3486 result = try self.wrapOperand(result, wanted_ty);
34143487 }
3415 return result;
3488 return result.toLocal(self, wanted_ty);
34163489}
34173490
34183491fn airBoolToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -3465,8 +3538,7 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
34653538
34663539 // load pointer onto the stack
34673540 if (ptr_ty.isSlice()) {
3468 const ptr_local = try self.load(ptr, Type.usize, 0);
3469 try self.addLabel(.local_get, ptr_local.local);
3541 _ = try self.load(ptr, Type.usize, 0);
34703542 } else {
34713543 try self.lowerToStack(ptr);
34723544 }
......@@ -3477,12 +3549,15 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
34773549 try self.addTag(.i32_mul);
34783550 try self.addTag(.i32_add);
34793551
3480 const result = try self.allocLocal(elem_ty);
3552 var result = try self.allocLocal(elem_ty);
34813553 try self.addLabel(.local_set, result.local);
34823554 if (isByRef(elem_ty, self.target)) {
34833555 return result;
34843556 }
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);
34863561}
34873562
34883563fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -3498,8 +3573,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
34983573
34993574 // load pointer onto the stack
35003575 if (ptr_ty.isSlice()) {
3501 const ptr_local = try self.load(ptr, Type.usize, 0);
3502 try self.addLabel(.local_get, ptr_local.local);
3576 _ = try self.load(ptr, Type.usize, 0);
35033577 } else {
35043578 try self.lowerToStack(ptr);
35053579 }
......@@ -3510,7 +3584,7 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
35103584 try self.addTag(.i32_mul);
35113585 try self.addTag(.i32_add);
35123586
3513 const result = try self.allocLocal(Type.initTag(.i32));
3587 const result = try self.allocLocal(Type.i32);
35143588 try self.addLabel(.local_set, result.local);
35153589 return result;
35163590}
......@@ -3598,7 +3672,7 @@ fn memset(self: *Self, ptr: WValue, len: WValue, value: WValue) InnerError!void
35983672 else => {
35993673 // TODO: We should probably lower this to a call to compiler_rt
36003674 // But for now, we implement it manually
3601 const offset = try self.allocLocal(Type.usize); // local for counter
3675 const offset = try self.ensureAllocLocal(Type.usize); // local for counter
36023676 // outer block to jump to when loop is done
36033677 try self.startBlock(.block, wasm.block_empty);
36043678 try self.startBlock(.loop, wasm.block_empty);
......@@ -3655,13 +3729,16 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
36553729 try self.addTag(.i32_mul);
36563730 try self.addTag(.i32_add);
36573731
3658 const result = try self.allocLocal(Type.usize);
3732 var result = try self.allocLocal(Type.usize);
36593733 try self.addLabel(.local_set, result.local);
36603734
36613735 if (isByRef(elem_ty, self.target)) {
36623736 return result;
36633737 }
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);
36653742}
36663743
36673744fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -3684,11 +3761,8 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
36843761 .signedness = if (dest_ty.isSignedInt()) .signed else .unsigned,
36853762 });
36863763 try self.addTag(Mir.Inst.Tag.fromOpcode(op));
3687
3688 const result = try self.allocLocal(dest_ty);
3689 try self.addLabel(.local_set, result.local);
3690
3691 return self.wrapOperand(result, dest_ty);
3764 const wrapped = try self.wrapOperand(.{ .stack = {} }, dest_ty);
3765 return wrapped.toLocal(self, dest_ty);
36923766}
36933767
36943768fn 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
38863960 const payload_ty = operand_ty.optionalChild(&buf);
38873961 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
38923963 // We store the final result in here that will be validated
38933964 // 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
38963968 try self.startBlock(.block, wasm.block_empty);
3897 try self.emitWValue(lhs_is_null);
3898 try self.emitWValue(rhs_is_null);
3969 _ = try self.isNull(lhs, operand_ty, .i32_eq);
3970 _ = try self.isNull(rhs, operand_ty, .i32_eq);
38993971 try self.addTag(.i32_ne); // inverse so we can exit early
39003972 try self.addLabel(.br_if, 0);
39013973
3902 const lhs_pl = try self.load(lhs, payload_ty, offset);
3903 const rhs_pl = try self.load(rhs, payload_ty, offset);
3904
3905 try self.emitWValue(lhs_pl);
3906 try self.emitWValue(rhs_pl);
3974 _ = try self.load(lhs, payload_ty, offset);
3975 _ = try self.load(rhs, payload_ty, offset);
39073976 const opcode = buildOpcode(.{ .op = .ne, .valtype1 = typeToValtype(payload_ty, self.target) });
39083977 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
39093978 try self.addLabel(.br_if, 0);
......@@ -3915,26 +3984,29 @@ fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std
39153984 try self.emitWValue(result);
39163985 try self.addImm32(0);
39173986 try self.addTag(if (op == .eq) .i32_ne else .i32_eq);
3918 try self.addLabel(.local_set, result.local);
3919 return result;
3987 return WValue{ .stack = {} };
39203988}
39213989
39223990/// 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.
39233992/// TODO: Lower this to compiler_rt call when bitsize > 128
39243993fn cmpBigInt(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {
39253994 assert(operand_ty.abiSize(self.target) >= 16);
3995 assert(!(lhs != .stack and rhs == .stack));
39263996 if (operand_ty.intInfo(self.target).bits > 128) {
39273997 return self.fail("TODO: Support cmpBigInt for integer bitsize: '{d}'", .{operand_ty.intInfo(self.target).bits});
39283998 }
39293999
3930 const lhs_high_bit = try self.load(lhs, Type.u64, 0);
3931 const lhs_low_bit = try self.load(lhs, Type.u64, 8);
3932 const rhs_high_bit = try self.load(rhs, Type.u64, 0);
3933 const rhs_low_bit = try self.load(rhs, Type.u64, 8);
4000 var lhs_high_bit = try (try self.load(lhs, Type.u64, 0)).toLocal(self, Type.u64);
4001 defer lhs_high_bit.free(self);
4002 var rhs_high_bit = try (try self.load(rhs, Type.u64, 0)).toLocal(self, Type.u64);
4003 defer rhs_high_bit.free(self);
39344004
39354005 switch (op) {
39364006 .eq, .neq => {
39374007 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);
39384010 const xor_low = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, .xor);
39394011 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
39464018 },
39474019 else => {
39484020 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);
3950 const high_bit_cmp = try self.cmp(lhs_high_bit, rhs_high_bit, ty, op);
3951 const low_bit_cmp = try self.cmp(lhs_low_bit, rhs_low_bit, ty, op);
3952
3953 try self.emitWValue(low_bit_cmp);
3954 try self.emitWValue(high_bit_cmp);
3955 try self.emitWValue(high_bit_eql);
4021 // leave those value on top of the stack for '.select'
4022 const lhs_low_bit = try self.load(lhs, Type.u64, 8);
4023 const rhs_low_bit = try self.load(rhs, Type.u64, 8);
4024 _ = try self.cmp(lhs_low_bit, rhs_low_bit, ty, op);
4025 _ = try self.cmp(lhs_high_bit, rhs_high_bit, ty, op);
4026 _ = try self.cmp(lhs_high_bit, rhs_high_bit, ty, .eq);
39564027 try self.addTag(.select);
39574028 },
39584029 }
39594030
3960 const result = try self.allocLocal(Type.initTag(.i32));
3961 try self.addLabel(.local_set, result.local);
3962 return result;
4031 return WValue{ .stack = {} };
39634032}
39644033
39654034fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -3999,7 +4068,8 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
39994068 const offset = if (layout.tag_align < layout.payload_align) blk: {
40004069 break :blk @intCast(u32, layout.payload_size);
40014070 } 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);
40034073}
40044074
40054075fn airFpext(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -4009,19 +4079,20 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
40094079 const dest_ty = self.air.typeOfIndex(inst);
40104080 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);
40134084}
40144085
4086/// Extends a float from a given `Type` to a larger wanted `Type`
4087/// NOTE: Leaves the result on the stack
40154088fn fpext(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WValue {
40164089 const given_bits = given.floatBits(self.target);
40174090 const wanted_bits = wanted.floatBits(self.target);
40184091
40194092 if (wanted_bits == 64 and given_bits == 32) {
4020 const result = try self.allocLocal(wanted);
40214093 try self.emitWValue(operand);
40224094 try self.addTag(.f64_promote_f32);
4023 try self.addLabel(.local_set, result.local);
4024 return result;
4095 return WValue{ .stack = {} };
40254096 } else if (given_bits == 16) {
40264097 // call __extendhfsf2(f16) f32
40274098 const f32_result = try self.callIntrinsic(
......@@ -4035,11 +4106,8 @@ fn fpext(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WVa
40354106 return f32_result;
40364107 }
40374108 if (wanted_bits == 64) {
4038 const result = try self.allocLocal(wanted);
4039 try self.emitWValue(f32_result);
40404109 try self.addTag(.f64_promote_f32);
4041 try self.addLabel(.local_set, result.local);
4042 return result;
4110 return WValue{ .stack = {} };
40434111 }
40444112 return self.fail("TODO: Implement 'fpext' for floats with bitsize: {d}", .{wanted_bits});
40454113 } else {
......@@ -4054,26 +4122,25 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
40544122 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
40554123 const dest_ty = self.air.typeOfIndex(inst);
40564124 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);
40584127}
40594128
4129/// Truncates a float from a given `Type` to its wanted `Type`
4130/// NOTE: The result value remains on the stack
40604131fn fptrunc(self: *Self, operand: WValue, given: Type, wanted: Type) InnerError!WValue {
40614132 const given_bits = given.floatBits(self.target);
40624133 const wanted_bits = wanted.floatBits(self.target);
40634134
40644135 if (wanted_bits == 32 and given_bits == 64) {
4065 const result = try self.allocLocal(wanted);
40664136 try self.emitWValue(operand);
40674137 try self.addTag(.f32_demote_f64);
4068 try self.addLabel(.local_set, result.local);
4069 return result;
4138 return WValue{ .stack = {} };
40704139 } else if (wanted_bits == 16) {
40714140 const op: WValue = if (given_bits == 64) blk: {
4072 const tmp = try self.allocLocal(Type.f32);
40734141 try self.emitWValue(operand);
40744142 try self.addTag(.f32_demote_f64);
4075 try self.addLabel(.local_set, tmp.local);
4076 break :blk tmp;
4143 break :blk WValue{ .stack = {} };
40774144 } else operand;
40784145
40794146 // call __truncsfhf2(f32) f16
......@@ -4158,12 +4225,9 @@ fn airPopcount(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
41584225
41594226 switch (wasm_bits) {
41604227 128 => {
4161 const msb = try self.load(operand, Type.u64, 0);
4162 const lsb = try self.load(operand, Type.u64, 8);
4163
4164 try self.emitWValue(msb);
4228 _ = try self.load(operand, Type.u64, 0);
41654229 try self.addTag(.i64_popcnt);
4166 try self.emitWValue(lsb);
4230 _ = try self.load(operand, Type.u64, 8);
41674231 try self.addTag(.i64_popcnt);
41684232 try self.addTag(.i64_add);
41694233 try self.addTag(.i32_wrap_i64);
......@@ -4267,24 +4331,26 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!W
42674331
42684332 // for signed integers, we first apply signed shifts by the difference in bits
42694333 // 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: {
4271 break :blk try self.signAbsValue(lhs_op, lhs_ty);
4334 var lhs = if (wasm_bits != int_info.bits and is_signed) blk: {
4335 break :blk try (try self.signAbsValue(lhs_op, lhs_ty)).toLocal(self, lhs_ty);
42724336 } else lhs_op;
4273 const rhs = if (wasm_bits != int_info.bits and is_signed) blk: {
4274 break :blk try self.signAbsValue(rhs_op, lhs_ty);
4337 var rhs = if (wasm_bits != int_info.bits and is_signed) blk: {
4338 break :blk try (try self.signAbsValue(rhs_op, lhs_ty)).toLocal(self, lhs_ty);
42754339 } else rhs_op;
42764340
4277 const bin_op = try self.binOp(lhs, rhs, lhs_ty, op);
4278 const result = if (wasm_bits != int_info.bits) blk: {
4279 break :blk try self.wrapOperand(bin_op, lhs_ty);
4341 var bin_op = try (try self.binOp(lhs, rhs, lhs_ty, op)).toLocal(self, lhs_ty);
4342 defer bin_op.free(self);
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);
42804345 } else bin_op;
4346 defer result.free(self); // no-op when wasm_bits == int_info.bits
42814347
42824348 const cmp_op: std.math.CompareOperator = if (op == .sub) .gt else .lt;
42834349 const overflow_bit: WValue = if (is_signed) blk: {
42844350 if (wasm_bits == int_info.bits) {
42854351 const cmp_zero = try self.cmp(rhs, zero, lhs_ty, cmp_op);
42864352 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 32bit
4353 break :blk try self.binOp(cmp_zero, lt, Type.u32, .xor);
42884354 }
42894355 const abs = try self.signAbsValue(bin_op, lhs_ty);
42904356 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
42924358 try self.cmp(bin_op, lhs, lhs_ty, cmp_op)
42934359 else
42944360 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
42964364 const result_ptr = try self.allocStack(self.air.typeOfIndex(inst));
42974365 try self.store(result_ptr, result, lhs_ty, 0);
42984366 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
43014378 return result_ptr;
43024379}
......@@ -4309,52 +4386,58 @@ fn airAddSubWithOverflowBigInt(self: *Self, lhs: WValue, rhs: WValue, ty: Type,
43094386 return self.fail("TODO: Implement @{{add/sub}}WithOverflow for integer bitsize '{d}'", .{int_info.bits});
43104387 }
43114388
4312 const lhs_high_bit = try self.load(lhs, Type.u64, 0);
4313 const lhs_low_bit = try self.load(lhs, Type.u64, 8);
4314 const rhs_high_bit = try self.load(rhs, Type.u64, 0);
4315 const rhs_low_bit = try self.load(rhs, Type.u64, 8);
4389 var lhs_high_bit = try (try self.load(lhs, Type.u64, 0)).toLocal(self, Type.u64);
4390 defer lhs_high_bit.free(self);
4391 var lhs_low_bit = try (try self.load(lhs, Type.u64, 8)).toLocal(self, Type.u64);
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);
4318 const high_op_res = try self.binOp(lhs_high_bit, rhs_high_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);
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: {
4321 break :blk try self.cmp(high_op_res, lhs_high_bit, Type.u64, .lt);
4403 var lt = if (op == .add) blk: {
4404 break :blk try (try self.cmp(high_op_res, lhs_high_bit, Type.u64, .lt)).toLocal(self, Type.u32);
43224405 } 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);
43244407 } else unreachable;
4325 const tmp = try self.intcast(lt, Type.u32, Type.u64);
4326 const tmp_op = try self.binOp(low_op_res, tmp, Type.u64, op);
4408 defer lt.free(self);
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
43284414 const overflow_bit = if (is_signed) blk: {
4329 const xor_op = try self.binOp(lhs_low_bit, tmp_op, Type.u64, .xor);
43304415 const xor_low = try self.binOp(lhs_low_bit, rhs_low_bit, Type.u64, .xor);
43314416 const to_wrap = if (op == .add) wrap: {
43324417 break :wrap try self.binOp(xor_low, .{ .imm64 = ~@as(u64, 0) }, Type.u64, .xor);
43334418 } else xor_low;
4419 const xor_op = try self.binOp(lhs_low_bit, tmp_op, Type.u64, .xor);
43344420 const wrap = try self.binOp(to_wrap, xor_op, Type.u64, .@"and");
43354421 break :blk try self.cmp(wrap, .{ .imm64 = 0 }, Type.i64, .lt); // i64 because signed
43364422 } 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
43404423 const first_arg = if (op == .sub) arg: {
43414424 break :arg try self.cmp(high_op_res, lhs_high_bit, Type.u64, .gt);
43424425 } else lt;
43434426
43444427 try self.emitWValue(first_arg);
4345 try self.emitWValue(op_eq);
4346 try self.emitWValue(eq);
4428 _ = try self.cmp(tmp_op, lhs_low_bit, Type.u64, if (op == .add) .lt else .gt);
4429 _ = try self.cmp(tmp_op, lhs_low_bit, Type.u64, .eq);
43474430 try self.addTag(.select);
43484431
4349 const overflow_bit = try self.allocLocal(Type.initTag(.u1));
4350 try self.addLabel(.local_set, overflow_bit.local);
4351 break :blk overflow_bit;
4432 break :blk WValue{ .stack = {} };
43524433 };
4434 var overflow_local = try overflow_bit.toLocal(self, Type.initTag(.u1));
4435 defer overflow_local.free(self);
43534436
43544437 const result_ptr = try self.allocStack(result_ty);
43554438 try self.store(result_ptr, high_op_res, Type.u64, 0);
43564439 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
43594442 return result_ptr;
43604443}
......@@ -4376,24 +4459,31 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
43764459 return self.fail("TODO: Implement shl_with_overflow for integer bitsize: {d}", .{int_info.bits});
43774460 };
43784461
4379 const shl = try self.binOp(lhs, rhs, lhs_ty, .shl);
4380 const result = if (wasm_bits != int_info.bits) blk: {
4381 break :blk try self.wrapOperand(shl, lhs_ty);
4462 var shl = try (try self.binOp(lhs, rhs, lhs_ty, .shl)).toLocal(self, lhs_ty);
4463 defer shl.free(self);
4464 var result = if (wasm_bits != int_info.bits) blk: {
4465 break :blk try (try self.wrapOperand(shl, lhs_ty)).toLocal(self, lhs_ty);
43824466 } 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
43844469 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);
43854472 const abs = try self.signAbsValue(shl, lhs_ty);
43864473 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);
43884475 } else blk: {
4476 try self.emitWValue(lhs);
43894477 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);
43914479 };
4480 var overflow_local = try overflow_bit.toLocal(self, Type.initTag(.u1));
4481 defer overflow_local.free(self);
43924482
43934483 const result_ptr = try self.allocStack(self.air.typeOfIndex(inst));
43944484 try self.store(result_ptr, result, lhs_ty, 0);
43954485 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
43984488 return result_ptr;
43994489}
......@@ -4411,7 +4501,9 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
44114501
44124502 // We store the bit if it's overflowed or not in this. As it's zero-initialized
44134503 // 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
44154507 const int_info = lhs_ty.intInfo(self.target);
44164508 const wasm_bits = toWasmBits(int_info.bits) orelse {
44174509 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 {
44324524 const new_ty = if (int_info.signedness == .signed) Type.i64 else Type.u64;
44334525 const lhs_upcast = try self.intcast(lhs, lhs_ty, new_ty);
44344526 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);
44364528 if (int_info.signedness == .unsigned) {
44374529 const shr = try self.binOp(bin_op, .{ .imm64 = int_info.bits }, new_ty, .shr);
44384530 const wrap = try self.intcast(shr, new_ty, lhs_ty);
4439 const cmp_res = try self.cmp(wrap, zero, lhs_ty, .neq);
4440 try self.emitWValue(cmp_res);
4531 _ = try self.cmp(wrap, zero, lhs_ty, .neq);
44414532 try self.addLabel(.local_set, overflow_bit.local);
44424533 break :blk try self.intcast(bin_op, new_ty, lhs_ty);
44434534 } else {
4444 const down_cast = try self.intcast(bin_op, new_ty, lhs_ty);
4445 const shr = try self.binOp(down_cast, .{ .imm32 = int_info.bits - 1 }, lhs_ty, .shr);
4535 const down_cast = try (try self.intcast(bin_op, new_ty, lhs_ty)).toLocal(self, lhs_ty);
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
44474539 const shr_res = try self.binOp(bin_op, .{ .imm64 = int_info.bits }, new_ty, .shr);
44484540 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);
4450 try self.emitWValue(cmp_res);
4541 _ = try self.cmp(down_shr_res, shr, lhs_ty, .neq);
44514542 try self.addLabel(.local_set, overflow_bit.local);
44524543 break :blk down_cast;
44534544 }
44544545 } else if (int_info.signedness == .signed) blk: {
44554546 const lhs_abs = try self.signAbsValue(lhs, lhs_ty);
44564547 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);
44584549 const mul_abs = try self.signAbsValue(bin_op, lhs_ty);
4459 const cmp_op = try self.cmp(mul_abs, bin_op, lhs_ty, .neq);
4460 try self.emitWValue(cmp_op);
4550 _ = try self.cmp(mul_abs, bin_op, lhs_ty, .neq);
44614551 try self.addLabel(.local_set, overflow_bit.local);
44624552 break :blk try self.wrapOperand(bin_op, lhs_ty);
44634553 } 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);
44654556 const shift_imm = if (wasm_bits == 32)
44664557 WValue{ .imm32 = int_info.bits }
44674558 else
44684559 WValue{ .imm64 = int_info.bits };
44694560 const shr = try self.binOp(bin_op, shift_imm, lhs_ty, .shr);
4470 const cmp_op = try self.cmp(shr, zero, lhs_ty, .neq);
4471 try self.emitWValue(cmp_op);
4561 _ = try self.cmp(shr, zero, lhs_ty, .neq);
44724562 try self.addLabel(.local_set, overflow_bit.local);
44734563 break :blk try self.wrapOperand(bin_op, lhs_ty);
44744564 };
4565 var bin_op_local = try bin_op.toLocal(self, lhs_ty);
4566 defer bin_op_local.free(self);
44754567
44764568 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);
44784570 const offset = @intCast(u32, lhs_ty.abiSize(self.target));
44794571 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
44964588 const lhs = try self.resolveInst(bin_op.lhs);
44974589 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
45014591 // operands to select from
45024592 try self.lowerToStack(lhs);
45034593 try self.lowerToStack(rhs);
4504 try self.emitWValue(cmp_result);
4594 _ = try self.cmp(lhs, rhs, ty, if (op == .max) .gt else .lt);
45054595
45064596 // based on the result from comparison, return operand 0 or 1.
45074597 try self.addTag(.select);
......@@ -4527,21 +4617,21 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
45274617 const rhs = try self.resolveInst(bin_op.rhs);
45284618
45294619 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);
45324620 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);
45334623 // call to compiler-rt `fn fmaf(f32, f32, f32) f32`
4534 const result = try self.callIntrinsic(
4624 var result = try self.callIntrinsic(
45354625 "fmaf",
45364626 &.{ Type.f32, Type.f32, Type.f32 },
45374627 Type.f32,
45384628 &.{ rhs_ext, lhs_ext, addend_ext },
45394629 );
4540 return try self.fptrunc(result, Type.f32, ty);
4630 return try (try self.fptrunc(result, Type.f32, ty)).toLocal(self, ty);
45414631 }
45424632
45434633 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);
45454635}
45464636
45474637fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -4570,17 +4660,16 @@ fn airClz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
45704660 try self.addTag(.i32_wrap_i64);
45714661 },
45724662 128 => {
4573 const msb = try self.load(operand, Type.u64, 0);
4574 const lsb = try self.load(operand, Type.u64, 8);
4575 const neq = try self.cmp(lsb, .{ .imm64 = 0 }, Type.u64, .neq);
4663 var lsb = try (try self.load(operand, Type.u64, 8)).toLocal(self, Type.u64);
4664 defer lsb.free(self);
45764665
45774666 try self.emitWValue(lsb);
45784667 try self.addTag(.i64_clz);
4579 try self.emitWValue(msb);
4668 _ = try self.load(operand, Type.u64, 0);
45804669 try self.addTag(.i64_clz);
45814670 try self.emitWValue(.{ .imm64 = 64 });
45824671 try self.addTag(.i64_add);
4583 try self.emitWValue(neq);
4672 _ = try self.cmp(lsb, .{ .imm64 = 0 }, Type.u64, .neq);
45844673 try self.addTag(.select);
45854674 try self.addTag(.i32_wrap_i64);
45864675 },
......@@ -4617,28 +4706,27 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
46174706 32 => {
46184707 if (wasm_bits != int_info.bits) {
46194708 const val: u32 = @as(u32, 1) << @intCast(u5, int_info.bits);
4620 const bin_op = try self.binOp(operand, .{ .imm32 = val }, ty, .@"or");
4621 try self.emitWValue(bin_op);
4709 // leave value on the stack
4710 _ = try self.binOp(operand, .{ .imm32 = val }, ty, .@"or");
46224711 } else try self.emitWValue(operand);
46234712 try self.addTag(.i32_ctz);
46244713 },
46254714 64 => {
46264715 if (wasm_bits != int_info.bits) {
46274716 const val: u64 = @as(u64, 1) << @intCast(u6, int_info.bits);
4628 const bin_op = try self.binOp(operand, .{ .imm64 = val }, ty, .@"or");
4629 try self.emitWValue(bin_op);
4717 // leave value on the stack
4718 _ = try self.binOp(operand, .{ .imm64 = val }, ty, .@"or");
46304719 } else try self.emitWValue(operand);
46314720 try self.addTag(.i64_ctz);
46324721 try self.addTag(.i32_wrap_i64);
46334722 },
46344723 128 => {
4635 const msb = try self.load(operand, Type.u64, 0);
4636 const lsb = try self.load(operand, Type.u64, 8);
4637 const neq = try self.cmp(msb, .{ .imm64 = 0 }, Type.u64, .neq);
4724 var msb = try (try self.load(operand, Type.u64, 0)).toLocal(self, Type.u64);
4725 defer msb.free(self);
46384726
46394727 try self.emitWValue(msb);
46404728 try self.addTag(.i64_ctz);
4641 try self.emitWValue(lsb);
4729 _ = try self.load(operand, Type.u64, 8);
46424730 if (wasm_bits != int_info.bits) {
46434731 try self.addImm64(@as(u64, 1) << @intCast(u6, int_info.bits - 64));
46444732 try self.addTag(.i64_or);
......@@ -4650,7 +4738,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
46504738 } else {
46514739 try self.addTag(.i64_add);
46524740 }
4653 try self.emitWValue(neq);
4741 _ = try self.cmp(msb, .{ .imm64 = 0 }, Type.u64, .neq);
46544742 try self.addTag(.select);
46554743 try self.addTag(.i32_wrap_i64);
46564744 },
......@@ -4776,7 +4864,8 @@ fn lowerTry(
47764864 if (isByRef(pl_ty, self.target)) {
47774865 return buildPointerOffset(self, err_union, pl_offset, .new);
47784866 }
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);
47804869}
47814870
47824871fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -4806,11 +4895,11 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
48064895 const res = if (int_info.signedness == .signed) blk: {
48074896 break :blk try self.wrapOperand(shr_res, Type.u8);
48084897 } else shr_res;
4809 return self.binOp(lhs, res, ty, .@"or");
4898 return (try self.binOp(lhs, res, ty, .@"or")).toLocal(self, ty);
48104899 },
48114900 24 => {
4812 const msb = try self.wrapOperand(operand, Type.u16);
4813 const lsb = try self.wrapBinOp(operand, .{ .imm32 = 16 }, Type.u8, .shr);
4901 var msb = try (try self.wrapOperand(operand, Type.u16)).toLocal(self, Type.u16);
4902 defer msb.free(self);
48144903
48154904 const shl_res = try self.binOp(msb, .{ .imm32 = 8 }, Type.u16, .shl);
48164905 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 {
48244913 const rhs_wrap = try self.wrapOperand(msb, Type.u8);
48254914 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);
48274917 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);
48294919 },
48304920 32 => {
48314921 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);
48334924 const shr_tmp = try self.binOp(operand, .{ .imm32 = 8 }, ty, .shr);
4834 const rhs = try self.binOp(shr_tmp, .{ .imm32 = 0xFF00FF }, ty, .@"and");
4835 const tmp_or = try self.binOp(lhs, rhs, ty, .@"or");
4925 var rhs = try (try self.binOp(shr_tmp, .{ .imm32 = 0xFF00FF }, ty, .@"and")).toLocal(self, ty);
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
48374930 const shl = try self.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shl);
48384931 const shr = try self.binOp(tmp_or, .{ .imm32 = 16 }, ty, .shr);
48394932 const res = if (int_info.signedness == .signed) blk: {
48404933 break :blk try self.wrapOperand(shr, Type.u16);
48414934 } else shr;
4842 return self.binOp(shl, res, ty, .@"or");
4935 return (try self.binOp(shl, res, ty, .@"or")).toLocal(self, ty);
48434936 },
48444937 else => return self.fail("TODO: @byteSwap for integers with bitsize {d}", .{int_info.bits}),
48454938 }
......@@ -4856,7 +4949,7 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
48564949 if (ty.isSignedInt()) {
48574950 return self.divSigned(lhs, rhs, ty);
48584951 }
4859 return self.binOp(lhs, rhs, ty, .div);
4952 return (try self.binOp(lhs, rhs, ty, .div)).toLocal(self, ty);
48604953}
48614954
48624955fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -4868,33 +4961,31 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
48684961 const rhs = try self.resolveInst(bin_op.rhs);
48694962
48704963 if (ty.isUnsignedInt()) {
4871 return self.binOp(lhs, rhs, ty, .div);
4964 return (try self.binOp(lhs, rhs, ty, .div)).toLocal(self, ty);
48724965 } else if (ty.isSignedInt()) {
48734966 const int_bits = ty.intInfo(self.target).bits;
48744967 const wasm_bits = toWasmBits(int_bits) orelse {
48754968 return self.fail("TODO: `@divFloor` for signed integers larger than '{d}' bits", .{int_bits});
48764969 };
48774970 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);
48794972 } else lhs;
48804973 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);
48824975 } 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
48874977 const zero = switch (wasm_bits) {
48884978 32 => WValue{ .imm32 = 0 },
48894979 64 => WValue{ .imm64 = 0 },
48904980 else => unreachable,
48914981 };
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);
4896 try self.emitWValue(lhs_less_than_zero);
4897 try self.emitWValue(rhs_less_than_zero);
4983 const div_result = try self.allocLocal(ty);
4984 // leave on stack
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);
48984989 switch (wasm_bits) {
48994990 32 => {
49004991 try self.addTag(.i32_xor);
......@@ -4907,7 +4998,8 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
49074998 else => unreachable,
49084999 }
49095000 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);
49115003 try self.addTag(.select);
49125004 } else {
49135005 const float_bits = ty.floatBits(self.target);
......@@ -4939,9 +5031,7 @@ fn airDivFloor(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
49395031 }
49405032
49415033 if (is_f16) {
4942 // we can re-use temporary local
4943 try self.addLabel(.local_set, lhs_operand.local);
4944 return self.fptrunc(lhs_operand, Type.f32, Type.f16);
5034 _ = try self.fptrunc(.{ .stack = {} }, Type.f32, Type.f16);
49455035 }
49465036 }
49475037
......@@ -4961,10 +5051,9 @@ fn divSigned(self: *Self, lhs: WValue, rhs: WValue, ty: Type) InnerError!WValue
49615051 }
49625052
49635053 if (wasm_bits != int_bits) {
4964 const lhs_abs = try self.signAbsValue(lhs, ty);
4965 const rhs_abs = try self.signAbsValue(rhs, ty);
4966 try self.emitWValue(lhs_abs);
4967 try self.emitWValue(rhs_abs);
5054 // Leave both values on the stack
5055 _ = try self.signAbsValue(lhs, ty);
5056 _ = try self.signAbsValue(rhs, ty);
49685057 } else {
49695058 try self.emitWValue(lhs);
49705059 try self.emitWValue(rhs);
......@@ -4976,6 +5065,8 @@ fn divSigned(self: *Self, lhs: WValue, rhs: WValue, ty: Type) InnerError!WValue
49765065 return result;
49775066}
49785067
5068/// Retrieves the absolute value of a signed integer
5069/// NOTE: Leaves the result value on the stack.
49795070fn signAbsValue(self: *Self, operand: WValue, ty: Type) InnerError!WValue {
49805071 const int_bits = ty.intInfo(self.target).bits;
49815072 const wasm_bits = toWasmBits(int_bits) orelse {
......@@ -5004,9 +5095,8 @@ fn signAbsValue(self: *Self, operand: WValue, ty: Type) InnerError!WValue {
50045095 },
50055096 else => unreachable,
50065097 }
5007 const result = try self.allocLocal(ty);
5008 try self.addLabel(.local_set, result.local);
5009 return result;
5098
5099 return WValue{ .stack = {} };
50105100}
50115101
50125102fn 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
50335123 try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
50345124
50355125 if (is_f16) {
5036 // re-use temporary to save locals
5037 try self.addLabel(.local_set, op_to_lower.local);
5038 return self.fptrunc(op_to_lower, Type.f32, Type.f16);
5126 _ = try self.fptrunc(.{ .stack = {} }, Type.f32, Type.f16);
50395127 }
50405128
50415129 const result = try self.allocLocal(ty);
......@@ -5064,7 +5152,8 @@ fn airSatBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
50645152 }
50655153
50665154 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);
50685157 if (wasm_bits != int_info.bits and op == .add) {
50695158 const val: u64 = @intCast(u64, (@as(u65, 1) << @intCast(u7, int_info.bits)) - 1);
50705159 const imm_val = switch (wasm_bits) {
......@@ -5073,19 +5162,17 @@ fn airSatBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
50735162 else => unreachable,
50745163 };
50755164
5076 const cmp_result = try self.cmp(bin_result, imm_val, ty, .lt);
50775165 try self.emitWValue(bin_result);
50785166 try self.emitWValue(imm_val);
5079 try self.emitWValue(cmp_result);
5167 _ = try self.cmp(bin_result, imm_val, ty, .lt);
50805168 } else {
5081 const cmp_result = try self.cmp(bin_result, lhs, ty, if (op == .add) .lt else .gt);
50825169 switch (wasm_bits) {
50835170 32 => try self.addImm32(if (op == .add) @as(i32, -1) else 0),
50845171 64 => try self.addImm64(if (op == .add) @bitCast(u64, @as(i64, -1)) else 0),
50855172 else => unreachable,
50865173 }
50875174 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);
50895176 }
50905177
50915178 try self.addTag(.select);
......@@ -5099,8 +5186,12 @@ fn signedSat(self: *Self, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op
50995186 const wasm_bits = toWasmBits(int_info.bits).?;
51005187 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;
5103 const rhs = if (!is_wasm_bits) try self.signAbsValue(rhs_operand, ty) else rhs_operand;
5189 var lhs = if (!is_wasm_bits) lhs: {
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
51055196 const max_val: u64 = @intCast(u64, (@as(u65, 1) << @intCast(u7, int_info.bits - 1)) - 1);
51065197 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
51155206 else => unreachable,
51165207 };
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);
51195210 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
51215214 try self.emitWValue(bin_result);
51225215 try self.emitWValue(max_wvalue);
5123 try self.emitWValue(cmp_result_lt);
5216 _ = try self.cmp(bin_result, max_wvalue, ty, .lt);
51245217 try self.addTag(.select);
51255218 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);
51285220 try self.emitWValue(bin_result);
51295221 try self.emitWValue(min_wvalue);
5130 try self.emitWValue(cmp_result_gt);
5222 _ = try self.cmp(bin_result, min_wvalue, ty, .gt);
51315223 try self.addTag(.select);
51325224 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);
51345226 } else {
51355227 const zero = switch (wasm_bits) {
51365228 32 => WValue{ .imm32 = 0 },
51375229 64 => WValue{ .imm64 = 0 },
51385230 else => unreachable,
51395231 };
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);
51445232 try self.emitWValue(max_wvalue);
51455233 try self.emitWValue(min_wvalue);
5146 try self.emitWValue(cmp_bin_zero_result);
5234 _ = try self.cmp(bin_result, zero, ty, .lt);
51475235 try self.addTag(.select);
51485236 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.
51505241 try self.addTag(.select);
51515242 try self.addLabel(.local_set, bin_result.local); // re-use local
51525243 return bin_result;
......@@ -5170,9 +5261,10 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
51705261 const result = try self.allocLocal(ty);
51715262
51725263 if (wasm_bits == int_info.bits) {
5173 const shl = try self.binOp(lhs, rhs, ty, .shl);
5174 const shr = try self.binOp(shl, rhs, ty, .shr);
5175 const cmp_result = try self.cmp(lhs, shr, ty, .neq);
5264 var shl = try (try self.binOp(lhs, rhs, ty, .shl)).toLocal(self, ty);
5265 defer shl.free(self);
5266 var shr = try (try self.binOp(shl, rhs, ty, .shr)).toLocal(self, ty);
5267 defer shr.free(self);
51765268
51775269 switch (wasm_bits) {
51785270 32 => blk: {
......@@ -5180,10 +5272,9 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
51805272 try self.addImm32(-1);
51815273 break :blk;
51825274 }
5183 const less_than_zero = try self.cmp(lhs, .{ .imm32 = 0 }, ty, .lt);
51845275 try self.addImm32(std.math.minInt(i32));
51855276 try self.addImm32(std.math.maxInt(i32));
5186 try self.emitWValue(less_than_zero);
5277 _ = try self.cmp(lhs, .{ .imm32 = 0 }, ty, .lt);
51875278 try self.addTag(.select);
51885279 },
51895280 64 => blk: {
......@@ -5191,16 +5282,15 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
51915282 try self.addImm64(@bitCast(u64, @as(i64, -1)));
51925283 break :blk;
51935284 }
5194 const less_than_zero = try self.cmp(lhs, .{ .imm64 = 0 }, ty, .lt);
51955285 try self.addImm64(@bitCast(u64, @as(i64, std.math.minInt(i64))));
51965286 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);
51985288 try self.addTag(.select);
51995289 },
52005290 else => unreachable,
52015291 }
52025292 try self.emitWValue(shl);
5203 try self.emitWValue(cmp_result);
5293 _ = try self.cmp(lhs, shr, ty, .neq);
52045294 try self.addTag(.select);
52055295 try self.addLabel(.local_set, result.local);
52065296 return result;
......@@ -5212,10 +5302,12 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
52125302 else => unreachable,
52135303 };
52145304
5215 const shl_res = try self.binOp(lhs, shift_value, ty, .shl);
5216 const shl = try self.binOp(shl_res, rhs, ty, .shl);
5217 const shr = try self.binOp(shl, rhs, ty, .shr);
5218 const cmp_result = try self.cmp(shl_res, shr, ty, .neq);
5305 var shl_res = try (try self.binOp(lhs, shift_value, ty, .shl)).toLocal(self, ty);
5306 defer shl_res.free(self);
5307 var shl = try (try self.binOp(shl_res, rhs, ty, .shl)).toLocal(self, ty);
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
52205312 switch (wasm_bits) {
52215313 32 => blk: {
......@@ -5224,10 +5316,9 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
52245316 break :blk;
52255317 }
52265318
5227 const less_than_zero = try self.cmp(shl_res, .{ .imm32 = 0 }, ty, .lt);
52285319 try self.addImm32(std.math.minInt(i32));
52295320 try self.addImm32(std.math.maxInt(i32));
5230 try self.emitWValue(less_than_zero);
5321 _ = try self.cmp(shl_res, .{ .imm32 = 0 }, ty, .lt);
52315322 try self.addTag(.select);
52325323 },
52335324 64 => blk: {
......@@ -5236,29 +5327,31 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
52365327 break :blk;
52375328 }
52385329
5239 const less_than_zero = try self.cmp(shl_res, .{ .imm64 = 0 }, ty, .lt);
52405330 try self.addImm64(@bitCast(u64, @as(i64, std.math.minInt(i64))));
52415331 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);
52435333 try self.addTag(.select);
52445334 },
52455335 else => unreachable,
52465336 }
52475337 try self.emitWValue(shl);
5248 try self.emitWValue(cmp_result);
5338 _ = try self.cmp(shl_res, shr, ty, .neq);
52495339 try self.addTag(.select);
52505340 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);
52525342 if (is_signed) {
5253 return self.wrapOperand(shift_result, ty);
5343 shift_result = try self.wrapOperand(shift_result, ty);
52545344 }
5255 return shift_result;
5345 return shift_result.toLocal(self, ty);
52565346 }
52575347}
52585348
52595349/// Calls a compiler-rt intrinsic by creating an undefined symbol,
52605350/// then lowering the arguments and calling the symbol as a function call.
52615351/// 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.
52625355fn callIntrinsic(
52635356 self: *Self,
52645357 name: []const u8,
......@@ -5288,6 +5381,7 @@ fn callIntrinsic(
52885381
52895382 // Lower all arguments to the stack before we call our function
52905383 for (args) |arg, arg_i| {
5384 assert(!(want_sret_param and arg == .stack));
52915385 assert(param_types[arg_i].hasRuntimeBitsIgnoreComptime());
52925386 try self.lowerArg(.C, param_types[arg_i], arg);
52935387 }
......@@ -5303,8 +5397,6 @@ fn callIntrinsic(
53035397 } else if (want_sret_param) {
53045398 return sret;
53055399 } else {
5306 const result_local = try self.allocLocal(return_type);
5307 try self.addLabel(.local_set, result_local.local);
5308 return result_local;
5400 return WValue{ .stack = {} };
53095401 }
53105402}
src/arch/wasm/Emit.zig+1-1
......@@ -343,7 +343,7 @@ fn emitMemArg(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) !void {
343343 try emit.code.append(@enumToInt(tag));
344344
345345 // 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);
347347 try leb128.writeULEB128(emit.code.writer(), encoded_alignment);
348348 try leb128.writeULEB128(emit.code.writer(), mem_arg.offset);
349349}
src/arch/x86_64/CodeGen.zig+53-4
......@@ -775,6 +775,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
775775 .float_to_int_optimized,
776776 => 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
778781 .wasm_memory_size => unreachable,
779782 .wasm_memory_grow => unreachable,
780783 // zig fmt: on
......@@ -3789,7 +3792,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
37893792
37903793 const ty = self.air.typeOfIndex(inst);
37913794 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);
37933796 const name_with_null = name.ptr[0 .. name.len + 1];
37943797
37953798 if (self.liveness.isUnused(inst))
......@@ -4368,6 +4371,7 @@ fn genVarDbgInfo(
43684371 .dwarf => |dw| {
43694372 const dbg_info = &dw.dbg_info;
43704373 try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable));
4374 const endian = self.target.cpu.arch.endian();
43714375
43724376 switch (mcv) {
43734377 .register => |reg| {
......@@ -4388,7 +4392,6 @@ fn genVarDbgInfo(
43884392 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
43894393 },
43904394 .memory, .got_load, .direct_load => {
4391 const endian = self.target.cpu.arch.endian();
43924395 const ptr_width = @intCast(u8, @divExact(self.target.cpu.arch.ptrBitWidth(), 8));
43934396 const is_ptr = switch (tag) {
43944397 .dbg_var_ptr => true,
......@@ -4423,7 +4426,53 @@ fn genVarDbgInfo(
44234426 else => {},
44244427 }
44254428 },
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 },
44264471 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 });
44274476 log.debug("TODO generate debug info for {}", .{mcv});
44284477 },
44294478 }
......@@ -6475,13 +6524,13 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
64756524 const extra = self.air.extraData(Air.Block, ty_pl.payload);
64766525 _ = ty_pl;
64776526 _ = extra;
6478 return self.fail("TODO implement airCmpxchg for {}", .{self.target.cpu.arch});
6527 return self.fail("TODO implement x86 airCmpxchg", .{});
64796528 // return self.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value });
64806529}
64816530
64826531fn airAtomicRmw(self: *Self, inst: Air.Inst.Index) !void {
64836532 _ = inst;
6484 return self.fail("TODO implement airCmpxchg for {}", .{self.target.cpu.arch});
6533 return self.fail("TODO implement x86 airAtomicRaw", .{});
64856534}
64866535
64876536fn 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"),
3333 .psl = false,
3434},
3535flagpd1("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},
3744.{
3845 .name = "MD",
3946 .syntax = .flag,
......@@ -53,7 +60,7 @@ flagpd1("M"),
5360.{
5461 .name = "MM",
5562 .syntax = .flag,
56 .zig_equivalent = .dep_file_mm,
63 .zig_equivalent = .dep_file_to_stdout,
5764 .pd1 = true,
5865 .pd2 = false,
5966 .psl = false,
......@@ -2033,7 +2040,7 @@ flagpsl("MT"),
20332040.{
20342041 .name = "user-dependencies",
20352042 .syntax = .flag,
2036 .zig_equivalent = .dep_file_mm,
2043 .zig_equivalent = .dep_file_to_stdout,
20372044 .pd1 = false,
20382045 .pd2 = true,
20392046 .psl = false,
......@@ -3390,7 +3397,14 @@ flagpd1("fno-stack-arrays"),
33903397 .psl = false,
33913398},
33923399flagpd1("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},
33943408flagpd1("fno-stack-size-section"),
33953409flagpd1("fno-standalone-debug"),
33963410flagpd1("fno-strength-reduce"),
......@@ -3689,9 +3703,30 @@ flagpd1("fstack-arrays"),
36893703 .psl = false,
36903704},
36913705flagpd1("fstack-clash-protection"),
3692flagpd1("fstack-protector"),
3693flagpd1("fstack-protector-all"),
3694flagpd1("fstack-protector-strong"),
3706.{
3707 .name = "fstack-protector",
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},
36953730flagpd1("fstack-size-section"),
36963731flagpd1("fstack-usage"),
36973732flagpd1("fstandalone-debug"),
......@@ -4978,7 +5013,14 @@ flagpd1("single_module"),
49785013},
49795014sepd1("split-dwarf-file"),
49805015sepd1("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},
49825024sepd1("stack-protector-buffer-size"),
49835025sepd1("stack-usage-file"),
49845026.{
src/codegen.zig+1-1
......@@ -607,7 +607,7 @@ pub fn generateSymbol(
607607
608608 const union_ty = typed_value.ty.cast(Type.Payload.Union).?.data;
609609 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).?;
611611 assert(union_ty.haveFieldTypes());
612612 const field_ty = union_ty.fields.values()[field_index].ty;
613613 if (!field_ty.hasRuntimeBits()) {
src/codegen/c.zig+5-3
......@@ -835,7 +835,6 @@ pub const DeclGen = struct {
835835 },
836836 .Union => {
837837 const union_obj = val.castTag(.@"union").?.data;
838 const union_ty = ty.cast(Type.Payload.Union).?.data;
839838 const layout = ty.unionGetLayout(target);
840839
841840 try writer.writeAll("(");
......@@ -851,7 +850,7 @@ pub const DeclGen = struct {
851850 try writer.writeAll(".payload = {");
852851 }
853852
854 const index = union_ty.tag_ty.enumTagFieldIndex(union_obj.tag, dg.module).?;
853 const index = ty.unionTagFieldIndex(union_obj.tag, dg.module).?;
855854 const field_ty = ty.unionFields().values()[index].ty;
856855 const field_name = ty.unionFields().keys()[index];
857856 if (field_ty.hasRuntimeBits()) {
......@@ -1952,6 +1951,9 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
19521951 .reduce_optimized,
19531952 .float_to_int_optimized,
19541953 => 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", .{}),
19551957 // zig fmt: on
19561958 };
19571959 switch (result_value) {
......@@ -3250,7 +3252,7 @@ fn airIsNull(
32503252
32513253 const ty = f.air.typeOf(un_op);
32523254 var opt_buf: Type.Payload.ElemType = undefined;
3253 const payload_ty = if (ty.zigTypeTag() == .Pointer)
3255 const payload_ty = if (deref_suffix[0] != 0)
32543256 ty.childType().optionalChild(&opt_buf)
32553257 else
32563258 ty.optionalChild(&opt_buf);
src/codegen/llvm.zig+393-43
......@@ -222,6 +222,8 @@ pub const Object = struct {
222222 /// * it works for functions not all globals.
223223 /// Therefore, this table keeps track of the mapping.
224224 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),
225227 /// Maps Zig types to LLVM types. The table memory itself is backed by the GPA of
226228 /// the compiler, but the Type/Value memory here is backed by `type_map_arena`.
227229 /// TODO we need to remove entries from this map in response to incremental compilation
......@@ -292,7 +294,7 @@ pub const Object = struct {
292294 var di_compile_unit: ?*llvm.DICompileUnit = null;
293295
294296 if (!options.strip) {
295 switch (options.object_format) {
297 switch (options.target.ofmt) {
296298 .coff => llvm_module.addModuleCodeViewFlag(),
297299 else => llvm_module.addModuleDebugInfoFlag(),
298300 }
......@@ -398,6 +400,7 @@ pub const Object = struct {
398400 .target_data = target_data,
399401 .target = options.target,
400402 .decl_map = .{},
403 .named_enum_map = .{},
401404 .type_map = .{},
402405 .type_map_arena = std.heap.ArenaAllocator.init(gpa),
403406 .di_type_map = .{},
......@@ -417,6 +420,7 @@ pub const Object = struct {
417420 self.llvm_module.dispose();
418421 self.context.dispose();
419422 self.decl_map.deinit(gpa);
423 self.named_enum_map.deinit(gpa);
420424 self.type_map.deinit(gpa);
421425 self.type_map_arena.deinit();
422426 self.extern_collisions.deinit(gpa);
......@@ -728,9 +732,14 @@ pub const Object = struct {
728732 DeclGen.removeFnAttr(llvm_func, "noinline");
729733 }
730734
731 // TODO: port these over from stage1
732 // addLLVMFnAttr(llvm_fn, "sspstrong");
733 // addLLVMFnAttrStr(llvm_fn, "stack-protector-buffer-size", "4");
735 // TODO: disable this if safety is off for the function scope
736 const ssp_buf_size = module.comp.bin_file.options.stack_protector;
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
735744 // TODO: disable this if safety is off for the function scope
736745 if (module.comp.bin_file.options.stack_check) {
......@@ -739,6 +748,10 @@ pub const Object = struct {
739748 dg.addFnAttrString(llvm_func, "no-stack-arg-probe", "");
740749 }
741750
751 if (decl.@"linksection") |section| {
752 llvm_func.setSection(section);
753 }
754
742755 // Remove all the basic blocks of a function in order to start over, generating
743756 // LLVM IR from an empty function body.
744757 while (llvm_func.getFirstBasicBlock()) |bb| {
......@@ -935,6 +948,40 @@ pub const Object = struct {
935948 };
936949 try args.append(loaded);
937950 },
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 },
938985 .as_u16 => {
939986 const param = llvm_func.getParam(llvm_arg_i);
940987 llvm_arg_i += 1;
......@@ -1078,6 +1125,7 @@ pub const Object = struct {
10781125 }
10791126 llvm_global.setUnnamedAddr(.False);
10801127 llvm_global.setLinkage(.External);
1128 if (module.wantDllExports()) llvm_global.setDLLStorageClass(.Default);
10811129 if (self.di_map.get(decl)) |di_node| {
10821130 if (try decl.isFunction()) {
10831131 const di_func = @ptrCast(*llvm.DISubprogram, di_node);
......@@ -1103,6 +1151,7 @@ pub const Object = struct {
11031151 const exp_name = exports[0].options.name;
11041152 llvm_global.setValueName2(exp_name.ptr, exp_name.len);
11051153 llvm_global.setUnnamedAddr(.False);
1154 if (module.wantDllExports()) llvm_global.setDLLStorageClass(.DLLExport);
11061155 if (self.di_map.get(decl)) |di_node| {
11071156 if (try decl.isFunction()) {
11081157 const di_func = @ptrCast(*llvm.DISubprogram, di_node);
......@@ -1125,6 +1174,11 @@ pub const Object = struct {
11251174 .hidden => llvm_global.setVisibility(.Hidden),
11261175 .protected => llvm_global.setVisibility(.Protected),
11271176 }
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 }
11281182 if (decl.val.castTag(.variable)) |variable| {
11291183 if (variable.data.is_threadlocal) {
11301184 llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);
......@@ -1157,6 +1211,7 @@ pub const Object = struct {
11571211 defer module.gpa.free(fqn);
11581212 llvm_global.setValueName2(fqn.ptr, fqn.len);
11591213 llvm_global.setLinkage(.Internal);
1214 if (module.wantDllExports()) llvm_global.setDLLStorageClass(.Default);
11601215 llvm_global.setUnnamedAddr(.True);
11611216 if (decl.val.castTag(.variable)) |variable| {
11621217 const single_threaded = module.comp.bin_file.options.single_threaded;
......@@ -1701,8 +1756,7 @@ pub const Object = struct {
17011756 if (ty.castTag(.@"struct")) |payload| {
17021757 const struct_obj = payload.data;
17031758 if (struct_obj.layout == .Packed) {
1704 var buf: Type.Payload.Bits = undefined;
1705 const info = struct_obj.packedIntegerType(target, &buf).intInfo(target);
1759 const info = struct_obj.backing_int_ty.intInfo(target);
17061760 const dwarf_encoding: c_uint = switch (info.signedness) {
17071761 .signed => DW.ATE.signed,
17081762 .unsigned => DW.ATE.unsigned,
......@@ -1817,6 +1871,7 @@ pub const Object = struct {
18171871 }
18181872
18191873 const fields = ty.structFields();
1874 const layout = ty.containerLayout();
18201875
18211876 var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};
18221877 defer di_fields.deinit(gpa);
......@@ -1827,10 +1882,10 @@ pub const Object = struct {
18271882 var offset: u64 = 0;
18281883
18291884 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
18321887 const field_size = field.ty.abiSize(target);
1833 const field_align = field.normalAlignment(target);
1888 const field_align = field.alignment(target, layout);
18341889 const field_offset = std.mem.alignForwardGeneric(u64, offset, field_align);
18351890 offset = field_offset + field_size;
18361891
......@@ -2202,6 +2257,7 @@ pub const DeclGen = struct {
22022257 const target = dg.module.getTarget();
22032258 var global = try dg.resolveGlobalDecl(decl_index);
22042259 global.setAlignment(decl.getAlignment(target));
2260 if (decl.@"linksection") |section| global.setSection(section);
22052261 assert(decl.has_tv);
22062262 const init_val = if (decl.val.castTag(.variable)) |payload| init_val: {
22072263 const variable = payload.data;
......@@ -2235,6 +2291,7 @@ pub const DeclGen = struct {
22352291 new_global.setLinkage(global.getLinkage());
22362292 new_global.setUnnamedAddr(global.getUnnamedAddress());
22372293 new_global.setAlignment(global.getAlignment());
2294 if (decl.@"linksection") |section| new_global.setSection(section);
22382295 new_global.setInitializer(llvm_init);
22392296 // replaceAllUsesWith requires the type to be unchanged. So we bitcast
22402297 // the new global to the old type and use that as the thing to replace
......@@ -2349,6 +2406,14 @@ pub const DeclGen = struct {
23492406 dg.addFnAttr(llvm_fn, "noreturn");
23502407 }
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
23522417 return llvm_fn;
23532418 }
23542419
......@@ -2688,9 +2753,7 @@ pub const DeclGen = struct {
26882753 const struct_obj = t.castTag(.@"struct").?.data;
26892754
26902755 if (struct_obj.layout == .Packed) {
2691 var buf: Type.Payload.Bits = undefined;
2692 const int_ty = struct_obj.packedIntegerType(target, &buf);
2693 const int_llvm_ty = try dg.lowerType(int_ty);
2756 const int_llvm_ty = try dg.lowerType(struct_obj.backing_int_ty);
26942757 gop.value_ptr.* = int_llvm_ty;
26952758 return int_llvm_ty;
26962759 }
......@@ -2714,9 +2777,9 @@ pub const DeclGen = struct {
27142777 var any_underaligned_fields = false;
27152778
27162779 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);
27202783 const field_ty_align = field.ty.abiAlignment(target);
27212784 any_underaligned_fields = any_underaligned_fields or
27222785 field_align < field_ty_align;
......@@ -2895,6 +2958,18 @@ pub const DeclGen = struct {
28952958 llvm_params.appendAssumeCapacity(big_int_ty);
28962959 }
28972960 },
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 },
28982973 .as_u16 => {
28992974 try llvm_params.append(dg.context.intType(16));
29002975 },
......@@ -3356,8 +3431,8 @@ pub const DeclGen = struct {
33563431 const struct_obj = tv.ty.castTag(.@"struct").?.data;
33573432
33583433 if (struct_obj.layout == .Packed) {
3359 const big_bits = struct_obj.packedIntegerBits(target);
3360 const int_llvm_ty = dg.context.intType(big_bits);
3434 const big_bits = struct_obj.backing_int_ty.bitSize(target);
3435 const int_llvm_ty = dg.context.intType(@intCast(c_uint, big_bits));
33613436 const fields = struct_obj.fields.values();
33623437 comptime assert(Type.packed_struct_layout_version == 2);
33633438 var running_int: *const llvm.Value = int_llvm_ty.constNull();
......@@ -3372,7 +3447,10 @@ pub const DeclGen = struct {
33723447 });
33733448 const ty_bit_size = @intCast(u16, field.ty.bitSize(target));
33743449 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);
33763454 const shift_rhs = int_llvm_ty.constInt(running_bits, .False);
33773455 // If the field is as large as the entire packed struct, this
33783456 // zext would go from, e.g. i16 to i16. This is legal with
......@@ -3395,9 +3473,9 @@ pub const DeclGen = struct {
33953473 var need_unnamed = false;
33963474
33973475 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);
34013479 big_align = @maximum(big_align, field_align);
34023480 const prev_offset = offset;
34033481 offset = std.mem.alignForwardGeneric(u64, offset, field_align);
......@@ -3457,7 +3535,7 @@ pub const DeclGen = struct {
34573535 });
34583536 }
34593537 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).?;
34613539 assert(union_obj.haveFieldTypes());
34623540
34633541 // Sometimes we must make an unnamed struct because LLVM does
......@@ -3976,6 +4054,9 @@ pub const FuncGen = struct {
39764054 /// Note that this can disagree with isByRef for the return type in the case
39774055 /// of C ABI functions.
39784056 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,
39794060 /// These fields are used to refer to the LLVM value of the function parameters
39804061 /// in an Arg instruction.
39814062 /// This list may be shorter than the list according to the zig type system;
......@@ -4215,6 +4296,9 @@ pub const FuncGen = struct {
42154296 .union_init => try self.airUnionInit(inst),
42164297 .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
42184302 .reduce => try self.airReduce(inst, false),
42194303 .reduce_optimized => try self.airReduce(inst, true),
42204304
......@@ -4423,6 +4507,39 @@ pub const FuncGen = struct {
44234507 llvm_args.appendAssumeCapacity(load_inst);
44244508 }
44254509 },
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 },
44264543 .as_u16 => {
44274544 const arg = args[it.zig_index - 1];
44284545 const llvm_arg = try self.resolveInst(arg);
......@@ -5295,7 +5412,7 @@ pub const FuncGen = struct {
52955412 const same_size_int = self.context.intType(elem_bits);
52965413 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");
52975414 return self.builder.buildBitCast(truncated_int, elem_llvm_ty, "");
5298 } else if (field_ty.zigTypeTag() == .Pointer) {
5415 } else if (field_ty.isPtrAtRuntime()) {
52995416 const elem_bits = @intCast(c_uint, field_ty.bitSize(target));
53005417 const same_size_int = self.context.intType(elem_bits);
53015418 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");
......@@ -6166,7 +6283,9 @@ pub const FuncGen = struct {
61666283 }
61676284 const llvm_optional_ty = try self.dg.lowerType(optional_ty);
61686285 if (isByRef(optional_ty)) {
6286 const target = self.dg.module.getTarget();
61696287 const optional_ptr = self.buildAlloca(llvm_optional_ty);
6288 optional_ptr.setAlignment(optional_ty.abiAlignment(target));
61706289 const payload_ptr = self.builder.buildStructGEP(llvm_optional_ty, optional_ptr, 0, "");
61716290 var ptr_ty_payload: Type.Payload.ElemType = .{
61726291 .base = .{ .tag = .single_mut_pointer },
......@@ -6186,20 +6305,21 @@ pub const FuncGen = struct {
61866305 if (self.liveness.isUnused(inst)) return null;
61876306
61886307 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);
61906309 const operand = try self.resolveInst(ty_op.operand);
61916310 const payload_ty = self.air.typeOf(ty_op.operand);
61926311 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
61936312 return operand;
61946313 }
61956314 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
61986317 const target = self.dg.module.getTarget();
61996318 const payload_offset = errUnionPayloadOffset(payload_ty, target);
62006319 const error_offset = errUnionErrorOffset(payload_ty, target);
6201 if (isByRef(inst_ty)) {
6320 if (isByRef(err_un_ty)) {
62026321 const result_ptr = self.buildAlloca(err_un_llvm_ty);
6322 result_ptr.setAlignment(err_un_ty.abiAlignment(target));
62036323 const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, "");
62046324 const store_inst = self.builder.buildStore(ok_err_code, err_ptr);
62056325 store_inst.setAlignment(Type.anyerror.abiAlignment(target));
......@@ -6234,6 +6354,7 @@ pub const FuncGen = struct {
62346354 const error_offset = errUnionErrorOffset(payload_ty, target);
62356355 if (isByRef(err_un_ty)) {
62366356 const result_ptr = self.buildAlloca(err_un_llvm_ty);
6357 result_ptr.setAlignment(err_un_ty.abiAlignment(target));
62376358 const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, "");
62386359 const store_inst = self.builder.buildStore(operand, err_ptr);
62396360 store_inst.setAlignment(Type.anyerror.abiAlignment(target));
......@@ -7412,7 +7533,7 @@ pub const FuncGen = struct {
74127533 const lbrace_col = func.lbrace_column + 1;
74137534 const di_local_var = dib.createParameterVariable(
74147535 self.di_scope.?,
7415 func.getParamName(src_index).ptr, // TODO test 0 bit args
7536 func.getParamName(self.dg.module, src_index).ptr, // TODO test 0 bit args
74167537 self.di_file.?,
74177538 lbrace_line,
74187539 try self.dg.object.lowerDebugType(inst_ty, .full),
......@@ -7515,8 +7636,7 @@ pub const FuncGen = struct {
75157636 const len = usize_llvm_ty.constInt(operand_size, .False);
75167637 _ = self.builder.buildMemSet(dest_ptr_u8, fill_char, len, dest_ptr_align, ptr_ty.isVolatilePtr());
75177638 if (self.dg.module.comp.bin_file.options.valgrind) {
7518 // TODO generate valgrind client request to mark byte range as undefined
7519 // see gen_valgrind_undef() in codegen.cpp
7639 self.valgrindMarkUndef(dest_ptr, len);
75207640 }
75217641 } else {
75227642 const src_operand = try self.resolveInst(bin_op.rhs);
......@@ -7786,8 +7906,7 @@ pub const FuncGen = struct {
77867906 _ = self.builder.buildMemSet(dest_ptr_u8, fill_char, len, dest_ptr_align, ptr_ty.isVolatilePtr());
77877907
77887908 if (val_is_undef and self.dg.module.comp.bin_file.options.valgrind) {
7789 // TODO generate valgrind client request to mark byte range as undefined
7790 // see gen_valgrind_undef() in codegen.cpp
7909 self.valgrindMarkUndef(dest_ptr_u8, len);
77917910 }
77927911 return null;
77937912 }
......@@ -7994,6 +8113,134 @@ pub const FuncGen = struct {
79948113 }
79958114 }
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
79978244 fn airTagName(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
79988245 if (self.liveness.isUnused(inst)) return null;
79998246
......@@ -8272,8 +8519,8 @@ pub const FuncGen = struct {
82728519 .Struct => {
82738520 if (result_ty.containerLayout() == .Packed) {
82748521 const struct_obj = result_ty.castTag(.@"struct").?.data;
8275 const big_bits = struct_obj.packedIntegerBits(target);
8276 const int_llvm_ty = self.dg.context.intType(big_bits);
8522 const big_bits = struct_obj.backing_int_ty.bitSize(target);
8523 const int_llvm_ty = self.dg.context.intType(@intCast(c_uint, big_bits));
82778524 const fields = struct_obj.fields.values();
82788525 comptime assert(Type.packed_struct_layout_version == 2);
82798526 var running_int: *const llvm.Value = int_llvm_ty.constNull();
......@@ -8285,7 +8532,7 @@ pub const FuncGen = struct {
82858532 const non_int_val = try self.resolveInst(elem);
82868533 const ty_bit_size = @intCast(u16, field.ty.bitSize(target));
82878534 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())
82898536 self.builder.buildPtrToInt(non_int_val, small_int_ty, "")
82908537 else
82918538 self.builder.buildBitCast(non_int_val, small_int_ty, "");
......@@ -8973,6 +9220,89 @@ pub const FuncGen = struct {
89739220 info.@"volatile",
89749221 );
89759222 }
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 }
89769306};
89779307
89789308fn initializeLLVMTarget(arch: std.Target.Cpu.Arch) void {
......@@ -9266,13 +9596,14 @@ fn llvmFieldIndex(
92669596 }
92679597 return null;
92689598 }
9269 assert(ty.containerLayout() != .Packed);
9599 const layout = ty.containerLayout();
9600 assert(layout != .Packed);
92709601
92719602 var llvm_field_index: c_uint = 0;
92729603 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);
92769607 big_align = @maximum(big_align, field_align);
92779608 const prev_offset = offset;
92789609 offset = std.mem.alignForwardGeneric(u64, offset, field_align);
......@@ -9392,16 +9723,20 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm.
93929723 llvm_types_index += 1;
93939724 },
93949725 .sse => {
9395 @panic("TODO");
9726 llvm_types_buffer[llvm_types_index] = dg.context.doubleType();
9727 llvm_types_index += 1;
93969728 },
93979729 .sseup => {
9398 @panic("TODO");
9730 llvm_types_buffer[llvm_types_index] = dg.context.doubleType();
9731 llvm_types_index += 1;
93999732 },
94009733 .x87 => {
9401 @panic("TODO");
9734 llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type();
9735 llvm_types_index += 1;
94029736 },
94039737 .x87up => {
9404 @panic("TODO");
9738 llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type();
9739 llvm_types_index += 1;
94059740 },
94069741 .complex_x87 => {
94079742 @panic("TODO");
......@@ -9447,6 +9782,7 @@ const ParamTypeIterator = struct {
94479782 target: std.Target,
94489783 llvm_types_len: u32,
94499784 llvm_types_buffer: [8]u16,
9785 byval_attr: bool,
94509786
94519787 const Lowering = enum {
94529788 no_bits,
......@@ -9454,6 +9790,7 @@ const ParamTypeIterator = struct {
94549790 byref,
94559791 abi_sized_int,
94569792 multiple_llvm_ints,
9793 multiple_llvm_float,
94579794 slice,
94589795 as_u16,
94599796 };
......@@ -9461,6 +9798,7 @@ const ParamTypeIterator = struct {
94619798 pub fn next(it: *ParamTypeIterator) ?Lowering {
94629799 if (it.zig_index >= it.fn_info.param_types.len) return null;
94639800 const ty = it.fn_info.param_types[it.zig_index];
9801 it.byval_attr = false;
94649802 return nextInner(it, ty);
94659803 }
94669804
......@@ -9546,6 +9884,7 @@ const ParamTypeIterator = struct {
95469884 .memory => {
95479885 it.zig_index += 1;
95489886 it.llvm_index += 1;
9887 it.byval_attr = true;
95499888 return .byref;
95509889 },
95519890 .sse => {
......@@ -9565,6 +9904,7 @@ const ParamTypeIterator = struct {
95659904 if (classes[0] == .memory) {
95669905 it.zig_index += 1;
95679906 it.llvm_index += 1;
9907 it.byval_attr = true;
95689908 return .byref;
95699909 }
95709910 var llvm_types_buffer: [8]u16 = undefined;
......@@ -9576,16 +9916,20 @@ const ParamTypeIterator = struct {
95769916 llvm_types_index += 1;
95779917 },
95789918 .sse => {
9579 @panic("TODO");
9919 llvm_types_buffer[llvm_types_index] = 64;
9920 llvm_types_index += 1;
95809921 },
95819922 .sseup => {
9582 @panic("TODO");
9923 llvm_types_buffer[llvm_types_index] = 64;
9924 llvm_types_index += 1;
95839925 },
95849926 .x87 => {
9585 @panic("TODO");
9927 llvm_types_buffer[llvm_types_index] = 80;
9928 llvm_types_index += 1;
95869929 },
95879930 .x87up => {
9588 @panic("TODO");
9931 llvm_types_buffer[llvm_types_index] = 80;
9932 llvm_types_index += 1;
95899933 },
95909934 .complex_x87 => {
95919935 @panic("TODO");
......@@ -9599,11 +9943,16 @@ const ParamTypeIterator = struct {
95999943 it.llvm_index += 1;
96009944 return .abi_sized_int;
96019945 }
9946 if (classes[0] == .sse and classes[1] == .none) {
9947 it.zig_index += 1;
9948 it.llvm_index += 1;
9949 return .byval;
9950 }
96029951 it.llvm_types_buffer = llvm_types_buffer;
96039952 it.llvm_types_len = llvm_types_index;
96049953 it.llvm_index += llvm_types_index;
96059954 it.zig_index += 1;
9606 return .multiple_llvm_ints;
9955 return if (classes[0] == .integer) .multiple_llvm_ints else .multiple_llvm_float;
96079956 },
96089957 },
96099958 .wasm32 => {
......@@ -9644,6 +9993,7 @@ fn iterateParamTypes(dg: *DeclGen, fn_info: Type.Payload.Function.Data) ParamTyp
96449993 .target = dg.module.getTarget(),
96459994 .llvm_types_buffer = undefined,
96469995 .llvm_types_len = 0,
9996 .byval_attr = false,
96479997 };
96489998}
96499999
src/codegen/llvm/bindings.zig+15
......@@ -129,6 +129,9 @@ pub const Value = opaque {
129129 pub const setThreadLocalMode = LLVMSetThreadLocalMode;
130130 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
132135 pub const deleteGlobal = LLVMDeleteGlobal;
133136 extern fn LLVMDeleteGlobal(GlobalVar: *const Value) void;
134137
......@@ -216,6 +219,9 @@ pub const Value = opaque {
216219 pub const setInitializer = LLVMSetInitializer;
217220 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
219225 pub const addCase = LLVMAddCase;
220226 extern fn LLVMAddCase(Switch: *const Value, OnVal: *const Value, Dest: *const BasicBlock) void;
221227
......@@ -244,6 +250,9 @@ pub const Value = opaque {
244250
245251 pub const getGEPResultElementType = ZigLLVMGetGEPResultElementType;
246252 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;
247256};
248257
249258pub const Type = opaque {
......@@ -1486,6 +1495,12 @@ pub const CallAttr = enum(c_int) {
14861495 AlwaysInline,
14871496};
14881497
1498pub const DLLStorageClass = enum(c_uint) {
1499 Default,
1500 DLLImport,
1501 DLLExport,
1502};
1503
14891504pub const address_space = struct {
14901505 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@;
88pub const enable_link_snapshots: bool = false;
99pub const enable_tracy = false;
1010pub const value_tracing = false;
11pub const is_stage1 = true;
11pub const have_stage1 = true;
1212pub 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{
4141 .{ .name = "rt", .sover = 1 },
4242 .{ .name = "ld", .sover = 2 },
4343 .{ .name = "util", .sover = 1 },
44};
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,
44 .{ .name = "resolv", .sover = 2 },
6745};
6846
6947pub const LoadMetaDataError = error{
......@@ -157,7 +135,7 @@ pub fn loadMetaData(gpa: Allocator, zig_lib_dir: fs.Dir) LoadMetaDataError!*ABI
157135 log.err("abilists: expected ABI name", .{});
158136 return error.ZigInstallationCorrupt;
159137 };
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 {
161139 log.err("abilists: unrecognized arch: '{s}'", .{arch_name});
162140 return error.ZigInstallationCorrupt;
163141 };
......@@ -171,7 +149,7 @@ pub fn loadMetaData(gpa: Allocator, zig_lib_dir: fs.Dir) LoadMetaDataError!*ABI
171149 };
172150
173151 targets[i] = .{
174 .arch = glibcToZigArch(arch_tag),
152 .arch = arch_tag,
175153 .os = .linux,
176154 .abi = abi_tag,
177155 };
......@@ -1111,6 +1089,7 @@ fn buildSharedLib(
11111089 .optimize_mode = comp.compilerRtOptMode(),
11121090 .want_sanitize_c = false,
11131091 .want_stack_check = false,
1092 .want_stack_protector = 0,
11141093 .want_red_zone = comp.bin_file.options.red_zone,
11151094 .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer,
11161095 .want_valgrind = false,
......@@ -1138,30 +1117,6 @@ fn buildSharedLib(
11381117 try sub_compilation.updateSubCompilation();
11391118}
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
11651120// Return true if glibc has crti/crtn sources for that architecture.
11661121pub fn needsCrtiCrtn(target: std.Target) bool {
11671122 return switch (target.cpu.arch) {
src/libcxx.zig+2
......@@ -208,6 +208,7 @@ pub fn buildLibCXX(comp: *Compilation) !void {
208208 .link_mode = link_mode,
209209 .want_sanitize_c = false,
210210 .want_stack_check = false,
211 .want_stack_protector = 0,
211212 .want_red_zone = comp.bin_file.options.red_zone,
212213 .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer,
213214 .want_valgrind = false,
......@@ -351,6 +352,7 @@ pub fn buildLibCXXABI(comp: *Compilation) !void {
351352 .link_mode = link_mode,
352353 .want_sanitize_c = false,
353354 .want_stack_check = false,
355 .want_stack_protector = 0,
354356 .want_red_zone = comp.bin_file.options.red_zone,
355357 .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer,
356358 .want_valgrind = false,
src/libtsan.zig+1
......@@ -211,6 +211,7 @@ pub fn buildTsan(comp: *Compilation) !void {
211211 .link_mode = link_mode,
212212 .want_sanitize_c = false,
213213 .want_stack_check = false,
214 .want_stack_protector = 0,
214215 .want_valgrind = false,
215216 .want_tsan = false,
216217 .want_pic = true,
src/libunwind.zig+1
......@@ -102,6 +102,7 @@ pub fn buildStaticLib(comp: *Compilation) !void {
102102 .link_mode = link_mode,
103103 .want_sanitize_c = false,
104104 .want_stack_check = false,
105 .want_stack_protector = 0,
105106 .want_red_zone = comp.bin_file.options.red_zone,
106107 .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer,
107108 .want_valgrind = false,
src/link.zig+23-11
......@@ -72,7 +72,6 @@ pub const Options = struct {
7272 target: std.Target,
7373 output_mode: std.builtin.OutputMode,
7474 link_mode: std.builtin.LinkMode,
75 object_format: std.Target.ObjectFormat,
7675 optimize_mode: std.builtin.Mode,
7776 machine_code_model: std.builtin.CodeModel,
7877 root_name: [:0]const u8,
......@@ -91,6 +90,9 @@ pub const Options = struct {
9190 entry: ?[]const u8,
9291 stack_size_override: ?u64,
9392 image_base_override: ?u64,
93 /// 0 means no stack protector
94 /// other value means stack protector with that buffer size.
95 stack_protector: u32,
9496 cache_mode: CacheMode,
9597 include_compiler_rt: bool,
9698 /// Set to `true` to omit debug info.
......@@ -173,6 +175,12 @@ pub const Options = struct {
173175 lib_dirs: []const []const u8,
174176 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
176184 version: ?std.builtin.Version,
177185 compatibility_version: ?std.builtin.Version,
178186 libc_installation: ?*const LibCInstallation,
......@@ -273,13 +281,13 @@ pub const File = struct {
273281 /// rewriting it. A malicious file is detected as incremental link failure
274282 /// and does not cause Illegal Behavior. This operation is not atomic.
275283 pub fn openPath(allocator: Allocator, options: Options) !*File {
276 if (options.object_format == .macho) {
284 if (options.target.ofmt == .macho) {
277285 return &(try MachO.openPath(allocator, options)).base;
278286 }
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;
281289 if (use_stage1 or options.emit == null) {
282 return switch (options.object_format) {
290 return switch (options.target.ofmt) {
283291 .coff => &(try Coff.createEmpty(allocator, options)).base,
284292 .elf => &(try Elf.createEmpty(allocator, options)).base,
285293 .macho => unreachable,
......@@ -299,7 +307,7 @@ pub const File = struct {
299307 if (options.module == null) {
300308 // No point in opening a file, we would not write anything to it.
301309 // Initialize with empty.
302 return switch (options.object_format) {
310 return switch (options.target.ofmt) {
303311 .coff => &(try Coff.createEmpty(allocator, options)).base,
304312 .elf => &(try Elf.createEmpty(allocator, options)).base,
305313 .macho => unreachable,
......@@ -316,12 +324,12 @@ pub const File = struct {
316324 // Open a temporary object file, not the final output file because we
317325 // want to link with LLD.
318326 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),
320328 });
321329 } else emit.sub_path;
322330 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) {
325333 .coff => &(try Coff.openPath(allocator, sub_path, options)).base,
326334 .elf => &(try Elf.openPath(allocator, sub_path, options)).base,
327335 .macho => unreachable,
......@@ -421,7 +429,7 @@ pub const File = struct {
421429 NoSpaceLeft,
422430 Unseekable,
423431 PermissionDenied,
424 FileBusy,
432 SwapFile,
425433 SystemResources,
426434 OperationAborted,
427435 BrokenPipe,
......@@ -438,6 +446,7 @@ pub const File = struct {
438446 EmitFail,
439447 NameTooLong,
440448 CurrentWorkingDirectoryUnlinked,
449 LockViolation,
441450 };
442451
443452 /// Called from within the CodeGen to lower a local variable instantion as an unnamed
......@@ -774,12 +783,15 @@ pub const File = struct {
774783 error.FileNotFound => {},
775784 else => |e| return e,
776785 }
777 try std.fs.rename(
786 std.fs.rename(
778787 cache_directory.handle,
779788 tmp_dir_sub_path,
780789 cache_directory.handle,
781790 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 };
783795 break;
784796 } else {
785797 std.fs.rename(
......@@ -814,7 +826,7 @@ pub const File = struct {
814826 // If there is no Zig code to compile, then we should skip flushing the output file
815827 // because it will not be part of the linker line anyway.
816828 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;
818830 if (use_stage1) {
819831 const obj_basename = try std.zig.binNameAlloc(arena, .{
820832 .root_name = base.options.root_name,
src/link/C.zig+1-1
......@@ -48,7 +48,7 @@ const DeclBlock = struct {
4848};
4949
5050pub 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
5353 if (options.use_llvm) return error.LLVMHasNoCBackend;
5454 if (options.use_lld) return error.LLDHasNoCBackend;
src/link/Coff.zig+25-14
......@@ -128,7 +128,7 @@ pub const TextBlock = struct {
128128pub const SrcFn = void;
129129
130130pub 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
133133 if (build_options.have_llvm and options.use_llvm) {
134134 return createEmpty(allocator, options);
......@@ -204,15 +204,18 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
204204 index += 2;
205205
206206 // Characteristics
207 var characteristics: u16 = std.coff.IMAGE_FILE_DEBUG_STRIPPED | std.coff.IMAGE_FILE_RELOCS_STRIPPED; // TODO Remove debug info stripped flag when necessary
207 var characteristics: std.coff.CoffHeaderFlags = .{
208 .DEBUG_STRIPPED = 1, // TODO remove debug info stripped flag when necessary
209 .RELOCS_STRIPPED = 1,
210 };
208211 if (options.output_mode == .Exe) {
209 characteristics |= std.coff.IMAGE_FILE_EXECUTABLE_IMAGE;
212 characteristics.EXECUTABLE_IMAGE = 1;
210213 }
211214 switch (self.ptr_width) {
212 .p32 => characteristics |= std.coff.IMAGE_FILE_32BIT_MACHINE,
213 .p64 => characteristics |= std.coff.IMAGE_FILE_LARGE_ADDRESS_AWARE,
215 .p32 => characteristics.@"32BIT_MACHINE" = 1,
216 .p64 => characteristics.LARGE_ADDRESS_AWARE = 1,
214217 }
215 mem.writeIntLittle(u16, hdr_data[index..][0..2], characteristics);
218 mem.writeIntLittle(u16, hdr_data[index..][0..2], @bitCast(u16, characteristics));
216219 index += 2;
217220
218221 assert(index == 20);
......@@ -352,7 +355,10 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
352355 mem.set(u8, hdr_data[index..][0..12], 0);
353356 index += 12;
354357 // 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 }));
356362 index += 4;
357363 // Then, the .text section
358364 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
378384 mem.set(u8, hdr_data[index..][0..12], 0);
379385 index += 12;
380386 // Section flags
381 mem.writeIntLittle(
382 u32,
383 hdr_data[index..][0..4],
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,
385 );
387 mem.writeIntLittle(u32, hdr_data[index..][0..4], @bitCast(u32, std.coff.SectionHeaderFlags{
388 .CNT_CODE = 1,
389 .MEM_EXECUTE = 1,
390 .MEM_READ = 1,
391 .MEM_WRITE = 1,
392 }));
386393 index += 4;
387394
388395 assert(index == optional_header_size + section_table_size);
......@@ -411,7 +418,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Coff {
411418 };
412419
413420 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;
415422 if (use_llvm and !use_stage1) {
416423 self.llvm_object = try LlvmObject.create(gpa, options);
417424 }
......@@ -949,7 +956,7 @@ fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !
949956 // If there is no Zig code to compile, then we should skip flushing the output file because it
950957 // will not be part of the linker line anyway.
951958 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;
953960 if (use_stage1) {
954961 const obj_basename = try std.zig.binNameAlloc(arena, .{
955962 .root_name = self.base.options.root_name,
......@@ -1126,6 +1133,10 @@ fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !
11261133 }
11271134 }
11281135
1136 for (self.base.options.force_undefined_symbols.keys()) |symbol| {
1137 try argv.append(try allocPrint(arena, "-INCLUDE:{s}", .{symbol}));
1138 }
1139
11291140 if (is_dyn_lib) {
11301141 try argv.append("-DLL");
11311142 }
src/link/Dwarf.zig+12-7
......@@ -102,7 +102,7 @@ pub const DeclState = struct {
102102 }
103103
104104 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 });
106106 try self.exprloc_relocs.append(self.gpa, .{
107107 .@"type" = if (is_ptr) .got_load else .direct_load,
108108 .target = target,
......@@ -135,7 +135,7 @@ pub const DeclState = struct {
135135 .@"type" = ty,
136136 .offset = undefined,
137137 });
138 log.debug("@{d}: {}", .{ sym_index, ty.fmtDebug() });
138 log.debug("%{d}: {}", .{ sym_index, ty.fmtDebug() });
139139 try self.abbrev_resolver.putNoClobberContext(self.gpa, ty, sym_index, .{
140140 .mod = self.mod,
141141 });
......@@ -143,7 +143,7 @@ pub const DeclState = struct {
143143 .mod = self.mod,
144144 }).?;
145145 };
146 log.debug("{x}: @{d} + 0", .{ offset, resolv });
146 log.debug("{x}: %{d} + 0", .{ offset, resolv });
147147 try self.abbrev_relocs.append(self.gpa, .{
148148 .target = resolv,
149149 .atom = atom,
......@@ -243,11 +243,13 @@ pub const DeclState = struct {
243243 .Pointer => {
244244 if (ty.isSlice()) {
245245 // 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));
246248 // DW.AT.structure_type
247249 try dbg_info_buffer.ensureUnusedCapacity(2);
248250 dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_type));
249251 // DW.AT.byte_size, DW.FORM.sdata
250 dbg_info_buffer.appendAssumeCapacity(@sizeOf(usize) * 2);
252 dbg_info_buffer.appendAssumeCapacity(ptr_bytes * 2);
251253 // DW.AT.name, DW.FORM.string
252254 try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(module)});
253255 // DW.AT.member
......@@ -276,7 +278,7 @@ pub const DeclState = struct {
276278 try self.addTypeRelocGlobal(atom, Type.usize, @intCast(u32, index));
277279 // DW.AT.data_member_location, DW.FORM.sdata
278280 try dbg_info_buffer.ensureUnusedCapacity(2);
279 dbg_info_buffer.appendAssumeCapacity(@sizeOf(usize));
281 dbg_info_buffer.appendAssumeCapacity(ptr_bytes);
280282 // DW.AT.structure_type delimit children
281283 dbg_info_buffer.appendAssumeCapacity(0);
282284 } else {
......@@ -1054,6 +1056,7 @@ pub fn commitDeclState(
10541056 break :blk false;
10551057 };
10561058 if (deferred) {
1059 log.debug("resolving %{d} deferred until flush", .{target});
10571060 try self.global_abbrev_relocs.append(gpa, .{
10581061 .target = null,
10591062 .offset = reloc.offset,
......@@ -1061,10 +1064,12 @@ pub fn commitDeclState(
10611064 .addend = reloc.addend,
10621065 });
10631066 } else {
1067 const value = symbol.atom.off + symbol.offset + reloc.addend;
1068 log.debug("{x}: [() => {x}] (%{d}, '{}')", .{ reloc.offset, value, target, ty.fmtDebug() });
10641069 mem.writeInt(
10651070 u32,
10661071 dbg_info_buffer.items[reloc.offset..][0..@sizeOf(u32)],
1067 symbol.atom.off + symbol.offset + reloc.addend,
1072 value,
10681073 target_endian,
10691074 );
10701075 }
......@@ -1257,7 +1262,7 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co
12571262 debug_info_sect.addr = dwarf_segment.vmaddr + new_offset - dwarf_segment.fileoff;
12581263 }
12591264 debug_info_sect.size = needed_size;
1260 d_sym.debug_line_header_dirty = true;
1265 d_sym.debug_info_header_dirty = true;
12611266 }
12621267 const file_pos = debug_info_sect.offset + atom.off;
12631268 try pwriteDbgInfoNops(
src/link/Elf.zig+13-2
......@@ -249,7 +249,7 @@ pub const Export = struct {
249249};
250250
251251pub 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
254254 if (build_options.have_llvm and options.use_llvm) {
255255 return createEmpty(allocator, options);
......@@ -328,7 +328,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf {
328328 .page_size = page_size,
329329 };
330330 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;
332332 if (use_llvm and !use_stage1) {
333333 self.llvm_object = try LlvmObject.create(gpa, options);
334334 }
......@@ -1448,6 +1448,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
14481448 try argv.append(entry);
14491449 }
14501450
1451 for (self.base.options.force_undefined_symbols.keys()) |symbol| {
1452 try argv.append("-u");
1453 try argv.append(symbol);
1454 }
1455
14511456 switch (self.base.options.hash_style) {
14521457 .gnu => try argv.append("--hash-style=gnu"),
14531458 .sysv => try argv.append("--hash-style=sysv"),
......@@ -1673,6 +1678,12 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
16731678 }
16741679 }
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
16761687 // compiler-rt
16771688 if (compiler_rt_path) |p| {
16781689 try argv.append(p);
src/link/MachO.zig+25-24
......@@ -270,42 +270,42 @@ pub const Export = struct {
270270};
271271
272272pub 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;
276 if (use_stage1 or options.emit == null) {
275 const use_stage1 = build_options.have_stage1 and options.use_stage1;
276 if (use_stage1 or options.emit == null or options.module == null) {
277277 return createEmpty(allocator, options);
278278 }
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.?;
287281 const self = try createEmpty(allocator, options);
288282 errdefer {
289283 self.base.file = null;
290284 self.base.destroy();
291285 }
292286
293 self.base.file = file;
294
295287 if (build_options.have_llvm and options.use_llvm and options.module != null) {
296288 // TODO this intermediary_basename isn't enough; in the case of `zig build-exe`,
297289 // we also want to put the intermediary object file in the cache while the
298290 // main emit directory is the cwd.
299291 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),
301293 });
302294 }
303295
304 if (options.output_mode == .Lib and
305 options.link_mode == .Static and self.base.intermediary_basename != null)
306 {
307 return self;
308 }
296 if (self.base.intermediary_basename != null) switch (options.output_mode) {
297 .Obj => return self,
298 .Lib => if (options.link_mode == .Static) return self,
299 else => {},
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
310310 if (!options.strip and options.module != null) blk: {
311311 // 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 {
363363 const cpu_arch = options.target.cpu.arch;
364364 const page_size: u16 = if (cpu_arch == .aarch64) 0x4000 else 0x1000;
365365 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
368368 const self = try gpa.create(MachO);
369369 errdefer gpa.destroy(self);
......@@ -5315,10 +5315,10 @@ fn writeFunctionStarts(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
53155315}
53165316
53175317fn filterDataInCode(
5318 dices: []const macho.data_in_code_entry,
5318 dices: []align(1) const macho.data_in_code_entry,
53195319 start_addr: u64,
53205320 end_addr: u64,
5321) []const macho.data_in_code_entry {
5321) []align(1) const macho.data_in_code_entry {
53225322 const Predicate = struct {
53235323 addr: u64,
53245324
......@@ -5825,7 +5825,7 @@ pub fn getEntryPoint(self: MachO) error{MissingMainEntrypoint}!SymbolWithLoc {
58255825 return global;
58265826}
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 {
58295829 if (!@hasDecl(@TypeOf(predicate), "predicate"))
58305830 @compileError("Predicate is required to define fn predicate(@This(), T) bool");
58315831
......@@ -5861,8 +5861,9 @@ pub fn generateSymbolStabs(
58615861 },
58625862 else => |e| return e,
58635863 };
5864 const tu_name = try compile_unit.die.getAttrString(&debug_info, dwarf.AT.name);
5865 const tu_comp_dir = try compile_unit.die.getAttrString(&debug_info, dwarf.AT.comp_dir);
5864
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
58675868 // Open scope
58685869 try locals.ensureUnusedCapacity(3);
src/link/MachO/Atom.zig+1-1
......@@ -218,7 +218,7 @@ const RelocContext = struct {
218218 base_offset: i32 = 0,
219219};
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 {
222222 const tracy = trace(@src());
223223 defer tracy.end();
224224
src/link/MachO/DebugSymbols.zig+8-8
......@@ -63,17 +63,16 @@ pub const Reloc = struct {
6363pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void {
6464 if (self.linkedit_segment_cmd_index == null) {
6565 self.linkedit_segment_cmd_index = @intCast(u8, self.segments.items.len);
66 log.debug("found __LINKEDIT segment free space 0x{x} to 0x{x}", .{
67 self.base.page_size,
68 self.base.page_size * 2,
69 });
66 const fileoff = @intCast(u64, self.base.page_size);
67 const needed_size = @intCast(u64, self.base.page_size) * 2;
68 log.debug("found __LINKEDIT segment free space 0x{x} to 0x{x}", .{ fileoff, needed_size });
7069 // TODO this needs reworking
7170 try self.segments.append(allocator, .{
7271 .segname = makeStaticString("__LINKEDIT"),
73 .vmaddr = self.base.page_size,
74 .vmsize = self.base.page_size,
75 .fileoff = self.base.page_size,
76 .filesize = self.base.page_size,
72 .vmaddr = fileoff,
73 .vmsize = needed_size,
74 .fileoff = fileoff,
75 .filesize = needed_size,
7776 .maxprot = macho.PROT.READ,
7877 .initprot = macho.PROT.READ,
7978 .cmdsize = @sizeOf(macho.segment_command_64),
......@@ -284,6 +283,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
284283 const lc_writer = lc_buffer.writer();
285284 var ncmds: u32 = 0;
286285
286 self.updateDwarfSegment();
287287 try self.writeLinkeditSegmentData(&ncmds, lc_writer);
288288 self.updateDwarfSegment();
289289
src/link/MachO/Object.zig+32-13
......@@ -24,7 +24,7 @@ mtime: u64,
2424contents: []align(@alignOf(u64)) const u8,
2525
2626header: macho.mach_header_64 = undefined,
27in_symtab: []const macho.nlist_64 = undefined,
27in_symtab: []align(1) const macho.nlist_64 = undefined,
2828in_strtab: []const u8 = undefined,
2929
3030symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{},
......@@ -99,12 +99,13 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch)
9999 },
100100 .SYMTAB => {
101101 const symtab = cmd.cast(macho.symtab_command).?;
102 // Sadly, SYMTAB may be at an unaligned offset within the object file.
102103 self.in_symtab = @ptrCast(
103 [*]const macho.nlist_64,
104 @alignCast(@alignOf(macho.nlist_64), &self.contents[symtab.symoff]),
104 [*]align(1) const macho.nlist_64,
105 self.contents.ptr + symtab.symoff,
105106 )[0..symtab.nsyms];
106107 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);
108109 },
109110 else => {},
110111 }
......@@ -196,10 +197,10 @@ fn filterSymbolsByAddress(
196197}
197198
198199fn filterRelocs(
199 relocs: []const macho.relocation_info,
200 relocs: []align(1) const macho.relocation_info,
200201 start_addr: u64,
201202 end_addr: u64,
202) []const macho.relocation_info {
203) []align(1) const macho.relocation_info {
203204 const Predicate = struct {
204205 addr: u64,
205206
......@@ -303,8 +304,8 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)
303304
304305 // Read section's list of relocations
305306 const relocs = @ptrCast(
306 [*]const macho.relocation_info,
307 @alignCast(@alignOf(macho.relocation_info), &self.contents[sect.reloff]),
307 [*]align(1) const macho.relocation_info,
308 self.contents.ptr + sect.reloff,
308309 )[0..sect.nreloc];
309310
310311 // Symbols within this section only.
......@@ -390,7 +391,7 @@ pub fn splitIntoAtomsOneShot(self: *Object, macho_file: *MachO, object_id: u32)
390391 break :blk cc[start..][0..size];
391392 } else null;
392393 const atom_align = if (addr > 0)
393 math.min(@ctz(u64, addr), sect.@"align")
394 math.min(@ctz(addr), sect.@"align")
394395 else
395396 sect.@"align";
396397 const atom = try self.createAtomFromSubsection(
......@@ -472,7 +473,7 @@ fn createAtomFromSubsection(
472473 size: u64,
473474 alignment: u32,
474475 code: ?[]const u8,
475 relocs: []const macho.relocation_info,
476 relocs: []align(1) const macho.relocation_info,
476477 indexes: []const SymbolAtIndex,
477478 match: u8,
478479 sect: macho.section_64,
......@@ -538,7 +539,7 @@ pub fn getSourceSection(self: Object, index: u16) macho.section_64 {
538539 return self.sections.items[index];
539540}
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 {
542543 var it = LoadCommandIterator{
543544 .ncmds = self.header.ncmds,
544545 .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 {
549550 const dice = cmd.cast(macho.linkedit_data_command).?;
550551 const ndice = @divExact(dice.datasize, @sizeOf(macho.data_in_code_entry));
551552 return @ptrCast(
552 [*]const macho.data_in_code_entry,
553 @alignCast(@alignOf(macho.data_in_code_entry), &self.contents[dice.dataoff]),
553 [*]align(1) const macho.data_in_code_entry,
554 self.contents.ptr + dice.dataoff,
554555 )[0..ndice];
555556 },
556557 else => {},
......@@ -579,9 +580,15 @@ pub fn parseDwarfInfo(self: Object) error{Overflow}!dwarf.DwarfInfo {
579580 .debug_info = &[0]u8{},
580581 .debug_abbrev = &[0]u8{},
581582 .debug_str = &[0]u8{},
583 .debug_str_offsets = &[0]u8{},
582584 .debug_line = &[0]u8{},
583585 .debug_line_str = &[0]u8{},
584586 .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{},
585592 };
586593 for (self.sections.items) |sect| {
587594 const segname = sect.segName();
......@@ -593,12 +600,24 @@ pub fn parseDwarfInfo(self: Object) error{Overflow}!dwarf.DwarfInfo {
593600 di.debug_abbrev = try self.getSectionContents(sect);
594601 } else if (mem.eql(u8, sectname, "__debug_str")) {
595602 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);
596605 } else if (mem.eql(u8, sectname, "__debug_line")) {
597606 di.debug_line = try self.getSectionContents(sect);
598607 } else if (mem.eql(u8, sectname, "__debug_line_str")) {
599608 di.debug_line_str = try self.getSectionContents(sect);
600609 } else if (mem.eql(u8, sectname, "__debug_ranges")) {
601610 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);
602621 }
603622 }
604623 }
src/link/NvPtx.zig+1-1
......@@ -57,7 +57,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*NvPtx {
5757pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*NvPtx {
5858 if (!build_options.have_llvm) @panic("nvptx target requires a zig compiler with llvm enabled.");
5959 if (!options.use_llvm) return error.PtxArchNotSupported;
60 assert(options.object_format == .nvptx);
60 assert(options.target.ofmt == .nvptx);
6161
6262 const nvptx = try createEmpty(allocator, options);
6363 log.info("Opening .ptx target file {s}", .{sub_path});
src/link/Plan9.zig+1-1
......@@ -657,7 +657,7 @@ pub const base_tag = .plan9;
657657pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Plan9 {
658658 if (options.use_llvm)
659659 return error.LLVMBackendDoesNotSupportPlan9;
660 assert(options.object_format == .plan9);
660 assert(options.target.ofmt == .plan9);
661661
662662 const self = try createEmpty(allocator, options);
663663 errdefer self.base.destroy();
src/link/SpirV.zig+1-1
......@@ -99,7 +99,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*SpirV {
9999}
100100
101101pub 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
104104 if (options.use_llvm) return error.LLVM_BackendIsTODO_ForSpirV; // TODO: LLVM Doesn't support SpirV at all.
105105 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 {
282282};
283283
284284pub 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
287287 if (build_options.have_llvm and options.use_llvm) {
288288 return createEmpty(allocator, options);
......@@ -356,7 +356,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm {
356356 }
357357
358358 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;
360360 if (use_llvm and !use_stage1) {
361361 self.llvm_object = try LlvmObject.create(gpa, options);
362362 }
......@@ -378,7 +378,7 @@ fn parseObjectFile(self: *Wasm, path: []const u8) !bool {
378378 const file = try fs.cwd().openFile(path, .{});
379379 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) {
382382 error.InvalidMagicByte, error.NotObjectFile => return false,
383383 else => |e| return e,
384384 };
......@@ -463,8 +463,6 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
463463 continue;
464464 }
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).
468466 const maybe_existing = try self.globals.getOrPut(self.base.allocator, sym_name_index);
469467 if (!maybe_existing.found_existing) {
470468 maybe_existing.value_ptr.* = location;
......@@ -483,8 +481,15 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
483481 break :blk self.objects.items[file].name;
484482 } else self.name;
485483
486 if (!existing_sym.isUndefined()) {
487 if (!symbol.isUndefined()) {
484 if (!existing_sym.isUndefined()) outer: {
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.
488493 log.err("symbol '{s}' defined multiple times", .{sym_name});
489494 log.err(" first definition in '{s}'", .{existing_file_path});
490495 log.err(" next definition in '{s}'", .{object.name});
......@@ -502,6 +507,53 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
502507 return error.SymbolMismatchingType;
503508 }
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
505557 // when both symbols are weak, we skip overwriting
506558 if (existing_sym.isWeak() and symbol.isWeak()) {
507559 try self.discarded.put(self.base.allocator, location, existing_loc);
......@@ -543,8 +595,8 @@ fn resolveSymbolsInArchives(self: *Wasm) !void {
543595 // Parse object and and resolve symbols again before we check remaining
544596 // undefined symbols.
545597 const object_file_index = @intCast(u16, self.objects.items.len);
546 const object = try self.objects.addOne(self.base.allocator);
547 object.* = try archive.parseObject(self.base.allocator, offset.items[0]);
598 var object = try archive.parseObject(self.base.allocator, offset.items[0]);
599 try self.objects.append(self.base.allocator, object);
548600 try self.resolveSymbolsInObject(object_file_index);
549601
550602 // 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 {
797849 try self.resolved_symbols.put(self.base.allocator, atom.symbolLoc(), {});
798850}
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
800895/// Lowers a constant typed value to a local symbol and atom.
801896/// Returns the symbol index of the local
802897/// 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) !
25012596 // If there is no Zig code to compile, then we should skip flushing the output file because it
25022597 // will not be part of the linker line anyway.
25032598 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;
25052600 if (use_stage1) {
25062601 const obj_basename = try std.zig.binNameAlloc(arena, .{
25072602 .root_name = self.base.options.root_name,
......@@ -2711,7 +2806,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
27112806 if (self.base.options.module) |mod| {
27122807 // when we use stage1, we use the exports that stage1 provided us.
27132808 // 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;
27152810 if (use_stage1) {
27162811 for (comp.export_symbol_names.items) |symbol_name| {
27172812 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 {
30403135 for (self.segment_info.items) |segment_info| {
30413136 log.debug("Emit segment: {s} align({d}) flags({b})", .{
30423137 segment_info.name,
3043 @ctz(u32, segment_info.alignment),
3138 @ctz(segment_info.alignment),
30443139 segment_info.flags,
30453140 });
30463141 try leb.writeULEB128(writer, @intCast(u32, segment_info.name.len));
30473142 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));
30493144 try leb.writeULEB128(writer, segment_info.flags);
30503145 }
30513146
src/link/Wasm/Archive.zig+69-52
......@@ -15,6 +15,12 @@ name: []const u8,
1515
1616header: 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
1824/// Parsed table of contents.
1925/// Each symbol name points to a list of all definition
2026/// sites within the current static archive.
......@@ -53,32 +59,33 @@ const ar_hdr = extern struct {
5359 /// Always contains ARFMAG.
5460 ar_fmag: [2]u8,
5561
56 const NameOrLength = union(enum) {
57 Name: []const u8,
58 Length: u32,
62 const NameOrIndex = union(enum) {
63 name: []const u8,
64 index: u32,
5965 };
60 fn nameOrLength(self: ar_hdr) !NameOrLength {
61 const value = getValue(&self.ar_name);
66
67 fn nameOrIndex(archive: ar_hdr) !NameOrIndex {
68 const value = getValue(&archive.ar_name);
6269 const slash_index = mem.indexOfScalar(u8, value, '/') orelse return error.MalformedArchive;
6370 const len = value.len;
6471 if (slash_index == len - 1) {
6572 // Name stored directly
66 return NameOrLength{ .Name = value };
73 return NameOrIndex{ .name = value };
6774 } else {
6875 // Name follows the header directly and its length is encoded in
6976 // the name field.
70 const length = try std.fmt.parseInt(u32, value[slash_index + 1 ..], 10);
71 return NameOrLength{ .Length = length };
77 const index = try std.fmt.parseInt(u32, value[slash_index + 1 ..], 10);
78 return NameOrIndex{ .index = index };
7279 }
7380 }
7481
75 fn date(self: ar_hdr) !u64 {
76 const value = getValue(&self.ar_date);
82 fn date(archive: ar_hdr) !u64 {
83 const value = getValue(&archive.ar_date);
7784 return std.fmt.parseInt(u64, value, 10);
7885 }
7986
80 fn size(self: ar_hdr) !u32 {
81 const value = getValue(&self.ar_size);
87 fn size(archive: ar_hdr) !u32 {
88 const value = getValue(&archive.ar_size);
8289 return std.fmt.parseInt(u32, value, 10);
8390 }
8491
......@@ -87,18 +94,19 @@ const ar_hdr = extern struct {
8794 }
8895};
8996
90pub fn deinit(self: *Archive, allocator: Allocator) void {
91 for (self.toc.keys()) |*key| {
97pub fn deinit(archive: *Archive, allocator: Allocator) void {
98 for (archive.toc.keys()) |*key| {
9299 allocator.free(key.*);
93100 }
94 for (self.toc.values()) |*value| {
101 for (archive.toc.values()) |*value| {
95102 value.deinit(allocator);
96103 }
97 self.toc.deinit(allocator);
104 archive.toc.deinit(allocator);
105 allocator.free(archive.long_file_names);
98106}
99107
100pub fn parse(self: *Archive, allocator: Allocator) !void {
101 const reader = self.file.reader();
108pub fn parse(archive: *Archive, allocator: Allocator) !void {
109 const reader = archive.file.reader();
102110
103111 const magic = try reader.readBytesNoEof(SARMAG);
104112 if (!mem.eql(u8, &magic, ARMAG)) {
......@@ -106,38 +114,31 @@ pub fn parse(self: *Archive, allocator: Allocator) !void {
106114 return error.NotArchive;
107115 }
108116
109 self.header = try reader.readStruct(ar_hdr);
110 if (!mem.eql(u8, &self.header.ar_fmag, ARFMAG)) {
111 log.debug("invalid header delimiter: expected '{s}', found '{s}'", .{ ARFMAG, self.header.ar_fmag });
117 archive.header = try reader.readStruct(ar_hdr);
118 if (!mem.eql(u8, &archive.header.ar_fmag, ARFMAG)) {
119 log.debug("invalid header delimiter: expected '{s}', found '{s}'", .{ ARFMAG, archive.header.ar_fmag });
112120 return error.NotArchive;
113121 }
114122
115 try self.parseTableOfContents(allocator, reader);
123 try archive.parseTableOfContents(allocator, reader);
124 try archive.parseNameTable(allocator, reader);
116125}
117126
118fn parseName(allocator: Allocator, header: ar_hdr, reader: anytype) ![]u8 {
119 const name_or_length = try header.nameOrLength();
120 var name: []u8 = undefined;
121 switch (name_or_length) {
122 .Name => |n| {
123 name = try allocator.dupe(u8, n);
124 },
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]);
127fn parseName(archive: *const Archive, header: ar_hdr) ![]const u8 {
128 const name_or_index = try header.nameOrIndex();
129 switch (name_or_index) {
130 .name => |name| return name,
131 .index => |index| {
132 const name = mem.sliceTo(archive.long_file_names[index..], 0x0a);
133 return mem.trimRight(u8, name, "/");
131134 },
132135 }
133 return name;
134136}
135137
136fn parseTableOfContents(self: *Archive, allocator: Allocator, reader: anytype) !void {
137 log.debug("parsing table of contents for archive file '{s}'", .{self.name});
138fn parseTableOfContents(archive: *Archive, allocator: Allocator, reader: anytype) !void {
138139 // size field can have extra spaces padded in front as well as the end,
139140 // 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, " ");
141142 const sym_tab_size = try std.fmt.parseInt(u32, size_trimmed, 10);
142143
143144 const num_symbols = try reader.readIntBig(u32);
......@@ -157,7 +158,7 @@ fn parseTableOfContents(self: *Archive, allocator: Allocator, reader: anytype) !
157158
158159 var i: usize = 0;
159160 while (i < sym_tab.len) {
160 const string = std.mem.sliceTo(sym_tab[i..], 0);
161 const string = mem.sliceTo(sym_tab[i..], 0);
161162 if (string.len == 0) {
162163 i += 1;
163164 continue;
......@@ -165,7 +166,7 @@ fn parseTableOfContents(self: *Archive, allocator: Allocator, reader: anytype) !
165166 i += string.len;
166167 const name = try allocator.dupe(u8, string);
167168 errdefer allocator.free(name);
168 const gop = try self.toc.getOrPut(allocator, name);
169 const gop = try archive.toc.getOrPut(allocator, name);
169170 if (gop.found_existing) {
170171 allocator.free(name);
171172 } else {
......@@ -175,33 +176,49 @@ fn parseTableOfContents(self: *Archive, allocator: Allocator, reader: anytype) !
175176 }
176177}
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
178196/// From a given file offset, starts reading for a file header.
179197/// When found, parses the object file into an `Object` and returns it.
180pub fn parseObject(self: Archive, allocator: Allocator, file_offset: u32) !Object {
181 try self.file.seekTo(file_offset);
182 const reader = self.file.reader();
198pub fn parseObject(archive: Archive, allocator: Allocator, file_offset: u32) !Object {
199 try archive.file.seekTo(file_offset);
200 const reader = archive.file.reader();
183201 const header = try reader.readStruct(ar_hdr);
184 const current_offset = try self.file.getPos();
185 try self.file.seekTo(0);
202 const current_offset = try archive.file.getPos();
203 try archive.file.seekTo(0);
186204
187205 if (!mem.eql(u8, &header.ar_fmag, ARFMAG)) {
188206 log.err("invalid header delimiter: expected '{s}', found '{s}'", .{ ARFMAG, header.ar_fmag });
189207 return error.MalformedArchive;
190208 }
191209
192 const object_name = try parseName(allocator, header, reader);
193 defer allocator.free(object_name);
194
210 const object_name = try archive.parseName(header);
195211 const name = name: {
196212 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);
198214 break :name try std.fmt.allocPrint(allocator, "{s}({s})", .{ path, object_name });
199215 };
200216 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, .{});
203219 errdefer object_file.close();
204220
221 const object_file_size = try header.size();
205222 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);
207224}
src/link/Wasm/Object.zig+21-2
......@@ -105,14 +105,33 @@ pub const InitError = error{NotObjectFile} || ParseError || std.fs.File.ReadErro
105105
106106/// Initializes a new `Object` from a wasm object file.
107107/// 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 {
109111 var object: Object = .{
110112 .file = file,
111113 .name = try gpa.dupe(u8, name),
112114 };
113115
114116 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);
116135 errdefer object.deinit(gpa);
117136 if (!is_object_file) return error.NotObjectFile;
118137
src/main.zig+44-33
......@@ -378,6 +378,8 @@ const usage_build_generic =
378378 \\ -fno-lto Force-disable Link Time Optimization
379379 \\ -fstack-check Enable stack probing in unsafe builds
380380 \\ -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
381383 \\ -fsanitize-c Enable C undefined behavior detection in unsafe builds
382384 \\ -fno-sanitize-c Disable C undefined behavior detection in safe builds
383385 \\ -fvalgrind Include valgrind client requests in release builds
......@@ -668,6 +670,7 @@ fn buildOutputType(
668670 var want_unwind_tables: ?bool = null;
669671 var want_sanitize_c: ?bool = null;
670672 var want_stack_check: ?bool = null;
673 var want_stack_protector: ?u32 = null;
671674 var want_red_zone: ?bool = null;
672675 var omit_frame_pointer: ?bool = null;
673676 var want_valgrind: ?bool = null;
......@@ -718,7 +721,7 @@ fn buildOutputType(
718721 var test_filter: ?[]const u8 = null;
719722 var test_name_prefix: ?[]const u8 = null;
720723 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");
722725 var override_lib_dir: ?[]const u8 = try optionalStringEnvVar(arena, "ZIG_LIB_DIR");
723726 var main_pkg_path: ?[]const u8 = null;
724727 var clang_preprocessor_mode: Compilation.ClangPreprocessorMode = .no;
......@@ -1168,6 +1171,10 @@ fn buildOutputType(
11681171 want_stack_check = true;
11691172 } else if (mem.eql(u8, arg, "-fno-stack-check")) {
11701173 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;
11711178 } else if (mem.eql(u8, arg, "-mred-zone")) {
11721179 want_red_zone = true;
11731180 } else if (mem.eql(u8, arg, "-mno-red-zone")) {
......@@ -1521,6 +1528,12 @@ fn buildOutputType(
15211528 .no_color_diagnostics => color = .off,
15221529 .stack_check => want_stack_check = true,
15231530 .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,
15241537 .unwind_tables => want_unwind_tables = true,
15251538 .no_unwind_tables => want_unwind_tables = false,
15261539 .nostdlib => ensure_libc_on_non_freestanding = false,
......@@ -1657,7 +1670,8 @@ fn buildOutputType(
16571670 disable_c_depfile = true;
16581671 try clang_argv.appendSlice(it.other_args);
16591672 },
1660 .dep_file_mm => { // -MM
1673 .dep_file_to_stdout => { // -M, -MM
1674 // "Like -MD, but also implies -E and writes to stdout by default"
16611675 // "Like -MMD, but also implies -E and writes to stdout by default"
16621676 c_out_mode = .preprocessor;
16631677 disable_c_depfile = true;
......@@ -2191,6 +2205,7 @@ fn buildOutputType(
21912205 .arch_os_abi = target_arch_os_abi,
21922206 .cpu_features = target_mcpu,
21932207 .dynamic_linker = target_dynamic_linker,
2208 .object_format = target_ofmt,
21942209 };
21952210
21962211 // Before passing the mcpu string in for parsing, we convert any -m flags that were
......@@ -2493,28 +2508,7 @@ fn buildOutputType(
24932508 }
24942509 }
24952510
2496 const object_format: std.Target.ObjectFormat = blk: {
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 };
2511 const object_format = target_info.target.ofmt;
25182512
25192513 if (output_mode == .Obj and (object_format == .coff or object_format == .macho)) {
25202514 const total_obj_count = c_source_files.items.len +
......@@ -2568,7 +2562,6 @@ fn buildOutputType(
25682562 .target = target_info.target,
25692563 .output_mode = output_mode,
25702564 .link_mode = link_mode,
2571 .object_format = object_format,
25722565 .version = optional_version,
25732566 }),
25742567 },
......@@ -2858,7 +2851,6 @@ fn buildOutputType(
28582851 .emit_implib = emit_implib_resolved.data,
28592852 .link_mode = link_mode,
28602853 .dll_export_fns = dll_export_fns,
2861 .object_format = object_format,
28622854 .optimize_mode = optimize_mode,
28632855 .keep_source_files_loaded = false,
28642856 .clang_argv = clang_argv.items,
......@@ -2880,6 +2872,7 @@ fn buildOutputType(
28802872 .want_unwind_tables = want_unwind_tables,
28812873 .want_sanitize_c = want_sanitize_c,
28822874 .want_stack_check = want_stack_check,
2875 .want_stack_protector = want_stack_protector,
28832876 .want_red_zone = want_red_zone,
28842877 .omit_frame_pointer = omit_frame_pointer,
28852878 .want_valgrind = want_valgrind,
......@@ -2996,7 +2989,7 @@ fn buildOutputType(
29962989 return std.io.getStdOut().writeAll(try comp.generateBuiltinZigSource(arena));
29972990 }
29982991 if (arg_mode == .translate_c) {
2999 const stage1_mode = use_stage1 orelse build_options.is_stage1;
2992 const stage1_mode = use_stage1 orelse false;
30002993 return cmdTranslateC(comp, arena, have_enable_cache, stage1_mode);
30012994 }
30022995
......@@ -3172,11 +3165,11 @@ fn parseCrossTargetOrReportFatalError(
31723165 for (diags.arch.?.allCpuModels()) |cpu| {
31733166 help_text.writer().print(" {s}\n", .{cpu.name}) catch break :help;
31743167 }
3175 std.log.info("Available CPUs for architecture '{s}':\n{s}", .{
3168 std.log.info("available CPUs for architecture '{s}':\n{s}", .{
31763169 @tagName(diags.arch.?), help_text.items,
31773170 });
31783171 }
3179 fatal("Unknown CPU: '{s}'", .{diags.cpu_name.?});
3172 fatal("unknown CPU: '{s}'", .{diags.cpu_name.?});
31803173 },
31813174 error.UnknownCpuFeature => {
31823175 help: {
......@@ -3185,11 +3178,26 @@ fn parseCrossTargetOrReportFatalError(
31853178 for (diags.arch.?.allFeaturesList()) |feature| {
31863179 help_text.writer().print(" {s}: {s}\n", .{ feature.name, feature.description }) catch break :help;
31873180 }
3188 std.log.info("Available CPU features for architecture '{s}':\n{s}", .{
3181 std.log.info("available CPU features for architecture '{s}':\n{s}", .{
31893182 @tagName(diags.arch.?), help_text.items,
31903183 });
31913184 }
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.?});
31933201 },
31943202 else => |e| return e,
31953203 };
......@@ -3359,7 +3367,7 @@ fn updateModule(gpa: Allocator, comp: *Compilation, hook: AfterUpdateHook) !void
33593367
33603368 // If a .pdb file is part of the expected output, we must also copy
33613369 // 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;
33633371 const have_pdb = is_coff and !comp.bin_file.options.strip;
33643372 if (have_pdb) {
33653373 // Replace `.out` or `.exe` with `.pdb` on both the source and destination
......@@ -4226,6 +4234,7 @@ const FmtError = error{
42264234 NotOpenForWriting,
42274235 UnsupportedEncoding,
42284236 ConnectionResetByPeer,
4237 LockViolation,
42294238} || fs.File.OpenError;
42304239
42314240fn 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 {
46524661 lib_dir,
46534662 mcpu,
46544663 dep_file,
4655 dep_file_mm,
4664 dep_file_to_stdout,
46564665 framework_dir,
46574666 framework,
46584667 nostdlibinc,
......@@ -4668,6 +4677,8 @@ pub const ClangArgIterator = struct {
46684677 no_color_diagnostics,
46694678 stack_check,
46704679 no_stack_check,
4680 stack_protector,
4681 no_stack_protector,
46714682 strip,
46724683 exec_model,
46734684 emit_llvm,
src/mingw.zig-6
......@@ -93,12 +93,6 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
9393 "-D_WIN32_WINNT=0x0f00",
9494 "-D__MSVCRT_VERSION__=0x700",
9595 });
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 }
10296 c_source_files[i] = .{
10397 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
10498 "libc", "mingw", "crt", dep,
src/musl.zig+1
......@@ -215,6 +215,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
215215 .optimize_mode = comp.compilerRtOptMode(),
216216 .want_sanitize_c = false,
217217 .want_stack_check = false,
218 .want_stack_protector = 0,
218219 .want_red_zone = comp.bin_file.options.red_zone,
219220 .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer,
220221 .want_valgrind = false,
src/print_air.zig+2
......@@ -170,6 +170,7 @@ const Writer = struct {
170170 .bool_to_int,
171171 .ret,
172172 .ret_load,
173 .is_named_enum_value,
173174 .tag_name,
174175 .error_name,
175176 .sqrt,
......@@ -242,6 +243,7 @@ const Writer = struct {
242243 .popcount,
243244 .byte_swap,
244245 .bit_reverse,
246 .error_set_has_value,
245247 => try w.writeTyOp(s, inst),
246248
247249 .block,
src/print_zir.zig+76-29
......@@ -214,7 +214,6 @@ const Writer = struct {
214214 .trunc,
215215 .round,
216216 .tag_name,
217 .reify,
218217 .type_name,
219218 .frame_type,
220219 .frame_size,
......@@ -247,7 +246,6 @@ const Writer = struct {
247246
248247 .validate_array_init_ty => try self.writeValidateArrayInitTy(stream, inst),
249248 .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst),
250 .param_type => try self.writeParamType(stream, inst),
251249 .ptr_type => try self.writePtrType(stream, inst),
252250 .int => try self.writeInt(stream, inst),
253251 .int_big => try self.writeIntBig(stream, inst),
......@@ -500,6 +498,7 @@ const Writer = struct {
500498 .wasm_memory_size,
501499 .error_to_int,
502500 .int_to_error,
501 .reify,
503502 => {
504503 const inst_data = self.code.extraData(Zir.Inst.UnNode, extended.operand).data;
505504 const src = LazySrcLoc.nodeOffset(inst_data.node);
......@@ -605,16 +604,6 @@ const Writer = struct {
605604 try self.writeSrc(stream, inst_data.src());
606605 }
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
618607 fn writePtrType(
619608 self: *Writer,
620609 stream: anytype,
......@@ -1158,7 +1147,8 @@ const Writer = struct {
11581147 fn writeCall(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
11591148 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
11601149 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
11631153 if (extra.data.flags.ensure_result_used) {
11641154 try stream.writeAll("nodiscard ");
......@@ -1166,10 +1156,27 @@ const Writer = struct {
11661156 try stream.print(".{s}, ", .{@tagName(@intToEnum(std.builtin.CallOptions.Modifier, extra.data.flags.packed_modifier))});
11671157 try self.writeInstRef(stream, extra.data.callee);
11681158 try stream.writeAll(", [");
1169 for (args) |arg, i| {
1170 if (i != 0) try stream.writeAll(", ");
1171 try self.writeInstRef(stream, arg);
1159
1160 self.indent += 2;
1161 if (args_len != 0) {
1162 try stream.writeAll("\n");
11721163 }
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
11731180 try stream.writeAll("]) ");
11741181 try self.writeSrc(stream, inst_data.src());
11751182 }
......@@ -1238,13 +1245,36 @@ const Writer = struct {
12381245
12391246 try self.writeFlag(stream, "known_non_opv, ", small.known_non_opv);
12401247 try self.writeFlag(stream, "known_comptime_only, ", small.known_comptime_only);
1241 try stream.print("{s}, {s}, ", .{
1242 @tagName(small.name_strategy), @tagName(small.layout),
1243 });
1248
1249 try stream.print("{s}, ", .{@tagName(small.name_strategy)});
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
12451271 if (decls_len == 0) {
12461272 try stream.writeAll("{}, ");
12471273 } 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
12481278 try stream.writeAll("{\n");
12491279 self.indent += 2;
12501280 extra_index = try self.writeDecls(stream, decls_len, extra_index);
......@@ -1413,22 +1443,31 @@ const Writer = struct {
14131443 try self.writeFlag(stream, "autoenum, ", small.auto_enum_tag);
14141444
14151445 if (decls_len == 0) {
1416 try stream.writeAll("{}, ");
1446 try stream.writeAll("{}");
14171447 } 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
14181452 try stream.writeAll("{\n");
14191453 self.indent += 2;
14201454 extra_index = try self.writeDecls(stream, decls_len, extra_index);
14211455 self.indent -= 2;
14221456 try stream.writeByteNTimes(' ', self.indent);
1423 try stream.writeAll("}, ");
1457 try stream.writeAll("}");
14241458 }
14251459
1426 assert(fields_len != 0);
1427
14281460 if (tag_type_ref != .none) {
1429 try self.writeInstRef(stream, tag_type_ref);
14301461 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;
14311469 }
1470 try stream.writeAll(", ");
14321471
14331472 const body = self.code.extra[extra_index..][0..body_len];
14341473 extra_index += body.len;
......@@ -1662,6 +1701,10 @@ const Writer = struct {
16621701 if (decls_len == 0) {
16631702 try stream.writeAll("{}, ");
16641703 } 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
16651708 try stream.writeAll("{\n");
16661709 self.indent += 2;
16671710 extra_index = try self.writeDecls(stream, decls_len, extra_index);
......@@ -1678,13 +1721,13 @@ const Writer = struct {
16781721 const body = self.code.extra[extra_index..][0..body_len];
16791722 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);
16811727 if (fields_len == 0) {
1682 assert(body.len == 0);
1683 try stream.writeAll("{}, {})");
1728 try stream.writeAll(", {})");
1729 self.parent_decl_node = prev_parent_decl_node;
16841730 } 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);
16881731 try stream.writeAll(", {\n");
16891732
16901733 self.indent += 2;
......@@ -1755,6 +1798,10 @@ const Writer = struct {
17551798 if (decls_len == 0) {
17561799 try stream.writeAll("{})");
17571800 } 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
17581805 try stream.writeAll("{\n");
17591806 self.indent += 2;
17601807 _ = try self.writeDecls(stream, decls_len, extra_index);
src/stage1.zig+2-2
......@@ -18,7 +18,7 @@ const target_util = @import("target.zig");
1818
1919comptime {
2020 assert(builtin.link_libc);
21 assert(build_options.is_stage1);
21 assert(build_options.have_stage1);
2222 assert(build_options.have_llvm);
2323 if (!builtin.is_test) {
2424 @export(main, .{ .name = "main" });
......@@ -416,7 +416,7 @@ export fn stage2_add_link_lib(
416416 const target = comp.getTarget();
417417 const is_libc = target_util.is_libc_lib_name(target, lib_name);
418418 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) {
420420 return "dependency on libc must be explicitly specified in the build command";
421421 }
422422 return null;
src/stage1/all_types.hpp+1
......@@ -1116,6 +1116,7 @@ struct AstNodeContainerDecl {
11161116 ContainerLayout layout;
11171117
11181118 bool auto_enum, is_root; // union(enum)
1119 bool unsupported_explicit_backing_int;
11191120};
11201121
11211122struct AstNodeErrorSetField {
src/stage1/analyze.cpp+6
......@@ -3034,6 +3034,12 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
30343034
30353035 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
30373043 if (struct_type->data.structure.resolve_loop_flag_zero_bits) {
30383044 if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) {
30393045 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
53745374 if (arg0_value == ag->codegen->invalid_inst_src)
53755375 return arg0_value;
53765376
5377 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
5378 Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope);
5379 if (arg1_value == ag->codegen->invalid_inst_src)
5380 return arg1_value;
5377 Stage1ZirInst *arg1_value = arg0_value;
5378 arg0_value = ir_build_typeof_1(ag, scope, arg0_node, arg1_value);
53815379
53825380 Stage1ZirInst *result;
53835381 switch (builtin_fn->id) {
src/stage1/codegen.cpp+6-6
......@@ -9977,11 +9977,11 @@ static void define_builtin_fns(CodeGen *g) {
99779977 create_builtin_fn(g, BuiltinFnIdCInclude, "cInclude", 1);
99789978 create_builtin_fn(g, BuiltinFnIdCDefine, "cDefine", 2);
99799979 create_builtin_fn(g, BuiltinFnIdCUndef, "cUndef", 1);
9980 create_builtin_fn(g, BuiltinFnIdCtz, "ctz", 2);
9981 create_builtin_fn(g, BuiltinFnIdClz, "clz", 2);
9982 create_builtin_fn(g, BuiltinFnIdPopCount, "popCount", 2);
9983 create_builtin_fn(g, BuiltinFnIdBswap, "byteSwap", 2);
9984 create_builtin_fn(g, BuiltinFnIdBitReverse, "bitReverse", 2);
9980 create_builtin_fn(g, BuiltinFnIdCtz, "ctz", 1);
9981 create_builtin_fn(g, BuiltinFnIdClz, "clz", 1);
9982 create_builtin_fn(g, BuiltinFnIdPopCount, "popCount", 1);
9983 create_builtin_fn(g, BuiltinFnIdBswap, "byteSwap", 1);
9984 create_builtin_fn(g, BuiltinFnIdBitReverse, "bitReverse", 1);
99859985 create_builtin_fn(g, BuiltinFnIdImport, "import", 1);
99869986 create_builtin_fn(g, BuiltinFnIdCImport, "cImport", 1);
99879987 create_builtin_fn(g, BuiltinFnIdErrName, "errorName", 1);
......@@ -10261,13 +10261,13 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
1026110261 buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded));
1026210262 buf_appendf(contents, "pub const abi = std.Target.Abi.%s;\n", cur_abi);
1026310263 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);
1026510264 buf_appendf(contents, "pub const os = std.Target.Os.Tag.defaultVersionRange(.%s, .%s);\n", cur_os, cur_arch);
1026610265 buf_appendf(contents,
1026710266 "pub const target = std.Target{\n"
1026810267 " .cpu = cpu,\n"
1026910268 " .os = os,\n"
1027010269 " .abi = abi,\n"
10270 " .ofmt = object_format,\n"
1027110271 "};\n"
1027210272 );
1027310273
src/stage1/ir.cpp+28-12
......@@ -18640,7 +18640,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *sour
1864018640 result->special = ConstValSpecialStatic;
1864118641 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);
1864418644 result->data.x_struct.fields = fields;
1864518645
1864618646 // layout: ContainerLayout
......@@ -18648,8 +18648,17 @@ static Error ir_make_type_info_value(IrAnalyze *ira, Scope *scope, AstNode *sour
1864818648 fields[0]->special = ConstValSpecialStatic;
1864918649 fields[0]->type = ir_type_info_get_type(ira, "ContainerLayout", nullptr);
1865018650 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
1865118660 // fields: []Type.StructField
18652 ensure_field_index(result->type, "fields", 1);
18661 ensure_field_index(result->type, "fields", 2);
1865318662
1865418663 ZigType *type_info_struct_field_type = ir_type_info_get_type(ira, "StructField", nullptr);
1865518664 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
1866318672 struct_field_array->data.x_array.special = ConstArraySpecialNone;
1866418673 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
1866818677 for (uint32_t struct_field_index = 0; struct_field_index < struct_field_count; struct_field_index++) {
1866918678 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
1871018719 struct_field_val->parent.data.p_array.elem_index = struct_field_index;
1871118720 }
1871218721 // decls: []Type.Declaration
18713 ensure_field_index(result->type, "decls", 2);
18714 if ((err = ir_make_type_info_decls(ira, source_node, fields[2],
18722 ensure_field_index(result->type, "decls", 3);
18723 if ((err = ir_make_type_info_decls(ira, source_node, fields[3],
1871518724 type_entry->data.structure.decls_scope, false)))
1871618725 {
1871718726 return err;
1871818727 }
1871918728
1872018729 // is_tuple: bool
18721 ensure_field_index(result->type, "is_tuple", 3);
18722 fields[3]->special = ConstValSpecialStatic;
18723 fields[3]->type = g->builtin_types.entry_bool;
18724 fields[3]->data.x_bool = is_tuple(type_entry);
18730 ensure_field_index(result->type, "is_tuple", 4);
18731 fields[4]->special = ConstValSpecialStatic;
18732 fields[4]->type = g->builtin_types.entry_bool;
18733 fields[4]->data.x_bool = is_tuple(type_entry);
1872518734
1872618735 break;
1872718736 }
......@@ -19313,7 +19322,14 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_
1931319322 assert(layout_value->type == ir_type_info_get_type(ira, "ContainerLayout", nullptr));
1931419323 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);
1931719333 if (fields_value == nullptr)
1931819334 return ira->codegen->invalid_inst_gen->value->type;
1931919335 assert(fields_value->special == ConstValSpecialStatic);
......@@ -19322,7 +19338,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_
1932219338 ZigValue *fields_len_value = fields_value->data.x_struct.fields[slice_len_index];
1932319339 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);
1932619342 if (decls_value == nullptr)
1932719343 return ira->codegen->invalid_inst_gen->value->type;
1932819344 assert(decls_value->special == ConstValSpecialStatic);
......@@ -19335,7 +19351,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, Scope *scope, AstNode *source_
1933519351 }
1933619352
1933719353 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)))
1933919355 return ira->codegen->invalid_inst_gen->value->type;
1934019356
1934119357 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) {
29022902}
29032903
29042904// ContainerDeclType
2905// <- KEYWORD_struct
2905// <- KEYWORD_struct (LPAREN Expr RPAREN)?
29062906// / KEYWORD_enum (LPAREN Expr RPAREN)?
29072907// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?
29082908// / KEYWORD_opaque
29092909static AstNode *ast_parse_container_decl_type(ParseContext *pc) {
29102910 TokenIndex first = eat_token_if(pc, TokenIdKeywordStruct);
29112911 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 }
29122918 AstNode *res = ast_create_node(pc, NodeTypeContainerDecl, first);
29132919 res->data.container_decl.init_arg_expr = nullptr;
29142920 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;
29152924 return res;
29162925 }
29172926
src/target.zig+9
......@@ -321,6 +321,15 @@ pub fn supportsStackProbing(target: std.Target) bool {
321321 (target.cpu.arch == .i386 or target.cpu.arch == .x86_64);
322322}
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
324333pub fn supportsReturnAddress(target: std.Target) bool {
325334 return switch (target.cpu.arch) {
326335 .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;
2525const hr = "=" ** 80;
2626
2727test {
28 if (build_options.is_stage1) {
28 if (build_options.have_stage1) {
2929 @import("stage1.zig").os_init();
3030 }
3131
......@@ -606,7 +606,6 @@ pub const TestContext = struct {
606606 output_mode: std.builtin.OutputMode,
607607 optimize_mode: std.builtin.Mode = .Debug,
608608 updates: std.ArrayList(Update),
609 object_format: ?std.Target.ObjectFormat = null,
610609 emit_h: bool = false,
611610 is_test: bool = false,
612611 expect_exact: bool = false,
......@@ -782,12 +781,13 @@ pub const TestContext = struct {
782781 pub fn exeFromCompiledC(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case {
783782 const prefixed_name = std.fmt.allocPrint(ctx.arena, "CBE: {s}", .{name}) catch
784783 @panic("out of memory");
784 var target_adjusted = target;
785 target_adjusted.ofmt = std.Target.ObjectFormat.c;
785786 ctx.cases.append(Case{
786787 .name = prefixed_name,
787 .target = target,
788 .target = target_adjusted,
788789 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
789790 .output_mode = .Exe,
790 .object_format = .c,
791791 .files = std.ArrayList(File).init(ctx.arena),
792792 }) catch @panic("out of memory");
793793 return &ctx.cases.items[ctx.cases.items.len - 1];
......@@ -851,12 +851,13 @@ pub const TestContext = struct {
851851
852852 /// Adds a test case for Zig or ZIR input, producing C code.
853853 pub fn addC(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case {
854 var target_adjusted = target;
855 target_adjusted.ofmt = std.Target.ObjectFormat.c;
854856 ctx.cases.append(Case{
855857 .name = name,
856 .target = target,
858 .target = target_adjusted,
857859 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
858860 .output_mode = .Obj,
859 .object_format = .c,
860861 .files = std.ArrayList(File).init(ctx.arena),
861862 }) catch @panic("out of memory");
862863 return &ctx.cases.items[ctx.cases.items.len - 1];
......@@ -1224,10 +1225,6 @@ pub const TestContext = struct {
12241225 try aux_thread_pool.init(self.gpa);
12251226 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
12311228 // Use the same global cache dir for all the tests, such that we for example don't have to
12321229 // rebuild musl libc for every case (when LLVM backend is enabled).
12331230 var global_tmp = std.testing.tmpDir(.{});
......@@ -1245,9 +1242,6 @@ pub const TestContext = struct {
12451242 defer self.gpa.free(global_cache_directory.path.?);
12461243
12471244 {
1248 var wait_group: WaitGroup = .{};
1249 defer wait_group.wait();
1250
12511245 for (self.cases.items) |*case| {
12521246 if (build_options.skip_non_native) {
12531247 if (case.target.getCpuArch() != builtin.cpu.arch)
......@@ -1267,17 +1261,19 @@ pub const TestContext = struct {
12671261 if (std.mem.indexOf(u8, case.name, test_filter) == null) continue;
12681262 }
12691263
1270 wait_group.start();
1271 try case_thread_pool.spawn(workerRunOneCase, .{
1264 var prg_node = root_node.start(case.name, case.updates.items.len);
1265 prg_node.activate();
1266 defer prg_node.end();
1267
1268 case.result = runOneCase(
12721269 self.gpa,
1273 root_node,
1274 case,
1270 &prg_node,
1271 case.*,
12751272 zig_lib_directory,
12761273 &aux_thread_pool,
12771274 global_cache_directory,
12781275 host,
1279 &wait_group,
1280 });
1276 );
12811277 }
12821278 }
12831279
......@@ -1295,33 +1291,6 @@ pub const TestContext = struct {
12951291 }
12961292 }
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
13251294 fn runOneCase(
13261295 allocator: Allocator,
13271296 root_node: *std.Progress.Node,
......@@ -1533,7 +1502,6 @@ pub const TestContext = struct {
15331502 .root_name = "test_case",
15341503 .target = target,
15351504 .output_mode = case.output_mode,
1536 .object_format = case.object_format,
15371505 });
15381506
15391507 const emit_directory: Compilation.Directory = .{
......@@ -1569,7 +1537,6 @@ pub const TestContext = struct {
15691537 .emit_h = emit_h,
15701538 .main_pkg = &main_pkg,
15711539 .keep_source_files_loaded = true,
1572 .object_format = case.object_format,
15731540 .is_native_os = case.target.isNativeOs(),
15741541 .is_native_abi = case.target.isNativeAbi(),
15751542 .dynamic_linker = target_info.dynamic_linker.get(),
......@@ -1814,7 +1781,7 @@ pub const TestContext = struct {
18141781 ".." ++ ss ++ "{s}" ++ ss ++ "{s}",
18151782 .{ &tmp.sub_path, bin_name },
18161783 );
1817 if (case.object_format != null and case.object_format.? == .c) {
1784 if (case.target.ofmt != null and case.target.ofmt.? == .c) {
18181785 if (host.getExternalExecutor(target_info, .{ .link_libc = true }) != .native) {
18191786 // We wouldn't be able to run the compiled C code.
18201787 continue :update; // Pass test.
src/translate_c.zig+39-12
......@@ -439,6 +439,24 @@ pub fn translate(
439439 return ast.render(gpa, context.global_scope.nodes.items);
440440}
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
442460fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void {
443461 if (!ast_unit.visitLocalTopLevelDecls(c, declVisitorNamesOnlyC)) {
444462 return error.OutOfMemory;
......@@ -455,7 +473,10 @@ fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void {
455473 const macro = @ptrCast(*clang.MacroDefinitionRecord, entity);
456474 const raw_name = macro.getName_getNameStart();
457475 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 }
459480 },
460481 else => {},
461482 }
......@@ -4001,8 +4022,7 @@ fn transCPtrCast(
40014022 // For opaque types a ptrCast is enough
40024023 expr
40034024 else blk: {
4004 const child_type_node = try transQualType(c, scope, child_type, loc);
4005 const alignof = try Tag.std_meta_alignment.create(c.arena, child_type_node);
4025 const alignof = try Tag.std_meta_alignment.create(c.arena, dst_type_node);
40064026 const align_cast = try Tag.align_cast.create(c.arena, .{ .lhs = alignof, .rhs = expr });
40074027 break :blk align_cast;
40084028 };
......@@ -5447,6 +5467,16 @@ fn tokenizeMacro(source: []const u8, tok_list: *std.ArrayList(CToken)) Error!voi
54475467 }
54485468}
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
54505480fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
54515481 // TODO if we see #undef, delete it from the table
54525482 var it = unit.getLocalPreprocessingEntities_begin();
......@@ -5463,22 +5493,18 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
54635493 const macro = @ptrCast(*clang.MacroDefinitionRecord, entity);
54645494 const raw_name = macro.getName_getNameStart();
54655495 const begin_loc = macro.getSourceRange_getBegin();
5466 const end_loc = clang.Lexer.getLocForEndOfToken(macro.getSourceRange_getEnd(), c.source_manager, unit);
54675496
54685497 const name = try c.str(raw_name);
54695498 if (scope.containsNow(name)) {
54705499 continue;
54715500 }
54725501
5473 const begin_c = c.source_manager.getCharacterData(begin_loc);
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];
5502 const source = getMacroText(unit, c, macro);
54775503
5478 try tokenizeMacro(slice, &tok_list);
5504 try tokenizeMacro(source, &tok_list);
54795505
54805506 var macro_ctx = MacroCtx{
5481 .source = slice,
5507 .source = source,
54825508 .list = tok_list.items,
54835509 .name = name,
54845510 .loc = begin_loc,
......@@ -5491,7 +5517,8 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
54915517 // if it equals itself, ignore. for example, from stdio.h:
54925518 // #define stdin stdin
54935519 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]));
54955522 continue;
54965523 }
54975524 },
......@@ -5648,7 +5675,7 @@ fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!Node {
56485675 switch (m.list[m.i].id) {
56495676 .IntegerLiteral => |suffix| {
56505677 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') {
56525679 switch (lit_bytes[1]) {
56535680 '0'...'7' => {
56545681 // Octal
src/type.zig+180-132
......@@ -2310,6 +2310,8 @@ pub const Type = extern union {
23102310 /// fields will count towards the ABI size. For example, `struct {T: type, x: i32}`
23112311 /// hasRuntimeBits()=true and abiSize()=4
23122312 /// * 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.
23132315 /// When `ignore_comptime_only` is true, then types that are comptime only
23142316 /// may return false positives.
23152317 pub fn hasRuntimeBitsAdvanced(
......@@ -2376,6 +2378,32 @@ pub const Type = extern union {
23762378 .error_set_merged,
23772379 => 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
23792407 // These are false because they are comptime-only types.
23802408 .single_const_pointer_to_comptime_int,
23812409 .void,
......@@ -2399,30 +2427,6 @@ pub const Type = extern union {
23992427 .fn_ccc_void_no_args,
24002428 => 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
24262430 .optional => {
24272431 var buf: Payload.ElemType = undefined;
24282432 const child_ty = ty.optionalChild(&buf);
......@@ -2450,9 +2454,9 @@ pub const Type = extern union {
24502454 _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty);
24512455 }
24522456 assert(struct_obj.haveFieldTypes());
2453 for (struct_obj.fields.values()) |value| {
2454 if (value.is_comptime) continue;
2455 if (try value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit))
2457 for (struct_obj.fields.values()) |field| {
2458 if (field.is_comptime) continue;
2459 if (try field.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit))
24562460 return true;
24572461 } else {
24582462 return false;
......@@ -2461,7 +2465,7 @@ pub const Type = extern union {
24612465
24622466 .enum_full => {
24632467 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);
24652469 },
24662470 .enum_simple => {
24672471 const enum_simple = ty.castTag(.enum_simple).?.data;
......@@ -2491,6 +2495,7 @@ pub const Type = extern union {
24912495 if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit)) {
24922496 return true;
24932497 }
2498
24942499 if (sema_kit) |sk| {
24952500 _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty);
24962501 }
......@@ -3000,9 +3005,17 @@ pub const Type = extern union {
30003005 .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) },
30013006 };
30023007 if (struct_obj.layout == .Packed) {
3003 var buf: Type.Payload.Bits = undefined;
3004 const int_ty = struct_obj.packedIntegerType(target, &buf);
3005 return AbiAlignmentAdvanced{ .scalar = int_ty.abiAlignment(target) };
3008 switch (strat) {
3009 .sema_kit => |sk| try sk.sema.resolveTypeLayout(sk.block, sk.src, ty),
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) };
30063019 }
30073020
30083021 const fields = ty.structFields();
......@@ -3021,6 +3034,15 @@ pub const Type = extern union {
30213034 },
30223035 };
30233036 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 }
30243046 }
30253047 return AbiAlignmentAdvanced{ .scalar = big_align };
30263048 },
......@@ -3105,6 +3127,13 @@ pub const Type = extern union {
31053127 .sema_kit => unreachable, // handled above
31063128 .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) },
31073129 };
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
31093138 var max_align: u32 = 0;
31103139 if (have_tag) max_align = union_obj.tag_ty.abiAlignment(target);
......@@ -3192,17 +3221,16 @@ pub const Type = extern union {
31923221 .Packed => {
31933222 const struct_obj = ty.castTag(.@"struct").?.data;
31943223 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),
31963225 .lazy => |arena| {
3197 if (!struct_obj.haveFieldTypes()) {
3226 if (!struct_obj.haveLayout()) {
31983227 return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) };
31993228 }
32003229 },
32013230 .eager => {},
32023231 }
3203 var buf: Type.Payload.Bits = undefined;
3204 const int_ty = struct_obj.packedIntegerType(target, &buf);
3205 return AbiSizeAdvanced{ .scalar = int_ty.abiSize(target) };
3232 assert(struct_obj.haveLayout());
3233 return AbiSizeAdvanced{ .scalar = struct_obj.backing_int_ty.abiSize(target) };
32063234 },
32073235 else => {
32083236 switch (strat) {
......@@ -3253,8 +3281,8 @@ pub const Type = extern union {
32533281
32543282 .array_u8 => return AbiSizeAdvanced{ .scalar = ty.castTag(.array_u8).?.data },
32553283 .array_u8_sentinel_0 => return AbiSizeAdvanced{ .scalar = ty.castTag(.array_u8_sentinel_0).?.data + 1 },
3256 .array, .vector => {
3257 const payload = ty.cast(Payload.Array).?.data;
3284 .array => {
3285 const payload = ty.castTag(.array).?.data;
32583286 switch (try payload.elem_type.abiSizeAdvanced(target, strat)) {
32593287 .scalar => |elem_size| return AbiSizeAdvanced{ .scalar = payload.len * elem_size },
32603288 .val => switch (strat) {
......@@ -3276,6 +3304,28 @@ pub const Type = extern union {
32763304 }
32773305 },
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
32793329 .isize,
32803330 .usize,
32813331 .@"anyframe",
......@@ -3319,7 +3369,13 @@ pub const Type = extern union {
33193369 .f128 => return AbiSizeAdvanced{ .scalar = 16 },
33203370
33213371 .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 },
33233379 .x86_64 => return AbiSizeAdvanced{ .scalar = 16 },
33243380 else => {
33253381 var payload: Payload.Bits = .{
......@@ -4236,11 +4292,18 @@ pub const Type = extern union {
42364292
42374293 pub fn unionFieldType(ty: Type, enum_tag: Value, mod: *Module) Type {
42384294 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).?;
42404296 assert(union_obj.haveFieldTypes());
42414297 return union_obj.fields.values()[index].ty;
42424298 }
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
42444307 pub fn unionHasAllZeroBitFieldTypes(ty: Type) bool {
42454308 return ty.cast(Payload.Union).?.data.hasAllZeroBitFieldTypes();
42464309 }
......@@ -4530,6 +4593,12 @@ pub const Type = extern union {
45304593
45314594 .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
45334602 else => unreachable,
45344603 };
45354604 }
......@@ -4910,33 +4979,38 @@ pub const Type = extern union {
49104979 const s = ty.castTag(.@"struct").?.data;
49114980 assert(s.haveFieldTypes());
49124981 for (s.fields.values()) |field| {
4913 if (field.ty.onePossibleValue() == null) {
4914 return null;
4915 }
4982 if (field.is_comptime) continue;
4983 if (field.ty.onePossibleValue() != null) continue;
4984 return null;
49164985 }
49174986 return Value.initTag(.empty_struct_value);
49184987 },
49194988
49204989 .tuple, .anon_struct => {
49214990 const tuple = ty.tupleFields();
4922 for (tuple.values) |val| {
4923 if (val.tag() == .unreachable_value) {
4924 return null; // non-comptime field
4925 }
4991 for (tuple.values) |val, i| {
4992 const is_comptime = val.tag() != .unreachable_value;
4993 if (is_comptime) continue;
4994 if (tuple.types[i].onePossibleValue() != null) continue;
4995 return null;
49264996 }
49274997 return Value.initTag(.empty_struct_value);
49284998 },
49294999
49305000 .enum_numbered => {
49315001 const enum_numbered = ty.castTag(.enum_numbered).?.data;
4932 if (enum_numbered.fields.count() == 1) {
4933 return enum_numbered.values.keys()[0];
4934 } else {
5002 // An explicit tag type is always provided for enum_numbered.
5003 if (enum_numbered.tag_ty.hasRuntimeBits()) {
49355004 return null;
49365005 }
5006 assert(enum_numbered.fields.count() == 1);
5007 return enum_numbered.values.keys()[0];
49375008 },
49385009 .enum_full => {
49395010 const enum_full = ty.castTag(.enum_full).?.data;
5011 if (enum_full.tag_ty.hasRuntimeBits()) {
5012 return null;
5013 }
49405014 if (enum_full.fields.count() == 1) {
49415015 if (enum_full.values.count() == 0) {
49425016 return Value.zero;
......@@ -5271,7 +5345,8 @@ pub const Type = extern union {
52715345 .enum_numbered => return ty.castTag(.enum_numbered).?.data.tag_ty,
52725346 .enum_simple => {
52735347 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);
52755350 buffer.* = .{
52765351 .base = .{ .tag = .int_unsigned },
52775352 .data = bits,
......@@ -5492,7 +5567,7 @@ pub const Type = extern union {
54925567 .@"struct" => {
54935568 const struct_obj = ty.castTag(.@"struct").?.data;
54945569 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);
54965571 },
54975572 .@"union", .union_safety_tagged, .union_tagged => {
54985573 const union_obj = ty.cast(Payload.Union).?.data;
......@@ -5591,19 +5666,22 @@ pub const Type = extern union {
55915666 target: Target,
55925667
55935668 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)
55955671 return null;
55965672
5597 const field = it.struct_obj.fields.values()[it.field];
5598 defer it.field += 1;
5599 if (!field.ty.hasRuntimeBits() or field.is_comptime)
5600 return FieldOffset{ .field = it.field, .offset = it.offset };
5673 const field = it.struct_obj.fields.values()[i];
5674 it.field += 1;
5675
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);
56035681 it.big_align = @maximum(it.big_align, field_align);
5604 it.offset = std.mem.alignForwardGeneric(u64, it.offset, field_align);
5605 defer it.offset += field.ty.abiSize(it.target);
5606 return FieldOffset{ .field = it.field, .offset = it.offset };
5682 const field_offset = std.mem.alignForwardGeneric(u64, it.offset, field_align);
5683 it.offset = field_offset + field.ty.abiSize(it.target);
5684 return FieldOffset{ .field = i, .offset = field_offset };
56075685 }
56085686 };
56095687
......@@ -5771,50 +5849,6 @@ pub const Type = extern union {
57715849 }
57725850 }
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
58185852 /// This enum does not directly correspond to `std.builtin.TypeId` because
58195853 /// it has extra enum tags in it, as a way of using less memory. For example,
58205854 /// even though Zig recognizes `*align(10) i32` and `*i32` both as Pointer types
......@@ -6345,6 +6379,8 @@ pub const Type = extern union {
63456379 pub const @"anyopaque" = initTag(.anyopaque);
63466380 pub const @"null" = initTag(.@"null");
63476381
6382 pub const err_int = Type.u16;
6383
63486384 pub fn ptr(arena: Allocator, mod: *Module, data: Payload.Pointer.Data) !Type {
63496385 const target = mod.getTarget();
63506386
......@@ -6535,6 +6571,11 @@ pub const CType = enum {
65356571 .long, .ulong => return 32,
65366572 .longlong, .ulonglong, .longdouble => return 64,
65376573 },
6574 .avr => switch (self) {
6575 .short, .ushort, .int, .uint => return 16,
6576 .long, .ulong, .longdouble => return 32,
6577 .longlong, .ulonglong => return 64,
6578 },
65386579 else => switch (self) {
65396580 .short, .ushort => return 16,
65406581 .int, .uint => return 32,
......@@ -6573,31 +6614,42 @@ pub const CType = enum {
65736614 .emscripten,
65746615 .plan9,
65756616 .solaris,
6576 => switch (self) {
6577 .short, .ushort => return 16,
6578 .int, .uint => return 32,
6579 .long, .ulong => return target.cpu.arch.ptrBitWidth(),
6580 .longlong, .ulonglong => return 64,
6581 .longdouble => switch (target.cpu.arch) {
6582 .i386, .x86_64 => return 80,
6617 .haiku,
6618 .ananas,
6619 .fuchsia,
6620 .minix,
6621 => switch (target.cpu.arch) {
6622 .avr => switch (self) {
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,
6585 .aarch64,
6586 .aarch64_be,
6587 .aarch64_32,
6588 .s390x,
6589 .mips64,
6590 .mips64el,
6591 .sparc,
6592 .sparc64,
6593 .sparcel,
6594 .powerpc,
6595 .powerpcle,
6596 .powerpc64,
6597 .powerpc64le,
6598 => return 128,
6635 .riscv64,
6636 .aarch64,
6637 .aarch64_be,
6638 .aarch64_32,
6639 .s390x,
6640 .mips64,
6641 .mips64el,
6642 .sparc,
6643 .sparc64,
6644 .sparcel,
6645 .powerpc,
6646 .powerpcle,
6647 .powerpc64,
6648 .powerpc64le,
6649 => return 128,
65996650
6600 else => return 64,
6651 else => return 64,
6652 },
66016653 },
66026654 },
66036655
......@@ -6617,14 +6669,10 @@ pub const CType = enum {
66176669 },
66186670 },
66196671
6620 .ananas,
66216672 .cloudabi,
6622 .fuchsia,
66236673 .kfreebsd,
66246674 .lv2,
66256675 .zos,
6626 .haiku,
6627 .minix,
66286676 .rtems,
66296677 .nacl,
66306678 .aix,
src/value.zig+75-66
......@@ -1194,6 +1194,16 @@ pub const Value = extern union {
11941194 return switch (self.tag()) {
11951195 .bool_true, .one => true,
11961196 .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 },
11971207 else => unreachable,
11981208 };
11991209 }
......@@ -1572,7 +1582,7 @@ pub const Value = extern union {
15721582 .one, .bool_true => return ty_bits - 1,
15731583
15741584 .int_u64 => {
1575 const big = @clz(u64, val.castTag(.int_u64).?.data);
1585 const big = @clz(val.castTag(.int_u64).?.data);
15761586 return big + ty_bits - 64;
15771587 },
15781588 .int_i64 => {
......@@ -1589,7 +1599,7 @@ pub const Value = extern union {
15891599 while (i != 0) {
15901600 i -= 1;
15911601 const limb = bigint.limbs[i];
1592 const this_limb_lz = @clz(std.math.big.Limb, limb);
1602 const this_limb_lz = @clz(limb);
15931603 total_limb_lz += this_limb_lz;
15941604 if (this_limb_lz != bits_per_limb) break;
15951605 }
......@@ -1616,7 +1626,7 @@ pub const Value = extern union {
16161626 .one, .bool_true => return 0,
16171627
16181628 .int_u64 => {
1619 const big = @ctz(u64, val.castTag(.int_u64).?.data);
1629 const big = @ctz(val.castTag(.int_u64).?.data);
16201630 return if (big == 64) ty_bits else big;
16211631 },
16221632 .int_i64 => {
......@@ -1628,7 +1638,7 @@ pub const Value = extern union {
16281638 // Limbs are stored in little-endian order.
16291639 var result: u64 = 0;
16301640 for (bigint.limbs) |limb| {
1631 const limb_tz = @ctz(std.math.big.Limb, limb);
1641 const limb_tz = @ctz(limb);
16321642 result += limb_tz;
16331643 if (limb_tz != @sizeOf(std.math.big.Limb) * 8) break;
16341644 }
......@@ -1653,7 +1663,7 @@ pub const Value = extern union {
16531663 .zero, .bool_false => return 0,
16541664 .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
16581668 else => {
16591669 const info = ty.intInfo(target);
......@@ -1994,6 +2004,10 @@ pub const Value = extern union {
19942004 return (try orderAgainstZeroAdvanced(lhs, sema_kit)).compare(op);
19952005 }
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
19972011 /// This function is used by hash maps and so treats floating-point NaNs as equal
19982012 /// to each other, and not equal to other floating-point values.
19992013 /// Similarly, it treats `undef` as a distinct value from all other values.
......@@ -2002,13 +2016,10 @@ pub const Value = extern union {
20022016 /// for `a`. This function must act *as if* `a` has been coerced to `ty`. This complication
20032017 /// is required in order to make generic function instantiation efficient - specifically
20042018 /// 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
20092019 /// If `null` is provided for `sema_kit` then it is guaranteed no error will be returned.
20102020 pub fn eqlAdvanced(
20112021 a: Value,
2022 a_ty: Type,
20122023 b: Value,
20132024 ty: Type,
20142025 mod: *Module,
......@@ -2034,33 +2045,34 @@ pub const Value = extern union {
20342045 const a_payload = a.castTag(.opt_payload).?.data;
20352046 const b_payload = b.castTag(.opt_payload).?.data;
20362047 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);
20382050 },
20392051 .slice => {
20402052 const a_payload = a.castTag(.slice).?.data;
20412053 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))) {
20432055 return false;
20442056 }
20452057
20462058 var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined;
20472059 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);
20502062 },
20512063 .elem_ptr => {
20522064 const a_payload = a.castTag(.elem_ptr).?.data;
20532065 const b_payload = b.castTag(.elem_ptr).?.data;
20542066 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);
20572069 },
20582070 .field_ptr => {
20592071 const a_payload = a.castTag(.field_ptr).?.data;
20602072 const b_payload = b.castTag(.field_ptr).?.data;
20612073 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);
20642076 },
20652077 .@"error" => {
20662078 const a_name = a.castTag(.@"error").?.data.name;
......@@ -2070,7 +2082,8 @@ pub const Value = extern union {
20702082 .eu_payload => {
20712083 const a_payload = a.castTag(.eu_payload).?.data;
20722084 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);
20742087 },
20752088 .eu_payload_ptr => @panic("TODO: Implement more pointer eql cases"),
20762089 .opt_payload_ptr => @panic("TODO: Implement more pointer eql cases"),
......@@ -2088,7 +2101,7 @@ pub const Value = extern union {
20882101 const types = ty.tupleFields().types;
20892102 assert(types.len == a_field_vals.len);
20902103 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))) {
20922105 return false;
20932106 }
20942107 }
......@@ -2099,7 +2112,7 @@ pub const Value = extern union {
20992112 const fields = ty.structFields().values();
21002113 assert(fields.len == a_field_vals.len);
21012114 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))) {
21032116 return false;
21042117 }
21052118 }
......@@ -2110,7 +2123,7 @@ pub const Value = extern union {
21102123 for (a_field_vals) |a_elem, i| {
21112124 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))) {
21142127 return false;
21152128 }
21162129 }
......@@ -2122,7 +2135,7 @@ pub const Value = extern union {
21222135 switch (ty.containerLayout()) {
21232136 .Packed, .Extern => {
21242137 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))) {
21262139 // In this case, we must disregard mismatching tags and compare
21272140 // based on the in-memory bytes of the payloads.
21282141 @panic("TODO comptime comparison of extern union values with mismatching tags");
......@@ -2130,13 +2143,13 @@ pub const Value = extern union {
21302143 },
21312144 .Auto => {
21322145 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))) {
21342147 return false;
21352148 }
21362149 },
21372150 }
21382151 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);
21402153 },
21412154 else => {},
21422155 } else if (a_tag == .null_value or b_tag == .null_value) {
......@@ -2170,7 +2183,7 @@ pub const Value = extern union {
21702183 const b_val = b.enumToInt(ty, &buf_b);
21712184 var buf_ty: Type.Payload.Bits = undefined;
21722185 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);
21742187 },
21752188 .Array, .Vector => {
21762189 const len = ty.arrayLen();
......@@ -2181,17 +2194,44 @@ pub const Value = extern union {
21812194 while (i < len) : (i += 1) {
21822195 const a_elem = elemValueBuffer(a, mod, i, &a_buf);
21832196 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))) {
21852198 return false;
21862199 }
21872200 }
21882201 return true;
21892202 },
21902203 .Struct => {
2191 // A tuple can be represented with .empty_struct_value,
2192 // the_one_possible_value, .aggregate in which case we could
2193 // end up here and the values are equal if the type has zero fields.
2194 return ty.isTupleOrAnonStruct() and ty.structFieldCount() != 0;
2204 // A struct can be represented with one of:
2205 // .empty_struct_value,
2206 // .the_one_possible_value,
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;
21952235 },
21962236 .Float => {
21972237 switch (ty.floatBits(target)) {
......@@ -2220,7 +2260,8 @@ pub const Value = extern union {
22202260 .base = .{ .tag = .opt_payload },
22212261 .data = a,
22222262 };
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);
22242265 }
22252266 },
22262267 else => {},
......@@ -2648,6 +2689,12 @@ pub const Value = extern union {
26482689 // to have only one possible value itself.
26492690 .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
26512698 else => unreachable,
26522699 }
26532700 }
......@@ -3472,44 +3519,6 @@ pub const Value = extern union {
34723519 return fromBigInt(allocator, result_q.toConst());
34733520 }
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
35133522 pub fn intMod(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value {
35143523 if (ty.zigTypeTag() == .Vector) {
35153524 const result_data = try allocator.alloc(Value, ty.vectorLen());
test/behavior.zig+5-2
......@@ -26,7 +26,6 @@ test {
2626 _ = @import("behavior/bugs/920.zig");
2727 _ = @import("behavior/bugs/1025.zig");
2828 _ = @import("behavior/bugs/1076.zig");
29 _ = @import("behavior/bugs/1111.zig");
3029 _ = @import("behavior/bugs/1277.zig");
3130 _ = @import("behavior/bugs/1310.zig");
3231 _ = @import("behavior/bugs/1381.zig");
......@@ -84,6 +83,8 @@ test {
8483 _ = @import("behavior/bugs/11213.zig");
8584 _ = @import("behavior/bugs/12003.zig");
8685 _ = @import("behavior/bugs/12033.zig");
86 _ = @import("behavior/bugs/12430.zig");
87 _ = @import("behavior/bugs/12486.zig");
8788 _ = @import("behavior/byteswap.zig");
8889 _ = @import("behavior/byval_arg_var.zig");
8990 _ = @import("behavior/call.zig");
......@@ -159,12 +160,14 @@ test {
159160 _ = @import("behavior/while.zig");
160161 _ = @import("behavior/widening.zig");
161162
162 if (builtin.stage2_arch == .wasm32) {
163 if (builtin.cpu.arch == .wasm32) {
163164 _ = @import("behavior/wasm.zig");
164165 }
165166
166167 if (builtin.zig_backend != .stage1) {
167168 _ = @import("behavior/decltest.zig");
169 _ = @import("behavior/packed_struct_explicit_backing_int.zig");
170 _ = @import("behavior/empty_union.zig");
168171 }
169172
170173 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" {
100100 .a_align = 8,
101101 .a_size = 16,
102102
103 .b_align = 8,
104 .b_size = 24,
103 .b_align = 16,
104 .b_size = 32,
105105
106106 .u128_align = 8,
107107 .u128_size = 16,
......@@ -114,8 +114,8 @@ test "alignment and size of structs with 128-bit fields" {
114114 .a_align = 8,
115115 .a_size = 16,
116116
117 .b_align = 8,
118 .b_size = 24,
117 .b_align = 16,
118 .b_size = 32,
119119
120120 .u128_align = 8,
121121 .u128_size = 16,
......@@ -126,8 +126,8 @@ test "alignment and size of structs with 128-bit fields" {
126126 .a_align = 4,
127127 .a_size = 16,
128128
129 .b_align = 4,
130 .b_size = 20,
129 .b_align = 16,
130 .b_size = 32,
131131
132132 .u128_align = 4,
133133 .u128_size = 16,
......@@ -140,12 +140,39 @@ test "alignment and size of structs with 128-bit fields" {
140140 .mips64el,
141141 .powerpc64,
142142 .powerpc64le,
143 .riscv64,
144143 .sparc64,
145144 .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
146172 .aarch64,
147173 .aarch64_be,
148174 .aarch64_32,
175 .riscv64,
149176 .bpfel,
150177 .bpfeb,
151178 .nvptx,
......@@ -166,17 +193,17 @@ test "alignment and size of structs with 128-bit fields" {
166193 else => return error.SkipZigTest,
167194 };
168195 comptime {
169 std.debug.assert(@alignOf(A) == expected.a_align);
170 std.debug.assert(@sizeOf(A) == expected.a_size);
196 assert(@alignOf(A) == expected.a_align);
197 assert(@sizeOf(A) == expected.a_size);
171198
172 std.debug.assert(@alignOf(B) == expected.b_align);
173 std.debug.assert(@sizeOf(B) == expected.b_size);
199 assert(@alignOf(B) == expected.b_align);
200 assert(@sizeOf(B) == expected.b_size);
174201
175 std.debug.assert(@alignOf(u128) == expected.u128_align);
176 std.debug.assert(@sizeOf(u128) == expected.u128_size);
202 assert(@alignOf(u128) == expected.u128_align);
203 assert(@sizeOf(u128) == expected.u128_size);
177204
178 std.debug.assert(@alignOf(u129) == expected.u129_align);
179 std.debug.assert(@sizeOf(u129) == expected.u129_size);
205 assert(@alignOf(u129) == expected.u129_align);
206 assert(@sizeOf(u129) == expected.u129_size);
180207 }
181208}
182209
test/behavior/basic.zig+21
......@@ -1104,3 +1104,24 @@ test "namespace lookup ignores decl causing the lookup" {
11041104 };
11051105 _ = S.foo();
11061106}
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" {
88 // Currently failing on stage1 for big-endian targets
99 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);
1212}
1313
1414test "@bitReverse" {
......@@ -23,74 +23,74 @@ test "@bitReverse" {
2323
2424fn testBitReverse() !void {
2525 // using comptime_ints, unsigned
26 try expect(@bitReverse(u0, @as(u0, 0)) == 0);
27 try expect(@bitReverse(u5, @as(u5, 0x12)) == 0x9);
28 try expect(@bitReverse(u8, @as(u8, 0x12)) == 0x48);
29 try expect(@bitReverse(u16, @as(u16, 0x1234)) == 0x2c48);
30 try expect(@bitReverse(u24, @as(u24, 0x123456)) == 0x6a2c48);
31 try expect(@bitReverse(u32, @as(u32, 0x12345678)) == 0x1e6a2c48);
32 try expect(@bitReverse(u40, @as(u40, 0x123456789a)) == 0x591e6a2c48);
33 try expect(@bitReverse(u48, @as(u48, 0x123456789abc)) == 0x3d591e6a2c48);
34 try expect(@bitReverse(u56, @as(u56, 0x123456789abcde)) == 0x7b3d591e6a2c48);
35 try expect(@bitReverse(u64, @as(u64, 0x123456789abcdef1)) == 0x8f7b3d591e6a2c48);
36 try expect(@bitReverse(u96, @as(u96, 0x123456789abcdef111213141)) == 0x828c84888f7b3d591e6a2c48);
37 try expect(@bitReverse(u128, @as(u128, 0x123456789abcdef11121314151617181)) == 0x818e868a828c84888f7b3d591e6a2c48);
26 try expect(@bitReverse(@as(u0, 0)) == 0);
27 try expect(@bitReverse(@as(u5, 0x12)) == 0x9);
28 try expect(@bitReverse(@as(u8, 0x12)) == 0x48);
29 try expect(@bitReverse(@as(u16, 0x1234)) == 0x2c48);
30 try expect(@bitReverse(@as(u24, 0x123456)) == 0x6a2c48);
31 try expect(@bitReverse(@as(u32, 0x12345678)) == 0x1e6a2c48);
32 try expect(@bitReverse(@as(u40, 0x123456789a)) == 0x591e6a2c48);
33 try expect(@bitReverse(@as(u48, 0x123456789abc)) == 0x3d591e6a2c48);
34 try expect(@bitReverse(@as(u56, 0x123456789abcde)) == 0x7b3d591e6a2c48);
35 try expect(@bitReverse(@as(u64, 0x123456789abcdef1)) == 0x8f7b3d591e6a2c48);
36 try expect(@bitReverse(@as(u96, 0x123456789abcdef111213141)) == 0x828c84888f7b3d591e6a2c48);
37 try expect(@bitReverse(@as(u128, 0x123456789abcdef11121314151617181)) == 0x818e868a828c84888f7b3d591e6a2c48);
3838
3939 // using runtime uints, unsigned
4040 var num0: u0 = 0;
41 try expect(@bitReverse(u0, num0) == 0);
41 try expect(@bitReverse(num0) == 0);
4242 var num5: u5 = 0x12;
43 try expect(@bitReverse(u5, num5) == 0x9);
43 try expect(@bitReverse(num5) == 0x9);
4444 var num8: u8 = 0x12;
45 try expect(@bitReverse(u8, num8) == 0x48);
45 try expect(@bitReverse(num8) == 0x48);
4646 var num16: u16 = 0x1234;
47 try expect(@bitReverse(u16, num16) == 0x2c48);
47 try expect(@bitReverse(num16) == 0x2c48);
4848 var num24: u24 = 0x123456;
49 try expect(@bitReverse(u24, num24) == 0x6a2c48);
49 try expect(@bitReverse(num24) == 0x6a2c48);
5050 var num32: u32 = 0x12345678;
51 try expect(@bitReverse(u32, num32) == 0x1e6a2c48);
51 try expect(@bitReverse(num32) == 0x1e6a2c48);
5252 var num40: u40 = 0x123456789a;
53 try expect(@bitReverse(u40, num40) == 0x591e6a2c48);
53 try expect(@bitReverse(num40) == 0x591e6a2c48);
5454 var num48: u48 = 0x123456789abc;
55 try expect(@bitReverse(u48, num48) == 0x3d591e6a2c48);
55 try expect(@bitReverse(num48) == 0x3d591e6a2c48);
5656 var num56: u56 = 0x123456789abcde;
57 try expect(@bitReverse(u56, num56) == 0x7b3d591e6a2c48);
57 try expect(@bitReverse(num56) == 0x7b3d591e6a2c48);
5858 var num64: u64 = 0x123456789abcdef1;
59 try expect(@bitReverse(u64, num64) == 0x8f7b3d591e6a2c48);
59 try expect(@bitReverse(num64) == 0x8f7b3d591e6a2c48);
6060 var num128: u128 = 0x123456789abcdef11121314151617181;
61 try expect(@bitReverse(u128, num128) == 0x818e868a828c84888f7b3d591e6a2c48);
61 try expect(@bitReverse(num128) == 0x818e868a828c84888f7b3d591e6a2c48);
6262
6363 // using comptime_ints, signed, positive
64 try expect(@bitReverse(u8, @as(u8, 0)) == 0);
65 try expect(@bitReverse(i8, @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)));
67 try expect(@bitReverse(i24, @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)));
69 try expect(@bitReverse(i24, @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)));
71 try expect(@bitReverse(i32, @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)));
73 try expect(@bitReverse(i40, @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)));
75 try expect(@bitReverse(i56, @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)));
77 try expect(@bitReverse(i96, @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)));
64 try expect(@bitReverse(@as(u8, 0)) == 0);
65 try expect(@bitReverse(@bitCast(i8, @as(u8, 0x92))) == @bitCast(i8, @as(u8, 0x49)));
66 try expect(@bitReverse(@bitCast(i16, @as(u16, 0x1234))) == @bitCast(i16, @as(u16, 0x2c48)));
67 try expect(@bitReverse(@bitCast(i24, @as(u24, 0x123456))) == @bitCast(i24, @as(u24, 0x6a2c48)));
68 try expect(@bitReverse(@bitCast(i24, @as(u24, 0x12345f))) == @bitCast(i24, @as(u24, 0xfa2c48)));
69 try expect(@bitReverse(@bitCast(i24, @as(u24, 0xf23456))) == @bitCast(i24, @as(u24, 0x6a2c4f)));
70 try expect(@bitReverse(@bitCast(i32, @as(u32, 0x12345678))) == @bitCast(i32, @as(u32, 0x1e6a2c48)));
71 try expect(@bitReverse(@bitCast(i32, @as(u32, 0xf2345678))) == @bitCast(i32, @as(u32, 0x1e6a2c4f)));
72 try expect(@bitReverse(@bitCast(i32, @as(u32, 0x1234567f))) == @bitCast(i32, @as(u32, 0xfe6a2c48)));
73 try expect(@bitReverse(@bitCast(i40, @as(u40, 0x123456789a))) == @bitCast(i40, @as(u40, 0x591e6a2c48)));
74 try expect(@bitReverse(@bitCast(i48, @as(u48, 0x123456789abc))) == @bitCast(i48, @as(u48, 0x3d591e6a2c48)));
75 try expect(@bitReverse(@bitCast(i56, @as(u56, 0x123456789abcde))) == @bitCast(i56, @as(u56, 0x7b3d591e6a2c48)));
76 try expect(@bitReverse(@bitCast(i64, @as(u64, 0x123456789abcdef1))) == @bitCast(i64, @as(u64, 0x8f7b3d591e6a2c48)));
77 try expect(@bitReverse(@bitCast(i96, @as(u96, 0x123456789abcdef111213141))) == @bitCast(i96, @as(u96, 0x828c84888f7b3d591e6a2c48)));
78 try expect(@bitReverse(@bitCast(i128, @as(u128, 0x123456789abcdef11121314151617181))) == @bitCast(i128, @as(u128, 0x818e868a828c84888f7b3d591e6a2c48)));
7979
8080 // using signed, negative. Compare to runtime ints returned from llvm.
8181 var neg8: i8 = -18;
82 try expect(@bitReverse(i8, @as(i8, -18)) == @bitReverse(i8, neg8));
82 try expect(@bitReverse(@as(i8, -18)) == @bitReverse(neg8));
8383 var neg16: i16 = -32694;
84 try expect(@bitReverse(i16, @as(i16, -32694)) == @bitReverse(i16, neg16));
84 try expect(@bitReverse(@as(i16, -32694)) == @bitReverse(neg16));
8585 var neg24: i24 = -6773785;
86 try expect(@bitReverse(i24, @as(i24, -6773785)) == @bitReverse(i24, neg24));
86 try expect(@bitReverse(@as(i24, -6773785)) == @bitReverse(neg24));
8787 var neg32: i32 = -16773785;
88 try expect(@bitReverse(i32, @as(i32, -16773785)) == @bitReverse(i32, neg32));
88 try expect(@bitReverse(@as(i32, -16773785)) == @bitReverse(neg32));
8989}
9090
9191fn vector8() !void {
9292 var v = @Vector(2, u8){ 0x12, 0x23 };
93 var result = @bitReverse(u8, v);
93 var result = @bitReverse(v);
9494 try expect(result[0] == 0x48);
9595 try expect(result[1] == 0xc4);
9696}
......@@ -109,7 +109,7 @@ test "bitReverse vectors u8" {
109109
110110fn vector16() !void {
111111 var v = @Vector(2, u16){ 0x1234, 0x2345 };
112 var result = @bitReverse(u16, v);
112 var result = @bitReverse(v);
113113 try expect(result[0] == 0x2c48);
114114 try expect(result[1] == 0xa2c4);
115115}
......@@ -128,7 +128,7 @@ test "bitReverse vectors u16" {
128128
129129fn vector24() !void {
130130 var v = @Vector(2, u24){ 0x123456, 0x234567 };
131 var result = @bitReverse(u24, v);
131 var result = @bitReverse(v);
132132 try expect(result[0] == 0x6a2c48);
133133 try expect(result[1] == 0xe6a2c4);
134134}
......@@ -147,7 +147,7 @@ test "bitReverse vectors u24" {
147147
148148fn vector0() !void {
149149 var v = @Vector(2, u0){ 0, 0 };
150 var result = @bitReverse(u0, v);
150 var result = @bitReverse(v);
151151 try expect(result[0] == 0);
152152 try expect(result[1] == 0);
153153}
test/behavior/bugs/10147.zig+3-2
......@@ -2,6 +2,7 @@ const builtin = @import("builtin");
22const std = @import("std");
33
44test "uses correct LLVM builtin" {
5 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
56 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
67 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
78 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
......@@ -12,8 +13,8 @@ test "uses correct LLVM builtin" {
1213 var y: @Vector(4, u32) = [_]u32{ 0x1, 0x1, 0x1, 0x1 };
1314 // The stage1 compiler used to call the same builtin function for both
1415 // scalar and vector inputs, causing the LLVM module verification to fail.
15 var a = @clz(u32, x);
16 var b = @clz(u32, y);
16 var a = @clz(x);
17 var b = @clz(y);
1718 try std.testing.expectEqual(@as(u6, 31), a);
1819 try std.testing.expectEqual([_]u6{ 31, 31, 31, 31 }, b);
1920}
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;
44const math = std.math;
55
66fn ctz(x: anytype) usize {
7 return @ctz(@TypeOf(x), x);
7 return @ctz(x);
88}
99
1010test "fixed" {
test/behavior/byteswap.zig+10-5
......@@ -3,6 +3,7 @@ const builtin = @import("builtin");
33const expect = std.testing.expect;
44
55test "@byteSwap integers" {
6 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
67 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
78 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
89 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
......@@ -46,7 +47,7 @@ test "@byteSwap integers" {
4647 );
4748 }
4849 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));
5051 }
5152 };
5253 comptime try ByteSwapIntTest.run();
......@@ -55,12 +56,13 @@ test "@byteSwap integers" {
5556
5657fn vector8() !void {
5758 var v = @Vector(2, u8){ 0x12, 0x13 };
58 var result = @byteSwap(u8, v);
59 var result = @byteSwap(v);
5960 try expect(result[0] == 0x12);
6061 try expect(result[1] == 0x13);
6162}
6263
6364test "@byteSwap vectors u8" {
65 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
6466 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
6567 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
6668 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
......@@ -73,12 +75,13 @@ test "@byteSwap vectors u8" {
7375
7476fn vector16() !void {
7577 var v = @Vector(2, u16){ 0x1234, 0x2345 };
76 var result = @byteSwap(u16, v);
78 var result = @byteSwap(v);
7779 try expect(result[0] == 0x3412);
7880 try expect(result[1] == 0x4523);
7981}
8082
8183test "@byteSwap vectors u16" {
84 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
8285 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
8386 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
8487 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
......@@ -91,12 +94,13 @@ test "@byteSwap vectors u16" {
9194
9295fn vector24() !void {
9396 var v = @Vector(2, u24){ 0x123456, 0x234567 };
94 var result = @byteSwap(u24, v);
97 var result = @byteSwap(v);
9598 try expect(result[0] == 0x563412);
9699 try expect(result[1] == 0x674523);
97100}
98101
99102test "@byteSwap vectors u24" {
103 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
100104 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
101105 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
102106 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
......@@ -109,12 +113,13 @@ test "@byteSwap vectors u24" {
109113
110114fn vector0() !void {
111115 var v = @Vector(2, u0){ 0, 0 };
112 var result = @byteSwap(u0, v);
116 var result = @byteSwap(v);
113117 try expect(result[0] == 0);
114118 try expect(result[1] == 0);
115119}
116120
117121test "@byteSwap vectors u0" {
122 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
118123 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
119124 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
120125 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" {
246246 };
247247 try S.doTheTest(39);
248248}
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" {
12811281test "cast between [*c]T and ?[*:0]T on fn parameter" {
12821282 const S = struct {
12831283 const Handler = ?fn ([*c]const u8) callconv(.C) void;
1284 fn addCallback(handler: Handler) void {
1284 fn addCallback(comptime handler: Handler) void {
12851285 _ = handler;
12861286 }
12871287
......@@ -1431,6 +1431,11 @@ test "coerce between pointers of compatible differently-named floats" {
14311431 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14321432 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
14341439 const F = switch (@typeInfo(c_longdouble).Float.bits) {
14351440 16 => f16,
14361441 32 => f32,
test/behavior/comptime_memory.zig+1-1
......@@ -82,7 +82,7 @@ test "type pun value and struct" {
8282}
8383
8484fn 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);
8686}
8787test "type pun endianness" {
8888 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 @@
11const builtin = @import("builtin");
22const std = @import("std");
33const expect = std.testing.expect;
4const assert = std.debug.assert;
45const mem = std.mem;
56const Tag = std.meta.Tag;
67
......@@ -1128,3 +1129,49 @@ test "tag name functions are unique" {
11281129 _ = a;
11291130 }
11301131}
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 {
168168 fooPtr(ptr);
169169}
170170
171fn foo2(f: fn () anyerror!void) void {
171fn foo2(comptime f: fn () anyerror!void) void {
172172 const x = f();
173173 x catch {
174174 @panic("fail");
......@@ -725,7 +725,7 @@ test "simple else prong allowed even when all errors handled" {
725725 try expect(value == 255);
726726}
727727
728test {
728test "pointer to error union payload" {
729729 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
730730 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
731731 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
......@@ -736,3 +736,79 @@ test {
736736 const payload_ptr = &(err_union catch unreachable);
737737 try expect(payload_ptr.* == 15);
738738}
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" {
12931293 try expect(payload_ptr.*.* == 16);
12941294 }
12951295}
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 {
194194 const eps = epsForType(ty);
195195 try expect(@sin(@as(ty, 0)) == 0);
196196 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));
198 try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi / 4)), 0.7071067811865475, 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)), 0.7071067811865475, eps));
199199 }
200200
201201 {
......@@ -228,8 +228,8 @@ fn testCos() !void {
228228 const eps = epsForType(ty);
229229 try expect(@cos(@as(ty, 0)) == 1);
230230 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));
232 try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi / 4)), 0.7071067811865475, 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)), 0.7071067811865475, eps));
233233 }
234234
235235 {
test/behavior/fn.zig+22-1
......@@ -137,7 +137,7 @@ test "implicit cast function unreachable return" {
137137 wantsFnWithVoid(fnWithUnreachable);
138138}
139139
140fn wantsFnWithVoid(f: fn () void) void {
140fn wantsFnWithVoid(comptime f: fn () void) void {
141141 _ = f;
142142}
143143
......@@ -422,3 +422,24 @@ test "import passed byref to function in return type" {
422422 var list = S.get();
423423 try expect(list.items.len == 0);
424424}
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" {
323323 S.copy(u8, &buffer, "hello");
324324 S.copy(u8, &buffer, "hello2");
325325}
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 {
9090}
9191
9292fn testOneClz(comptime T: type, x: T) u32 {
93 return @clz(T, x);
93 return @clz(x);
9494}
9595
9696test "@clz vectors" {
97 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
9798 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
9899 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
99100 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
......@@ -120,7 +121,7 @@ fn testOneClzVector(
120121 x: @Vector(len, T),
121122 expected: @Vector(len, u32),
122123) !void {
123 try expectVectorsEqual(@clz(T, x), expected);
124 try expectVectorsEqual(@clz(x), expected);
124125}
125126
126127fn expectVectorsEqual(a: anytype, b: anytype) !void {
......@@ -151,19 +152,18 @@ fn testCtz() !void {
151152}
152153
153154fn testOneCtz(comptime T: type, x: T) u32 {
154 return @ctz(T, x);
155 return @ctz(x);
155156}
156157
157158test "@ctz vectors" {
159 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
158160 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
159161 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
160162 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
161163 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
162164 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
163165
164 if ((builtin.zig_backend == .stage1 or builtin.zig_backend == .stage2_llvm) and
165 builtin.cpu.arch == .aarch64)
166 {
166 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) {
167167 // This regressed with LLVM 14:
168168 // https://github.com/ziglang/zig/issues/12013
169169 return error.SkipZigTest;
......@@ -187,7 +187,7 @@ fn testOneCtzVector(
187187 x: @Vector(len, T),
188188 expected: @Vector(len, u32),
189189) !void {
190 try expectVectorsEqual(@ctz(T, x), expected);
190 try expectVectorsEqual(@ctz(x), expected);
191191}
192192
193193test "const number literal" {
......@@ -239,10 +239,9 @@ test "quad hex float literal parsing in range" {
239239}
240240
241241test "underscore separator parsing" {
242 try expect(0_0_0_0 == 0);
243242 try expect(1_234_567 == 1234567);
244 try expect(001_234_567 == 1234567);
245 try expect(0_0_1_2_3_4_5_6_7 == 1234567);
243 try expect(1_234_567 == 1234567);
244 try expect(1_2_3_4_5_6_7 == 1234567);
246245
247246 try expect(0b0_0_0_0 == 0);
248247 try expect(0b1010_1010 == 0b10101010);
......@@ -260,7 +259,7 @@ test "underscore separator parsing" {
260259 try expect(0x1_0_1_0_1_0_1_0 == 0x10101010);
261260
262261 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
265264 try expect(0x1234_5678.9ABC_DEF0p-1_0 == 0x12345678.9ABCDEF0p-10);
266265 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" {
11681167 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11691168 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11701169 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
11721172 comptime try remdiv(f16);
11731173 comptime try remdiv(f32);
......@@ -1199,6 +1199,7 @@ test "float remainder division using @rem" {
11991199 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12001200 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12011201 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
12031204 comptime try frem(f16);
12041205 comptime try frem(f32);
......@@ -1241,6 +1242,7 @@ test "float modulo division using @mod" {
12411242 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12421243 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12431244 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
12451247 comptime try fmod(f16);
12461248 comptime try fmod(f32);
......@@ -1368,6 +1370,7 @@ test "@floor f80" {
13681370 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13691371 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
13701372 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
13721375 try testFloor(f80, 12.0);
13731376 comptime try testFloor(f80, 12.0);
......@@ -1416,6 +1419,7 @@ test "@ceil f80" {
14161419 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14171420 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
14181421 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
14201424 try testCeil(f80, 12.0);
14211425 comptime try testCeil(f80, 12.0);
......@@ -1464,6 +1468,7 @@ test "@trunc f80" {
14641468 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14651469 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
14661470 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
14681473 try testTrunc(f80, 12.0);
14691474 comptime try testTrunc(f80, 12.0);
......@@ -1526,6 +1531,7 @@ test "@round f80" {
15261531 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15271532 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
15281533 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
15301536 try testRound(f80, 12.0);
15311537 comptime try testRound(f80, 12.0);
......@@ -1721,3 +1727,18 @@ fn testAbsFloat() !void {
17211727fn testAbsFloatOne(in: f32, out: f32) !void {
17221728 try expect(@fabs(@as(f32, in)) == @as(f32, out));
17231729}
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" {
5151 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5252 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5353 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
5556 comptime try testMulAdd80();
5657 try testMulAdd80();
......@@ -182,6 +183,7 @@ test "vector f80" {
182183 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
183184 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
184185 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
186188 comptime try vector80();
187189 try vector80();
test/behavior/optional.zig+59
......@@ -369,3 +369,62 @@ test "optional pointer to zero bit error union payload" {
369369 some.foo();
370370 } else |_| {}
371371}
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" {
434434 };
435435 try expect(@ptrToInt(&S.p0.z) - @ptrToInt(&S.p0.x) == 2);
436436}
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" {
1818 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1919
2020 comptime {
21 try expect(@popCount(u128, @as(u128, 0b11111111000110001100010000100001000011000011100101010001)) == 24);
22 try expect(@popCount(i128, @as(i128, 0b11111111000110001100010000100001000011000011100101010001)) == 24);
21 try expect(@popCount(@as(u128, 0b11111111000110001100010000100001000011000011100101010001)) == 24);
22 try expect(@popCount(@as(i128, 0b11111111000110001100010000100001000011000011100101010001)) == 24);
2323 }
2424
2525 {
2626 var x: u128 = 0b11111111000110001100010000100001000011000011100101010001;
27 try expect(@popCount(u128, x) == 24);
27 try expect(@popCount(x) == 24);
2828 }
2929
30 try expect(@popCount(i128, @as(i128, 0b11111111000110001100010000100001000011000011100101010001)) == 24);
30 try expect(@popCount(@as(i128, 0b11111111000110001100010000100001000011000011100101010001)) == 24);
3131}
3232
3333fn testPopCountIntegers() !void {
3434 {
3535 var x: u32 = 0xffffffff;
36 try expect(@popCount(u32, x) == 32);
36 try expect(@popCount(x) == 32);
3737 }
3838 {
3939 var x: u5 = 0x1f;
40 try expect(@popCount(u5, x) == 5);
40 try expect(@popCount(x) == 5);
4141 }
4242 {
4343 var x: u32 = 0xaa;
44 try expect(@popCount(u32, x) == 4);
44 try expect(@popCount(x) == 4);
4545 }
4646 {
4747 var x: u32 = 0xaaaaaaaa;
48 try expect(@popCount(u32, x) == 16);
48 try expect(@popCount(x) == 16);
4949 }
5050 {
5151 var x: u32 = 0xaaaaaaaa;
52 try expect(@popCount(u32, x) == 16);
52 try expect(@popCount(x) == 16);
5353 }
5454 {
5555 var x: i16 = -1;
56 try expect(@popCount(i16, x) == 16);
56 try expect(@popCount(x) == 16);
5757 }
5858 {
5959 var x: i8 = -120;
60 try expect(@popCount(i8, x) == 2);
60 try expect(@popCount(x) == 2);
6161 }
6262 comptime {
63 try expect(@popCount(u8, @bitCast(u8, @as(i8, -120))) == 2);
63 try expect(@popCount(@bitCast(u8, @as(i8, -120))) == 2);
6464 }
6565}
6666
6767test "@popCount vectors" {
68 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
6869 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
6970 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
7071 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
......@@ -79,13 +80,13 @@ fn testPopCountVectors() !void {
7980 {
8081 var x: @Vector(8, u32) = [1]u32{0xffffffff} ** 8;
8182 const expected = [1]u6{32} ** 8;
82 const result: [8]u6 = @popCount(u32, x);
83 const result: [8]u6 = @popCount(x);
8384 try expect(std.mem.eql(u6, &expected, &result));
8485 }
8586 {
8687 var x: @Vector(8, i16) = [1]i16{-1} ** 8;
8788 const expected = [1]u5{16} ** 8;
88 const result: [8]u5 = @popCount(i16, x);
89 const result: [8]u5 = @popCount(x);
8990 try expect(std.mem.eql(u5, &expected, &result));
9091 }
9192}
test/behavior/struct.zig+2-2
......@@ -147,7 +147,7 @@ test "fn call of struct field" {
147147 return 13;
148148 }
149149
150 fn callStructField(foo: Foo) i32 {
150 fn callStructField(comptime foo: Foo) i32 {
151151 return foo.ptr();
152152 }
153153 };
......@@ -963,7 +963,7 @@ test "tuple assigned to variable" {
963963
964964test "comptime struct field" {
965965 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
966 if (builtin.stage2_arch == .arm) return error.SkipZigTest; // TODO
966 if (builtin.cpu.arch == .arm) return error.SkipZigTest; // TODO
967967
968968 const T = struct {
969969 a: i32,
test/behavior/switch.zig+1
......@@ -531,6 +531,7 @@ test "switch with null and T peer types and inferred result location type" {
531531test "switch prongs with cases with identical payload types" {
532532 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
533533 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
534 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
534535
535536 const Union = union(enum) {
536537 A: usize,
test/behavior/tuple.zig+38
......@@ -290,3 +290,41 @@ test "coerce tuple to tuple" {
290290 };
291291 try S.foo(.{123});
292292}
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" {
513513 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
514514 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
516521 const some_opaque = opaque {};
517522 const some_ptr = *some_opaque;
518523 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" {
293293fn testStruct() !void {
294294 const unpacked_struct_info = @typeInfo(TestStruct);
295295 try expect(unpacked_struct_info.Struct.is_tuple == false);
296 try expect(unpacked_struct_info.Struct.backing_integer == null);
296297 try expect(unpacked_struct_info.Struct.fields[0].alignment == @alignOf(u32));
297298 try expect(@ptrCast(*const u32, unpacked_struct_info.Struct.fields[0].default_value.?).* == 4);
298299 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 {
315316 try expect(struct_info == .Struct);
316317 try expect(struct_info.Struct.is_tuple == false);
317318 try expect(struct_info.Struct.layout == .Packed);
319 try expect(struct_info.Struct.backing_integer == u128);
318320 try expect(struct_info.Struct.fields.len == 4);
319321 try expect(struct_info.Struct.fields[0].alignment == 0);
320322 try expect(struct_info.Struct.fields[2].field_type == f32);
......@@ -326,7 +328,7 @@ fn testPackedStruct() !void {
326328}
327329
328330const TestPackedStruct = packed struct {
329 fieldA: usize,
331 fieldA: u64,
330332 fieldB: void,
331333 fieldC: f32,
332334 fieldD: u32 = 4,
test/behavior/typename.zig+11
......@@ -235,3 +235,14 @@ test "local variable" {
235235 try expectEqualStrings("behavior.typename.test.local variable.Qux", @typeName(Qux));
236236 try expectEqualStrings("behavior.typename.test.local variable.Quux", @typeName(Quux));
237237}
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 @@
11const builtin = @import("builtin");
22const std = @import("std");
33const expect = std.testing.expect;
4const assert = std.debug.assert;
45const expectEqual = std.testing.expectEqual;
56const Tag = std.meta.Tag;
67
......@@ -744,7 +745,7 @@ fn setAttribute(attr: Attribute) void {
744745 _ = attr;
745746}
746747
747fn Setter(attr: Attribute) type {
748fn Setter(comptime attr: Attribute) type {
748749 return struct {
749750 fn set() void {
750751 setAttribute(attr);
......@@ -1065,6 +1066,8 @@ test "@unionInit on union with tag but no fields" {
10651066 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
10661067 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10671068 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
10691072 const S = struct {
10701073 const Type = enum(u8) { no_op = 105 };
......@@ -1079,11 +1082,7 @@ test "@unionInit on union with tag but no fields" {
10791082 };
10801083
10811084 comptime {
1082 if (builtin.zig_backend == .stage1) {
1083 // stage1 gets the wrong answer here
1084 } else {
1085 std.debug.assert(@sizeOf(Data) == 0);
1086 }
1085 assert(@sizeOf(Data) == 1);
10871086 }
10881087
10891088 fn doTheTest() !void {
......@@ -1256,3 +1255,72 @@ test "return an extern union from C calling convention" {
12561255 });
12571256 try expect(u.d == 4.0);
12581257}
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" {
807807 comptime try S.doTheTest();
808808}
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
810827test "mask parameter of @shuffle is comptime scope" {
811828 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
812829 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
......@@ -1094,3 +1111,26 @@ test "loading the second vector from a slice of vectors" {
10941111 var a4 = a[1][1];
10951112 try expect(a4 == 3);
10961113}
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" {
4545 var x = [_]void{{}} ** 1004;
4646 _ = x[0];
4747}
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 {
33 m.copy(u8, self[0..], m);
44}
55export 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
713// error
814// backend=stage2
915// target=native
1016//
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}'
1119// :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 @@
11pub export fn entry() void {
22 var arr: [100]u8 = undefined;
3 for (arr) |bits| _ = @popCount(bits);
3 for (arr) |bits| _ = @popCount(u8, bits);
44}
55
66// error
77// backend=stage2
88// target=native
99//
10// :3:26: error: expected 2 arguments, found 1
10// :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{
66// backend=stage2
77// target=native
88//
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; }
1212// backend=stage2
1313// target=native
1414//
15// :5:12: error: extern function cannot be generic
16// :5:30: note: function is generic because of this parameter
17// :6:12: error: extern function cannot be generic
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
15// :1:15: error: comptime parameters not allowed in function with calling convention 'C'
16// :5:30: error: comptime parameters not allowed in function with calling convention 'C'
17// :6:30: error: generic parameters not allowed in function with calling convention 'C'
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 @@
11fn main() void {
2 var bad: u128 = 0010_;
2 var bad: u128 = 10_;
33 _ = bad;
44}
55
......@@ -8,4 +8,4 @@ fn main() void {
88// target=native
99//
1010// :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"); }
1111// target=native
1212//
1313// :5:25: error: cannot load runtime value in comptime block
14// :2:15: note: called from here
14// :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 {};
1717// target=native
1818//
1919// :4:9: error: expected type '@typeInfo(tmp.Error).Union.tag_type.?', found 'type'
20// :8:1: note: enum declared here
20// :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 @@
11export fn entry(x: f32) u32 {
2 return @popCount(f32, x);
2 return @popCount(x);
33}
44
55// error
66// backend=stage2
77// target=native
88//
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 {
3131// backend=stage2
3232// target=native
3333//
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'
3535// :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 {
1818//
1919// :11:20: error: runtime coercion from enum 'tmp.Letter' to union 'tmp.Value' which has non-void fields
2020// :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'
2321// :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" {
99// is_test=1
1010//
1111// :3:9: error: no field with value '5' in enum 'test.enum.E'
12// :1:1: note: declared here
12// :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; }
77// backend=stage2
88// target=native
99//
10// :2:6: error: expected 3 argument(s), found 1
10// :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 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = 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);
79}
810const Foo = enum {
911 A,
......@@ -18,6 +20,7 @@ fn bar(a: u2) Foo {
1820 return @intToEnum(Foo, a);
1921}
2022fn baz(_: Foo) void {}
23
2124// run
22// backend=stage1
25// backend=llvm
2326// 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
1010
1111const E = enum(u32) {
1212 X = 1,
13 Y = 2,
1314};
1415
1516pub fn main() !void {
......@@ -21,5 +22,5 @@ pub fn main() !void {
2122}
2223
2324// run
24// backend=stage1
25// backend=llvm
2526// 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
1010
1111const U = union(enum(u32)) {
1212 X: u8,
13 Y: i8,
1314};
1415
1516pub fn main() !void {
......@@ -22,5 +23,5 @@ pub fn main() !void {
2223}
2324
2425// run
25// backend=stage1
26// backend=llvm
2627// target=native
test/cases/safety/cast []u8 to bigger slice of wrong size.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = 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);
79}
810
911pub fn main() !void {
......@@ -15,5 +17,5 @@ fn widenSlice(slice: []align(1) const u8) []align(1) const i32 {
1517 return std.mem.bytesAsSlice(i32, slice);
1618}
1719// 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");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
44 _ = 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")) {
66 std.process.exit(0);
77 }
88 std.process.exit(1);
......@@ -17,5 +17,5 @@ pub fn main() !void {
1717}
1818
1919// run
20// backend=stage1
20// backend=llvm
2121// 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");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
44 _ = 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")) {
66 std.process.exit(0);
77 }
88 std.process.exit(1);
99}
1010pub fn main() !void {
11 const a = [_]i32{1, 2, 3, 4};
11 const a = [_]i32{ 1, 2, 3, 4 };
1212 baz(bar(&a));
1313 return error.TestFailed;
1414}
1515fn bar(a: []const i32) i32 {
1616 return a[4];
1717}
18fn baz(_: i32) void { }
18fn baz(_: i32) void {}
1919// run
2020// backend=llvm
2121// target=native
test/cases/safety/pointer casting null to non-optional pointer.zig +7-3
......@@ -1,16 +1,20 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = 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);
79}
10
811pub fn main() !void {
912 var c_ptr: [*c]u8 = 0;
1013 var zig_ptr: *u8 = c_ptr;
1114 _ = zig_ptr;
1215 return error.TestFailed;
1316}
17
1418// run
15// backend=stage1
19// backend=llvm
1620// target=native
test/cases/safety/pointer slice sentinel mismatch.zig +3-3
......@@ -2,14 +2,14 @@ const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
44 _ = stack_trace;
5 if (std.mem.eql(u8, message, "sentinel mismatch")) {
5 if (std.mem.eql(u8, message, "sentinel mismatch: expected 0, found 4")) {
66 std.process.exit(0);
77 }
88 std.process.exit(1);
99}
1010
1111pub fn main() !void {
12 var buf: [4]u8 = undefined;
12 var buf: [4]u8 = .{ 1, 2, 3, 4 };
1313 const ptr: [*]u8 = &buf;
1414 const slice = ptr[0..3 :0];
1515 _ = slice;
......@@ -17,5 +17,5 @@ pub fn main() !void {
1717}
1818
1919// run
20// backend=stage1
20// backend=llvm
2121// 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 {
1717}
1818
1919// run
20// backend=stage1
20// backend=llvm
2121// target=native
test/cases/safety/shift right by huge amount.zig +1-1
......@@ -17,5 +17,5 @@ pub fn main() !void {
1717}
1818
1919// run
20// backend=stage1
20// backend=llvm
2121// target=native
test/cases/safety/signed integer division overflow - vectors.zig +6-4
......@@ -1,9 +1,11 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = 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);
79}
810
911pub fn main() !void {
......@@ -17,5 +19,5 @@ fn div(a: @Vector(4, i16), b: @Vector(4, i16)) @Vector(4, i16) {
1719 return @divTrunc(a, b);
1820}
1921// 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 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = 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);
79}
810
911pub fn main() !void {
......@@ -15,5 +17,5 @@ fn div(a: i16, b: i16) i16 {
1517 return @divTrunc(a, b);
1618}
1719// 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");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
44 _ = 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")) {
66 std.process.exit(0);
77 }
88 std.process.exit(1);
99}
1010
1111pub fn main() !void {
12 var buf: [4]f32 = undefined;
12 var buf: [4]f32 = .{ 1, 2, 3, 4 };
1313 const slice = buf[0..3 :1.2];
1414 _ = slice;
1515 return error.TestFailed;
1616}
1717
1818// run
19// backend=stage1
19// backend=llvm
2020// target=native
test/cases/safety/slice sentinel mismatch - optional pointers.zig +3-3
......@@ -2,19 +2,19 @@ const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
44 _ = 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")) {
66 std.process.exit(0);
77 }
88 std.process.exit(1);
99}
1010
1111pub 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) };
1313 const slice = buf[0..3 :null];
1414 _ = slice;
1515 return error.TestFailed;
1616}
1717
1818// run
19// backend=stage1
19// backend=llvm
2020// target=native
test/cases/safety/slice slice sentinel mismatch.zig +3-3
......@@ -2,18 +2,18 @@ const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
44 _ = stack_trace;
5 if (std.mem.eql(u8, message, "sentinel mismatch")) {
5 if (std.mem.eql(u8, message, "sentinel mismatch: expected 0, found 4")) {
66 std.process.exit(0);
77 }
88 std.process.exit(1);
99}
1010pub fn main() !void {
11 var buf: [4]u8 = undefined;
11 var buf: [4]u8 = .{ 1, 2, 3, 4 };
1212 const slice = buf[0..];
1313 const slice2 = slice[0..3 :0];
1414 _ = slice2;
1515 return error.TestFailed;
1616}
1717// run
18// backend=stage1
18// backend=llvm
1919// 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");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
44 _ = 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")) {
66 std.process.exit(0);
77 }
88 std.process.exit(1);
......@@ -17,5 +17,5 @@ pub fn main() !void {
1717}
1818
1919// run
20// backend=stage1
20// backend=llvm
2121// 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 @@
11const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
54 _ = 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);
79}
810
911pub fn main() !void {
......@@ -13,5 +15,5 @@ pub fn main() !void {
1315 return error.TestFailed;
1416}
1517// 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");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
44 _ = stack_trace;
5 if (std.mem.eql(u8, message, "reached unreachable code")) {
5 if (std.mem.eql(u8, message, "switch on corrupt value")) {
66 std.process.exit(0);
77 }
88 std.process.exit(1);
......@@ -10,17 +10,18 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noretur
1010
1111const E = enum(u32) {
1212 X = 1,
13 Y = 2,
1314};
1415
1516pub fn main() !void {
1617 var e: E = undefined;
1718 @memset(@ptrCast([*]u8, &e), 0x55, @sizeOf(E));
1819 switch (e) {
19 .X => @breakpoint(),
20 .X, .Y => @breakpoint(),
2021 }
2122 return error.TestFailed;
2223}
2324
2425// run
25// backend=stage1
26// backend=llvm
2627// target=native
test/cases/safety/switch on corrupted union value.zig +4-3
......@@ -2,7 +2,7 @@ const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
44 _ = stack_trace;
5 if (std.mem.eql(u8, message, "reached unreachable code")) {
5 if (std.mem.eql(u8, message, "switch on corrupt value")) {
66 std.process.exit(0);
77 }
88 std.process.exit(1);
......@@ -10,17 +10,18 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noretur
1010
1111const U = union(enum(u32)) {
1212 X: u8,
13 Y: i8,
1314};
1415
1516pub fn main() !void {
1617 var u: U = undefined;
1718 @memset(@ptrCast([*]u8, &u), 0x55, @sizeOf(U));
1819 switch (u) {
19 .X => @breakpoint(),
20 .X, .Y => @breakpoint(),
2021 }
2122 return error.TestFailed;
2223}
2324
2425// run
25// backend=stage1
26// backend=llvm
2627// 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 {
184184 }
185185
186186 {
187 const case = ctx.obj("argument causes error ", .{});
187 const case = ctx.obj("argument causes error", .{});
188188 case.backend = .stage2;
189189
190190 case.addSourceFile("b.zig",
......@@ -204,6 +204,24 @@ pub fn addCases(ctx: *TestContext) !void {
204204 , &[_][]const u8{
205205 ":3:12: error: unable to resolve comptime value",
206206 ":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",
207225 });
208226 }
209227
test/link.zig+32-22
......@@ -23,11 +23,12 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
2323 .build_modes = true,
2424 });
2525
26 cases.addBuildFile("test/link/tls/build.zig", .{
27 .build_modes = true,
28 });
26 addWasmCases(cases);
27 addMachOCases(cases);
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", .{
3132 .build_modes = true,
3233 .requires_stage2 = true,
3334 });
......@@ -42,23 +43,18 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
4243 .requires_stage2 = true,
4344 });
4445
45 cases.addBuildFile("test/link/wasm/bss/build.zig", .{
46 cases.addBuildFile("test/link/wasm/type/build.zig", .{
4647 .build_modes = true,
4748 .requires_stage2 = true,
4849 });
4950
50 cases.addBuildFile("test/link/macho/entry/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", .{
51 cases.addBuildFile("test/link/wasm/archive/build.zig", .{
5952 .build_modes = true,
53 .requires_stage2 = true,
6054 });
55}
6156
57fn addMachOCases(cases: *tests.StandaloneContext) void {
6258 cases.addBuildFile("test/link/macho/dead_strip/build.zig", .{
6359 .build_modes = false,
6460 });
......@@ -68,45 +64,59 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
6864 .requires_macos_sdk = true,
6965 });
7066
71 cases.addBuildFile("test/link/macho/needed_library/build.zig", .{
67 cases.addBuildFile("test/link/macho/dylib/build.zig", .{
7268 .build_modes = true,
7369 });
7470
75 cases.addBuildFile("test/link/macho/weak_library/build.zig", .{
71 cases.addBuildFile("test/link/macho/entry/build.zig", .{
7672 .build_modes = true,
7773 });
7874
79 cases.addBuildFile("test/link/macho/needed_framework/build.zig", .{
75 cases.addBuildFile("test/link/macho/headerpad/build.zig", .{
8076 .build_modes = true,
8177 .requires_macos_sdk = true,
8278 });
8379
84 cases.addBuildFile("test/link/macho/weak_framework/build.zig", .{
80 cases.addBuildFile("test/link/macho/needed_framework/build.zig", .{
8581 .build_modes = true,
8682 .requires_macos_sdk = true,
8783 });
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
9089 cases.addBuildFile("test/link/macho/objc/build.zig", .{
9190 .build_modes = true,
9291 .requires_macos_sdk = true,
9392 });
9493
95 // Try to build and run an Objective-C++ executable.
9694 cases.addBuildFile("test/link/macho/objcpp/build.zig", .{
9795 .build_modes = true,
9896 .requires_macos_sdk = true,
9997 });
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
101107 cases.addBuildFile("test/link/macho/stack_size/build.zig", .{
102108 .build_modes = true,
103109 });
104110
105 cases.addBuildFile("test/link/macho/search_strategy/build.zig", .{
111 cases.addBuildFile("test/link/macho/tls/build.zig", .{
106112 .build_modes = true,
107113 });
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", .{
110120 .build_modes = true,
111121 .requires_macos_sdk = true,
112122 });
test/link/macho/dead_strip/build.zig+5-3
......@@ -4,13 +4,14 @@ const LibExeObjectStep = std.build.LibExeObjStep;
44
55pub fn build(b: *Builder) void {
66 const mode = b.standardReleaseOptions();
7 const target: std.zig.CrossTarget = .{ .os_tag = .macos };
78
89 const test_step = b.step("test", "Test the program");
910 test_step.dependOn(b.getInstallStep());
1011
1112 {
1213 // Without -dead_strip, we expect `iAmUnused` symbol present
13 const exe = createScenario(b, mode);
14 const exe = createScenario(b, mode, target);
1415
1516 const check = exe.checkObject(.macho);
1617 check.checkInSymtab();
......@@ -23,7 +24,7 @@ pub fn build(b: *Builder) void {
2324
2425 {
2526 // With -dead_strip, no `iAmUnused` symbol should be present
26 const exe = createScenario(b, mode);
27 const exe = createScenario(b, mode, target);
2728 exe.link_gc_sections = true;
2829
2930 const check = exe.checkObject(.macho);
......@@ -36,10 +37,11 @@ pub fn build(b: *Builder) void {
3637 }
3738}
3839
39fn createScenario(b: *Builder, mode: std.builtin.Mode) *LibExeObjectStep {
40fn createScenario(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarget) *LibExeObjectStep {
4041 const exe = b.addExecutable("test", null);
4142 exe.addCSourceFile("main.c", &[0][]const u8{});
4243 exe.setBuildMode(mode);
44 exe.setTarget(target);
4345 exe.linkLibC();
4446 return exe;
4547}
test/link/macho/pagezero/build.zig+3-2
......@@ -3,13 +3,14 @@ const Builder = std.build.Builder;
33
44pub fn build(b: *Builder) void {
55 const mode = b.standardReleaseOptions();
6 const target: std.zig.CrossTarget = .{ .os_tag = .macos };
67
78 const test_step = b.step("test", "Test");
89 test_step.dependOn(b.getInstallStep());
910
1011 {
1112 const exe = b.addExecutable("pagezero", null);
12 exe.setTarget(.{ .os_tag = .macos });
13 exe.setTarget(target);
1314 exe.setBuildMode(mode);
1415 exe.addCSourceFile("main.c", &.{});
1516 exe.linkLibC();
......@@ -29,7 +30,7 @@ pub fn build(b: *Builder) void {
2930
3031 {
3132 const exe = b.addExecutable("no_pagezero", null);
32 exe.setTarget(.{ .os_tag = .macos });
33 exe.setTarget(target);
3334 exe.setBuildMode(mode);
3435 exe.addCSourceFile("main.c", &.{});
3536 exe.linkLibC();
test/link/macho/search_strategy/build.zig+4-4
......@@ -1,17 +1,17 @@
11const std = @import("std");
22const Builder = std.build.Builder;
33const LibExeObjectStep = std.build.LibExeObjStep;
4const target: std.zig.CrossTarget = .{ .os_tag = .macos };
54
65pub fn build(b: *Builder) void {
76 const mode = b.standardReleaseOptions();
7 const target: std.zig.CrossTarget = .{ .os_tag = .macos };
88
99 const test_step = b.step("test", "Test");
1010 test_step.dependOn(b.getInstallStep());
1111
1212 {
1313 // -search_dylibs_first
14 const exe = createScenario(b, mode);
14 const exe = createScenario(b, mode, target);
1515 exe.search_strategy = .dylibs_first;
1616
1717 const check = exe.checkObject(.macho);
......@@ -26,7 +26,7 @@ pub fn build(b: *Builder) void {
2626
2727 {
2828 // -search_paths_first
29 const exe = createScenario(b, mode);
29 const exe = createScenario(b, mode, target);
3030 exe.search_strategy = .paths_first;
3131
3232 const run = std.build.EmulatableRunStep.create(b, "run", exe);
......@@ -36,7 +36,7 @@ pub fn build(b: *Builder) void {
3636 }
3737}
3838
39fn createScenario(b: *Builder, mode: std.builtin.Mode) *LibExeObjectStep {
39fn createScenario(b: *Builder, mode: std.builtin.Mode, target: std.zig.CrossTarget) *LibExeObjectStep {
4040 const static = b.addStaticLibrary("a", null);
4141 static.setTarget(target);
4242 static.setBuildMode(mode);
test/link/macho/stack_size/build.zig+2-1
......@@ -3,12 +3,13 @@ const Builder = std.build.Builder;
33
44pub fn build(b: *Builder) void {
55 const mode = b.standardReleaseOptions();
6 const target: std.zig.CrossTarget = .{ .os_tag = .macos };
67
78 const test_step = b.step("test", "Test");
89 test_step.dependOn(b.getInstallStep());
910
1011 const exe = b.addExecutable("main", null);
11 exe.setTarget(.{ .os_tag = .macos });
12 exe.setTarget(target);
1213 exe.setBuildMode(mode);
1314 exe.addCSourceFile("main.c", &.{});
1415 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 {
2121 },
2222 .ReleaseSafe = .{
2323 .exclude_os = .{
24 .windows, // segfault
24 .windows, // TODO
25 .linux, // defeated by aggressive inlining
2526 },
2627 .expect =
2728 \\error: TheSkyIsFalling
......@@ -70,7 +71,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
7071 },
7172 .ReleaseSafe = .{
7273 .exclude_os = .{
73 .windows, // segfault
74 .windows, // TODO
7475 },
7576 .expect =
7677 \\error: TheSkyIsFalling
......@@ -136,7 +137,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
136137 },
137138 .ReleaseSafe = .{
138139 .exclude_os = .{
139 .windows, // segfault
140 .windows, // TODO
140141 },
141142 .expect =
142143 \\error: TheSkyIsFalling
......@@ -172,7 +173,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
172173 cases.addCase(.{
173174 .exclude_os = .{
174175 .openbsd, // integer overflow
175 .windows,
176 .windows, // TODO intermittent failures
176177 },
177178 .name = "dumpCurrentStackTrace",
178179 .source =
test/stage2/cbe.zig-9
......@@ -704,15 +704,6 @@ pub fn addCases(ctx: *TestContext) !void {
704704 ":5:9: error: '_' is used to mark an enum as non-exhaustive and cannot be assigned a value",
705705 });
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
716707 case.addError(
717708 \\const E1 = enum { a, b, _ };
718709 \\export fn foo() void {
test/standalone.zig+6-2
......@@ -9,6 +9,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
99 if (builtin.zig_backend == .stage1) { // https://github.com/ziglang/zig/issues/6025
1010 cases.add("test/standalone/issue_9693/main.zig");
1111 }
12 cases.add("test/standalone/issue_12471/main.zig");
1213 cases.add("test/standalone/guess_number/main.zig");
1314 cases.add("test/standalone/main_return_error/error_u8.zig");
1415 cases.add("test/standalone/main_return_error/error_u8_non_zero.zig");
......@@ -34,13 +35,16 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
3435 if (builtin.zig_backend == .stage1) { // https://github.com/ziglang/zig/issues/12194
3536 cases.addBuildFile("test/standalone/issue_9812/build.zig", .{});
3637 }
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 }
3842 if (builtin.os.tag != .wasi) {
3943 cases.addBuildFile("test/standalone/load_dynamic_library/build.zig", .{});
4044 }
4145 // C ABI compatibility issue: https://github.com/ziglang/zig/issues/1481
4246 if (builtin.cpu.arch == .x86_64) {
43 if (builtin.zig_backend == .stage1) { // https://github.com/ziglang/zig/issues/12222
47 if (builtin.zig_backend == .stage1 or builtin.zig_backend == .stage2_llvm) { // https://github.com/ziglang/zig/issues/12222
4448 cases.addBuildFile("test/c_abi/build.zig", .{});
4549 }
4650 }
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(
605605 skip_libc: bool,
606606 skip_stage1: bool,
607607 skip_stage2: bool,
608 is_stage1: bool,
609608) *build.Step {
610609 const step = b.step(b.fmt("test-{s}", .{name}), desc);
611610
......@@ -633,14 +632,22 @@ pub fn addPkgTests(
633632
634633 if (test_target.backend) |backend| switch (backend) {
635634 .stage1 => if (skip_stage1) continue,
635 .stage2_llvm => {},
636636 else => if (skip_stage2) continue,
637 } else if (is_stage1 and skip_stage1) continue;
637 };
638638
639639 const want_this_mode = for (modes) |m| {
640640 if (m == test_target.mode) break true;
641641 } else false;
642642 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
644651 const libc_prefix = if (test_target.target.getOs().requiresLibC())
645652 ""
646653 else if (test_target.link_libc)
......@@ -917,7 +924,7 @@ pub const StackTracesContext = struct {
917924 pos = marks[i] + delim.len;
918925 }
919926 // 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 {
921928 // unexpected pattern: emit raw line and cont
922929 try buf.appendSlice(line);
923930 try buf.appendSlice("\n");
......@@ -929,9 +936,9 @@ pub const StackTracesContext = struct {
929936 try buf.appendSlice(line[pos + 1 .. marks[2] + delims[2].len]);
930937 try buf.appendSlice(" [address]");
931938 if (self.mode == .Debug) {
932 if (mem.lastIndexOfScalar(u8, line[marks[4]..marks[5]], '.')) |idot| {
933 // On certain platforms (windows) or possibly depending on how we choose to link main
934 // the object file extension may be present so we simply strip any extension.
939 // On certain platforms (windows) or possibly depending on how we choose to link main
940 // the object file extension may be present so we simply strip any extension.
941 if (mem.indexOfScalar(u8, line[marks[4]..marks[5]], '.')) |idot| {
935942 try buf.appendSlice(line[marks[3] .. marks[4] + idot]);
936943 try buf.appendSlice(line[marks[5]..]);
937944 } else {
test/translate_c.zig+33-9
......@@ -1485,7 +1485,19 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
14851485 , &[_][]const u8{
14861486 \\pub export fn ptrcast() [*c]f32 {
14871487 \\ 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));
14891501 \\}
14901502 });
14911503
......@@ -1509,23 +1521,23 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
15091521 \\pub export fn test_ptr_cast() void {
15101522 \\ var p: ?*anyopaque = undefined;
15111523 \\ {
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));
15131525 \\ _ = 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));
15151527 \\ _ = 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));
15171529 \\ _ = 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));
15191531 \\ _ = to_longlong;
15201532 \\ }
15211533 \\ {
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));
15231535 \\ _ = 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));
15251537 \\ _ = 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));
15271539 \\ _ = 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));
15291541 \\ _ = to_longlong;
15301542 \\ }
15311543 \\}
......@@ -3830,4 +3842,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
38303842 , &[_][]const u8{
38313843 \\pub const FOO = "";
38323844 });
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 });
38333857}
tools/gen_spirv_spec.zig+2-2
......@@ -299,11 +299,11 @@ fn renderBitEnum(
299299 for (enumerants) |enumerant, i| {
300300 if (enumerant.value != .bitflag) return error.InvalidRegistry;
301301 const value = try parseHexInt(enumerant.value.bitflag);
302 if (@popCount(u32, value) == 0) {
302 if (@popCount(value) == 0) {
303303 continue; // Skip 'none' items
304304 }
305305
306 std.debug.assert(@popCount(u32, value) == 1);
306 std.debug.assert(@popCount(value) == 1);
307307
308308 var bitpos = std.math.log2_int(u32, value);
309309 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)
389389 const S = struct {
390390 fn endianSwap(x: anytype) @TypeOf(x) {
391391 if (endian != native_endian) {
392 return @byteSwap(@TypeOf(x), x);
392 return @byteSwap(x);
393393 } else {
394394 return x;
395395 }
tools/update_clang_options.zig+32-8
......@@ -352,6 +352,26 @@ const known_options = [_]KnownOpt{
352352 .name = "fno-stack-check",
353353 .ident = "no_stack_check",
354354 },
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 },
355375 .{
356376 .name = "MD",
357377 .ident = "dep_file",
......@@ -386,11 +406,15 @@ const known_options = [_]KnownOpt{
386406 },
387407 .{
388408 .name = "MM",
389 .ident = "dep_file_mm",
409 .ident = "dep_file_to_stdout",
410 },
411 .{
412 .name = "M",
413 .ident = "dep_file_to_stdout",
390414 },
391415 .{
392416 .name = "user-dependencies",
393 .ident = "dep_file_mm",
417 .ident = "dep_file_to_stdout",
394418 },
395419 .{
396420 .name = "MMD",
......@@ -648,9 +672,9 @@ pub fn main() anyerror!void {
648672 \\ .name = "{s}",
649673 \\ .syntax = {s},
650674 \\ .zig_equivalent = .{s},
651 \\ .pd1 = {any},
652 \\ .pd2 = {any},
653 \\ .psl = {any},
675 \\ .pd1 = {},
676 \\ .pd2 = {},
677 \\ .psl = {},
654678 \\}},
655679 \\
656680 , .{ name, final_syntax, ident, pd1, pd2, pslash });
......@@ -678,9 +702,9 @@ pub fn main() anyerror!void {
678702 \\ .name = "{s}",
679703 \\ .syntax = {s},
680704 \\ .zig_equivalent = .other,
681 \\ .pd1 = {any},
682 \\ .pd2 = {any},
683 \\ .psl = {any},
705 \\ .pd1 = {},
706 \\ .pd2 = {},
707 \\ .psl = {},
684708 \\}},
685709 \\
686710 , .{ name, syntax, pd1, pd2, pslash });