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

This commit is contained in:
Andrew Kelley 2022-08-29 14:10:59 -07:00
commit de7270028d
319 changed files with 14392 additions and 8717 deletions

View File

@ -12,7 +12,7 @@ if(NOT CMAKE_BUILD_TYPE)
endif() endif()
if(NOT CMAKE_INSTALL_PREFIX) if(NOT CMAKE_INSTALL_PREFIX)
set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/stage1" CACHE STRING set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/stage3" CACHE STRING
"Directory to install zig to" FORCE) "Directory to install zig to" FORCE)
endif() endif()
@ -65,6 +65,9 @@ if("${ZIG_VERSION}" STREQUAL "")
endif() endif()
message(STATUS "Configuring zig version ${ZIG_VERSION}") message(STATUS "Configuring zig version ${ZIG_VERSION}")
set(ZIG_SKIP_INSTALL_LIB_FILES off CACHE BOOL
"Disable copying lib/ files to install prefix during the build phase")
set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)") set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)")
set(ZIG_SHARED_LLVM off CACHE BOOL "Prefer linking against shared LLVM libraries") set(ZIG_SHARED_LLVM off CACHE BOOL "Prefer linking against shared LLVM libraries")
set(ZIG_STATIC_LLVM off CACHE BOOL "Prefer linking against static LLVM libraries") set(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")
set(ZIG_CONFIG_ZIG_OUT "${CMAKE_BINARY_DIR}/config.zig") set(ZIG_CONFIG_ZIG_OUT "${CMAKE_BINARY_DIR}/config.zig")
# This is our shim which will be replaced by stage1.zig. # This is our shim which will be replaced by stage1.zig.
set(ZIG0_SOURCES set(ZIG1_SOURCES
"${CMAKE_SOURCE_DIR}/src/stage1/zig0.cpp" "${CMAKE_SOURCE_DIR}/src/stage1/zig0.cpp"
) )
@ -373,9 +376,9 @@ set(ZIG_CPP_SOURCES
# https://github.com/ziglang/zig/issues/6363 # https://github.com/ziglang/zig/issues/6363
"${CMAKE_SOURCE_DIR}/src/windows_sdk.cpp" "${CMAKE_SOURCE_DIR}/src/windows_sdk.cpp"
) )
# Needed because we use cmake, not the zig build system, to build zig1.o. # Needed because we use cmake, not the zig build system, to build zig2.o.
# This list is generated by building zig and then clearing the zig-cache directory, # This list is generated by building zig and then clearing the zig-cache directory,
# then manually running the build-obj command (see BUILD_ZIG1_ARGS), and then looking # then manually running the build-obj command (see BUILD_ZIG2_ARGS), and then looking
# in the zig-cache directory for the compiler-generated list of zig file dependencies. # in the zig-cache directory for the compiler-generated list of zig file dependencies.
set(ZIG_STAGE2_SOURCES set(ZIG_STAGE2_SOURCES
"${ZIG_CONFIG_ZIG_OUT}" "${ZIG_CONFIG_ZIG_OUT}"
@ -942,40 +945,51 @@ if(MSVC OR MINGW)
endif() endif()
if("${ZIG_EXECUTABLE}" STREQUAL "") if("${ZIG_EXECUTABLE}" STREQUAL "")
add_executable(zig0 ${ZIG0_SOURCES}) add_executable(zig1 ${ZIG1_SOURCES})
set_target_properties(zig0 PROPERTIES set_target_properties(zig1 PROPERTIES
COMPILE_FLAGS ${EXE_CFLAGS} COMPILE_FLAGS ${EXE_CFLAGS}
LINK_FLAGS ${EXE_LDFLAGS} LINK_FLAGS ${EXE_LDFLAGS}
) )
target_link_libraries(zig0 zigstage1) target_link_libraries(zig1 zigstage1)
endif() endif()
if(MSVC) if(MSVC)
set(ZIG1_OBJECT "${CMAKE_BINARY_DIR}/zig1.obj") set(ZIG2_OBJECT "${CMAKE_BINARY_DIR}/zig2.obj")
else() else()
set(ZIG1_OBJECT "${CMAKE_BINARY_DIR}/zig1.o") set(ZIG2_OBJECT "${CMAKE_BINARY_DIR}/zig2.o")
endif() endif()
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
set(ZIG1_RELEASE_ARG "") set(ZIG_RELEASE_ARG "")
elseif("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo")
set(ZIG_RELEASE_ARG -Drelease)
else() else()
set(ZIG1_RELEASE_ARG -OReleaseFast --strip) set(ZIG_RELEASE_ARG -Drelease -Dstrip)
endif()
if(ZIG_SKIP_INSTALL_LIB_FILES)
set(ZIG_SKIP_INSTALL_LIB_FILES_ARG "-Dskip-install-lib-files")
else()
set(ZIG_SKIP_INSTALL_LIB_FILES_ARG "-Dskip-install-lib-files=false")
endif() endif()
if(ZIG_SINGLE_THREADED) if(ZIG_SINGLE_THREADED)
set(ZIG1_SINGLE_THREADED_ARG "-fsingle-threaded") set(ZIG_SINGLE_THREADED_ARG "-fsingle-threaded")
else() else()
set(ZIG1_SINGLE_THREADED_ARG "") set(ZIG_SINGLE_THREADED_ARG "")
endif()
if(ZIG_STATIC)
set(ZIG_STATIC_ARG "-Duse-zig-libcxx")
else()
set(ZIG_STATIC_ARG "")
endif() endif()
set(BUILD_ZIG1_ARGS set(BUILD_ZIG2_ARGS
"src/stage1.zig" "src/stage1.zig"
-target "${ZIG_TARGET_TRIPLE}" --name zig2
"-mcpu=${ZIG_TARGET_MCPU}"
--name zig1
--zig-lib-dir "${CMAKE_SOURCE_DIR}/lib" --zig-lib-dir "${CMAKE_SOURCE_DIR}/lib"
"-femit-bin=${ZIG1_OBJECT}" "-femit-bin=${ZIG2_OBJECT}"
-fcompiler-rt -fcompiler-rt
"${ZIG1_RELEASE_ARG}" ${ZIG_SINGLE_THREADED_ARG}
"${ZIG1_SINGLE_THREADED_ARG}" -target "${ZIG_TARGET_TRIPLE}"
-mcpu "${ZIG_TARGET_MCPU}"
-lc -lc
--pkg-begin build_options "${ZIG_CONFIG_ZIG_OUT}" --pkg-begin build_options "${ZIG_CONFIG_ZIG_OUT}"
--pkg-end --pkg-end
@ -985,68 +999,64 @@ set(BUILD_ZIG1_ARGS
if("${ZIG_EXECUTABLE}" STREQUAL "") if("${ZIG_EXECUTABLE}" STREQUAL "")
add_custom_command( add_custom_command(
OUTPUT "${ZIG1_OBJECT}" OUTPUT "${ZIG2_OBJECT}"
COMMAND zig0 ${BUILD_ZIG1_ARGS} COMMAND zig1 ${BUILD_ZIG2_ARGS}
DEPENDS zig0 "${ZIG_STAGE2_SOURCES}" DEPENDS zig1 "${ZIG_STAGE2_SOURCES}"
COMMENT STATUS "Building self-hosted component ${ZIG1_OBJECT}" COMMENT STATUS "Building stage2 object ${ZIG2_OBJECT}"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
) )
set(ZIG_EXECUTABLE "${zig_BINARY_DIR}/zig")
if (WIN32) if (WIN32)
set(ZIG_EXECUTABLE "${ZIG_EXECUTABLE}.exe") set(ZIG_EXECUTABLE "${zig2_BINARY_DIR}/zig2.exe")
else()
set(ZIG_EXECUTABLE "${zig2_BINARY_DIR}/zig2")
endif() endif()
else() else()
add_custom_command( add_custom_command(
OUTPUT "${ZIG1_OBJECT}" OUTPUT "${ZIG2_OBJECT}"
COMMAND "${ZIG_EXECUTABLE}" "build-obj" ${BUILD_ZIG1_ARGS} COMMAND "${ZIG_EXECUTABLE}" "build-obj" ${BUILD_ZIG2_ARGS}
DEPENDS ${ZIG_STAGE2_SOURCES} DEPENDS ${ZIG_STAGE2_SOURCES}
COMMENT STATUS "Building self-hosted component ${ZIG1_OBJECT}" COMMENT STATUS "Building stage2 component ${ZIG2_OBJECT}"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
) )
endif() endif()
# cmake won't let us configure an executable without C sources. # cmake won't let us configure an executable without C sources.
add_executable(zig "${CMAKE_SOURCE_DIR}/src/stage1/empty.cpp" "${ZIG1_OBJECT}") add_executable(zig2 "${CMAKE_SOURCE_DIR}/src/stage1/empty.cpp" "${ZIG2_OBJECT}")
set_target_properties(zig PROPERTIES set_target_properties(zig2 PROPERTIES
COMPILE_FLAGS ${EXE_CFLAGS} COMPILE_FLAGS ${EXE_CFLAGS}
LINK_FLAGS ${EXE_LDFLAGS} LINK_FLAGS ${EXE_LDFLAGS}
) )
target_link_libraries(zig zigstage1) target_link_libraries(zig2 zigstage1)
if(MSVC) if(MSVC)
target_link_libraries(zig ntdll.lib) target_link_libraries(zig2 ntdll.lib)
elseif(MINGW) elseif(MINGW)
target_link_libraries(zig ntdll) target_link_libraries(zig2 ntdll)
endif() endif()
install(TARGETS zig DESTINATION bin) # Dummy install command so that the "install" target is not missing.
# This is redundant from the "stage3" custom target below.
set(ZIG_SKIP_INSTALL_LIB_FILES off CACHE BOOL
"Disable copying lib/ files to install prefix during the build phase")
if(NOT ZIG_SKIP_INSTALL_LIB_FILES) if(NOT ZIG_SKIP_INSTALL_LIB_FILES)
set(ZIG_INSTALL_ARGS "build" install(FILES "lib/compiler_rt.zig" DESTINATION "lib/zig")
--zig-lib-dir "${CMAKE_SOURCE_DIR}/lib"
"-Dlib-files-only"
--prefix "${CMAKE_INSTALL_PREFIX}"
"-Dconfig_h=${ZIG_CONFIG_H_OUT}"
install
)
# CODE has no effect with Visual Studio build system generator, therefore
# when using Visual Studio build system generator we resort to running
# `zig build install` during the build phase.
if(MSVC)
add_custom_target(zig_install_lib_files ALL
COMMAND zig ${ZIG_INSTALL_ARGS}
DEPENDS zig
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
)
else()
get_target_property(zig_BINARY_DIR zig BINARY_DIR)
install(CODE "set(zig_EXE \"${ZIG_EXECUTABLE}\")")
install(CODE "set(ZIG_INSTALL_ARGS \"${ZIG_INSTALL_ARGS}\")")
install(CODE "set(CMAKE_SOURCE_DIR \"${CMAKE_SOURCE_DIR}\")")
install(SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/cmake/install.cmake)
endif()
endif() endif()
set(ZIG_INSTALL_ARGS "build"
--zig-lib-dir "${CMAKE_SOURCE_DIR}/lib"
--prefix "${CMAKE_INSTALL_PREFIX}"
"-Dconfig_h=${ZIG_CONFIG_H_OUT}"
"-Denable-llvm"
"-Denable-stage1"
${ZIG_RELEASE_ARG}
${ZIG_STATIC_ARG}
${ZIG_SKIP_INSTALL_LIB_FILES_ARG}
${ZIG_SINGLE_THREADED_ARG}
"-Dtarget=${ZIG_TARGET_TRIPLE}"
"-Dcpu=${ZIG_TARGET_MCPU}"
)
add_custom_target(stage3 ALL
COMMAND zig2 ${ZIG_INSTALL_ARGS}
DEPENDS zig2
COMMENT STATUS "Building stage3"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
)

View File

@ -15,6 +15,7 @@ const stack_size = 32 * 1024 * 1024;
pub fn build(b: *Builder) !void { pub fn build(b: *Builder) !void {
b.setPreferredReleaseMode(.ReleaseFast); b.setPreferredReleaseMode(.ReleaseFast);
const test_step = b.step("test", "Run all the tests");
const mode = b.standardReleaseOptions(); const mode = b.standardReleaseOptions();
const target = b.standardTargetOptions(.{}); const target = b.standardTargetOptions(.{});
const single_threaded = b.option(bool, "single-threaded", "Build artifacts that run in single threaded mode"); 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 {
const docs_step = b.step("docs", "Build documentation"); const docs_step = b.step("docs", "Build documentation");
docs_step.dependOn(&docgen_cmd.step); docs_step.dependOn(&docgen_cmd.step);
const toolchain_step = b.step("test-toolchain", "Run the tests for the toolchain");
var test_cases = b.addTest("src/test.zig"); var test_cases = b.addTest("src/test.zig");
test_cases.stack_size = stack_size; test_cases.stack_size = stack_size;
test_cases.setBuildMode(mode); test_cases.setBuildMode(mode);
@ -64,10 +63,9 @@ pub fn build(b: *Builder) !void {
const only_install_lib_files = b.option(bool, "lib-files-only", "Only install library files") orelse false; const only_install_lib_files = b.option(bool, "lib-files-only", "Only install library files") orelse false;
const is_stage1 = b.option(bool, "stage1", "Build the stage1 compiler, put stage2 behind a feature flag") orelse false; const have_stage1 = b.option(bool, "enable-stage1", "Include the stage1 compiler behind a feature flag") orelse false;
const omit_stage2 = b.option(bool, "omit-stage2", "Do not include stage2 behind a feature flag inside stage1") orelse false;
const static_llvm = b.option(bool, "static-llvm", "Disable integration with system-installed LLVM, Clang, LLD, and libc++") orelse false; const static_llvm = b.option(bool, "static-llvm", "Disable integration with system-installed LLVM, Clang, LLD, and libc++") orelse false;
const enable_llvm = b.option(bool, "enable-llvm", "Build self-hosted compiler with LLVM backend enabled") orelse (is_stage1 or static_llvm); const enable_llvm = b.option(bool, "enable-llvm", "Build self-hosted compiler with LLVM backend enabled") orelse (have_stage1 or static_llvm);
const llvm_has_m68k = b.option( const llvm_has_m68k = b.option(
bool, bool,
"llvm-has-m68k", "llvm-has-m68k",
@ -137,7 +135,7 @@ pub fn build(b: *Builder) !void {
}; };
const main_file: ?[]const u8 = mf: { const main_file: ?[]const u8 = mf: {
if (!is_stage1) break :mf "src/main.zig"; if (!have_stage1) break :mf "src/main.zig";
if (use_zig0) break :mf null; if (use_zig0) break :mf null;
break :mf "src/stage1.zig"; break :mf "src/stage1.zig";
}; };
@ -150,7 +148,7 @@ pub fn build(b: *Builder) !void {
exe.setBuildMode(mode); exe.setBuildMode(mode);
exe.setTarget(target); exe.setTarget(target);
if (!skip_stage2_tests) { if (!skip_stage2_tests) {
toolchain_step.dependOn(&exe.step); test_step.dependOn(&exe.step);
} }
b.default_step.dependOn(&exe.step); b.default_step.dependOn(&exe.step);
@ -248,7 +246,7 @@ pub fn build(b: *Builder) !void {
} }
}; };
if (is_stage1) { if (have_stage1) {
const softfloat = b.addStaticLibrary("softfloat", null); const softfloat = b.addStaticLibrary("softfloat", null);
softfloat.setBuildMode(.ReleaseFast); softfloat.setBuildMode(.ReleaseFast);
softfloat.setTarget(target); softfloat.setTarget(target);
@ -360,8 +358,7 @@ pub fn build(b: *Builder) !void {
exe_options.addOption(bool, "enable_tracy_callstack", tracy_callstack); exe_options.addOption(bool, "enable_tracy_callstack", tracy_callstack);
exe_options.addOption(bool, "enable_tracy_allocation", tracy_allocation); exe_options.addOption(bool, "enable_tracy_allocation", tracy_allocation);
exe_options.addOption(bool, "value_tracing", value_tracing); exe_options.addOption(bool, "value_tracing", value_tracing);
exe_options.addOption(bool, "is_stage1", is_stage1); exe_options.addOption(bool, "have_stage1", have_stage1);
exe_options.addOption(bool, "omit_stage2", omit_stage2);
if (tracy) |tracy_path| { if (tracy) |tracy_path| {
const client_cpp = fs.path.join( const client_cpp = fs.path.join(
b.allocator, b.allocator,
@ -396,8 +393,7 @@ pub fn build(b: *Builder) !void {
test_cases_options.addOption(bool, "enable_link_snapshots", enable_link_snapshots); test_cases_options.addOption(bool, "enable_link_snapshots", enable_link_snapshots);
test_cases_options.addOption(bool, "skip_non_native", skip_non_native); test_cases_options.addOption(bool, "skip_non_native", skip_non_native);
test_cases_options.addOption(bool, "skip_stage1", skip_stage1); test_cases_options.addOption(bool, "skip_stage1", skip_stage1);
test_cases_options.addOption(bool, "is_stage1", is_stage1); test_cases_options.addOption(bool, "have_stage1", have_stage1);
test_cases_options.addOption(bool, "omit_stage2", omit_stage2);
test_cases_options.addOption(bool, "have_llvm", enable_llvm); test_cases_options.addOption(bool, "have_llvm", enable_llvm);
test_cases_options.addOption(bool, "llvm_has_m68k", llvm_has_m68k); test_cases_options.addOption(bool, "llvm_has_m68k", llvm_has_m68k);
test_cases_options.addOption(bool, "llvm_has_csky", llvm_has_csky); test_cases_options.addOption(bool, "llvm_has_csky", llvm_has_csky);
@ -418,7 +414,7 @@ pub fn build(b: *Builder) !void {
const test_cases_step = b.step("test-cases", "Run the main compiler test cases"); const test_cases_step = b.step("test-cases", "Run the main compiler test cases");
test_cases_step.dependOn(&test_cases.step); test_cases_step.dependOn(&test_cases.step);
if (!skip_stage2_tests) { if (!skip_stage2_tests) {
toolchain_step.dependOn(test_cases_step); test_step.dependOn(test_cases_step);
} }
var chosen_modes: [4]builtin.Mode = undefined; var chosen_modes: [4]builtin.Mode = undefined;
@ -442,11 +438,11 @@ pub fn build(b: *Builder) !void {
const modes = chosen_modes[0..chosen_mode_index]; const modes = chosen_modes[0..chosen_mode_index];
// run stage1 `zig fmt` on this build.zig file just to make sure it works // run stage1 `zig fmt` on this build.zig file just to make sure it works
toolchain_step.dependOn(&fmt_build_zig.step); test_step.dependOn(&fmt_build_zig.step);
const fmt_step = b.step("test-fmt", "Run zig fmt against build.zig to make sure it works"); const fmt_step = b.step("test-fmt", "Run zig fmt against build.zig to make sure it works");
fmt_step.dependOn(&fmt_build_zig.step); fmt_step.dependOn(&fmt_build_zig.step);
toolchain_step.dependOn(tests.addPkgTests( test_step.dependOn(tests.addPkgTests(
b, b,
test_filter, test_filter,
"test/behavior.zig", "test/behavior.zig",
@ -457,11 +453,10 @@ pub fn build(b: *Builder) !void {
skip_non_native, skip_non_native,
skip_libc, skip_libc,
skip_stage1, skip_stage1,
omit_stage2, skip_stage2_tests,
is_stage1,
)); ));
toolchain_step.dependOn(tests.addPkgTests( test_step.dependOn(tests.addPkgTests(
b, b,
test_filter, test_filter,
"lib/compiler_rt.zig", "lib/compiler_rt.zig",
@ -472,11 +467,10 @@ pub fn build(b: *Builder) !void {
skip_non_native, skip_non_native,
true, // skip_libc true, // skip_libc
skip_stage1, skip_stage1,
omit_stage2 or true, // TODO get these all passing skip_stage2_tests or true, // TODO get these all passing
is_stage1,
)); ));
toolchain_step.dependOn(tests.addPkgTests( test_step.dependOn(tests.addPkgTests(
b, b,
test_filter, test_filter,
"lib/c.zig", "lib/c.zig",
@ -487,37 +481,36 @@ pub fn build(b: *Builder) !void {
skip_non_native, skip_non_native,
true, // skip_libc true, // skip_libc
skip_stage1, skip_stage1,
omit_stage2 or true, // TODO get these all passing skip_stage2_tests or true, // TODO get these all passing
is_stage1,
)); ));
toolchain_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes)); test_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes));
toolchain_step.dependOn(tests.addStandaloneTests( test_step.dependOn(tests.addStandaloneTests(
b, b,
test_filter, test_filter,
modes, modes,
skip_non_native, skip_non_native,
enable_macos_sdk, enable_macos_sdk,
target, target,
omit_stage2, skip_stage2_tests,
b.enable_darling, b.enable_darling,
b.enable_qemu, b.enable_qemu,
b.enable_rosetta, b.enable_rosetta,
b.enable_wasmtime, b.enable_wasmtime,
b.enable_wine, b.enable_wine,
)); ));
toolchain_step.dependOn(tests.addLinkTests(b, test_filter, modes, enable_macos_sdk, omit_stage2)); test_step.dependOn(tests.addLinkTests(b, test_filter, modes, enable_macos_sdk, skip_stage2_tests));
toolchain_step.dependOn(tests.addStackTraceTests(b, test_filter, modes)); test_step.dependOn(tests.addStackTraceTests(b, test_filter, modes));
toolchain_step.dependOn(tests.addCliTests(b, test_filter, modes)); test_step.dependOn(tests.addCliTests(b, test_filter, modes));
toolchain_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes)); test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes));
toolchain_step.dependOn(tests.addTranslateCTests(b, test_filter)); test_step.dependOn(tests.addTranslateCTests(b, test_filter));
if (!skip_run_translated_c) { if (!skip_run_translated_c) {
toolchain_step.dependOn(tests.addRunTranslatedCTests(b, test_filter, target)); test_step.dependOn(tests.addRunTranslatedCTests(b, test_filter, target));
} }
// tests for this feature are disabled until we have the self-hosted compiler available // tests for this feature are disabled until we have the self-hosted compiler available
// toolchain_step.dependOn(tests.addGenHTests(b, test_filter)); // test_step.dependOn(tests.addGenHTests(b, test_filter));
const std_step = tests.addPkgTests( test_step.dependOn(tests.addPkgTests(
b, b,
test_filter, test_filter,
"lib/std/std.zig", "lib/std/std.zig",
@ -528,14 +521,8 @@ pub fn build(b: *Builder) !void {
skip_non_native, skip_non_native,
skip_libc, skip_libc,
skip_stage1, skip_stage1,
omit_stage2 or true, // TODO get these all passing true, // TODO get these all passing
is_stage1, ));
);
const test_step = b.step("test", "Run all the tests");
test_step.dependOn(toolchain_step);
test_step.dependOn(std_step);
test_step.dependOn(docs_step);
} }
const exe_cflags = [_][]const u8{ const exe_cflags = [_][]const u8{

View File

@ -1,976 +0,0 @@
const std = @import("std");
const builtin = std.builtin;
const Builder = std.build.Builder;
const BufMap = std.BufMap;
const mem = std.mem;
const ArrayList = std.ArrayList;
const io = std.io;
const fs = std.fs;
const InstallDirectoryOptions = std.build.InstallDirectoryOptions;
const assert = std.debug.assert;
const zig_version = std.builtin.Version{ .major = 0, .minor = 10, .patch = 0 };
pub fn build(b: *Builder) !void {
b.setPreferredReleaseMode(.ReleaseFast);
const mode = b.standardReleaseOptions();
const target = b.standardTargetOptions(.{});
const single_threaded = b.option(bool, "single-threaded", "Build artifacts that run in single threaded mode");
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;
const docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");
docgen_exe.single_threaded = single_threaded;
const rel_zig_exe = try fs.path.relative(b.allocator, b.build_root, b.zig_exe);
const langref_out_path = fs.path.join(
b.allocator,
&[_][]const u8{ b.cache_root, "langref.html" },
) catch unreachable;
const docgen_cmd = docgen_exe.run();
docgen_cmd.addArgs(&[_][]const u8{
rel_zig_exe,
"doc" ++ fs.path.sep_str ++ "langref.html.in",
langref_out_path,
});
docgen_cmd.step.dependOn(&docgen_exe.step);
const docs_step = b.step("docs", "Build documentation");
docs_step.dependOn(&docgen_cmd.step);
const is_stage1 = b.option(bool, "stage1", "Build the stage1 compiler, put stage2 behind a feature flag") orelse false;
const omit_stage2 = b.option(bool, "omit-stage2", "Do not include stage2 behind a feature flag inside stage1") orelse false;
const static_llvm = b.option(bool, "static-llvm", "Disable integration with system-installed LLVM, Clang, LLD, and libc++") orelse false;
const enable_llvm = b.option(bool, "enable-llvm", "Build self-hosted compiler with LLVM backend enabled") orelse (is_stage1 or static_llvm);
const llvm_has_m68k = b.option(
bool,
"llvm-has-m68k",
"Whether LLVM has the experimental target m68k enabled",
) orelse false;
const llvm_has_csky = b.option(
bool,
"llvm-has-csky",
"Whether LLVM has the experimental target csky enabled",
) orelse false;
const llvm_has_arc = b.option(
bool,
"llvm-has-arc",
"Whether LLVM has the experimental target arc enabled",
) orelse false;
const config_h_path_option = b.option([]const u8, "config_h", "Path to the generated config.h");
b.installDirectory(InstallDirectoryOptions{
.source_dir = "lib",
.install_dir = .lib,
.install_subdir = "zig",
.exclude_extensions = &[_][]const u8{
// exclude files from lib/std/compress/
".gz",
".z.0",
".z.9",
"rfc1951.txt",
"rfc1952.txt",
// exclude files from lib/std/compress/deflate/testdata
".expect",
".expect-noinput",
".golden",
".input",
"compress-e.txt",
"compress-gettysburg.txt",
"compress-pi.txt",
"rfc1951.txt",
// exclude files from lib/std/tz/
".tzif",
// others
"README.md",
},
.blank_extensions = &[_][]const u8{
"test.zig",
},
});
const tracy = b.option([]const u8, "tracy", "Enable Tracy integration. Supply path to Tracy source");
const tracy_callstack = b.option(bool, "tracy-callstack", "Include callstack information with Tracy data. Does nothing if -Dtracy is not provided") orelse false;
const tracy_allocation = b.option(bool, "tracy-allocation", "Include allocation information with Tracy data. Does nothing if -Dtracy is not provided") orelse false;
const force_gpa = b.option(bool, "force-gpa", "Force the compiler to use GeneralPurposeAllocator") orelse false;
const link_libc = b.option(bool, "force-link-libc", "Force self-hosted compiler to link libc") orelse enable_llvm;
const strip = b.option(bool, "strip", "Omit debug information") orelse false;
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;
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: {
if (strip) break :blk @as(u32, 0);
if (mode != .Debug) break :blk 0;
break :blk 4;
};
const main_file: ?[]const u8 = if (is_stage1) null else "src/main.zig";
const exe = b.addExecutable("zig", main_file);
exe.strip = strip;
exe.install();
exe.setBuildMode(mode);
exe.setTarget(target);
b.default_step.dependOn(&exe.step);
exe.single_threaded = single_threaded;
if (target.isWindows() and target.getAbi() == .gnu) {
// LTO is currently broken on mingw, this can be removed when it's fixed.
exe.want_lto = false;
}
const exe_options = b.addOptions();
exe.addOptions("build_options", exe_options);
exe_options.addOption(u32, "mem_leak_frames", mem_leak_frames);
exe_options.addOption(bool, "skip_non_native", false);
exe_options.addOption(bool, "have_llvm", enable_llvm);
exe_options.addOption(bool, "llvm_has_m68k", llvm_has_m68k);
exe_options.addOption(bool, "llvm_has_csky", llvm_has_csky);
exe_options.addOption(bool, "llvm_has_arc", llvm_has_arc);
exe_options.addOption(bool, "force_gpa", force_gpa);
if (link_libc) {
exe.linkLibC();
}
const is_debug = mode == .Debug;
const enable_logging = b.option(bool, "log", "Enable debug logging with --debug-log") orelse is_debug;
const enable_link_snapshots = b.option(bool, "link-snapshot", "Whether to enable linker state snapshots") orelse false;
const opt_version_string = b.option([]const u8, "version-string", "Override Zig version string. Default is to find out with git.");
const version = if (opt_version_string) |version| version else v: {
const version_string = b.fmt("{d}.{d}.{d}", .{ zig_version.major, zig_version.minor, zig_version.patch });
var code: u8 = undefined;
const git_describe_untrimmed = b.execAllowFail(&[_][]const u8{
"git", "-C", b.build_root, "describe", "--match", "*.*.*", "--tags",
}, &code, .Ignore) catch {
break :v version_string;
};
const git_describe = mem.trim(u8, git_describe_untrimmed, " \n\r");
switch (mem.count(u8, git_describe, "-")) {
0 => {
// Tagged release version (e.g. 0.9.0).
if (!mem.eql(u8, git_describe, version_string)) {
std.debug.print("Zig version '{s}' does not match Git tag '{s}'\n", .{ version_string, git_describe });
std.process.exit(1);
}
break :v version_string;
},
2 => {
// Untagged development build (e.g. 0.9.0-dev.2025+ecf0050a9).
var it = mem.split(u8, git_describe, "-");
const tagged_ancestor = it.next() orelse unreachable;
const commit_height = it.next() orelse unreachable;
const commit_id = it.next() orelse unreachable;
const ancestor_ver = try std.builtin.Version.parse(tagged_ancestor);
if (zig_version.order(ancestor_ver) != .gt) {
std.debug.print("Zig version '{}' must be greater than tagged ancestor '{}'\n", .{ zig_version, ancestor_ver });
std.process.exit(1);
}
// Check that the commit hash is prefixed with a 'g' (a Git convention).
if (commit_id.len < 1 or commit_id[0] != 'g') {
std.debug.print("Unexpected `git describe` output: {s}\n", .{git_describe});
break :v version_string;
}
// The version is reformatted in accordance with the https://semver.org specification.
break :v b.fmt("{s}-dev.{s}+{s}", .{ version_string, commit_height, commit_id[1..] });
},
else => {
std.debug.print("Unexpected `git describe` output: {s}\n", .{git_describe});
break :v version_string;
},
}
};
exe_options.addOption([:0]const u8, "version", try b.allocator.dupeZ(u8, version));
if (enable_llvm) {
const cmake_cfg = if (static_llvm) null else findAndParseConfigH(b, config_h_path_option);
if (is_stage1) {
const softfloat = b.addStaticLibrary("softfloat", null);
softfloat.setBuildMode(.ReleaseFast);
softfloat.setTarget(target);
softfloat.addIncludeDir("deps/SoftFloat-3e-prebuilt");
softfloat.addIncludeDir("deps/SoftFloat-3e/source/8086");
softfloat.addIncludeDir("deps/SoftFloat-3e/source/include");
softfloat.addCSourceFiles(&softfloat_sources, &[_][]const u8{ "-std=c99", "-O3" });
softfloat.single_threaded = single_threaded;
const zig0 = b.addExecutable("zig0", null);
zig0.addCSourceFiles(&.{"src/stage1/zig0.cpp"}, &exe_cflags);
zig0.addIncludeDir("zig-cache/tmp"); // for config.h
zig0.defineCMacro("ZIG_VERSION_MAJOR", b.fmt("{d}", .{zig_version.major}));
zig0.defineCMacro("ZIG_VERSION_MINOR", b.fmt("{d}", .{zig_version.minor}));
zig0.defineCMacro("ZIG_VERSION_PATCH", b.fmt("{d}", .{zig_version.patch}));
zig0.defineCMacro("ZIG_VERSION_STRING", b.fmt("\"{s}\"", .{version}));
for ([_]*std.build.LibExeObjStep{ zig0, exe }) |artifact| {
artifact.addIncludeDir("src");
artifact.addIncludeDir("deps/SoftFloat-3e/source/include");
artifact.addIncludeDir("deps/SoftFloat-3e-prebuilt");
artifact.defineCMacro("ZIG_LINK_MODE", "Static");
artifact.addCSourceFiles(&stage1_sources, &exe_cflags);
artifact.addCSourceFiles(&optimized_c_sources, &[_][]const u8{ "-std=c99", "-O3" });
artifact.linkLibrary(softfloat);
artifact.linkLibCpp();
}
try addStaticLlvmOptionsToExe(zig0);
const zig1_obj_ext = target.getObjectFormat().fileExt(target.getCpuArch());
const zig1_obj_path = b.pathJoin(&.{ "zig-cache", "tmp", b.fmt("zig1{s}", .{zig1_obj_ext}) });
const zig1_compiler_rt_path = b.pathJoin(&.{ b.pathFromRoot("lib"), "std", "special", "compiler_rt.zig" });
const zig1_obj = zig0.run();
zig1_obj.addArgs(&.{
"src/stage1.zig",
"-target",
try target.zigTriple(b.allocator),
"-mcpu=baseline",
"--name",
"zig1",
"--zig-lib-dir",
b.pathFromRoot("lib"),
b.fmt("-femit-bin={s}", .{b.pathFromRoot(zig1_obj_path)}),
"-fcompiler-rt",
"-lc",
});
{
zig1_obj.addArgs(&.{ "--pkg-begin", "build_options" });
zig1_obj.addFileSourceArg(exe_options.getSource());
zig1_obj.addArgs(&.{ "--pkg-end", "--pkg-begin", "compiler_rt", zig1_compiler_rt_path, "--pkg-end" });
}
switch (mode) {
.Debug => {},
.ReleaseFast => {
zig1_obj.addArg("-OReleaseFast");
zig1_obj.addArg("--strip");
},
.ReleaseSafe => {
zig1_obj.addArg("-OReleaseSafe");
zig1_obj.addArg("--strip");
},
.ReleaseSmall => {
zig1_obj.addArg("-OReleaseSmall");
zig1_obj.addArg("--strip");
},
}
if (single_threaded orelse false) {
zig1_obj.addArg("-fsingle-threaded");
}
exe.step.dependOn(&zig1_obj.step);
exe.addObjectFile(zig1_obj_path);
// This is intentionally a dummy path. stage1.zig tries to @import("compiler_rt") in case
// of being built by cmake. But when built by zig it's gonna get a compiler_rt so that
// is pointless.
exe.addPackagePath("compiler_rt", "src/empty.zig");
}
if (cmake_cfg) |cfg| {
// Inside this code path, we have to coordinate with system packaged LLVM, Clang, and LLD.
// That means we also have to rely on stage1 compiled c++ files. We parse config.h to find
// the information passed on to us from cmake.
if (cfg.cmake_prefix_path.len > 0) {
b.addSearchPrefix(cfg.cmake_prefix_path);
}
try addCmakeCfgOptionsToExe(b, cfg, exe, use_zig_libcxx);
} else {
// Here we are -Denable-llvm but no cmake integration.
try addStaticLlvmOptionsToExe(exe);
}
}
const semver = try std.SemanticVersion.parse(version);
exe_options.addOption(std.SemanticVersion, "semver", semver);
exe_options.addOption(bool, "enable_logging", enable_logging);
exe_options.addOption(bool, "enable_link_snapshots", enable_link_snapshots);
exe_options.addOption(bool, "enable_tracy", tracy != null);
exe_options.addOption(bool, "enable_tracy_callstack", tracy_callstack);
exe_options.addOption(bool, "enable_tracy_allocation", tracy_allocation);
exe_options.addOption(bool, "value_tracing", value_tracing);
exe_options.addOption(bool, "is_stage1", is_stage1);
exe_options.addOption(bool, "omit_stage2", omit_stage2);
if (tracy) |tracy_path| {
const client_cpp = fs.path.join(
b.allocator,
&[_][]const u8{ tracy_path, "TracyClient.cpp" },
) catch unreachable;
// On mingw, we need to opt into windows 7+ to get some features required by tracy.
const tracy_c_flags: []const []const u8 = if (target.isWindows() and target.getAbi() == .gnu)
&[_][]const u8{ "-DTRACY_ENABLE=1", "-fno-sanitize=undefined", "-D_WIN32_WINNT=0x601" }
else
&[_][]const u8{ "-DTRACY_ENABLE=1", "-fno-sanitize=undefined" };
exe.addIncludeDir(tracy_path);
exe.addCSourceFile(client_cpp, tracy_c_flags);
if (!enable_llvm) {
exe.linkSystemLibraryName("c++");
}
exe.linkLibC();
if (target.isWindows()) {
exe.linkSystemLibrary("dbghelp");
exe.linkSystemLibrary("ws2_32");
}
}
}
const exe_cflags = [_][]const u8{
"-std=c++14",
"-D__STDC_CONSTANT_MACROS",
"-D__STDC_FORMAT_MACROS",
"-D__STDC_LIMIT_MACROS",
"-D_GNU_SOURCE",
"-fvisibility-inlines-hidden",
"-fno-exceptions",
"-fno-rtti",
"-Werror=type-limits",
"-Wno-missing-braces",
"-Wno-comment",
};
fn addCmakeCfgOptionsToExe(
b: *Builder,
cfg: CMakeConfig,
exe: *std.build.LibExeObjStep,
use_zig_libcxx: bool,
) !void {
exe.addObjectFile(fs.path.join(b.allocator, &[_][]const u8{
cfg.cmake_binary_dir,
"zigcpp",
b.fmt("{s}{s}{s}", .{ exe.target.libPrefix(), "zigcpp", exe.target.staticLibSuffix() }),
}) catch unreachable);
assert(cfg.lld_include_dir.len != 0);
exe.addIncludeDir(cfg.lld_include_dir);
addCMakeLibraryList(exe, cfg.clang_libraries);
addCMakeLibraryList(exe, cfg.lld_libraries);
addCMakeLibraryList(exe, cfg.llvm_libraries);
if (use_zig_libcxx) {
exe.linkLibCpp();
} else {
const need_cpp_includes = true;
// System -lc++ must be used because in this code path we are attempting to link
// against system-provided LLVM, Clang, LLD.
if (exe.target.getOsTag() == .linux) {
// First we try to static link against gcc libstdc++. If that doesn't work,
// we fall back to -lc++ and cross our fingers.
addCxxKnownPath(b, cfg, exe, "libstdc++.a", "", need_cpp_includes) catch |err| switch (err) {
error.RequiredLibraryNotFound => {
exe.linkSystemLibrary("c++");
},
else => |e| return e,
};
exe.linkSystemLibrary("unwind");
} else if (exe.target.isFreeBSD()) {
try addCxxKnownPath(b, cfg, exe, "libc++.a", null, need_cpp_includes);
exe.linkSystemLibrary("pthread");
} else if (exe.target.getOsTag() == .openbsd) {
try addCxxKnownPath(b, cfg, exe, "libc++.a", null, need_cpp_includes);
try addCxxKnownPath(b, cfg, exe, "libc++abi.a", null, need_cpp_includes);
} else if (exe.target.isDarwin()) {
exe.linkSystemLibrary("c++");
}
}
if (cfg.dia_guids_lib.len != 0) {
exe.addObjectFile(cfg.dia_guids_lib);
}
}
fn addStaticLlvmOptionsToExe(
exe: *std.build.LibExeObjStep,
) !void {
// Adds the Zig C++ sources which both stage1 and stage2 need.
//
// We need this because otherwise zig_clang_cc1_main.cpp ends up pulling
// in a dependency on llvm::cfg::Update<llvm::BasicBlock*>::dump() which is
// unavailable when LLVM is compiled in Release mode.
const zig_cpp_cflags = exe_cflags ++ [_][]const u8{"-DNDEBUG=1"};
exe.addCSourceFiles(&zig_cpp_sources, &zig_cpp_cflags);
for (clang_libs) |lib_name| {
exe.linkSystemLibrary(lib_name);
}
for (lld_libs) |lib_name| {
exe.linkSystemLibrary(lib_name);
}
for (llvm_libs) |lib_name| {
exe.linkSystemLibrary(lib_name);
}
exe.linkSystemLibrary("z");
// This means we rely on clang-or-zig-built LLVM, Clang, LLD libraries.
exe.linkSystemLibrary("c++");
if (exe.target.getOs().tag == .windows) {
exe.linkSystemLibrary("version");
exe.linkSystemLibrary("uuid");
exe.linkSystemLibrary("ole32");
}
}
fn addCxxKnownPath(
b: *Builder,
ctx: CMakeConfig,
exe: *std.build.LibExeObjStep,
objname: []const u8,
errtxt: ?[]const u8,
need_cpp_includes: bool,
) !void {
const path_padded = try b.exec(&[_][]const u8{
ctx.cxx_compiler,
b.fmt("-print-file-name={s}", .{objname}),
});
const path_unpadded = mem.tokenize(u8, path_padded, "\r\n").next().?;
if (mem.eql(u8, path_unpadded, objname)) {
if (errtxt) |msg| {
std.debug.print("{s}", .{msg});
} else {
std.debug.print("Unable to determine path to {s}\n", .{objname});
}
return error.RequiredLibraryNotFound;
}
exe.addObjectFile(path_unpadded);
// TODO a way to integrate with system c++ include files here
// cc -E -Wp,-v -xc++ /dev/null
if (need_cpp_includes) {
// I used these temporarily for testing something but we obviously need a
// more general purpose solution here.
//exe.addIncludeDir("/nix/store/fvf3qjqa5qpcjjkq37pb6ypnk1mzhf5h-gcc-9.3.0/lib/gcc/x86_64-unknown-linux-gnu/9.3.0/../../../../include/c++/9.3.0");
//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");
//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");
}
}
fn addCMakeLibraryList(exe: *std.build.LibExeObjStep, list: []const u8) void {
var it = mem.tokenize(u8, list, ";");
while (it.next()) |lib| {
if (mem.startsWith(u8, lib, "-l")) {
exe.linkSystemLibrary(lib["-l".len..]);
} else {
exe.addObjectFile(lib);
}
}
}
const CMakeConfig = struct {
cmake_binary_dir: []const u8,
cmake_prefix_path: []const u8,
cxx_compiler: []const u8,
lld_include_dir: []const u8,
lld_libraries: []const u8,
clang_libraries: []const u8,
llvm_libraries: []const u8,
dia_guids_lib: []const u8,
};
const max_config_h_bytes = 1 * 1024 * 1024;
fn findAndParseConfigH(b: *Builder, config_h_path_option: ?[]const u8) ?CMakeConfig {
const config_h_text: []const u8 = if (config_h_path_option) |config_h_path| blk: {
break :blk fs.cwd().readFileAlloc(b.allocator, config_h_path, max_config_h_bytes) catch unreachable;
} else blk: {
// TODO this should stop looking for config.h once it detects we hit the
// zig source root directory.
var check_dir = fs.path.dirname(b.zig_exe).?;
while (true) {
var dir = fs.cwd().openDir(check_dir, .{}) catch unreachable;
defer dir.close();
break :blk dir.readFileAlloc(b.allocator, "config.h", max_config_h_bytes) catch |err| switch (err) {
error.FileNotFound => {
const new_check_dir = fs.path.dirname(check_dir);
if (new_check_dir == null or mem.eql(u8, new_check_dir.?, check_dir)) {
return null;
}
check_dir = new_check_dir.?;
continue;
},
else => unreachable,
};
} else unreachable; // TODO should not need `else unreachable`.
};
var ctx: CMakeConfig = .{
.cmake_binary_dir = undefined,
.cmake_prefix_path = undefined,
.cxx_compiler = undefined,
.lld_include_dir = undefined,
.lld_libraries = undefined,
.clang_libraries = undefined,
.llvm_libraries = undefined,
.dia_guids_lib = undefined,
};
const mappings = [_]struct { prefix: []const u8, field: []const u8 }{
.{
.prefix = "#define ZIG_CMAKE_BINARY_DIR ",
.field = "cmake_binary_dir",
},
.{
.prefix = "#define ZIG_CMAKE_PREFIX_PATH ",
.field = "cmake_prefix_path",
},
.{
.prefix = "#define ZIG_CXX_COMPILER ",
.field = "cxx_compiler",
},
.{
.prefix = "#define ZIG_LLD_INCLUDE_PATH ",
.field = "lld_include_dir",
},
.{
.prefix = "#define ZIG_LLD_LIBRARIES ",
.field = "lld_libraries",
},
.{
.prefix = "#define ZIG_CLANG_LIBRARIES ",
.field = "clang_libraries",
},
.{
.prefix = "#define ZIG_LLVM_LIBRARIES ",
.field = "llvm_libraries",
},
.{
.prefix = "#define ZIG_DIA_GUIDS_LIB ",
.field = "dia_guids_lib",
},
};
var lines_it = mem.tokenize(u8, config_h_text, "\r\n");
while (lines_it.next()) |line| {
inline for (mappings) |mapping| {
if (mem.startsWith(u8, line, mapping.prefix)) {
var it = mem.split(u8, line, "\"");
_ = it.next().?; // skip the stuff before the quote
const quoted = it.next().?; // the stuff inside the quote
@field(ctx, mapping.field) = toNativePathSep(b, quoted);
}
}
}
return ctx;
}
fn toNativePathSep(b: *Builder, s: []const u8) []u8 {
const duplicated = b.allocator.dupe(u8, s) catch unreachable;
for (duplicated) |*byte| switch (byte.*) {
'/' => byte.* = fs.path.sep,
else => {},
};
return duplicated;
}
const softfloat_sources = [_][]const u8{
"deps/SoftFloat-3e/source/8086/f128M_isSignalingNaN.c",
"deps/SoftFloat-3e/source/8086/extF80M_isSignalingNaN.c",
"deps/SoftFloat-3e/source/8086/s_commonNaNToF128M.c",
"deps/SoftFloat-3e/source/8086/s_commonNaNToExtF80M.c",
"deps/SoftFloat-3e/source/8086/s_commonNaNToF16UI.c",
"deps/SoftFloat-3e/source/8086/s_commonNaNToF32UI.c",
"deps/SoftFloat-3e/source/8086/s_commonNaNToF64UI.c",
"deps/SoftFloat-3e/source/8086/s_f128MToCommonNaN.c",
"deps/SoftFloat-3e/source/8086/s_extF80MToCommonNaN.c",
"deps/SoftFloat-3e/source/8086/s_f16UIToCommonNaN.c",
"deps/SoftFloat-3e/source/8086/s_f32UIToCommonNaN.c",
"deps/SoftFloat-3e/source/8086/s_f64UIToCommonNaN.c",
"deps/SoftFloat-3e/source/8086/s_propagateNaNF128M.c",
"deps/SoftFloat-3e/source/8086/s_propagateNaNExtF80M.c",
"deps/SoftFloat-3e/source/8086/s_propagateNaNF16UI.c",
"deps/SoftFloat-3e/source/8086/softfloat_raiseFlags.c",
"deps/SoftFloat-3e/source/f128M_add.c",
"deps/SoftFloat-3e/source/f128M_div.c",
"deps/SoftFloat-3e/source/f128M_eq.c",
"deps/SoftFloat-3e/source/f128M_eq_signaling.c",
"deps/SoftFloat-3e/source/f128M_le.c",
"deps/SoftFloat-3e/source/f128M_le_quiet.c",
"deps/SoftFloat-3e/source/f128M_lt.c",
"deps/SoftFloat-3e/source/f128M_lt_quiet.c",
"deps/SoftFloat-3e/source/f128M_mul.c",
"deps/SoftFloat-3e/source/f128M_mulAdd.c",
"deps/SoftFloat-3e/source/f128M_rem.c",
"deps/SoftFloat-3e/source/f128M_roundToInt.c",
"deps/SoftFloat-3e/source/f128M_sqrt.c",
"deps/SoftFloat-3e/source/f128M_sub.c",
"deps/SoftFloat-3e/source/f128M_to_f16.c",
"deps/SoftFloat-3e/source/f128M_to_f32.c",
"deps/SoftFloat-3e/source/f128M_to_f64.c",
"deps/SoftFloat-3e/source/f128M_to_extF80M.c",
"deps/SoftFloat-3e/source/f128M_to_i32.c",
"deps/SoftFloat-3e/source/f128M_to_i32_r_minMag.c",
"deps/SoftFloat-3e/source/f128M_to_i64.c",
"deps/SoftFloat-3e/source/f128M_to_i64_r_minMag.c",
"deps/SoftFloat-3e/source/f128M_to_ui32.c",
"deps/SoftFloat-3e/source/f128M_to_ui32_r_minMag.c",
"deps/SoftFloat-3e/source/f128M_to_ui64.c",
"deps/SoftFloat-3e/source/f128M_to_ui64_r_minMag.c",
"deps/SoftFloat-3e/source/extF80M_add.c",
"deps/SoftFloat-3e/source/extF80M_div.c",
"deps/SoftFloat-3e/source/extF80M_eq.c",
"deps/SoftFloat-3e/source/extF80M_le.c",
"deps/SoftFloat-3e/source/extF80M_lt.c",
"deps/SoftFloat-3e/source/extF80M_mul.c",
"deps/SoftFloat-3e/source/extF80M_rem.c",
"deps/SoftFloat-3e/source/extF80M_roundToInt.c",
"deps/SoftFloat-3e/source/extF80M_sqrt.c",
"deps/SoftFloat-3e/source/extF80M_sub.c",
"deps/SoftFloat-3e/source/extF80M_to_f16.c",
"deps/SoftFloat-3e/source/extF80M_to_f32.c",
"deps/SoftFloat-3e/source/extF80M_to_f64.c",
"deps/SoftFloat-3e/source/extF80M_to_f128M.c",
"deps/SoftFloat-3e/source/f16_add.c",
"deps/SoftFloat-3e/source/f16_div.c",
"deps/SoftFloat-3e/source/f16_eq.c",
"deps/SoftFloat-3e/source/f16_isSignalingNaN.c",
"deps/SoftFloat-3e/source/f16_lt.c",
"deps/SoftFloat-3e/source/f16_mul.c",
"deps/SoftFloat-3e/source/f16_mulAdd.c",
"deps/SoftFloat-3e/source/f16_rem.c",
"deps/SoftFloat-3e/source/f16_roundToInt.c",
"deps/SoftFloat-3e/source/f16_sqrt.c",
"deps/SoftFloat-3e/source/f16_sub.c",
"deps/SoftFloat-3e/source/f16_to_extF80M.c",
"deps/SoftFloat-3e/source/f16_to_f128M.c",
"deps/SoftFloat-3e/source/f16_to_f64.c",
"deps/SoftFloat-3e/source/f32_to_extF80M.c",
"deps/SoftFloat-3e/source/f32_to_f128M.c",
"deps/SoftFloat-3e/source/f64_to_extF80M.c",
"deps/SoftFloat-3e/source/f64_to_f128M.c",
"deps/SoftFloat-3e/source/f64_to_f16.c",
"deps/SoftFloat-3e/source/i32_to_f128M.c",
"deps/SoftFloat-3e/source/s_add256M.c",
"deps/SoftFloat-3e/source/s_addCarryM.c",
"deps/SoftFloat-3e/source/s_addComplCarryM.c",
"deps/SoftFloat-3e/source/s_addF128M.c",
"deps/SoftFloat-3e/source/s_addExtF80M.c",
"deps/SoftFloat-3e/source/s_addM.c",
"deps/SoftFloat-3e/source/s_addMagsF16.c",
"deps/SoftFloat-3e/source/s_addMagsF32.c",
"deps/SoftFloat-3e/source/s_addMagsF64.c",
"deps/SoftFloat-3e/source/s_approxRecip32_1.c",
"deps/SoftFloat-3e/source/s_approxRecipSqrt32_1.c",
"deps/SoftFloat-3e/source/s_approxRecipSqrt_1Ks.c",
"deps/SoftFloat-3e/source/s_approxRecip_1Ks.c",
"deps/SoftFloat-3e/source/s_compare128M.c",
"deps/SoftFloat-3e/source/s_compare96M.c",
"deps/SoftFloat-3e/source/s_compareNonnormExtF80M.c",
"deps/SoftFloat-3e/source/s_countLeadingZeros16.c",
"deps/SoftFloat-3e/source/s_countLeadingZeros32.c",
"deps/SoftFloat-3e/source/s_countLeadingZeros64.c",
"deps/SoftFloat-3e/source/s_countLeadingZeros8.c",
"deps/SoftFloat-3e/source/s_eq128.c",
"deps/SoftFloat-3e/source/s_invalidF128M.c",
"deps/SoftFloat-3e/source/s_invalidExtF80M.c",
"deps/SoftFloat-3e/source/s_isNaNF128M.c",
"deps/SoftFloat-3e/source/s_le128.c",
"deps/SoftFloat-3e/source/s_lt128.c",
"deps/SoftFloat-3e/source/s_mul128MTo256M.c",
"deps/SoftFloat-3e/source/s_mul64To128M.c",
"deps/SoftFloat-3e/source/s_mulAddF128M.c",
"deps/SoftFloat-3e/source/s_mulAddF16.c",
"deps/SoftFloat-3e/source/s_mulAddF32.c",
"deps/SoftFloat-3e/source/s_mulAddF64.c",
"deps/SoftFloat-3e/source/s_negXM.c",
"deps/SoftFloat-3e/source/s_normExtF80SigM.c",
"deps/SoftFloat-3e/source/s_normRoundPackMToF128M.c",
"deps/SoftFloat-3e/source/s_normRoundPackMToExtF80M.c",
"deps/SoftFloat-3e/source/s_normRoundPackToF16.c",
"deps/SoftFloat-3e/source/s_normRoundPackToF32.c",
"deps/SoftFloat-3e/source/s_normRoundPackToF64.c",
"deps/SoftFloat-3e/source/s_normSubnormalF128SigM.c",
"deps/SoftFloat-3e/source/s_normSubnormalF16Sig.c",
"deps/SoftFloat-3e/source/s_normSubnormalF32Sig.c",
"deps/SoftFloat-3e/source/s_normSubnormalF64Sig.c",
"deps/SoftFloat-3e/source/s_remStepMBy32.c",
"deps/SoftFloat-3e/source/s_roundMToI64.c",
"deps/SoftFloat-3e/source/s_roundMToUI64.c",
"deps/SoftFloat-3e/source/s_roundPackMToExtF80M.c",
"deps/SoftFloat-3e/source/s_roundPackMToF128M.c",
"deps/SoftFloat-3e/source/s_roundPackToF16.c",
"deps/SoftFloat-3e/source/s_roundPackToF32.c",
"deps/SoftFloat-3e/source/s_roundPackToF64.c",
"deps/SoftFloat-3e/source/s_roundToI32.c",
"deps/SoftFloat-3e/source/s_roundToI64.c",
"deps/SoftFloat-3e/source/s_roundToUI32.c",
"deps/SoftFloat-3e/source/s_roundToUI64.c",
"deps/SoftFloat-3e/source/s_shiftLeftM.c",
"deps/SoftFloat-3e/source/s_shiftNormSigF128M.c",
"deps/SoftFloat-3e/source/s_shiftRightJam256M.c",
"deps/SoftFloat-3e/source/s_shiftRightJam32.c",
"deps/SoftFloat-3e/source/s_shiftRightJam64.c",
"deps/SoftFloat-3e/source/s_shiftRightJamM.c",
"deps/SoftFloat-3e/source/s_shiftRightM.c",
"deps/SoftFloat-3e/source/s_shortShiftLeft64To96M.c",
"deps/SoftFloat-3e/source/s_shortShiftLeftM.c",
"deps/SoftFloat-3e/source/s_shortShiftRightExtendM.c",
"deps/SoftFloat-3e/source/s_shortShiftRightJam64.c",
"deps/SoftFloat-3e/source/s_shortShiftRightJamM.c",
"deps/SoftFloat-3e/source/s_shortShiftRightM.c",
"deps/SoftFloat-3e/source/s_sub1XM.c",
"deps/SoftFloat-3e/source/s_sub256M.c",
"deps/SoftFloat-3e/source/s_subM.c",
"deps/SoftFloat-3e/source/s_subMagsF16.c",
"deps/SoftFloat-3e/source/s_subMagsF32.c",
"deps/SoftFloat-3e/source/s_subMagsF64.c",
"deps/SoftFloat-3e/source/s_tryPropagateNaNF128M.c",
"deps/SoftFloat-3e/source/s_tryPropagateNaNExtF80M.c",
"deps/SoftFloat-3e/source/softfloat_state.c",
"deps/SoftFloat-3e/source/ui32_to_f128M.c",
"deps/SoftFloat-3e/source/ui64_to_f128M.c",
"deps/SoftFloat-3e/source/ui32_to_extF80M.c",
"deps/SoftFloat-3e/source/ui64_to_extF80M.c",
};
const stage1_sources = [_][]const u8{
"src/stage1/analyze.cpp",
"src/stage1/astgen.cpp",
"src/stage1/bigfloat.cpp",
"src/stage1/bigint.cpp",
"src/stage1/buffer.cpp",
"src/stage1/codegen.cpp",
"src/stage1/errmsg.cpp",
"src/stage1/error.cpp",
"src/stage1/heap.cpp",
"src/stage1/ir.cpp",
"src/stage1/ir_print.cpp",
"src/stage1/mem.cpp",
"src/stage1/os.cpp",
"src/stage1/parser.cpp",
"src/stage1/range_set.cpp",
"src/stage1/stage1.cpp",
"src/stage1/target.cpp",
"src/stage1/tokenizer.cpp",
"src/stage1/util.cpp",
"src/stage1/softfloat_ext.cpp",
};
const optimized_c_sources = [_][]const u8{
"src/stage1/parse_f128.c",
};
const zig_cpp_sources = [_][]const u8{
// These are planned to stay even when we are self-hosted.
"src/zig_llvm.cpp",
"src/zig_clang.cpp",
"src/zig_llvm-ar.cpp",
"src/zig_clang_driver.cpp",
"src/zig_clang_cc1_main.cpp",
"src/zig_clang_cc1as_main.cpp",
// https://github.com/ziglang/zig/issues/6363
"src/windows_sdk.cpp",
};
const clang_libs = [_][]const u8{
"clangFrontendTool",
"clangCodeGen",
"clangFrontend",
"clangDriver",
"clangSerialization",
"clangSema",
"clangStaticAnalyzerFrontend",
"clangStaticAnalyzerCheckers",
"clangStaticAnalyzerCore",
"clangAnalysis",
"clangASTMatchers",
"clangAST",
"clangParse",
"clangSema",
"clangBasic",
"clangEdit",
"clangLex",
"clangARCMigrate",
"clangRewriteFrontend",
"clangRewrite",
"clangCrossTU",
"clangIndex",
"clangToolingCore",
};
const lld_libs = [_][]const u8{
"lldMinGW",
"lldELF",
"lldCOFF",
"lldWasm",
"lldMachO",
"lldCommon",
};
// This list can be re-generated with `llvm-config --libfiles` and then
// reformatting using your favorite text editor. Note we do not execute
// `llvm-config` here because we are cross compiling. Also omit LLVMTableGen
// from these libs.
const llvm_libs = [_][]const u8{
"LLVMWindowsManifest",
"LLVMXRay",
"LLVMLibDriver",
"LLVMDlltoolDriver",
"LLVMCoverage",
"LLVMLineEditor",
"LLVMXCoreDisassembler",
"LLVMXCoreCodeGen",
"LLVMXCoreDesc",
"LLVMXCoreInfo",
"LLVMX86TargetMCA",
"LLVMX86Disassembler",
"LLVMX86AsmParser",
"LLVMX86CodeGen",
"LLVMX86Desc",
"LLVMX86Info",
"LLVMWebAssemblyDisassembler",
"LLVMWebAssemblyAsmParser",
"LLVMWebAssemblyCodeGen",
"LLVMWebAssemblyDesc",
"LLVMWebAssemblyUtils",
"LLVMWebAssemblyInfo",
"LLVMVEDisassembler",
"LLVMVEAsmParser",
"LLVMVECodeGen",
"LLVMVEDesc",
"LLVMVEInfo",
"LLVMSystemZDisassembler",
"LLVMSystemZAsmParser",
"LLVMSystemZCodeGen",
"LLVMSystemZDesc",
"LLVMSystemZInfo",
"LLVMSparcDisassembler",
"LLVMSparcAsmParser",
"LLVMSparcCodeGen",
"LLVMSparcDesc",
"LLVMSparcInfo",
"LLVMRISCVDisassembler",
"LLVMRISCVAsmParser",
"LLVMRISCVCodeGen",
"LLVMRISCVDesc",
"LLVMRISCVInfo",
"LLVMPowerPCDisassembler",
"LLVMPowerPCAsmParser",
"LLVMPowerPCCodeGen",
"LLVMPowerPCDesc",
"LLVMPowerPCInfo",
"LLVMNVPTXCodeGen",
"LLVMNVPTXDesc",
"LLVMNVPTXInfo",
"LLVMMSP430Disassembler",
"LLVMMSP430AsmParser",
"LLVMMSP430CodeGen",
"LLVMMSP430Desc",
"LLVMMSP430Info",
"LLVMMipsDisassembler",
"LLVMMipsAsmParser",
"LLVMMipsCodeGen",
"LLVMMipsDesc",
"LLVMMipsInfo",
"LLVMLanaiDisassembler",
"LLVMLanaiCodeGen",
"LLVMLanaiAsmParser",
"LLVMLanaiDesc",
"LLVMLanaiInfo",
"LLVMHexagonDisassembler",
"LLVMHexagonCodeGen",
"LLVMHexagonAsmParser",
"LLVMHexagonDesc",
"LLVMHexagonInfo",
"LLVMBPFDisassembler",
"LLVMBPFAsmParser",
"LLVMBPFCodeGen",
"LLVMBPFDesc",
"LLVMBPFInfo",
"LLVMAVRDisassembler",
"LLVMAVRAsmParser",
"LLVMAVRCodeGen",
"LLVMAVRDesc",
"LLVMAVRInfo",
"LLVMARMDisassembler",
"LLVMARMAsmParser",
"LLVMARMCodeGen",
"LLVMARMDesc",
"LLVMARMUtils",
"LLVMARMInfo",
"LLVMAMDGPUTargetMCA",
"LLVMAMDGPUDisassembler",
"LLVMAMDGPUAsmParser",
"LLVMAMDGPUCodeGen",
"LLVMAMDGPUDesc",
"LLVMAMDGPUUtils",
"LLVMAMDGPUInfo",
"LLVMAArch64Disassembler",
"LLVMAArch64AsmParser",
"LLVMAArch64CodeGen",
"LLVMAArch64Desc",
"LLVMAArch64Utils",
"LLVMAArch64Info",
"LLVMOrcJIT",
"LLVMMCJIT",
"LLVMJITLink",
"LLVMInterpreter",
"LLVMExecutionEngine",
"LLVMRuntimeDyld",
"LLVMOrcTargetProcess",
"LLVMOrcShared",
"LLVMDWP",
"LLVMSymbolize",
"LLVMDebugInfoPDB",
"LLVMDebugInfoGSYM",
"LLVMOption",
"LLVMObjectYAML",
"LLVMMCA",
"LLVMMCDisassembler",
"LLVMLTO",
"LLVMPasses",
"LLVMCFGuard",
"LLVMCoroutines",
"LLVMObjCARCOpts",
"LLVMipo",
"LLVMVectorize",
"LLVMLinker",
"LLVMInstrumentation",
"LLVMFrontendOpenMP",
"LLVMFrontendOpenACC",
"LLVMExtensions",
"LLVMDWARFLinker",
"LLVMGlobalISel",
"LLVMMIRParser",
"LLVMAsmPrinter",
"LLVMDebugInfoMSF",
"LLVMSelectionDAG",
"LLVMCodeGen",
"LLVMIRReader",
"LLVMAsmParser",
"LLVMInterfaceStub",
"LLVMFileCheck",
"LLVMFuzzMutate",
"LLVMTarget",
"LLVMScalarOpts",
"LLVMInstCombine",
"LLVMAggressiveInstCombine",
"LLVMTransformUtils",
"LLVMBitWriter",
"LLVMAnalysis",
"LLVMProfileData",
"LLVMDebugInfoDWARF",
"LLVMObject",
"LLVMTextAPI",
"LLVMMCParser",
"LLVMMC",
"LLVMDebugInfoCodeView",
"LLVMBitReader",
"LLVMCore",
"LLVMRemarks",
"LLVMBitstreamReader",
"LLVMBinaryFormat",
"LLVMSupport",
"LLVMDemangle",
};

View File

@ -1,132 +0,0 @@
#!/bin/sh
set -x
set -e
brew update && brew install ncurses s3cmd
ZIGDIR="$(pwd)"
HOST_ARCH="x86_64"
HOST_TARGET="$HOST_ARCH-macos-none"
HOST_MCPU="baseline"
HOST_CACHE_BASENAME="zig+llvm+lld+clang-$HOST_TARGET-0.10.0-dev.2931+bdf3fa12f"
HOST_PREFIX="$HOME/$HOST_CACHE_BASENAME"
ARCH="aarch64"
TARGET="$ARCH-macos-none"
MCPU="apple_a14"
CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.10.0-dev.2931+bdf3fa12f"
PREFIX="$HOME/$CACHE_BASENAME"
JOBS="-j2"
rm -rf $HOST_PREFIX $PREFIX
cd $HOME
wget -nv "https://ziglang.org/deps/$HOST_CACHE_BASENAME.tar.xz"
wget -nv "https://ziglang.org/deps/$CACHE_BASENAME.tar.xz"
tar xf "$HOST_CACHE_BASENAME.tar.xz"
tar xf "$CACHE_BASENAME.tar.xz"
cd $ZIGDIR
# Make the `zig version` number consistent.
# This will affect the cmake command below.
git config core.abbrev 9
git fetch --unshallow || true
git fetch --tags
# Build host zig compiler in debug so that we can get the
# current version when packaging
ZIG="$HOST_PREFIX/bin/zig"
export CC="$ZIG cc -target $HOST_TARGET -mcpu=$HOST_MCPU"
export CXX="$ZIG c++ -target $HOST_TARGET -mcpu=$HOST_MCPU"
mkdir build.host
cd build.host
cmake .. \
-DCMAKE_INSTALL_PREFIX="$(pwd)/release" \
-DCMAKE_PREFIX_PATH="$HOST_PREFIX" \
-DCMAKE_BUILD_TYPE=Release \
-DZIG_TARGET_TRIPLE="$HOST_TARGET" \
-DZIG_TARGET_MCPU="$HOST_MCPU" \
-DZIG_STATIC=ON \
-DZIG_OMIT_STAGE2=ON
unset CC
unset CXX
make $JOBS install
# Build zig compiler cross-compiled for arm64
cd $ZIGDIR
ZIG="$ZIGDIR/build.host/release/bin/zig"
export CC="$ZIG cc -target $TARGET -mcpu=$MCPU"
export CXX="$ZIG c++ -target $TARGET -mcpu=$MCPU"
mkdir build
cd build
cmake .. \
-DCMAKE_INSTALL_PREFIX="$(pwd)/release" \
-DCMAKE_PREFIX_PATH="$PREFIX" \
-DCMAKE_BUILD_TYPE=Release \
-DZIG_TARGET_TRIPLE="$TARGET" \
-DZIG_TARGET_MCPU="$MCPU" \
-DZIG_EXECUTABLE="$ZIG" \
-DZIG_STATIC=ON
unset CC
unset CXX
make $JOBS install
if [ "${BUILD_REASON}" != "PullRequest" ]; then
mv ../LICENSE release/
# We do not run test suite but still need langref.
mkdir -p release/docs
$ZIG run ../doc/docgen.zig -- $ZIG ../doc/langref.html.in release/docs/langref.html
# Produce the experimental std lib documentation.
mkdir -p release/docs/std
$ZIG test ../lib/std/std.zig \
--zig-lib-dir ../lib \
-femit-docs=release/docs/std \
-fno-emit-bin
mv release/bin/zig release/
rmdir release/bin
VERSION=$(../build.host/release/bin/zig version)
DIRNAME="zig-macos-$ARCH-$VERSION"
TARBALL="$DIRNAME.tar.xz"
mv release "$DIRNAME"
tar cfJ "$TARBALL" "$DIRNAME"
mv "$DOWNLOADSECUREFILE_SECUREFILEPATH" "$HOME/.s3cfg"
s3cmd put -P --add-header="cache-control: public, max-age=31536000, immutable" "$TARBALL" s3://ziglang.org/builds/
SHASUM=$(shasum -a 256 $TARBALL | cut '-d ' -f1)
BYTESIZE=$(wc -c < $TARBALL)
JSONFILE="macos-$GITBRANCH.json"
touch $JSONFILE
echo "{\"tarball\": \"$TARBALL\"," >>$JSONFILE
echo "\"shasum\": \"$SHASUM\"," >>$JSONFILE
echo "\"size\": \"$BYTESIZE\"}" >>$JSONFILE
s3cmd put -P --add-header="Cache-Control: max-age=0, must-revalidate" "$JSONFILE" "s3://ziglang.org/builds/$JSONFILE"
s3cmd put -P "$JSONFILE" "s3://ziglang.org/builds/$ARCH-macos-$VERSION.json"
# `set -x` causes these variables to be mangled.
# See https://developercommunity.visualstudio.com/content/problem/375679/pipeline-variable-incorrectly-inserts-single-quote.html
set +x
echo "##vso[task.setvariable variable=tarball;isOutput=true]$TARBALL"
echo "##vso[task.setvariable variable=shasum;isOutput=true]$SHASUM"
echo "##vso[task.setvariable variable=bytesize;isOutput=true]$BYTESIZE"
fi

View File

@ -34,13 +34,12 @@ git fetch --tags
mkdir build mkdir build
cd build cd build
cmake .. \ cmake .. \
-DCMAKE_INSTALL_PREFIX="$(pwd)/release" \ -DCMAKE_INSTALL_PREFIX="stage3-release" \
-DCMAKE_PREFIX_PATH="$PREFIX" \ -DCMAKE_PREFIX_PATH="$PREFIX" \
-DCMAKE_BUILD_TYPE=Release \ -DCMAKE_BUILD_TYPE=Release \
-DZIG_TARGET_TRIPLE="$TARGET" \ -DZIG_TARGET_TRIPLE="$TARGET" \
-DZIG_TARGET_MCPU="$MCPU" \ -DZIG_TARGET_MCPU="$MCPU" \
-DZIG_STATIC=ON \ -DZIG_STATIC=ON
-DZIG_OMIT_STAGE2=ON
# Now cmake will use zig as the C/C++ compiler. We reset the environment variables # Now cmake will use zig as the C/C++ compiler. We reset the environment variables
# so that installation and testing do not get affected by them. # so that installation and testing do not get affected by them.
@ -49,45 +48,21 @@ unset CXX
make $JOBS install make $JOBS install
# Here we rebuild zig but this time using the Zig binary we just now produced to stage3-release/bin/zig build test docs \
# build zig1.o rather than relying on the one built with stage0. See -Denable-macos-sdk \
# https://github.com/ziglang/zig/issues/6830 for more details. -Dstatic-llvm \
cmake .. -DZIG_EXECUTABLE="$(pwd)/release/bin/zig" --search-prefix "$PREFIX"
make $JOBS install
# Build stage2 standalone so that we can test stage2 against stage2 compiler-rt.
release/bin/zig build -p stage2 -Denable-llvm
stage2/bin/zig build test-behavior
# TODO: upgrade these to test stage2 instead of stage1
# TODO: upgrade these to test stage3 instead of stage2
release/bin/zig build test-behavior -Denable-macos-sdk -Domit-stage2
release/bin/zig build test-compiler-rt -Denable-macos-sdk
release/bin/zig build test-std -Denable-macos-sdk
release/bin/zig build test-universal-libc -Denable-macos-sdk
release/bin/zig build test-compare-output -Denable-macos-sdk
release/bin/zig build test-standalone -Denable-macos-sdk
release/bin/zig build test-stack-traces -Denable-macos-sdk
release/bin/zig build test-cli -Denable-macos-sdk
release/bin/zig build test-asm-link -Denable-macos-sdk
release/bin/zig build test-translate-c -Denable-macos-sdk
release/bin/zig build test-run-translated-c -Denable-macos-sdk
release/bin/zig build docs -Denable-macos-sdk
release/bin/zig build test-fmt -Denable-macos-sdk
release/bin/zig build test-cases -Denable-macos-sdk -Dsingle-threaded
release/bin/zig build test-link -Denable-macos-sdk -Domit-stage2
if [ "${BUILD_REASON}" != "PullRequest" ]; then if [ "${BUILD_REASON}" != "PullRequest" ]; then
mv ../LICENSE release/ mv ../LICENSE stage3-release/
mv ../zig-cache/langref.html release/ mv ../zig-cache/langref.html stage3-release/
mv release/bin/zig release/ mv stage3-release/bin/zig stage3-release/
rmdir release/bin rmdir stage3-release/bin
VERSION=$(release/zig version) VERSION=$(stage3-release/zig version)
DIRNAME="zig-macos-$ARCH-$VERSION" DIRNAME="zig-macos-$ARCH-$VERSION"
TARBALL="$DIRNAME.tar.xz" TARBALL="$DIRNAME.tar.xz"
mv release "$DIRNAME" mv stage3-release "$DIRNAME"
tar cfJ "$TARBALL" "$DIRNAME" tar cfJ "$TARBALL" "$DIRNAME"
mv "$DOWNLOADSECUREFILE_SECUREFILEPATH" "$HOME/.s3cfg" mv "$DOWNLOADSECUREFILE_SECUREFILEPATH" "$HOME/.s3cfg"

View File

@ -10,24 +10,13 @@ jobs:
- script: ci/azure/macos_script - script: ci/azure/macos_script
name: main name: main
displayName: 'Build and test' displayName: 'Build and test'
- job: BuildMacOS_arm64
pool:
vmImage: 'macOS-11'
timeoutInMinutes: 180
steps:
- task: DownloadSecureFile@1
inputs:
secureFile: s3cfg
- script: ci/azure/macos_arm64_script
name: main
displayName: 'Build'
- job: BuildWindows - job: BuildWindows
timeoutInMinutes: 360 timeoutInMinutes: 360
pool: pool:
vmImage: 'windows-2019' vmImage: 'windows-2019'
variables: variables:
TARGET: 'x86_64-windows-gnu' TARGET: 'x86_64-windows-gnu'
ZIG_LLVM_CLANG_LLD_NAME: 'zig+llvm+lld+clang-${{ variables.TARGET }}-0.10.0-dev.2931+bdf3fa12f' ZIG_LLVM_CLANG_LLD_NAME: 'zig+llvm+lld+clang-${{ variables.TARGET }}-0.10.0-dev.3733+a9af47272'
ZIG_LLVM_CLANG_LLD_URL: 'https://ziglang.org/deps/${{ variables.ZIG_LLVM_CLANG_LLD_NAME }}.zip' ZIG_LLVM_CLANG_LLD_URL: 'https://ziglang.org/deps/${{ variables.ZIG_LLVM_CLANG_LLD_NAME }}.zip'
steps: steps:
- pwsh: | - pwsh: |
@ -37,10 +26,17 @@ jobs:
displayName: 'Install ZIG/LLVM/CLANG/LLD' displayName: 'Install ZIG/LLVM/CLANG/LLD'
- pwsh: | - pwsh: |
Set-Variable -Name ZIGBUILDDIR -Value "$(Get-Location)\build" Set-Variable -Name ZIGLIBDIR -Value "$(Get-Location)\lib"
Set-Variable -Name ZIGINSTALLDIR -Value "${ZIGBUILDDIR}\dist" Set-Variable -Name ZIGINSTALLDIR -Value "$(Get-Location)\stage3-release"
Set-Variable -Name ZIGPREFIXPATH -Value "$(Get-Location)\$(ZIG_LLVM_CLANG_LLD_NAME)" Set-Variable -Name ZIGPREFIXPATH -Value "$(Get-Location)\$(ZIG_LLVM_CLANG_LLD_NAME)"
function CheckLastExitCode {
if (!$?) {
exit 1
}
return 0
}
# Make the `zig version` number consistent. # Make the `zig version` number consistent.
# This will affect the `zig build` command below which uses `git describe`. # This will affect the `zig build` command below which uses `git describe`.
git config core.abbrev 9 git config core.abbrev 9
@ -49,64 +45,45 @@ jobs:
git fetch --unshallow # `git describe` won't work on a shallow repo git fetch --unshallow # `git describe` won't work on a shallow repo
} }
# The dev kit zip file that we have here is old, and may be incompatible with & "$ZIGPREFIXPATH\bin\zig.exe" build `
# the build.zig script of master branch. So we keep an old version of build.zig
# here in the CI directory.
mv build.zig build.zig.master
mv ci/azure/build.zig build.zig
mkdir $ZIGBUILDDIR
cd $ZIGBUILDDIR
& "${ZIGPREFIXPATH}/bin/zig.exe" build `
--prefix "$ZIGINSTALLDIR" ` --prefix "$ZIGINSTALLDIR" `
--search-prefix "$ZIGPREFIXPATH" ` --search-prefix "$ZIGPREFIXPATH" `
-Dstage1 ` --zig-lib-dir "$ZIGLIBDIR" `
<# stage2 is omitted until we resolve https://github.com/ziglang/zig/issues/6485 #> ` -Denable-stage1 `
-Domit-stage2 `
-Dstatic-llvm ` -Dstatic-llvm `
-Drelease ` -Drelease `
-Dstrip ` -Dstrip `
-Duse-zig-libcxx ` -Duse-zig-libcxx `
-Dtarget=$(TARGET) -Dtarget=$(TARGET)
CheckLastExitCode
cd -
# Now that we have built an up-to-date zig.exe, we restore the original
# build script from master branch.
rm build.zig
mv build.zig.master build.zig
name: build name: build
displayName: 'Build' displayName: 'Build'
- pwsh: | - pwsh: |
Set-Variable -Name ZIGINSTALLDIR -Value "$(Get-Location)\build\dist" Set-Variable -Name ZIGINSTALLDIR -Value "$(Get-Location)\stage3-release"
# Sadly, stage2 is omitted from this build to save memory on the CI server. Once self-hosted is function CheckLastExitCode {
# built with itself and does not gobble as much memory, we can enable these tests. if (!$?) {
#& "$ZIGINSTALLDIR\bin\zig.exe" test "..\test\behavior.zig" -fno-stage1 -fLLVM -I "..\test" 2>&1 exit 1
}
return 0
}
& "$ZIGINSTALLDIR\bin\zig.exe" build test-toolchain -Dskip-non-native -Dskip-stage2-tests 2>&1 & "$ZIGINSTALLDIR\bin\zig.exe" build test docs `
& "$ZIGINSTALLDIR\bin\zig.exe" build test-std -Dskip-non-native 2>&1 --search-prefix "$ZIGPREFIXPATH" `
-Dstatic-llvm `
-Dskip-non-native `
-Dskip-stage2-tests
CheckLastExitCode
name: test name: test
displayName: 'Test' displayName: 'Test'
- pwsh: |
Set-Variable -Name ZIGINSTALLDIR -Value "$(Get-Location)\build\dist"
& "$ZIGINSTALLDIR\bin\zig.exe" build docs
timeoutInMinutes: 60
name: doc
displayName: 'Documentation'
- task: DownloadSecureFile@1 - task: DownloadSecureFile@1
inputs: inputs:
name: aws_credentials name: aws_credentials
secureFile: aws_credentials secureFile: aws_credentials
- pwsh: | - pwsh: |
Set-Variable -Name ZIGBUILDDIR -Value "$(Get-Location)\build"
$Env:AWS_SHARED_CREDENTIALS_FILE = "$Env:DOWNLOADSECUREFILE_SECUREFILEPATH" $Env:AWS_SHARED_CREDENTIALS_FILE = "$Env:DOWNLOADSECUREFILE_SECUREFILEPATH"
# Workaround Azure networking issue # Workaround Azure networking issue
@ -114,21 +91,20 @@ jobs:
$Env:AWS_EC2_METADATA_DISABLED = "true" $Env:AWS_EC2_METADATA_DISABLED = "true"
$Env:AWS_REGION = "us-west-2" $Env:AWS_REGION = "us-west-2"
cd "$ZIGBUILDDIR" mv LICENSE stage3-release/
mv ../LICENSE dist/ mv zig-cache/langref.html stage3-release/
mv ../zig-cache/langref.html dist/ mv stage3-release/bin/zig.exe stage3-release/
mv dist/bin/zig.exe dist/ rmdir stage3-release/bin
rmdir dist/bin
# Remove the unnecessary zig dir in $prefix/lib/zig/std/std.zig # Remove the unnecessary zig dir in $prefix/lib/zig/std/std.zig
mv dist/lib/zig dist/lib2 mv stage3-release/lib/zig stage3-release/lib2
rmdir dist/lib rmdir stage3-release/lib
mv dist/lib2 dist/lib mv stage3-release/lib2 stage3-release/lib
Set-Variable -Name VERSION -Value $(./dist/zig.exe version) Set-Variable -Name VERSION -Value $(./stage3-release/zig.exe version)
Set-Variable -Name DIRNAME -Value "zig-windows-x86_64-$VERSION" Set-Variable -Name DIRNAME -Value "zig-windows-x86_64-$VERSION"
Set-Variable -Name TARBALL -Value "$DIRNAME.zip" Set-Variable -Name TARBALL -Value "$DIRNAME.zip"
mv dist "$DIRNAME" mv stage3-release "$DIRNAME"
7z a "$TARBALL" "$DIRNAME" 7z a "$TARBALL" "$DIRNAME"
aws s3 cp ` aws s3 cp `
@ -168,7 +144,6 @@ jobs:
- job: OnMasterSuccess - job: OnMasterSuccess
dependsOn: dependsOn:
- BuildMacOS - BuildMacOS
- BuildMacOS_arm64
- BuildWindows - BuildWindows
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master')) condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
strategy: strategy:

View File

@ -13,65 +13,65 @@ steps:
commands: commands:
- ./ci/drone/linux_script_build - ./ci/drone/linux_script_build
- name: test-1 - name: behavior
depends_on: depends_on:
- build - build
image: ziglang/static-base:llvm14-aarch64-3 image: ziglang/static-base:llvm14-aarch64-3
commands: commands:
- ./ci/drone/linux_script_test 1 - ./ci/drone/test_linux_behavior
- name: test-2 - name: std_Debug
depends_on: depends_on:
- build - build
image: ziglang/static-base:llvm14-aarch64-3 image: ziglang/static-base:llvm14-aarch64-3
commands: commands:
- ./ci/drone/linux_script_test 2 - ./ci/drone/test_linux_std_Debug
- name: test-3 - name: std_ReleaseSafe
depends_on: depends_on:
- build - build
image: ziglang/static-base:llvm14-aarch64-3 image: ziglang/static-base:llvm14-aarch64-3
commands: commands:
- ./ci/drone/linux_script_test 3 - ./ci/drone/test_linux_std_ReleaseSafe
- name: test-4 - name: std_ReleaseFast
depends_on: depends_on:
- build - build
image: ziglang/static-base:llvm14-aarch64-3 image: ziglang/static-base:llvm14-aarch64-3
commands: commands:
- ./ci/drone/linux_script_test 4 - ./ci/drone/test_linux_std_ReleaseFast
- name: test-5 - name: std_ReleaseSmall
depends_on: depends_on:
- build - build
image: ziglang/static-base:llvm14-aarch64-3 image: ziglang/static-base:llvm14-aarch64-3
commands: commands:
- ./ci/drone/linux_script_test 5 - ./ci/drone/test_linux_std_ReleaseSmall
- name: test-6 - name: misc
depends_on: depends_on:
- build - build
image: ziglang/static-base:llvm14-aarch64-3 image: ziglang/static-base:llvm14-aarch64-3
commands: commands:
- ./ci/drone/linux_script_test 6 - ./ci/drone/test_linux_misc
- name: test-7 - name: cases
depends_on: depends_on:
- build - build
image: ziglang/static-base:llvm14-aarch64-3 image: ziglang/static-base:llvm14-aarch64-3
commands: commands:
- ./ci/drone/linux_script_test 7 - ./ci/drone/test_linux_cases
- name: finalize - name: finalize
depends_on: depends_on:
- build - build
- test-1 - behavior
- test-2 - std_Debug
- test-3 - std_ReleaseSafe
- test-4 - std_ReleaseFast
- test-5 - std_ReleaseSmall
- test-6 - misc
- test-7 - cases
image: ziglang/static-base:llvm14-aarch64-3 image: ziglang/static-base:llvm14-aarch64-3
environment: environment:
SRHT_OAUTH_TOKEN: SRHT_OAUTH_TOKEN:

View File

@ -1,22 +0,0 @@
#!/bin/sh
# https://docs.drone.io/pipeline/docker/syntax/workspace/
#
# Drone automatically creates a temporary volume, known as your workspace,
# where it clones your repository. The workspace is the current working
# directory for each step in your pipeline.
#
# Because the workspace is a volume, filesystem changes are persisted between
# pipeline steps. In other words, individual steps can communicate and share
# state using the filesystem.
#
# Workspace volumes are ephemeral. They are created when the pipeline starts
# and destroyed after the pipeline completes.
set -x
set -e
TRIPLEARCH="$(uname -m)"
DISTDIR="$DRONE_WORKSPACE/dist"
export ZIG_GLOBAL_CACHE_DIR="$DRONE_WORKSPACE/zig-cache"

View File

@ -1,17 +1,16 @@
#!/bin/sh #!/bin/sh
. ./ci/drone/linux_script_base set -x
set -e
# Probe CPU/brand details. ARCH="$(uname -m)"
# TODO: `lscpu` is changing package names in EDGE to `util-linux-misc` INSTALL_PREFIX="$DRONE_WORKSPACE/stage3-release"
apk update
apk add util-linux export ZIG_GLOBAL_CACHE_DIR="$DRONE_WORKSPACE/zig-cache"
echo "lscpu:"
lscpu | sed 's,^, : ,'
PREFIX="/deps/local" PREFIX="/deps/local"
ZIG="$PREFIX/bin/zig" ZIG="$PREFIX/bin/zig"
TARGET="$TRIPLEARCH-linux-musl" TARGET="$ARCH-linux-musl"
MCPU="baseline" MCPU="baseline"
export CC="$ZIG cc -target $TARGET -mcpu=$MCPU" export CC="$ZIG cc -target $TARGET -mcpu=$MCPU"
@ -30,8 +29,8 @@ cat <<'ENDFILE' >$PREFIX/bin/ranlib
/deps/local/bin/zig ranlib $@ /deps/local/bin/zig ranlib $@
ENDFILE ENDFILE
chmod +x $PREFIX/bin/ar chmod +x "$PREFIX/bin/ar"
chmod +x $PREFIX/bin/ranlib chmod +x "$PREFIX/bin/ranlib"
# Make the `zig version` number consistent. # Make the `zig version` number consistent.
# This will affect the cmake command below. # This will affect the cmake command below.
@ -42,8 +41,8 @@ git fetch --tags
mkdir build mkdir build
cd build cd build
cmake .. \ cmake .. \
-DCMAKE_INSTALL_PREFIX="$DISTDIR" \
-DCMAKE_PREFIX_PATH="$PREFIX" \ -DCMAKE_PREFIX_PATH="$PREFIX" \
-DCMAKE_INSTALL_PREFIX="$INSTALL_PREFIX" \
-DCMAKE_BUILD_TYPE=Release \ -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_AR="$PREFIX/bin/ar" \ -DCMAKE_AR="$PREFIX/bin/ar" \
-DCMAKE_RANLIB="$PREFIX/bin/ranlib" \ -DCMAKE_RANLIB="$PREFIX/bin/ranlib" \
@ -57,9 +56,3 @@ cmake .. \
unset CC unset CC
unset CXX unset CXX
samu install samu install
# Here we rebuild Zig but this time using the Zig binary we just now produced to
# build zig1.o rather than relying on the one built with stage0. See
# https://github.com/ziglang/zig/issues/6830 for more details.
cmake .. -DZIG_EXECUTABLE="$DISTDIR/bin/zig"
samu install

View File

@ -1,6 +1,12 @@
#!/bin/sh #!/bin/sh
. ./ci/drone/linux_script_base set -x
set -e
ARCH="$(uname -m)"
INSTALL_PREFIX="$DRONE_WORKSPACE/stage3-release"
export ZIG_GLOBAL_CACHE_DIR="$DRONE_WORKSPACE/zig-cache"
if [ -n "$DRONE_PULL_REQUEST" ]; then if [ -n "$DRONE_PULL_REQUEST" ]; then
exit 0 exit 0
@ -12,16 +18,16 @@ pip3 install s3cmd
cd build cd build
mv ../LICENSE "$DISTDIR/" mv ../LICENSE "$INSTALL_PREFIX/"
mv ../zig-cache/langref.html "$DISTDIR/" mv ../zig-cache/langref.html "$INSTALL_PREFIX/"
mv "$DISTDIR/bin/zig" "$DISTDIR/" mv "$INSTALL_PREFIX/bin/zig" "$INSTALL_PREFIX/"
rmdir "$DISTDIR/bin" rmdir "$INSTALL_PREFIX/bin"
GITBRANCH="$DRONE_BRANCH" GITBRANCH="$DRONE_BRANCH"
VERSION="$("$DISTDIR/zig" version)" VERSION="$("$INSTALL_PREFIX/zig" version)"
DIRNAME="zig-linux-$TRIPLEARCH-$VERSION" DIRNAME="zig-linux-$ARCH-$VERSION"
TARBALL="$DIRNAME.tar.xz" TARBALL="$DIRNAME.tar.xz"
mv "$DISTDIR" "$DIRNAME" mv "$INSTALL_PREFIX" "$DIRNAME"
tar cfJ "$TARBALL" "$DIRNAME" tar cfJ "$TARBALL" "$DIRNAME"
s3cmd put -P --add-header="cache-control: public, max-age=31536000, immutable" "$TARBALL" s3://ziglang.org/builds/ s3cmd put -P --add-header="cache-control: public, max-age=31536000, immutable" "$TARBALL" s3://ziglang.org/builds/
@ -35,7 +41,7 @@ echo "{\"tarball\": \"$TARBALL\"," >>$JSONFILE
echo "\"shasum\": \"$SHASUM\"," >>$JSONFILE echo "\"shasum\": \"$SHASUM\"," >>$JSONFILE
echo "\"size\": \"$BYTESIZE\"}" >>$JSONFILE echo "\"size\": \"$BYTESIZE\"}" >>$JSONFILE
s3cmd put -P "$JSONFILE" "s3://ziglang.org/builds/$TRIPLEARCH-linux-$VERSION.json" s3cmd put -P "$JSONFILE" "s3://ziglang.org/builds/$ARCH-linux-$VERSION.json"
if [ "$GITBRANCH" = "master" ]; then if [ "$GITBRANCH" = "master" ]; then
# avoid leaking oauth token # avoid leaking oauth token
set +x set +x

View File

@ -1,51 +0,0 @@
#!/bin/sh
. ./ci/drone/linux_script_base
BUILD_FLAGS="-Dskip-non-native"
case "$1" in
1)
./build/zig build $BUILD_FLAGS test-behavior
./build/zig build $BUILD_FLAGS test-compiler-rt
./build/zig build $BUILD_FLAGS test-fmt
./build/zig build $BUILD_FLAGS docs
;;
2)
# Debug
./build/zig build $BUILD_FLAGS test-std -Dskip-release-safe -Dskip-release-fast -Dskip-release-small
;;
3)
# ReleaseSafe
./build/zig build $BUILD_FLAGS test-std -Dskip-debug -Dskip-release-fast -Dskip-release-small -Dskip-non-native -Dskip-single-threaded
;;
4)
# ReleaseFast
./build/zig build $BUILD_FLAGS test-std -Dskip-debug -Dskip-release-safe -Dskip-release-small -Dskip-non-native -Dskip-single-threaded
;;
5)
# ReleaseSmall
./build/zig build $BUILD_FLAGS test-std -Dskip-debug -Dskip-release-safe -Dskip-release-fast
;;
6)
./build/zig build $BUILD_FLAGS test-universal-libc
./build/zig build $BUILD_FLAGS test-compare-output
./build/zig build $BUILD_FLAGS test-standalone -Dskip-release-safe
./build/zig build $BUILD_FLAGS test-stack-traces
./build/zig build $BUILD_FLAGS test-cli
./build/zig build $BUILD_FLAGS test-asm-link
./build/zig build $BUILD_FLAGS test-translate-c
;;
7)
./build/zig build $BUILD_FLAGS # test building self-hosted without LLVM
./build/zig build $BUILD_FLAGS test-cases
;;
'')
echo "error: expecting test group argument"
exit 1
;;
*)
echo "error: unknown test group: $1"
exit 1
;;
esac

13
ci/drone/test_linux_behavior Executable file
View File

@ -0,0 +1,13 @@
#!/bin/sh
set -x
set -e
INSTALL_PREFIX="$DRONE_WORKSPACE/stage3-release"
ZIG="$INSTALL_PREFIX/bin/zig"
export ZIG_GLOBAL_CACHE_DIR="$DRONE_WORKSPACE/zig-cache"
$ZIG build test-behavior -Dskip-non-native
$ZIG build test-compiler-rt -Dskip-non-native
$ZIG build test-fmt
$ZIG build docs

11
ci/drone/test_linux_cases Executable file
View File

@ -0,0 +1,11 @@
#!/bin/sh
set -x
set -e
INSTALL_PREFIX="$DRONE_WORKSPACE/stage3-release"
ZIG="$INSTALL_PREFIX/bin/zig"
export ZIG_GLOBAL_CACHE_DIR="$DRONE_WORKSPACE/zig-cache"
$ZIG build -Dskip-non-native # test building self-hosted without LLVM
$ZIG build -Dskip-non-native test-cases

16
ci/drone/test_linux_misc Executable file
View File

@ -0,0 +1,16 @@
#!/bin/sh
set -x
set -e
INSTALL_PREFIX="$DRONE_WORKSPACE/stage3-release"
ZIG="$INSTALL_PREFIX/bin/zig"
export ZIG_GLOBAL_CACHE_DIR="$DRONE_WORKSPACE/zig-cache"
$ZIG build test-universal-libc -Dskip-non-native
$ZIG build test-compare-output -Dskip-non-native
$ZIG build test-standalone -Dskip-non-native -Dskip-release-safe
$ZIG build test-stack-traces -Dskip-non-native
$ZIG build test-cli -Dskip-non-native
$ZIG build test-asm-link -Dskip-non-native
$ZIG build test-translate-c -Dskip-non-native

10
ci/drone/test_linux_std_Debug Executable file
View File

@ -0,0 +1,10 @@
#!/bin/sh
set -x
set -e
INSTALL_PREFIX="$DRONE_WORKSPACE/stage3-release"
ZIG="$INSTALL_PREFIX/bin/zig"
export ZIG_GLOBAL_CACHE_DIR="$DRONE_WORKSPACE/zig-cache"
$ZIG build test-std -Dskip-release-safe -Dskip-release-fast -Dskip-release-small -Dskip-non-native

View File

@ -0,0 +1,10 @@
#!/bin/sh
set -x
set -e
INSTALL_PREFIX="$DRONE_WORKSPACE/stage3-release"
ZIG="$INSTALL_PREFIX/bin/zig"
export ZIG_GLOBAL_CACHE_DIR="$DRONE_WORKSPACE/zig-cache"
$ZIG build test-std -Dskip-debug -Dskip-release-safe -Dskip-release-small -Dskip-non-native -Dskip-single-threaded

View File

@ -0,0 +1,10 @@
#!/bin/sh
set -x
set -e
INSTALL_PREFIX="$DRONE_WORKSPACE/stage3-release"
ZIG="$INSTALL_PREFIX/bin/zig"
export ZIG_GLOBAL_CACHE_DIR="$DRONE_WORKSPACE/zig-cache"
$ZIG build test-std -Dskip-debug -Dskip-release-fast -Dskip-release-small -Dskip-non-native -Dskip-single-threaded

View File

@ -0,0 +1,16 @@
#!/bin/sh
set -x
set -e
INSTALL_PREFIX="$DRONE_WORKSPACE/stage3-release"
ZIG="$INSTALL_PREFIX/bin/zig"
export ZIG_GLOBAL_CACHE_DIR="$DRONE_WORKSPACE/zig-cache"
# Empirically, this takes about 55 minutes on the CI, and is the bottleneck
# causing timeouts. So this is disabled in favor of running a smaller set
# of ReleaseSmall std lib tests.
# $ZIG build test-std -Dskip-debug -Dskip-release-safe -Dskip-release-fast -Dskip-non-native
$ZIG test lib/std/std.zig -OReleaseSmall
$ZIG test lib/std/std.zig -OReleaseSmall -lc

View File

@ -7,7 +7,9 @@ sudo pkg update -fq
sudo pkg install -y cmake py39-s3cmd wget curl jq samurai sudo pkg install -y cmake py39-s3cmd wget curl jq samurai
ZIGDIR="$(pwd)" ZIGDIR="$(pwd)"
CACHE_BASENAME="zig+llvm+lld+clang-x86_64-freebsd-gnu-0.10.0-dev.2931+bdf3fa12f" TARGET="x86_64-freebsd-gnu"
MCPU="baseline"
CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.10.0-dev.3524+74673b7f6"
PREFIX="$HOME/$CACHE_BASENAME" PREFIX="$HOME/$CACHE_BASENAME"
cd $HOME cd $HOME
@ -29,34 +31,47 @@ export TERM=dumb
mkdir build mkdir build
cd build cd build
cmake .. \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_PREFIX_PATH=$PREFIX \
"-DCMAKE_INSTALL_PREFIX=$(pwd)/release" \
-DZIG_STATIC=ON \
-DZIG_TARGET_TRIPLE=x86_64-freebsd-gnu \
-GNinja
samu install
# TODO ld.lld: error: undefined symbol: main
# >>> referenced by crt1_c.c:75 (/usr/src/lib/csu/amd64/crt1_c.c:75) cmake .. \
# >>> /usr/lib/crt1.o:(_start) -DCMAKE_BUILD_TYPE=Release \
#release/bin/zig test ../test/behavior.zig -fno-stage1 -fLLVM -I ../test -DCMAKE_PREFIX_PATH=$PREFIX \
-DZIG_TARGET_TRIPLE="$TARGET" \
-DZIG_TARGET_MCPU="$MCPU" \
-DZIG_STATIC=ON \
-GNinja
# TODO: eliminate this workaround. Without this, zig does not end up passing
# -isystem /usr/include when building libc++, resulting in #include <sys/endian.h>
# "file not found" errors.
echo "include_dir=/usr/include" >>libc.txt
echo "sys_include_dir=/usr/include" >>libc.txt
echo "crt_dir=/usr/lib" >>libc.txt
echo "msvc_lib_dir=" >>libc.txt
echo "kernel32_lib_dir=" >>libc.txt
echo "gcc_dir=" >>libc.txt
ZIG_LIBC_TXT="$(pwd)/libc.txt"
ZIG_LIBC="$ZIG_LIBC_TXT" samu install
# Here we skip some tests to save time. # Here we skip some tests to save time.
release/bin/zig build test -Dskip-stage1 -Dskip-non-native stage3/bin/zig build test docs \
-Dstatic-llvm \
--search-prefix "$PREFIX" \
-Dskip-stage1 \
-Dskip-non-native
if [ -f ~/.s3cfg ]; then if [ -f ~/.s3cfg ]; then
mv ../LICENSE release/ mv ../LICENSE stage3/
mv ../zig-cache/langref.html release/ mv ../zig-cache/langref.html stage3/
mv release/bin/zig release/ mv stage3/bin/zig stage3/
rmdir release/bin rmdir stage3/bin
GITBRANCH=$(basename $GITHUB_REF) GITBRANCH=$(basename $GITHUB_REF)
VERSION=$(release/zig version) VERSION=$(stage3/zig version)
DIRNAME="zig-freebsd-x86_64-$VERSION" DIRNAME="zig-freebsd-x86_64-$VERSION"
TARBALL="$DIRNAME.tar.xz" TARBALL="$DIRNAME.tar.xz"
mv release "$DIRNAME" mv stage3 "$DIRNAME"
tar cfJ "$TARBALL" "$DIRNAME" tar cfJ "$TARBALL" "$DIRNAME"
s3cmd put -P --add-header="cache-control: public, max-age=31536000, immutable" "$TARBALL" s3://ziglang.org/builds/ s3cmd put -P --add-header="cache-control: public, max-age=31536000, immutable" "$TARBALL" s3://ziglang.org/builds/

View File

@ -100,6 +100,27 @@ cd "$SRCTARBALLDIR/ci/srht"
CIDIR="$(pwd)" CIDIR="$(pwd)"
cd "$HOME" cd "$HOME"
# Upload new stdlib autodocs
mkdir -p docs_to_upload/documentation/master/std/
gzip -c -9 "$ZIGDIR/docs/std/index.html" > docs_to_upload/documentation/master/std/index.html
gzip -c -9 "$ZIGDIR/docs/std/data.js" > docs_to_upload/documentation/master/std/data.js
gzip -c -9 "$ZIGDIR/docs/std/main.js" > docs_to_upload/documentation/master/std/main.js
gzip -c -9 "$LANGREF" > docs_to_upload/documentation/master/index.html
$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/
mkdir -p docs_src_to_upload/documentation/master/std/
cp -r "$ZIGDIR/docs/std/src" docs_src_to_upload/documentation/master/std/
$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/
## Copy without compression:
# mkdir -p docs_to_upload/documentation/master/std/
# cp "$ZIGDIR/docs/std/index.html" docs_to_upload/documentation/master/std/index.html
# cp "$ZIGDIR/docs/std/data.js" docs_to_upload/documentation/master/std/data.js
# cp "$ZIGDIR/docs/std/main.js" docs_to_upload/documentation/master/std/main.js
# cp "$LANGREF" docs_to_upload/documentation/master/index.html
# $S3CMD put -P --no-mime-magic --recursive --add-header="Cache-Control: max-age=0, must-revalidate" "docs_to_upload/" s3://ziglang.org/
git clone --depth 1 git@github.com:ziglang/www.ziglang.org.git git clone --depth 1 git@github.com:ziglang/www.ziglang.org.git
cd www.ziglang.org cd www.ziglang.org
WWWDIR="$(pwd)" WWWDIR="$(pwd)"
@ -108,12 +129,6 @@ $S3CMD put -P --no-mime-magic --add-header="cache-control: public, max-age=31536
cd "$WWWDIR" cd "$WWWDIR"
cp "$CIDIR/out/index.json" data/releases.json cp "$CIDIR/out/index.json" data/releases.json
mkdir -p content/documentation/master/std
cp "$LANGREF" content/documentation/master/index.html
cp "$ZIGDIR/docs/std/index.html" content/documentation/master/std/index.html
cp "$ZIGDIR/docs/std/data.js" content/documentation/master/std/data.js
cp "$ZIGDIR/docs/std/main.js" content/documentation/master/std/main.js
git add data/releases.json git add data/releases.json
git add content/ git commit -m "CI: update releases"
git commit -m "CI: update releases and docs"
git push origin master git push origin master

20
ci/zinc/build_aarch64_macos Executable file
View File

@ -0,0 +1,20 @@
#!/bin/sh
set -x
set -e
RELEASE_STAGING="$DRONE_WORKSPACE/_release/staging"
TARGET="aarch64-macos-none"
MCPU="apple_a14"
INSTALL_PREFIX="$DRONE_WORKSPACE/$TARGET"
SEARCH_PREFIX="/deps/$TARGET"
"$RELEASE_STAGING/bin/zig" build \
--prefix "$INSTALL_PREFIX" \
--search-prefix "$SEARCH_PREFIX" \
-Dstatic-llvm \
-Drelease \
-Dstrip \
-Dtarget="$TARGET" \
-Dmcpu="$MCPU" \
-Denable-stage1

10
ci/zinc/configure_git Executable file
View File

@ -0,0 +1,10 @@
#!/bin/sh
set -x
set -e
# Make the `zig version` number consistent.
# This will affect the cmake commands that follow.
# This is in its own script because git does not support this command
# being run concurrently with itself.
git config core.abbrev 9

View File

@ -9,26 +9,75 @@ workspace:
path: /workspace path: /workspace
steps: steps:
- name: test - name: configure_git
image: ci/debian-amd64:11.1-6 image: ci/debian-amd64:11.1-9
commands: commands:
- ./ci/zinc/linux_test.sh - ./ci/zinc/configure_git
- name: package - name: test_stage3_debug
depends_on: depends_on:
- test - configure_git
image: ci/debian-amd64:11.1-9
commands:
- ./ci/zinc/linux_test_stage3_debug
- name: test_stage3_release
depends_on:
- configure_git
image: ci/debian-amd64:11.1-9
commands:
- ./ci/zinc/linux_test_stage3_release
- name: build_aarch64_macos
depends_on:
- test_stage3_release
image: ci/debian-amd64:11.1-9
commands:
- ./ci/zinc/build_aarch64_macos
- name: linux_package
depends_on:
- test_stage3_debug
- test_stage3_release
when: when:
branch: branch:
- master - master
event: event:
- push - push
image: ci/debian-amd64:11.1-6 image: ci/debian-amd64:11.1-9
environment: environment:
AWS_ACCESS_KEY_ID: AWS_ACCESS_KEY_ID:
from_secret: AWS_ACCESS_KEY_ID from_secret: AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY: AWS_SECRET_ACCESS_KEY:
from_secret: AWS_SECRET_ACCESS_KEY from_secret: AWS_SECRET_ACCESS_KEY
commands:
- ./ci/zinc/linux_package
- name: macos_package
depends_on:
- test_stage3_debug
- build_aarch64_macos
when:
branch:
- master
event:
- push
image: ci/debian-amd64:11.1-9
environment:
AWS_ACCESS_KEY_ID:
from_secret: AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY:
from_secret: AWS_SECRET_ACCESS_KEY
commands:
- ./ci/zinc/macos_package
- name: notify_lavahut
depends_on:
- macos_package
- linux_package
image: ci/debian-amd64:11.1-9
environment:
SRHT_OAUTH_TOKEN: SRHT_OAUTH_TOKEN:
from_secret: SRHT_OAUTH_TOKEN from_secret: SRHT_OAUTH_TOKEN
commands: commands:
- ./ci/zinc/linux_package.sh - ./ci/zinc/notify_lavahut

View File

@ -1,27 +0,0 @@
#!/bin/sh
# https://docs.drone.io/pipeline/docker/syntax/workspace/
#
# Drone automatically creates a temporary volume, known as your workspace,
# where it clones your repository. The workspace is the current working
# directory for each step in your pipeline.
#
# Because the workspace is a volume, filesystem changes are persisted between
# pipeline steps. In other words, individual steps can communicate and share
# state using the filesystem.
#
# Workspace volumes are ephemeral. They are created when the pipeline starts
# and destroyed after the pipeline completes.
set -x
set -e
ARCH="$(uname -m)"
DEPS_LOCAL="/deps/local"
WORKSPACE="$DRONE_WORKSPACE"
DEBUG_STAGING="$WORKSPACE/_debug/staging"
RELEASE_STAGING="$WORKSPACE/_release/staging"
export PATH=$DEPS_LOCAL/bin:$PATH

View File

@ -1,25 +1,30 @@
#!/bin/sh #!/bin/sh
. ./ci/zinc/linux_base.sh set -x
set -e
cp LICENSE $RELEASE_STAGING/ ARCH="$(uname -m)"
cp zig-cache/langref.html $RELEASE_STAGING/docs/ OS="linux"
RELEASE_STAGING="$DRONE_WORKSPACE/_release/staging"
VERSION=$($RELEASE_STAGING/bin/zig version)
BASENAME="zig-$OS-$ARCH-$VERSION"
TARBALL="$BASENAME.tar.xz"
# This runs concurrently with the macos_package script, so it should not make
# any changes to the filesystem that will cause problems for the other script.
cp -r "$RELEASE_STAGING" "$BASENAME"
# Remove the unnecessary bin dir in $prefix/bin/zig # Remove the unnecessary bin dir in $prefix/bin/zig
mv $RELEASE_STAGING/bin/zig $RELEASE_STAGING/ mv $BASENAME/bin/zig $BASENAME/
rmdir $RELEASE_STAGING/bin rmdir $BASENAME/bin
# Remove the unnecessary zig dir in $prefix/lib/zig/std/std.zig # Remove the unnecessary zig dir in $prefix/lib/zig/std/std.zig
mv $RELEASE_STAGING/lib/zig $RELEASE_STAGING/lib2 mv $BASENAME/lib/zig $BASENAME/lib2
rmdir $RELEASE_STAGING/lib rmdir $BASENAME/lib
mv $RELEASE_STAGING/lib2 $RELEASE_STAGING/lib mv $BASENAME/lib2 $BASENAME/lib
VERSION=$($RELEASE_STAGING/zig version)
BASENAME="zig-linux-$ARCH-$VERSION"
TARBALL="$BASENAME.tar.xz"
mv "$RELEASE_STAGING" "$BASENAME"
tar cfJ "$TARBALL" "$BASENAME" tar cfJ "$TARBALL" "$BASENAME"
ls -l "$TARBALL"
SHASUM=$(sha256sum $TARBALL | cut '-d ' -f1) SHASUM=$(sha256sum $TARBALL | cut '-d ' -f1)
BYTESIZE=$(wc -c < $TARBALL) BYTESIZE=$(wc -c < $TARBALL)
@ -34,15 +39,7 @@ echo "\"size\": \"$BYTESIZE\"}" >>$MANIFEST
s3cmd put -P --add-header="cache-control: public, max-age=31536000, immutable" "$TARBALL" s3://ziglang.org/builds/ s3cmd put -P --add-header="cache-control: public, max-age=31536000, immutable" "$TARBALL" s3://ziglang.org/builds/
# Publish manifest. # Publish manifest.
s3cmd put -P --add-header="cache-control: max-age=0, must-revalidate" "$MANIFEST" "s3://ziglang.org/builds/$ARCH-linux-$VERSION.json" s3cmd put -P --add-header="cache-control: max-age=0, must-revalidate" "$MANIFEST" "s3://ziglang.org/builds/$ARCH-$OS-$VERSION.json"
# Avoid leaking oauth token.
set +x
cd $WORKSPACE
./ci/srht/on_master_success "$VERSION" "$SRHT_OAUTH_TOKEN"
set -x
# Explicit exit helps show last command duration. # Explicit exit helps show last command duration.
exit exit

View File

@ -1,93 +0,0 @@
#!/bin/sh
. ./ci/zinc/linux_base.sh
OLD_ZIG="$DEPS_LOCAL/bin/zig"
TARGET="${ARCH}-linux-musl"
MCPU="baseline"
# Make the `zig version` number consistent.
# This will affect the cmake command below.
git config core.abbrev 9
echo "building debug zig with zig version $($OLD_ZIG version)"
export CC="$OLD_ZIG cc -target $TARGET -mcpu=$MCPU"
export CXX="$OLD_ZIG c++ -target $TARGET -mcpu=$MCPU"
mkdir _debug
cd _debug
cmake .. \
-DCMAKE_INSTALL_PREFIX="$DEBUG_STAGING" \
-DCMAKE_PREFIX_PATH="$DEPS_LOCAL" \
-DCMAKE_BUILD_TYPE=Debug \
-DZIG_TARGET_TRIPLE="$TARGET" \
-DZIG_TARGET_MCPU="$MCPU" \
-DZIG_STATIC=ON \
-GNinja
# Now cmake will use zig as the C/C++ compiler. We reset the environment variables
# so that installation and testing do not get affected by them.
unset CC
unset CXX
ninja install
STAGE1_ZIG="$DEBUG_STAGING/bin/zig"
# Here we rebuild zig but this time using the Zig binary we just now produced to
# build zig1.o rather than relying on the one built with stage0. See
# https://github.com/ziglang/zig/issues/6830 for more details.
cmake .. -DZIG_EXECUTABLE="$STAGE1_ZIG"
ninja install
cd $WORKSPACE
echo "Looking for non-conforming code formatting..."
echo "Formatting errors can be fixed by running 'zig fmt' on the files printed here."
$STAGE1_ZIG fmt --check . --exclude test/cases/
$STAGE1_ZIG build -p stage2 -Dstatic-llvm -Dtarget=native-native-musl --search-prefix "$DEPS_LOCAL"
stage2/bin/zig build -p stage3 -Dstatic-llvm -Dtarget=native-native-musl --search-prefix "$DEPS_LOCAL"
stage3/bin/zig build # test building self-hosted without LLVM
stage3/bin/zig build -Dtarget=arm-linux-musleabihf # test building self-hosted for 32-bit arm
stage3/bin/zig build test-compiler-rt -fqemu -fwasmtime -Denable-llvm
stage3/bin/zig build test-behavior -fqemu -fwasmtime -Denable-llvm
stage3/bin/zig build test-std -fqemu -fwasmtime -Denable-llvm
stage3/bin/zig build test-universal-libc -fqemu -fwasmtime -Denable-llvm
stage3/bin/zig build test-compare-output -fqemu -fwasmtime -Denable-llvm
stage3/bin/zig build test-asm-link -fqemu -fwasmtime -Denable-llvm
stage3/bin/zig build test-fmt -fqemu -fwasmtime -Denable-llvm
stage3/bin/zig build test-translate-c -fqemu -fwasmtime -Denable-llvm
stage3/bin/zig build test-run-translated-c -fqemu -fwasmtime -Denable-llvm
stage3/bin/zig build test-standalone -fqemu -fwasmtime -Denable-llvm
stage3/bin/zig build test-cli -fqemu -fwasmtime -Denable-llvm
stage3/bin/zig build test-cases -fqemu -fwasmtime -Dstatic-llvm -Dtarget=native-native-musl --search-prefix "$DEPS_LOCAL"
stage3/bin/zig build test-link -fqemu -fwasmtime -Denable-llvm
$STAGE1_ZIG build test-stack-traces -fqemu -fwasmtime
$STAGE1_ZIG build docs -fqemu -fwasmtime
# Produce the experimental std lib documentation.
mkdir -p "$RELEASE_STAGING/docs/std"
stage3/bin/zig test lib/std/std.zig \
--zig-lib-dir lib \
-femit-docs=$RELEASE_STAGING/docs/std \
-fno-emit-bin
# Look for HTML errors.
tidy --drop-empty-elements no -qe zig-cache/langref.html
# Build release zig.
stage3/bin/zig build \
--prefix "$RELEASE_STAGING" \
--search-prefix "$DEPS_LOCAL" \
-Dstatic-llvm \
-Drelease \
-Dstrip \
-Dtarget="$TARGET" \
-Dstage1
# Explicit exit helps show last command duration.
exit

61
ci/zinc/linux_test_stage3_debug Executable file
View File

@ -0,0 +1,61 @@
#!/bin/sh
set -x
set -e
ARCH="$(uname -m)"
DEPS_LOCAL="/deps/local"
OLD_ZIG="$DEPS_LOCAL/bin/zig"
TARGET="${ARCH}-linux-musl"
MCPU="baseline"
export PATH=$DEPS_LOCAL/bin:$PATH
echo "building stage3-debug with zig version $($OLD_ZIG version)"
# Override the cache directories so that we don't clobber with the release
# testing script which is running concurrently and in the same directory.
# Normally we want processes to cooperate, but in this case we want them isolated.
export ZIG_LOCAL_CACHE_DIR="$(pwd)/zig-cache-local-debug"
export ZIG_GLOBAL_CACHE_DIR="$(pwd)/zig-cache-global-debug"
export CC="$OLD_ZIG cc -target $TARGET -mcpu=$MCPU"
export CXX="$OLD_ZIG c++ -target $TARGET -mcpu=$MCPU"
mkdir build-debug
cd build-debug
cmake .. \
-DCMAKE_INSTALL_PREFIX="$(pwd)/stage3" \
-DCMAKE_PREFIX_PATH="$DEPS_LOCAL" \
-DCMAKE_BUILD_TYPE=Debug \
-DZIG_STATIC=ON \
-DZIG_USE_LLVM_CONFIG=OFF \
-GNinja
# Now cmake will use zig as the C/C++ compiler. We reset the environment variables
# so that installation and testing do not get affected by them.
unset CC
unset CXX
ninja install
echo "Looking for non-conforming code formatting..."
stage3/bin/zig fmt --check .. \
--exclude ../test/cases/ \
--exclude ../build-debug \
--exclude ../build-release \
--exclude "$ZIG_LOCAL_CACHE_DIR" \
--exclude "$ZIG_GLOBAL_CACHE_DIR"
# simultaneously test building self-hosted without LLVM and with 32-bit arm
stage3/bin/zig build -Dtarget=arm-linux-musleabihf
stage3/bin/zig build test \
-fqemu \
-fwasmtime \
-Dstatic-llvm \
-Dtarget=native-native-musl \
--search-prefix "$DEPS_LOCAL"
# Explicit exit helps show last command duration.
exit

View File

@ -0,0 +1,58 @@
#!/bin/sh
set -x
set -e
ARCH="$(uname -m)"
DEPS_LOCAL="/deps/local"
RELEASE_STAGING="$DRONE_WORKSPACE/_release/staging"
OLD_ZIG="$DEPS_LOCAL/bin/zig"
TARGET="${ARCH}-linux-musl"
MCPU="baseline"
export PATH=$DEPS_LOCAL/bin:$PATH
echo "building stage3-release with zig version $($OLD_ZIG version)"
export CC="$OLD_ZIG cc -target $TARGET -mcpu=$MCPU"
export CXX="$OLD_ZIG c++ -target $TARGET -mcpu=$MCPU"
mkdir build-release
cd build-release
cmake .. \
-DCMAKE_INSTALL_PREFIX="$RELEASE_STAGING" \
-DCMAKE_PREFIX_PATH="$DEPS_LOCAL" \
-DCMAKE_BUILD_TYPE=Release \
-DZIG_TARGET_TRIPLE="$TARGET" \
-DZIG_TARGET_MCPU="$MCPU" \
-DZIG_STATIC=ON \
-GNinja
# Now cmake will use zig as the C/C++ compiler. We reset the environment variables
# so that installation and testing do not get affected by them.
unset CC
unset CXX
ninja install
"$RELEASE_STAGING/bin/zig" build test docs \
-fqemu \
-fwasmtime \
-Dstatic-llvm \
-Dtarget=native-native-musl \
--search-prefix "$DEPS_LOCAL"
# Produce the experimental std lib documentation.
mkdir -p "$RELEASE_STAGING/docs/std"
"$RELEASE_STAGING/bin/zig" test ../lib/std/std.zig \
-femit-docs=$RELEASE_STAGING/docs/std \
-fno-emit-bin
cp ../LICENSE $RELEASE_STAGING/
cp ../zig-cache/langref.html $RELEASE_STAGING/docs/
# Look for HTML errors.
tidy --drop-empty-elements no -qe $RELEASE_STAGING/docs/langref.html
# Explicit exit helps show last command duration.
exit

49
ci/zinc/macos_package Executable file
View File

@ -0,0 +1,49 @@
#!/bin/sh
set -x
set -e
ARCH="aarch64"
OS=macos
ZIG_PREFIX="$DRONE_WORKSPACE/_release/staging"
VERSION=$($ZIG_PREFIX/bin/zig version)
TARGET="$ARCH-$OS-none"
INSTALL_PREFIX="$DRONE_WORKSPACE/$TARGET"
BASENAME="zig-$OS-$ARCH-$VERSION"
TARBALL="$BASENAME.tar.xz"
# This runs concurrently with the linux_package script, so it should not make
# any changes to the filesystem that will cause problems for the other script.
# Remove the unnecessary bin dir in $prefix/bin/zig
mv $INSTALL_PREFIX/bin/zig $INSTALL_PREFIX/
rmdir $INSTALL_PREFIX/bin
# Remove the unnecessary zig dir in $prefix/lib/zig/std/std.zig
mv $INSTALL_PREFIX/lib/zig $INSTALL_PREFIX/lib2
rmdir $INSTALL_PREFIX/lib
mv $INSTALL_PREFIX/lib2 $INSTALL_PREFIX/lib
cp -r "$ZIG_PREFIX/docs" "$INSTALL_PREFIX/"
cp "$ZIG_PREFIX/LICENSE" "$INSTALL_PREFIX/"
mv "$INSTALL_PREFIX" "$BASENAME"
tar cfJ "$TARBALL" "$BASENAME"
SHASUM=$(sha256sum $TARBALL | cut '-d ' -f1)
BYTESIZE=$(wc -c < $TARBALL)
MANIFEST="manifest.json"
touch $MANIFEST
echo "{\"tarball\": \"$TARBALL\"," >>$MANIFEST
echo "\"shasum\": \"$SHASUM\"," >>$MANIFEST
echo "\"size\": \"$BYTESIZE\"}" >>$MANIFEST
# Publish artifact.
s3cmd put -P --add-header="cache-control: public, max-age=31536000, immutable" "$TARBALL" s3://ziglang.org/builds/
# Publish manifest.
s3cmd put -P --add-header="cache-control: max-age=0, must-revalidate" "$MANIFEST" "s3://ziglang.org/builds/$ARCH-$OS-$VERSION.json"
# Explicit exit helps show last command duration.
exit

9
ci/zinc/notify_lavahut Executable file
View File

@ -0,0 +1,9 @@
#!/bin/sh
set +x # Avoid leaking oauth token.
set -e
ZIG_PREFIX="$DRONE_WORKSPACE/_release/staging"
VERSION=$($ZIG_PREFIX/bin/zig version)
cd $DRONE_WORKSPACE
./ci/srht/on_master_success "$VERSION" "$SRHT_OAUTH_TOKEN"

View File

@ -1,37 +0,0 @@
message("-- Installing: ${CMAKE_INSTALL_PREFIX}/lib")
if(NOT EXISTS ${zig_EXE})
message("::")
message(":: ERROR: Executable not found")
message(":: (execute_process)")
message("::")
message(":: executable: ${zig_EXE}")
message("::")
message(FATAL_ERROR)
endif()
execute_process(COMMAND ${zig_EXE} ${ZIG_INSTALL_ARGS}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
RESULT_VARIABLE _result
)
if(_result)
message("::")
message(":: ERROR: ${_result}")
message(":: (execute_process)")
string(REPLACE ";" " " s_INSTALL_LIBSTAGE2_ARGS "${ZIG_INSTALL_ARGS}")
message("::")
message(":: argv: ${zig_EXE} ${s_INSTALL_LIBSTAGE2_ARGS}")
set(_args ${zig_EXE} ${ZIG_INSTALL_ARGS})
list(LENGTH _args _len)
math(EXPR _len "${_len} - 1")
message("::")
foreach(_i RANGE 0 ${_len})
list(GET _args ${_i} _arg)
message(":: argv[${_i}]: ${_arg}")
endforeach()
message("::")
message(FATAL_ERROR)
endif()

View File

@ -285,6 +285,7 @@ const Code = struct {
link_objects: []const []const u8, link_objects: []const []const u8,
target_str: ?[]const u8, target_str: ?[]const u8,
link_libc: bool, link_libc: bool,
backend_stage1: bool,
link_mode: ?std.builtin.LinkMode, link_mode: ?std.builtin.LinkMode,
disable_cache: bool, disable_cache: bool,
verbose_cimport: bool, verbose_cimport: bool,
@ -554,6 +555,7 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {
var link_mode: ?std.builtin.LinkMode = null; var link_mode: ?std.builtin.LinkMode = null;
var disable_cache = false; var disable_cache = false;
var verbose_cimport = false; var verbose_cimport = false;
var backend_stage1 = false;
const source_token = while (true) { const source_token = while (true) {
const content_tok = try eatToken(tokenizer, Token.Id.Content); const content_tok = try eatToken(tokenizer, Token.Id.Content);
@ -586,6 +588,8 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {
link_libc = true; link_libc = true;
} else if (mem.eql(u8, end_tag_name, "link_mode_dynamic")) { } else if (mem.eql(u8, end_tag_name, "link_mode_dynamic")) {
link_mode = .Dynamic; link_mode = .Dynamic;
} else if (mem.eql(u8, end_tag_name, "backend_stage1")) {
backend_stage1 = true;
} else if (mem.eql(u8, end_tag_name, "code_end")) { } else if (mem.eql(u8, end_tag_name, "code_end")) {
_ = try eatToken(tokenizer, Token.Id.BracketClose); _ = try eatToken(tokenizer, Token.Id.BracketClose);
break content_tok; break content_tok;
@ -609,6 +613,7 @@ fn genToc(allocator: Allocator, tokenizer: *Tokenizer) !Toc {
.link_objects = link_objects.toOwnedSlice(), .link_objects = link_objects.toOwnedSlice(),
.target_str = target_str, .target_str = target_str,
.link_libc = link_libc, .link_libc = link_libc,
.backend_stage1 = backend_stage1,
.link_mode = link_mode, .link_mode = link_mode,
.disable_cache = disable_cache, .disable_cache = disable_cache,
.verbose_cimport = verbose_cimport, .verbose_cimport = verbose_cimport,
@ -1187,6 +1192,9 @@ fn printShell(out: anytype, shell_content: []const u8) !void {
try out.writeAll("</samp></pre></figure>"); try out.writeAll("</samp></pre></figure>");
} }
// Override this to skip to later tests
const debug_start_line = 0;
fn genHtml( fn genHtml(
allocator: Allocator, allocator: Allocator,
tokenizer: *Tokenizer, tokenizer: *Tokenizer,
@ -1266,6 +1274,13 @@ fn genHtml(
continue; continue;
} }
if (debug_start_line > 0) {
const loc = tokenizer.getTokenLocation(code.source_token);
if (debug_start_line > loc.line) {
continue;
}
}
const raw_source = tokenizer.buffer[code.source_token.start..code.source_token.end]; const raw_source = tokenizer.buffer[code.source_token.start..code.source_token.end];
const trimmed_raw_source = mem.trim(u8, raw_source, " \n"); const trimmed_raw_source = mem.trim(u8, raw_source, " \n");
const tmp_source_file_name = try fs.path.join( const tmp_source_file_name = try fs.path.join(
@ -1311,6 +1326,10 @@ fn genHtml(
try build_args.append("-lc"); try build_args.append("-lc");
try shell_out.print("-lc ", .{}); try shell_out.print("-lc ", .{});
} }
if (code.backend_stage1) {
try build_args.append("-fstage1");
try shell_out.print("-fstage1", .{});
}
const target = try std.zig.CrossTarget.parse(.{ const target = try std.zig.CrossTarget.parse(.{
.arch_os_abi = code.target_str orelse "native", .arch_os_abi = code.target_str orelse "native",
}); });
@ -1443,6 +1462,10 @@ fn genHtml(
try test_args.append("-lc"); try test_args.append("-lc");
try shell_out.print("-lc ", .{}); try shell_out.print("-lc ", .{});
} }
if (code.backend_stage1) {
try test_args.append("-fstage1");
try shell_out.print("-fstage1", .{});
}
if (code.target_str) |triple| { if (code.target_str) |triple| {
try test_args.appendSlice(&[_][]const u8{ "-target", triple }); try test_args.appendSlice(&[_][]const u8{ "-target", triple });
try shell_out.print("-target {s} ", .{triple}); try shell_out.print("-target {s} ", .{triple});
@ -1490,6 +1513,14 @@ fn genHtml(
try shell_out.print("-O {s} ", .{@tagName(code.mode)}); try shell_out.print("-O {s} ", .{@tagName(code.mode)});
}, },
} }
if (code.link_libc) {
try test_args.append("-lc");
try shell_out.print("-lc ", .{});
}
if (code.backend_stage1) {
try test_args.append("-fstage1");
try shell_out.print("-fstage1", .{});
}
const result = try ChildProcess.exec(.{ const result = try ChildProcess.exec(.{
.allocator = allocator, .allocator = allocator,
.argv = test_args.items, .argv = test_args.items,

View File

@ -535,8 +535,8 @@ const Timestamp = struct {
{#header_close#} {#header_close#}
{#header_open|Top-Level Doc Comments#} {#header_open|Top-Level Doc Comments#}
<p>User documentation that doesn't belong to whatever <p>User documentation that doesn't belong to whatever
immediately follows it, like container level documentation, goes immediately follows it, like container-level documentation, goes
in top level doc comments. A top level doc comment is one that in top-level doc comments. A top-level doc comment is one that
begins with two slashes and an exclamation point: begins with two slashes and an exclamation point:
{#syntax#}//!{#endsyntax#}.</p> {#syntax#}//!{#endsyntax#}.</p>
{#code_begin|syntax|tldoc_comments#} {#code_begin|syntax|tldoc_comments#}
@ -1188,6 +1188,7 @@ test "this will be skipped" {
(The evented IO mode is enabled using the <kbd>--test-evented-io</kbd> command line parameter.) (The evented IO mode is enabled using the <kbd>--test-evented-io</kbd> command line parameter.)
</p> </p>
{#code_begin|test|async_skip#} {#code_begin|test|async_skip#}
{#backend_stage1#}
const std = @import("std"); const std = @import("std");
test "async skip test" { test "async skip test" {
@ -1520,7 +1521,8 @@ fn divide(a: i32, b: i32) i32 {
Zig supports arbitrary bit-width integers, referenced by using Zig supports arbitrary bit-width integers, referenced by using
an identifier of <code>i</code> or <code>u</code> followed by digits. For example, the identifier an identifier of <code>i</code> or <code>u</code> followed by digits. For example, the identifier
{#syntax#}i7{#endsyntax#} refers to a signed 7-bit integer. The maximum allowed bit-width of an {#syntax#}i7{#endsyntax#} refers to a signed 7-bit integer. The maximum allowed bit-width of an
integer type is {#syntax#}65535{#endsyntax#}. integer type is {#syntax#}65535{#endsyntax#}. For signed integer types, Zig uses a
<a href="https://en.wikipedia.org/wiki/Two's_complement">two's complement</a> representation.
</p> </p>
{#see_also|Wrapping Operations#} {#see_also|Wrapping Operations#}
{#header_close#} {#header_close#}
@ -2768,7 +2770,7 @@ test "comptime @intToPtr" {
} }
} }
{#code_end#} {#code_end#}
{#see_also|Optional Pointers|@intToPtr|@ptrToInt|C Pointers|Pointers to Zero Bit Types#} {#see_also|Optional Pointers|@intToPtr|@ptrToInt|C Pointers#}
{#header_open|volatile#} {#header_open|volatile#}
<p>Loads and stores are assumed to not have side effects. If a given load or store <p>Loads and stores are assumed to not have side effects. If a given load or store
should have side effects, such as Memory Mapped Input/Output (MMIO), use {#syntax#}volatile{#endsyntax#}. 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;
test "global variable alignment" { test "global variable alignment" {
try expect(@typeInfo(@TypeOf(&foo)).Pointer.alignment == 4); try expect(@typeInfo(@TypeOf(&foo)).Pointer.alignment == 4);
try expect(@TypeOf(&foo) == *align(4) u8); try expect(@TypeOf(&foo) == *align(4) u8);
const as_pointer_to_array: *[1]u8 = &foo; const as_pointer_to_array: *align(4) [1]u8 = &foo;
const as_slice: []u8 = as_pointer_to_array; const as_slice: []align(4) u8 = as_pointer_to_array;
try expect(@TypeOf(as_slice) == []align(4) u8); const as_unaligned_slice: []u8 = as_slice;
try expect(as_unaligned_slice[0] == 100);
} }
fn derp() align(@sizeOf(usize) * 2) i32 { return 1234; } fn derp() align(@sizeOf(usize) * 2) i32 {
return 1234;
}
fn noop1() align(1) void {} fn noop1() align(1) void {}
fn noop4() align(4) void {} fn noop4() align(4) void {}
test "function alignment" { test "function alignment" {
try expect(derp() == 1234); try expect(derp() == 1234);
try expect(@TypeOf(noop1) == fn() align(1) void); try expect(@TypeOf(noop1) == fn () align(1) void);
try expect(@TypeOf(noop4) == fn() align(4) void); try expect(@TypeOf(noop4) == fn () align(4) void);
noop1(); noop1();
noop4(); noop4();
} }
@ -3336,6 +3341,7 @@ fn doTheTest() !void {
Zig allows the address to be taken of a non-byte-aligned field: Zig allows the address to be taken of a non-byte-aligned field:
</p> </p>
{#code_begin|test|pointer_to_non-byte_aligned_field#} {#code_begin|test|pointer_to_non-byte_aligned_field#}
{#backend_stage1#}
const std = @import("std"); const std = @import("std");
const expect = std.testing.expect; const expect = std.testing.expect;
@ -3391,7 +3397,8 @@ fn bar(x: *const u3) u3 {
<p> <p>
Pointers to non-ABI-aligned fields share the same address as the other fields within their host integer: Pointers to non-ABI-aligned fields share the same address as the other fields within their host integer:
</p> </p>
{#code_begin|test|pointer_to_non-bit_aligned_field#} {#code_begin|test|packed_struct_field_addrs#}
{#backend_stage1#}
const std = @import("std"); const std = @import("std");
const expect = std.testing.expect; const expect = std.testing.expect;
@ -3407,7 +3414,7 @@ var bit_field = BitField{
.c = 3, .c = 3,
}; };
test "pointer to non-bit-aligned field" { test "pointers of sub-byte-aligned fields share addresses" {
try expect(@ptrToInt(&bit_field.a) == @ptrToInt(&bit_field.b)); try expect(@ptrToInt(&bit_field.a) == @ptrToInt(&bit_field.b));
try expect(@ptrToInt(&bit_field.a) == @ptrToInt(&bit_field.c)); try expect(@ptrToInt(&bit_field.a) == @ptrToInt(&bit_field.c));
} }
@ -3438,20 +3445,22 @@ test "pointer to non-bit-aligned field" {
} }
{#code_end#} {#code_end#}
<p> <p>
Packed structs have 1-byte alignment. However if you have an overaligned pointer to a packed struct, Packed structs have the same alignment as their backing integer, however, overaligned
Zig should correctly understand the alignment of fields. However there is pointers to packed structs can override this:
<a href="https://github.com/ziglang/zig/issues/1994">a bug</a>:
</p> </p>
{#code_begin|test_err|expected type '*u32', found '*align(1) u32'#} {#code_begin|test|overaligned_packed_struct#}
const std = @import("std");
const expect = std.testing.expect;
const S = packed struct { const S = packed struct {
a: u32, a: u32,
b: u32, b: u32,
}; };
test "overaligned pointer to packed struct" { test "overaligned pointer to packed struct" {
var foo: S align(4) = undefined; var foo: S align(4) = .{ .a = 1, .b = 2 };
const ptr: *align(4) S = &foo; const ptr: *align(4) S = &foo;
const ptr_to_b: *u32 = &ptr.b; const ptr_to_b: *u32 = &ptr.b;
_ = ptr_to_b; try expect(ptr_to_b.* == 2);
} }
{#code_end#} {#code_end#}
<p>When this bug is fixed, the above test in the documentation will unexpectedly pass, which will <p>When this bug is fixed, the above test in the documentation will unexpectedly pass, which will
@ -3698,7 +3707,7 @@ test "@tagName" {
<p> <p>
By default, enums are not guaranteed to be compatible with the C ABI: By default, enums are not guaranteed to be compatible with the C ABI:
</p> </p>
{#code_begin|obj_err|parameter of type 'Foo' not allowed in function with calling convention 'C'#} {#code_begin|obj_err|parameter of type 'test.Foo' not allowed in function with calling convention 'C'#}
const Foo = enum { a, b, c }; const Foo = enum { a, b, c };
export fn entry(foo: Foo) void { _ = foo; } export fn entry(foo: Foo) void { _ = foo; }
{#code_end#} {#code_end#}
@ -4004,7 +4013,7 @@ fn makeNumber() Number {
This is typically used for type safety when interacting with C code that does not expose struct details. This is typically used for type safety when interacting with C code that does not expose struct details.
Example: Example:
</p> </p>
{#code_begin|test_err|expected type '*Derp', found '*Wat'#} {#code_begin|test_err|expected type '*test.Derp', found '*test.Wat'#}
const Derp = opaque {}; const Derp = opaque {};
const Wat = opaque {}; const Wat = opaque {};
@ -4203,7 +4212,7 @@ test "switch on tagged union" {
When a {#syntax#}switch{#endsyntax#} expression does not have an {#syntax#}else{#endsyntax#} clause, When a {#syntax#}switch{#endsyntax#} expression does not have an {#syntax#}else{#endsyntax#} clause,
it must exhaustively list all the possible values. Failure to do so is a compile error: it must exhaustively list all the possible values. Failure to do so is a compile error:
</p> </p>
{#code_begin|test_err|not handled in switch#} {#code_begin|test_err|unhandled enumeration value#}
const Color = enum { const Color = enum {
auto, auto,
off, off,
@ -5015,8 +5024,8 @@ fn shiftLeftOne(a: u32) callconv(.Inline) u32 {
// Another file can use @import and call sub2 // Another file can use @import and call sub2
pub fn sub2(a: i8, b: i8) i8 { return a - b; } pub fn sub2(a: i8, b: i8) i8 { return a - b; }
// Functions can be used as values and are equivalent to pointers. // Function pointers are prefixed with `*const `.
const call2_op = fn (a: i8, b: i8) i8; const call2_op = *const fn (a: i8, b: i8) i8;
fn do_op(fn_call: call2_op, op1: i8, op2: i8) i8 { fn do_op(fn_call: call2_op, op1: i8, op2: i8) i8 {
return fn_call(op1, op2); return fn_call(op1, op2);
} }
@ -5026,17 +5035,9 @@ test "function" {
try expect(do_op(sub2, 5, 6) == -1); try expect(do_op(sub2, 5, 6) == -1);
} }
{#code_end#} {#code_end#}
<p>Function values are like pointers:</p> <p>There is a difference between a function <em>body</em> and a function <em>pointer</em>.
{#code_begin|obj#} Function bodies are {#link|comptime#}-only types while function {#link|Pointers#} may be
const assert = @import("std").debug.assert; runtime-known.</p>
comptime {
assert(@TypeOf(foo) == fn()void);
assert(@sizeOf(fn()void) == @sizeOf(?fn()void));
}
fn foo() void { }
{#code_end#}
{#header_open|Pass-by-value Parameters#} {#header_open|Pass-by-value Parameters#}
<p> <p>
Primitive types such as {#link|Integers#} and {#link|Floats#} passed as parameters Primitive types such as {#link|Integers#} and {#link|Floats#} passed as parameters
@ -6123,10 +6124,11 @@ test "float widening" {
two choices about the coercion. two choices about the coercion.
</p> </p>
<ul> <ul>
<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> <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>
<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> <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>
</ul> </ul>
{#code_begin|test_err#} {#code_begin|test_err#}
{#backend_stage1#}
// Compile time coercion of float to int // Compile time coercion of float to int
test "implicit cast to comptime_int" { test "implicit cast to comptime_int" {
var f: f32 = 54.0 / 5; var f: f32 = 54.0 / 5;
@ -6302,19 +6304,6 @@ test "coercion between unions and enums" {
{#code_end#} {#code_end#}
{#see_also|union|enum#} {#see_also|union|enum#}
{#header_close#} {#header_close#}
{#header_open|Type Coercion: Zero Bit Types#}
<p>{#link|Zero Bit Types#} may be coerced to single-item {#link|Pointers#},
regardless of const.</p>
<p>TODO document the reasoning for this</p>
<p>TODO document whether vice versa should work and why</p>
{#code_begin|test|coerce_zero_bit_types#}
test "coercion of zero bit types" {
var x: void = {};
var y: *void = x;
_ = y;
}
{#code_end#}
{#header_close#}
{#header_open|Type Coercion: undefined#} {#header_open|Type Coercion: undefined#}
<p>{#link|undefined#} can be cast to any type.</p> <p>{#link|undefined#} can be cast to any type.</p>
{#header_close#} {#header_close#}
@ -6467,7 +6456,6 @@ test "peer type resolution: *const T and ?*T" {
<li>An {#link|enum#} with only 1 tag.</li> <li>An {#link|enum#} with only 1 tag.</li>
<li>A {#link|struct#} with all fields being zero bit types.</li> <li>A {#link|struct#} with all fields being zero bit types.</li>
<li>A {#link|union#} with only 1 field which is a zero bit type.</li> <li>A {#link|union#} with only 1 field which is a zero bit type.</li>
<li>{#link|Pointers to Zero Bit Types#} are themselves zero bit types.</li>
</ul> </ul>
<p> <p>
These types can only ever have one possible value, and thus These types can only ever have one possible value, and thus
@ -6527,7 +6515,7 @@ test "turn HashMap into a set with void" {
<p> <p>
Expressions of type {#syntax#}void{#endsyntax#} are the only ones whose value can be ignored. For example: Expressions of type {#syntax#}void{#endsyntax#} are the only ones whose value can be ignored. For example:
</p> </p>
{#code_begin|test_err|expression value is ignored#} {#code_begin|test_err|ignored#}
test "ignoring expression value" { test "ignoring expression value" {
foo(); foo();
} }
@ -6553,37 +6541,6 @@ fn foo() i32 {
} }
{#code_end#} {#code_end#}
{#header_close#} {#header_close#}
{#header_open|Pointers to Zero Bit Types#}
<p>Pointers to zero bit types also have zero bits. They always compare equal to each other:</p>
{#code_begin|test|pointers_to_zero_bits#}
const std = @import("std");
const expect = std.testing.expect;
test "pointer to empty struct" {
const Empty = struct {};
var a = Empty{};
var b = Empty{};
var ptr_a = &a;
var ptr_b = &b;
comptime try expect(ptr_a == ptr_b);
}
{#code_end#}
<p>The type being pointed to can only ever be one value; therefore loads and stores are
never generated. {#link|ptrToInt#} and {#link|intToPtr#} are not allowed:</p>
{#code_begin|test_err#}
const Empty = struct {};
test "@ptrToInt for pointer to zero bit type" {
var a = Empty{};
_ = @ptrToInt(&a);
}
test "@intToPtr for pointer to zero bit type" {
_ = @intToPtr(*Empty, 0x1);
}
{#code_end#}
{#header_close#}
{#header_close#} {#header_close#}
{#header_open|Result Location Semantics#} {#header_open|Result Location Semantics#}
@ -6666,7 +6623,7 @@ fn gimmeTheBiggerInteger(a: u64, b: u64) u64 {
<p> <p>
For example, if we were to introduce another function to the above snippet: For example, if we were to introduce another function to the above snippet:
</p> </p>
{#code_begin|test_err|values of type 'type' must be comptime known#} {#code_begin|test_err|unable to resolve comptime value#}
fn max(comptime T: type, a: T, b: T) T { fn max(comptime T: type, a: T, b: T) T {
return if (a > b) a else b; return if (a > b) a else b;
} }
@ -6692,7 +6649,7 @@ fn foo(condition: bool) void {
<p> <p>
For example: For example:
</p> </p>
{#code_begin|test_err|operator not allowed for type 'bool'#} {#code_begin|test_err|operator > not allowed for type 'bool'#}
fn max(comptime T: type, a: T, b: T) T { fn max(comptime T: type, a: T, b: T) T {
return if (a > b) a else b; return if (a > b) a else b;
} }
@ -6837,7 +6794,7 @@ fn performFn(start_value: i32) i32 {
use a {#syntax#}comptime{#endsyntax#} expression to guarantee that the expression will be evaluated at compile-time. use a {#syntax#}comptime{#endsyntax#} expression to guarantee that the expression will be evaluated at compile-time.
If this cannot be accomplished, the compiler will emit an error. For example: If this cannot be accomplished, the compiler will emit an error. For example:
</p> </p>
{#code_begin|test_err|unable to evaluate constant expression#} {#code_begin|test_err|comptime call of extern function#}
extern fn exit() noreturn; extern fn exit() noreturn;
test "foo" { test "foo" {
@ -6889,7 +6846,7 @@ test "fibonacci" {
<p> <p>
Imagine if we had forgotten the base case of the recursive function and tried to run the tests: Imagine if we had forgotten the base case of the recursive function and tried to run the tests:
</p> </p>
{#code_begin|test_err|operation caused overflow#} {#code_begin|test_err|overflow of integer type#}
const expect = @import("std").testing.expect; const expect = @import("std").testing.expect;
fn fibonacci(index: u32) u32 { fn fibonacci(index: u32) u32 {
@ -6913,7 +6870,8 @@ test "fibonacci" {
But what would have happened if we used a signed integer? But what would have happened if we used a signed integer?
</p> </p>
{#code_begin|test_err|evaluation exceeded 1000 backwards branches#} {#code_begin|test_err|evaluation exceeded 1000 backwards branches#}
const expect = @import("std").testing.expect; {#backend_stage1#}
const assert = @import("std").debug.assert;
fn fibonacci(index: i32) i32 { fn fibonacci(index: i32) i32 {
//if (index < 2) return index; //if (index < 2) return index;
@ -6922,7 +6880,7 @@ fn fibonacci(index: i32) i32 {
test "fibonacci" { test "fibonacci" {
comptime { comptime {
try expect(fibonacci(7) == 13); try assert(fibonacci(7) == 13);
} }
} }
{#code_end#} {#code_end#}
@ -6935,8 +6893,8 @@ test "fibonacci" {
<p> <p>
What if we fix the base case, but put the wrong value in the {#syntax#}expect{#endsyntax#} line? What if we fix the base case, but put the wrong value in the {#syntax#}expect{#endsyntax#} line?
</p> </p>
{#code_begin|test_err|test "fibonacci"... FAIL (TestUnexpectedResult)#} {#code_begin|test_err|reached unreachable#}
const expect = @import("std").testing.expect; const assert = @import("std").debug.assert;
fn fibonacci(index: i32) i32 { fn fibonacci(index: i32) i32 {
if (index < 2) return index; if (index < 2) return index;
@ -6945,16 +6903,10 @@ fn fibonacci(index: i32) i32 {
test "fibonacci" { test "fibonacci" {
comptime { comptime {
try expect(fibonacci(7) == 99999); try assert(fibonacci(7) == 99999);
} }
} }
{#code_end#} {#code_end#}
<p>
What happened is Zig started interpreting the {#syntax#}expect{#endsyntax#} function with the
parameter {#syntax#}ok{#endsyntax#} set to {#syntax#}false{#endsyntax#}. When the interpreter hit
{#syntax#}@panic{#endsyntax#} it emitted a compile error because a panic during compile
causes a compile error if it is detected at compile-time.
</p>
<p> <p>
At container level (outside of any function), all expressions are implicitly At container level (outside of any function), all expressions are implicitly
@ -7280,6 +7232,7 @@ pub fn main() void {
</p> </p>
{#code_begin|exe#} {#code_begin|exe#}
{#target_linux_x86_64#} {#target_linux_x86_64#}
{#backend_stage1#}
pub fn main() noreturn { pub fn main() noreturn {
const msg = "hello world\n"; const msg = "hello world\n";
_ = syscall3(SYS_write, STDOUT_FILENO, @ptrToInt(msg), msg.len); _ = syscall3(SYS_write, STDOUT_FILENO, @ptrToInt(msg), msg.len);
@ -7497,6 +7450,7 @@ test "global assembly" {
or resumer (in the case of subsequent suspensions). or resumer (in the case of subsequent suspensions).
</p> </p>
{#code_begin|test|suspend_no_resume#} {#code_begin|test|suspend_no_resume#}
{#backend_stage1#}
const std = @import("std"); const std = @import("std");
const expect = std.testing.expect; const expect = std.testing.expect;
@ -7524,6 +7478,7 @@ fn func() void {
{#link|@frame#} provides access to the async function frame pointer. {#link|@frame#} provides access to the async function frame pointer.
</p> </p>
{#code_begin|test|async_suspend_block#} {#code_begin|test|async_suspend_block#}
{#backend_stage1#}
const std = @import("std"); const std = @import("std");
const expect = std.testing.expect; const expect = std.testing.expect;
@ -7562,6 +7517,7 @@ fn testSuspendBlock() void {
never returns to its resumer and continues executing. never returns to its resumer and continues executing.
</p> </p>
{#code_begin|test|resume_from_suspend#} {#code_begin|test|resume_from_suspend#}
{#backend_stage1#}
const std = @import("std"); const std = @import("std");
const expect = std.testing.expect; const expect = std.testing.expect;
@ -7598,6 +7554,7 @@ fn testResumeFromSuspend(my_result: *i32) void {
and the return value of the async function would be lost. and the return value of the async function would be lost.
</p> </p>
{#code_begin|test|async_await#} {#code_begin|test|async_await#}
{#backend_stage1#}
const std = @import("std"); const std = @import("std");
const expect = std.testing.expect; const expect = std.testing.expect;
@ -7642,6 +7599,7 @@ fn func() void {
return value directly from the target function's frame. return value directly from the target function's frame.
</p> </p>
{#code_begin|test|async_await_sequence#} {#code_begin|test|async_await_sequence#}
{#backend_stage1#}
const std = @import("std"); const std = @import("std");
const expect = std.testing.expect; const expect = std.testing.expect;
@ -7695,6 +7653,7 @@ fn seq(c: u8) void {
{#syntax#}async{#endsyntax#}/{#syntax#}await{#endsyntax#} usage: {#syntax#}async{#endsyntax#}/{#syntax#}await{#endsyntax#} usage:
</p> </p>
{#code_begin|exe|async#} {#code_begin|exe|async#}
{#backend_stage1#}
const std = @import("std"); const std = @import("std");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
@ -7773,6 +7732,7 @@ fn readFile(allocator: Allocator, filename: []const u8) ![]u8 {
observe the same behavior, with one tiny difference: observe the same behavior, with one tiny difference:
</p> </p>
{#code_begin|exe|blocking#} {#code_begin|exe|blocking#}
{#backend_stage1#}
const std = @import("std"); const std = @import("std");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
@ -7910,6 +7870,7 @@ comptime {
{#syntax#}await{#endsyntax#} will copy the result from {#syntax#}result_ptr{#endsyntax#}. {#syntax#}await{#endsyntax#} will copy the result from {#syntax#}result_ptr{#endsyntax#}.
</p> </p>
{#code_begin|test|async_struct_field_fn_pointer#} {#code_begin|test|async_struct_field_fn_pointer#}
{#backend_stage1#}
const std = @import("std"); const std = @import("std");
const expect = std.testing.expect; const expect = std.testing.expect;
@ -8071,8 +8032,8 @@ fn func(y: *i32) void {
{#header_close#} {#header_close#}
{#header_open|@byteSwap#} {#header_open|@byteSwap#}
<pre>{#syntax#}@byteSwap(comptime T: type, operand: T) T{#endsyntax#}</pre> <pre>{#syntax#}@byteSwap(operand: anytype) T{#endsyntax#}</pre>
<p>{#syntax#}T{#endsyntax#} must be an integer type with bit count evenly divisible by 8.</p> <p>{#syntax#}@TypeOf(operand){#endsyntax#} must be an integer type or an integer vector type with bit count evenly divisible by 8.</p>
<p>{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.</p> <p>{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.</p>
<p> <p>
Swaps the byte order of the integer. This converts a big endian integer to a little endian integer, 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 {
{#header_close#} {#header_close#}
{#header_open|@bitReverse#} {#header_open|@bitReverse#}
<pre>{#syntax#}@bitReverse(comptime T: type, integer: T) T{#endsyntax#}</pre> <pre>{#syntax#}@bitReverse(integer: anytype) T{#endsyntax#}</pre>
<p>{#syntax#}T{#endsyntax#} accepts any integer type.</p> <p>{#syntax#}@TypeOf(anytype){#endsyntax#} accepts any integer type or integer vector type.</p>
<p> <p>
Reverses the bitpattern of an integer value, including the sign bit if applicable. Reverses the bitpattern of an integer value, including the sign bit if applicable.
</p> </p>
@ -8229,8 +8190,8 @@ pub const CallOptions = struct {
{#header_close#} {#header_close#}
{#header_open|@clz#} {#header_open|@clz#}
<pre>{#syntax#}@clz(comptime T: type, operand: T){#endsyntax#}</pre> <pre>{#syntax#}@clz(operand: anytype){#endsyntax#}</pre>
<p>{#syntax#}T{#endsyntax#} must be an integer type.</p> <p>{#syntax#}@TypeOf(operand){#endsyntax#} must be an integer type or an integer vector type.</p>
<p>{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.</p> <p>{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.</p>
<p> <p>
This function counts the number of most-significant (leading in a big-Endian sense) zeroes in an integer. This function counts the number of most-significant (leading in a big-Endian sense) zeroes in an integer.
@ -8375,8 +8336,8 @@ test "main" {
{#header_close#} {#header_close#}
{#header_open|@ctz#} {#header_open|@ctz#}
<pre>{#syntax#}@ctz(comptime T: type, operand: T){#endsyntax#}</pre> <pre>{#syntax#}@ctz(operand: anytype){#endsyntax#}</pre>
<p>{#syntax#}T{#endsyntax#} must be an integer type.</p> <p>{#syntax#}@TypeOf(operand){#endsyntax#} must be an integer type or an integer vector type.</p>
<p>{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.</p> <p>{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.</p>
<p> <p>
This function counts the number of least-significant (trailing in a big-Endian sense) zeroes in an integer. 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" {
allows one to, for example, heap-allocate an async function frame: allows one to, for example, heap-allocate an async function frame:
</p> </p>
{#code_begin|test|heap_allocated_frame#} {#code_begin|test|heap_allocated_frame#}
{#backend_stage1#}
const std = @import("std"); const std = @import("std");
test "heap allocated frame" { test "heap allocated frame" {
@ -9011,8 +8973,8 @@ test "@wasmMemoryGrow" {
{#header_close#} {#header_close#}
{#header_open|@popCount#} {#header_open|@popCount#}
<pre>{#syntax#}@popCount(comptime T: type, operand: T){#endsyntax#}</pre> <pre>{#syntax#}@popCount(operand: anytype){#endsyntax#}</pre>
<p>{#syntax#}T{#endsyntax#} must be an integer type.</p> <p>{#syntax#}@TypeOf(operand){#endsyntax#} must be an integer type.</p>
<p>{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.</p> <p>{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.</p>
<p>Counts the number of bits set in an integer.</p> <p>Counts the number of bits set in an integer.</p>
<p> <p>
@ -9423,12 +9385,6 @@ const std = @import("std");
const expect = std.testing.expect; const expect = std.testing.expect;
test "vector @reduce" { test "vector @reduce" {
// This test regressed with LLVM 14:
// https://github.com/llvm/llvm-project/issues/55522
// We'll skip this test unless the self-hosted compiler is being used.
// After LLVM 15 is released we can delete this line.
if (@import("builtin").zig_backend == .stage1) return;
const value = @Vector(4, i32){ 1, -1, 1, -1 }; const value = @Vector(4, i32){ 1, -1, 1, -1 };
const result = value > @splat(4, @as(i32, 0)); const result = value > @splat(4, @as(i32, 0));
// result is { true, false, true, false }; // result is { true, false, true, false };
@ -9938,7 +9894,7 @@ pub fn main() void {
{#header_close#} {#header_close#}
{#header_open|Index out of Bounds#} {#header_open|Index out of Bounds#}
<p>At compile-time:</p> <p>At compile-time:</p>
{#code_begin|test_err|index 5 outside array of size 5#} {#code_begin|test_err|index 5 outside array of length 5#}
comptime { comptime {
const array: [5]u8 = "hello".*; const array: [5]u8 = "hello".*;
const garbage = array[5]; const garbage = array[5];
@ -9959,9 +9915,9 @@ fn foo(x: []const u8) u8 {
{#header_close#} {#header_close#}
{#header_open|Cast Negative Number to Unsigned Integer#} {#header_open|Cast Negative Number to Unsigned Integer#}
<p>At compile-time:</p> <p>At compile-time:</p>
{#code_begin|test_err|attempt to cast negative value to unsigned integer#} {#code_begin|test_err|type 'u32' cannot represent integer value '-1'#}
comptime { comptime {
const value: i32 = -1; var value: i32 = -1;
const unsigned = @intCast(u32, value); const unsigned = @intCast(u32, value);
_ = unsigned; _ = unsigned;
} }
@ -9982,7 +9938,7 @@ pub fn main() void {
{#header_close#} {#header_close#}
{#header_open|Cast Truncates Data#} {#header_open|Cast Truncates Data#}
<p>At compile-time:</p> <p>At compile-time:</p>
{#code_begin|test_err|cast from 'u16' to 'u8' truncates bits#} {#code_begin|test_err|type 'u8' cannot represent integer value '300'#}
comptime { comptime {
const spartan_count: u16 = 300; const spartan_count: u16 = 300;
const byte = @intCast(u8, spartan_count); const byte = @intCast(u8, spartan_count);
@ -10017,7 +9973,7 @@ pub fn main() void {
<li>{#link|@divExact#} (division)</li> <li>{#link|@divExact#} (division)</li>
</ul> </ul>
<p>Example with addition at compile-time:</p> <p>Example with addition at compile-time:</p>
{#code_begin|test_err|operation caused overflow#} {#code_begin|test_err|overflow of integer type 'u8' with value '256'#}
comptime { comptime {
var byte: u8 = 255; var byte: u8 = 255;
byte += 1; byte += 1;
@ -10118,6 +10074,7 @@ test "wraparound addition and subtraction" {
{#header_open|Exact Left Shift Overflow#} {#header_open|Exact Left Shift Overflow#}
<p>At compile-time:</p> <p>At compile-time:</p>
{#code_begin|test_err|operation caused overflow#} {#code_begin|test_err|operation caused overflow#}
{#backend_stage1#}
comptime { comptime {
const x = @shlExact(@as(u8, 0b01010101), 2); const x = @shlExact(@as(u8, 0b01010101), 2);
_ = x; _ = x;
@ -10137,6 +10094,7 @@ pub fn main() void {
{#header_open|Exact Right Shift Overflow#} {#header_open|Exact Right Shift Overflow#}
<p>At compile-time:</p> <p>At compile-time:</p>
{#code_begin|test_err|exact shift shifted out 1 bits#} {#code_begin|test_err|exact shift shifted out 1 bits#}
{#backend_stage1#}
comptime { comptime {
const x = @shrExact(@as(u8, 0b10101010), 2); const x = @shrExact(@as(u8, 0b10101010), 2);
_ = x; _ = x;
@ -10200,6 +10158,7 @@ pub fn main() void {
{#header_open|Exact Division Remainder#} {#header_open|Exact Division Remainder#}
<p>At compile-time:</p> <p>At compile-time:</p>
{#code_begin|test_err|exact division had a remainder#} {#code_begin|test_err|exact division had a remainder#}
{#backend_stage1#}
comptime { comptime {
const a: u32 = 10; const a: u32 = 10;
const b: u32 = 3; const b: u32 = 3;
@ -10302,7 +10261,7 @@ fn getNumberOrFail() !i32 {
{#header_close#} {#header_close#}
{#header_open|Invalid Error Code#} {#header_open|Invalid Error Code#}
<p>At compile-time:</p> <p>At compile-time:</p>
{#code_begin|test_err|integer value 11 represents no error#} {#code_begin|test_err|integer value '11' represents no error#}
comptime { comptime {
const err = error.AnError; const err = error.AnError;
const number = @errorToInt(err) + 10; const number = @errorToInt(err) + 10;
@ -10324,7 +10283,7 @@ pub fn main() void {
{#header_close#} {#header_close#}
{#header_open|Invalid Enum Cast#} {#header_open|Invalid Enum Cast#}
<p>At compile-time:</p> <p>At compile-time:</p>
{#code_begin|test_err|has no tag matching integer value 3#} {#code_begin|test_err|enum 'test.Foo' has no tag with value '3'#}
const Foo = enum { const Foo = enum {
a, a,
b, b,
@ -10356,7 +10315,7 @@ pub fn main() void {
{#header_open|Invalid Error Set Cast#} {#header_open|Invalid Error Set Cast#}
<p>At compile-time:</p> <p>At compile-time:</p>
{#code_begin|test_err|error.B not a member of error set 'Set2'#} {#code_begin|test_err|'error.B' not a member of error set 'error{A,C}'#}
const Set1 = error{ const Set1 = error{
A, A,
B, B,
@ -10417,7 +10376,7 @@ fn foo(bytes: []u8) u32 {
{#header_close#} {#header_close#}
{#header_open|Wrong Union Field Access#} {#header_open|Wrong Union Field Access#}
<p>At compile-time:</p> <p>At compile-time:</p>
{#code_begin|test_err|accessing union field 'float' while field 'int' is set#} {#code_begin|test_err|access of union field 'float' while field 'int' is active#}
comptime { comptime {
var f = Foo{ .int = 42 }; var f = Foo{ .int = 42 };
f.float = 12.34; f.float = 12.34;
@ -10509,6 +10468,7 @@ fn bar(f: *Foo) void {
</p> </p>
<p>At compile-time:</p> <p>At compile-time:</p>
{#code_begin|test_err|null pointer casted to type#} {#code_begin|test_err|null pointer casted to type#}
{#backend_stage1#}
comptime { comptime {
const opt_ptr: ?*i32 = null; const opt_ptr: ?*i32 = null;
const ptr = @ptrCast(*i32, opt_ptr); const ptr = @ptrCast(*i32, opt_ptr);
@ -10551,7 +10511,8 @@ const expect = std.testing.expect;
test "using an allocator" { test "using an allocator" {
var buffer: [100]u8 = undefined; var buffer: [100]u8 = undefined;
const allocator = std.heap.FixedBufferAllocator.init(&buffer).allocator(); var fba = std.heap.FixedBufferAllocator.init(&buffer);
const allocator = fba.allocator();
const result = try concat(allocator, "foo", "bar"); const result = try concat(allocator, "foo", "bar");
try expect(std.mem.eql(u8, "foobar", result)); try expect(std.mem.eql(u8, "foobar", result));
} }
@ -10647,7 +10608,7 @@ pub fn main() !void {
<p>String literals such as {#syntax#}"foo"{#endsyntax#} are in the global constant data section. <p>String literals such as {#syntax#}"foo"{#endsyntax#} are in the global constant data section.
This is why it is an error to pass a string literal to a mutable slice, like this: This is why it is an error to pass a string literal to a mutable slice, like this:
</p> </p>
{#code_begin|test_err|cannot cast pointer to array literal to slice type '[]u8'#} {#code_begin|test_err|expected type '[]u8', found '*const [5:0]u8'#}
fn foo(s: []u8) void { fn foo(s: []u8) void {
_ = s; _ = s;
} }
@ -11832,8 +11793,8 @@ fn readU32Be() u32 {}
<pre>{#syntax#}anytype{#endsyntax#}</pre> <pre>{#syntax#}anytype{#endsyntax#}</pre>
</th> </th>
<td> <td>
Function parameters and struct fields can be declared with {#syntax#}anytype{#endsyntax#} in place of the type. Function parameters can be declared with {#syntax#}anytype{#endsyntax#} in place of the type.
The type will be inferred where the function is called or the struct is instantiated. The type will be inferred where the function is called.
<ul> <ul>
<li>See also {#link|Function Parameter Type Inference#}</li> <li>See also {#link|Function Parameter Type Inference#}</li>
</ul> </ul>

View File

@ -9,7 +9,7 @@ const normalize = common.normalize;
pub inline fn addf3(comptime T: type, a: T, b: T) T { pub inline fn addf3(comptime T: type, a: T, b: T) T {
const bits = @typeInfo(T).Float.bits; const bits = @typeInfo(T).Float.bits;
const Z = std.meta.Int(.unsigned, bits); const Z = std.meta.Int(.unsigned, bits);
const S = std.meta.Int(.unsigned, bits - @clz(Z, @as(Z, bits) - 1)); const S = std.meta.Int(.unsigned, bits - @clz(@as(Z, bits) - 1));
const typeWidth = bits; const typeWidth = bits;
const significandBits = math.floatMantissaBits(T); const significandBits = math.floatMantissaBits(T);
@ -118,7 +118,7 @@ pub inline fn addf3(comptime T: type, a: T, b: T) T {
// If partial cancellation occured, we need to left-shift the result // If partial cancellation occured, we need to left-shift the result
// and adjust the exponent: // and adjust the exponent:
if (aSignificand < integerBit << 3) { if (aSignificand < integerBit << 3) {
const shift = @intCast(i32, @clz(Z, aSignificand)) - @intCast(i32, @clz(std.meta.Int(.unsigned, bits), integerBit << 3)); const shift = @intCast(i32, @clz(aSignificand)) - @intCast(i32, @clz(integerBit << 3));
aSignificand <<= @intCast(S, shift); aSignificand <<= @intCast(S, shift);
aExponent -= shift; aExponent -= shift;
} }

View File

@ -199,7 +199,7 @@ pub fn normalize(comptime T: type, significand: *std.meta.Int(.unsigned, @typeIn
const Z = std.meta.Int(.unsigned, @typeInfo(T).Float.bits); const Z = std.meta.Int(.unsigned, @typeInfo(T).Float.bits);
const integerBit = @as(Z, 1) << std.math.floatFractionalBits(T); const integerBit = @as(Z, 1) << std.math.floatFractionalBits(T);
const shift = @clz(Z, significand.*) - @clz(Z, integerBit); const shift = @clz(significand.*) - @clz(integerBit);
significand.* <<= @intCast(std.math.Log2Int(Z), shift); significand.* <<= @intCast(std.math.Log2Int(Z), shift);
return @as(i32, 1) - shift; return @as(i32, 1) - shift;
} }

View File

@ -206,5 +206,7 @@ pub fn __divxf3(a: f80, b: f80) callconv(.C) f80 {
} }
test { test {
if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/12603
_ = @import("divxf3_test.zig"); _ = @import("divxf3_test.zig");
} }

View File

@ -56,8 +56,8 @@ pub inline fn extendf(
// a is denormal. // a is denormal.
// renormalize the significand and clear the leading bit, then insert // renormalize the significand and clear the leading bit, then insert
// the correct adjusted exponent in the destination type. // the correct adjusted exponent in the destination type.
const scale: u32 = @clz(src_rep_t, aAbs) - const scale: u32 = @clz(aAbs) -
@clz(src_rep_t, @as(src_rep_t, srcMinNormal)); @clz(@as(src_rep_t, srcMinNormal));
absResult = @as(dst_rep_t, aAbs) << @intCast(DstShift, dstSigBits - srcSigBits + scale); absResult = @as(dst_rep_t, aAbs) << @intCast(DstShift, dstSigBits - srcSigBits + scale);
absResult ^= dstMinNormal; absResult ^= dstMinNormal;
const resultExponent: u32 = dstExpBias - srcExpBias - scale + 1; 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
// a is denormal. // a is denormal.
// renormalize the significand and clear the leading bit, then insert // renormalize the significand and clear the leading bit, then insert
// the correct adjusted exponent in the destination type. // the correct adjusted exponent in the destination type.
const scale: u16 = @clz(src_rep_t, a_abs) - const scale: u16 = @clz(a_abs) -
@clz(src_rep_t, @as(src_rep_t, src_min_normal)); @clz(@as(src_rep_t, src_min_normal));
dst.fraction = @as(u64, a_abs) << @intCast(u6, dst_sig_bits - src_sig_bits + scale); dst.fraction = @as(u64, a_abs) << @intCast(u6, dst_sig_bits - src_sig_bits + scale);
dst.fraction |= dst_int_bit; // bit 64 is always set for normal numbers dst.fraction |= dst_int_bit; // bit 64 is always set for normal numbers

View File

@ -38,7 +38,7 @@ fn __extendxftf2(a: f80) callconv(.C) f128 {
// a is denormal // a is denormal
// renormalize the significand and clear the leading bit and integer part, // renormalize the significand and clear the leading bit and integer part,
// then insert the correct adjusted exponent in the destination type. // then insert the correct adjusted exponent in the destination type.
const scale: u32 = @clz(u64, a_rep.fraction); const scale: u32 = @clz(a_rep.fraction);
abs_result = @as(u128, a_rep.fraction) << @intCast(u7, dst_sig_bits - src_sig_bits + scale + 1); abs_result = @as(u128, a_rep.fraction) << @intCast(u7, dst_sig_bits - src_sig_bits + scale + 1);
abs_result ^= dst_min_normal; abs_result ^= dst_min_normal;
abs_result |= @as(u128, scale + 1) << dst_sig_bits; abs_result |= @as(u128, scale + 1) << dst_sig_bits;

View File

@ -243,7 +243,7 @@ inline fn div_u32(n: u32, d: u32) u32 {
// special cases // special cases
if (d == 0) return 0; // ?! if (d == 0) return 0; // ?!
if (n == 0) return 0; if (n == 0) return 0;
var sr = @bitCast(c_uint, @as(c_int, @clz(u32, d)) - @as(c_int, @clz(u32, n))); var sr = @bitCast(c_uint, @as(c_int, @clz(d)) - @as(c_int, @clz(n)));
// 0 <= sr <= n_uword_bits - 1 or sr large // 0 <= sr <= n_uword_bits - 1 or sr large
if (sr > n_uword_bits - 1) { if (sr > n_uword_bits - 1) {
// d > r // d > r

View File

@ -23,7 +23,7 @@ pub fn intToFloat(comptime T: type, x: anytype) T {
var result: uT = sign_bit; var result: uT = sign_bit;
// Compute significand // Compute significand
var exp = int_bits - @clz(Z, abs_val) - 1; var exp = int_bits - @clz(abs_val) - 1;
if (int_bits <= fractional_bits or exp <= fractional_bits) { if (int_bits <= fractional_bits or exp <= fractional_bits) {
const shift_amt = fractional_bits - @intCast(math.Log2Int(uT), exp); const shift_amt = fractional_bits - @intCast(math.Log2Int(uT), exp);
@ -32,7 +32,7 @@ pub fn intToFloat(comptime T: type, x: anytype) T {
result ^= implicit_bit; // Remove implicit integer bit result ^= implicit_bit; // Remove implicit integer bit
} else { } else {
var shift_amt = @intCast(math.Log2Int(Z), exp - fractional_bits); var shift_amt = @intCast(math.Log2Int(Z), exp - fractional_bits);
const exact_tie: bool = @ctz(Z, abs_val) == shift_amt - 1; const exact_tie: bool = @ctz(abs_val) == shift_amt - 1;
// Shift down result and remove implicit integer bit // Shift down result and remove implicit integer bit
result = @intCast(uT, (abs_val >> (shift_amt - 1))) ^ (implicit_bit << 1); result = @intCast(uT, (abs_val >> (shift_amt - 1))) ^ (implicit_bit << 1);

View File

@ -186,7 +186,7 @@ fn normalize(comptime T: type, significand: *PowerOfTwoSignificandZ(T)) i32 {
const Z = PowerOfTwoSignificandZ(T); const Z = PowerOfTwoSignificandZ(T);
const integerBit = @as(Z, 1) << math.floatFractionalBits(T); const integerBit = @as(Z, 1) << math.floatFractionalBits(T);
const shift = @clz(Z, significand.*) - @clz(Z, integerBit); const shift = @clz(significand.*) - @clz(integerBit);
significand.* <<= @intCast(math.Log2Int(Z), shift); significand.* <<= @intCast(math.Log2Int(Z), shift);
return @as(i32, 1) - shift; return @as(i32, 1) - shift;
} }

View File

@ -75,12 +75,12 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
r[high] = n[high] & (d[high] - 1); r[high] = n[high] & (d[high] - 1);
rem.* = @ptrCast(*align(@alignOf(SingleInt)) DoubleInt, &r[0]).*; // TODO issue #421 rem.* = @ptrCast(*align(@alignOf(SingleInt)) DoubleInt, &r[0]).*; // TODO issue #421
} }
return n[high] >> @intCast(Log2SingleInt, @ctz(SingleInt, d[high])); return n[high] >> @intCast(Log2SingleInt, @ctz(d[high]));
} }
// K K // K K
// --- // ---
// K 0 // K 0
sr = @bitCast(c_uint, @as(c_int, @clz(SingleInt, d[high])) - @as(c_int, @clz(SingleInt, n[high]))); sr = @bitCast(c_uint, @as(c_int, @clz(d[high])) - @as(c_int, @clz(n[high])));
// 0 <= sr <= single_int_bits - 2 or sr large // 0 <= sr <= single_int_bits - 2 or sr large
if (sr > single_int_bits - 2) { if (sr > single_int_bits - 2) {
if (maybe_rem) |rem| { if (maybe_rem) |rem| {
@ -110,7 +110,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
if (d[low] == 1) { if (d[low] == 1) {
return a; return a;
} }
sr = @ctz(SingleInt, d[low]); sr = @ctz(d[low]);
q[high] = n[high] >> @intCast(Log2SingleInt, sr); q[high] = n[high] >> @intCast(Log2SingleInt, sr);
q[low] = (n[high] << @intCast(Log2SingleInt, single_int_bits - sr)) | (n[low] >> @intCast(Log2SingleInt, sr)); q[low] = (n[high] << @intCast(Log2SingleInt, single_int_bits - sr)) | (n[low] >> @intCast(Log2SingleInt, sr));
return @ptrCast(*align(@alignOf(SingleInt)) DoubleInt, &q[0]).*; // TODO issue #421 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:
// K X // K X
// --- // ---
// 0 K // 0 K
sr = 1 + single_int_bits + @as(c_uint, @clz(SingleInt, d[low])) - @as(c_uint, @clz(SingleInt, n[high])); sr = 1 + single_int_bits + @as(c_uint, @clz(d[low])) - @as(c_uint, @clz(n[high]));
// 2 <= sr <= double_int_bits - 1 // 2 <= sr <= double_int_bits - 1
// q.all = a << (double_int_bits - sr); // q.all = a << (double_int_bits - sr);
// r.all = a >> sr; // r.all = a >> sr;
@ -144,7 +144,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
// K X // K X
// --- // ---
// K K // K K
sr = @bitCast(c_uint, @as(c_int, @clz(SingleInt, d[high])) - @as(c_int, @clz(SingleInt, n[high]))); sr = @bitCast(c_uint, @as(c_int, @clz(d[high])) - @as(c_int, @clz(n[high])));
// 0 <= sr <= single_int_bits - 1 or sr large // 0 <= sr <= single_int_bits - 1 or sr large
if (sr > single_int_bits - 1) { if (sr > single_int_bits - 1) {
if (maybe_rem) |rem| { if (maybe_rem) |rem| {

View File

@ -25,9 +25,10 @@
--search-bg-color-focus: #ffffff; --search-bg-color-focus: #ffffff;
--search-sh-color: rgba(0, 0, 0, 0.18); --search-sh-color: rgba(0, 0, 0, 0.18);
--help-sh-color: rgba(0, 0, 0, 0.75); --help-sh-color: rgba(0, 0, 0, 0.75);
--help-bg-color: #aaa;
} }
html, body { margin: 0; padding:0; height: 100%; } html, body { margin: 0; padding: 0; height: 100%; }
a { a {
text-decoration: none; text-decoration: none;
@ -168,8 +169,8 @@
width: 100%; width: 100%;
margin-bottom: 0.8rem; margin-bottom: 0.8rem;
padding: 0.5rem; padding: 0.5rem;
font-size: 1rem;
font-family: var(--ui); font-family: var(--ui);
font-size: 1rem;
color: var(--tx-color); color: var(--tx-color);
background-color: var(--search-bg-color); background-color: var(--search-bg-color);
border-top: 0; border-top: 0;
@ -190,11 +191,11 @@
box-shadow: 0 0.3em 1em 0.125em var(--search-sh-color); box-shadow: 0 0.3em 1em 0.125em var(--search-sh-color);
} }
.docs .search::placeholder { #searchPlaceholder {
font-size: 1rem; position: absolute;
font-family: var(--ui); pointer-events: none;
color: var(--tx-color); top: 5px;
opacity: 0.5; left: 5px;
} }
.docs a { .docs a {
@ -207,9 +208,9 @@
.docs pre { .docs pre {
font-family: var(--mono); font-family: var(--mono);
font-size:1em; font-size: 1em;
background-color:#F5F5F5; background-color: #F5F5F5;
padding:1em; padding: 1em;
overflow-x: auto; overflow-x: auto;
} }
@ -225,7 +226,7 @@
border-bottom: 0.0625rem dashed; border-bottom: 0.0625rem dashed;
} }
.docs h2 { .docs h2 {
font-size: 1.3em; font-size: 1.3em;
margin: 0.5em 0; margin: 0.5em 0;
padding: 0; padding: 0;
@ -289,12 +290,12 @@
} }
.fieldDocs { .fieldDocs {
border: 1px solid #2A2A2A; border: 1px solid #F5F5F5;
border-top: 0px; border-top: 0px;
padding: 1px 1em; padding: 1px 1em;
} }
/* help dialog */ /* help modal */
.help-modal { .help-modal {
display: flex; display: flex;
width: 100%; width: 100%;
@ -308,13 +309,13 @@
backdrop-filter: blur(0.3em); backdrop-filter: blur(0.3em);
} }
.help-modal > .dialog { .help-modal > .modal {
max-width: 97vw; max-width: 97vw;
max-height: 97vh; max-height: 97vh;
overflow: auto; overflow: auto;
font-size: 1rem; font-size: 1rem;
color: #fff; color: #fff;
background-color: #333; background-color: var(--help-bg-color);
border: 0.125rem solid #000; border: 0.125rem solid #000;
box-shadow: 0 0.5rem 2.5rem 0.3rem var(--help-sh-color); box-shadow: 0 0.5rem 2.5rem 0.3rem var(--help-sh-color);
} }
@ -335,11 +336,11 @@
margin-right: 0.5em; margin-right: 0.5em;
} }
.help-modal kbd { kbd {
display: inline-block; display: inline-block;
padding: 0.3em 0.2em; padding: 0.3em 0.2em;
font-size: 1.2em; font-family: var(--mono);
font-size: var(--mono); font-size: 1em;
line-height: 0.8em; line-height: 0.8em;
vertical-align: middle; vertical-align: middle;
color: #000; color: #000;
@ -348,16 +349,20 @@
border-bottom-color: #c6cbd1; border-bottom-color: #c6cbd1;
border: solid 0.0625em; border: solid 0.0625em;
border-radius: 0.1875em; border-radius: 0.1875em;
box-shadow: inset 0 -0.0625em 0 #c6cbd1; box-shadow: inset 0 -0.2em 0 #c6cbd1;
cursor: default; cursor: default;
} }
#listFns > div {
padding-bottom: 10px;
}
#listFns dt { #listFns dt {
font-family: var(--mono); font-family: var(--mono);
} }
.argBreaker { .argBreaker {
display: none; display: none;
} }
/* tokens */ /* tokens */
.tok-kw { .tok-kw {
@ -391,7 +396,6 @@
/* dark mode */ /* dark mode */
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
:root { :root {
--tx-color: #bbb; --tx-color: #bbb;
--bg-color: #111; --bg-color: #111;
@ -408,11 +412,15 @@
--search-bg-color-focus: #000; --search-bg-color-focus: #000;
--search-sh-color: rgba(255, 255, 255, 0.28); --search-sh-color: rgba(255, 255, 255, 0.28);
--help-sh-color: rgba(142, 142, 142, 0.5); --help-sh-color: rgba(142, 142, 142, 0.5);
--help-bg-color: #333;
} }
.docs pre { .docs pre {
background-color:#2A2A2A; background-color:#2A2A2A;
} }
.fieldDocs {
border-color:#2A2A2A;
}
#listNav { #listNav {
background-color: #333; background-color: #333;
} }
@ -457,7 +465,6 @@
.tok-type { .tok-type {
color: #68f; color: #68f;
} }
} }
@media only screen and (max-width: 750px) { @media only screen and (max-width: 750px) {
@ -544,7 +551,7 @@
<body class="canvas"> <body class="canvas">
<div class="banner"> <div class="banner">
This is a beta autodoc build; expect bugs and missing information. This is a beta autodoc build; expect bugs and missing information.
<a href="https://github.com/ziglang/zig/wiki/How-to-contribute-to-Autodoc">Report an Issue</a>, <a href="https://github.com/ziglang/zig/wiki/How-to-contribute-to-Autodoc">Report an Issue</a>,
<a href="https://github.com/ziglang/zig/wiki/How-to-contribute-to-Autodoc">Contribute</a>, <a href="https://github.com/ziglang/zig/wiki/How-to-contribute-to-Autodoc">Contribute</a>,
<a href="https://github.com/ziglang/zig/wiki/How-to-read-the-standard-library-source-code">Learn more about stdlib source code</a>. <a href="https://github.com/ziglang/zig/wiki/How-to-read-the-standard-library-source-code">Learn more about stdlib source code</a>.
</div> </div>
@ -555,43 +562,43 @@
<div class="logo"> <div class="logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 140"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 140">
<g fill="#F7A41D"> <g fill="#F7A41D">
<g> <g>
<polygon points="46,22 28,44 19,30"/> <polygon points="46,22 28,44 19,30"/>
<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"/> <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"/>
<polygon points="31,95 12,117 4,106"/> <polygon points="31,95 12,117 4,106"/>
</g> </g>
<g> <g>
<polygon points="56,22 62,36 37,44"/> <polygon points="56,22 62,36 37,44"/>
<polygon points="56,22 111,22 111,44 37,44 56,32" shape-rendering="crispEdges"/> <polygon points="56,22 111,22 111,44 37,44 56,32" shape-rendering="crispEdges"/>
<polygon points="116,95 97,117 90,104"/> <polygon points="116,95 97,117 90,104"/>
<polygon points="116,95 100,104 97,117 42,117 42,95" shape-rendering="crispEdges"/> <polygon points="116,95 100,104 97,117 42,117 42,95" shape-rendering="crispEdges"/>
<polygon points="150,0 52,117 3,140 101,22"/> <polygon points="150,0 52,117 3,140 101,22"/>
</g> </g>
<g> <g>
<polygon points="141,22 140,40 122,45"/> <polygon points="141,22 140,40 122,45"/>
<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"/> <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"/>
<polygon points="125,95 130,110 106,117"/> <polygon points="125,95 130,110 106,117"/>
</g> </g>
</g> </g>
<style> <style>
#text { fill: #121212 } #text { fill: #121212 }
@media (prefers-color-scheme: dark) { #text { fill: #f2f2f2 } } @media (prefers-color-scheme: dark) { #text { fill: #f2f2f2 } }
</style> </style>
<g id="text"> <g id="text">
<g> <g>
<polygon points="260,22 260,37 229,40 177,40 177,22" shape-rendering="crispEdges"/> <polygon points="260,22 260,37 229,40 177,40 177,22" shape-rendering="crispEdges"/>
<polygon points="260,37 207,99 207,103 176,103 229,40 229,37"/> <polygon points="260,37 207,99 207,103 176,103 229,40 229,37"/>
<polygon points="261,99 261,117 176,117 176,103 206,99" shape-rendering="crispEdges"/> <polygon points="261,99 261,117 176,117 176,103 206,99" shape-rendering="crispEdges"/>
</g> </g>
<rect x="272" y="22" shape-rendering="crispEdges" width="22" height="95"/> <rect x="272" y="22" shape-rendering="crispEdges" width="22" height="95"/>
<g> <g>
<polygon points="394,67 394,106 376,106 376,81 360,70 346,67" shape-rendering="crispEdges"/> <polygon points="394,67 394,106 376,106 376,81 360,70 346,67" shape-rendering="crispEdges"/>
<polygon points="360,68 376,81 346,67"/> <polygon points="360,68 376,81 346,67"/>
<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"/> <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"/>
</g> </g>
</g> </g>
</svg> </svg>
</div> </div>
<div id="sectMainPkg" class="hidden"> <div id="sectMainPkg" class="hidden">
<h2><span>Main Package</span></h2> <h2><span>Main Package</span></h2>
<ul class="packages"> <ul class="packages">
@ -606,16 +613,19 @@
<h2><span>Zig Version</span></h2> <h2><span>Zig Version</span></h2>
<p class="str" id="tdZigVer"></p> <p class="str" id="tdZigVer"></p>
</div> </div>
<div> <div>
<input id="privDeclsBox" type="checkbox"/> <input id="privDeclsBox" type="checkbox"/>
<label for="privDeclsBox">Internal Doc Mode</label> <label for="privDeclsBox">Internal Doc Mode</label>
</div> </div>
</nav> </nav>
</div> </div>
<div class="flex-right"> <div id="docs" class="flex-right">
<div class="wrap"> <div class="wrap">
<section class="docs"> <section class="docs">
<input type="search" class="search" id="search" autocomplete="off" spellcheck="false" placeholder="`s` to search, `?` to see more options"> <div style="position: relative">
<span id="searchPlaceholder"><kbd>S</kbd> to search, <kbd>?</kbd> for more options</span>
<input type="search" class="search" id="search" autocomplete="off" spellcheck="false" disabled>
</div>
<p id="status">Loading...</p> <p id="status">Loading...</p>
<div id="sectNav" class="hidden"><ul id="listNav"></ul></div> <div id="sectNav" class="hidden"><ul id="listNav"></ul></div>
<div id="fnProto" class="hidden"> <div id="fnProto" class="hidden">
@ -647,10 +657,17 @@
<div id="sectSearchResults" class="hidden"> <div id="sectSearchResults" class="hidden">
<h2>Search Results</h2> <h2>Search Results</h2>
<ul id="listSearchResults"></ul> <ul id="listSearchResults"></ul>
<p id="sectSearchAllResultsLink" class="hidden"><a href="">show all results</a></p>
</div> </div>
<div id="sectSearchNoResults" class="hidden"> <div id="sectSearchNoResults" class="hidden">
<h2>No Results Found</h2> <h2>No Results Found</h2>
<p>Press escape to exit search and then '?' to see more options.</p> <p>Here are some things you can try:</p>
<ul>
<li>Check out the <a id="langRefLink">Language Reference</a> for the language itself.</li>
<li>Check out the <a href="https://ziglang.org/learn/">Learn page</a> for other helpful resources for learning Zig.</li>
<li>Use your search engine.</li>
</ul>
<p>Press <kbd>?</kbd> to see keyboard shortcuts and <kbd>Esc</kbd> to return.</p>
</div> </div>
<div id="sectFields" class="hidden"> <div id="sectFields" class="hidden">
<h2>Fields</h2> <h2>Fields</h2>
@ -702,21 +719,23 @@
</table> </table>
</div> </div>
</div> </div>
</section> </section>
</div> </div>
<div class="flex-filler"></div> <div class="flex-filler"></div>
</div> </div>
</div> </div>
<div id="helpDialog" class="hidden"> <div id="helpModal" class="hidden">
<div class="help-modal"> <div class="help-modal">
<div class="dialog"> <div class="modal">
<h1>Keyboard Shortcuts</h1> <h1>Keyboard Shortcuts</h1>
<dl><dt><kbd>?</kbd></dt><dd>Show this help dialog</dd></dl> <dl><dt><kbd>?</kbd></dt><dd>Show this help modal</dd></dl>
<dl><dt><kbd>Esc</kbd></dt><dd>Clear focus; close this dialog</dd></dl>
<dl><dt><kbd>s</kbd></dt><dd>Focus the search field</dd></dl> <dl><dt><kbd>s</kbd></dt><dd>Focus the search field</dd></dl>
<dl><dt><kbd></kbd></dt><dd>Move up in search results</dd></dl> <div style="margin-left: 1em">
<dl><dt><kbd></kbd></dt><dd>Move down in search results</dd></dl> <dl><dt><kbd></kbd></dt><dd>Move up in search results</dd></dl>
<dl><dt><kbd></kbd></dt><dd>Go to active search result</dd></dl> <dl><dt><kbd></kbd></dt><dd>Move down in search results</dd></dl>
<dl><dt><kbd></kbd></dt><dd>Go to active search result</dd></dl>
</div>
<dl><dt><kbd>Esc</kbd></dt><dd>Clear focus; close this modal</dd></dl>
</div> </div>
</div> </div>
</div> </div>

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -703,7 +703,7 @@ const PosixImpl = struct {
const max_multiplier_bits = @bitSizeOf(usize); const max_multiplier_bits = @bitSizeOf(usize);
const fibonacci_multiplier = 0x9E3779B97F4A7C15 >> (64 - max_multiplier_bits); const fibonacci_multiplier = 0x9E3779B97F4A7C15 >> (64 - max_multiplier_bits);
const max_bucket_bits = @ctz(usize, buckets.len); const max_bucket_bits = @ctz(buckets.len);
comptime assert(std.math.isPowerOfTwo(buckets.len)); comptime assert(std.math.isPowerOfTwo(buckets.len));
const index = (address *% fibonacci_multiplier) >> (max_multiplier_bits - max_bucket_bits); const index = (address *% fibonacci_multiplier) >> (max_multiplier_bits - max_bucket_bits);
@ -721,7 +721,7 @@ const PosixImpl = struct {
// then cut off the zero bits from the alignment to get the unique address. // then cut off the zero bits from the alignment to get the unique address.
const addr = @ptrToInt(ptr); const addr = @ptrToInt(ptr);
assert(addr & (alignment - 1) == 0); assert(addr & (alignment - 1) == 0);
return addr >> @ctz(usize, alignment); return addr >> @ctz(alignment);
} }
}; };

View File

@ -140,7 +140,7 @@ const FutexImpl = struct {
// - they both seem to mark the cache-line as modified regardless: https://stackoverflow.com/a/63350048 // - they both seem to mark the cache-line as modified regardless: https://stackoverflow.com/a/63350048
// - `lock bts` is smaller instruction-wise which makes it better for inlining // - `lock bts` is smaller instruction-wise which makes it better for inlining
if (comptime builtin.target.cpu.arch.isX86()) { if (comptime builtin.target.cpu.arch.isX86()) {
const locked_bit = @ctz(u32, @as(u32, locked)); const locked_bit = @ctz(@as(u32, locked));
return self.state.bitSet(locked_bit, .Acquire) == 0; return self.state.bitSet(locked_bit, .Acquire) == 0;
} }

View File

@ -168,8 +168,8 @@ pub const DefaultRwLock = struct {
const IS_WRITING: usize = 1; const IS_WRITING: usize = 1;
const WRITER: usize = 1 << 1; const WRITER: usize = 1 << 1;
const READER: usize = 1 << (1 + @bitSizeOf(Count)); const READER: usize = 1 << (1 + @bitSizeOf(Count));
const WRITER_MASK: usize = std.math.maxInt(Count) << @ctz(usize, WRITER); const WRITER_MASK: usize = std.math.maxInt(Count) << @ctz(WRITER);
const READER_MASK: usize = std.math.maxInt(Count) << @ctz(usize, READER); const READER_MASK: usize = std.math.maxInt(Count) << @ctz(READER);
const Count = std.meta.Int(.unsigned, @divFloor(@bitSizeOf(usize) - 1, 2)); const Count = std.meta.Int(.unsigned, @divFloor(@bitSizeOf(usize) - 1, 2));
pub fn tryLock(rwl: *DefaultRwLock) bool { pub fn tryLock(rwl: *DefaultRwLock) bool {

View File

@ -221,6 +221,30 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
mem.copy(T, self.items[old_len..], items); mem.copy(T, self.items[old_len..], items);
} }
/// Append an unaligned slice of items to the list. Allocates more
/// memory as necessary. Only call this function if calling
/// `appendSlice` instead would be a compile error.
pub fn appendUnalignedSlice(self: *Self, items: []align(1) const T) Allocator.Error!void {
try self.ensureUnusedCapacity(items.len);
self.appendUnalignedSliceAssumeCapacity(items);
}
/// Append the slice of items to the list, asserting the capacity is already
/// enough to store the new items. **Does not** invalidate pointers.
/// Only call this function if calling `appendSliceAssumeCapacity` instead
/// would be a compile error.
pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void {
const old_len = self.items.len;
const new_len = old_len + items.len;
assert(new_len <= self.capacity);
self.items.len = new_len;
@memcpy(
@ptrCast([*]align(@alignOf(T)) u8, self.items.ptr + old_len),
@ptrCast([*]const u8, items.ptr),
items.len * @sizeOf(T),
);
}
pub const Writer = if (T != u8) pub const Writer = if (T != u8)
@compileError("The Writer interface is only defined for ArrayList(u8) " ++ @compileError("The Writer interface is only defined for ArrayList(u8) " ++
"but the given type is ArrayList(" ++ @typeName(T) ++ ")") "but the given type is ArrayList(" ++ @typeName(T) ++ ")")
@ -592,6 +616,29 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
mem.copy(T, self.items[old_len..], items); mem.copy(T, self.items[old_len..], items);
} }
/// Append the slice of items to the list. Allocates more
/// memory as necessary. Only call this function if a call to `appendSlice` instead would
/// be a compile error.
pub fn appendUnalignedSlice(self: *Self, allocator: Allocator, items: []align(1) const T) Allocator.Error!void {
try self.ensureUnusedCapacity(allocator, items.len);
self.appendUnalignedSliceAssumeCapacity(items);
}
/// Append an unaligned slice of items to the list, asserting the capacity is enough
/// to store the new items. Only call this function if a call to `appendSliceAssumeCapacity`
/// instead would be a compile error.
pub fn appendUnalignedSliceAssumeCapacity(self: *Self, items: []align(1) const T) void {
const old_len = self.items.len;
const new_len = old_len + items.len;
assert(new_len <= self.capacity);
self.items.len = new_len;
@memcpy(
@ptrCast([*]align(@alignOf(T)) u8, self.items.ptr + old_len),
@ptrCast([*]const u8, items.ptr),
items.len * @sizeOf(T),
);
}
pub const WriterContext = struct { pub const WriterContext = struct {
self: *Self, self: *Self,
allocator: Allocator, allocator: Allocator,
@ -899,6 +946,14 @@ test "std.ArrayList/ArrayListUnmanaged.basic" {
try testing.expect(list.pop() == 1); try testing.expect(list.pop() == 1);
try testing.expect(list.items.len == 9); try testing.expect(list.items.len == 9);
var unaligned: [3]i32 align(1) = [_]i32{ 4, 5, 6 };
list.appendUnalignedSlice(&unaligned) catch unreachable;
try testing.expect(list.items.len == 12);
try testing.expect(list.pop() == 6);
try testing.expect(list.pop() == 5);
try testing.expect(list.pop() == 4);
try testing.expect(list.items.len == 9);
list.appendSlice(&[_]i32{}) catch unreachable; list.appendSlice(&[_]i32{}) catch unreachable;
try testing.expect(list.items.len == 9); try testing.expect(list.items.len == 9);
@ -941,6 +996,14 @@ test "std.ArrayList/ArrayListUnmanaged.basic" {
try testing.expect(list.pop() == 1); try testing.expect(list.pop() == 1);
try testing.expect(list.items.len == 9); try testing.expect(list.items.len == 9);
var unaligned: [3]i32 align(1) = [_]i32{ 4, 5, 6 };
list.appendUnalignedSlice(a, &unaligned) catch unreachable;
try testing.expect(list.items.len == 12);
try testing.expect(list.pop() == 6);
try testing.expect(list.pop() == 5);
try testing.expect(list.pop() == 4);
try testing.expect(list.items.len == 9);
list.appendSlice(a, &[_]i32{}) catch unreachable; list.appendSlice(a, &[_]i32{}) catch unreachable;
try testing.expect(list.items.len == 9); try testing.expect(list.items.len == 9);

View File

@ -91,7 +91,7 @@ pub fn IntegerBitSet(comptime size: u16) type {
/// Returns the total number of set bits in this bit set. /// Returns the total number of set bits in this bit set.
pub fn count(self: Self) usize { pub fn count(self: Self) usize {
return @popCount(MaskInt, self.mask); return @popCount(self.mask);
} }
/// Changes the value of the specified bit of the bit /// Changes the value of the specified bit of the bit
@ -179,7 +179,7 @@ pub fn IntegerBitSet(comptime size: u16) type {
pub fn findFirstSet(self: Self) ?usize { pub fn findFirstSet(self: Self) ?usize {
const mask = self.mask; const mask = self.mask;
if (mask == 0) return null; if (mask == 0) return null;
return @ctz(MaskInt, mask); return @ctz(mask);
} }
/// Finds the index of the first set bit, and unsets it. /// Finds the index of the first set bit, and unsets it.
@ -187,7 +187,7 @@ pub fn IntegerBitSet(comptime size: u16) type {
pub fn toggleFirstSet(self: *Self) ?usize { pub fn toggleFirstSet(self: *Self) ?usize {
const mask = self.mask; const mask = self.mask;
if (mask == 0) return null; if (mask == 0) return null;
const index = @ctz(MaskInt, mask); const index = @ctz(mask);
self.mask = mask & (mask - 1); self.mask = mask & (mask - 1);
return index; return index;
} }
@ -222,12 +222,12 @@ pub fn IntegerBitSet(comptime size: u16) type {
switch (direction) { switch (direction) {
.forward => { .forward => {
const next_index = @ctz(MaskInt, self.bits_remain); const next_index = @ctz(self.bits_remain);
self.bits_remain &= self.bits_remain - 1; self.bits_remain &= self.bits_remain - 1;
return next_index; return next_index;
}, },
.reverse => { .reverse => {
const leading_zeroes = @clz(MaskInt, self.bits_remain); const leading_zeroes = @clz(self.bits_remain);
const top_bit = (@bitSizeOf(MaskInt) - 1) - leading_zeroes; const top_bit = (@bitSizeOf(MaskInt) - 1) - leading_zeroes;
self.bits_remain &= (@as(MaskInt, 1) << @intCast(ShiftInt, top_bit)) - 1; self.bits_remain &= (@as(MaskInt, 1) << @intCast(ShiftInt, top_bit)) - 1;
return top_bit; return top_bit;
@ -347,7 +347,7 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type {
pub fn count(self: Self) usize { pub fn count(self: Self) usize {
var total: usize = 0; var total: usize = 0;
for (self.masks) |mask| { for (self.masks) |mask| {
total += @popCount(MaskInt, mask); total += @popCount(mask);
} }
return total; return total;
} }
@ -475,7 +475,7 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type {
if (mask != 0) break mask; if (mask != 0) break mask;
offset += @bitSizeOf(MaskInt); offset += @bitSizeOf(MaskInt);
} else return null; } else return null;
return offset + @ctz(MaskInt, mask); return offset + @ctz(mask);
} }
/// Finds the index of the first set bit, and unsets it. /// 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 {
if (mask.* != 0) break mask; if (mask.* != 0) break mask;
offset += @bitSizeOf(MaskInt); offset += @bitSizeOf(MaskInt);
} else return null; } else return null;
const index = @ctz(MaskInt, mask.*); const index = @ctz(mask.*);
mask.* &= (mask.* - 1); mask.* &= (mask.* - 1);
return offset + index; return offset + index;
} }
@ -657,7 +657,7 @@ pub const DynamicBitSetUnmanaged = struct {
var total: usize = 0; var total: usize = 0;
for (self.masks[0..num_masks]) |mask| { for (self.masks[0..num_masks]) |mask| {
// Note: This is where we depend on padding bits being zero // Note: This is where we depend on padding bits being zero
total += @popCount(MaskInt, mask); total += @popCount(mask);
} }
return total; return total;
} }
@ -795,7 +795,7 @@ pub const DynamicBitSetUnmanaged = struct {
mask += 1; mask += 1;
offset += @bitSizeOf(MaskInt); offset += @bitSizeOf(MaskInt);
} else return null; } else return null;
return offset + @ctz(MaskInt, mask[0]); return offset + @ctz(mask[0]);
} }
/// Finds the index of the first set bit, and unsets it. /// Finds the index of the first set bit, and unsets it.
@ -808,7 +808,7 @@ pub const DynamicBitSetUnmanaged = struct {
mask += 1; mask += 1;
offset += @bitSizeOf(MaskInt); offset += @bitSizeOf(MaskInt);
} else return null; } else return null;
const index = @ctz(MaskInt, mask[0]); const index = @ctz(mask[0]);
mask[0] &= (mask[0] - 1); mask[0] &= (mask[0] - 1);
return offset + index; return offset + index;
} }
@ -1067,12 +1067,12 @@ fn BitSetIterator(comptime MaskInt: type, comptime options: IteratorOptions) typ
switch (direction) { switch (direction) {
.forward => { .forward => {
const next_index = @ctz(MaskInt, self.bits_remain) + self.bit_offset; const next_index = @ctz(self.bits_remain) + self.bit_offset;
self.bits_remain &= self.bits_remain - 1; self.bits_remain &= self.bits_remain - 1;
return next_index; return next_index;
}, },
.reverse => { .reverse => {
const leading_zeroes = @clz(MaskInt, self.bits_remain); const leading_zeroes = @clz(self.bits_remain);
const top_bit = (@bitSizeOf(MaskInt) - 1) - leading_zeroes; const top_bit = (@bitSizeOf(MaskInt) - 1) - leading_zeroes;
const no_top_bit_mask = (@as(MaskInt, 1) << @intCast(ShiftInt, top_bit)) - 1; const no_top_bit_mask = (@as(MaskInt, 1) << @intCast(ShiftInt, top_bit)) - 1;
self.bits_remain &= no_top_bit_mask; self.bits_remain &= no_top_bit_mask;

View File

@ -15,16 +15,16 @@ const testing = std.testing;
/// var slice = a.slice(); // a slice of the 64-byte array /// var slice = a.slice(); // a slice of the 64-byte array
/// var a_clone = a; // creates a copy - the structure doesn't use any internal pointers /// var a_clone = a; // creates a copy - the structure doesn't use any internal pointers
/// ``` /// ```
pub fn BoundedArray(comptime T: type, comptime capacity: usize) type { pub fn BoundedArray(comptime T: type, comptime buffer_capacity: usize) type {
return struct { return struct {
const Self = @This(); const Self = @This();
buffer: [capacity]T = undefined, buffer: [buffer_capacity]T = undefined,
len: usize = 0, len: usize = 0,
/// Set the actual length of the slice. /// Set the actual length of the slice.
/// Returns error.Overflow if it exceeds the length of the backing array. /// Returns error.Overflow if it exceeds the length of the backing array.
pub fn init(len: usize) error{Overflow}!Self { pub fn init(len: usize) error{Overflow}!Self {
if (len > capacity) return error.Overflow; if (len > buffer_capacity) return error.Overflow;
return Self{ .len = len }; return Self{ .len = len };
} }
@ -41,7 +41,7 @@ pub fn BoundedArray(comptime T: type, comptime capacity: usize) type {
/// Adjust the slice's length to `len`. /// Adjust the slice's length to `len`.
/// Does not initialize added items if any. /// Does not initialize added items if any.
pub fn resize(self: *Self, len: usize) error{Overflow}!void { pub fn resize(self: *Self, len: usize) error{Overflow}!void {
if (len > capacity) return error.Overflow; if (len > buffer_capacity) return error.Overflow;
self.len = len; self.len = len;
} }
@ -69,7 +69,7 @@ pub fn BoundedArray(comptime T: type, comptime capacity: usize) type {
/// Check that the slice can hold at least `additional_count` items. /// Check that the slice can hold at least `additional_count` items.
pub fn ensureUnusedCapacity(self: Self, additional_count: usize) error{Overflow}!void { pub fn ensureUnusedCapacity(self: Self, additional_count: usize) error{Overflow}!void {
if (self.len + additional_count > capacity) { if (self.len + additional_count > buffer_capacity) {
return error.Overflow; return error.Overflow;
} }
} }
@ -83,7 +83,7 @@ pub fn BoundedArray(comptime T: type, comptime capacity: usize) type {
/// Increase length by 1, returning pointer to the new item. /// Increase length by 1, returning pointer to the new item.
/// Asserts that there is space for the new item. /// Asserts that there is space for the new item.
pub fn addOneAssumeCapacity(self: *Self) *T { pub fn addOneAssumeCapacity(self: *Self) *T {
assert(self.len < capacity); assert(self.len < buffer_capacity);
self.len += 1; self.len += 1;
return &self.slice()[self.len - 1]; return &self.slice()[self.len - 1];
} }
@ -236,7 +236,7 @@ pub fn BoundedArray(comptime T: type, comptime capacity: usize) type {
pub fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void { pub fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void {
const old_len = self.len; const old_len = self.len;
self.len += n; self.len += n;
assert(self.len <= capacity); assert(self.len <= buffer_capacity);
mem.set(T, self.slice()[old_len..self.len], value); mem.set(T, self.slice()[old_len..self.len], value);
} }
@ -275,7 +275,7 @@ test "BoundedArray" {
try testing.expectEqualSlices(u8, &x, a.constSlice()); try testing.expectEqualSlices(u8, &x, a.constSlice());
var a2 = a; var a2 = a;
try testing.expectEqualSlices(u8, a.constSlice(), a.constSlice()); try testing.expectEqualSlices(u8, a.constSlice(), a2.constSlice());
a2.set(0, 0); a2.set(0, 0);
try testing.expect(a.get(0) != a2.get(0)); try testing.expect(a.get(0) != a2.get(0));

View File

@ -1495,6 +1495,7 @@ pub const LibExeObjStep = struct {
emit_h: bool = false, emit_h: bool = false,
bundle_compiler_rt: ?bool = null, bundle_compiler_rt: ?bool = null,
single_threaded: ?bool = null, single_threaded: ?bool = null,
stack_protector: ?bool = null,
disable_stack_probing: bool, disable_stack_probing: bool,
disable_sanitize_c: bool, disable_sanitize_c: bool,
sanitize_thread: bool, sanitize_thread: bool,
@ -1896,13 +1897,12 @@ pub const LibExeObjStep = struct {
/// When a binary cannot be ran through emulation or the option is disabled, a warning /// When a binary cannot be ran through emulation or the option is disabled, a warning
/// will be printed and the binary will *NOT* be ran. /// will be printed and the binary will *NOT* be ran.
pub fn runEmulatable(exe: *LibExeObjStep) *EmulatableRunStep { pub fn runEmulatable(exe: *LibExeObjStep) *EmulatableRunStep {
assert(exe.kind == .exe or exe.kind == .text_exe); assert(exe.kind == .exe or exe.kind == .test_exe);
const run_step = EmulatableRunStep.create(exe.builder.fmt("run {s}", .{exe.step.name}), exe); const run_step = EmulatableRunStep.create(exe.builder, exe.builder.fmt("run {s}", .{exe.step.name}), exe);
if (exe.vcpkg_bin_path) |path| { if (exe.vcpkg_bin_path) |path| {
run_step.addPathDir(path); RunStep.addPathDirInternal(&run_step.step, exe.builder, path);
} }
return run_step; return run_step;
} }
@ -2826,6 +2826,13 @@ pub const LibExeObjStep = struct {
if (self.disable_stack_probing) { if (self.disable_stack_probing) {
try zig_args.append("-fno-stack-check"); try zig_args.append("-fno-stack-check");
} }
if (self.stack_protector) |stack_protector| {
if (stack_protector) {
try zig_args.append("-fstack-protector");
} else {
try zig_args.append("-fno-stack-protector");
}
}
if (self.red_zone) |red_zone| { if (self.red_zone) |red_zone| {
if (red_zone) { if (red_zone) {
try zig_args.append("-mred-zone"); try zig_args.append("-mred-zone");

View File

@ -171,6 +171,7 @@ fn printLiteral(out: anytype, val: anytype, indent: u8) !void {
.Void, .Void,
.Bool, .Bool,
.Int, .Int,
.ComptimeInt,
.Float, .Float,
.Null, .Null,
=> try out.print("{any}", .{val}), => try out.print("{any}", .{val}),
@ -302,6 +303,7 @@ test "OptionsStep" {
options.addOption(usize, "option1", 1); options.addOption(usize, "option1", 1);
options.addOption(?usize, "option2", null); options.addOption(?usize, "option2", null);
options.addOption(?usize, "option3", 3); options.addOption(?usize, "option3", 3);
options.addOption(comptime_int, "option4", 4);
options.addOption([]const u8, "string", "zigisthebest"); options.addOption([]const u8, "string", "zigisthebest");
options.addOption(?[]const u8, "optional_string", null); options.addOption(?[]const u8, "optional_string", null);
options.addOption([2][2]u16, "nested_array", nested_array); options.addOption([2][2]u16, "nested_array", nested_array);
@ -314,6 +316,7 @@ test "OptionsStep" {
\\pub const option1: usize = 1; \\pub const option1: usize = 1;
\\pub const option2: ?usize = null; \\pub const option2: ?usize = null;
\\pub const option3: ?usize = 3; \\pub const option3: ?usize = 3;
\\pub const option4: comptime_int = 4;
\\pub const string: []const u8 = "zigisthebest"; \\pub const string: []const u8 = "zigisthebest";
\\pub const optional_string: ?[]const u8 = null; \\pub const optional_string: ?[]const u8 = null;
\\pub const nested_array: [2][2]u16 = [2][2]u16 { \\pub const nested_array: [2][2]u16 = [2][2]u16 {

View File

@ -101,7 +101,7 @@ pub fn addPathDir(self: *RunStep, search_path: []const u8) void {
} }
/// For internal use only, users of `RunStep` should use `addPathDir` directly. /// For internal use only, users of `RunStep` should use `addPathDir` directly.
fn addPathDirInternal(step: *Step, builder: *Builder, search_path: []const u8) void { pub fn addPathDirInternal(step: *Step, builder: *Builder, search_path: []const u8) void {
const env_map = getEnvMapInternal(step, builder.allocator); const env_map = getEnvMapInternal(step, builder.allocator);
const key = "PATH"; const key = "PATH";

View File

@ -21,6 +21,7 @@ output_dir: ?[]const u8,
out_basename: []const u8, out_basename: []const u8,
target: CrossTarget = CrossTarget{}, target: CrossTarget = CrossTarget{},
output_file: build.GeneratedFile, output_file: build.GeneratedFile,
use_stage1: ?bool = null,
pub fn create(builder: *Builder, source: build.FileSource) *TranslateCStep { pub fn create(builder: *Builder, source: build.FileSource) *TranslateCStep {
const self = builder.allocator.create(TranslateCStep) catch unreachable; const self = builder.allocator.create(TranslateCStep) catch unreachable;
@ -91,6 +92,19 @@ fn make(step: *Step) !void {
try argv_list.append("-D"); try argv_list.append("-D");
try argv_list.append(c_macro); try argv_list.append(c_macro);
} }
if (self.use_stage1) |stage1| {
if (stage1) {
try argv_list.append("-fstage1");
} else {
try argv_list.append("-fno-stage1");
}
} else if (self.builder.use_stage1) |stage1| {
if (stage1) {
try argv_list.append("-fstage1");
} else {
try argv_list.append("-fno-stage1");
}
}
try argv_list.append(self.source.getPath(self.builder)); try argv_list.append(self.source.getPath(self.builder));

View File

@ -294,6 +294,8 @@ pub const Type = union(enum) {
/// therefore must be kept in sync with the compiler implementation. /// therefore must be kept in sync with the compiler implementation.
pub const Struct = struct { pub const Struct = struct {
layout: ContainerLayout, layout: ContainerLayout,
/// Only valid if layout is .Packed
backing_integer: ?type = null,
fields: []const StructField, fields: []const StructField,
decls: []const Declaration, decls: []const Declaration,
is_tuple: bool, is_tuple: bool,
@ -864,13 +866,12 @@ pub fn panicUnwrapError(st: ?*StackTrace, err: anyerror) noreturn {
pub fn panicOutOfBounds(index: usize, len: usize) noreturn { pub fn panicOutOfBounds(index: usize, len: usize) noreturn {
@setCold(true); @setCold(true);
std.debug.panic("attempt to index out of bound: index {d}, len {d}", .{ index, len }); std.debug.panic("index out of bounds: index {d}, len {d}", .{ index, len });
} }
pub noinline fn returnError(maybe_st: ?*StackTrace) void { pub noinline fn returnError(st: *StackTrace) void {
@setCold(true); @setCold(true);
@setRuntimeSafety(false); @setRuntimeSafety(false);
const st = maybe_st orelse return;
addErrRetTraceAddr(st, @returnAddress()); addErrRetTraceAddr(st, @returnAddress());
} }

View File

@ -20,7 +20,7 @@ pub const Tokenizer = tokenizer.Tokenizer;
/// If linking gnu libc (glibc), the `ok` value will be true if the target /// If linking gnu libc (glibc), the `ok` value will be true if the target
/// version is greater than or equal to `glibc_version`. /// version is greater than or equal to `glibc_version`.
/// If linking a libc other than these, returns `false`. /// If linking a libc other than these, returns `false`.
pub fn versionCheck(glibc_version: std.builtin.Version) type { pub fn versionCheck(comptime glibc_version: std.builtin.Version) type {
return struct { return struct {
pub const ok = blk: { pub const ok = blk: {
if (!builtin.link_libc) break :blk false; if (!builtin.link_libc) break :blk false;
@ -263,7 +263,11 @@ const PThreadForkFn = if (builtin.zig_backend == .stage1)
fn () callconv(.C) void fn () callconv(.C) void
else else
*const fn () callconv(.C) void; *const fn () callconv(.C) void;
pub extern "c" fn pthread_key_create(key: *c.pthread_key_t, destructor: ?fn (value: *anyopaque) callconv(.C) void) c.E; pub extern "c" fn pthread_key_create(key: *c.pthread_key_t, destructor: ?PThreadKeyCreateFn) c.E;
const PThreadKeyCreateFn = if (builtin.zig_backend == .stage1)
fn (value: *anyopaque) callconv(.C) void
else
*const fn (value: *anyopaque) callconv(.C) void;
pub extern "c" fn pthread_key_delete(key: c.pthread_key_t) c.E; pub extern "c" fn pthread_key_delete(key: c.pthread_key_t) c.E;
pub extern "c" fn pthread_getspecific(key: c.pthread_key_t) ?*anyopaque; pub extern "c" fn pthread_getspecific(key: c.pthread_key_t) ?*anyopaque;
pub extern "c" fn pthread_setspecific(key: c.pthread_key_t, value: ?*anyopaque) c_int; pub extern "c" fn pthread_setspecific(key: c.pthread_key_t, value: ?*anyopaque) c_int;

View File

@ -814,10 +814,10 @@ pub const sigset_t = u32;
pub const empty_sigset: sigset_t = 0; pub const empty_sigset: sigset_t = 0;
pub const SIG = struct { pub const SIG = struct {
pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize)); pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0); pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1); pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
pub const HOLD = @intToPtr(?Sigaction.sigaction_fn, 5); pub const HOLD = @intToPtr(?Sigaction.handler_fn, 5);
/// block specified signal set /// block specified signal set
pub const _BLOCK = 1; pub const _BLOCK = 1;

View File

@ -609,9 +609,9 @@ pub const S = struct {
pub const BADSIG = SIG.ERR; pub const BADSIG = SIG.ERR;
pub const SIG = struct { pub const SIG = struct {
pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0); pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1); pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize)); pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
pub const BLOCK = 1; pub const BLOCK = 1;
pub const UNBLOCK = 2; pub const UNBLOCK = 2;

View File

@ -670,9 +670,9 @@ pub const SIG = struct {
pub const UNBLOCK = 2; pub const UNBLOCK = 2;
pub const SETMASK = 3; pub const SETMASK = 3;
pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0); pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1); pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize)); pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
pub const WORDS = 4; pub const WORDS = 4;
pub const MAXSIG = 128; pub const MAXSIG = 128;

View File

@ -702,7 +702,7 @@ pub const T = struct {
pub const CSETAF = 0x8002; pub const CSETAF = 0x8002;
pub const CSETAW = 0x8003; pub const CSETAW = 0x8003;
pub const CWAITEVENT = 0x8004; pub const CWAITEVENT = 0x8004;
pub const CSBRK = 08005; pub const CSBRK = 0x8005;
pub const CFLSH = 0x8006; pub const CFLSH = 0x8006;
pub const CXONC = 0x8007; pub const CXONC = 0x8007;
pub const CQUERYCONNECTED = 0x8008; pub const CQUERYCONNECTED = 0x8008;
@ -874,7 +874,7 @@ pub const S = struct {
pub const IFDIR = 0o040000; pub const IFDIR = 0o040000;
pub const IFCHR = 0o020000; pub const IFCHR = 0o020000;
pub const IFIFO = 0o010000; pub const IFIFO = 0o010000;
pub const INDEX_DIR = 04000000000; pub const INDEX_DIR = 0o4000000000;
pub const IUMSK = 0o7777; pub const IUMSK = 0o7777;
pub const ISUID = 0o4000; pub const ISUID = 0o4000;

View File

@ -910,9 +910,9 @@ pub const winsize = extern struct {
const NSIG = 32; const NSIG = 32;
pub const SIG = struct { pub const SIG = struct {
pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0); pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1); pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize)); pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
pub const WORDS = 4; pub const WORDS = 4;
pub const MAXSIG = 128; pub const MAXSIG = 128;

View File

@ -982,11 +982,11 @@ pub const winsize = extern struct {
const NSIG = 33; const NSIG = 33;
pub const SIG = struct { pub const SIG = struct {
pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0); pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1); pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize)); pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
pub const CATCH = @intToPtr(?Sigaction.sigaction_fn, 2); pub const CATCH = @intToPtr(?Sigaction.handler_fn, 2);
pub const HOLD = @intToPtr(?Sigaction.sigaction_fn, 3); pub const HOLD = @intToPtr(?Sigaction.handler_fn, 3);
pub const HUP = 1; pub const HUP = 1;
pub const INT = 2; pub const INT = 2;
@ -1119,26 +1119,11 @@ pub usingnamespace switch (builtin.cpu.arch) {
sc_rsp: c_long, sc_rsp: c_long,
sc_ss: c_long, sc_ss: c_long,
sc_fpstate: fxsave64, sc_fpstate: *anyopaque, // struct fxsave64 *
__sc_unused: c_int, __sc_unused: c_int,
sc_mask: c_int, sc_mask: c_int,
sc_cookie: c_long, sc_cookie: c_long,
}; };
pub const fxsave64 = packed struct {
fx_fcw: u16,
fx_fsw: u16,
fx_ftw: u8,
fx_unused1: u8,
fx_fop: u16,
fx_rip: u64,
fx_rdp: u64,
fx_mxcsr: u32,
fx_mxcsr_mask: u32,
fx_st: [8][2]u64,
fx_xmm: [16][2]u64,
fx_unused3: [96]u8,
};
}, },
else => struct {}, else => struct {},
}; };

View File

@ -879,10 +879,10 @@ pub const winsize = extern struct {
const NSIG = 75; const NSIG = 75;
pub const SIG = struct { pub const SIG = struct {
pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0); pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize)); pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1); pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
pub const HOLD = @intToPtr(?Sigaction.sigaction_fn, 2); pub const HOLD = @intToPtr(?Sigaction.handler_fn, 2);
pub const WORDS = 4; pub const WORDS = 4;
pub const MAXSIG = 75; pub const MAXSIG = 75;

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@ const math = @import("std").math;
// Reverse bit-by-bit a N-bit code. // Reverse bit-by-bit a N-bit code.
pub fn bitReverse(comptime T: type, value: T, N: usize) T { pub fn bitReverse(comptime T: type, value: T, N: usize) T {
const r = @bitReverse(T, value); const r = @bitReverse(value);
return r >> @intCast(math.Log2Int(T), @typeInfo(T).Int.bits - N); return r >> @intCast(math.Log2Int(T), @typeInfo(T).Int.bits - N);
} }

View File

@ -355,7 +355,9 @@ test "ed25519 batch verification" {
try Ed25519.verifyBatch(2, signature_batch); try Ed25519.verifyBatch(2, signature_batch);
signature_batch[1].sig = sig1; signature_batch[1].sig = sig1;
try std.testing.expectError(error.SignatureVerificationFailed, Ed25519.verifyBatch(signature_batch.len, signature_batch)); // TODO https://github.com/ziglang/zig/issues/12240
const sig_len = signature_batch.len;
try std.testing.expectError(error.SignatureVerificationFailed, Ed25519.verifyBatch(sig_len, signature_batch));
} }
} }

View File

@ -66,7 +66,7 @@ fn AesOcb(comptime Aes: anytype) type {
var offset = [_]u8{0} ** 16; var offset = [_]u8{0} ** 16;
var i: usize = 0; var i: usize = 0;
while (i < full_blocks) : (i += 1) { while (i < full_blocks) : (i += 1) {
xorWith(&offset, lt[@ctz(usize, i + 1)]); xorWith(&offset, lt[@ctz(i + 1)]);
var e = xorBlocks(offset, a[i * 16 ..][0..16].*); var e = xorBlocks(offset, a[i * 16 ..][0..16].*);
aes_enc_ctx.encrypt(&e, &e); aes_enc_ctx.encrypt(&e, &e);
xorWith(&sum, e); xorWith(&sum, e);
@ -129,7 +129,7 @@ fn AesOcb(comptime Aes: anytype) type {
var es: [16 * wb]u8 align(16) = undefined; var es: [16 * wb]u8 align(16) = undefined;
var j: usize = 0; var j: usize = 0;
while (j < wb) : (j += 1) { while (j < wb) : (j += 1) {
xorWith(&offset, lt[@ctz(usize, i + 1 + j)]); xorWith(&offset, lt[@ctz(i + 1 + j)]);
offsets[j] = offset; offsets[j] = offset;
const p = m[(i + j) * 16 ..][0..16].*; const p = m[(i + j) * 16 ..][0..16].*;
mem.copy(u8, es[j * 16 ..][0..16], &xorBlocks(p, offsets[j])); mem.copy(u8, es[j * 16 ..][0..16], &xorBlocks(p, offsets[j]));
@ -143,7 +143,7 @@ fn AesOcb(comptime Aes: anytype) type {
} }
} }
while (i < full_blocks) : (i += 1) { while (i < full_blocks) : (i += 1) {
xorWith(&offset, lt[@ctz(usize, i + 1)]); xorWith(&offset, lt[@ctz(i + 1)]);
const p = m[i * 16 ..][0..16].*; const p = m[i * 16 ..][0..16].*;
var e = xorBlocks(p, offset); var e = xorBlocks(p, offset);
aes_enc_ctx.encrypt(&e, &e); aes_enc_ctx.encrypt(&e, &e);
@ -193,7 +193,7 @@ fn AesOcb(comptime Aes: anytype) type {
var es: [16 * wb]u8 align(16) = undefined; var es: [16 * wb]u8 align(16) = undefined;
var j: usize = 0; var j: usize = 0;
while (j < wb) : (j += 1) { while (j < wb) : (j += 1) {
xorWith(&offset, lt[@ctz(usize, i + 1 + j)]); xorWith(&offset, lt[@ctz(i + 1 + j)]);
offsets[j] = offset; offsets[j] = offset;
const q = c[(i + j) * 16 ..][0..16].*; const q = c[(i + j) * 16 ..][0..16].*;
mem.copy(u8, es[j * 16 ..][0..16], &xorBlocks(q, offsets[j])); mem.copy(u8, es[j * 16 ..][0..16], &xorBlocks(q, offsets[j]));
@ -207,7 +207,7 @@ fn AesOcb(comptime Aes: anytype) type {
} }
} }
while (i < full_blocks) : (i += 1) { while (i < full_blocks) : (i += 1) {
xorWith(&offset, lt[@ctz(usize, i + 1)]); xorWith(&offset, lt[@ctz(i + 1)]);
const q = c[i * 16 ..][0..16].*; const q = c[i * 16 ..][0..16].*;
var e = xorBlocks(q, offset); var e = xorBlocks(q, offset);
aes_dec_ctx.decrypt(&e, &e); aes_dec_ctx.decrypt(&e, &e);

View File

@ -41,8 +41,8 @@ pub const Ghash = struct {
pub fn init(key: *const [key_length]u8) Ghash { pub fn init(key: *const [key_length]u8) Ghash {
const h1 = mem.readIntBig(u64, key[0..8]); const h1 = mem.readIntBig(u64, key[0..8]);
const h0 = mem.readIntBig(u64, key[8..16]); const h0 = mem.readIntBig(u64, key[8..16]);
const h1r = @bitReverse(u64, h1); const h1r = @bitReverse(h1);
const h0r = @bitReverse(u64, h0); const h0r = @bitReverse(h0);
const h2 = h0 ^ h1; const h2 = h0 ^ h1;
const h2r = h0r ^ h1r; const h2r = h0r ^ h1r;
@ -68,8 +68,8 @@ pub const Ghash = struct {
hh.update(key); hh.update(key);
const hh1 = hh.y1; const hh1 = hh.y1;
const hh0 = hh.y0; const hh0 = hh.y0;
const hh1r = @bitReverse(u64, hh1); const hh1r = @bitReverse(hh1);
const hh0r = @bitReverse(u64, hh0); const hh0r = @bitReverse(hh0);
const hh2 = hh0 ^ hh1; const hh2 = hh0 ^ hh1;
const hh2r = hh0r ^ hh1r; const hh2r = hh0r ^ hh1r;
@ -156,8 +156,8 @@ pub const Ghash = struct {
y1 ^= mem.readIntBig(u64, msg[i..][0..8]); y1 ^= mem.readIntBig(u64, msg[i..][0..8]);
y0 ^= mem.readIntBig(u64, msg[i..][8..16]); y0 ^= mem.readIntBig(u64, msg[i..][8..16]);
const y1r = @bitReverse(u64, y1); const y1r = @bitReverse(y1);
const y0r = @bitReverse(u64, y0); const y0r = @bitReverse(y0);
const y2 = y0 ^ y1; const y2 = y0 ^ y1;
const y2r = y0r ^ y1r; const y2r = y0r ^ y1r;
@ -172,8 +172,8 @@ pub const Ghash = struct {
const sy1 = mem.readIntBig(u64, msg[i..][16..24]); const sy1 = mem.readIntBig(u64, msg[i..][16..24]);
const sy0 = mem.readIntBig(u64, msg[i..][24..32]); const sy0 = mem.readIntBig(u64, msg[i..][24..32]);
const sy1r = @bitReverse(u64, sy1); const sy1r = @bitReverse(sy1);
const sy0r = @bitReverse(u64, sy0); const sy0r = @bitReverse(sy0);
const sy2 = sy0 ^ sy1; const sy2 = sy0 ^ sy1;
const sy2r = sy0r ^ sy1r; const sy2r = sy0r ^ sy1r;
@ -191,9 +191,9 @@ pub const Ghash = struct {
z0h ^= sz0h; z0h ^= sz0h;
z1h ^= sz1h; z1h ^= sz1h;
z2h ^= sz2h; z2h ^= sz2h;
z0h = @bitReverse(u64, z0h) >> 1; z0h = @bitReverse(z0h) >> 1;
z1h = @bitReverse(u64, z1h) >> 1; z1h = @bitReverse(z1h) >> 1;
z2h = @bitReverse(u64, z2h) >> 1; z2h = @bitReverse(z2h) >> 1;
var v3 = z1h; var v3 = z1h;
var v2 = z1 ^ z2h; var v2 = z1 ^ z2h;
@ -217,8 +217,8 @@ pub const Ghash = struct {
y1 ^= mem.readIntBig(u64, msg[i..][0..8]); y1 ^= mem.readIntBig(u64, msg[i..][0..8]);
y0 ^= mem.readIntBig(u64, msg[i..][8..16]); y0 ^= mem.readIntBig(u64, msg[i..][8..16]);
const y1r = @bitReverse(u64, y1); const y1r = @bitReverse(y1);
const y0r = @bitReverse(u64, y0); const y0r = @bitReverse(y0);
const y2 = y0 ^ y1; const y2 = y0 ^ y1;
const y2r = y0r ^ y1r; const y2r = y0r ^ y1r;
@ -228,9 +228,9 @@ pub const Ghash = struct {
var z0h = clmul(y0r, st.h0r); var z0h = clmul(y0r, st.h0r);
var z1h = clmul(y1r, st.h1r); var z1h = clmul(y1r, st.h1r);
var z2h = clmul(y2r, st.h2r) ^ z0h ^ z1h; var z2h = clmul(y2r, st.h2r) ^ z0h ^ z1h;
z0h = @bitReverse(u64, z0h) >> 1; z0h = @bitReverse(z0h) >> 1;
z1h = @bitReverse(u64, z1h) >> 1; z1h = @bitReverse(z1h) >> 1;
z2h = @bitReverse(u64, z2h) >> 1; z2h = @bitReverse(z2h) >> 1;
// shift & reduce // shift & reduce
var v3 = z1h; var v3 = z1h;

View File

@ -816,11 +816,11 @@ pub fn openSelfDebugInfo(allocator: mem.Allocator) anyerror!DebugInfo {
/// TODO it's weird to take ownership even on error, rework this code. /// TODO it's weird to take ownership even on error, rework this code.
fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo { fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo {
nosuspend { nosuspend {
errdefer coff_file.close(); defer coff_file.close();
const coff_obj = try allocator.create(coff.Coff); const coff_obj = try allocator.create(coff.Coff);
errdefer allocator.destroy(coff_obj); errdefer allocator.destroy(coff_obj);
coff_obj.* = coff.Coff.init(allocator, coff_file); coff_obj.* = .{ .allocator = allocator };
var di = ModuleDebugInfo{ var di = ModuleDebugInfo{
.base_address = undefined, .base_address = undefined,
@ -828,27 +828,42 @@ fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo
.debug_data = undefined, .debug_data = undefined,
}; };
try di.coff.loadHeader(); // TODO convert to Windows' memory-mapped file API
try di.coff.loadSections(); const file_len = math.cast(usize, try coff_file.getEndPos()) orelse math.maxInt(usize);
if (di.coff.getSection(".debug_info")) |sec| { const data = try coff_file.readToEndAlloc(allocator, file_len);
try di.coff.parse(data);
if (di.coff.getSectionByName(".debug_info")) |sec| {
// This coff file has embedded DWARF debug info // This coff file has embedded DWARF debug info
_ = sec; _ = sec;
// TODO: free the section data slices // TODO: free the section data slices
const debug_info_data = di.coff.getSectionData(".debug_info", allocator) catch null; const debug_info = di.coff.getSectionDataAlloc(".debug_info", allocator) catch null;
const debug_abbrev_data = di.coff.getSectionData(".debug_abbrev", allocator) catch null; const debug_abbrev = di.coff.getSectionDataAlloc(".debug_abbrev", allocator) catch null;
const debug_str_data = di.coff.getSectionData(".debug_str", allocator) catch null; const debug_str = di.coff.getSectionDataAlloc(".debug_str", allocator) catch null;
const debug_line_data = di.coff.getSectionData(".debug_line", allocator) catch null; const debug_str_offsets = di.coff.getSectionDataAlloc(".debug_str_offsets", allocator) catch null;
const debug_line_str_data = di.coff.getSectionData(".debug_line_str", allocator) catch null; const debug_line = di.coff.getSectionDataAlloc(".debug_line", allocator) catch null;
const debug_ranges_data = di.coff.getSectionData(".debug_ranges", allocator) catch null; const debug_line_str = di.coff.getSectionDataAlloc(".debug_line_str", allocator) catch null;
const debug_ranges = di.coff.getSectionDataAlloc(".debug_ranges", allocator) catch null;
const debug_loclists = di.coff.getSectionDataAlloc(".debug_loclists", allocator) catch null;
const debug_rnglists = di.coff.getSectionDataAlloc(".debug_rnglists", allocator) catch null;
const debug_addr = di.coff.getSectionDataAlloc(".debug_addr", allocator) catch null;
const debug_names = di.coff.getSectionDataAlloc(".debug_names", allocator) catch null;
const debug_frame = di.coff.getSectionDataAlloc(".debug_frame", allocator) catch null;
var dwarf = DW.DwarfInfo{ var dwarf = DW.DwarfInfo{
.endian = native_endian, .endian = native_endian,
.debug_info = debug_info_data orelse return error.MissingDebugInfo, .debug_info = debug_info orelse return error.MissingDebugInfo,
.debug_abbrev = debug_abbrev_data orelse return error.MissingDebugInfo, .debug_abbrev = debug_abbrev orelse return error.MissingDebugInfo,
.debug_str = debug_str_data orelse return error.MissingDebugInfo, .debug_str = debug_str orelse return error.MissingDebugInfo,
.debug_line = debug_line_data orelse return error.MissingDebugInfo, .debug_str_offsets = debug_str_offsets,
.debug_line_str = debug_line_str_data, .debug_line = debug_line orelse return error.MissingDebugInfo,
.debug_ranges = debug_ranges_data, .debug_line_str = debug_line_str,
.debug_ranges = debug_ranges,
.debug_loclists = debug_loclists,
.debug_rnglists = debug_rnglists,
.debug_addr = debug_addr,
.debug_names = debug_names,
.debug_frame = debug_frame,
}; };
try DW.openDwarfDebugInfo(&dwarf, allocator); try DW.openDwarfDebugInfo(&dwarf, allocator);
di.debug_data = PdbOrDwarf{ .dwarf = dwarf }; di.debug_data = PdbOrDwarf{ .dwarf = dwarf };
@ -863,7 +878,10 @@ fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo
defer allocator.free(path); defer allocator.free(path);
di.debug_data = PdbOrDwarf{ .pdb = undefined }; di.debug_data = PdbOrDwarf{ .pdb = undefined };
di.debug_data.pdb = try pdb.Pdb.init(allocator, path); di.debug_data.pdb = pdb.Pdb.init(allocator, path) catch |err| switch (err) {
error.FileNotFound, error.IsDir => return error.MissingDebugInfo,
else => return err,
};
try di.debug_data.pdb.parseInfoStream(); try di.debug_data.pdb.parseInfoStream();
try di.debug_data.pdb.parseDbiStream(); try di.debug_data.pdb.parseDbiStream();
@ -912,9 +930,15 @@ pub fn readElfDebugInfo(allocator: mem.Allocator, elf_file: File) !ModuleDebugIn
var opt_debug_info: ?[]const u8 = null; var opt_debug_info: ?[]const u8 = null;
var opt_debug_abbrev: ?[]const u8 = null; var opt_debug_abbrev: ?[]const u8 = null;
var opt_debug_str: ?[]const u8 = null; var opt_debug_str: ?[]const u8 = null;
var opt_debug_str_offsets: ?[]const u8 = null;
var opt_debug_line: ?[]const u8 = null; var opt_debug_line: ?[]const u8 = null;
var opt_debug_line_str: ?[]const u8 = null; var opt_debug_line_str: ?[]const u8 = null;
var opt_debug_ranges: ?[]const u8 = null; var opt_debug_ranges: ?[]const u8 = null;
var opt_debug_loclists: ?[]const u8 = null;
var opt_debug_rnglists: ?[]const u8 = null;
var opt_debug_addr: ?[]const u8 = null;
var opt_debug_names: ?[]const u8 = null;
var opt_debug_frame: ?[]const u8 = null;
for (shdrs) |*shdr| { for (shdrs) |*shdr| {
if (shdr.sh_type == elf.SHT_NULL) continue; if (shdr.sh_type == elf.SHT_NULL) continue;
@ -926,12 +950,24 @@ pub fn readElfDebugInfo(allocator: mem.Allocator, elf_file: File) !ModuleDebugIn
opt_debug_abbrev = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size); opt_debug_abbrev = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
} else if (mem.eql(u8, name, ".debug_str")) { } else if (mem.eql(u8, name, ".debug_str")) {
opt_debug_str = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size); opt_debug_str = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
} else if (mem.eql(u8, name, ".debug_str_offsets")) {
opt_debug_str_offsets = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
} else if (mem.eql(u8, name, ".debug_line")) { } else if (mem.eql(u8, name, ".debug_line")) {
opt_debug_line = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size); opt_debug_line = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
} else if (mem.eql(u8, name, ".debug_line_str")) { } else if (mem.eql(u8, name, ".debug_line_str")) {
opt_debug_line_str = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size); opt_debug_line_str = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
} else if (mem.eql(u8, name, ".debug_ranges")) { } else if (mem.eql(u8, name, ".debug_ranges")) {
opt_debug_ranges = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size); opt_debug_ranges = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
} else if (mem.eql(u8, name, ".debug_loclists")) {
opt_debug_loclists = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
} else if (mem.eql(u8, name, ".debug_rnglists")) {
opt_debug_rnglists = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
} else if (mem.eql(u8, name, ".debug_addr")) {
opt_debug_addr = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
} else if (mem.eql(u8, name, ".debug_names")) {
opt_debug_names = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
} else if (mem.eql(u8, name, ".debug_frame")) {
opt_debug_frame = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
} }
} }
@ -940,9 +976,15 @@ pub fn readElfDebugInfo(allocator: mem.Allocator, elf_file: File) !ModuleDebugIn
.debug_info = opt_debug_info orelse return error.MissingDebugInfo, .debug_info = opt_debug_info orelse return error.MissingDebugInfo,
.debug_abbrev = opt_debug_abbrev orelse return error.MissingDebugInfo, .debug_abbrev = opt_debug_abbrev orelse return error.MissingDebugInfo,
.debug_str = opt_debug_str orelse return error.MissingDebugInfo, .debug_str = opt_debug_str orelse return error.MissingDebugInfo,
.debug_str_offsets = opt_debug_str_offsets,
.debug_line = opt_debug_line orelse return error.MissingDebugInfo, .debug_line = opt_debug_line orelse return error.MissingDebugInfo,
.debug_line_str = opt_debug_line_str, .debug_line_str = opt_debug_line_str,
.debug_ranges = opt_debug_ranges, .debug_ranges = opt_debug_ranges,
.debug_loclists = opt_debug_loclists,
.debug_rnglists = opt_debug_rnglists,
.debug_addr = opt_debug_addr,
.debug_names = opt_debug_names,
.debug_frame = opt_debug_frame,
}; };
try DW.openDwarfDebugInfo(&di, allocator); try DW.openDwarfDebugInfo(&di, allocator);
@ -968,24 +1010,20 @@ fn readMachODebugInfo(allocator: mem.Allocator, macho_file: File) !ModuleDebugIn
if (hdr.magic != macho.MH_MAGIC_64) if (hdr.magic != macho.MH_MAGIC_64)
return error.InvalidDebugInfo; return error.InvalidDebugInfo;
const hdr_base = @ptrCast([*]const u8, hdr); var it = macho.LoadCommandIterator{
var ptr = hdr_base + @sizeOf(macho.mach_header_64); .ncmds = hdr.ncmds,
var ncmd: u32 = hdr.ncmds; .buffer = mapped_mem[@sizeOf(macho.mach_header_64)..][0..hdr.sizeofcmds],
const symtab = while (ncmd != 0) : (ncmd -= 1) {
const lc = @ptrCast(*const std.macho.load_command, ptr);
switch (lc.cmd) {
.SYMTAB => break @ptrCast(*const std.macho.symtab_command, ptr),
else => {},
}
ptr = @alignCast(@alignOf(std.macho.load_command), ptr + lc.cmdsize);
} else {
return error.MissingDebugInfo;
}; };
const symtab = while (it.next()) |cmd| switch (cmd.cmd()) {
.SYMTAB => break cmd.cast(macho.symtab_command).?,
else => {},
} else return error.MissingDebugInfo;
const syms = @ptrCast( const syms = @ptrCast(
[*]const macho.nlist_64, [*]const macho.nlist_64,
@alignCast(@alignOf(macho.nlist_64), hdr_base + symtab.symoff), @alignCast(@alignOf(macho.nlist_64), &mapped_mem[symtab.symoff]),
)[0..symtab.nsyms]; )[0..symtab.nsyms];
const strings = @ptrCast([*]const u8, hdr_base + symtab.stroff)[0 .. symtab.strsize - 1 :0]; const strings = mapped_mem[symtab.stroff..][0 .. symtab.strsize - 1 :0];
const symbols_buf = try allocator.alloc(MachoSymbol, syms.len); const symbols_buf = try allocator.alloc(MachoSymbol, syms.len);
@ -1200,48 +1238,46 @@ pub const DebugInfo = struct {
if (address < base_address) continue; if (address < base_address) continue;
const header = std.c._dyld_get_image_header(i) orelse continue; const header = std.c._dyld_get_image_header(i) orelse continue;
// The array of load commands is right after the header
var cmd_ptr = @intToPtr([*]u8, @ptrToInt(header) + @sizeOf(macho.mach_header_64));
var cmds = header.ncmds; var it = macho.LoadCommandIterator{
while (cmds != 0) : (cmds -= 1) { .ncmds = header.ncmds,
const lc = @ptrCast( .buffer = @alignCast(@alignOf(u64), @intToPtr(
*macho.load_command, [*]u8,
@alignCast(@alignOf(macho.load_command), cmd_ptr), @ptrToInt(header) + @sizeOf(macho.mach_header_64),
); ))[0..header.sizeofcmds],
cmd_ptr += lc.cmdsize; };
if (lc.cmd != .SEGMENT_64) continue; while (it.next()) |cmd| switch (cmd.cmd()) {
.SEGMENT_64 => {
const segment_cmd = cmd.cast(macho.segment_command_64).?;
const rebased_address = address - base_address;
const seg_start = segment_cmd.vmaddr;
const seg_end = seg_start + segment_cmd.vmsize;
const segment_cmd = @ptrCast( if (rebased_address >= seg_start and rebased_address < seg_end) {
*const std.macho.segment_command_64, if (self.address_map.get(base_address)) |obj_di| {
@alignCast(@alignOf(std.macho.segment_command_64), lc), return obj_di;
); }
const rebased_address = address - base_address; const obj_di = try self.allocator.create(ModuleDebugInfo);
const seg_start = segment_cmd.vmaddr; errdefer self.allocator.destroy(obj_di);
const seg_end = seg_start + segment_cmd.vmsize;
const macho_path = mem.sliceTo(std.c._dyld_get_image_name(i), 0);
const macho_file = fs.cwd().openFile(macho_path, .{
.intended_io_mode = .blocking,
}) catch |err| switch (err) {
error.FileNotFound => return error.MissingDebugInfo,
else => return err,
};
obj_di.* = try readMachODebugInfo(self.allocator, macho_file);
obj_di.base_address = base_address;
try self.address_map.putNoClobber(base_address, obj_di);
if (rebased_address >= seg_start and rebased_address < seg_end) {
if (self.address_map.get(base_address)) |obj_di| {
return obj_di; return obj_di;
} }
},
const obj_di = try self.allocator.create(ModuleDebugInfo); else => {},
errdefer self.allocator.destroy(obj_di); };
const macho_path = mem.sliceTo(std.c._dyld_get_image_name(i), 0);
const macho_file = fs.cwd().openFile(macho_path, .{ .intended_io_mode = .blocking }) catch |err| switch (err) {
error.FileNotFound => return error.MissingDebugInfo,
else => return err,
};
obj_di.* = try readMachODebugInfo(self.allocator, macho_file);
obj_di.base_address = base_address;
try self.address_map.putNoClobber(base_address, obj_di);
return obj_di;
}
}
} }
return error.MissingDebugInfo; return error.MissingDebugInfo;
@ -1445,44 +1481,31 @@ pub const ModuleDebugInfo = switch (native_os) {
if (hdr.magic != std.macho.MH_MAGIC_64) if (hdr.magic != std.macho.MH_MAGIC_64)
return error.InvalidDebugInfo; return error.InvalidDebugInfo;
const hdr_base = @ptrCast([*]const u8, hdr); var segcmd: ?macho.LoadCommandIterator.LoadCommand = null;
var ptr = hdr_base + @sizeOf(macho.mach_header_64); var symtabcmd: ?macho.symtab_command = null;
var segptr = ptr; var it = macho.LoadCommandIterator{
var ncmd: u32 = hdr.ncmds; .ncmds = hdr.ncmds,
var segcmd: ?*const macho.segment_command_64 = null; .buffer = mapped_mem[@sizeOf(macho.mach_header_64)..][0..hdr.sizeofcmds],
var symtabcmd: ?*const macho.symtab_command = null; };
while (it.next()) |cmd| switch (cmd.cmd()) {
while (ncmd != 0) : (ncmd -= 1) { .SEGMENT_64 => segcmd = cmd,
const lc = @ptrCast(*const std.macho.load_command, ptr); .SYMTAB => symtabcmd = cmd.cast(macho.symtab_command).?,
switch (lc.cmd) { else => {},
.SEGMENT_64 => { };
segcmd = @ptrCast(
*const std.macho.segment_command_64,
@alignCast(@alignOf(std.macho.segment_command_64), ptr),
);
segptr = ptr;
},
.SYMTAB => {
symtabcmd = @ptrCast(
*const std.macho.symtab_command,
@alignCast(@alignOf(std.macho.symtab_command), ptr),
);
},
else => {},
}
ptr = @alignCast(@alignOf(std.macho.load_command), ptr + lc.cmdsize);
}
if (segcmd == null or symtabcmd == null) return error.MissingDebugInfo; if (segcmd == null or symtabcmd == null) return error.MissingDebugInfo;
// Parse symbols // Parse symbols
const strtab = @ptrCast( const strtab = @ptrCast(
[*]const u8, [*]const u8,
hdr_base + symtabcmd.?.stroff, &mapped_mem[symtabcmd.?.stroff],
)[0 .. symtabcmd.?.strsize - 1 :0]; )[0 .. symtabcmd.?.strsize - 1 :0];
const symtab = @ptrCast( const symtab = @ptrCast(
[*]const macho.nlist_64, [*]const macho.nlist_64,
@alignCast(@alignOf(macho.nlist_64), hdr_base + symtabcmd.?.symoff), @alignCast(
@alignOf(macho.nlist_64),
&mapped_mem[symtabcmd.?.symoff],
),
)[0..symtabcmd.?.nsyms]; )[0..symtabcmd.?.nsyms];
// TODO handle tentative (common) symbols // TODO handle tentative (common) symbols
@ -1496,25 +1519,21 @@ pub const ModuleDebugInfo = switch (native_os) {
addr_table.putAssumeCapacityNoClobber(sym_name, sym.n_value); addr_table.putAssumeCapacityNoClobber(sym_name, sym.n_value);
} }
var opt_debug_line: ?*const macho.section_64 = null; var opt_debug_line: ?macho.section_64 = null;
var opt_debug_info: ?*const macho.section_64 = null; var opt_debug_info: ?macho.section_64 = null;
var opt_debug_abbrev: ?*const macho.section_64 = null; var opt_debug_abbrev: ?macho.section_64 = null;
var opt_debug_str: ?*const macho.section_64 = null; var opt_debug_str: ?macho.section_64 = null;
var opt_debug_line_str: ?*const macho.section_64 = null; var opt_debug_str_offsets: ?macho.section_64 = null;
var opt_debug_ranges: ?*const macho.section_64 = null; var opt_debug_line_str: ?macho.section_64 = null;
var opt_debug_ranges: ?macho.section_64 = null;
const sections = @ptrCast( var opt_debug_loclists: ?macho.section_64 = null;
[*]const macho.section_64, var opt_debug_rnglists: ?macho.section_64 = null;
@alignCast(@alignOf(macho.section_64), segptr + @sizeOf(std.macho.segment_command_64)), var opt_debug_addr: ?macho.section_64 = null;
)[0..segcmd.?.nsects]; var opt_debug_names: ?macho.section_64 = null;
for (sections) |*sect| { var opt_debug_frame: ?macho.section_64 = null;
// The section name may not exceed 16 chars and a trailing null may
// not be present
const name = if (mem.indexOfScalar(u8, sect.sectname[0..], 0)) |last|
sect.sectname[0..last]
else
sect.sectname[0..];
for (segcmd.?.getSections()) |sect| {
const name = sect.sectName();
if (mem.eql(u8, name, "__debug_line")) { if (mem.eql(u8, name, "__debug_line")) {
opt_debug_line = sect; opt_debug_line = sect;
} else if (mem.eql(u8, name, "__debug_info")) { } else if (mem.eql(u8, name, "__debug_info")) {
@ -1523,10 +1542,22 @@ pub const ModuleDebugInfo = switch (native_os) {
opt_debug_abbrev = sect; opt_debug_abbrev = sect;
} else if (mem.eql(u8, name, "__debug_str")) { } else if (mem.eql(u8, name, "__debug_str")) {
opt_debug_str = sect; opt_debug_str = sect;
} else if (mem.eql(u8, name, "__debug_str_offsets")) {
opt_debug_str_offsets = sect;
} else if (mem.eql(u8, name, "__debug_line_str")) { } else if (mem.eql(u8, name, "__debug_line_str")) {
opt_debug_line_str = sect; opt_debug_line_str = sect;
} else if (mem.eql(u8, name, "__debug_ranges")) { } else if (mem.eql(u8, name, "__debug_ranges")) {
opt_debug_ranges = sect; opt_debug_ranges = sect;
} else if (mem.eql(u8, name, "__debug_loclists")) {
opt_debug_loclists = sect;
} else if (mem.eql(u8, name, "__debug_rnglists")) {
opt_debug_rnglists = sect;
} else if (mem.eql(u8, name, "__debug_addr")) {
opt_debug_addr = sect;
} else if (mem.eql(u8, name, "__debug_names")) {
opt_debug_names = sect;
} else if (mem.eql(u8, name, "__debug_frame")) {
opt_debug_frame = sect;
} }
} }
@ -1544,6 +1575,10 @@ pub const ModuleDebugInfo = switch (native_os) {
.debug_info = try chopSlice(mapped_mem, debug_info.offset, debug_info.size), .debug_info = try chopSlice(mapped_mem, debug_info.offset, debug_info.size),
.debug_abbrev = try chopSlice(mapped_mem, debug_abbrev.offset, debug_abbrev.size), .debug_abbrev = try chopSlice(mapped_mem, debug_abbrev.offset, debug_abbrev.size),
.debug_str = try chopSlice(mapped_mem, debug_str.offset, debug_str.size), .debug_str = try chopSlice(mapped_mem, debug_str.offset, debug_str.size),
.debug_str_offsets = if (opt_debug_str_offsets) |debug_str_offsets|
try chopSlice(mapped_mem, debug_str_offsets.offset, debug_str_offsets.size)
else
null,
.debug_line = try chopSlice(mapped_mem, debug_line.offset, debug_line.size), .debug_line = try chopSlice(mapped_mem, debug_line.offset, debug_line.size),
.debug_line_str = if (opt_debug_line_str) |debug_line_str| .debug_line_str = if (opt_debug_line_str) |debug_line_str|
try chopSlice(mapped_mem, debug_line_str.offset, debug_line_str.size) try chopSlice(mapped_mem, debug_line_str.offset, debug_line_str.size)
@ -1553,6 +1588,26 @@ pub const ModuleDebugInfo = switch (native_os) {
try chopSlice(mapped_mem, debug_ranges.offset, debug_ranges.size) try chopSlice(mapped_mem, debug_ranges.offset, debug_ranges.size)
else else
null, null,
.debug_loclists = if (opt_debug_loclists) |debug_loclists|
try chopSlice(mapped_mem, debug_loclists.offset, debug_loclists.size)
else
null,
.debug_rnglists = if (opt_debug_rnglists) |debug_rnglists|
try chopSlice(mapped_mem, debug_rnglists.offset, debug_rnglists.size)
else
null,
.debug_addr = if (opt_debug_addr) |debug_addr|
try chopSlice(mapped_mem, debug_addr.offset, debug_addr.size)
else
null,
.debug_names = if (opt_debug_names) |debug_names|
try chopSlice(mapped_mem, debug_names.offset, debug_names.size)
else
null,
.debug_frame = if (opt_debug_frame) |debug_frame|
try chopSlice(mapped_mem, debug_frame.offset, debug_frame.size)
else
null,
}; };
try DW.openDwarfDebugInfo(&di, allocator); try DW.openDwarfDebugInfo(&di, allocator);
@ -1607,6 +1662,8 @@ pub const ModuleDebugInfo = switch (native_os) {
.compile_unit_name = compile_unit.die.getAttrString( .compile_unit_name = compile_unit.die.getAttrString(
o_file_di, o_file_di,
DW.AT.name, DW.AT.name,
o_file_di.debug_str,
compile_unit.*,
) catch |err| switch (err) { ) catch |err| switch (err) {
error.MissingDebugInfo, error.InvalidDebugInfo => "???", error.MissingDebugInfo, error.InvalidDebugInfo => "???",
}, },
@ -1647,7 +1704,7 @@ pub const ModuleDebugInfo = switch (native_os) {
switch (self.debug_data) { switch (self.debug_data) {
.dwarf => |*dwarf| { .dwarf => |*dwarf| {
const dwarf_address = relocated_address + self.coff.pe_header.image_base; const dwarf_address = relocated_address + self.coff.getImageBase();
return getSymbolFromDwarf(allocator, dwarf_address, dwarf); return getSymbolFromDwarf(allocator, dwarf_address, dwarf);
}, },
.pdb => { .pdb => {
@ -1655,13 +1712,14 @@ pub const ModuleDebugInfo = switch (native_os) {
}, },
} }
var coff_section: *coff.Section = undefined; var coff_section: *align(1) const coff.SectionHeader = undefined;
const mod_index = for (self.debug_data.pdb.sect_contribs) |sect_contrib| { const mod_index = for (self.debug_data.pdb.sect_contribs) |sect_contrib| {
if (sect_contrib.Section > self.coff.sections.items.len) continue; const sections = self.coff.getSectionHeaders();
if (sect_contrib.Section > sections.len) continue;
// Remember that SectionContribEntry.Section is 1-based. // Remember that SectionContribEntry.Section is 1-based.
coff_section = &self.coff.sections.items[sect_contrib.Section - 1]; coff_section = &sections[sect_contrib.Section - 1];
const vaddr_start = coff_section.header.virtual_address + sect_contrib.Offset; const vaddr_start = coff_section.virtual_address + sect_contrib.Offset;
const vaddr_end = vaddr_start + sect_contrib.Size; const vaddr_end = vaddr_start + sect_contrib.Size;
if (relocated_address >= vaddr_start and relocated_address < vaddr_end) { if (relocated_address >= vaddr_start and relocated_address < vaddr_end) {
break sect_contrib.ModuleIndex; break sect_contrib.ModuleIndex;
@ -1677,11 +1735,11 @@ pub const ModuleDebugInfo = switch (native_os) {
const symbol_name = self.debug_data.pdb.getSymbolName( const symbol_name = self.debug_data.pdb.getSymbolName(
module, module,
relocated_address - coff_section.header.virtual_address, relocated_address - coff_section.virtual_address,
) orelse "???"; ) orelse "???";
const opt_line_info = try self.debug_data.pdb.getLineNumberInfo( const opt_line_info = try self.debug_data.pdb.getLineNumberInfo(
module, module,
relocated_address - coff_section.header.virtual_address, relocated_address - coff_section.virtual_address,
); );
return SymbolInfo{ return SymbolInfo{
@ -1727,7 +1785,7 @@ fn getSymbolFromDwarf(allocator: mem.Allocator, address: u64, di: *DW.DwarfInfo)
if (nosuspend di.findCompileUnit(address)) |compile_unit| { if (nosuspend di.findCompileUnit(address)) |compile_unit| {
return SymbolInfo{ return SymbolInfo{
.symbol_name = nosuspend di.getSymbolName(address) orelse "???", .symbol_name = nosuspend di.getSymbolName(address) orelse "???",
.compile_unit_name = compile_unit.die.getAttrString(di, DW.AT.name) catch |err| switch (err) { .compile_unit_name = compile_unit.die.getAttrString(di, DW.AT.name, di.debug_str, compile_unit.*) catch |err| switch (err) {
error.MissingDebugInfo, error.InvalidDebugInfo => "???", error.MissingDebugInfo, error.InvalidDebugInfo => "???",
}, },
.line_info = nosuspend di.getLineNumberInfo(allocator, compile_unit.*, address) catch |err| switch (err) { .line_info = nosuspend di.getLineNumberInfo(allocator, compile_unit.*, address) catch |err| switch (err) {
@ -1816,7 +1874,7 @@ fn resetSegfaultHandler() void {
return; return;
} }
var act = os.Sigaction{ var act = os.Sigaction{
.handler = .{ .sigaction = os.SIG.DFL }, .handler = .{ .handler = os.SIG.DFL },
.mask = os.empty_sigset, .mask = os.empty_sigset,
.flags = 0, .flags = 0,
}; };
@ -1976,7 +2034,7 @@ noinline fn showMyTrace() usize {
/// For more advanced usage, see `ConfigurableTrace`. /// For more advanced usage, see `ConfigurableTrace`.
pub const Trace = ConfigurableTrace(2, 4, builtin.mode == .Debug); pub const Trace = ConfigurableTrace(2, 4, builtin.mode == .Debug);
pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize, comptime enabled: bool) type { pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize, comptime is_enabled: bool) type {
return struct { return struct {
addrs: [actual_size][stack_frame_count]usize = undefined, addrs: [actual_size][stack_frame_count]usize = undefined,
notes: [actual_size][]const u8 = undefined, notes: [actual_size][]const u8 = undefined,
@ -1985,7 +2043,7 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize
const actual_size = if (enabled) size else 0; const actual_size = if (enabled) size else 0;
const Index = if (enabled) usize else u0; const Index = if (enabled) usize else u0;
pub const enabled = enabled; pub const enabled = is_enabled;
pub const add = if (enabled) addNoInline else addNoOp; pub const add = if (enabled) addNoInline else addNoOp;

View File

@ -168,6 +168,11 @@ const CompileUnit = struct {
is_64: bool, is_64: bool,
die: *Die, die: *Die,
pc_range: ?PcRange, pc_range: ?PcRange,
str_offsets_base: usize,
addr_base: usize,
rnglists_base: usize,
loclists_base: usize,
}; };
const AbbrevTable = std.ArrayList(AbbrevTableEntry); const AbbrevTable = std.ArrayList(AbbrevTableEntry);
@ -205,6 +210,7 @@ const AbbrevAttr = struct {
const FormValue = union(enum) { const FormValue = union(enum) {
Address: u64, Address: u64,
AddrOffset: usize,
Block: []u8, Block: []u8,
Const: Constant, Const: Constant,
ExprLoc: []u8, ExprLoc: []u8,
@ -214,15 +220,46 @@ const FormValue = union(enum) {
RefAddr: u64, RefAddr: u64,
String: []const u8, String: []const u8,
StrPtr: u64, StrPtr: u64,
StrOffset: usize,
LineStrPtr: u64, LineStrPtr: u64,
LocListOffset: u64,
RangeListOffset: u64,
data16: [16]u8,
fn getString(fv: FormValue, di: DwarfInfo) ![]const u8 {
switch (fv) {
.String => |s| return s,
.StrPtr => |off| return di.getString(off),
.LineStrPtr => |off| return di.getLineString(off),
else => return badDwarf(),
}
}
fn getUInt(fv: FormValue, comptime U: type) !U {
switch (fv) {
.Const => |c| {
const int = try c.asUnsignedLe();
return math.cast(U, int) orelse return badDwarf();
},
.SecOffset => |x| return math.cast(U, x) orelse return badDwarf(),
else => return badDwarf(),
}
}
fn getData16(fv: FormValue) ![16]u8 {
switch (fv) {
.data16 => |d| return d,
else => return badDwarf(),
}
}
}; };
const Constant = struct { const Constant = struct {
payload: u64, payload: u64,
signed: bool, signed: bool,
fn asUnsignedLe(self: *const Constant) !u64 { fn asUnsignedLe(self: Constant) !u64 {
if (self.signed) return error.InvalidDebugInfo; if (self.signed) return badDwarf();
return self.payload; return self.payload;
} }
}; };
@ -251,21 +288,46 @@ const Die = struct {
return null; return null;
} }
fn getAttrAddr(self: *const Die, id: u64) !u64 { fn getAttrAddr(
self: *const Die,
di: *DwarfInfo,
id: u64,
compile_unit: CompileUnit,
) error{ InvalidDebugInfo, MissingDebugInfo }!u64 {
const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
return switch (form_value.*) { return switch (form_value.*) {
FormValue.Address => |value| value, FormValue.Address => |value| value,
FormValue.AddrOffset => |index| {
const debug_addr = di.debug_addr orelse return badDwarf();
// addr_base points to the first item after the header, however we
// need to read the header to know the size of each item. Empirically,
// it may disagree with is_64 on the compile unit.
// The header is 8 or 12 bytes depending on is_64.
if (compile_unit.addr_base < 8) return badDwarf();
const version = mem.readInt(u16, debug_addr[compile_unit.addr_base - 4 ..][0..2], di.endian);
if (version != 5) return badDwarf();
const addr_size = debug_addr[compile_unit.addr_base - 2];
const seg_size = debug_addr[compile_unit.addr_base - 1];
const byte_offset = compile_unit.addr_base + (addr_size + seg_size) * index;
if (byte_offset + addr_size > debug_addr.len) return badDwarf();
switch (addr_size) {
1 => return debug_addr[byte_offset],
2 => return mem.readInt(u16, debug_addr[byte_offset..][0..2], di.endian),
4 => return mem.readInt(u32, debug_addr[byte_offset..][0..4], di.endian),
8 => return mem.readInt(u64, debug_addr[byte_offset..][0..8], di.endian),
else => return badDwarf(),
}
},
else => error.InvalidDebugInfo, else => error.InvalidDebugInfo,
}; };
} }
fn getAttrSecOffset(self: *const Die, id: u64) !u64 { fn getAttrSecOffset(self: *const Die, id: u64) !u64 {
const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
return switch (form_value.*) { return form_value.getUInt(u64);
FormValue.Const => |value| value.asUnsignedLe(),
FormValue.SecOffset => |value| value,
else => error.InvalidDebugInfo,
};
} }
fn getAttrUnsignedLe(self: *const Die, id: u64) !u64 { fn getAttrUnsignedLe(self: *const Die, id: u64) !u64 {
@ -284,22 +346,44 @@ const Die = struct {
}; };
} }
pub fn getAttrString(self: *const Die, di: *DwarfInfo, id: u64) ![]const u8 { pub fn getAttrString(
self: *const Die,
di: *DwarfInfo,
id: u64,
opt_str: ?[]const u8,
compile_unit: CompileUnit,
) error{ InvalidDebugInfo, MissingDebugInfo }![]const u8 {
const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
return switch (form_value.*) { switch (form_value.*) {
FormValue.String => |value| value, FormValue.String => |value| return value,
FormValue.StrPtr => |offset| di.getString(offset), FormValue.StrPtr => |offset| return di.getString(offset),
FormValue.LineStrPtr => |offset| di.getLineString(offset), FormValue.StrOffset => |index| {
else => error.InvalidDebugInfo, const debug_str_offsets = di.debug_str_offsets orelse return badDwarf();
}; if (compile_unit.str_offsets_base == 0) return badDwarf();
if (compile_unit.is_64) {
const byte_offset = compile_unit.str_offsets_base + 8 * index;
if (byte_offset + 8 > debug_str_offsets.len) return badDwarf();
const offset = mem.readInt(u64, debug_str_offsets[byte_offset..][0..8], di.endian);
return getStringGeneric(opt_str, offset);
} else {
const byte_offset = compile_unit.str_offsets_base + 4 * index;
if (byte_offset + 4 > debug_str_offsets.len) return badDwarf();
const offset = mem.readInt(u32, debug_str_offsets[byte_offset..][0..4], di.endian);
return getStringGeneric(opt_str, offset);
}
},
FormValue.LineStrPtr => |offset| return di.getLineString(offset),
else => return badDwarf(),
}
} }
}; };
const FileEntry = struct { const FileEntry = struct {
file_name: []const u8, path: []const u8,
dir_index: usize, dir_index: u32 = 0,
mtime: usize, mtime: u64 = 0,
len_bytes: usize, size: u64 = 0,
md5: [16]u8 = [1]u8{0} ** 16,
}; };
const LineNumberProgram = struct { const LineNumberProgram = struct {
@ -307,13 +391,14 @@ const LineNumberProgram = struct {
file: usize, file: usize,
line: i64, line: i64,
column: u64, column: u64,
version: u16,
is_stmt: bool, is_stmt: bool,
basic_block: bool, basic_block: bool,
end_sequence: bool, end_sequence: bool,
default_is_stmt: bool, default_is_stmt: bool,
target_address: u64, target_address: u64,
include_dirs: []const []const u8, include_dirs: []const FileEntry,
prev_valid: bool, prev_valid: bool,
prev_address: u64, prev_address: u64,
@ -344,12 +429,18 @@ const LineNumberProgram = struct {
self.prev_end_sequence = undefined; self.prev_end_sequence = undefined;
} }
pub fn init(is_stmt: bool, include_dirs: []const []const u8, target_address: u64) LineNumberProgram { pub fn init(
is_stmt: bool,
include_dirs: []const FileEntry,
target_address: u64,
version: u16,
) LineNumberProgram {
return LineNumberProgram{ return LineNumberProgram{
.address = 0, .address = 0,
.file = 1, .file = 1,
.line = 1, .line = 1,
.column = 0, .column = 0,
.version = version,
.is_stmt = is_stmt, .is_stmt = is_stmt,
.basic_block = false, .basic_block = false,
.end_sequence = false, .end_sequence = false,
@ -372,18 +463,24 @@ const LineNumberProgram = struct {
allocator: mem.Allocator, allocator: mem.Allocator,
file_entries: []const FileEntry, file_entries: []const FileEntry,
) !?debug.LineInfo { ) !?debug.LineInfo {
if (self.prev_valid and self.target_address >= self.prev_address and self.target_address < self.address) { if (self.prev_valid and
const file_entry = if (self.prev_file == 0) { self.target_address >= self.prev_address and
return error.MissingDebugInfo; self.target_address < self.address)
} else if (self.prev_file - 1 >= file_entries.len) { {
return error.InvalidDebugInfo; const file_index = if (self.version >= 5) self.prev_file else i: {
} else &file_entries[self.prev_file - 1]; if (self.prev_file == 0) return missingDwarf();
break :i self.prev_file - 1;
};
const dir_name = if (file_entry.dir_index >= self.include_dirs.len) { if (file_index >= file_entries.len) return badDwarf();
return error.InvalidDebugInfo; const file_entry = &file_entries[file_index];
} else self.include_dirs[file_entry.dir_index];
const file_name = try fs.path.join(allocator, &[_][]const u8{ dir_name, file_entry.file_name }); if (file_entry.dir_index >= self.include_dirs.len) return badDwarf();
const dir_name = self.include_dirs[file_entry.dir_index].path;
const file_name = try fs.path.join(allocator, &[_][]const u8{
dir_name, file_entry.path,
});
return debug.LineInfo{ return debug.LineInfo{
.line = if (self.prev_line >= 0) @intCast(u64, self.prev_line) else 0, .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)
if (is_64.*) { if (is_64.*) {
return in_stream.readInt(u64, endian); return in_stream.readInt(u64, endian);
} else { } else {
if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo; if (first_32_bits >= 0xfffffff0) return badDwarf();
// TODO this cast should not be needed // TODO this cast should not be needed
return @as(u64, first_32_bits); return @as(u64, first_32_bits);
} }
@ -487,6 +584,12 @@ fn parseFormValueRef(in_stream: anytype, endian: std.builtin.Endian, size: i32)
fn parseFormValue(allocator: mem.Allocator, in_stream: anytype, form_id: u64, endian: std.builtin.Endian, is_64: bool) anyerror!FormValue { fn parseFormValue(allocator: mem.Allocator, in_stream: anytype, form_id: u64, endian: std.builtin.Endian, is_64: bool) anyerror!FormValue {
return switch (form_id) { return switch (form_id) {
FORM.addr => FormValue{ .Address = try readAddress(in_stream, endian, @sizeOf(usize) == 8) }, FORM.addr => FormValue{ .Address = try readAddress(in_stream, endian, @sizeOf(usize) == 8) },
FORM.addrx1 => return FormValue{ .AddrOffset = try in_stream.readInt(u8, endian) },
FORM.addrx2 => return FormValue{ .AddrOffset = try in_stream.readInt(u16, endian) },
FORM.addrx3 => return FormValue{ .AddrOffset = try in_stream.readInt(u24, endian) },
FORM.addrx4 => return FormValue{ .AddrOffset = try in_stream.readInt(u32, endian) },
FORM.addrx => return FormValue{ .AddrOffset = try nosuspend leb.readULEB128(usize, in_stream) },
FORM.block1 => parseFormValueBlock(allocator, in_stream, endian, 1), FORM.block1 => parseFormValueBlock(allocator, in_stream, endian, 1),
FORM.block2 => parseFormValueBlock(allocator, in_stream, endian, 2), FORM.block2 => parseFormValueBlock(allocator, in_stream, endian, 2),
FORM.block4 => parseFormValueBlock(allocator, in_stream, endian, 4), FORM.block4 => parseFormValueBlock(allocator, in_stream, endian, 4),
@ -498,6 +601,11 @@ fn parseFormValue(allocator: mem.Allocator, in_stream: anytype, form_id: u64, en
FORM.data2 => parseFormValueConstant(in_stream, false, endian, 2), FORM.data2 => parseFormValueConstant(in_stream, false, endian, 2),
FORM.data4 => parseFormValueConstant(in_stream, false, endian, 4), FORM.data4 => parseFormValueConstant(in_stream, false, endian, 4),
FORM.data8 => parseFormValueConstant(in_stream, false, endian, 8), FORM.data8 => parseFormValueConstant(in_stream, false, endian, 8),
FORM.data16 => {
var buf: [16]u8 = undefined;
if ((try nosuspend in_stream.readAll(&buf)) < 16) return error.EndOfFile;
return FormValue{ .data16 = buf };
},
FORM.udata, FORM.sdata => { FORM.udata, FORM.sdata => {
const signed = form_id == FORM.sdata; const signed = form_id == FORM.sdata;
return parseFormValueConstant(in_stream, signed, endian, -1); return parseFormValueConstant(in_stream, signed, endian, -1);
@ -522,6 +630,11 @@ fn parseFormValue(allocator: mem.Allocator, in_stream: anytype, form_id: u64, en
FORM.string => FormValue{ .String = try in_stream.readUntilDelimiterAlloc(allocator, 0, math.maxInt(usize)) }, FORM.string => FormValue{ .String = try in_stream.readUntilDelimiterAlloc(allocator, 0, math.maxInt(usize)) },
FORM.strp => FormValue{ .StrPtr = try readAddress(in_stream, endian, is_64) }, FORM.strp => FormValue{ .StrPtr = try readAddress(in_stream, endian, is_64) },
FORM.strx1 => return FormValue{ .StrOffset = try in_stream.readInt(u8, endian) },
FORM.strx2 => return FormValue{ .StrOffset = try in_stream.readInt(u16, endian) },
FORM.strx3 => return FormValue{ .StrOffset = try in_stream.readInt(u24, endian) },
FORM.strx4 => return FormValue{ .StrOffset = try in_stream.readInt(u32, endian) },
FORM.strx => return FormValue{ .StrOffset = try nosuspend leb.readULEB128(usize, in_stream) },
FORM.line_strp => FormValue{ .LineStrPtr = try readAddress(in_stream, endian, is_64) }, FORM.line_strp => FormValue{ .LineStrPtr = try readAddress(in_stream, endian, is_64) },
FORM.indirect => { FORM.indirect => {
const child_form_id = try nosuspend leb.readULEB128(u64, in_stream); 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
return await @asyncCall(frame, {}, parseFormValue, .{ allocator, in_stream, child_form_id, endian, is_64 }); return await @asyncCall(frame, {}, parseFormValue, .{ allocator, in_stream, child_form_id, endian, is_64 });
}, },
FORM.implicit_const => FormValue{ .Const = Constant{ .signed = true, .payload = undefined } }, FORM.implicit_const => FormValue{ .Const = Constant{ .signed = true, .payload = undefined } },
FORM.loclistx => return FormValue{ .LocListOffset = try nosuspend leb.readULEB128(u64, in_stream) },
FORM.rnglistx => return FormValue{ .RangeListOffset = try nosuspend leb.readULEB128(u64, in_stream) },
else => { else => {
return error.InvalidDebugInfo; //std.debug.print("unrecognized form id: {x}\n", .{form_id});
return badDwarf();
}, },
}; };
} }
@ -554,9 +669,15 @@ pub const DwarfInfo = struct {
debug_info: []const u8, debug_info: []const u8,
debug_abbrev: []const u8, debug_abbrev: []const u8,
debug_str: []const u8, debug_str: []const u8,
debug_str_offsets: ?[]const u8,
debug_line: []const u8, debug_line: []const u8,
debug_line_str: ?[]const u8, debug_line_str: ?[]const u8,
debug_ranges: ?[]const u8, debug_ranges: ?[]const u8,
debug_loclists: ?[]const u8,
debug_rnglists: ?[]const u8,
debug_addr: ?[]const u8,
debug_names: ?[]const u8,
debug_frame: ?[]const u8,
// Filled later by the initializer // Filled later by the initializer
abbrev_table_list: std.ArrayListUnmanaged(AbbrevTableHeader) = .{}, abbrev_table_list: std.ArrayListUnmanaged(AbbrevTableHeader) = .{},
compile_unit_list: std.ArrayListUnmanaged(CompileUnit) = .{}, compile_unit_list: std.ArrayListUnmanaged(CompileUnit) = .{},
@ -592,7 +713,7 @@ pub const DwarfInfo = struct {
fn scanAllFunctions(di: *DwarfInfo, allocator: mem.Allocator) !void { fn scanAllFunctions(di: *DwarfInfo, allocator: mem.Allocator) !void {
var stream = io.fixedBufferStream(di.debug_info); var stream = io.fixedBufferStream(di.debug_info);
const in = &stream.reader(); const in = stream.reader();
const seekable = &stream.seekableStream(); const seekable = &stream.seekableStream();
var this_unit_offset: u64 = 0; var this_unit_offset: u64 = 0;
@ -609,29 +730,26 @@ pub const DwarfInfo = struct {
const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4)); const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
const version = try in.readInt(u16, di.endian); const version = try in.readInt(u16, di.endian);
if (version < 2 or version > 5) return error.InvalidDebugInfo; if (version < 2 or version > 5) return badDwarf();
var address_size: u8 = undefined; var address_size: u8 = undefined;
var debug_abbrev_offset: u64 = undefined; var debug_abbrev_offset: u64 = undefined;
switch (version) { if (version >= 5) {
5 => { const unit_type = try in.readInt(u8, di.endian);
const unit_type = try in.readInt(u8, di.endian); if (unit_type != UT.compile) return badDwarf();
if (unit_type != UT.compile) return error.InvalidDebugInfo; address_size = try in.readByte();
address_size = try in.readByte(); debug_abbrev_offset = if (is_64)
debug_abbrev_offset = if (is_64) try in.readInt(u64, di.endian)
try in.readInt(u64, di.endian) else
else try in.readInt(u32, di.endian);
try in.readInt(u32, di.endian); } else {
}, debug_abbrev_offset = if (is_64)
else => { try in.readInt(u64, di.endian)
debug_abbrev_offset = if (is_64) else
try in.readInt(u64, di.endian) try in.readInt(u32, di.endian);
else address_size = try in.readByte();
try in.readInt(u32, di.endian);
address_size = try in.readByte();
},
} }
if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo; if (address_size != @sizeOf(usize)) return badDwarf();
const compile_unit_pos = try seekable.getPos(); const compile_unit_pos = try seekable.getPos();
const abbrev_table = try di.getAbbrevTable(allocator, debug_abbrev_offset); const abbrev_table = try di.getAbbrevTable(allocator, debug_abbrev_offset);
@ -640,11 +758,26 @@ pub const DwarfInfo = struct {
const next_unit_pos = this_unit_offset + next_offset; const next_unit_pos = this_unit_offset + next_offset;
var compile_unit: CompileUnit = undefined;
while ((try seekable.getPos()) < next_unit_pos) { while ((try seekable.getPos()) < next_unit_pos) {
const die_obj = (try di.parseDie(arena, in, abbrev_table, is_64)) orelse continue; var die_obj = (try di.parseDie(arena, in, abbrev_table, is_64)) orelse continue;
const after_die_offset = try seekable.getPos(); const after_die_offset = try seekable.getPos();
switch (die_obj.tag_id) { switch (die_obj.tag_id) {
TAG.compile_unit => {
compile_unit = .{
.version = version,
.is_64 = is_64,
.die = &die_obj,
.pc_range = null,
.str_offsets_base = if (die_obj.getAttr(AT.str_offsets_base)) |fv| try fv.getUInt(usize) else 0,
.addr_base = if (die_obj.getAttr(AT.addr_base)) |fv| try fv.getUInt(usize) else 0,
.rnglists_base = if (die_obj.getAttr(AT.rnglists_base)) |fv| try fv.getUInt(usize) else 0,
.loclists_base = if (die_obj.getAttr(AT.loclists_base)) |fv| try fv.getUInt(usize) else 0,
};
},
TAG.subprogram, TAG.inlined_subroutine, TAG.subroutine, TAG.entry_point => { TAG.subprogram, TAG.inlined_subroutine, TAG.subroutine, TAG.entry_point => {
const fn_name = x: { const fn_name = x: {
var depth: i32 = 3; var depth: i32 = 3;
@ -652,30 +785,30 @@ pub const DwarfInfo = struct {
// Prevent endless loops // Prevent endless loops
while (depth > 0) : (depth -= 1) { while (depth > 0) : (depth -= 1) {
if (this_die_obj.getAttr(AT.name)) |_| { if (this_die_obj.getAttr(AT.name)) |_| {
const name = try this_die_obj.getAttrString(di, AT.name); const name = try this_die_obj.getAttrString(di, AT.name, di.debug_str, compile_unit);
break :x try allocator.dupe(u8, name); break :x try allocator.dupe(u8, name);
} else if (this_die_obj.getAttr(AT.abstract_origin)) |_| { } else if (this_die_obj.getAttr(AT.abstract_origin)) |_| {
// Follow the DIE it points to and repeat // Follow the DIE it points to and repeat
const ref_offset = try this_die_obj.getAttrRef(AT.abstract_origin); const ref_offset = try this_die_obj.getAttrRef(AT.abstract_origin);
if (ref_offset > next_offset) return error.InvalidDebugInfo; if (ref_offset > next_offset) return badDwarf();
try seekable.seekTo(this_unit_offset + ref_offset); try seekable.seekTo(this_unit_offset + ref_offset);
this_die_obj = (try di.parseDie( this_die_obj = (try di.parseDie(
arena, arena,
in, in,
abbrev_table, abbrev_table,
is_64, is_64,
)) orelse return error.InvalidDebugInfo; )) orelse return badDwarf();
} else if (this_die_obj.getAttr(AT.specification)) |_| { } else if (this_die_obj.getAttr(AT.specification)) |_| {
// Follow the DIE it points to and repeat // Follow the DIE it points to and repeat
const ref_offset = try this_die_obj.getAttrRef(AT.specification); const ref_offset = try this_die_obj.getAttrRef(AT.specification);
if (ref_offset > next_offset) return error.InvalidDebugInfo; if (ref_offset > next_offset) return badDwarf();
try seekable.seekTo(this_unit_offset + ref_offset); try seekable.seekTo(this_unit_offset + ref_offset);
this_die_obj = (try di.parseDie( this_die_obj = (try di.parseDie(
arena, arena,
in, in,
abbrev_table, abbrev_table,
is_64, is_64,
)) orelse return error.InvalidDebugInfo; )) orelse return badDwarf();
} else { } else {
break :x null; break :x null;
} }
@ -685,7 +818,7 @@ pub const DwarfInfo = struct {
}; };
const pc_range = x: { const pc_range = x: {
if (die_obj.getAttrAddr(AT.low_pc)) |low_pc| { if (die_obj.getAttrAddr(di, AT.low_pc, compile_unit)) |low_pc| {
if (die_obj.getAttr(AT.high_pc)) |high_pc_value| { if (die_obj.getAttr(AT.high_pc)) |high_pc_value| {
const pc_end = switch (high_pc_value.*) { const pc_end = switch (high_pc_value.*) {
FormValue.Address => |value| value, FormValue.Address => |value| value,
@ -693,7 +826,7 @@ pub const DwarfInfo = struct {
const offset = try value.asUnsignedLe(); const offset = try value.asUnsignedLe();
break :b (low_pc + offset); break :b (low_pc + offset);
}, },
else => return error.InvalidDebugInfo, else => return badDwarf(),
}; };
break :x PcRange{ break :x PcRange{
.start = low_pc, .start = low_pc,
@ -738,29 +871,26 @@ pub const DwarfInfo = struct {
const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4)); const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
const version = try in.readInt(u16, di.endian); const version = try in.readInt(u16, di.endian);
if (version < 2 or version > 5) return error.InvalidDebugInfo; if (version < 2 or version > 5) return badDwarf();
var address_size: u8 = undefined; var address_size: u8 = undefined;
var debug_abbrev_offset: u64 = undefined; var debug_abbrev_offset: u64 = undefined;
switch (version) { if (version >= 5) {
5 => { const unit_type = try in.readInt(u8, di.endian);
const unit_type = try in.readInt(u8, di.endian); if (unit_type != UT.compile) return badDwarf();
if (unit_type != UT.compile) return error.InvalidDebugInfo; address_size = try in.readByte();
address_size = try in.readByte(); debug_abbrev_offset = if (is_64)
debug_abbrev_offset = if (is_64) try in.readInt(u64, di.endian)
try in.readInt(u64, di.endian) else
else try in.readInt(u32, di.endian);
try in.readInt(u32, di.endian); } else {
}, debug_abbrev_offset = if (is_64)
else => { try in.readInt(u64, di.endian)
debug_abbrev_offset = if (is_64) else
try in.readInt(u64, di.endian) try in.readInt(u32, di.endian);
else address_size = try in.readByte();
try in.readInt(u32, di.endian);
address_size = try in.readByte();
},
} }
if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo; if (address_size != @sizeOf(usize)) return badDwarf();
const compile_unit_pos = try seekable.getPos(); const compile_unit_pos = try seekable.getPos();
const abbrev_table = try di.getAbbrevTable(allocator, debug_abbrev_offset); const abbrev_table = try di.getAbbrevTable(allocator, debug_abbrev_offset);
@ -770,12 +900,23 @@ pub const DwarfInfo = struct {
const compile_unit_die = try allocator.create(Die); const compile_unit_die = try allocator.create(Die);
errdefer allocator.destroy(compile_unit_die); errdefer allocator.destroy(compile_unit_die);
compile_unit_die.* = (try di.parseDie(allocator, in, abbrev_table, is_64)) orelse compile_unit_die.* = (try di.parseDie(allocator, in, abbrev_table, is_64)) orelse
return error.InvalidDebugInfo; return badDwarf();
if (compile_unit_die.tag_id != TAG.compile_unit) return error.InvalidDebugInfo; if (compile_unit_die.tag_id != TAG.compile_unit) return badDwarf();
const pc_range = x: { var compile_unit: CompileUnit = .{
if (compile_unit_die.getAttrAddr(AT.low_pc)) |low_pc| { .version = version,
.is_64 = is_64,
.pc_range = null,
.die = compile_unit_die,
.str_offsets_base = if (compile_unit_die.getAttr(AT.str_offsets_base)) |fv| try fv.getUInt(usize) else 0,
.addr_base = if (compile_unit_die.getAttr(AT.addr_base)) |fv| try fv.getUInt(usize) else 0,
.rnglists_base = if (compile_unit_die.getAttr(AT.rnglists_base)) |fv| try fv.getUInt(usize) else 0,
.loclists_base = if (compile_unit_die.getAttr(AT.loclists_base)) |fv| try fv.getUInt(usize) else 0,
};
compile_unit.pc_range = x: {
if (compile_unit_die.getAttrAddr(di, AT.low_pc, compile_unit)) |low_pc| {
if (compile_unit_die.getAttr(AT.high_pc)) |high_pc_value| { if (compile_unit_die.getAttr(AT.high_pc)) |high_pc_value| {
const pc_end = switch (high_pc_value.*) { const pc_end = switch (high_pc_value.*) {
FormValue.Address => |value| value, FormValue.Address => |value| value,
@ -783,7 +924,7 @@ pub const DwarfInfo = struct {
const offset = try value.asUnsignedLe(); const offset = try value.asUnsignedLe();
break :b (low_pc + offset); break :b (low_pc + offset);
}, },
else => return error.InvalidDebugInfo, else => return badDwarf(),
}; };
break :x PcRange{ break :x PcRange{
.start = low_pc, .start = low_pc,
@ -798,12 +939,7 @@ pub const DwarfInfo = struct {
} }
}; };
try di.compile_unit_list.append(allocator, CompileUnit{ try di.compile_unit_list.append(allocator, compile_unit);
.version = version,
.is_64 = is_64,
.pc_range = pc_range,
.die = compile_unit_die,
});
this_unit_offset += next_offset; this_unit_offset += next_offset;
} }
@ -824,7 +960,7 @@ pub const DwarfInfo = struct {
// specified by DW_AT.low_pc or to some other value encoded // specified by DW_AT.low_pc or to some other value encoded
// in the list itself. // in the list itself.
// If no starting value is specified use zero. // If no starting value is specified use zero.
var base_address = compile_unit.die.getAttrAddr(AT.low_pc) catch |err| switch (err) { var base_address = compile_unit.die.getAttrAddr(di, AT.low_pc, compile_unit.*) catch |err| switch (err) {
error.MissingDebugInfo => @as(u64, 0), // TODO https://github.com/ziglang/zig/issues/11135 error.MissingDebugInfo => @as(u64, 0), // TODO https://github.com/ziglang/zig/issues/11135
else => return err, else => return err,
}; };
@ -852,7 +988,7 @@ pub const DwarfInfo = struct {
} }
} }
} }
return error.MissingDebugInfo; return missingDwarf();
} }
/// Gets an already existing AbbrevTable given the abbrev_offset, or if not found, /// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
@ -919,7 +1055,7 @@ pub const DwarfInfo = struct {
) !?Die { ) !?Die {
const abbrev_code = try leb.readULEB128(u64, in_stream); const abbrev_code = try leb.readULEB128(u64, in_stream);
if (abbrev_code == 0) return null; if (abbrev_code == 0) return null;
const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo; const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return badDwarf();
var result = Die{ var result = Die{
// Lives as long as the Die. // Lives as long as the Die.
@ -956,7 +1092,7 @@ pub const DwarfInfo = struct {
const in = &stream.reader(); const in = &stream.reader();
const seekable = &stream.seekableStream(); const seekable = &stream.seekableStream();
const compile_unit_cwd = try compile_unit.die.getAttrString(di, AT.comp_dir); const compile_unit_cwd = try compile_unit.die.getAttrString(di, AT.comp_dir, di.debug_line_str, compile_unit);
const line_info_offset = try compile_unit.die.getAttrSecOffset(AT.stmt_list); const line_info_offset = try compile_unit.die.getAttrSecOffset(AT.stmt_list);
try seekable.seekTo(line_info_offset); try seekable.seekTo(line_info_offset);
@ -964,18 +1100,25 @@ pub const DwarfInfo = struct {
var is_64: bool = undefined; var is_64: bool = undefined;
const unit_length = try readUnitLength(in, di.endian, &is_64); const unit_length = try readUnitLength(in, di.endian, &is_64);
if (unit_length == 0) { if (unit_length == 0) {
return error.MissingDebugInfo; return missingDwarf();
} }
const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4)); const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4));
const version = try in.readInt(u16, di.endian); const version = try in.readInt(u16, di.endian);
if (version < 2 or version > 4) return error.InvalidDebugInfo; if (version < 2) return badDwarf();
var addr_size: u8 = if (is_64) 8 else 4;
var seg_size: u8 = 0;
if (version >= 5) {
addr_size = try in.readByte();
seg_size = try in.readByte();
}
const prologue_length = if (is_64) try in.readInt(u64, di.endian) else try in.readInt(u32, di.endian); const prologue_length = if (is_64) try in.readInt(u64, di.endian) else try in.readInt(u32, di.endian);
const prog_start_offset = (try seekable.getPos()) + prologue_length; const prog_start_offset = (try seekable.getPos()) + prologue_length;
const minimum_instruction_length = try in.readByte(); const minimum_instruction_length = try in.readByte();
if (minimum_instruction_length == 0) return error.InvalidDebugInfo; if (minimum_instruction_length == 0) return badDwarf();
if (version >= 4) { if (version >= 4) {
// maximum_operations_per_instruction // maximum_operations_per_instruction
@ -986,7 +1129,7 @@ pub const DwarfInfo = struct {
const line_base = try in.readByteSigned(); const line_base = try in.readByteSigned();
const line_range = try in.readByte(); const line_range = try in.readByte();
if (line_range == 0) return error.InvalidDebugInfo; if (line_range == 0) return badDwarf();
const opcode_base = try in.readByte(); const opcode_base = try in.readByte();
@ -1004,36 +1147,120 @@ pub const DwarfInfo = struct {
defer tmp_arena.deinit(); defer tmp_arena.deinit();
const arena = tmp_arena.allocator(); const arena = tmp_arena.allocator();
var include_directories = std.ArrayList([]const u8).init(arena); var include_directories = std.ArrayList(FileEntry).init(arena);
try include_directories.append(compile_unit_cwd); var file_entries = std.ArrayList(FileEntry).init(arena);
while (true) { if (version < 5) {
const dir = try in.readUntilDelimiterAlloc(arena, 0, math.maxInt(usize)); try include_directories.append(.{ .path = compile_unit_cwd });
if (dir.len == 0) break;
try include_directories.append(dir); while (true) {
const dir = try in.readUntilDelimiterAlloc(arena, 0, math.maxInt(usize));
if (dir.len == 0) break;
try include_directories.append(.{ .path = dir });
}
while (true) {
const file_name = try in.readUntilDelimiterAlloc(arena, 0, math.maxInt(usize));
if (file_name.len == 0) break;
const dir_index = try leb.readULEB128(u32, in);
const mtime = try leb.readULEB128(u64, in);
const size = try leb.readULEB128(u64, in);
try file_entries.append(FileEntry{
.path = file_name,
.dir_index = dir_index,
.mtime = mtime,
.size = size,
});
}
} else {
const FileEntFmt = struct {
content_type_code: u8,
form_code: u16,
};
{
var dir_ent_fmt_buf: [10]FileEntFmt = undefined;
const directory_entry_format_count = try in.readByte();
if (directory_entry_format_count > dir_ent_fmt_buf.len) return badDwarf();
for (dir_ent_fmt_buf[0..directory_entry_format_count]) |*ent_fmt| {
ent_fmt.* = .{
.content_type_code = try leb.readULEB128(u8, in),
.form_code = try leb.readULEB128(u16, in),
};
}
const directories_count = try leb.readULEB128(usize, in);
try include_directories.ensureUnusedCapacity(directories_count);
{
var i: usize = 0;
while (i < directories_count) : (i += 1) {
var e: FileEntry = .{ .path = &.{} };
for (dir_ent_fmt_buf[0..directory_entry_format_count]) |ent_fmt| {
const form_value = try parseFormValue(
arena,
in,
ent_fmt.form_code,
di.endian,
is_64,
);
switch (ent_fmt.content_type_code) {
LNCT.path => e.path = try form_value.getString(di.*),
LNCT.directory_index => e.dir_index = try form_value.getUInt(u32),
LNCT.timestamp => e.mtime = try form_value.getUInt(u64),
LNCT.size => e.size = try form_value.getUInt(u64),
LNCT.MD5 => e.md5 = try form_value.getData16(),
else => continue,
}
}
include_directories.appendAssumeCapacity(e);
}
}
}
var file_ent_fmt_buf: [10]FileEntFmt = undefined;
const file_name_entry_format_count = try in.readByte();
if (file_name_entry_format_count > file_ent_fmt_buf.len) return badDwarf();
for (file_ent_fmt_buf[0..file_name_entry_format_count]) |*ent_fmt| {
ent_fmt.* = .{
.content_type_code = try leb.readULEB128(u8, in),
.form_code = try leb.readULEB128(u16, in),
};
}
const file_names_count = try leb.readULEB128(usize, in);
try file_entries.ensureUnusedCapacity(file_names_count);
{
var i: usize = 0;
while (i < file_names_count) : (i += 1) {
var e: FileEntry = .{ .path = &.{} };
for (file_ent_fmt_buf[0..file_name_entry_format_count]) |ent_fmt| {
const form_value = try parseFormValue(
arena,
in,
ent_fmt.form_code,
di.endian,
is_64,
);
switch (ent_fmt.content_type_code) {
LNCT.path => e.path = try form_value.getString(di.*),
LNCT.directory_index => e.dir_index = try form_value.getUInt(u32),
LNCT.timestamp => e.mtime = try form_value.getUInt(u64),
LNCT.size => e.size = try form_value.getUInt(u64),
LNCT.MD5 => e.md5 = try form_value.getData16(),
else => continue,
}
}
file_entries.appendAssumeCapacity(e);
}
}
} }
var file_entries = std.ArrayList(FileEntry).init(arena);
var prog = LineNumberProgram.init( var prog = LineNumberProgram.init(
default_is_stmt, default_is_stmt,
include_directories.items, include_directories.items,
target_address, target_address,
version,
); );
while (true) {
const file_name = try in.readUntilDelimiterAlloc(arena, 0, math.maxInt(usize));
if (file_name.len == 0) break;
const dir_index = try leb.readULEB128(usize, in);
const mtime = try leb.readULEB128(usize, in);
const len_bytes = try leb.readULEB128(usize, in);
try file_entries.append(FileEntry{
.file_name = file_name,
.dir_index = dir_index,
.mtime = mtime,
.len_bytes = len_bytes,
});
}
try seekable.seekTo(prog_start_offset); try seekable.seekTo(prog_start_offset);
const next_unit_pos = line_info_offset + next_offset; const next_unit_pos = line_info_offset + next_offset;
@ -1043,7 +1270,7 @@ pub const DwarfInfo = struct {
if (opcode == LNS.extended_op) { if (opcode == LNS.extended_op) {
const op_size = try leb.readULEB128(u64, in); const op_size = try leb.readULEB128(u64, in);
if (op_size < 1) return error.InvalidDebugInfo; if (op_size < 1) return badDwarf();
var sub_op = try in.readByte(); var sub_op = try in.readByte();
switch (sub_op) { switch (sub_op) {
LNE.end_sequence => { LNE.end_sequence => {
@ -1056,19 +1283,19 @@ pub const DwarfInfo = struct {
prog.address = addr; prog.address = addr;
}, },
LNE.define_file => { LNE.define_file => {
const file_name = try in.readUntilDelimiterAlloc(arena, 0, math.maxInt(usize)); const path = try in.readUntilDelimiterAlloc(arena, 0, math.maxInt(usize));
const dir_index = try leb.readULEB128(usize, in); const dir_index = try leb.readULEB128(u32, in);
const mtime = try leb.readULEB128(usize, in); const mtime = try leb.readULEB128(u64, in);
const len_bytes = try leb.readULEB128(usize, in); const size = try leb.readULEB128(u64, in);
try file_entries.append(FileEntry{ try file_entries.append(FileEntry{
.file_name = file_name, .path = path,
.dir_index = dir_index, .dir_index = dir_index,
.mtime = mtime, .mtime = mtime,
.len_bytes = len_bytes, .size = size,
}); });
}, },
else => { else => {
const fwd_amt = math.cast(isize, op_size - 1) orelse return error.InvalidDebugInfo; const fwd_amt = math.cast(isize, op_size - 1) orelse return badDwarf();
try seekable.seekBy(fwd_amt); try seekable.seekBy(fwd_amt);
}, },
} }
@ -1119,7 +1346,7 @@ pub const DwarfInfo = struct {
}, },
LNS.set_prologue_end => {}, LNS.set_prologue_end => {},
else => { else => {
if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo; if (opcode - 1 >= standard_opcode_lengths.len) return badDwarf();
const len_bytes = standard_opcode_lengths[opcode - 1]; const len_bytes = standard_opcode_lengths[opcode - 1];
try seekable.seekBy(len_bytes); try seekable.seekBy(len_bytes);
}, },
@ -1127,36 +1354,15 @@ pub const DwarfInfo = struct {
} }
} }
return error.MissingDebugInfo; return missingDwarf();
} }
fn getString(di: *DwarfInfo, offset: u64) ![]const u8 { fn getString(di: DwarfInfo, offset: u64) ![]const u8 {
if (offset > di.debug_str.len) return getStringGeneric(di.debug_str, offset);
return error.InvalidDebugInfo;
const casted_offset = math.cast(usize, offset) orelse
return error.InvalidDebugInfo;
// Valid strings always have a terminating zero byte
if (mem.indexOfScalarPos(u8, di.debug_str, casted_offset, 0)) |last| {
return di.debug_str[casted_offset..last];
}
return error.InvalidDebugInfo;
} }
fn getLineString(di: *DwarfInfo, offset: u64) ![]const u8 { fn getLineString(di: DwarfInfo, offset: u64) ![]const u8 {
const debug_line_str = di.debug_line_str orelse return error.InvalidDebugInfo; return getStringGeneric(di.debug_line_str, offset);
if (offset > debug_line_str.len)
return error.InvalidDebugInfo;
const casted_offset = math.cast(usize, offset) orelse
return error.InvalidDebugInfo;
// Valid strings always have a terminating zero byte
if (mem.indexOfScalarPos(u8, debug_line_str, casted_offset, 0)) |last| {
return debug_line_str[casted_offset..last];
}
return error.InvalidDebugInfo;
} }
}; };
@ -1166,3 +1372,24 @@ pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: mem.Allocator) !void {
try di.scanAllFunctions(allocator); try di.scanAllFunctions(allocator);
try di.scanAllCompileUnits(allocator); try di.scanAllCompileUnits(allocator);
} }
/// This function is to make it handy to comment out the return and make it
/// into a crash when working on this file.
fn badDwarf() error{InvalidDebugInfo} {
//std.os.abort(); // can be handy to uncomment when working on this file
return error.InvalidDebugInfo;
}
fn missingDwarf() error{MissingDebugInfo} {
//std.os.abort(); // can be handy to uncomment when working on this file
return error.MissingDebugInfo;
}
fn getStringGeneric(opt_str: ?[]const u8, offset: u64) ![:0]const u8 {
const str = opt_str orelse return badDwarf();
if (offset > str.len) return badDwarf();
const casted_offset = math.cast(usize, offset) orelse return badDwarf();
// Valid strings always have a terminating zero byte
const last = mem.indexOfScalarPos(u8, str, casted_offset, 0) orelse return badDwarf();
return str[casted_offset..last :0];
}

View File

@ -3,7 +3,7 @@ const io = std.io;
const os = std.os; const os = std.os;
const math = std.math; const math = std.math;
const mem = std.mem; const mem = std.mem;
const debug = std.debug; const assert = std.debug.assert;
const File = std.fs.File; const File = std.fs.File;
const native_endian = @import("builtin").target.cpu.arch.endian(); const native_endian = @import("builtin").target.cpu.arch.endian();
@ -387,7 +387,7 @@ pub const Header = struct {
const machine = if (need_bswap) blk: { const machine = if (need_bswap) blk: {
const value = @enumToInt(hdr32.e_machine); const value = @enumToInt(hdr32.e_machine);
break :blk @intToEnum(EM, @byteSwap(@TypeOf(value), value)); break :blk @intToEnum(EM, @byteSwap(value));
} else hdr32.e_machine; } else hdr32.e_machine;
return @as(Header, .{ return @as(Header, .{
@ -406,7 +406,7 @@ pub const Header = struct {
} }
}; };
pub fn ProgramHeaderIterator(ParseSource: anytype) type { pub fn ProgramHeaderIterator(comptime ParseSource: anytype) type {
return struct { return struct {
elf_header: Header, elf_header: Header,
parse_source: ParseSource, parse_source: ParseSource,
@ -456,7 +456,7 @@ pub fn ProgramHeaderIterator(ParseSource: anytype) type {
}; };
} }
pub fn SectionHeaderIterator(ParseSource: anytype) type { pub fn SectionHeaderIterator(comptime ParseSource: anytype) type {
return struct { return struct {
elf_header: Header, elf_header: Header,
parse_source: ParseSource, parse_source: ParseSource,
@ -511,7 +511,7 @@ pub fn SectionHeaderIterator(ParseSource: anytype) type {
pub fn int(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @TypeOf(int_64) { pub fn int(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @TypeOf(int_64) {
if (is_64) { if (is_64) {
if (need_bswap) { if (need_bswap) {
return @byteSwap(@TypeOf(int_64), int_64); return @byteSwap(int_64);
} else { } else {
return int_64; return int_64;
} }
@ -522,7 +522,7 @@ pub fn int(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @Typ
pub fn int32(need_bswap: bool, int_32: anytype, comptime Int64: anytype) Int64 { pub fn int32(need_bswap: bool, int_32: anytype, comptime Int64: anytype) Int64 {
if (need_bswap) { if (need_bswap) {
return @byteSwap(@TypeOf(int_32), int_32); return @byteSwap(int_32);
} else { } else {
return int_32; return int_32;
} }
@ -872,14 +872,14 @@ pub const Elf_MIPS_ABIFlags_v0 = extern struct {
}; };
comptime { comptime {
debug.assert(@sizeOf(Elf32_Ehdr) == 52); assert(@sizeOf(Elf32_Ehdr) == 52);
debug.assert(@sizeOf(Elf64_Ehdr) == 64); assert(@sizeOf(Elf64_Ehdr) == 64);
debug.assert(@sizeOf(Elf32_Phdr) == 32); assert(@sizeOf(Elf32_Phdr) == 32);
debug.assert(@sizeOf(Elf64_Phdr) == 56); assert(@sizeOf(Elf64_Phdr) == 56);
debug.assert(@sizeOf(Elf32_Shdr) == 40); assert(@sizeOf(Elf32_Shdr) == 40);
debug.assert(@sizeOf(Elf64_Shdr) == 64); assert(@sizeOf(Elf64_Shdr) == 64);
} }
pub const Auxv = switch (@sizeOf(usize)) { pub const Auxv = switch (@sizeOf(usize)) {

View File

@ -57,7 +57,7 @@ pub fn values(comptime E: type) []const E {
/// the total number of items which have no matching enum key (holes in the enum /// the total number of items which have no matching enum key (holes in the enum
/// numbering). So for example, if an enum has values 1, 2, 5, and 6, max_unused_slots /// numbering). So for example, if an enum has values 1, 2, 5, and 6, max_unused_slots
/// must be at least 3, to allow unused slots 0, 3, and 4. /// must be at least 3, to allow unused slots 0, 3, and 4.
fn directEnumArrayLen(comptime E: type, comptime max_unused_slots: comptime_int) comptime_int { pub fn directEnumArrayLen(comptime E: type, comptime max_unused_slots: comptime_int) comptime_int {
var max_value: comptime_int = -1; var max_value: comptime_int = -1;
const max_usize: comptime_int = ~@as(usize, 0); const max_usize: comptime_int = ~@as(usize, 0);
const fields = std.meta.fields(E); const fields = std.meta.fields(E);

View File

@ -56,7 +56,7 @@ pub fn Channel(comptime T: type) type {
pub fn init(self: *SelfChannel, buffer: []T) void { pub fn init(self: *SelfChannel, buffer: []T) void {
// The ring buffer implementation only works with power of 2 buffer sizes // The ring buffer implementation only works with power of 2 buffer sizes
// because of relying on subtracting across zero. For example (0 -% 1) % 10 == 5 // because of relying on subtracting across zero. For example (0 -% 1) % 10 == 5
assert(buffer.len == 0 or @popCount(usize, buffer.len) == 1); assert(buffer.len == 0 or @popCount(buffer.len) == 1);
self.* = SelfChannel{ self.* = SelfChannel{
.buffer_len = 0, .buffer_len = 0,

View File

@ -195,7 +195,7 @@ pub fn format(
} }
if (comptime arg_state.hasUnusedArgs()) { if (comptime arg_state.hasUnusedArgs()) {
const missing_count = arg_state.args_len - @popCount(ArgSetType, arg_state.used_args); const missing_count = arg_state.args_len - @popCount(arg_state.used_args);
switch (missing_count) { switch (missing_count) {
0 => unreachable, 0 => unreachable,
1 => @compileError("unused argument in '" ++ fmt ++ "'"), 1 => @compileError("unused argument in '" ++ fmt ++ "'"),
@ -380,7 +380,7 @@ const ArgState = struct {
args_len: usize, args_len: usize,
fn hasUnusedArgs(self: *@This()) bool { fn hasUnusedArgs(self: *@This()) bool {
return @popCount(ArgSetType, self.used_args) != self.args_len; return @popCount(self.used_args) != self.args_len;
} }
fn nextArg(self: *@This(), arg_index: ?usize) ?usize { fn nextArg(self: *@This(), arg_index: ?usize) ?usize {

View File

@ -36,7 +36,7 @@ pub fn convertEiselLemire(comptime T: type, q: i64, w_: u64) ?BiasedFp(f64) {
} }
// Normalize our significant digits, so the most-significant bit is set. // Normalize our significant digits, so the most-significant bit is set.
const lz = @clz(u64, @bitCast(u64, w)); const lz = @clz(@bitCast(u64, w));
w = math.shl(u64, w, lz); w = math.shl(u64, w, lz);
const r = computeProductApprox(q, w, float_info.mantissa_explicit_bits + 3); const r = computeProductApprox(q, w, float_info.mantissa_explicit_bits + 3);

View File

@ -877,8 +877,9 @@ pub const IterableDir = struct {
/// a reference to the path. /// a reference to the path.
pub fn next(self: *Walker) !?WalkerEntry { pub fn next(self: *Walker) !?WalkerEntry {
while (self.stack.items.len != 0) { while (self.stack.items.len != 0) {
// `top` becomes invalid after appending to `self.stack` // `top` and `containing` become invalid after appending to `self.stack`
var top = &self.stack.items[self.stack.items.len - 1]; var top = &self.stack.items[self.stack.items.len - 1];
var containing = top;
var dirname_len = top.dirname_len; var dirname_len = top.dirname_len;
if (try top.iter.next()) |base| { if (try top.iter.next()) |base| {
self.name_buffer.shrinkRetainingCapacity(dirname_len); self.name_buffer.shrinkRetainingCapacity(dirname_len);
@ -899,10 +900,11 @@ pub const IterableDir = struct {
.dirname_len = self.name_buffer.items.len, .dirname_len = self.name_buffer.items.len,
}); });
top = &self.stack.items[self.stack.items.len - 1]; top = &self.stack.items[self.stack.items.len - 1];
containing = &self.stack.items[self.stack.items.len - 2];
} }
} }
return WalkerEntry{ return WalkerEntry{
.dir = top.iter.dir, .dir = containing.iter.dir,
.basename = self.name_buffer.items[dirname_len..], .basename = self.name_buffer.items[dirname_len..],
.path = self.name_buffer.items, .path = self.name_buffer.items,
.kind = base.kind, .kind = base.kind,

View File

@ -42,7 +42,7 @@ pub fn isSep(byte: u8) bool {
/// This is different from mem.join in that the separator will not be repeated if /// This is different from mem.join in that the separator will not be repeated if
/// it is found at the end or beginning of a pair of consecutive paths. /// it is found at the end or beginning of a pair of consecutive paths.
fn joinSepMaybeZ(allocator: Allocator, separator: u8, sepPredicate: fn (u8) bool, paths: []const []const u8, zero: bool) ![]u8 { fn joinSepMaybeZ(allocator: Allocator, separator: u8, comptime sepPredicate: fn (u8) bool, paths: []const []const u8, zero: bool) ![]u8 {
if (paths.len == 0) return if (zero) try allocator.dupe(u8, &[1]u8{0}) else &[0]u8{}; if (paths.len == 0) return if (zero) try allocator.dupe(u8, &[1]u8{0}) else &[0]u8{};
// Find first non-empty path index. // Find first non-empty path index.

View File

@ -1058,6 +1058,9 @@ test "walker" {
std.debug.print("found unexpected path: {s}\n", .{std.fmt.fmtSliceEscapeLower(entry.path)}); std.debug.print("found unexpected path: {s}\n", .{std.fmt.fmtSliceEscapeLower(entry.path)});
return err; return err;
}; };
// make sure that the entry.dir is the containing dir
var entry_dir = try entry.dir.openDir(entry.basename, .{});
defer entry_dir.close();
num_walked += 1; num_walked += 1;
} }
try testing.expectEqual(expected_paths.kvs.len, num_walked); try testing.expectEqual(expected_paths.kvs.len, num_walked);

View File

@ -30,13 +30,15 @@ pub fn hashPointer(hasher: anytype, key: anytype, comptime strat: HashStrategy)
.DeepRecursive => hash(hasher, key.*, .DeepRecursive), .DeepRecursive => hash(hasher, key.*, .DeepRecursive),
}, },
.Slice => switch (strat) { .Slice => {
.Shallow => { switch (strat) {
hashPointer(hasher, key.ptr, .Shallow); .Shallow => {
hash(hasher, key.len, .Shallow); hashPointer(hasher, key.ptr, .Shallow);
}, },
.Deep => hashArray(hasher, key, .Shallow), .Deep => hashArray(hasher, key, .Shallow),
.DeepRecursive => hashArray(hasher, key, .DeepRecursive), .DeepRecursive => hashArray(hasher, key, .DeepRecursive),
}
hash(hasher, key.len, .Shallow);
}, },
.Many, .Many,
@ -53,17 +55,8 @@ pub fn hashPointer(hasher: anytype, key: anytype, comptime strat: HashStrategy)
/// Helper function to hash a set of contiguous objects, from an array or slice. /// Helper function to hash a set of contiguous objects, from an array or slice.
pub fn hashArray(hasher: anytype, key: anytype, comptime strat: HashStrategy) void { pub fn hashArray(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {
switch (strat) { for (key) |element| {
.Shallow => { hash(hasher, element, strat);
for (key) |element| {
hash(hasher, element, .Shallow);
}
},
else => {
for (key) |element| {
hash(hasher, element, strat);
}
},
} }
} }
@ -193,8 +186,8 @@ fn typeContainsSlice(comptime K: type) bool {
pub fn autoHash(hasher: anytype, key: anytype) void { pub fn autoHash(hasher: anytype, key: anytype) void {
const Key = @TypeOf(key); const Key = @TypeOf(key);
if (comptime typeContainsSlice(Key)) { if (comptime typeContainsSlice(Key)) {
@compileError("std.auto_hash.autoHash does not allow slices as well as unions and structs containing slices here (" ++ @typeName(Key) ++ @compileError("std.hash.autoHash does not allow slices as well as unions and structs containing slices here (" ++ @typeName(Key) ++
") because the intent is unclear. Consider using std.auto_hash.hash or providing your own hash function instead."); ") because the intent is unclear. Consider using std.hash.autoHashStrat or providing your own hash function instead.");
} }
hash(hasher, key, .Shallow); hash(hasher, key, .Shallow);
@ -359,6 +352,12 @@ test "testHash array" {
try testing.expectEqual(h, hasher.final()); try testing.expectEqual(h, hasher.final());
} }
test "testHash multi-dimensional array" {
const a = [_][]const u32{ &.{ 1, 2, 3 }, &.{ 4, 5 } };
const b = [_][]const u32{ &.{ 1, 2 }, &.{ 3, 4, 5 } };
try testing.expect(testHash(a) != testHash(b));
}
test "testHash struct" { test "testHash struct" {
const Foo = struct { const Foo = struct {
a: u32 = 1, a: u32 = 1,

View File

@ -143,9 +143,9 @@ pub const CityHash32 = struct {
h = rotr32(h, 19); h = rotr32(h, 19);
h = h *% 5 +% 0xe6546b64; h = h *% 5 +% 0xe6546b64;
g ^= b4; g ^= b4;
g = @byteSwap(u32, g) *% 5; g = @byteSwap(g) *% 5;
h +%= b4 *% 5; h +%= b4 *% 5;
h = @byteSwap(u32, h); h = @byteSwap(h);
f +%= b0; f +%= b0;
const t: u32 = h; const t: u32 = h;
h = f; h = f;
@ -252,11 +252,11 @@ pub const CityHash64 = struct {
const u: u64 = rotr64(a +% g, 43) +% (rotr64(b, 30) +% c) *% 9; const u: u64 = rotr64(a +% g, 43) +% (rotr64(b, 30) +% c) *% 9;
const v: u64 = ((a +% g) ^ d) +% f +% 1; const v: u64 = ((a +% g) ^ d) +% f +% 1;
const w: u64 = @byteSwap(u64, (u +% v) *% mul) +% h; const w: u64 = @byteSwap((u +% v) *% mul) +% h;
const x: u64 = rotr64(e +% f, 42) +% c; const x: u64 = rotr64(e +% f, 42) +% c;
const y: u64 = (@byteSwap(u64, (v +% w) *% mul) +% g) *% mul; const y: u64 = (@byteSwap((v +% w) *% mul) +% g) *% mul;
const z: u64 = e +% f +% c; const z: u64 = e +% f +% c;
const a1: u64 = @byteSwap(u64, (x +% z) *% mul +% y) +% b; const a1: u64 = @byteSwap((x +% z) *% mul +% y) +% b;
const b1: u64 = shiftmix((z +% a1) *% mul +% d +% h) *% mul; const b1: u64 = shiftmix((z +% a1) *% mul +% d +% h) *% mul;
return b1 +% x; return b1 +% x;
} }

View File

@ -19,7 +19,7 @@ pub const Murmur2_32 = struct {
for (@ptrCast([*]align(1) const u32, str.ptr)[0..(len >> 2)]) |v| { for (@ptrCast([*]align(1) const u32, str.ptr)[0..(len >> 2)]) |v| {
var k1: u32 = v; var k1: u32 = v;
if (native_endian == .Big) if (native_endian == .Big)
k1 = @byteSwap(u32, k1); k1 = @byteSwap(k1);
k1 *%= m; k1 *%= m;
k1 ^= k1 >> 24; k1 ^= k1 >> 24;
k1 *%= m; k1 *%= m;
@ -104,7 +104,7 @@ pub const Murmur2_64 = struct {
for (@ptrCast([*]align(1) const u64, str.ptr)[0..@intCast(usize, len >> 3)]) |v| { for (@ptrCast([*]align(1) const u64, str.ptr)[0..@intCast(usize, len >> 3)]) |v| {
var k1: u64 = v; var k1: u64 = v;
if (native_endian == .Big) if (native_endian == .Big)
k1 = @byteSwap(u64, k1); k1 = @byteSwap(k1);
k1 *%= m; k1 *%= m;
k1 ^= k1 >> 47; k1 ^= k1 >> 47;
k1 *%= m; k1 *%= m;
@ -117,7 +117,7 @@ pub const Murmur2_64 = struct {
var k1: u64 = 0; var k1: u64 = 0;
@memcpy(@ptrCast([*]u8, &k1), @ptrCast([*]const u8, &str[@intCast(usize, offset)]), @intCast(usize, rest)); @memcpy(@ptrCast([*]u8, &k1), @ptrCast([*]const u8, &str[@intCast(usize, offset)]), @intCast(usize, rest));
if (native_endian == .Big) if (native_endian == .Big)
k1 = @byteSwap(u64, k1); k1 = @byteSwap(k1);
h1 ^= k1; h1 ^= k1;
h1 *%= m; h1 *%= m;
} }
@ -184,7 +184,7 @@ pub const Murmur3_32 = struct {
for (@ptrCast([*]align(1) const u32, str.ptr)[0..(len >> 2)]) |v| { for (@ptrCast([*]align(1) const u32, str.ptr)[0..(len >> 2)]) |v| {
var k1: u32 = v; var k1: u32 = v;
if (native_endian == .Big) if (native_endian == .Big)
k1 = @byteSwap(u32, k1); k1 = @byteSwap(k1);
k1 *%= c1; k1 *%= c1;
k1 = rotl32(k1, 15); k1 = rotl32(k1, 15);
k1 *%= c2; k1 *%= c2;
@ -296,7 +296,7 @@ fn SMHasherTest(comptime hash_fn: anytype, comptime hashbits: u32) u32 {
var h = hash_fn(key[0..i], 256 - i); var h = hash_fn(key[0..i], 256 - i);
if (native_endian == .Big) if (native_endian == .Big)
h = @byteSwap(@TypeOf(h), h); h = @byteSwap(h);
@memcpy(@ptrCast([*]u8, &hashes[i * hashbytes]), @ptrCast([*]u8, &h), hashbytes); @memcpy(@ptrCast([*]u8, &hashes[i * hashbytes]), @ptrCast([*]u8, &h), hashbytes);
} }
@ -310,8 +310,8 @@ test "murmur2_32" {
var v0le: u32 = v0; var v0le: u32 = v0;
var v1le: u64 = v1; var v1le: u64 = v1;
if (native_endian == .Big) { if (native_endian == .Big) {
v0le = @byteSwap(u32, v0le); v0le = @byteSwap(v0le);
v1le = @byteSwap(u64, v1le); v1le = @byteSwap(v1le);
} }
try testing.expectEqual(Murmur2_32.hash(@ptrCast([*]u8, &v0le)[0..4]), Murmur2_32.hashUint32(v0)); try testing.expectEqual(Murmur2_32.hash(@ptrCast([*]u8, &v0le)[0..4]), Murmur2_32.hashUint32(v0));
try testing.expectEqual(Murmur2_32.hash(@ptrCast([*]u8, &v1le)[0..8]), Murmur2_32.hashUint64(v1)); try testing.expectEqual(Murmur2_32.hash(@ptrCast([*]u8, &v1le)[0..8]), Murmur2_32.hashUint64(v1));
@ -324,8 +324,8 @@ test "murmur2_64" {
var v0le: u32 = v0; var v0le: u32 = v0;
var v1le: u64 = v1; var v1le: u64 = v1;
if (native_endian == .Big) { if (native_endian == .Big) {
v0le = @byteSwap(u32, v0le); v0le = @byteSwap(v0le);
v1le = @byteSwap(u64, v1le); v1le = @byteSwap(v1le);
} }
try testing.expectEqual(Murmur2_64.hash(@ptrCast([*]u8, &v0le)[0..4]), Murmur2_64.hashUint32(v0)); try testing.expectEqual(Murmur2_64.hash(@ptrCast([*]u8, &v0le)[0..4]), Murmur2_64.hashUint32(v0));
try testing.expectEqual(Murmur2_64.hash(@ptrCast([*]u8, &v1le)[0..8]), Murmur2_64.hashUint64(v1)); try testing.expectEqual(Murmur2_64.hash(@ptrCast([*]u8, &v1le)[0..8]), Murmur2_64.hashUint64(v1));
@ -338,8 +338,8 @@ test "murmur3_32" {
var v0le: u32 = v0; var v0le: u32 = v0;
var v1le: u64 = v1; var v1le: u64 = v1;
if (native_endian == .Big) { if (native_endian == .Big) {
v0le = @byteSwap(u32, v0le); v0le = @byteSwap(v0le);
v1le = @byteSwap(u64, v1le); v1le = @byteSwap(v1le);
} }
try testing.expectEqual(Murmur3_32.hash(@ptrCast([*]u8, &v0le)[0..4]), Murmur3_32.hashUint32(v0)); try testing.expectEqual(Murmur3_32.hash(@ptrCast([*]u8, &v0le)[0..4]), Murmur3_32.hashUint32(v0));
try testing.expectEqual(Murmur3_32.hash(@ptrCast([*]u8, &v1le)[0..8]), Murmur3_32.hashUint64(v1)); try testing.expectEqual(Murmur3_32.hash(@ptrCast([*]u8, &v1le)[0..8]), Murmur3_32.hashUint64(v1));

View File

@ -479,7 +479,7 @@ const WasmPageAllocator = struct {
@setCold(true); @setCold(true);
for (self.data) |segment, i| { for (self.data) |segment, i| {
const spills_into_next = @bitCast(i128, segment) < 0; const spills_into_next = @bitCast(i128, segment) < 0;
const has_enough_bits = @popCount(u128, segment) >= num_pages; const has_enough_bits = @popCount(segment) >= num_pages;
if (!spills_into_next and !has_enough_bits) continue; if (!spills_into_next and !has_enough_bits) continue;
@ -1185,7 +1185,7 @@ pub fn testAllocatorLargeAlignment(base_allocator: mem.Allocator) !void {
const large_align = @as(u29, mem.page_size << 2); const large_align = @as(u29, mem.page_size << 2);
var align_mask: usize = undefined; var align_mask: usize = undefined;
_ = @shlWithOverflow(usize, ~@as(usize, 0), @as(USizeShift, @ctz(u29, large_align)), &align_mask); _ = @shlWithOverflow(usize, ~@as(usize, 0), @as(USizeShift, @ctz(large_align)), &align_mask);
var slice = try allocator.alignedAlloc(u8, large_align, 500); var slice = try allocator.alignedAlloc(u8, large_align, 500);
try testing.expect(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr)); try testing.expect(@ptrToInt(slice.ptr) & align_mask == @ptrToInt(slice.ptr));

View File

@ -7,7 +7,7 @@ const meta = std.meta;
const math = std.math; const math = std.math;
/// Creates a stream which allows for reading bit fields from another stream /// Creates a stream which allows for reading bit fields from another stream
pub fn BitReader(endian: std.builtin.Endian, comptime ReaderType: type) type { pub fn BitReader(comptime endian: std.builtin.Endian, comptime ReaderType: type) type {
return struct { return struct {
forward_reader: ReaderType, forward_reader: ReaderType,
bit_buffer: u7, bit_buffer: u7,

View File

@ -7,7 +7,7 @@ const meta = std.meta;
const math = std.math; const math = std.math;
/// Creates a stream which allows for writing bit fields to another stream /// Creates a stream which allows for writing bit fields to another stream
pub fn BitWriter(endian: std.builtin.Endian, comptime WriterType: type) type { pub fn BitWriter(comptime endian: std.builtin.Endian, comptime WriterType: type) type {
return struct { return struct {
forward_writer: WriterType, forward_writer: WriterType,
bit_buffer: u8, bit_buffer: u8,

View File

@ -247,6 +247,27 @@ pub fn Reader(
return bytes; return bytes;
} }
/// Reads bytes into the bounded array, until
/// the bounded array is full, or the stream ends.
pub fn readIntoBoundedBytes(
self: Self,
comptime num_bytes: usize,
bounded: *std.BoundedArray(u8, num_bytes),
) !void {
while (bounded.len < num_bytes) {
const bytes_read = try self.read(bounded.unusedCapacitySlice());
if (bytes_read == 0) return;
bounded.len += bytes_read;
}
}
/// Reads at most `num_bytes` and returns as a bounded array.
pub fn readBoundedBytes(self: Self, comptime num_bytes: usize) !std.BoundedArray(u8, num_bytes) {
var result = std.BoundedArray(u8, num_bytes){};
try self.readIntoBoundedBytes(num_bytes, &result);
return result;
}
/// Reads a native-endian integer /// Reads a native-endian integer
pub fn readIntNative(self: Self, comptime T: type) !T { pub fn readIntNative(self: Self, comptime T: type) !T {
const bytes = try self.readBytesNoEof((@typeInfo(T).Int.bits + 7) / 8); const bytes = try self.readBytesNoEof((@typeInfo(T).Int.bits + 7) / 8);

View File

@ -317,7 +317,7 @@ fn test_write_leb128(value: anytype) !void {
const bytes_needed = bn: { const bytes_needed = bn: {
if (@typeInfo(T).Int.bits <= 7) break :bn @as(u16, 1); if (@typeInfo(T).Int.bits <= 7) break :bn @as(u16, 1);
const unused_bits = if (value < 0) @clz(T, ~value) else @clz(T, value); const unused_bits = if (value < 0) @clz(~value) else @clz(value);
const used_bits: u16 = (@typeInfo(T).Int.bits - unused_bits) + @boolToInt(t_signed); const used_bits: u16 = (@typeInfo(T).Int.bits - unused_bits) + @boolToInt(t_signed);
if (used_bits <= 7) break :bn @as(u16, 1); if (used_bits <= 7) break :bn @as(u16, 1);
break :bn ((used_bits + 6) / 7); break :bn ((used_bits + 6) / 7);

View File

@ -1146,7 +1146,7 @@ pub fn ceilPowerOfTwoPromote(comptime T: type, value: T) std.meta.Int(@typeInfo(
assert(value != 0); assert(value != 0);
const PromotedType = std.meta.Int(@typeInfo(T).Int.signedness, @typeInfo(T).Int.bits + 1); const PromotedType = std.meta.Int(@typeInfo(T).Int.signedness, @typeInfo(T).Int.bits + 1);
const ShiftType = std.math.Log2Int(PromotedType); const ShiftType = std.math.Log2Int(PromotedType);
return @as(PromotedType, 1) << @intCast(ShiftType, @typeInfo(T).Int.bits - @clz(T, value - 1)); return @as(PromotedType, 1) << @intCast(ShiftType, @typeInfo(T).Int.bits - @clz(value - 1));
} }
/// Returns the next power of two (if the value is not already a power of two). /// 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) {
if (@typeInfo(T) != .Int or @typeInfo(T).Int.signedness != .unsigned) if (@typeInfo(T) != .Int or @typeInfo(T).Int.signedness != .unsigned)
@compileError("log2_int requires an unsigned integer, found " ++ @typeName(T)); @compileError("log2_int requires an unsigned integer, found " ++ @typeName(T));
assert(x != 0); assert(x != 0);
return @intCast(Log2Int(T), @typeInfo(T).Int.bits - 1 - @clz(T, x)); return @intCast(Log2Int(T), @typeInfo(T).Int.bits - 1 - @clz(x));
} }
/// Return the log base 2 of integer value x, rounding up to the /// Return the log base 2 of integer value x, rounding up to the
@ -1548,7 +1548,7 @@ test "boolMask" {
} }
/// Return the mod of `num` with the smallest integer type /// Return the mod of `num` with the smallest integer type
pub fn comptimeMod(num: anytype, denom: comptime_int) IntFittingRange(0, denom - 1) { pub fn comptimeMod(num: anytype, comptime denom: comptime_int) IntFittingRange(0, denom - 1) {
return @intCast(IntFittingRange(0, denom - 1), @mod(num, denom)); return @intCast(IntFittingRange(0, denom - 1), @mod(num, denom));
} }

View File

@ -887,7 +887,7 @@ pub const Mutable = struct {
var sum: Limb = 0; var sum: Limb = 0;
for (r.limbs[0..r.len]) |limb| { for (r.limbs[0..r.len]) |limb| {
sum += @popCount(Limb, limb); sum += @popCount(limb);
} }
r.set(sum); r.set(sum);
} }
@ -1520,7 +1520,7 @@ pub const Mutable = struct {
) void { ) void {
// 0. // 0.
// Normalize so that y[t] > b/2 // Normalize so that y[t] > b/2
const lz = @clz(Limb, y.limbs[y.len - 1]); const lz = @clz(y.limbs[y.len - 1]);
const norm_shift = if (lz == 0 and y.toConst().isOdd()) const norm_shift = if (lz == 0 and y.toConst().isOdd())
limb_bits // Force an extra limb so that y is even. limb_bits // Force an extra limb so that y is even.
else else
@ -1917,7 +1917,7 @@ pub const Const = struct {
/// Returns the number of bits required to represent the absolute value of an integer. /// Returns the number of bits required to represent the absolute value of an integer.
pub fn bitCountAbs(self: Const) usize { pub fn bitCountAbs(self: Const) usize {
return (self.limbs.len - 1) * limb_bits + (limb_bits - @clz(Limb, self.limbs[self.limbs.len - 1])); return (self.limbs.len - 1) * limb_bits + (limb_bits - @clz(self.limbs[self.limbs.len - 1]));
} }
/// Returns the number of bits required to represent the integer in twos-complement form. /// Returns the number of bits required to represent the integer in twos-complement form.
@ -1936,9 +1936,9 @@ pub const Const = struct {
if (!self.positive) block: { if (!self.positive) block: {
bits += 1; bits += 1;
if (@popCount(Limb, self.limbs[self.limbs.len - 1]) == 1) { if (@popCount(self.limbs[self.limbs.len - 1]) == 1) {
for (self.limbs[0 .. self.limbs.len - 1]) |limb| { for (self.limbs[0 .. self.limbs.len - 1]) |limb| {
if (@popCount(Limb, limb) != 0) { if (@popCount(limb) != 0) {
break :block; break :block;
} }
} }
@ -3895,8 +3895,8 @@ fn llpow(r: []Limb, a: []const Limb, b: u32, tmp_limbs: []Limb) void {
// The initial assignment makes the result end in `r` so an extra memory // The initial assignment makes the result end in `r` so an extra memory
// copy is saved, each 1 flips the index twice so it's only the zeros that // copy is saved, each 1 flips the index twice so it's only the zeros that
// matter. // matter.
const b_leading_zeros = @clz(u32, b); const b_leading_zeros = @clz(b);
const exp_zeros = @popCount(u32, ~b) - b_leading_zeros; const exp_zeros = @popCount(~b) - b_leading_zeros;
if (exp_zeros & 1 != 0) { if (exp_zeros & 1 != 0) {
tmp1 = tmp_limbs; tmp1 = tmp_limbs;
tmp2 = r; tmp2 = r;

View File

@ -8,7 +8,7 @@ inline fn mantissaOne(comptime T: type) comptime_int {
} }
/// Creates floating point type T from an unbiased exponent and raw mantissa. /// Creates floating point type T from an unbiased exponent and raw mantissa.
inline fn reconstructFloat(comptime T: type, exponent: comptime_int, mantissa: comptime_int) T { inline fn reconstructFloat(comptime T: type, comptime exponent: comptime_int, comptime mantissa: comptime_int) T {
const TBits = @Type(.{ .Int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } }); const TBits = @Type(.{ .Int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } });
const biased_exponent = @as(TBits, exponent + floatExponentMax(T)); const biased_exponent = @as(TBits, exponent + floatExponentMax(T));
return @bitCast(T, (biased_exponent << floatMantissaBits(T)) | @as(TBits, mantissa)); return @bitCast(T, (biased_exponent << floatMantissaBits(T)) | @as(TBits, mantissa));

View File

@ -267,7 +267,7 @@ pub fn zeroes(comptime T: type) T {
return null; return null;
}, },
.Struct => |struct_info| { .Struct => |struct_info| {
if (@sizeOf(T) == 0) return T{}; if (@sizeOf(T) == 0) return undefined;
if (struct_info.layout == .Extern) { if (struct_info.layout == .Extern) {
var item: T = undefined; var item: T = undefined;
set(u8, asBytes(&item), 0); set(u8, asBytes(&item), 0);
@ -424,6 +424,9 @@ test "zeroes" {
comptime var comptime_union = zeroes(C_union); comptime var comptime_union = zeroes(C_union);
try testing.expectEqual(@as(u8, 0), comptime_union.a); try testing.expectEqual(@as(u8, 0), comptime_union.a);
// Ensure zero sized struct with fields is initialized correctly.
_ = zeroes(struct { handle: void });
} }
/// Initializes all fields of the struct with their default value, or zero values if no default value is present. /// 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
/// This function cannot fail and cannot cause undefined behavior. /// This function cannot fail and cannot cause undefined behavior.
/// Assumes the endianness of memory is foreign, so it must byte-swap. /// Assumes the endianness of memory is foreign, so it must byte-swap.
pub fn readIntForeign(comptime T: type, bytes: *const [@divExact(@typeInfo(T).Int.bits, 8)]u8) T { pub fn readIntForeign(comptime T: type, bytes: *const [@divExact(@typeInfo(T).Int.bits, 8)]u8) T {
return @byteSwap(T, readIntNative(T, bytes)); return @byteSwap(readIntNative(T, bytes));
} }
pub const readIntLittle = switch (native_endian) { pub const readIntLittle = switch (native_endian) {
@ -1345,7 +1348,7 @@ pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T {
/// The bit count of T must be evenly divisible by 8. /// The bit count of T must be evenly divisible by 8.
/// Assumes the endianness of memory is foreign, so it must byte-swap. /// Assumes the endianness of memory is foreign, so it must byte-swap.
pub fn readIntSliceForeign(comptime T: type, bytes: []const u8) T { pub fn readIntSliceForeign(comptime T: type, bytes: []const u8) T {
return @byteSwap(T, readIntSliceNative(T, bytes)); return @byteSwap(readIntSliceNative(T, bytes));
} }
pub const readIntSliceLittle = switch (native_endian) { pub const readIntSliceLittle = switch (native_endian) {
@ -1427,7 +1430,7 @@ pub fn writeIntNative(comptime T: type, buf: *[(@typeInfo(T).Int.bits + 7) / 8]u
/// the integer bit width must be divisible by 8. /// the integer bit width must be divisible by 8.
/// This function stores in foreign endian, which means it does a @byteSwap first. /// This function stores in foreign endian, which means it does a @byteSwap first.
pub fn writeIntForeign(comptime T: type, buf: *[@divExact(@typeInfo(T).Int.bits, 8)]u8, value: T) void { pub fn writeIntForeign(comptime T: type, buf: *[@divExact(@typeInfo(T).Int.bits, 8)]u8, value: T) void {
writeIntNative(T, buf, @byteSwap(T, value)); writeIntNative(T, buf, @byteSwap(value));
} }
pub const writeIntLittle = switch (native_endian) { pub const writeIntLittle = switch (native_endian) {
@ -1572,7 +1575,7 @@ pub const bswapAllFields = @compileError("bswapAllFields has been renamed to byt
pub fn byteSwapAllFields(comptime S: type, ptr: *S) void { pub fn byteSwapAllFields(comptime S: type, ptr: *S) void {
if (@typeInfo(S) != .Struct) @compileError("byteSwapAllFields expects a struct as the first argument"); if (@typeInfo(S) != .Struct) @compileError("byteSwapAllFields expects a struct as the first argument");
inline for (std.meta.fields(S)) |f| { inline for (std.meta.fields(S)) |f| {
@field(ptr, f.name) = @byteSwap(f.field_type, @field(ptr, f.name)); @field(ptr, f.name) = @byteSwap(@field(ptr, f.name));
} }
} }
@ -2749,14 +2752,14 @@ test "replaceOwned" {
pub fn littleToNative(comptime T: type, x: T) T { pub fn littleToNative(comptime T: type, x: T) T {
return switch (native_endian) { return switch (native_endian) {
.Little => x, .Little => x,
.Big => @byteSwap(T, x), .Big => @byteSwap(x),
}; };
} }
/// Converts a big-endian integer to host endianness. /// Converts a big-endian integer to host endianness.
pub fn bigToNative(comptime T: type, x: T) T { pub fn bigToNative(comptime T: type, x: T) T {
return switch (native_endian) { return switch (native_endian) {
.Little => @byteSwap(T, x), .Little => @byteSwap(x),
.Big => x, .Big => x,
}; };
} }
@ -2781,14 +2784,14 @@ pub fn nativeTo(comptime T: type, x: T, desired_endianness: Endian) T {
pub fn nativeToLittle(comptime T: type, x: T) T { pub fn nativeToLittle(comptime T: type, x: T) T {
return switch (native_endian) { return switch (native_endian) {
.Little => x, .Little => x,
.Big => @byteSwap(T, x), .Big => @byteSwap(x),
}; };
} }
/// Converts an integer which has host endianness to big endian. /// Converts an integer which has host endianness to big endian.
pub fn nativeToBig(comptime T: type, x: T) T { pub fn nativeToBig(comptime T: type, x: T) T {
return switch (native_endian) { return switch (native_endian) {
.Little => @byteSwap(T, x), .Little => @byteSwap(x),
.Big => x, .Big => x,
}; };
} }
@ -2800,7 +2803,7 @@ pub fn nativeToBig(comptime T: type, x: T) T {
/// - The delta required to align the pointer is not a multiple of the pointee's /// - The delta required to align the pointer is not a multiple of the pointee's
/// type. /// type.
pub fn alignPointerOffset(ptr: anytype, align_to: u29) ?usize { pub fn alignPointerOffset(ptr: anytype, align_to: u29) ?usize {
assert(align_to != 0 and @popCount(u29, align_to) == 1); assert(align_to != 0 and @popCount(align_to) == 1);
const T = @TypeOf(ptr); const T = @TypeOf(ptr);
const info = @typeInfo(T); const info = @typeInfo(T);
@ -3249,13 +3252,13 @@ test "sliceAsBytes preserves pointer attributes" {
try testing.expectEqual(in.alignment, out.alignment); try testing.expectEqual(in.alignment, out.alignment);
} }
/// Round an address up to the nearest aligned address /// Round an address up to the next (or current) aligned address.
/// The alignment must be a power of 2 and greater than 0. /// The alignment must be a power of 2 and greater than 0.
pub fn alignForward(addr: usize, alignment: usize) usize { pub fn alignForward(addr: usize, alignment: usize) usize {
return alignForwardGeneric(usize, addr, alignment); return alignForwardGeneric(usize, addr, alignment);
} }
/// Round an address up to the nearest aligned address /// Round an address up to the next (or current) aligned address.
/// The alignment must be a power of 2 and greater than 0. /// The alignment must be a power of 2 and greater than 0.
pub fn alignForwardGeneric(comptime T: type, addr: T, alignment: T) T { pub fn alignForwardGeneric(comptime T: type, addr: T, alignment: T) T {
return alignBackwardGeneric(T, addr + (alignment - 1), alignment); return alignBackwardGeneric(T, addr + (alignment - 1), alignment);
@ -3287,25 +3290,25 @@ test "alignForward" {
try testing.expect(alignForward(17, 8) == 24); try testing.expect(alignForward(17, 8) == 24);
} }
/// Round an address up to the previous aligned address /// Round an address down to the previous (or current) aligned address.
/// Unlike `alignBackward`, `alignment` can be any positive number, not just a power of 2. /// Unlike `alignBackward`, `alignment` can be any positive number, not just a power of 2.
pub fn alignBackwardAnyAlign(i: usize, alignment: usize) usize { pub fn alignBackwardAnyAlign(i: usize, alignment: usize) usize {
if (@popCount(usize, alignment) == 1) if (@popCount(alignment) == 1)
return alignBackward(i, alignment); return alignBackward(i, alignment);
assert(alignment != 0); assert(alignment != 0);
return i - @mod(i, alignment); return i - @mod(i, alignment);
} }
/// Round an address up to the previous aligned address /// Round an address down to the previous (or current) aligned address.
/// The alignment must be a power of 2 and greater than 0. /// The alignment must be a power of 2 and greater than 0.
pub fn alignBackward(addr: usize, alignment: usize) usize { pub fn alignBackward(addr: usize, alignment: usize) usize {
return alignBackwardGeneric(usize, addr, alignment); return alignBackwardGeneric(usize, addr, alignment);
} }
/// Round an address up to the previous aligned address /// Round an address down to the previous (or current) aligned address.
/// The alignment must be a power of 2 and greater than 0. /// The alignment must be a power of 2 and greater than 0.
pub fn alignBackwardGeneric(comptime T: type, addr: T, alignment: T) T { pub fn alignBackwardGeneric(comptime T: type, addr: T, alignment: T) T {
assert(@popCount(T, alignment) == 1); assert(@popCount(alignment) == 1);
// 000010000 // example alignment // 000010000 // example alignment
// 000001111 // subtract 1 // 000001111 // subtract 1
// 111110000 // binary not // 111110000 // binary not
@ -3315,11 +3318,11 @@ pub fn alignBackwardGeneric(comptime T: type, addr: T, alignment: T) T {
/// Returns whether `alignment` is a valid alignment, meaning it is /// Returns whether `alignment` is a valid alignment, meaning it is
/// a positive power of 2. /// a positive power of 2.
pub fn isValidAlign(alignment: u29) bool { pub fn isValidAlign(alignment: u29) bool {
return @popCount(u29, alignment) == 1; return @popCount(alignment) == 1;
} }
pub fn isAlignedAnyAlign(i: usize, alignment: usize) bool { pub fn isAlignedAnyAlign(i: usize, alignment: usize) bool {
if (@popCount(usize, alignment) == 1) if (@popCount(alignment) == 1)
return isAligned(i, alignment); return isAligned(i, alignment);
assert(alignment != 0); assert(alignment != 0);
return 0 == @mod(i, alignment); return 0 == @mod(i, alignment);

View File

@ -764,7 +764,7 @@ const TagPayloadType = TagPayload;
///Given a tagged union type, and an enum, return the type of the union ///Given a tagged union type, and an enum, return the type of the union
/// field corresponding to the enum tag. /// field corresponding to the enum tag.
pub fn TagPayload(comptime U: type, tag: Tag(U)) type { pub fn TagPayload(comptime U: type, comptime tag: Tag(U)) type {
comptime debug.assert(trait.is(.Union)(U)); comptime debug.assert(trait.is(.Union)(U));
const info = @typeInfo(U).Union; const info = @typeInfo(U).Union;
@ -1024,28 +1024,13 @@ pub fn ArgsTuple(comptime Function: type) type {
if (function_info.is_var_args) if (function_info.is_var_args)
@compileError("Cannot create ArgsTuple for variadic function"); @compileError("Cannot create ArgsTuple for variadic function");
var argument_field_list: [function_info.args.len]std.builtin.Type.StructField = undefined; var argument_field_list: [function_info.args.len]type = undefined;
inline for (function_info.args) |arg, i| { inline for (function_info.args) |arg, i| {
const T = arg.arg_type.?; const T = arg.arg_type.?;
@setEvalBranchQuota(10_000); argument_field_list[i] = T;
var num_buf: [128]u8 = undefined;
argument_field_list[i] = .{
.name = std.fmt.bufPrint(&num_buf, "{d}", .{i}) catch unreachable,
.field_type = T,
.default_value = null,
.is_comptime = false,
.alignment = if (@sizeOf(T) > 0) @alignOf(T) else 0,
};
} }
return @Type(.{ return CreateUniqueTuple(argument_field_list.len, argument_field_list);
.Struct = .{
.is_tuple = true,
.layout = .Auto,
.decls = &.{},
.fields = &argument_field_list,
},
});
} }
/// For a given anonymous list of types, returns a new tuple type /// For a given anonymous list of types, returns a new tuple type
@ -1056,6 +1041,10 @@ pub fn ArgsTuple(comptime Function: type) type {
/// - `Tuple(&[_]type {f32})` `tuple { f32 }` /// - `Tuple(&[_]type {f32})` `tuple { f32 }`
/// - `Tuple(&[_]type {f32,u32})` `tuple { f32, u32 }` /// - `Tuple(&[_]type {f32,u32})` `tuple { f32, u32 }`
pub fn Tuple(comptime types: []const type) type { pub fn Tuple(comptime types: []const type) type {
return CreateUniqueTuple(types.len, types[0..types.len].*);
}
fn CreateUniqueTuple(comptime N: comptime_int, comptime types: [N]type) type {
var tuple_fields: [types.len]std.builtin.Type.StructField = undefined; var tuple_fields: [types.len]std.builtin.Type.StructField = undefined;
inline for (types) |T, i| { inline for (types) |T, i| {
@setEvalBranchQuota(10_000); @setEvalBranchQuota(10_000);
@ -1118,6 +1107,32 @@ test "Tuple" {
TupleTester.assertTuple(.{ u32, f16, []const u8, void }, Tuple(&[_]type{ u32, f16, []const u8, void })); TupleTester.assertTuple(.{ u32, f16, []const u8, void }, Tuple(&[_]type{ u32, f16, []const u8, void }));
} }
test "Tuple deduplication" {
const T1 = std.meta.Tuple(&.{ u32, f32, i8 });
const T2 = std.meta.Tuple(&.{ u32, f32, i8 });
const T3 = std.meta.Tuple(&.{ u32, f32, i7 });
if (T1 != T2) {
@compileError("std.meta.Tuple doesn't deduplicate tuple types.");
}
if (T1 == T3) {
@compileError("std.meta.Tuple fails to generate different types.");
}
}
test "ArgsTuple forwarding" {
const T1 = std.meta.Tuple(&.{ u32, f32, i8 });
const T2 = std.meta.ArgsTuple(fn (u32, f32, i8) void);
const T3 = std.meta.ArgsTuple(fn (u32, f32, i8) callconv(.C) noreturn);
if (T1 != T2) {
@compileError("std.meta.ArgsTuple produces different types than std.meta.Tuple");
}
if (T1 != T3) {
@compileError("std.meta.ArgsTuple produces different types for the same argument lists.");
}
}
/// TODO: https://github.com/ziglang/zig/issues/425 /// TODO: https://github.com/ziglang/zig/issues/425
pub fn globalOption(comptime name: []const u8, comptime T: type) ?T { pub fn globalOption(comptime name: []const u8, comptime T: type) ?T {
if (!@hasDecl(root, name)) if (!@hasDecl(root, name))
@ -1134,3 +1149,27 @@ test "isError" {
try std.testing.expect(isError(math.absInt(@as(i8, -128)))); try std.testing.expect(isError(math.absInt(@as(i8, -128))));
try std.testing.expect(!isError(math.absInt(@as(i8, -127)))); try std.testing.expect(!isError(math.absInt(@as(i8, -127))));
} }
/// This function returns a function pointer for a given function signature.
/// It's a helper to make code compatible to both stage1 and stage2.
///
/// **WARNING:** This function is deprecated and will be removed together with stage1.
pub fn FnPtr(comptime Fn: type) type {
return if (@import("builtin").zig_backend != .stage1)
*const Fn
else
Fn;
}
test "FnPtr" {
var func: FnPtr(fn () i64) = undefined;
// verify that we can perform runtime exchange
// and not have a function body in stage2:
func = std.time.timestamp;
_ = func();
func = std.time.milliTimestamp;
_ = func();
}

View File

@ -459,7 +459,7 @@ pub fn MultiArrayList(comptime S: type) type {
return self.bytes[0..capacityInBytes(self.capacity)]; return self.bytes[0..capacityInBytes(self.capacity)];
} }
fn FieldType(field: Field) type { fn FieldType(comptime field: Field) type {
return meta.fieldInfo(S, field).field_type; return meta.fieldInfo(S, field).field_type;
} }

View File

@ -475,10 +475,9 @@ pub fn abort() noreturn {
// Install default handler so that the tkill below will terminate. // Install default handler so that the tkill below will terminate.
const sigact = Sigaction{ const sigact = Sigaction{
.handler = .{ .sigaction = SIG.DFL }, .handler = .{ .handler = SIG.DFL },
.mask = undefined, .mask = empty_sigset,
.flags = undefined, .flags = 0,
.restorer = undefined,
}; };
sigaction(SIG.ABRT, &sigact, null) catch |err| switch (err) { sigaction(SIG.ABRT, &sigact, null) catch |err| switch (err) {
error.OperationNotSupported => unreachable, error.OperationNotSupported => unreachable,
@ -953,6 +952,10 @@ pub const WriteError = error{
OperationAborted, OperationAborted,
NotOpenForWriting, NotOpenForWriting,
/// The process cannot access the file because another process has locked
/// a portion of the file. Windows-only.
LockViolation,
/// This error occurs when no global event loop is configured, /// This error occurs when no global event loop is configured,
/// and reading from the file descriptor would block. /// and reading from the file descriptor would block.
WouldBlock, WouldBlock,
@ -2648,6 +2651,7 @@ pub fn renameatW(
.creation = windows.FILE_OPEN, .creation = windows.FILE_OPEN,
.io_mode = .blocking, .io_mode = .blocking,
.filter = .any, // This function is supposed to rename both files and directories. .filter = .any, // This function is supposed to rename both files and directories.
.follow_symlinks = false,
}) catch |err| switch (err) { }) catch |err| switch (err) {
error.WouldBlock => unreachable, // Not possible without `.share_access_nonblocking = true`. error.WouldBlock => unreachable, // Not possible without `.share_access_nonblocking = true`.
else => |e| return e, else => |e| return e,
@ -5443,11 +5447,7 @@ pub fn toPosixPath(file_path: []const u8) ![MAX_PATH_BYTES - 1:0]u8 {
/// if this happens the fix is to add the error code to the corresponding /// if this happens the fix is to add the error code to the corresponding
/// switch expression, possibly introduce a new error in the error set, and /// switch expression, possibly introduce a new error in the error set, and
/// send a patch to Zig. /// send a patch to Zig.
/// The self-hosted compiler is not fully capable of handle the related code. pub const unexpected_error_tracing = (builtin.zig_backend == .stage1 or builtin.zig_backend == .stage2_llvm) and builtin.mode == .Debug;
/// Until then, unexpected error tracing is disabled for the self-hosted compiler.
/// TODO remove this once self-hosted is capable enough to handle printing and
/// stack trace dumping.
pub const unexpected_error_tracing = builtin.zig_backend == .stage1 and builtin.mode == .Debug;
pub const UnexpectedError = error{ pub const UnexpectedError = error{
/// The Operating System returned an undocumented error code. /// The Operating System returned an undocumented error code.
@ -6251,7 +6251,7 @@ pub const CopyFileRangeError = error{
NoSpaceLeft, NoSpaceLeft,
Unseekable, Unseekable,
PermissionDenied, PermissionDenied,
FileBusy, SwapFile,
} || PReadError || PWriteError || UnexpectedError; } || PReadError || PWriteError || UnexpectedError;
var has_copy_file_range_syscall = std.atomic.Atomic(bool).init(true); var 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
.NOSPC => return error.NoSpaceLeft, .NOSPC => return error.NoSpaceLeft,
.OVERFLOW => return error.Unseekable, .OVERFLOW => return error.Unseekable,
.PERM => return error.PermissionDenied, .PERM => return error.PermissionDenied,
.TXTBSY => return error.FileBusy, .TXTBSY => return error.SwapFile,
// these may not be regular files, try fallback // these may not be regular files, try fallback
.INVAL => {}, .INVAL => {},
// support for cross-filesystem copy added in Linux 5.3, use fallback // support for cross-filesystem copy added in Linux 5.3, use fallback

View File

@ -1945,9 +1945,9 @@ pub const SIG = if (is_mips) struct {
pub const SYS = 31; pub const SYS = 31;
pub const UNUSED = SIG.SYS; pub const UNUSED = SIG.SYS;
pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize)); pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0); pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1); pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
} else if (is_sparc) struct { } else if (is_sparc) struct {
pub const BLOCK = 1; pub const BLOCK = 1;
pub const UNBLOCK = 2; pub const UNBLOCK = 2;
@ -1989,9 +1989,9 @@ pub const SIG = if (is_mips) struct {
pub const PWR = LOST; pub const PWR = LOST;
pub const IO = SIG.POLL; pub const IO = SIG.POLL;
pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize)); pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0); pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1); pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
} else struct { } else struct {
pub const BLOCK = 0; pub const BLOCK = 0;
pub const UNBLOCK = 1; pub const UNBLOCK = 1;
@ -2032,9 +2032,9 @@ pub const SIG = if (is_mips) struct {
pub const SYS = 31; pub const SYS = 31;
pub const UNUSED = SIG.SYS; pub const UNUSED = SIG.SYS;
pub const ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize)); pub const ERR = @intToPtr(?Sigaction.handler_fn, maxInt(usize));
pub const DFL = @intToPtr(?Sigaction.sigaction_fn, 0); pub const DFL = @intToPtr(?Sigaction.handler_fn, 0);
pub const IGN = @intToPtr(?Sigaction.sigaction_fn, 1); pub const IGN = @intToPtr(?Sigaction.handler_fn, 1);
}; };
pub const kernel_rwf = u32; pub const kernel_rwf = u32;
@ -3377,7 +3377,7 @@ pub const cpu_count_t = std.meta.Int(.unsigned, std.math.log2(CPU_SETSIZE * 8));
pub fn CPU_COUNT(set: cpu_set_t) cpu_count_t { pub fn CPU_COUNT(set: cpu_set_t) cpu_count_t {
var sum: cpu_count_t = 0; var sum: cpu_count_t = 0;
for (set) |x| { for (set) |x| {
sum += @popCount(usize, x); sum += @popCount(x);
} }
return sum; return sum;
} }

View File

@ -458,7 +458,7 @@ pub const Insn = packed struct {
else else
ImmOrReg{ .imm = src }; ImmOrReg{ .imm = src };
const src_type = switch (imm_or_reg) { const src_type: u8 = switch (imm_or_reg) {
.imm => K, .imm => K,
.reg => X, .reg => X,
}; };

View File

@ -3485,6 +3485,7 @@ pub const RiscV64 = enum(usize) {
landlock_create_ruleset = 444, landlock_create_ruleset = 444,
landlock_add_rule = 445, landlock_add_rule = 445,
landlock_restrict_self = 446, landlock_restrict_self = 446,
memfd_secret = 447,
process_mrelease = 448, process_mrelease = 448,
futex_waitv = 449, futex_waitv = 449,
set_mempolicy_home_node = 450, set_mempolicy_home_node = 450,

View File

@ -1,7 +1,7 @@
const std = @import("../std.zig"); const std = @import("../std.zig");
const builtin = @import("builtin"); const builtin = @import("builtin");
pub const syscall_bits = switch (builtin.stage2_arch) { pub const syscall_bits = switch (builtin.cpu.arch) {
.x86_64 => @import("plan9/x86_64.zig"), .x86_64 => @import("plan9/x86_64.zig"),
else => @compileError("more plan9 syscall implementations (needs more inline asm in stage2"), else => @compileError("more plan9 syscall implementations (needs more inline asm in stage2"),
}; };

View File

@ -785,7 +785,7 @@ test "sigaction" {
try testing.expect(signal_test_failed == false); try testing.expect(signal_test_failed == false);
// Check if the handler has been correctly reset to SIG_DFL // Check if the handler has been correctly reset to SIG_DFL
try os.sigaction(os.SIG.USR1, null, &old_sa); try os.sigaction(os.SIG.USR1, null, &old_sa);
try testing.expectEqual(os.SIG.DFL, old_sa.handler.sigaction); try testing.expectEqual(os.SIG.DFL, old_sa.handler.handler);
} }
test "dup & dup2" { test "dup & dup2" {

View File

@ -55,9 +55,9 @@ pub const Guid = extern struct {
if (f.len == 0) { if (f.len == 0) {
const fmt = std.fmt.fmtSliceHexLower; const fmt = std.fmt.fmtSliceHexLower;
const time_low = @byteSwap(u32, self.time_low); const time_low = @byteSwap(self.time_low);
const time_mid = @byteSwap(u16, self.time_mid); const time_mid = @byteSwap(self.time_mid);
const time_high_and_version = @byteSwap(u16, self.time_high_and_version); const time_high_and_version = @byteSwap(self.time_high_and_version);
return std.fmt.format(writer, "{:0>8}-{:0>4}-{:0>4}-{:0>2}{:0>2}-{:0>12}", .{ return std.fmt.format(writer, "{:0>8}-{:0>4}-{:0>4}-{:0>2}{:0>2}-{:0>12}", .{
fmt(std.mem.asBytes(&time_low)), fmt(std.mem.asBytes(&time_low)),

Some files were not shown because too many files have changed in this diff Show More