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

This commit is contained in:
Andrew Kelley 2019-02-28 09:19:18 -05:00
commit 2dcf1a2392
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
133 changed files with 11476 additions and 4974 deletions

View File

@ -4,7 +4,7 @@ packages:
- ninja - ninja
- llvm70 - llvm70
sources: sources:
- https://github.com/ziglang/zig.git - https://github.com/ziglang/zig
tasks: tasks:
- build: | - build: |
cd zig && mkdir build && cd build cd zig && mkdir build && cd build

6
.gitignore vendored
View File

@ -10,6 +10,6 @@
# -andrewrk # -andrewrk
zig-cache/ zig-cache/
build/ /build/
build-*/ /build-*/
docgen_tmp/ /docgen_tmp/

View File

@ -417,6 +417,7 @@ set(ZIG_SOURCES
"${CMAKE_SOURCE_DIR}/src/error.cpp" "${CMAKE_SOURCE_DIR}/src/error.cpp"
"${CMAKE_SOURCE_DIR}/src/ir.cpp" "${CMAKE_SOURCE_DIR}/src/ir.cpp"
"${CMAKE_SOURCE_DIR}/src/ir_print.cpp" "${CMAKE_SOURCE_DIR}/src/ir_print.cpp"
"${CMAKE_SOURCE_DIR}/src/libc_installation.cpp"
"${CMAKE_SOURCE_DIR}/src/link.cpp" "${CMAKE_SOURCE_DIR}/src/link.cpp"
"${CMAKE_SOURCE_DIR}/src/main.cpp" "${CMAKE_SOURCE_DIR}/src/main.cpp"
"${CMAKE_SOURCE_DIR}/src/os.cpp" "${CMAKE_SOURCE_DIR}/src/os.cpp"
@ -432,6 +433,10 @@ set(BLAKE_SOURCES
) )
set(ZIG_CPP_SOURCES set(ZIG_CPP_SOURCES
"${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp" "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp"
"${CMAKE_SOURCE_DIR}/src/zig_clang.cpp"
"${CMAKE_SOURCE_DIR}/src/zig_clang_driver.cpp"
"${CMAKE_SOURCE_DIR}/src/zig_clang_cc1_main.cpp"
"${CMAKE_SOURCE_DIR}/src/zig_clang_cc1as_main.cpp"
"${CMAKE_SOURCE_DIR}/src/windows_sdk.cpp" "${CMAKE_SOURCE_DIR}/src/windows_sdk.cpp"
) )
@ -446,10 +451,12 @@ set(ZIG_STD_FILES
"buf_set.zig" "buf_set.zig"
"buffer.zig" "buffer.zig"
"build.zig" "build.zig"
"build/fmt.zig"
"c/darwin.zig" "c/darwin.zig"
"c/freebsd.zig" "c/freebsd.zig"
"c/index.zig" "c/index.zig"
"c/linux.zig" "c/linux.zig"
"c/netbsd.zig"
"c/windows.zig" "c/windows.zig"
"coff.zig" "coff.zig"
"crypto/blake2.zig" "crypto/blake2.zig"
@ -485,6 +492,7 @@ set(ZIG_STD_FILES
"fmt/errol/index.zig" "fmt/errol/index.zig"
"fmt/errol/lookup.zig" "fmt/errol/lookup.zig"
"fmt/index.zig" "fmt/index.zig"
"fmt/parse_float.zig"
"hash/adler.zig" "hash/adler.zig"
"hash/crc.zig" "hash/crc.zig"
"hash/fnv.zig" "hash/fnv.zig"
@ -589,6 +597,8 @@ set(ZIG_STD_FILES
"os/linux/index.zig" "os/linux/index.zig"
"os/linux/vdso.zig" "os/linux/vdso.zig"
"os/linux/x86_64.zig" "os/linux/x86_64.zig"
"os/netbsd/errno.zig"
"os/netbsd/index.zig"
"os/path.zig" "os/path.zig"
"os/time.zig" "os/time.zig"
"os/uefi.zig" "os/uefi.zig"
@ -603,6 +613,7 @@ set(ZIG_STD_FILES
"os/windows/util.zig" "os/windows/util.zig"
"os/zen.zig" "os/zen.zig"
"pdb.zig" "pdb.zig"
"priority_queue.zig"
"rand/index.zig" "rand/index.zig"
"rand/ziggurat.zig" "rand/ziggurat.zig"
"segmented_list.zig" "segmented_list.zig"
@ -611,6 +622,7 @@ set(ZIG_STD_FILES
"special/bootstrap_lib.zig" "special/bootstrap_lib.zig"
"special/build_runner.zig" "special/build_runner.zig"
"special/builtin.zig" "special/builtin.zig"
"special/compiler_rt/addXf3.zig"
"special/compiler_rt/aulldiv.zig" "special/compiler_rt/aulldiv.zig"
"special/compiler_rt/aullrem.zig" "special/compiler_rt/aullrem.zig"
"special/compiler_rt/comparetf2.zig" "special/compiler_rt/comparetf2.zig"
@ -653,6 +665,7 @@ set(ZIG_STD_FILES
"special/compiler_rt/udivmodti4.zig" "special/compiler_rt/udivmodti4.zig"
"special/compiler_rt/udivti3.zig" "special/compiler_rt/udivti3.zig"
"special/compiler_rt/umodti3.zig" "special/compiler_rt/umodti3.zig"
"special/fmt_runner.zig"
"special/init-exe/build.zig" "special/init-exe/build.zig"
"special/init-exe/src/main.zig" "special/init-exe/src/main.zig"
"special/init-lib/build.zig" "special/init-lib/build.zig"
@ -906,3 +919,7 @@ foreach(file ${ZIG_STD_FILES})
get_filename_component(file_dir "${ZIG_STD_DEST}/${file}" DIRECTORY) get_filename_component(file_dir "${ZIG_STD_DEST}/${file}" DIRECTORY)
install(FILES "${CMAKE_SOURCE_DIR}/std/${file}" DESTINATION "${file_dir}") install(FILES "${CMAKE_SOURCE_DIR}/std/${file}" DESTINATION "${file_dir}")
endforeach() endforeach()
install(FILES "${CMAKE_SOURCE_DIR}/src-self-hosted/arg.zig" DESTINATION "${ZIG_STD_DEST}/special/fmt/")
install(FILES "${CMAKE_SOURCE_DIR}/src-self-hosted/main.zig" DESTINATION "${ZIG_STD_DEST}/special/fmt/")
install(FILES "${CMAKE_SOURCE_DIR}/src-self-hosted/errmsg.zig" DESTINATION "${ZIG_STD_DEST}/special/fmt/")

View File

@ -3,7 +3,7 @@
A programming language designed for robustness, optimality, and A programming language designed for robustness, optimality, and
clarity. clarity.
[ziglang.org](https://ziglang.org) [Download & Documentation](https://ziglang.org/download/)
## Feature Highlights ## Feature Highlights
@ -77,36 +77,54 @@ clarity.
- what sizes are the C integer types - what sizes are the C integer types
- C ABI calling convention for this target - C ABI calling convention for this target
- bootstrap code and default panic handler - bootstrap code and default panic handler
* `zig targets` is guaranteed to include this target.
#### Tier 4 Support #### Tier 4 Support
* Support for these targets is entirely experimental. * Support for these targets is entirely experimental.
* LLVM may have the target as an experimental target, which means that you * LLVM may have the target as an experimental target, which means that you
need to use Zig-provided binaries for the target to be available, or need to use Zig-provided binaries for the target to be available, or
build LLVM from source with special configure flags. build LLVM from source with special configure flags. `zig targets` will
display the target if it is available.
* This target may be considered deprecated by an official party,
[such as macosx/i386](https://support.apple.com/en-us/HT208436) in which
case this target will remain forever stuck in Tier 4.
* This target may only support `--emit asm` and cannot emit object files.
#### Support Table #### Support Table
| | freestanding | linux | macosx | windows | freebsd | UEFI | other | | | freestanding | linux | macosx | windows | freebsd | netbsd | UEFI | other |
|--------|--------------|--------|--------|---------|---------|--------|--------| |-------------|--------------|--------|--------|---------|---------|------- | -------|--------|
|x86_64 | Tier 2 | Tier 1 | Tier 1 | Tier 1 | Tier 2 | Tier 2 | Tier 3 | |x86_64 | Tier 2 | Tier 1 | Tier 1 | Tier 1 | Tier 2 | Tier 2 | Tier 2 | Tier 3 |
|i386 | Tier 2 | Tier 2 | Tier 2 | Tier 2 | Tier 3 | Tier 3 | Tier 3 | |i386 | Tier 2 | Tier 2 | Tier 4 | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 |
|arm | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | |arm | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 |
|arm64 | Tier 2 | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | |arm64 | Tier 2 | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 |
|bpf | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 | |avr | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | N/A | Tier 3 |
|hexagon | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 | |bpf | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | N/A | Tier 3 |
|mips | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 | |hexagon | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | N/A | Tier 3 |
|powerpc | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 | |mips | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | N/A | Tier 3 |
|r600 | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 | |powerpc | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | N/A | Tier 3 |
|amdgcn | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 | |amdgcn | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | N/A | Tier 3 |
|sparc | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 | |sparc | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | N/A | Tier 3 |
|s390x | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 | |s390x | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | N/A | Tier 3 |
|spir | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 | |lanai | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | N/A | Tier 3 |
|lanai | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | Tier 3 | |wasm32 | Tier 4 | N/A | N/A | N/A | N/A | N/A | N/A | N/A |
|wasm32 | Tier 4 | N/A | N/A | N/A | N/A | N/A | N/A | |wasm64 | Tier 4 | N/A | N/A | N/A | N/A | N/A | N/A | N/A |
|wasm64 | Tier 4 | N/A | N/A | N/A | N/A | N/A | N/A | |riscv32 | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | Tier 4 | Tier 4 |
|riscv32 | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | Tier 4 | |riscv64 | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | Tier 4 | Tier 4 |
|riscv64 | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | Tier 4 | |xcore | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 |
|nvptx | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 |
|msp430 | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 |
|r600 | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 |
|arc | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 |
|tce | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 |
|le | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 |
|amdil | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 |
|hsail | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 |
|spir | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 |
|kalimba | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 |
|shave | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 |
|renderscript | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 | N/A | Tier 4 |
## Community ## Community

View File

@ -49,13 +49,14 @@ pub fn build(b: *Builder) !void {
.c_header_files = nextValue(&index, build_info), .c_header_files = nextValue(&index, build_info),
.dia_guids_lib = nextValue(&index, build_info), .dia_guids_lib = nextValue(&index, build_info),
.llvm = undefined, .llvm = undefined,
.no_rosegment = b.option(bool, "no-rosegment", "Workaround to enable valgrind builds") orelse false,
}; };
ctx.llvm = try findLLVM(b, ctx.llvm_config_exe); ctx.llvm = try findLLVM(b, ctx.llvm_config_exe);
var test_stage2 = b.addTest("src-self-hosted/test.zig"); var test_stage2 = b.addTest("src-self-hosted/test.zig");
test_stage2.setBuildMode(builtin.Mode.Debug); test_stage2.setBuildMode(builtin.Mode.Debug);
const fmt_build_zig = b.addFmt([][]const u8{"build.zig"});
var exe = b.addExecutable("zig", "src-self-hosted/main.zig"); var exe = b.addExecutable("zig", "src-self-hosted/main.zig");
exe.setBuildMode(mode); exe.setBuildMode(mode);
@ -107,6 +108,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
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");
fmt_step.dependOn(&fmt_build_zig.step);
test_step.dependOn(tests.addPkgTests(b, test_filter, "test/stage1/behavior.zig", "behavior", "Run the behavior tests", modes)); test_step.dependOn(tests.addPkgTests(b, test_filter, "test/stage1/behavior.zig", "behavior", "Run the behavior tests", modes));
test_step.dependOn(tests.addPkgTests(b, test_filter, "std/index.zig", "std", "Run the standard library tests", modes)); test_step.dependOn(tests.addPkgTests(b, test_filter, "std/index.zig", "std", "Run the standard library tests", modes));
@ -289,8 +295,6 @@ fn nextValue(index: *usize, build_info: []const u8) []const u8 {
} }
fn configureStage2(b: *Builder, exe: var, ctx: Context) !void { fn configureStage2(b: *Builder, exe: var, ctx: Context) !void {
exe.setNoRoSegment(ctx.no_rosegment);
exe.addIncludeDir("src"); exe.addIncludeDir("src");
exe.addIncludeDir(ctx.cmake_binary_dir); exe.addIncludeDir(ctx.cmake_binary_dir);
addCppLib(b, exe, ctx.cmake_binary_dir, "zig_cpp"); addCppLib(b, exe, ctx.cmake_binary_dir, "zig_cpp");
@ -375,5 +379,4 @@ const Context = struct {
c_header_files: []const u8, c_header_files: []const u8,
dia_guids_lib: []const u8, dia_guids_lib: []const u8,
llvm: LibraryDep, llvm: LibraryDep,
no_rosegment: bool,
}; };

View File

@ -11,17 +11,28 @@ if(MSVC)
find_package(CLANG REQUIRED CONFIG) find_package(CLANG REQUIRED CONFIG)
set(CLANG_LIBRARIES set(CLANG_LIBRARIES
clangFrontendTool
clangCodeGen
clangFrontend clangFrontend
clangDriver clangDriver
clangSerialization clangSerialization
clangSema clangSema
clangStaticAnalyzerFrontend
clangStaticAnalyzerCheckers
clangStaticAnalyzerCore
clangAnalysis clangAnalysis
clangASTMatchers
clangAST clangAST
clangParse clangParse
clangSema clangSema
clangBasic clangBasic
clangEdit clangEdit
clangLex clangLex
clangARCMigrate
clangRewriteFrontend
clangRewrite
clangCrossTU
clangIndex
) )
else() else()
@ -50,17 +61,28 @@ else()
endif() endif()
endmacro(FIND_AND_ADD_CLANG_LIB) endmacro(FIND_AND_ADD_CLANG_LIB)
FIND_AND_ADD_CLANG_LIB(clangFrontendTool)
FIND_AND_ADD_CLANG_LIB(clangCodeGen)
FIND_AND_ADD_CLANG_LIB(clangFrontend) FIND_AND_ADD_CLANG_LIB(clangFrontend)
FIND_AND_ADD_CLANG_LIB(clangDriver) FIND_AND_ADD_CLANG_LIB(clangDriver)
FIND_AND_ADD_CLANG_LIB(clangSerialization) FIND_AND_ADD_CLANG_LIB(clangSerialization)
FIND_AND_ADD_CLANG_LIB(clangSema) FIND_AND_ADD_CLANG_LIB(clangSema)
FIND_AND_ADD_CLANG_LIB(clangStaticAnalyzerFrontend)
FIND_AND_ADD_CLANG_LIB(clangStaticAnalyzerCheckers)
FIND_AND_ADD_CLANG_LIB(clangStaticAnalyzerCore)
FIND_AND_ADD_CLANG_LIB(clangAnalysis) FIND_AND_ADD_CLANG_LIB(clangAnalysis)
FIND_AND_ADD_CLANG_LIB(clangASTMatchers)
FIND_AND_ADD_CLANG_LIB(clangAST) FIND_AND_ADD_CLANG_LIB(clangAST)
FIND_AND_ADD_CLANG_LIB(clangParse) FIND_AND_ADD_CLANG_LIB(clangParse)
FIND_AND_ADD_CLANG_LIB(clangSema) FIND_AND_ADD_CLANG_LIB(clangSema)
FIND_AND_ADD_CLANG_LIB(clangBasic) FIND_AND_ADD_CLANG_LIB(clangBasic)
FIND_AND_ADD_CLANG_LIB(clangEdit) FIND_AND_ADD_CLANG_LIB(clangEdit)
FIND_AND_ADD_CLANG_LIB(clangLex) FIND_AND_ADD_CLANG_LIB(clangLex)
FIND_AND_ADD_CLANG_LIB(clangARCMigrate)
FIND_AND_ADD_CLANG_LIB(clangRewriteFrontend)
FIND_AND_ADD_CLANG_LIB(clangRewrite)
FIND_AND_ADD_CLANG_LIB(clangCrossTU)
FIND_AND_ADD_CLANG_LIB(clangIndex)
endif() endif()
include(FindPackageHandleStandardArgs) include(FindPackageHandleStandardArgs)

View File

@ -916,6 +916,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
std.zig.Token.Id.AngleBracketAngleBracketRightEqual, std.zig.Token.Id.AngleBracketAngleBracketRightEqual,
std.zig.Token.Id.Tilde, std.zig.Token.Id.Tilde,
std.zig.Token.Id.BracketStarBracket, std.zig.Token.Id.BracketStarBracket,
std.zig.Token.Id.BracketStarCBracket,
=> try writeEscaped(out, src[token.start..token.end]), => try writeEscaped(out, src[token.start..token.end]),
std.zig.Token.Id.Invalid => return parseError( std.zig.Token.Id.Invalid => return parseError(
@ -1104,14 +1105,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
}, },
} }
if (code.target_windows) { if (code.target_windows) {
try test_args.appendSlice([][]const u8{ try test_args.appendSlice([][]const u8{ "-target", "x86_64-windows" });
"--target-os",
"windows",
"--target-arch",
"x86_64",
"--target-environ",
"msvc",
});
} }
const result = exec(allocator, &env_map, test_args.toSliceConst()) catch return parseError(tokenizer, code.source_token, "test failed"); const result = exec(allocator, &env_map, test_args.toSliceConst()) catch return parseError(tokenizer, code.source_token, "test failed");
const escaped_stderr = try escapeHtml(allocator, result.stderr); const escaped_stderr = try escapeHtml(allocator, result.stderr);

View File

@ -8,13 +8,7 @@
body{ body{
background-color:#111; background-color:#111;
color: #bbb; color: #bbb;
font-family: system-ui, font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
/* Fallbacks for browsers that don't support system-ui */
/* https://caniuse.com/#search=system-ui */
-apple-system, /* iOS and macOS */
Roboto, /* Android */
"Segoe UI", /* Windows */
sans-serif;
} }
a { a {
color: #88f; color: #88f;
@ -243,8 +237,9 @@ const Timestamp = struct {
{#header_close#} {#header_close#}
{#header_open|Values#} {#header_open|Values#}
{#code_begin|exe|values#} {#code_begin|exe|values#}
const std = @import("std"); // Top-level declarations are order-independent:
const warn = std.debug.warn; const warn = std.debug.warn;
const std = @import("std");
const os = std.os; const os = std.os;
const assert = std.debug.assert; const assert = std.debug.assert;
@ -706,15 +701,21 @@ fn divide(a: i32, b: i32) i32 {
{#code_end#} {#code_end#}
<p> <p>
In this function, values {#syntax#}a{#endsyntax#} and {#syntax#}b{#endsyntax#} are known only at runtime, In this function, values {#syntax#}a{#endsyntax#} and {#syntax#}b{#endsyntax#} are known only at runtime,
and thus this division operation is vulnerable to both integer overflow and and thus this division operation is vulnerable to both {#link|Integer Overflow#} and
division by zero. {#link|Division by Zero#}.
</p> </p>
<p> <p>
Operators such as {#syntax#}+{#endsyntax#} and {#syntax#}-{#endsyntax#} cause undefined behavior on Operators such as {#syntax#}+{#endsyntax#} and {#syntax#}-{#endsyntax#} cause undefined behavior on
integer overflow. Also available are operations such as {#syntax#}+%{#endsyntax#} and integer overflow. Also available are operations such as {#syntax#}+%{#endsyntax#} and
{#syntax#}-%{#endsyntax#} which are defined to have wrapping arithmetic on all targets. {#syntax#}-%{#endsyntax#} which are defined to have wrapping arithmetic on all targets.
</p> </p>
{#see_also|Integer Overflow|Division by Zero|Wrapping Operations#} <p>
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
{#syntax#}i7{#endsyntax#} refers to a signed 7-bit integer. The maximum allowed bit-width of an
integer type is {#syntax#}65535{#endsyntax#}.
</p>
{#see_also|Wrapping Operations#}
{#header_close#} {#header_close#}
{#header_close#} {#header_close#}
{#header_open|Floats#} {#header_open|Floats#}
@ -1694,7 +1695,7 @@ test "comptime @intToPtr" {
} }
} }
{#code_end#} {#code_end#}
{#see_also|Optional Pointers#} {#see_also|Optional Pointers|@intToPtr|@ptrToInt#}
{#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#}.
@ -1823,7 +1824,9 @@ fn foo(bytes: []u8) u32 {
} }
{#code_end#} {#code_end#}
{#header_close#} {#header_close#}
{#see_also|C Pointers|Pointers to Zero Bit Types#}
{#header_close#} {#header_close#}
{#header_open|Slices#} {#header_open|Slices#}
{#code_begin|test_safety|index out of bounds#} {#code_begin|test_safety|index out of bounds#}
const assert = @import("std").debug.assert; const assert = @import("std").debug.assert;
@ -2043,14 +2046,211 @@ test "linked list" {
assert(list2.first.?.data == 1234); assert(list2.first.?.data == 1234);
} }
{#code_end#} {#code_end#}
{#header_open|extern struct#}
<p>An {#syntax#}extern struct{#endsyntax#} has in-memory layout guaranteed to match the
C ABI for the target.</p>
{#see_also|extern union|extern enum#}
{#header_close#}
{#header_open|packed struct#} {#header_open|packed struct#}
<p>{#syntax#}packed{#endsyntax#} structs have guaranteed in-memory layout.</p> <p>
<p>TODO bit fields</p> Unlike normal structs, {#syntax#}packed{#endsyntax#} structs have guaranteed in-memory layout:
<p>TODO alignment</p> </p>
<p>TODO endianness</p> <ul>
<p>TODO @bitOffsetOf and @byteOffsetOf</p> <li>Fields remain in the order declared.</li>
<p>TODO mention how volatile loads and stores of bit packed fields could be more efficient when <li>There is no padding between fields.</li>
done by hand instead of with packed struct</p> <li>Zig supports arbitrary width {#link|Integers#} and although normally, integers with fewer
than 8 bits will still use 1 byte of memory, in packed structs, they use
exactly their bit width.
</li>
<li>{#syntax#}bool{#endsyntax#} fields use exactly 1 bit.</li>
<li>A {#link|packed enum#} field uses exactly the bit width of its integer tag type.</li>
<li>A {#link|packed union#} field uses exactly the bit width of the union field with
the largest bit width.</li>
<li>Non-byte-aligned fields are packed into the smallest possible
byte-aligned integers in accordance with the target endianness.
</li>
</ul>
<p>
This means that a {#syntax#}packed struct{#endsyntax#} can participate
in a {#link|@bitCast#} or a {#link|@ptrCast#} to reinterpret memory.
This even works at {#link|comptime#}:
</p>
{#code_begin|test#}
const std = @import("std");
const builtin = @import("builtin");
const assert = std.debug.assert;
const Full = packed struct {
number: u16,
};
const Divided = packed struct {
half1: u8,
quarter3: u4,
quarter4: u4,
};
test "@bitCast between packed structs" {
doTheTest();
comptime doTheTest();
}
fn doTheTest() void {
assert(@sizeOf(Full) == 2);
assert(@sizeOf(Divided) == 2);
var full = Full{ .number = 0x1234 };
var divided = @bitCast(Divided, full);
switch (builtin.endian) {
builtin.Endian.Big => {
assert(divided.half1 == 0x12);
assert(divided.quarter3 == 0x3);
assert(divided.quarter4 == 0x4);
},
builtin.Endian.Little => {
assert(divided.half1 == 0x34);
assert(divided.quarter3 == 0x2);
assert(divided.quarter4 == 0x1);
},
}
}
{#code_end#}
<p>
Zig allows the address to be taken of a non-byte-aligned field:
</p>
{#code_begin|test#}
const std = @import("std");
const assert = std.debug.assert;
const BitField = packed struct {
a: u3,
b: u3,
c: u2,
};
var foo = BitField{
.a = 1,
.b = 2,
.c = 3,
};
test "pointer to non-byte-aligned field" {
const ptr = &foo.b;
assert(ptr.* == 2);
}
{#code_end#}
<p>
However, the pointer to a non-byte-aligned field has special properties and cannot
be passed when a normal pointer is expected:
</p>
{#code_begin|test_err|expected type#}
const std = @import("std");
const assert = std.debug.assert;
const BitField = packed struct {
a: u3,
b: u3,
c: u2,
};
var bit_field = BitField{
.a = 1,
.b = 2,
.c = 3,
};
test "pointer to non-bit-aligned field" {
assert(bar(&bit_field.b) == 2);
}
fn bar(x: *const u3) u3 {
return x.*;
}
{#code_end#}
<p>
In this case, the function {#syntax#}bar{#endsyntax#} cannot be called becuse the pointer
to the non-byte-aligned field mentions the bit offset, but the function expects a byte-aligned pointer.
</p>
<p>
Pointers to non-byte-aligned fields share the same address as the other fields within their host integer:
</p>
{#code_begin|test#}
const std = @import("std");
const assert = std.debug.assert;
const BitField = packed struct {
a: u3,
b: u3,
c: u2,
};
var bit_field = BitField{
.a = 1,
.b = 2,
.c = 3,
};
test "pointer to non-bit-aligned field" {
assert(@ptrToInt(&bit_field.a) == @ptrToInt(&bit_field.b));
assert(@ptrToInt(&bit_field.a) == @ptrToInt(&bit_field.c));
}
{#code_end#}
<p>
This can be observed with {#link|@bitOffsetOf#} and {#link|byteOffsetOf#}:
</p>
{#code_begin|test#}
const std = @import("std");
const assert = std.debug.assert;
const BitField = packed struct {
a: u3,
b: u3,
c: u2,
};
test "pointer to non-bit-aligned field" {
comptime {
assert(@bitOffsetOf(BitField, "a") == 0);
assert(@bitOffsetOf(BitField, "b") == 3);
assert(@bitOffsetOf(BitField, "c") == 6);
assert(@byteOffsetOf(BitField, "a") == 0);
assert(@byteOffsetOf(BitField, "b") == 0);
assert(@byteOffsetOf(BitField, "c") == 0);
}
}
{#code_end#}
<p>
Packed structs have 1-byte alignment. However if you have an overaligned pointer to a packed struct,
Zig should correctly understand the alignment of fields. However there is
<a href="https://github.com/ziglang/zig/issues/1994">a bug</a>:
</p>
{#code_begin|test_err#}
const S = packed struct {
a: u32,
b: u32,
};
test "overaligned pointer to packed struct" {
var foo: S align(4) = undefined;
const ptr: *align(4) S = &foo;
const ptr_to_b: *u32 = &ptr.b;
}
{#code_end#}
<p>When this bug is fixed, the above test in the documentation will unexpectedly pass, which will
cause the test suite to fail, notifying the bug fixer to update these docs.
</p>
<p>
It's also
<a href="https://github.com/ziglang/zig/issues/1512">planned to be able to set alignment of struct fields</a>.
</p>
<p>
Using packed structs with {#link|volatile#} is problematic, and may be a compile error in the future.
For details on this subscribe to
<a href="https://github.com/ziglang/zig/issues/1761">this issue</a>.
TODO update these docs with a recommendation on how to use packed structs with MMIO
(the use case for volatile packed structs) once this issue is resolved.
Don't worry, there will be a good solution for this use case in zig.
</p>
{#header_close#} {#header_close#}
{#header_open|struct Naming#} {#header_open|struct Naming#}
<p>Since all structs are anonymous, Zig infers the type name based on a few rules.</p> <p>Since all structs are anonymous, Zig infers the type name based on a few rules.</p>
@ -2200,8 +2400,8 @@ export fn entry(foo: Foo) void { }
{#header_close#} {#header_close#}
{#header_open|packed enum#} {#header_open|packed enum#}
<p>By default, the size of enums is not guaranteed.</p> <p>By default, the size of enums is not guaranteed.</p>
<p>{#syntax#}packed enum{#endsyntax#} causes the size of the enum to be the same as the size of the integer tag type <p>{#syntax#}packed enum{#endsyntax#} causes the size of the enum to be the same as the size of the
of the enum:</p> integer tag type of the enum:</p>
{#code_begin|test#} {#code_begin|test#}
const std = @import("std"); const std = @import("std");
@ -2214,131 +2414,179 @@ test "packed enum" {
std.debug.assert(@sizeOf(Number) == @sizeOf(u8)); std.debug.assert(@sizeOf(Number) == @sizeOf(u8));
} }
{#code_end#} {#code_end#}
<p>This makes the enum eligible to be in a {#link|packed struct#}.</p>
{#header_close#} {#header_close#}
{#see_also|@memberName|@memberCount|@tagName|@sizeOf#} {#see_also|@memberName|@memberCount|@tagName|@sizeOf#}
{#header_close#} {#header_close#}
{#header_open|union#} {#header_open|union#}
{#code_begin|test|union#} <p>
const assert = @import("std").debug.assert; A bare {#syntax#}union{#endsyntax#} defines a set of possible types that a value
const mem = @import("std").mem; can be as a list of fields. Only one field can be active at a time.
The in-memory representation of bare unions is not guaranteed.
// A union has only 1 active field at a time. Bare unions cannot be used to reinterpret memory. For that, use {#link|@ptrCast#},
or use an {#link|extern union#} or a {#link|packed union#} which have
guaranteed in-memory layout.
{#link|Accessing the non-active field|Wrong Union Field Access#} is
safety-checked {#link|Undefined Behavior#}:
</p>
{#code_begin|test_err|inactive union field#}
const Payload = union { const Payload = union {
Int: i64, Int: i64,
Float: f64, Float: f64,
Bool: bool, Bool: bool,
}; };
test "simple union" { test "simple union" {
var payload = Payload {.Int = 1234}; var payload = Payload{ .Int = 1234 };
// payload.Float = 12.34; // ERROR! field not active payload.Float = 12.34;
}
{#code_end#}
<p>You can activate another field by assigning the entire union:</p>
{#code_begin|test#}
const std = @import("std");
const assert = std.debug.assert;
const Payload = union {
Int: i64,
Float: f64,
Bool: bool,
};
test "simple union" {
var payload = Payload{ .Int = 1234 };
assert(payload.Int == 1234); assert(payload.Int == 1234);
// You can activate another field by assigning the entire union. payload = Payload{ .Float = 12.34 };
payload = Payload {.Float = 12.34};
assert(payload.Float == 12.34); assert(payload.Float == 12.34);
} }
{#code_end#}
<p>
In order to use {#link|switch#} with a union, it must be a {#link|Tagged union#}.
</p>
// Unions can be given an enum tag type: {#header_open|Tagged union#}
const ComplexTypeTag = enum { Ok, NotOk }; <p>Unions can be declared with an enum tag type.
This turns the union into a <em>tagged</em> union, which makes it eligible
to use with {#link|switch#} expressions. One can use {#link|@TagType#} to
obtain the enum type from the union type.
</p>
{#code_begin|test#}
const std = @import("std");
const assert = std.debug.assert;
const ComplexTypeTag = enum {
Ok,
NotOk,
};
const ComplexType = union(ComplexTypeTag) { const ComplexType = union(ComplexTypeTag) {
Ok: u8, Ok: u8,
NotOk: void, NotOk: void,
}; };
// Declare a specific instance of the union variant. test "switch on tagged union" {
test "declare union value" { const c = ComplexType{ .Ok = 42 };
const c = ComplexType { .Ok = 0 };
assert(ComplexTypeTag(c) == ComplexTypeTag.Ok); assert(ComplexTypeTag(c) == ComplexTypeTag.Ok);
switch (c) {
ComplexTypeTag.Ok => |value| assert(value == 42),
ComplexTypeTag.NotOk => unreachable,
}
} }
// @TagType can be used to access the enum tag type of a union.
test "@TagType" { test "@TagType" {
assert(@TagType(ComplexType) == ComplexTypeTag); assert(@TagType(ComplexType) == ComplexTypeTag);
} }
{#code_end#}
<p>In order to modify the payload of a tagged union in a switch expression,
place a {#syntax#}*{#endsyntax#} before the variable name to make it a pointer:
</p>
{#code_begin|test#}
const std = @import("std");
const assert = std.debug.assert;
// Unions can be made to infer the enum tag type. const ComplexTypeTag = enum {
const Foo = union(enum) { Ok,
String: []const u8, NotOk,
Number: u64, };
const ComplexType = union(ComplexTypeTag) {
// void can be omitted when inferring enum tag type. Ok: u8,
None, NotOk: void,
}; };
test "union variant switch" {
const p = Foo { .Number = 54 };
const what_is_it = switch (p) {
// Capture by reference
Foo.String => |*x| blk: {
break :blk "this is a string";
},
// Capture by value test "modify tagged union in switch" {
Foo.Number => |x| blk: { var c = ComplexType{ .Ok = 42 };
assert(x == 54); assert(ComplexTypeTag(c) == ComplexTypeTag.Ok);
break :blk "this is a number";
},
Foo.None => blk: { switch (c) {
break :blk "this is a none"; ComplexTypeTag.Ok => |*value| value.* += 1,
}, ComplexTypeTag.NotOk => unreachable,
}; }
assert(mem.eql(u8, what_is_it, "this is a number"));
assert(c.Ok == 43);
} }
{#code_end#}
// Unions can have methods just like structs and enums: <p>
Unions can be made to infer the enum tag type.
Further, unions can have methods just like structs and enums.
</p>
{#code_begin|test#}
const std = @import("std");
const assert = std.debug.assert;
const Variant = union(enum) { const Variant = union(enum) {
Int: i32, Int: i32,
Bool: bool, Bool: bool,
// void can be omitted when inferring enum tag type.
None,
fn truthy(self: Variant) bool { fn truthy(self: Variant) bool {
return switch (self) { return switch (self) {
Variant.Int => |x_int| x_int != 0, Variant.Int => |x_int| x_int != 0,
Variant.Bool => |x_bool| x_bool, Variant.Bool => |x_bool| x_bool,
Variant.None => false,
}; };
} }
}; };
test "union method" { test "union method" {
var v1 = Variant { .Int = 1 }; var v1 = Variant{ .Int = 1 };
var v2 = Variant { .Bool = false }; var v2 = Variant{ .Bool = false };
assert(v1.truthy()); assert(v1.truthy());
assert(!v2.truthy()); assert(!v2.truthy());
} }
{#code_end#}
<p>
{#link|@tagName#} can be used to return a {#link|comptime#}
{#syntax#}[]const u8{#endsyntax#} value representing the field name:
</p>
{#code_begin|test#}
const std = @import("std");
const assert = std.debug.assert;
const Small = union {
A: i32,
B: bool,
C: u8,
};
// @memberCount tells how many fields a union has:
test "@memberCount" {
assert(@memberCount(Small) == 3);
}
// @memberName tells the name of a field in an enum:
test "@memberName" {
assert(mem.eql(u8, @memberName(Small, 1), "B"));
}
// @tagName gives a []const u8 representation of an enum value,
// but only if the union has an enum tag type.
const Small2 = union(enum) { const Small2 = union(enum) {
A: i32, A: i32,
B: bool, B: bool,
C: u8, C: u8,
}; };
test "@tagName" { test "@tagName" {
assert(mem.eql(u8, @tagName(Small2.C), "C")); assert(std.mem.eql(u8, @tagName(Small2.C), "C"));
} }
{#code_end#} {#code_end#}
<p>
Unions with an enum tag are generated as a struct with a tag field and union field. Zig
sorts the order of the tag and union field by the largest alignment.
</p>
{#header_close#} {#header_close#}
{#header_open|extern union#}
<p>
An {#syntax#}extern union{#endsyntax#} has memory layout guaranteed to be compatible with
the target C ABI.
</p>
{#see_also|extern struct#}
{#header_close#}
{#header_open|packed union#}
<p>A {#syntax#}packed union{#endsyntax#} has well-defined in-memory layout and is eligible
to be in a {#link|packed struct#}.
{#header_close#}
{#header_close#}
{#header_open|blocks#} {#header_open|blocks#}
<p> <p>
Blocks are used to limit the scope of variable declarations: Blocks are used to limit the scope of variable declarations:
@ -2371,7 +2619,36 @@ test "labeled break from labeled block expression" {
{#code_end#} {#code_end#}
<p>Here, {#syntax#}blk{#endsyntax#} can be any name.</p> <p>Here, {#syntax#}blk{#endsyntax#} can be any name.</p>
{#see_also|Labeled while|Labeled for#} {#see_also|Labeled while|Labeled for#}
{#header_open|Shadowing#}
<p>It is never allowed for an identifier to "hide" another one by using the same name:</p>
{#code_begin|test_err|redefinition#}
const pi = 3.14;
test "inside test block" {
// Let's even go inside another block
{
var pi: i32 = 1234;
}
}
{#code_end#}
<p>
Because of this, when you read Zig code you can rely on an identifier always meaning the same thing,
within the scope it is defined. Note that you can, however use the same name if the scopes are separate:
</p>
{#code_begin|test#}
test "separate scopes" {
{
const pi = 3.14;
}
{
var pi: bool = true;
}
}
{#code_end#}
{#header_close#} {#header_close#}
{#header_close#}
{#header_open|switch#} {#header_open|switch#}
{#code_begin|test|switch#} {#code_begin|test|switch#}
const assert = @import("std").debug.assert; const assert = @import("std").debug.assert;
@ -2392,7 +2669,7 @@ test "switch simple" {
// Ranges can be specified using the ... syntax. These are inclusive // Ranges can be specified using the ... syntax. These are inclusive
// both ends. // both ends.
5 ... 100 => 1, 5...100 => 1,
// Branches can be arbitrarily complex. // Branches can be arbitrarily complex.
101 => blk: { 101 => blk: {
@ -2418,34 +2695,6 @@ test "switch simple" {
assert(b == 1); assert(b == 1);
} }
test "switch enum" {
const Item = union(enum) {
A: u32,
C: struct { x: u8, y: u8 },
D,
};
var a = Item { .A = 3 };
// Switching on more complex enums is allowed.
const b = switch (a) {
// A capture group is allowed on a match, and will return the enum
// value matched.
Item.A => |item| item,
// A reference to the matched value can be obtained using `*` syntax.
Item.C => |*item| blk: {
item.*.x += 1;
break :blk 6;
},
// No else is required if the types cases was exhaustively handled
Item.D => 8,
};
assert(b == 3);
}
// Switch expressions can be used outside a function: // Switch expressions can be used outside a function:
const os_msg = switch (builtin.os) { const os_msg = switch (builtin.os) {
builtin.Os.linux => "we found a linux user", builtin.Os.linux => "we found a linux user",
@ -2464,6 +2713,48 @@ test "switch inside function" {
}, },
else => {}, else => {},
} }
}
{#code_end#}
<p>
{#syntax#}switch{#endsyntax#} can be used to capture the field values
of a {#link|Tagged union#}. Modifications to the field values can be
done by placing a {#syntax#}*{#endsyntax#} before the capture variable name,
turning it into a pointer.
</p>
{#code_begin|test#}
const assert = @import("std").debug.assert;
test "switch on tagged union" {
const Point = struct {
x: u8,
y: u8,
};
const Item = union(enum) {
A: u32,
C: Point,
D,
};
var a = Item{ .C = Point{ .x = 1, .y = 2 } };
// Switching on more complex enums is allowed.
const b = switch (a) {
// A capture group is allowed on a match, and will return the enum
// value matched.
Item.A => |item| item,
// A reference to the matched value can be obtained using `*` syntax.
Item.C => |*item| blk: {
item.*.x += 1;
break :blk 6;
},
// No else is required if the types cases was exhaustively handled
Item.D => 8,
};
assert(b == 6);
assert(a.C.x == 2);
} }
{#code_end#} {#code_end#}
{#see_also|comptime|enum|@compileError|Compile Variables#} {#see_also|comptime|enum|@compileError|Compile Variables#}
@ -3134,7 +3425,6 @@ const assert = @import("std").debug.assert;
// Functions are declared like this // Functions are declared like this
fn add(a: i8, b: i8) i8 { fn add(a: i8, b: i8) i8 {
if (a == 0) { if (a == 0) {
// You can still return manually if needed.
return b; return b;
} }
@ -3158,12 +3448,18 @@ fn abort() noreturn {
while (true) {} while (true) {}
} }
// nakedcc makes a function not have any function prologue or epilogue. // The nakedcc specifier makes a function not have any function prologue or epilogue.
// This can be useful when integrating with assembly. // This can be useful when integrating with assembly.
nakedcc fn _start() noreturn { nakedcc fn _start() noreturn {
abort(); abort();
} }
// The inline specifier forces a function to be inlined at all call sites.
// If the function cannot be inlined, it is a compile-time error.
inline fn shiftLeftOne(a: u32) u32 {
return a << 1;
}
// The pub specifier allows the function to be visible when importing. // The pub specifier allows the function to be visible when importing.
// 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; }
@ -3981,7 +4277,7 @@ test "implicit cast - invoke a type as a function" {
{#code_end#} {#code_end#}
<p> <p>
Implicit casts are only allowed when it is completely unambiguous how to get from one type to another, Implicit casts are only allowed when it is completely unambiguous how to get from one type to another,
and the transformation is guaranteed to be safe. and the transformation is guaranteed to be safe. There is one exception, which is {#link|C Pointers#}.
</p> </p>
{#header_open|Implicit Cast: Stricter Qualification#} {#header_open|Implicit Cast: Stricter Qualification#}
<p> <p>
@ -4228,9 +4524,20 @@ fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 {
{#header_close#} {#header_close#}
{#header_close#} {#header_close#}
{#header_open|void#} {#header_open|Zero Bit Types#}
<p>For some types, {#link|@sizeOf#} is 0:</p>
<ul>
<li>{#link|void#}</li>
<li>The {#link|Integers#} {#syntax#}u0{#endsyntax#} and {#syntax#}i0{#endsyntax#}.</li>
<li>{#link|Arrays#} and {#link|Vectors#} with len 0, or with an element type that is a zero bit type.</li>
<li>An {#link|enum#} with only 1 tag.</li>
<li>An {#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>{#link|Pointers to Zero Bit Types#} are themselves zero bit types.</li>
</ul>
<p> <p>
{#syntax#}void{#endsyntax#} represents a type that has no value. Code that makes use of void values is These types can only ever have one possible value, and thus
require 0 bits to represent. Code that makes use of these types is
not included in the final generated code: not included in the final generated code:
</p> </p>
{#code_begin|syntax#} {#code_begin|syntax#}
@ -4240,8 +4547,8 @@ export fn entry() void {
x = y; x = y;
} }
{#code_end#} {#code_end#}
<p>When this turns into LLVM IR, there is no code generated in the body of {#syntax#}entry{#endsyntax#}, <p>When this turns into machine code, there is no code generated in the
even in debug mode. For example, on x86_64:</p> body of {#syntax#}entry{#endsyntax#}, even in {#link|Debug#} mode. For example, on x86_64:</p>
<pre><code>0000000000000010 &lt;entry&gt;: <pre><code>0000000000000010 &lt;entry&gt;:
10: 55 push %rbp 10: 55 push %rbp
11: 48 89 e5 mov %rsp,%rbp 11: 48 89 e5 mov %rsp,%rbp
@ -4249,6 +4556,8 @@ export fn entry() void {
15: c3 retq </code></pre> 15: c3 retq </code></pre>
<p>These assembly instructions do not have any code associated with the void values - <p>These assembly instructions do not have any code associated with the void values -
they only perform the function call prologue and epilog.</p> they only perform the function call prologue and epilog.</p>
{#header_open|void#}
<p> <p>
{#syntax#}void{#endsyntax#} can be useful for instantiating generic types. For example, given a {#syntax#}void{#endsyntax#} can be useful for instantiating generic types. For example, given a
{#syntax#}Map(Key, Value){#endsyntax#}, one can pass {#syntax#}void{#endsyntax#} for the {#syntax#}Value{#endsyntax#} {#syntax#}Map(Key, Value){#endsyntax#}, one can pass {#syntax#}void{#endsyntax#} for the {#syntax#}Value{#endsyntax#}
@ -4320,6 +4629,38 @@ 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#}
const std = @import("std");
const assert = std.debug.assert;
test "pointer to empty struct" {
const Empty = struct {};
var a = Empty{};
var b = Empty{};
var ptr_a = &a;
var ptr_b = &b;
comptime assert(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_open|comptime#} {#header_open|comptime#}
<p> <p>
Zig places importance on the concept of whether an expression is known at compile-time. Zig places importance on the concept of whether an expression is known at compile-time.
@ -5658,12 +5999,13 @@ test "main" {
{#header_close#} {#header_close#}
{#header_open|@enumToInt#} {#header_open|@enumToInt#}
<pre>{#syntax#}@enumToInt(enum_value: var) var{#endsyntax#}</pre> <pre>{#syntax#}@enumToInt(enum_or_tagged_union: var) var{#endsyntax#}</pre>
<p> <p>
Converts an enumeration value into its integer tag type. Converts an enumeration value into its integer tag type. When a tagged union is passed,
the tag value is used as the enumeration value.
</p> </p>
<p> <p>
If the enum has only 1 possible value, the resut is a {#syntax#}comptime_int{#endsyntax#} If there is only one possible enum value, the resut is a {#syntax#}comptime_int{#endsyntax#}
known at {#link|comptime#}. known at {#link|comptime#}.
</p> </p>
{#see_also|@intToEnum#} {#see_also|@intToEnum#}
@ -6104,6 +6446,10 @@ test "call foo" {
<p> <p>
Converts a pointer of one type to a pointer of another type. Converts a pointer of one type to a pointer of another type.
</p> </p>
<p>
{#link|Optional Pointers#} are allowed. Casting an optional pointer which is {#link|null#}
to a non-optional pointer invokes safety-checked {#link|Undefined Behavior#}.
</p>
{#header_close#} {#header_close#}
{#header_open|@ptrToInt#} {#header_open|@ptrToInt#}
@ -6293,10 +6639,15 @@ pub const FloatMode = enum {
<pre>{#syntax#}@sizeOf(comptime T: type) comptime_int{#endsyntax#}</pre> <pre>{#syntax#}@sizeOf(comptime T: type) comptime_int{#endsyntax#}</pre>
<p> <p>
This function returns the number of bytes it takes to store {#syntax#}T{#endsyntax#} in memory. This function returns the number of bytes it takes to store {#syntax#}T{#endsyntax#} in memory.
</p>
<p>
The result is a target-specific compile time constant. The result is a target-specific compile time constant.
</p> </p>
<p>
This size may contain padding bytes. If there were two consecutive T in memory, this would be the offset
in bytes between element at index 0 and the element at index 1. For {#link|integer|Integers#},
consider whether you want to use {#syntax#}@sizeOf(T){#endsyntax#} or
{#syntax#}@typeInfo(T).Int.bits{#endsyntax#}.
</p>
{#see_also|@typeInfo#}
{#header_close#} {#header_close#}
{#header_open|@sliceToBytes#} {#header_open|@sliceToBytes#}
@ -6730,11 +7081,7 @@ pub fn build(b: *Builder) void {
{#header_open|Single Threaded Builds#} {#header_open|Single Threaded Builds#}
<p>Zig has a compile option <code>--single-threaded</code> which has the following effects: <p>Zig has a compile option <code>--single-threaded</code> which has the following effects:
<ul> <ul>
<li>{#link|@atomicLoad#} is emitted as a normal load.</li> <li>Variables which have Thread Local Storage instead become globals.</li>
<li>{#link|@atomicRmw#} is emitted as a normal memory load, modify, store.</li>
<li>{#link|@fence#} becomes a no-op.</li>
<li>Variables which have Thread Local Storage instead become globals. TODO thread local variables
are not implemented yet.</li>
<li>The overhead of {#link|Coroutines#} becomes equivalent to function call overhead. <li>The overhead of {#link|Coroutines#} becomes equivalent to function call overhead.
TODO: please note this will not be implemented until the upcoming Coroutine Rewrite</li> TODO: please note this will not be implemented until the upcoming Coroutine Rewrite</li>
<li>The {#syntax#}@import("builtin").single_threaded{#endsyntax#} becomes {#syntax#}true{#endsyntax#} <li>The {#syntax#}@import("builtin").single_threaded{#endsyntax#} becomes {#syntax#}true{#endsyntax#}
@ -7343,12 +7690,30 @@ fn bar(f: *Foo) void {
f.float = 12.34; f.float = 12.34;
} }
{#code_end#} {#code_end#}
{#see_also|union|extern union#}
{#header_close#} {#header_close#}
{#header_open|Out of Bounds Float To Integer Cast#} {#header_open|Out of Bounds Float to Integer Cast#}
<p>TODO</p> <p>TODO</p>
{#header_close#} {#header_close#}
{#header_open|Pointer Cast Invalid Null#}
<p>At compile-time:</p>
{#code_begin|test_err|null pointer casted to type#}
comptime {
const opt_ptr: ?*i32 = null;
const ptr = @ptrCast(*i32, opt_ptr);
}
{#code_end#}
<p>At runtime:</p>
{#code_begin|exe_err#}
pub fn main() void {
var opt_ptr: ?*i32 = null;
var ptr = @ptrCast(*i32, opt_ptr);
}
{#code_end#}
{#header_close#}
{#header_close#} {#header_close#}
{#header_open|Memory#} {#header_open|Memory#}
<p>TODO: explain no default allocator in zig</p> <p>TODO: explain no default allocator in zig</p>
@ -7439,6 +7804,7 @@ pub fn main() void {
{#code_end#} {#code_end#}
{#see_also|String Literals#} {#see_also|String Literals#}
{#header_close#} {#header_close#}
{#header_open|Import from C Header File#} {#header_open|Import from C Header File#}
<p> <p>
The {#syntax#}@cImport{#endsyntax#} builtin function can be used The {#syntax#}@cImport{#endsyntax#} builtin function can be used
@ -7477,6 +7843,36 @@ const c = @cImport({
{#code_end#} {#code_end#}
{#see_also|@cImport|@cInclude|@cDefine|@cUndef|@import#} {#see_also|@cImport|@cInclude|@cDefine|@cUndef|@import#}
{#header_close#} {#header_close#}
{#header_open|C Pointers#}
<p>
This type is to be avoided whenever possible. The only valid reason for using a C pointer is in
auto-generated code from translating C code.
</p>
<p>
When importing C header files, it is ambiguous whether pointers should be translated as
single-item pointers ({#syntax#}*T{#endsyntax#}) or unknown-length pointers ({#syntax#}[*]T{#endsyntax#}).
C pointers are a compromise so that Zig code can utilize translated header files directly.
</p>
<p>{#syntax#}[*c]T{#endsyntax#} - C pointer.</p>
<ul>
<li>Supports all the syntax of the other two pointer types.</li>
<li>Implicitly casts to other pointer types, as well as {#link|Optional Pointers#}.
When a C pointer is implicitly casted to a non-optional pointer, safety-checked
{#link|Undefined Behavior#} occurs if the address is 0.
</li>
<li>Allows address 0. On non-freestanding targets, dereferencing address 0 is safety-checked
{#link|Undefined Behavior#}. Optional C pointers introduce another bit to keep track of
null, just like {#syntax#}?usize{#endsyntax#}. Note that creating an optional C pointer
is unnecessary as one can use normal {#link|Optional Pointers#}.
</li>
<li>Supports {#link|implicit casting|Implicit Casts#} to and from integers.</li>
<li>Supports comparison with integers.</li>
<li>Does not support Zig-only pointer attributes such as alignment. Use normal {#link|Pointers#}
please!</li>
</ul>
{#header_close#}
{#header_open|Exporting a C Library#} {#header_open|Exporting a C Library#}
<p> <p>
One of the primary use cases for Zig is exporting a library with the C ABI for other programming languages One of the primary use cases for Zig is exporting a library with the C ABI for other programming languages
@ -7729,7 +8125,7 @@ Environments:
coreclr coreclr
opencl</code></pre> opencl</code></pre>
<p> <p>
The Zig Standard Library ({#syntax#}@import("std"){#endsyntax#}) has architecture, environment, and operating sytsem The Zig Standard Library ({#syntax#}@import("std"){#endsyntax#}) has architecture, environment, and operating system
abstractions, and thus takes additional work to support more platforms. abstractions, and thus takes additional work to support more platforms.
Not all standard library code requires operating system abstractions, however, Not all standard library code requires operating system abstractions, however,
so things such as generic data structures work an all above platforms. so things such as generic data structures work an all above platforms.
@ -8164,7 +8560,8 @@ ArrayTypeStart &lt;- LBRACKET Expr? RBRACKET
PtrTypeStart PtrTypeStart
&lt;- ASTERISK &lt;- ASTERISK
/ ASTERISK2 / ASTERISK2
/ LBRACKET ASTERISK RBRACKET / PTRUNKNOWN
/ PTRC
# ContainerDecl specific # ContainerDecl specific
ContainerDeclAuto &lt;- ContainerDeclType LBRACE ContainerMembers RBRACE ContainerDeclAuto &lt;- ContainerDeclType LBRACE ContainerMembers RBRACE
@ -8262,7 +8659,7 @@ LARROW2 &lt;- '&lt;&lt;' ![=] skip
LARROW2EQUAL &lt;- '&lt;&lt;=' skip LARROW2EQUAL &lt;- '&lt;&lt;=' skip
LARROWEQUAL &lt;- '&lt;=' skip LARROWEQUAL &lt;- '&lt;=' skip
LBRACE &lt;- '{' skip LBRACE &lt;- '{' skip
LBRACKET &lt;- '[' skip LBRACKET &lt;- '[' ![*] skip
LPAREN &lt;- '(' skip LPAREN &lt;- '(' skip
MINUS &lt;- '-' ![%=&gt;] skip MINUS &lt;- '-' ![%=&gt;] skip
MINUSEQUAL &lt;- '-=' skip MINUSEQUAL &lt;- '-=' skip
@ -8279,6 +8676,8 @@ PLUS2 &lt;- '++' skip
PLUSEQUAL &lt;- '+=' skip PLUSEQUAL &lt;- '+=' skip
PLUSPERCENT &lt;- '+%' ![=] skip PLUSPERCENT &lt;- '+%' ![=] skip
PLUSPERCENTEQUAL &lt;- '+%=' skip PLUSPERCENTEQUAL &lt;- '+%=' skip
PTRC &lt;- '[*c]' skip
PTRUNKNOWN &lt;- '[*]' skip
QUESTIONMARK &lt;- '?' skip QUESTIONMARK &lt;- '?' skip
RARROW &lt;- '&gt;' ![&gt;=] skip RARROW &lt;- '&gt;' ![&gt;=] skip
RARROW2 &lt;- '&gt;&gt;' ![=] skip RARROW2 &lt;- '&gt;&gt;' ![=] skip

View File

@ -3,10 +3,10 @@ const Builder = @import("std").build.Builder;
pub fn build(b: *Builder) void { pub fn build(b: *Builder) void {
const obj = b.addObject("base64", "base64.zig"); const obj = b.addObject("base64", "base64.zig");
const exe = b.addCExecutable("test"); const exe = b.addExecutable("test", null);
exe.addCompileFlags([][]const u8{"-std=c99"}); exe.addCSourceFile("test.c",[][]const u8{"-std=c99"});
exe.addSourceFile("test.c");
exe.addObject(obj); exe.addObject(obj);
exe.linkSystemLibrary("c");
b.default_step.dependOn(&exe.step); b.default_step.dependOn(&exe.step);

View File

@ -3,10 +3,10 @@ const Builder = @import("std").build.Builder;
pub fn build(b: *Builder) void { pub fn build(b: *Builder) void {
const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0)); const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0));
const exe = b.addCExecutable("test"); const exe = b.addExecutable("test", null);
exe.addCompileFlags([][]const u8{"-std=c99"}); exe.addCSourceFile("test.c", [][]const u8{"-std=c99"});
exe.addSourceFile("test.c");
exe.linkLibrary(lib); exe.linkLibrary(lib);
exe.linkSystemLibrary("c");
b.default_step.dependOn(&exe.step); b.default_step.dependOn(&exe.step);

View File

@ -1,12 +1,3 @@
// TODO Remove this workaround
comptime {
const builtin = @import("builtin");
if (builtin.os == builtin.Os.macosx) {
@export("__mh_execute_header", _mh_execute_header, builtin.GlobalLinkage.Weak);
}
}
var _mh_execute_header = extern struct {x: usize}{.x = 0};
export fn add(a: i32, b: i32) i32 { export fn add(a: i32, b: i32) i32 {
return a + b; return a + b;
} }

View File

@ -137,10 +137,10 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code)
pub const ObjectFile = struct { pub const ObjectFile = struct {
comp: *Compilation, comp: *Compilation,
module: llvm.ModuleRef, module: *llvm.Module,
builder: llvm.BuilderRef, builder: *llvm.Builder,
dibuilder: *llvm.DIBuilder, dibuilder: *llvm.DIBuilder,
context: llvm.ContextRef, context: *llvm.Context,
lock: event.Lock, lock: event.Lock,
arena: *std.mem.Allocator, arena: *std.mem.Allocator,
@ -323,7 +323,7 @@ pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code)
fn addLLVMAttr( fn addLLVMAttr(
ofile: *ObjectFile, ofile: *ObjectFile,
val: llvm.ValueRef, val: *llvm.Value,
attr_index: llvm.AttributeIndex, attr_index: llvm.AttributeIndex,
attr_name: []const u8, attr_name: []const u8,
) !void { ) !void {
@ -335,7 +335,7 @@ fn addLLVMAttr(
fn addLLVMAttrStr( fn addLLVMAttrStr(
ofile: *ObjectFile, ofile: *ObjectFile,
val: llvm.ValueRef, val: *llvm.Value,
attr_index: llvm.AttributeIndex, attr_index: llvm.AttributeIndex,
attr_name: []const u8, attr_name: []const u8,
attr_val: []const u8, attr_val: []const u8,
@ -351,7 +351,7 @@ fn addLLVMAttrStr(
} }
fn addLLVMAttrInt( fn addLLVMAttrInt(
val: llvm.ValueRef, val: *llvm.Value,
attr_index: llvm.AttributeIndex, attr_index: llvm.AttributeIndex,
attr_name: []const u8, attr_name: []const u8,
attr_val: u64, attr_val: u64,
@ -362,25 +362,25 @@ fn addLLVMAttrInt(
llvm.AddAttributeAtIndex(val, attr_index, llvm_attr); llvm.AddAttributeAtIndex(val, attr_index, llvm_attr);
} }
fn addLLVMFnAttr(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8) !void { fn addLLVMFnAttr(ofile: *ObjectFile, fn_val: *llvm.Value, attr_name: []const u8) !void {
return addLLVMAttr(ofile, fn_val, maxInt(llvm.AttributeIndex), attr_name); return addLLVMAttr(ofile, fn_val, maxInt(llvm.AttributeIndex), attr_name);
} }
fn addLLVMFnAttrStr(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8, attr_val: []const u8) !void { fn addLLVMFnAttrStr(ofile: *ObjectFile, fn_val: *llvm.Value, attr_name: []const u8, attr_val: []const u8) !void {
return addLLVMAttrStr(ofile, fn_val, maxInt(llvm.AttributeIndex), attr_name, attr_val); return addLLVMAttrStr(ofile, fn_val, maxInt(llvm.AttributeIndex), attr_name, attr_val);
} }
fn addLLVMFnAttrInt(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8, attr_val: u64) !void { fn addLLVMFnAttrInt(ofile: *ObjectFile, fn_val: *llvm.Value, attr_name: []const u8, attr_val: u64) !void {
return addLLVMAttrInt(ofile, fn_val, maxInt(llvm.AttributeIndex), attr_name, attr_val); return addLLVMAttrInt(ofile, fn_val, maxInt(llvm.AttributeIndex), attr_name, attr_val);
} }
fn renderLoadUntyped( fn renderLoadUntyped(
ofile: *ObjectFile, ofile: *ObjectFile,
ptr: llvm.ValueRef, ptr: *llvm.Value,
alignment: Type.Pointer.Align, alignment: Type.Pointer.Align,
vol: Type.Pointer.Vol, vol: Type.Pointer.Vol,
name: [*]const u8, name: [*]const u8,
) !llvm.ValueRef { ) !*llvm.Value {
const result = llvm.BuildLoad(ofile.builder, ptr, name) orelse return error.OutOfMemory; const result = llvm.BuildLoad(ofile.builder, ptr, name) orelse return error.OutOfMemory;
switch (vol) { switch (vol) {
Type.Pointer.Vol.Non => {}, Type.Pointer.Vol.Non => {},
@ -390,11 +390,11 @@ fn renderLoadUntyped(
return result; return result;
} }
fn renderLoad(ofile: *ObjectFile, ptr: llvm.ValueRef, ptr_type: *Type.Pointer, name: [*]const u8) !llvm.ValueRef { fn renderLoad(ofile: *ObjectFile, ptr: *llvm.Value, ptr_type: *Type.Pointer, name: [*]const u8) !*llvm.Value {
return renderLoadUntyped(ofile, ptr, ptr_type.key.alignment, ptr_type.key.vol, name); return renderLoadUntyped(ofile, ptr, ptr_type.key.alignment, ptr_type.key.vol, name);
} }
pub fn getHandleValue(ofile: *ObjectFile, ptr: llvm.ValueRef, ptr_type: *Type.Pointer) !?llvm.ValueRef { pub fn getHandleValue(ofile: *ObjectFile, ptr: *llvm.Value, ptr_type: *Type.Pointer) !?*llvm.Value {
const child_type = ptr_type.key.child_type; const child_type = ptr_type.key.child_type;
if (!child_type.hasBits()) { if (!child_type.hasBits()) {
return null; return null;
@ -407,11 +407,11 @@ pub fn getHandleValue(ofile: *ObjectFile, ptr: llvm.ValueRef, ptr_type: *Type.Po
pub fn renderStoreUntyped( pub fn renderStoreUntyped(
ofile: *ObjectFile, ofile: *ObjectFile,
value: llvm.ValueRef, value: *llvm.Value,
ptr: llvm.ValueRef, ptr: *llvm.Value,
alignment: Type.Pointer.Align, alignment: Type.Pointer.Align,
vol: Type.Pointer.Vol, vol: Type.Pointer.Vol,
) !llvm.ValueRef { ) !*llvm.Value {
const result = llvm.BuildStore(ofile.builder, value, ptr) orelse return error.OutOfMemory; const result = llvm.BuildStore(ofile.builder, value, ptr) orelse return error.OutOfMemory;
switch (vol) { switch (vol) {
Type.Pointer.Vol.Non => {}, Type.Pointer.Vol.Non => {},
@ -423,10 +423,10 @@ pub fn renderStoreUntyped(
pub fn renderStore( pub fn renderStore(
ofile: *ObjectFile, ofile: *ObjectFile,
value: llvm.ValueRef, value: *llvm.Value,
ptr: llvm.ValueRef, ptr: *llvm.Value,
ptr_type: *Type.Pointer, ptr_type: *Type.Pointer,
) !llvm.ValueRef { ) !*llvm.Value {
return renderStoreUntyped(ofile, value, ptr, ptr_type.key.alignment, ptr_type.key.vol); return renderStoreUntyped(ofile, value, ptr, ptr_type.key.alignment, ptr_type.key.vol);
} }
@ -435,7 +435,7 @@ pub fn renderAlloca(
var_type: *Type, var_type: *Type,
name: []const u8, name: []const u8,
alignment: Type.Pointer.Align, alignment: Type.Pointer.Align,
) !llvm.ValueRef { ) !*llvm.Value {
const llvm_var_type = try var_type.getLlvmType(ofile.arena, ofile.context); const llvm_var_type = try var_type.getLlvmType(ofile.arena, ofile.context);
const name_with_null = try std.cstr.addNullByte(ofile.arena, name); const name_with_null = try std.cstr.addNullByte(ofile.arena, name);
const result = llvm.BuildAlloca(ofile.builder, llvm_var_type, name_with_null.ptr) orelse return error.OutOfMemory; const result = llvm.BuildAlloca(ofile.builder, llvm_var_type, name_with_null.ptr) orelse return error.OutOfMemory;
@ -443,7 +443,7 @@ pub fn renderAlloca(
return result; return result;
} }
pub fn resolveAlign(ofile: *ObjectFile, alignment: Type.Pointer.Align, llvm_type: llvm.TypeRef) u32 { pub fn resolveAlign(ofile: *ObjectFile, alignment: Type.Pointer.Align, llvm_type: *llvm.Type) u32 {
return switch (alignment) { return switch (alignment) {
Type.Pointer.Align.Abi => return llvm.ABIAlignmentOfType(ofile.comp.target_data_ref, llvm_type), Type.Pointer.Align.Abi => return llvm.ABIAlignmentOfType(ofile.comp.target_data_ref, llvm_type),
Type.Pointer.Align.Override => |a| a, Type.Pointer.Align.Override => |a| a,

View File

@ -37,7 +37,7 @@ const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB
/// Data that is local to the event loop. /// Data that is local to the event loop.
pub const ZigCompiler = struct { pub const ZigCompiler = struct {
loop: *event.Loop, loop: *event.Loop,
llvm_handle_pool: std.atomic.Stack(llvm.ContextRef), llvm_handle_pool: std.atomic.Stack(*llvm.Context),
lld_lock: event.Lock, lld_lock: event.Lock,
/// TODO pool these so that it doesn't have to lock /// TODO pool these so that it doesn't have to lock
@ -60,7 +60,7 @@ pub const ZigCompiler = struct {
return ZigCompiler{ return ZigCompiler{
.loop = loop, .loop = loop,
.lld_lock = event.Lock.init(loop), .lld_lock = event.Lock.init(loop),
.llvm_handle_pool = std.atomic.Stack(llvm.ContextRef).init(), .llvm_handle_pool = std.atomic.Stack(*llvm.Context).init(),
.prng = event.Locked(std.rand.DefaultPrng).init(loop, std.rand.DefaultPrng.init(seed)), .prng = event.Locked(std.rand.DefaultPrng).init(loop, std.rand.DefaultPrng.init(seed)),
.native_libc = event.Future(LibCInstallation).init(loop), .native_libc = event.Future(LibCInstallation).init(loop),
}; };
@ -70,7 +70,7 @@ pub const ZigCompiler = struct {
fn deinit(self: *ZigCompiler) void { fn deinit(self: *ZigCompiler) void {
self.lld_lock.deinit(); self.lld_lock.deinit();
while (self.llvm_handle_pool.pop()) |node| { while (self.llvm_handle_pool.pop()) |node| {
c.LLVMContextDispose(node.data); llvm.ContextDispose(node.data);
self.loop.allocator.destroy(node); self.loop.allocator.destroy(node);
} }
} }
@ -80,11 +80,11 @@ pub const ZigCompiler = struct {
pub fn getAnyLlvmContext(self: *ZigCompiler) !LlvmHandle { pub fn getAnyLlvmContext(self: *ZigCompiler) !LlvmHandle {
if (self.llvm_handle_pool.pop()) |node| return LlvmHandle{ .node = node }; if (self.llvm_handle_pool.pop()) |node| return LlvmHandle{ .node = node };
const context_ref = c.LLVMContextCreate() orelse return error.OutOfMemory; const context_ref = llvm.ContextCreate() orelse return error.OutOfMemory;
errdefer c.LLVMContextDispose(context_ref); errdefer llvm.ContextDispose(context_ref);
const node = try self.loop.allocator.create(std.atomic.Stack(llvm.ContextRef).Node); const node = try self.loop.allocator.create(std.atomic.Stack(*llvm.Context).Node);
node.* = std.atomic.Stack(llvm.ContextRef).Node{ node.* = std.atomic.Stack(*llvm.Context).Node{
.next = undefined, .next = undefined,
.data = context_ref, .data = context_ref,
}; };
@ -114,7 +114,7 @@ pub const ZigCompiler = struct {
}; };
pub const LlvmHandle = struct { pub const LlvmHandle = struct {
node: *std.atomic.Stack(llvm.ContextRef).Node, node: *std.atomic.Stack(*llvm.Context).Node,
pub fn release(self: LlvmHandle, zig_compiler: *ZigCompiler) void { pub fn release(self: LlvmHandle, zig_compiler: *ZigCompiler) void {
zig_compiler.llvm_handle_pool.push(self.node); zig_compiler.llvm_handle_pool.push(self.node);
@ -128,7 +128,7 @@ pub const Compilation = struct {
llvm_triple: Buffer, llvm_triple: Buffer,
root_src_path: ?[]const u8, root_src_path: ?[]const u8,
target: Target, target: Target,
llvm_target: llvm.TargetRef, llvm_target: *llvm.Target,
build_mode: builtin.Mode, build_mode: builtin.Mode,
zig_lib_dir: []const u8, zig_lib_dir: []const u8,
zig_std_dir: []const u8, zig_std_dir: []const u8,
@ -212,8 +212,8 @@ pub const Compilation = struct {
false_value: *Value.Bool, false_value: *Value.Bool,
noreturn_value: *Value.NoReturn, noreturn_value: *Value.NoReturn,
target_machine: llvm.TargetMachineRef, target_machine: *llvm.TargetMachine,
target_data_ref: llvm.TargetDataRef, target_data_ref: *llvm.TargetData,
target_layout_str: [*]u8, target_layout_str: [*]u8,
target_ptr_bits: u32, target_ptr_bits: u32,

View File

@ -67,7 +67,7 @@ pub const Inst = struct {
parent: ?*Inst, parent: ?*Inst,
/// populated durign codegen /// populated durign codegen
llvm_value: ?llvm.ValueRef, llvm_value: ?*llvm.Value,
pub fn cast(base: *Inst, comptime T: type) ?*T { pub fn cast(base: *Inst, comptime T: type) ?*T {
if (base.id == comptime typeToId(T)) { if (base.id == comptime typeToId(T)) {
@ -129,7 +129,7 @@ pub const Inst = struct {
} }
} }
pub fn render(base: *Inst, ofile: *ObjectFile, fn_val: *Value.Fn) (error{OutOfMemory}!?llvm.ValueRef) { pub fn render(base: *Inst, ofile: *ObjectFile, fn_val: *Value.Fn) (error{OutOfMemory}!?*llvm.Value) {
switch (base.id) { switch (base.id) {
Id.Return => return @fieldParentPtr(Return, "base", base).render(ofile, fn_val), Id.Return => return @fieldParentPtr(Return, "base", base).render(ofile, fn_val),
Id.Const => return @fieldParentPtr(Const, "base", base).render(ofile, fn_val), Id.Const => return @fieldParentPtr(Const, "base", base).render(ofile, fn_val),
@ -313,10 +313,10 @@ pub const Inst = struct {
return new_inst; return new_inst;
} }
pub fn render(self: *Call, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef { pub fn render(self: *Call, ofile: *ObjectFile, fn_val: *Value.Fn) !?*llvm.Value {
const fn_ref = self.params.fn_ref.llvm_value.?; const fn_ref = self.params.fn_ref.llvm_value.?;
const args = try ofile.arena.alloc(llvm.ValueRef, self.params.args.len); const args = try ofile.arena.alloc(*llvm.Value, self.params.args.len);
for (self.params.args) |arg, i| { for (self.params.args) |arg, i| {
args[i] = arg.llvm_value.?; args[i] = arg.llvm_value.?;
} }
@ -360,7 +360,7 @@ pub const Inst = struct {
return new_inst; return new_inst;
} }
pub fn render(self: *Const, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef { pub fn render(self: *Const, ofile: *ObjectFile, fn_val: *Value.Fn) !?*llvm.Value {
return self.base.val.KnownValue.getLlvmConst(ofile); return self.base.val.KnownValue.getLlvmConst(ofile);
} }
}; };
@ -392,7 +392,7 @@ pub const Inst = struct {
return ira.irb.build(Return, self.base.scope, self.base.span, Params{ .return_value = casted_value }); return ira.irb.build(Return, self.base.scope, self.base.span, Params{ .return_value = casted_value });
} }
pub fn render(self: *Return, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef { pub fn render(self: *Return, ofile: *ObjectFile, fn_val: *Value.Fn) !?*llvm.Value {
const value = self.params.return_value.llvm_value; const value = self.params.return_value.llvm_value;
const return_type = self.params.return_value.getKnownType(); const return_type = self.params.return_value.getKnownType();
@ -540,7 +540,7 @@ pub const Inst = struct {
} }
} }
pub fn render(self: *VarPtr, ofile: *ObjectFile, fn_val: *Value.Fn) llvm.ValueRef { pub fn render(self: *VarPtr, ofile: *ObjectFile, fn_val: *Value.Fn) *llvm.Value {
switch (self.params.var_scope.data) { switch (self.params.var_scope.data) {
Scope.Var.Data.Const => unreachable, // turned into Inst.Const in analyze pass Scope.Var.Data.Const => unreachable, // turned into Inst.Const in analyze pass
Scope.Var.Data.Param => |param| return param.llvm_value, Scope.Var.Data.Param => |param| return param.llvm_value,
@ -596,7 +596,7 @@ pub const Inst = struct {
return new_inst; return new_inst;
} }
pub fn render(self: *LoadPtr, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef { pub fn render(self: *LoadPtr, ofile: *ObjectFile, fn_val: *Value.Fn) !?*llvm.Value {
const child_type = self.base.getKnownType(); const child_type = self.base.getKnownType();
if (!child_type.hasBits()) { if (!child_type.hasBits()) {
return null; return null;
@ -935,8 +935,8 @@ pub const BasicBlock = struct {
ref_instruction: ?*Inst, ref_instruction: ?*Inst,
/// for codegen /// for codegen
llvm_block: llvm.BasicBlockRef, llvm_block: *llvm.BasicBlock,
llvm_exit_block: llvm.BasicBlockRef, llvm_exit_block: *llvm.BasicBlock,
/// the basic block that is derived from this one in analysis /// the basic block that is derived from this one in analysis
child: ?*BasicBlock, child: ?*BasicBlock,

View File

@ -154,8 +154,8 @@ pub const LibCInstallation = struct {
c.ZigFindWindowsSdkError.None => { c.ZigFindWindowsSdkError.None => {
windows_sdk = sdk; windows_sdk = sdk;
if (sdk.msvc_lib_dir_ptr) |ptr| { if (sdk.msvc_lib_dir_ptr != 0) {
self.msvc_lib_dir = try std.mem.dupe(loop.allocator, u8, ptr[0..sdk.msvc_lib_dir_len]); self.msvc_lib_dir = try std.mem.dupe(loop.allocator, u8, sdk.msvc_lib_dir_ptr[0..sdk.msvc_lib_dir_len]);
} }
try group.call(findNativeKernel32LibDir, self, loop, sdk); try group.call(findNativeKernel32LibDir, self, loop, sdk);
try group.call(findNativeIncludeDirWindows, self, loop, sdk); try group.call(findNativeIncludeDirWindows, self, loop, sdk);
@ -172,7 +172,7 @@ pub const LibCInstallation = struct {
try group.call(findNativeStaticLibDir, self, loop); try group.call(findNativeStaticLibDir, self, loop);
try group.call(findNativeDynamicLinker, self, loop); try group.call(findNativeDynamicLinker, self, loop);
}, },
builtin.Os.macosx, builtin.Os.freebsd => { builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
self.include_dir = try std.mem.dupe(loop.allocator, u8, "/usr/include"); self.include_dir = try std.mem.dupe(loop.allocator, u8, "/usr/include");
}, },
else => @compileError("unimplemented: find libc for this OS"), else => @compileError("unimplemented: find libc for this OS"),
@ -283,7 +283,7 @@ pub const LibCInstallation = struct {
switch (builtin.arch) { switch (builtin.arch) {
builtin.Arch.i386 => try stream.write("x86"), builtin.Arch.i386 => try stream.write("x86"),
builtin.Arch.x86_64 => try stream.write("x64"), builtin.Arch.x86_64 => try stream.write("x64"),
builtin.Arch.aarch64v8 => try stream.write("arm"), builtin.Arch.aarch64 => try stream.write("arm"),
else => return error.UnsupportedArchitecture, else => return error.UnsupportedArchitecture,
} }
const ucrt_lib_path = try std.os.path.join( const ucrt_lib_path = try std.os.path.join(
@ -361,7 +361,7 @@ pub const LibCInstallation = struct {
switch (builtin.arch) { switch (builtin.arch) {
builtin.Arch.i386 => try stream.write("x86\\"), builtin.Arch.i386 => try stream.write("x86\\"),
builtin.Arch.x86_64 => try stream.write("x64\\"), builtin.Arch.x86_64 => try stream.write("x64\\"),
builtin.Arch.aarch64v8 => try stream.write("arm\\"), builtin.Arch.aarch64 => try stream.write("arm\\"),
else => return error.UnsupportedArchitecture, else => return error.UnsupportedArchitecture,
} }
const kernel32_path = try std.os.path.join( const kernel32_path = try std.os.path.join(
@ -437,20 +437,20 @@ const Search = struct {
fn fillSearch(search_buf: *[2]Search, sdk: *c.ZigWindowsSDK) []Search { fn fillSearch(search_buf: *[2]Search, sdk: *c.ZigWindowsSDK) []Search {
var search_end: usize = 0; var search_end: usize = 0;
if (sdk.path10_ptr) |path10_ptr| { if (sdk.path10_ptr != 0) {
if (sdk.version10_ptr) |ver10_ptr| { if (sdk.version10_ptr != 0) {
search_buf[search_end] = Search{ search_buf[search_end] = Search{
.path = path10_ptr[0..sdk.path10_len], .path = sdk.path10_ptr[0..sdk.path10_len],
.version = ver10_ptr[0..sdk.version10_len], .version = sdk.version10_ptr[0..sdk.version10_len],
}; };
search_end += 1; search_end += 1;
} }
} }
if (sdk.path81_ptr) |path81_ptr| { if (sdk.path81_ptr != 0) {
if (sdk.version81_ptr) |ver81_ptr| { if (sdk.version81_ptr != 0) {
search_buf[search_end] = Search{ search_buf[search_end] = Search{
.path = path81_ptr[0..sdk.path81_len], .path = sdk.path81_ptr[0..sdk.path81_len],
.version = ver81_ptr[0..sdk.version81_len], .version = sdk.version81_ptr[0..sdk.version81_len],
}; };
search_end += 1; search_end += 1;
} }

View File

@ -145,10 +145,6 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
// lj->args.append("-T"); // lj->args.append("-T");
// lj->args.append(g->linker_script); // lj->args.append(g->linker_script);
//} //}
//if (g->no_rosegment_workaround) {
// lj->args.append("--no-rosegment");
//}
try ctx.args.append(c"--gc-sections"); try ctx.args.append(c"--gc-sections");
//lj->args.append("-m"); //lj->args.append("-m");
@ -330,7 +326,7 @@ fn constructLinkerArgsCoff(ctx: *Context) !void {
switch (ctx.comp.target.getArch()) { switch (ctx.comp.target.getArch()) {
builtin.Arch.i386 => try ctx.args.append(c"-MACHINE:X86"), builtin.Arch.i386 => try ctx.args.append(c"-MACHINE:X86"),
builtin.Arch.x86_64 => try ctx.args.append(c"-MACHINE:X64"), builtin.Arch.x86_64 => try ctx.args.append(c"-MACHINE:X64"),
builtin.Arch.aarch64v8 => try ctx.args.append(c"-MACHINE:ARM"), builtin.Arch.aarch64 => try ctx.args.append(c"-MACHINE:ARM"),
else => return error.UnsupportedLinkArchitecture, else => return error.UnsupportedLinkArchitecture,
} }
@ -556,7 +552,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {
} }
}, },
DarwinPlatform.Kind.IPhoneOS => { DarwinPlatform.Kind.IPhoneOS => {
if (ctx.comp.target.getArch() == builtin.Arch.aarch64v8) { if (ctx.comp.target.getArch() == builtin.Arch.aarch64) {
// iOS does not need any crt1 files for arm64 // iOS does not need any crt1 files for arm64
} else if (platform.versionLessThan(3, 1)) { } else if (platform.versionLessThan(3, 1)) {
try ctx.args.append(c"-lcrt1.o"); try ctx.args.append(c"-lcrt1.o");

View File

@ -11,45 +11,31 @@ const assert = @import("std").debug.assert;
pub const AttributeIndex = c_uint; pub const AttributeIndex = c_uint;
pub const Bool = c_int; pub const Bool = c_int;
pub const BuilderRef = removeNullability(c.LLVMBuilderRef); pub const Builder = c.LLVMBuilderRef.Child.Child;
pub const ContextRef = removeNullability(c.LLVMContextRef); pub const Context = c.LLVMContextRef.Child.Child;
pub const ModuleRef = removeNullability(c.LLVMModuleRef); pub const Module = c.LLVMModuleRef.Child.Child;
pub const ValueRef = removeNullability(c.LLVMValueRef); pub const Value = c.LLVMValueRef.Child.Child;
pub const TypeRef = removeNullability(c.LLVMTypeRef); pub const Type = c.LLVMTypeRef.Child.Child;
pub const BasicBlockRef = removeNullability(c.LLVMBasicBlockRef); pub const BasicBlock = c.LLVMBasicBlockRef.Child.Child;
pub const AttributeRef = removeNullability(c.LLVMAttributeRef); pub const Attribute = c.LLVMAttributeRef.Child.Child;
pub const TargetRef = removeNullability(c.LLVMTargetRef); pub const Target = c.LLVMTargetRef.Child.Child;
pub const TargetMachineRef = removeNullability(c.LLVMTargetMachineRef); pub const TargetMachine = c.LLVMTargetMachineRef.Child.Child;
pub const TargetDataRef = removeNullability(c.LLVMTargetDataRef); pub const TargetData = c.LLVMTargetDataRef.Child.Child;
pub const DIBuilder = c.ZigLLVMDIBuilder; pub const DIBuilder = c.ZigLLVMDIBuilder;
pub const DIFile = c.ZigLLVMDIFile;
pub const DICompileUnit = c.ZigLLVMDICompileUnit;
pub const ABIAlignmentOfType = c.LLVMABIAlignmentOfType; pub const ABIAlignmentOfType = c.LLVMABIAlignmentOfType;
pub const AddAttributeAtIndex = c.LLVMAddAttributeAtIndex; pub const AddAttributeAtIndex = c.LLVMAddAttributeAtIndex;
pub const AddFunction = c.LLVMAddFunction;
pub const AddGlobal = c.LLVMAddGlobal;
pub const AddModuleCodeViewFlag = c.ZigLLVMAddModuleCodeViewFlag; pub const AddModuleCodeViewFlag = c.ZigLLVMAddModuleCodeViewFlag;
pub const AddModuleDebugInfoFlag = c.ZigLLVMAddModuleDebugInfoFlag; pub const AddModuleDebugInfoFlag = c.ZigLLVMAddModuleDebugInfoFlag;
pub const ArrayType = c.LLVMArrayType;
pub const BuildLoad = c.LLVMBuildLoad;
pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation; pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation;
pub const ConstAllOnes = c.LLVMConstAllOnes; pub const ConstAllOnes = c.LLVMConstAllOnes;
pub const ConstArray = c.LLVMConstArray; pub const ConstArray = c.LLVMConstArray;
pub const ConstBitCast = c.LLVMConstBitCast; pub const ConstBitCast = c.LLVMConstBitCast;
pub const ConstInt = c.LLVMConstInt;
pub const ConstIntOfArbitraryPrecision = c.LLVMConstIntOfArbitraryPrecision; pub const ConstIntOfArbitraryPrecision = c.LLVMConstIntOfArbitraryPrecision;
pub const ConstNeg = c.LLVMConstNeg; pub const ConstNeg = c.LLVMConstNeg;
pub const ConstNull = c.LLVMConstNull;
pub const ConstStringInContext = c.LLVMConstStringInContext;
pub const ConstStructInContext = c.LLVMConstStructInContext; pub const ConstStructInContext = c.LLVMConstStructInContext;
pub const CopyStringRepOfTargetData = c.LLVMCopyStringRepOfTargetData;
pub const CreateBuilderInContext = c.LLVMCreateBuilderInContext;
pub const CreateCompileUnit = c.ZigLLVMCreateCompileUnit;
pub const CreateDIBuilder = c.ZigLLVMCreateDIBuilder;
pub const CreateEnumAttribute = c.LLVMCreateEnumAttribute;
pub const CreateFile = c.ZigLLVMCreateFile;
pub const CreateStringAttribute = c.LLVMCreateStringAttribute;
pub const CreateTargetDataLayout = c.LLVMCreateTargetDataLayout;
pub const CreateTargetMachine = c.LLVMCreateTargetMachine;
pub const DIBuilderFinalize = c.ZigLLVMDIBuilderFinalize; pub const DIBuilderFinalize = c.ZigLLVMDIBuilderFinalize;
pub const DisposeBuilder = c.LLVMDisposeBuilder; pub const DisposeBuilder = c.LLVMDisposeBuilder;
pub const DisposeDIBuilder = c.ZigLLVMDisposeDIBuilder; pub const DisposeDIBuilder = c.ZigLLVMDisposeDIBuilder;
@ -62,9 +48,7 @@ pub const DumpModule = c.LLVMDumpModule;
pub const FP128TypeInContext = c.LLVMFP128TypeInContext; pub const FP128TypeInContext = c.LLVMFP128TypeInContext;
pub const FloatTypeInContext = c.LLVMFloatTypeInContext; pub const FloatTypeInContext = c.LLVMFloatTypeInContext;
pub const GetEnumAttributeKindForName = c.LLVMGetEnumAttributeKindForName; pub const GetEnumAttributeKindForName = c.LLVMGetEnumAttributeKindForName;
pub const GetHostCPUName = c.ZigLLVMGetHostCPUName;
pub const GetMDKindIDInContext = c.LLVMGetMDKindIDInContext; pub const GetMDKindIDInContext = c.LLVMGetMDKindIDInContext;
pub const GetNativeFeatures = c.ZigLLVMGetNativeFeatures;
pub const GetUndef = c.LLVMGetUndef; pub const GetUndef = c.LLVMGetUndef;
pub const HalfTypeInContext = c.LLVMHalfTypeInContext; pub const HalfTypeInContext = c.LLVMHalfTypeInContext;
pub const InitializeAllAsmParsers = c.LLVMInitializeAllAsmParsers; pub const InitializeAllAsmParsers = c.LLVMInitializeAllAsmParsers;
@ -81,14 +65,11 @@ pub const Int64TypeInContext = c.LLVMInt64TypeInContext;
pub const Int8TypeInContext = c.LLVMInt8TypeInContext; pub const Int8TypeInContext = c.LLVMInt8TypeInContext;
pub const IntPtrTypeForASInContext = c.LLVMIntPtrTypeForASInContext; pub const IntPtrTypeForASInContext = c.LLVMIntPtrTypeForASInContext;
pub const IntPtrTypeInContext = c.LLVMIntPtrTypeInContext; pub const IntPtrTypeInContext = c.LLVMIntPtrTypeInContext;
pub const IntTypeInContext = c.LLVMIntTypeInContext;
pub const LabelTypeInContext = c.LLVMLabelTypeInContext; pub const LabelTypeInContext = c.LLVMLabelTypeInContext;
pub const MDNodeInContext = c.LLVMMDNodeInContext; pub const MDNodeInContext = c.LLVMMDNodeInContext;
pub const MDStringInContext = c.LLVMMDStringInContext; pub const MDStringInContext = c.LLVMMDStringInContext;
pub const MetadataTypeInContext = c.LLVMMetadataTypeInContext; pub const MetadataTypeInContext = c.LLVMMetadataTypeInContext;
pub const ModuleCreateWithNameInContext = c.LLVMModuleCreateWithNameInContext;
pub const PPCFP128TypeInContext = c.LLVMPPCFP128TypeInContext; pub const PPCFP128TypeInContext = c.LLVMPPCFP128TypeInContext;
pub const PointerType = c.LLVMPointerType;
pub const SetAlignment = c.LLVMSetAlignment; pub const SetAlignment = c.LLVMSetAlignment;
pub const SetDataLayout = c.LLVMSetDataLayout; pub const SetDataLayout = c.LLVMSetDataLayout;
pub const SetGlobalConstant = c.LLVMSetGlobalConstant; pub const SetGlobalConstant = c.LLVMSetGlobalConstant;
@ -99,50 +80,146 @@ pub const SetUnnamedAddr = c.LLVMSetUnnamedAddr;
pub const SetVolatile = c.LLVMSetVolatile; pub const SetVolatile = c.LLVMSetVolatile;
pub const StructTypeInContext = c.LLVMStructTypeInContext; pub const StructTypeInContext = c.LLVMStructTypeInContext;
pub const TokenTypeInContext = c.LLVMTokenTypeInContext; pub const TokenTypeInContext = c.LLVMTokenTypeInContext;
pub const VoidTypeInContext = c.LLVMVoidTypeInContext;
pub const X86FP80TypeInContext = c.LLVMX86FP80TypeInContext; pub const X86FP80TypeInContext = c.LLVMX86FP80TypeInContext;
pub const X86MMXTypeInContext = c.LLVMX86MMXTypeInContext; pub const X86MMXTypeInContext = c.LLVMX86MMXTypeInContext;
pub const AddGlobal = LLVMAddGlobal;
extern fn LLVMAddGlobal(M: *Module, Ty: *Type, Name: [*]const u8) ?*Value;
pub const ConstStringInContext = LLVMConstStringInContext;
extern fn LLVMConstStringInContext(C: *Context, Str: [*]const u8, Length: c_uint, DontNullTerminate: Bool) ?*Value;
pub const ConstInt = LLVMConstInt;
extern fn LLVMConstInt(IntTy: *Type, N: c_ulonglong, SignExtend: Bool) ?*Value;
pub const BuildLoad = LLVMBuildLoad;
extern fn LLVMBuildLoad(arg0: *Builder, PointerVal: *Value, Name: [*]const u8) ?*Value;
pub const ConstNull = LLVMConstNull;
extern fn LLVMConstNull(Ty: *Type) ?*Value;
pub const CreateStringAttribute = LLVMCreateStringAttribute;
extern fn LLVMCreateStringAttribute(
C: *Context,
K: [*]const u8,
KLength: c_uint,
V: [*]const u8,
VLength: c_uint,
) ?*Attribute;
pub const CreateEnumAttribute = LLVMCreateEnumAttribute;
extern fn LLVMCreateEnumAttribute(C: *Context, KindID: c_uint, Val: u64) ?*Attribute;
pub const AddFunction = LLVMAddFunction;
extern fn LLVMAddFunction(M: *Module, Name: [*]const u8, FunctionTy: *Type) ?*Value;
pub const CreateCompileUnit = ZigLLVMCreateCompileUnit;
extern fn ZigLLVMCreateCompileUnit(
dibuilder: *DIBuilder,
lang: c_uint,
difile: *DIFile,
producer: [*]const u8,
is_optimized: bool,
flags: [*]const u8,
runtime_version: c_uint,
split_name: [*]const u8,
dwo_id: u64,
emit_debug_info: bool,
) ?*DICompileUnit;
pub const CreateFile = ZigLLVMCreateFile;
extern fn ZigLLVMCreateFile(dibuilder: *DIBuilder, filename: [*]const u8, directory: [*]const u8) ?*DIFile;
pub const ArrayType = LLVMArrayType;
extern fn LLVMArrayType(ElementType: *Type, ElementCount: c_uint) ?*Type;
pub const CreateDIBuilder = ZigLLVMCreateDIBuilder;
extern fn ZigLLVMCreateDIBuilder(module: *Module, allow_unresolved: bool) ?*DIBuilder;
pub const PointerType = LLVMPointerType;
extern fn LLVMPointerType(ElementType: *Type, AddressSpace: c_uint) ?*Type;
pub const CreateBuilderInContext = LLVMCreateBuilderInContext;
extern fn LLVMCreateBuilderInContext(C: *Context) ?*Builder;
pub const IntTypeInContext = LLVMIntTypeInContext;
extern fn LLVMIntTypeInContext(C: *Context, NumBits: c_uint) ?*Type;
pub const ModuleCreateWithNameInContext = LLVMModuleCreateWithNameInContext;
extern fn LLVMModuleCreateWithNameInContext(ModuleID: [*]const u8, C: *Context) ?*Module;
pub const VoidTypeInContext = LLVMVoidTypeInContext;
extern fn LLVMVoidTypeInContext(C: *Context) ?*Type;
pub const ContextCreate = LLVMContextCreate;
extern fn LLVMContextCreate() ?*Context;
pub const ContextDispose = LLVMContextDispose;
extern fn LLVMContextDispose(C: *Context) void;
pub const CopyStringRepOfTargetData = LLVMCopyStringRepOfTargetData;
extern fn LLVMCopyStringRepOfTargetData(TD: *TargetData) ?[*]u8;
pub const CreateTargetDataLayout = LLVMCreateTargetDataLayout;
extern fn LLVMCreateTargetDataLayout(T: *TargetMachine) ?*TargetData;
pub const CreateTargetMachine = LLVMCreateTargetMachine;
extern fn LLVMCreateTargetMachine(
T: *Target,
Triple: [*]const u8,
CPU: [*]const u8,
Features: [*]const u8,
Level: CodeGenOptLevel,
Reloc: RelocMode,
CodeModel: CodeModel,
) ?*TargetMachine;
pub const GetHostCPUName = LLVMGetHostCPUName;
extern fn LLVMGetHostCPUName() ?[*]u8;
pub const GetNativeFeatures = ZigLLVMGetNativeFeatures;
extern fn ZigLLVMGetNativeFeatures() ?[*]u8;
pub const GetElementType = LLVMGetElementType; pub const GetElementType = LLVMGetElementType;
extern fn LLVMGetElementType(Ty: TypeRef) TypeRef; extern fn LLVMGetElementType(Ty: *Type) *Type;
pub const TypeOf = LLVMTypeOf; pub const TypeOf = LLVMTypeOf;
extern fn LLVMTypeOf(Val: ValueRef) TypeRef; extern fn LLVMTypeOf(Val: *Value) *Type;
pub const BuildStore = LLVMBuildStore; pub const BuildStore = LLVMBuildStore;
extern fn LLVMBuildStore(arg0: BuilderRef, Val: ValueRef, Ptr: ValueRef) ?ValueRef; extern fn LLVMBuildStore(arg0: *Builder, Val: *Value, Ptr: *Value) ?*Value;
pub const BuildAlloca = LLVMBuildAlloca; pub const BuildAlloca = LLVMBuildAlloca;
extern fn LLVMBuildAlloca(arg0: BuilderRef, Ty: TypeRef, Name: ?[*]const u8) ?ValueRef; extern fn LLVMBuildAlloca(arg0: *Builder, Ty: *Type, Name: ?[*]const u8) ?*Value;
pub const ConstInBoundsGEP = LLVMConstInBoundsGEP; pub const ConstInBoundsGEP = LLVMConstInBoundsGEP;
pub extern fn LLVMConstInBoundsGEP(ConstantVal: ValueRef, ConstantIndices: [*]ValueRef, NumIndices: c_uint) ?ValueRef; pub extern fn LLVMConstInBoundsGEP(ConstantVal: *Value, ConstantIndices: [*]*Value, NumIndices: c_uint) ?*Value;
pub const GetTargetFromTriple = LLVMGetTargetFromTriple; pub const GetTargetFromTriple = LLVMGetTargetFromTriple;
extern fn LLVMGetTargetFromTriple(Triple: [*]const u8, T: *TargetRef, ErrorMessage: ?*[*]u8) Bool; extern fn LLVMGetTargetFromTriple(Triple: [*]const u8, T: **Target, ErrorMessage: ?*[*]u8) Bool;
pub const VerifyModule = LLVMVerifyModule; pub const VerifyModule = LLVMVerifyModule;
extern fn LLVMVerifyModule(M: ModuleRef, Action: VerifierFailureAction, OutMessage: *?[*]u8) Bool; extern fn LLVMVerifyModule(M: *Module, Action: VerifierFailureAction, OutMessage: *?[*]u8) Bool;
pub const GetInsertBlock = LLVMGetInsertBlock; pub const GetInsertBlock = LLVMGetInsertBlock;
extern fn LLVMGetInsertBlock(Builder: BuilderRef) BasicBlockRef; extern fn LLVMGetInsertBlock(Builder: *Builder) *BasicBlock;
pub const FunctionType = LLVMFunctionType; pub const FunctionType = LLVMFunctionType;
extern fn LLVMFunctionType( extern fn LLVMFunctionType(
ReturnType: TypeRef, ReturnType: *Type,
ParamTypes: [*]TypeRef, ParamTypes: [*]*Type,
ParamCount: c_uint, ParamCount: c_uint,
IsVarArg: Bool, IsVarArg: Bool,
) ?TypeRef; ) ?*Type;
pub const GetParam = LLVMGetParam; pub const GetParam = LLVMGetParam;
extern fn LLVMGetParam(Fn: ValueRef, Index: c_uint) ValueRef; extern fn LLVMGetParam(Fn: *Value, Index: c_uint) *Value;
pub const AppendBasicBlockInContext = LLVMAppendBasicBlockInContext; pub const AppendBasicBlockInContext = LLVMAppendBasicBlockInContext;
extern fn LLVMAppendBasicBlockInContext(C: ContextRef, Fn: ValueRef, Name: [*]const u8) ?BasicBlockRef; extern fn LLVMAppendBasicBlockInContext(C: *Context, Fn: *Value, Name: [*]const u8) ?*BasicBlock;
pub const PositionBuilderAtEnd = LLVMPositionBuilderAtEnd; pub const PositionBuilderAtEnd = LLVMPositionBuilderAtEnd;
extern fn LLVMPositionBuilderAtEnd(Builder: BuilderRef, Block: BasicBlockRef) void; extern fn LLVMPositionBuilderAtEnd(Builder: *Builder, Block: *BasicBlock) void;
pub const AbortProcessAction = VerifierFailureAction.LLVMAbortProcessAction; pub const AbortProcessAction = VerifierFailureAction.LLVMAbortProcessAction;
pub const PrintMessageAction = VerifierFailureAction.LLVMPrintMessageAction; pub const PrintMessageAction = VerifierFailureAction.LLVMPrintMessageAction;
@ -190,17 +267,17 @@ pub const FnInline = extern enum {
}; };
fn removeNullability(comptime T: type) type { fn removeNullability(comptime T: type) type {
comptime assert(@typeId(T) == builtin.TypeId.Optional); comptime assert(@typeInfo(T).Pointer.size == @import("builtin").TypeInfo.Pointer.Size.C);
return T.Child; return *T.Child;
} }
pub const BuildRet = LLVMBuildRet; pub const BuildRet = LLVMBuildRet;
extern fn LLVMBuildRet(arg0: BuilderRef, V: ?ValueRef) ?ValueRef; extern fn LLVMBuildRet(arg0: *Builder, V: ?*Value) ?*Value;
pub const TargetMachineEmitToFile = ZigLLVMTargetMachineEmitToFile; pub const TargetMachineEmitToFile = ZigLLVMTargetMachineEmitToFile;
extern fn ZigLLVMTargetMachineEmitToFile( extern fn ZigLLVMTargetMachineEmitToFile(
targ_machine_ref: TargetMachineRef, targ_machine_ref: *TargetMachine,
module_ref: ModuleRef, module_ref: *Module,
filename: [*]const u8, filename: [*]const u8,
output_type: EmitOutputType, output_type: EmitOutputType,
error_message: *[*]u8, error_message: *[*]u8,
@ -209,6 +286,6 @@ extern fn ZigLLVMTargetMachineEmitToFile(
) bool; ) bool;
pub const BuildCall = ZigLLVMBuildCall; pub const BuildCall = ZigLLVMBuildCall;
extern fn ZigLLVMBuildCall(B: BuilderRef, Fn: ValueRef, Args: [*]ValueRef, NumArgs: c_uint, CC: c_uint, fn_inline: FnInline, Name: [*]const u8) ?ValueRef; extern fn ZigLLVMBuildCall(B: *Builder, Fn: *Value, Args: [*]*Value, NumArgs: c_uint, CC: c_uint, fn_inline: FnInline, Name: [*]const u8) ?*Value;
pub const PrivateLinkage = c.LLVMLinkage.LLVMPrivateLinkage; pub const PrivateLinkage = c.LLVMLinkage.LLVMPrivateLinkage;

View File

@ -24,7 +24,7 @@ var stderr_file: os.File = undefined;
var stderr: *io.OutStream(os.File.WriteError) = undefined; var stderr: *io.OutStream(os.File.WriteError) = undefined;
var stdout: *io.OutStream(os.File.WriteError) = undefined; var stdout: *io.OutStream(os.File.WriteError) = undefined;
const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB pub const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB
const usage = const usage =
\\usage: zig [command] [options] \\usage: zig [command] [options]
@ -154,9 +154,7 @@ const usage_build_generic =
\\ release-small optimize for small binary, safety off \\ release-small optimize for small binary, safety off
\\ --static Output will be statically linked \\ --static Output will be statically linked
\\ --strip Exclude debug symbols \\ --strip Exclude debug symbols
\\ --target-arch [name] Specify target architecture \\ -target [name] <arch><sub>-<os>-<abi> see the targets command
\\ --target-environ [name] Specify target environment
\\ --target-os [name] Specify target operating system
\\ --verbose-tokenize Turn on compiler debug output for tokenization \\ --verbose-tokenize Turn on compiler debug output for tokenization
\\ --verbose-ast-tree Turn on compiler debug output for parsing into an AST (tree view) \\ --verbose-ast-tree Turn on compiler debug output for parsing into an AST (tree view)
\\ --verbose-ast-fmt Turn on compiler debug output for parsing into an AST (render source) \\ --verbose-ast-fmt Turn on compiler debug output for parsing into an AST (render source)
@ -220,9 +218,7 @@ const args_build_generic = []Flag{
Flag.Bool("--pkg-end"), Flag.Bool("--pkg-end"),
Flag.Bool("--static"), Flag.Bool("--static"),
Flag.Bool("--strip"), Flag.Bool("--strip"),
Flag.Arg1("--target-arch"), Flag.Arg1("-target"),
Flag.Arg1("--target-environ"),
Flag.Arg1("--target-os"),
Flag.Bool("--verbose-tokenize"), Flag.Bool("--verbose-tokenize"),
Flag.Bool("--verbose-ast-tree"), Flag.Bool("--verbose-ast-tree"),
Flag.Bool("--verbose-ast-fmt"), Flag.Bool("--verbose-ast-fmt"),
@ -510,7 +506,7 @@ fn cmdBuildObj(allocator: *Allocator, args: []const []const u8) !void {
return buildOutputType(allocator, args, Compilation.Kind.Obj); return buildOutputType(allocator, args, Compilation.Kind.Obj);
} }
const usage_fmt = pub const usage_fmt =
\\usage: zig fmt [file]... \\usage: zig fmt [file]...
\\ \\
\\ Formats the input files and modifies them in-place. \\ Formats the input files and modifies them in-place.
@ -527,7 +523,7 @@ const usage_fmt =
\\ \\
; ;
const args_fmt_spec = []Flag{ pub const args_fmt_spec = []Flag{
Flag.Bool("--help"), Flag.Bool("--help"),
Flag.Bool("--check"), Flag.Bool("--check"),
Flag.Option("--color", []const []const u8{ Flag.Option("--color", []const []const u8{
@ -839,15 +835,15 @@ fn cmdTargets(allocator: *Allocator, args: []const []const u8) !void {
} }
try stdout.write("\n"); try stdout.write("\n");
try stdout.write("Environments:\n"); try stdout.write("C ABIs:\n");
{ {
comptime var i: usize = 0; comptime var i: usize = 0;
inline while (i < @memberCount(builtin.Environ)) : (i += 1) { inline while (i < @memberCount(builtin.Abi)) : (i += 1) {
comptime const environ_tag = @memberName(builtin.Environ, i); comptime const abi_tag = @memberName(builtin.Abi, i);
// NOTE: Cannot use empty string, see #918. // NOTE: Cannot use empty string, see #918.
comptime const native_str = if (comptime mem.eql(u8, environ_tag, @tagName(builtin.environ))) " (native)\n" else "\n"; comptime const native_str = if (comptime mem.eql(u8, abi_tag, @tagName(builtin.abi))) " (native)\n" else "\n";
try stdout.print(" {}{}", environ_tag, native_str); try stdout.print(" {}{}", abi_tag, native_str);
} }
} }
} }

View File

@ -362,7 +362,7 @@ pub const Scope = struct {
pub const Param = struct { pub const Param = struct {
index: usize, index: usize,
typ: *Type, typ: *Type,
llvm_value: llvm.ValueRef, llvm_value: *llvm.Value,
}; };
pub fn createParam( pub fn createParam(

View File

@ -16,7 +16,7 @@ pub const Target = union(enum) {
pub const Cross = struct { pub const Cross = struct {
arch: builtin.Arch, arch: builtin.Arch,
os: builtin.Os, os: builtin.Os,
environ: builtin.Environ, abi: builtin.Abi,
object_format: builtin.ObjectFormat, object_format: builtin.ObjectFormat,
}; };
@ -49,16 +49,16 @@ pub const Target = union(enum) {
} }
pub fn getArch(self: Target) builtin.Arch { pub fn getArch(self: Target) builtin.Arch {
return switch (self) { switch (self) {
Target.Native => builtin.arch, Target.Native => return builtin.arch,
@TagType(Target).Cross => |t| t.arch, @TagType(Target).Cross => |t| return t.arch,
}; }
} }
pub fn getEnviron(self: Target) builtin.Environ { pub fn getAbi(self: Target) builtin.Abi {
return switch (self) { return switch (self) {
Target.Native => builtin.environ, Target.Native => builtin.abi,
@TagType(Target).Cross => |t| t.environ, @TagType(Target).Cross => |t| t.abi,
}; };
} }
@ -93,50 +93,10 @@ pub const Target = union(enum) {
/// TODO expose the arch and subarch separately /// TODO expose the arch and subarch separately
pub fn isArmOrThumb(self: Target) bool { pub fn isArmOrThumb(self: Target) bool {
return switch (self.getArch()) { return switch (self.getArch()) {
builtin.Arch.armv8_5a, builtin.Arch.arm,
builtin.Arch.armv8_4a, builtin.Arch.armeb,
builtin.Arch.armv8_3a, builtin.Arch.aarch64,
builtin.Arch.armv8_2a, builtin.Arch.aarch64_be,
builtin.Arch.armv8_1a,
builtin.Arch.armv8,
builtin.Arch.armv8r,
builtin.Arch.armv8m_baseline,
builtin.Arch.armv8m_mainline,
builtin.Arch.armv7,
builtin.Arch.armv7em,
builtin.Arch.armv7m,
builtin.Arch.armv7s,
builtin.Arch.armv7k,
builtin.Arch.armv7ve,
builtin.Arch.armv6,
builtin.Arch.armv6m,
builtin.Arch.armv6k,
builtin.Arch.armv6t2,
builtin.Arch.armv5,
builtin.Arch.armv5te,
builtin.Arch.armv4t,
builtin.Arch.armebv8_5a,
builtin.Arch.armebv8_4a,
builtin.Arch.armebv8_3a,
builtin.Arch.armebv8_2a,
builtin.Arch.armebv8_1a,
builtin.Arch.armebv8,
builtin.Arch.armebv8r,
builtin.Arch.armebv8m_baseline,
builtin.Arch.armebv8m_mainline,
builtin.Arch.armebv7,
builtin.Arch.armebv7em,
builtin.Arch.armebv7m,
builtin.Arch.armebv7s,
builtin.Arch.armebv7k,
builtin.Arch.armebv7ve,
builtin.Arch.armebv6,
builtin.Arch.armebv6m,
builtin.Arch.armebv6k,
builtin.Arch.armebv6t2,
builtin.Arch.armebv5,
builtin.Arch.armebv5te,
builtin.Arch.armebv4t,
builtin.Arch.thumb, builtin.Arch.thumb,
builtin.Arch.thumbeb, builtin.Arch.thumbeb,
=> true, => true,
@ -159,14 +119,14 @@ pub const Target = union(enum) {
// LLVM WebAssembly output support requires the target to be activated at // LLVM WebAssembly output support requires the target to be activated at
// build type with -DCMAKE_LLVM_EXPIERMENTAL_TARGETS_TO_BUILD=WebAssembly. // build type with -DCMAKE_LLVM_EXPIERMENTAL_TARGETS_TO_BUILD=WebAssembly.
// //
// LLVM determines the output format based on the environment suffix, // LLVM determines the output format based on the abi suffix,
// defaulting to an object based on the architecture. The default format in // defaulting to an object based on the architecture. The default format in
// LLVM 6 sets the wasm arch output incorrectly to ELF. We need to // LLVM 6 sets the wasm arch output incorrectly to ELF. We need to
// explicitly set this ourself in order for it to work. // explicitly set this ourself in order for it to work.
// //
// This is fixed in LLVM 7 and you will be able to get wasm output by // This is fixed in LLVM 7 and you will be able to get wasm output by
// using the target triple `wasm32-unknown-unknown-unknown`. // using the target triple `wasm32-unknown-unknown-unknown`.
const env_name = if (self.isWasm()) "wasm" else @tagName(self.getEnviron()); const env_name = if (self.isWasm()) "wasm" else @tagName(self.getAbi());
var out = &std.io.BufferOutStream.init(&result).stream; var out = &std.io.BufferOutStream.init(&result).stream;
try out.print("{}-unknown-{}-{}", @tagName(self.getArch()), @tagName(self.getOs()), env_name); try out.print("{}-unknown-{}-{}", @tagName(self.getArch()), @tagName(self.getOs()), env_name);
@ -185,50 +145,8 @@ pub const Target = union(enum) {
=> return 16, => return 16,
builtin.Arch.arc, builtin.Arch.arc,
builtin.Arch.armv8_5a, builtin.Arch.arm,
builtin.Arch.armv8_4a, builtin.Arch.armeb,
builtin.Arch.armv8_3a,
builtin.Arch.armv8_2a,
builtin.Arch.armv8_1a,
builtin.Arch.armv8,
builtin.Arch.armv8r,
builtin.Arch.armv8m_baseline,
builtin.Arch.armv8m_mainline,
builtin.Arch.armv7,
builtin.Arch.armv7em,
builtin.Arch.armv7m,
builtin.Arch.armv7s,
builtin.Arch.armv7k,
builtin.Arch.armv7ve,
builtin.Arch.armv6,
builtin.Arch.armv6m,
builtin.Arch.armv6k,
builtin.Arch.armv6t2,
builtin.Arch.armv5,
builtin.Arch.armv5te,
builtin.Arch.armv4t,
builtin.Arch.armebv8_5a,
builtin.Arch.armebv8_4a,
builtin.Arch.armebv8_3a,
builtin.Arch.armebv8_2a,
builtin.Arch.armebv8_1a,
builtin.Arch.armebv8,
builtin.Arch.armebv8r,
builtin.Arch.armebv8m_baseline,
builtin.Arch.armebv8m_mainline,
builtin.Arch.armebv7,
builtin.Arch.armebv7em,
builtin.Arch.armebv7m,
builtin.Arch.armebv7s,
builtin.Arch.armebv7k,
builtin.Arch.armebv7ve,
builtin.Arch.armebv6,
builtin.Arch.armebv6m,
builtin.Arch.armebv6k,
builtin.Arch.armebv6t2,
builtin.Arch.armebv5,
builtin.Arch.armebv5te,
builtin.Arch.armebv4t,
builtin.Arch.hexagon, builtin.Arch.hexagon,
builtin.Arch.le32, builtin.Arch.le32,
builtin.Arch.mipsr6, builtin.Arch.mipsr6,
@ -248,35 +166,17 @@ pub const Target = union(enum) {
builtin.Arch.amdil, builtin.Arch.amdil,
builtin.Arch.hsail, builtin.Arch.hsail,
builtin.Arch.spir, builtin.Arch.spir,
builtin.Arch.kalimbav3, builtin.Arch.kalimba,
builtin.Arch.kalimbav4,
builtin.Arch.kalimbav5,
builtin.Arch.shave, builtin.Arch.shave,
builtin.Arch.lanai, builtin.Arch.lanai,
builtin.Arch.wasm32, builtin.Arch.wasm32,
builtin.Arch.renderscript32, builtin.Arch.renderscript32,
=> return 32, => return 32,
builtin.Arch.aarch64v8_5a, builtin.Arch.aarch64,
builtin.Arch.aarch64v8_4a, builtin.Arch.aarch64_be,
builtin.Arch.aarch64v8_3a, builtin.Arch.mips64,
builtin.Arch.aarch64v8_2a, builtin.Arch.mips64el,
builtin.Arch.aarch64v8_1a,
builtin.Arch.aarch64v8,
builtin.Arch.aarch64v8r,
builtin.Arch.aarch64v8m_baseline,
builtin.Arch.aarch64v8m_mainline,
builtin.Arch.aarch64_bev8_5a,
builtin.Arch.aarch64_bev8_4a,
builtin.Arch.aarch64_bev8_3a,
builtin.Arch.aarch64_bev8_2a,
builtin.Arch.aarch64_bev8_1a,
builtin.Arch.aarch64_bev8,
builtin.Arch.aarch64_bev8r,
builtin.Arch.aarch64_bev8m_baseline,
builtin.Arch.aarch64_bev8m_mainline,
builtin.Arch.mips64r6,
builtin.Arch.mips64elr6,
builtin.Arch.powerpc64, builtin.Arch.powerpc64,
builtin.Arch.powerpc64le, builtin.Arch.powerpc64le,
builtin.Arch.riscv64, builtin.Arch.riscv64,
@ -298,17 +198,17 @@ pub const Target = union(enum) {
} }
pub fn getFloatAbi(self: Target) FloatAbi { pub fn getFloatAbi(self: Target) FloatAbi {
return switch (self.getEnviron()) { return switch (self.getAbi()) {
builtin.Environ.gnueabihf, builtin.Abi.gnueabihf,
builtin.Environ.eabihf, builtin.Abi.eabihf,
builtin.Environ.musleabihf, builtin.Abi.musleabihf,
=> FloatAbi.Hard, => FloatAbi.Hard,
else => FloatAbi.Soft, else => FloatAbi.Soft,
}; };
} }
pub fn getDynamicLinkerPath(self: Target) ?[]const u8 { pub fn getDynamicLinkerPath(self: Target) ?[]const u8 {
const env = self.getEnviron(); const env = self.getAbi();
const arch = self.getArch(); const arch = self.getArch();
const os = self.getOs(); const os = self.getOs();
switch (os) { switch (os) {
@ -317,21 +217,21 @@ pub const Target = union(enum) {
}, },
builtin.Os.linux => { builtin.Os.linux => {
switch (env) { switch (env) {
builtin.Environ.android => { builtin.Abi.android => {
if (self.is64bit()) { if (self.is64bit()) {
return "/system/bin/linker64"; return "/system/bin/linker64";
} else { } else {
return "/system/bin/linker"; return "/system/bin/linker";
} }
}, },
builtin.Environ.gnux32 => { builtin.Abi.gnux32 => {
if (arch == builtin.Arch.x86_64) { if (arch == builtin.Arch.x86_64) {
return "/libx32/ld-linux-x32.so.2"; return "/libx32/ld-linux-x32.so.2";
} }
}, },
builtin.Environ.musl, builtin.Abi.musl,
builtin.Environ.musleabi, builtin.Abi.musleabi,
builtin.Environ.musleabihf, builtin.Abi.musleabihf,
=> { => {
if (arch == builtin.Arch.x86_64) { if (arch == builtin.Arch.x86_64) {
return "/lib/ld-musl-x86_64.so.1"; return "/lib/ld-musl-x86_64.so.1";
@ -345,73 +245,18 @@ pub const Target = union(enum) {
builtin.Arch.sparcel, builtin.Arch.sparcel,
=> return "/lib/ld-linux.so.2", => return "/lib/ld-linux.so.2",
builtin.Arch.aarch64v8_5a, builtin.Arch.aarch64 => return "/lib/ld-linux-aarch64.so.1",
builtin.Arch.aarch64v8_4a,
builtin.Arch.aarch64v8_3a,
builtin.Arch.aarch64v8_2a,
builtin.Arch.aarch64v8_1a,
builtin.Arch.aarch64v8,
builtin.Arch.aarch64v8r,
builtin.Arch.aarch64v8m_baseline,
builtin.Arch.aarch64v8m_mainline,
=> return "/lib/ld-linux-aarch64.so.1",
builtin.Arch.aarch64_bev8_5a, builtin.Arch.aarch64_be => return "/lib/ld-linux-aarch64_be.so.1",
builtin.Arch.aarch64_bev8_4a,
builtin.Arch.aarch64_bev8_3a,
builtin.Arch.aarch64_bev8_2a,
builtin.Arch.aarch64_bev8_1a,
builtin.Arch.aarch64_bev8,
builtin.Arch.aarch64_bev8r,
builtin.Arch.aarch64_bev8m_baseline,
builtin.Arch.aarch64_bev8m_mainline,
=> return "/lib/ld-linux-aarch64_be.so.1",
builtin.Arch.armv8_5a, builtin.Arch.arm,
builtin.Arch.armv8_4a,
builtin.Arch.armv8_3a,
builtin.Arch.armv8_2a,
builtin.Arch.armv8_1a,
builtin.Arch.armv8,
builtin.Arch.armv8r,
builtin.Arch.armv8m_baseline,
builtin.Arch.armv8m_mainline,
builtin.Arch.armv7,
builtin.Arch.armv7em,
builtin.Arch.armv7m,
builtin.Arch.armv7s,
builtin.Arch.armv7k,
builtin.Arch.armv7ve,
builtin.Arch.armv6,
builtin.Arch.armv6m,
builtin.Arch.armv6k,
builtin.Arch.armv6t2,
builtin.Arch.armv5,
builtin.Arch.armv5te,
builtin.Arch.armv4t,
builtin.Arch.thumb, builtin.Arch.thumb,
builtin.Arch.armebv8_5a, => return switch (self.getFloatAbi()) {
builtin.Arch.armebv8_4a, FloatAbi.Hard => return "/lib/ld-linux-armhf.so.3",
builtin.Arch.armebv8_3a, else => return "/lib/ld-linux.so.3",
builtin.Arch.armebv8_2a, },
builtin.Arch.armebv8_1a,
builtin.Arch.armebv8, builtin.Arch.armeb,
builtin.Arch.armebv8r,
builtin.Arch.armebv8m_baseline,
builtin.Arch.armebv8m_mainline,
builtin.Arch.armebv7,
builtin.Arch.armebv7em,
builtin.Arch.armebv7m,
builtin.Arch.armebv7s,
builtin.Arch.armebv7k,
builtin.Arch.armebv7ve,
builtin.Arch.armebv6,
builtin.Arch.armebv6m,
builtin.Arch.armebv6k,
builtin.Arch.armebv6t2,
builtin.Arch.armebv5,
builtin.Arch.armebv5te,
builtin.Arch.armebv4t,
builtin.Arch.thumbeb, builtin.Arch.thumbeb,
=> return switch (self.getFloatAbi()) { => return switch (self.getFloatAbi()) {
FloatAbi.Hard => return "/lib/ld-linux-armhf.so.3", FloatAbi.Hard => return "/lib/ld-linux-armhf.so.3",
@ -454,9 +299,7 @@ pub const Target = union(enum) {
builtin.Arch.hsail64, builtin.Arch.hsail64,
builtin.Arch.spir, builtin.Arch.spir,
builtin.Arch.spir64, builtin.Arch.spir64,
builtin.Arch.kalimbav3, builtin.Arch.kalimba,
builtin.Arch.kalimbav4,
builtin.Arch.kalimbav5,
builtin.Arch.shave, builtin.Arch.shave,
builtin.Arch.lanai, builtin.Arch.lanai,
builtin.Arch.wasm32, builtin.Arch.wasm32,
@ -470,8 +313,8 @@ pub const Target = union(enum) {
} }
} }
pub fn llvmTargetFromTriple(triple: std.Buffer) !llvm.TargetRef { pub fn llvmTargetFromTriple(triple: std.Buffer) !*llvm.Target {
var result: llvm.TargetRef = undefined; var result: *llvm.Target = undefined;
var err_msg: [*]u8 = undefined; var err_msg: [*]u8 = undefined;
if (llvm.GetTargetFromTriple(triple.ptr(), &result, &err_msg) != 0) { if (llvm.GetTargetFromTriple(triple.ptr(), &result, &err_msg) != 0) {
std.debug.warn("triple: {s} error: {s}\n", triple.ptr(), err_msg); std.debug.warn("triple: {s} error: {s}\n", triple.ptr(), err_msg);
@ -582,39 +425,9 @@ pub const Target = union(enum) {
pub fn getDarwinArchString(self: Target) []const u8 { pub fn getDarwinArchString(self: Target) []const u8 {
const arch = self.getArch(); const arch = self.getArch();
switch (arch) { switch (arch) {
builtin.Arch.aarch64v8_5a, builtin.Arch.aarch64 => return "arm64",
builtin.Arch.aarch64v8_4a,
builtin.Arch.aarch64v8_3a,
builtin.Arch.aarch64v8_2a,
builtin.Arch.aarch64v8_1a,
builtin.Arch.aarch64v8,
builtin.Arch.aarch64v8r,
builtin.Arch.aarch64v8m_baseline,
builtin.Arch.aarch64v8m_mainline,
=> return "arm64",
builtin.Arch.thumb, builtin.Arch.thumb,
builtin.Arch.armv8_5a, builtin.Arch.arm,
builtin.Arch.armv8_4a,
builtin.Arch.armv8_3a,
builtin.Arch.armv8_2a,
builtin.Arch.armv8_1a,
builtin.Arch.armv8,
builtin.Arch.armv8r,
builtin.Arch.armv8m_baseline,
builtin.Arch.armv8m_mainline,
builtin.Arch.armv7,
builtin.Arch.armv7em,
builtin.Arch.armv7m,
builtin.Arch.armv7s,
builtin.Arch.armv7k,
builtin.Arch.armv7ve,
builtin.Arch.armv6,
builtin.Arch.armv6m,
builtin.Arch.armv6k,
builtin.Arch.armv6t2,
builtin.Arch.armv5,
builtin.Arch.armv5te,
builtin.Arch.armv4t,
=> return "arm", => return "arm",
builtin.Arch.powerpc => return "ppc", builtin.Arch.powerpc => return "ppc",
builtin.Arch.powerpc64 => return "ppc64", builtin.Arch.powerpc64 => return "ppc64",

View File

@ -51,8 +51,8 @@ pub const Type = struct {
pub fn getLlvmType( pub fn getLlvmType(
base: *Type, base: *Type,
allocator: *Allocator, allocator: *Allocator,
llvm_context: llvm.ContextRef, llvm_context: *llvm.Context,
) (error{OutOfMemory}!llvm.TypeRef) { ) (error{OutOfMemory}!*llvm.Type) {
switch (base.id) { switch (base.id) {
Id.Struct => return @fieldParentPtr(Struct, "base", base).getLlvmType(allocator, llvm_context), Id.Struct => return @fieldParentPtr(Struct, "base", base).getLlvmType(allocator, llvm_context),
Id.Fn => return @fieldParentPtr(Fn, "base", base).getLlvmType(allocator, llvm_context), Id.Fn => return @fieldParentPtr(Fn, "base", base).getLlvmType(allocator, llvm_context),
@ -196,7 +196,7 @@ pub const Type = struct {
} }
/// If you have an llvm conext handy, you can use it here. /// If you have an llvm conext handy, you can use it here.
pub async fn getAbiAlignmentInContext(base: *Type, comp: *Compilation, llvm_context: llvm.ContextRef) !u32 { pub async fn getAbiAlignmentInContext(base: *Type, comp: *Compilation, llvm_context: *llvm.Context) !u32 {
if (await (async base.abi_alignment.start() catch unreachable)) |ptr| return ptr.*; if (await (async base.abi_alignment.start() catch unreachable)) |ptr| return ptr.*;
base.abi_alignment.data = await (async base.resolveAbiAlignment(comp, llvm_context) catch unreachable); base.abi_alignment.data = await (async base.resolveAbiAlignment(comp, llvm_context) catch unreachable);
@ -205,7 +205,7 @@ pub const Type = struct {
} }
/// Lower level function that does the work. See getAbiAlignment. /// Lower level function that does the work. See getAbiAlignment.
async fn resolveAbiAlignment(base: *Type, comp: *Compilation, llvm_context: llvm.ContextRef) !u32 { async fn resolveAbiAlignment(base: *Type, comp: *Compilation, llvm_context: *llvm.Context) !u32 {
const llvm_type = try base.getLlvmType(comp.gpa(), llvm_context); const llvm_type = try base.getLlvmType(comp.gpa(), llvm_context);
return @intCast(u32, llvm.ABIAlignmentOfType(comp.target_data_ref, llvm_type)); return @intCast(u32, llvm.ABIAlignmentOfType(comp.target_data_ref, llvm_type));
} }
@ -218,7 +218,7 @@ pub const Type = struct {
comp.gpa().destroy(self); comp.gpa().destroy(self);
} }
pub fn getLlvmType(self: *Struct, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { pub fn getLlvmType(self: *Struct, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
@panic("TODO"); @panic("TODO");
} }
}; };
@ -496,13 +496,13 @@ pub const Type = struct {
comp.gpa().destroy(self); comp.gpa().destroy(self);
} }
pub fn getLlvmType(self: *Fn, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef { pub fn getLlvmType(self: *Fn, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type {
const normal = &self.key.data.Normal; const normal = &self.key.data.Normal;
const llvm_return_type = switch (normal.return_type.id) { const llvm_return_type = switch (normal.return_type.id) {
Type.Id.Void => llvm.VoidTypeInContext(llvm_context) orelse return error.OutOfMemory, Type.Id.Void => llvm.VoidTypeInContext(llvm_context) orelse return error.OutOfMemory,
else => try normal.return_type.getLlvmType(allocator, llvm_context), else => try normal.return_type.getLlvmType(allocator, llvm_context),
}; };
const llvm_param_types = try allocator.alloc(llvm.TypeRef, normal.params.len); const llvm_param_types = try allocator.alloc(*llvm.Type, normal.params.len);
defer allocator.free(llvm_param_types); defer allocator.free(llvm_param_types);
for (llvm_param_types) |*llvm_param_type, i| { for (llvm_param_types) |*llvm_param_type, i| {
llvm_param_type.* = try normal.params[i].typ.getLlvmType(allocator, llvm_context); llvm_param_type.* = try normal.params[i].typ.getLlvmType(allocator, llvm_context);
@ -559,7 +559,7 @@ pub const Type = struct {
comp.gpa().destroy(self); comp.gpa().destroy(self);
} }
pub fn getLlvmType(self: *Bool, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { pub fn getLlvmType(self: *Bool, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
@panic("TODO"); @panic("TODO");
} }
}; };
@ -658,7 +658,7 @@ pub const Type = struct {
comp.gpa().destroy(self); comp.gpa().destroy(self);
} }
pub fn getLlvmType(self: *Int, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef { pub fn getLlvmType(self: *Int, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type {
return llvm.IntTypeInContext(llvm_context, self.key.bit_count) orelse return error.OutOfMemory; return llvm.IntTypeInContext(llvm_context, self.key.bit_count) orelse return error.OutOfMemory;
} }
}; };
@ -670,7 +670,7 @@ pub const Type = struct {
comp.gpa().destroy(self); comp.gpa().destroy(self);
} }
pub fn getLlvmType(self: *Float, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { pub fn getLlvmType(self: *Float, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
@panic("TODO"); @panic("TODO");
} }
}; };
@ -794,6 +794,7 @@ pub const Type = struct {
Size.One => "*", Size.One => "*",
Size.Many => "[*]", Size.Many => "[*]",
Size.Slice => "[]", Size.Slice => "[]",
Size.C => "[*c]",
}; };
const mut_str = switch (self.key.mut) { const mut_str = switch (self.key.mut) {
Mut.Const => "const ", Mut.Const => "const ",
@ -835,7 +836,7 @@ pub const Type = struct {
return self; return self;
} }
pub fn getLlvmType(self: *Pointer, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef { pub fn getLlvmType(self: *Pointer, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type {
const elem_llvm_type = try self.key.child_type.getLlvmType(allocator, llvm_context); const elem_llvm_type = try self.key.child_type.getLlvmType(allocator, llvm_context);
return llvm.PointerType(elem_llvm_type, 0) orelse return error.OutOfMemory; return llvm.PointerType(elem_llvm_type, 0) orelse return error.OutOfMemory;
} }
@ -903,7 +904,7 @@ pub const Type = struct {
return self; return self;
} }
pub fn getLlvmType(self: *Array, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef { pub fn getLlvmType(self: *Array, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type {
const elem_llvm_type = try self.key.elem_type.getLlvmType(allocator, llvm_context); const elem_llvm_type = try self.key.elem_type.getLlvmType(allocator, llvm_context);
return llvm.ArrayType(elem_llvm_type, @intCast(c_uint, self.key.len)) orelse return error.OutOfMemory; return llvm.ArrayType(elem_llvm_type, @intCast(c_uint, self.key.len)) orelse return error.OutOfMemory;
} }
@ -916,7 +917,7 @@ pub const Type = struct {
comp.gpa().destroy(self); comp.gpa().destroy(self);
} }
pub fn getLlvmType(self: *Vector, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { pub fn getLlvmType(self: *Vector, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
@panic("TODO"); @panic("TODO");
} }
}; };
@ -966,7 +967,7 @@ pub const Type = struct {
comp.gpa().destroy(self); comp.gpa().destroy(self);
} }
pub fn getLlvmType(self: *Optional, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { pub fn getLlvmType(self: *Optional, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
@panic("TODO"); @panic("TODO");
} }
}; };
@ -978,7 +979,7 @@ pub const Type = struct {
comp.gpa().destroy(self); comp.gpa().destroy(self);
} }
pub fn getLlvmType(self: *ErrorUnion, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { pub fn getLlvmType(self: *ErrorUnion, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
@panic("TODO"); @panic("TODO");
} }
}; };
@ -990,7 +991,7 @@ pub const Type = struct {
comp.gpa().destroy(self); comp.gpa().destroy(self);
} }
pub fn getLlvmType(self: *ErrorSet, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { pub fn getLlvmType(self: *ErrorSet, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
@panic("TODO"); @panic("TODO");
} }
}; };
@ -1002,7 +1003,7 @@ pub const Type = struct {
comp.gpa().destroy(self); comp.gpa().destroy(self);
} }
pub fn getLlvmType(self: *Enum, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { pub fn getLlvmType(self: *Enum, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
@panic("TODO"); @panic("TODO");
} }
}; };
@ -1014,7 +1015,7 @@ pub const Type = struct {
comp.gpa().destroy(self); comp.gpa().destroy(self);
} }
pub fn getLlvmType(self: *Union, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { pub fn getLlvmType(self: *Union, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
@panic("TODO"); @panic("TODO");
} }
}; };
@ -1034,7 +1035,7 @@ pub const Type = struct {
comp.gpa().destroy(self); comp.gpa().destroy(self);
} }
pub fn getLlvmType(self: *BoundFn, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { pub fn getLlvmType(self: *BoundFn, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
@panic("TODO"); @panic("TODO");
} }
}; };
@ -1054,7 +1055,7 @@ pub const Type = struct {
comp.gpa().destroy(self); comp.gpa().destroy(self);
} }
pub fn getLlvmType(self: *Opaque, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { pub fn getLlvmType(self: *Opaque, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
@panic("TODO"); @panic("TODO");
} }
}; };
@ -1066,7 +1067,7 @@ pub const Type = struct {
comp.gpa().destroy(self); comp.gpa().destroy(self);
} }
pub fn getLlvmType(self: *Promise, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef { pub fn getLlvmType(self: *Promise, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
@panic("TODO"); @panic("TODO");
} }
}; };
@ -1088,6 +1089,7 @@ fn hashAny(x: var, comptime seed: u64) u32 {
builtin.TypeInfo.Pointer.Size.One => return hashAny(@ptrToInt(x), seed), builtin.TypeInfo.Pointer.Size.One => return hashAny(@ptrToInt(x), seed),
builtin.TypeInfo.Pointer.Size.Many => @compileError("implement hash function"), builtin.TypeInfo.Pointer.Size.Many => @compileError("implement hash function"),
builtin.TypeInfo.Pointer.Size.Slice => @compileError("implement hash function"), builtin.TypeInfo.Pointer.Size.Slice => @compileError("implement hash function"),
builtin.TypeInfo.Pointer.Size.C => unreachable,
} }
}, },
builtin.TypeId.Enum => return hashAny(@enumToInt(x), seed), builtin.TypeId.Enum => return hashAny(@enumToInt(x), seed),

View File

@ -57,7 +57,7 @@ pub const Value = struct {
std.debug.warn("{}", @tagName(base.id)); std.debug.warn("{}", @tagName(base.id));
} }
pub fn getLlvmConst(base: *Value, ofile: *ObjectFile) (error{OutOfMemory}!?llvm.ValueRef) { pub fn getLlvmConst(base: *Value, ofile: *ObjectFile) (error{OutOfMemory}!?*llvm.Value) {
switch (base.id) { switch (base.id) {
Id.Type => unreachable, Id.Type => unreachable,
Id.Fn => return @fieldParentPtr(Fn, "base", base).getLlvmConst(ofile), Id.Fn => return @fieldParentPtr(Fn, "base", base).getLlvmConst(ofile),
@ -153,7 +153,7 @@ pub const Value = struct {
comp.gpa().destroy(self); comp.gpa().destroy(self);
} }
pub fn getLlvmConst(self: *FnProto, ofile: *ObjectFile) !?llvm.ValueRef { pub fn getLlvmConst(self: *FnProto, ofile: *ObjectFile) !?*llvm.Value {
const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context); const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
const llvm_fn = llvm.AddFunction( const llvm_fn = llvm.AddFunction(
ofile.module, ofile.module,
@ -238,7 +238,7 @@ pub const Value = struct {
/// We know that the function definition will end up in an .o file somewhere. /// We know that the function definition will end up in an .o file somewhere.
/// Here, all we have to do is generate a global prototype. /// Here, all we have to do is generate a global prototype.
/// TODO cache the prototype per ObjectFile /// TODO cache the prototype per ObjectFile
pub fn getLlvmConst(self: *Fn, ofile: *ObjectFile) !?llvm.ValueRef { pub fn getLlvmConst(self: *Fn, ofile: *ObjectFile) !?*llvm.Value {
const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context); const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
const llvm_fn = llvm.AddFunction( const llvm_fn = llvm.AddFunction(
ofile.module, ofile.module,
@ -283,8 +283,8 @@ pub const Value = struct {
comp.gpa().destroy(self); comp.gpa().destroy(self);
} }
pub fn getLlvmConst(self: *Bool, ofile: *ObjectFile) ?llvm.ValueRef { pub fn getLlvmConst(self: *Bool, ofile: *ObjectFile) !?*llvm.Value {
const llvm_type = llvm.Int1TypeInContext(ofile.context); const llvm_type = llvm.Int1TypeInContext(ofile.context) orelse return error.OutOfMemory;
if (self.x) { if (self.x) {
return llvm.ConstAllOnes(llvm_type); return llvm.ConstAllOnes(llvm_type);
} else { } else {
@ -381,7 +381,7 @@ pub const Value = struct {
comp.gpa().destroy(self); comp.gpa().destroy(self);
} }
pub fn getLlvmConst(self: *Ptr, ofile: *ObjectFile) !?llvm.ValueRef { pub fn getLlvmConst(self: *Ptr, ofile: *ObjectFile) !?*llvm.Value {
const llvm_type = self.base.typ.getLlvmType(ofile.arena, ofile.context); const llvm_type = self.base.typ.getLlvmType(ofile.arena, ofile.context);
// TODO carefully port the logic from codegen.cpp:gen_const_val_ptr // TODO carefully port the logic from codegen.cpp:gen_const_val_ptr
switch (self.special) { switch (self.special) {
@ -391,7 +391,7 @@ pub const Value = struct {
const array_llvm_value = (try base_array.val.getLlvmConst(ofile)).?; const array_llvm_value = (try base_array.val.getLlvmConst(ofile)).?;
const ptr_bit_count = ofile.comp.target_ptr_bits; const ptr_bit_count = ofile.comp.target_ptr_bits;
const usize_llvm_type = llvm.IntTypeInContext(ofile.context, ptr_bit_count) orelse return error.OutOfMemory; const usize_llvm_type = llvm.IntTypeInContext(ofile.context, ptr_bit_count) orelse return error.OutOfMemory;
const indices = []llvm.ValueRef{ const indices = []*llvm.Value{
llvm.ConstNull(usize_llvm_type) orelse return error.OutOfMemory, llvm.ConstNull(usize_llvm_type) orelse return error.OutOfMemory,
llvm.ConstInt(usize_llvm_type, base_array.elem_index, 0) orelse return error.OutOfMemory, llvm.ConstInt(usize_llvm_type, base_array.elem_index, 0) orelse return error.OutOfMemory,
}; };
@ -459,7 +459,7 @@ pub const Value = struct {
comp.gpa().destroy(self); comp.gpa().destroy(self);
} }
pub fn getLlvmConst(self: *Array, ofile: *ObjectFile) !?llvm.ValueRef { pub fn getLlvmConst(self: *Array, ofile: *ObjectFile) !?*llvm.Value {
switch (self.special) { switch (self.special) {
Special.Undefined => { Special.Undefined => {
const llvm_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context); const llvm_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
@ -534,7 +534,7 @@ pub const Value = struct {
return self; return self;
} }
pub fn getLlvmConst(self: *Int, ofile: *ObjectFile) !?llvm.ValueRef { pub fn getLlvmConst(self: *Int, ofile: *ObjectFile) !?*llvm.Value {
switch (self.base.typ.id) { switch (self.base.typ.id) {
Type.Id.Int => { Type.Id.Int => {
const type_ref = try self.base.typ.getLlvmType(ofile.arena, ofile.context); const type_ref = try self.base.typ.getLlvmType(ofile.arena, ofile.context);

View File

@ -18,6 +18,7 @@
#include "bigfloat.hpp" #include "bigfloat.hpp"
#include "target.hpp" #include "target.hpp"
#include "tokenizer.hpp" #include "tokenizer.hpp"
#include "libc_installation.hpp"
struct AstNode; struct AstNode;
struct ImportTableEntry; struct ImportTableEntry;
@ -630,24 +631,12 @@ struct AstNodeUnwrapOptional {
AstNode *expr; AstNode *expr;
}; };
enum CastOp {
CastOpNoCast, // signifies the function call expression is not a cast
CastOpNoop, // fn call expr is a cast, but does nothing
CastOpIntToFloat,
CastOpFloatToInt,
CastOpBoolToInt,
CastOpResizeSlice,
CastOpNumLitToConcrete,
CastOpErrSet,
CastOpBitCast,
CastOpPtrOfArrayToSlice,
};
struct AstNodeFnCallExpr { struct AstNodeFnCallExpr {
AstNode *fn_ref_expr; AstNode *fn_ref_expr;
ZigList<AstNode *> params; ZigList<AstNode *> params;
bool is_builtin; bool is_builtin;
bool is_async; bool is_async;
bool seen; // used by @compileLog
AstNode *async_allocator; AstNode *async_allocator;
}; };
@ -691,15 +680,17 @@ struct AstNodePointerType {
AstNode *align_expr; AstNode *align_expr;
BigInt *bit_offset_start; BigInt *bit_offset_start;
BigInt *host_int_bytes; BigInt *host_int_bytes;
AstNode *op_expr;
Token *allow_zero_token;
bool is_const; bool is_const;
bool is_volatile; bool is_volatile;
AstNode *op_expr;
}; };
struct AstNodeArrayType { struct AstNodeArrayType {
AstNode *size; AstNode *size;
AstNode *child_type; AstNode *child_type;
AstNode *align_expr; AstNode *align_expr;
Token *allow_zero_token;
bool is_const; bool is_const;
bool is_volatile; bool is_volatile;
}; };
@ -1038,6 +1029,7 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b);
enum PtrLen { enum PtrLen {
PtrLenUnknown, PtrLenUnknown,
PtrLenSingle, PtrLenSingle,
PtrLenC,
}; };
struct ZigTypePointer { struct ZigTypePointer {
@ -1049,6 +1041,7 @@ struct ZigTypePointer {
uint32_t host_int_bytes; // size of host integer. 0 means no host integer; this field is aligned uint32_t host_int_bytes; // size of host integer. 0 means no host integer; this field is aligned
bool is_const; bool is_const;
bool is_volatile; bool is_volatile;
bool allow_zero;
}; };
struct ZigTypeInt { struct ZigTypeInt {
@ -1247,6 +1240,12 @@ enum ZigTypeId {
ZigTypeIdVector, ZigTypeIdVector,
}; };
enum OnePossibleValue {
OnePossibleValueInvalid,
OnePossibleValueNo,
OnePossibleValueYes,
};
struct ZigType { struct ZigType {
ZigTypeId id; ZigTypeId id;
Buf name; Buf name;
@ -1254,9 +1253,6 @@ struct ZigType {
LLVMTypeRef type_ref; LLVMTypeRef type_ref;
ZigLLVMDIType *di_type; ZigLLVMDIType *di_type;
bool zero_bits; // this is denormalized data
bool gen_h_loop_flag;
union { union {
ZigTypePointer pointer; ZigTypePointer pointer;
ZigTypeInt integral; ZigTypeInt integral;
@ -1282,6 +1278,11 @@ struct ZigType {
// If we generate a constant name value for this type, we memoize it here. // If we generate a constant name value for this type, we memoize it here.
// The type of this is array // The type of this is array
ConstExprValue *cached_const_name_val; ConstExprValue *cached_const_name_val;
OnePossibleValue one_possible_value;
bool zero_bits; // this is denormalized data
bool gen_h_loop_flag;
}; };
struct PackageTableEntry { struct PackageTableEntry {
@ -1340,15 +1341,11 @@ struct ZigFn {
// in the case of async functions this is the implicit return type according to the // in the case of async functions this is the implicit return type according to the
// zig source code, not according to zig ir // zig source code, not according to zig ir
ZigType *src_implicit_return_type; ZigType *src_implicit_return_type;
bool is_test;
FnInline fn_inline;
FnAnalState anal_state;
IrExecutable ir_executable; IrExecutable ir_executable;
IrExecutable analyzed_executable; IrExecutable analyzed_executable;
size_t prealloc_bbc; size_t prealloc_bbc;
AstNode **param_source_nodes; AstNode **param_source_nodes;
Buf **param_names; Buf **param_names;
uint32_t align_bytes;
AstNode *fn_no_inline_set_node; AstNode *fn_no_inline_set_node;
AstNode *fn_static_eval_set_node; AstNode *fn_static_eval_set_node;
@ -1358,13 +1355,22 @@ struct ZigFn {
Buf *section_name; Buf *section_name;
AstNode *set_alignstack_node; AstNode *set_alignstack_node;
uint32_t alignstack_value;
AstNode *set_cold_node; AstNode *set_cold_node;
bool is_cold;
ZigList<FnExport> export_list; ZigList<FnExport> export_list;
LLVMValueRef valgrind_client_request_array;
FnInline fn_inline;
FnAnalState anal_state;
uint32_t align_bytes;
uint32_t alignstack_value;
bool calls_or_awaits_errorable_fn; bool calls_or_awaits_errorable_fn;
bool is_cold;
bool is_test;
}; };
uint32_t fn_table_entry_hash(ZigFn*); uint32_t fn_table_entry_hash(ZigFn*);
@ -1484,6 +1490,7 @@ enum PanicMsgId {
PanicMsgIdBadUnionField, PanicMsgIdBadUnionField,
PanicMsgIdBadEnumValue, PanicMsgIdBadEnumValue,
PanicMsgIdFloatToInt, PanicMsgIdFloatToInt,
PanicMsgIdPtrCastNull,
PanicMsgIdCount, PanicMsgIdCount,
}; };
@ -1498,11 +1505,12 @@ struct TypeId {
struct { struct {
ZigType *child_type; ZigType *child_type;
PtrLen ptr_len; PtrLen ptr_len;
bool is_const;
bool is_volatile;
uint32_t alignment; uint32_t alignment;
uint32_t bit_offset_in_host; uint32_t bit_offset_in_host;
uint32_t host_int_bytes; uint32_t host_int_bytes;
bool is_const;
bool is_volatile;
bool allow_zero;
} pointer; } pointer;
struct { struct {
ZigType *child_type; ZigType *child_type;
@ -1605,6 +1613,17 @@ struct LinkLib {
bool provided_explicitly; bool provided_explicitly;
}; };
enum ValgrindSupport {
ValgrindSupportAuto,
ValgrindSupportDisabled,
ValgrindSupportEnabled,
};
struct CFile {
ZigList<const char *> args;
const char *source_path;
};
// When adding fields, check if they should be added to the hash computation in build_with_cache // When adding fields, check if they should be added to the hash computation in build_with_cache
struct CodeGen { struct CodeGen {
//////////////////////////// Runtime State //////////////////////////// Runtime State
@ -1660,7 +1679,7 @@ struct CodeGen {
HashMap<GenericFnTypeId *, ZigFn *, generic_fn_type_id_hash, generic_fn_type_id_eql> generic_table; HashMap<GenericFnTypeId *, ZigFn *, generic_fn_type_id_hash, generic_fn_type_id_eql> generic_table;
HashMap<Scope *, ConstExprValue *, fn_eval_hash, fn_eval_eql> memoized_fn_eval_table; HashMap<Scope *, ConstExprValue *, fn_eval_hash, fn_eval_eql> memoized_fn_eval_table;
HashMap<ZigLLVMFnKey, LLVMValueRef, zig_llvm_fn_key_hash, zig_llvm_fn_key_eql> llvm_fn_table; HashMap<ZigLLVMFnKey, LLVMValueRef, zig_llvm_fn_key_hash, zig_llvm_fn_key_eql> llvm_fn_table;
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> exported_symbol_names; HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> exported_symbol_names;
HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes; HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes;
HashMap<Buf *, ConstExprValue *, buf_hash, buf_eql_buf> string_literals_table; HashMap<Buf *, ConstExprValue *, buf_hash, buf_eql_buf> string_literals_table;
HashMap<const ZigType *, ConstExprValue *, type_ptr_hash, type_ptr_eql> type_info_cache; HashMap<const ZigType *, ConstExprValue *, type_ptr_hash, type_ptr_eql> type_info_cache;
@ -1732,12 +1751,16 @@ struct CodeGen {
Buf triple_str; Buf triple_str;
Buf global_asm; Buf global_asm;
Buf *out_h_path; Buf *out_h_path;
Buf *out_lib_path;
Buf artifact_dir; Buf artifact_dir;
Buf output_file_path; Buf output_file_path;
Buf o_file_output_path; Buf o_file_output_path;
Buf *wanted_output_file_path; Buf *wanted_output_file_path;
Buf cache_dir; Buf cache_dir;
Buf *zig_c_headers_dir; // Cannot be overridden; derived from zig_lib_dir.
Buf *zig_std_special_dir; // Cannot be overridden; derived from zig_lib_dir.
IrInstruction *invalid_instruction; IrInstruction *invalid_instruction;
IrInstruction *unreach_instruction; IrInstruction *unreach_instruction;
@ -1752,6 +1775,7 @@ struct CodeGen {
ZigFn *cur_fn; ZigFn *cur_fn;
ZigFn *main_fn; ZigFn *main_fn;
ZigFn *panic_fn; ZigFn *panic_fn;
TldFn *panic_tld_fn;
AstNode *root_export_decl; AstNode *root_export_decl;
CacheHash cache_hash; CacheHash cache_hash;
@ -1760,7 +1784,8 @@ struct CodeGen {
unsigned pointer_size_bytes; unsigned pointer_size_bytes;
uint32_t target_os_index; uint32_t target_os_index;
uint32_t target_arch_index; uint32_t target_arch_index;
uint32_t target_environ_index; uint32_t target_sub_arch_index;
uint32_t target_abi_index;
uint32_t target_oformat_index; uint32_t target_oformat_index;
bool is_big_endian; bool is_big_endian;
bool have_pub_main; bool have_pub_main;
@ -1778,13 +1803,17 @@ struct CodeGen {
bool verbose_ir; bool verbose_ir;
bool verbose_llvm_ir; bool verbose_llvm_ir;
bool verbose_cimport; bool verbose_cimport;
bool verbose_cc;
bool error_during_imports; bool error_during_imports;
bool generate_error_name_table; bool generate_error_name_table;
bool enable_cache; bool enable_cache;
bool enable_time_report; bool enable_time_report;
bool system_linker_hack; bool system_linker_hack;
bool reported_bad_link_libc_error;
//////////////////////////// Participates in Input Parameter Cache Hash //////////////////////////// Participates in Input Parameter Cache Hash
/////// Note: there is a separate cache hash for builtin.zig, when adding fields,
/////// consider if they need to go into both.
ZigList<LinkLib *> link_libs_list; ZigList<LinkLib *> link_libs_list;
// add -framework [name] args to linker // add -framework [name] args to linker
ZigList<Buf *> darwin_frameworks; ZigList<Buf *> darwin_frameworks;
@ -1793,8 +1822,11 @@ struct CodeGen {
ZigList<Buf *> forbidden_libs; ZigList<Buf *> forbidden_libs;
ZigList<Buf *> link_objects; ZigList<Buf *> link_objects;
ZigList<Buf *> assembly_files; ZigList<Buf *> assembly_files;
ZigList<CFile *> c_source_files;
ZigList<const char *> lib_dirs; ZigList<const char *> lib_dirs;
ZigLibCInstallation *libc;
size_t version_major; size_t version_major;
size_t version_minor; size_t version_minor;
size_t version_patch; size_t version_patch;
@ -1803,15 +1835,14 @@ struct CodeGen {
EmitFileType emit_file_type; EmitFileType emit_file_type;
BuildMode build_mode; BuildMode build_mode;
OutType out_type; OutType out_type;
ZigTarget zig_target; const ZigTarget *zig_target;
TargetSubsystem subsystem; TargetSubsystem subsystem;
ValgrindSupport valgrind_support;
bool is_static; bool is_static;
bool strip_debug_symbols; bool strip_debug_symbols;
bool is_test_build; bool is_test_build;
bool is_single_threaded; bool is_single_threaded;
bool is_native_target;
bool linker_rdynamic; bool linker_rdynamic;
bool no_rosegment_workaround;
bool each_lib_rpath; bool each_lib_rpath;
bool disable_pic; bool disable_pic;
@ -1821,31 +1852,21 @@ struct CodeGen {
Buf *test_filter; Buf *test_filter;
Buf *test_name_prefix; Buf *test_name_prefix;
PackageTableEntry *root_package; PackageTableEntry *root_package;
Buf *zig_lib_dir;
Buf *zig_std_dir;
const char **llvm_argv; const char **llvm_argv;
size_t llvm_argv_len; size_t llvm_argv_len;
const char **clang_argv; const char **clang_argv;
size_t clang_argv_len; size_t clang_argv_len;
//////////////////////////// Unsorted
Buf *libc_lib_dir;
Buf *libc_static_lib_dir;
Buf *libc_include_dir;
Buf *msvc_lib_dir;
Buf *kernel32_lib_dir;
Buf *zig_lib_dir;
Buf *zig_std_dir;
Buf *zig_c_headers_dir;
Buf *zig_std_special_dir;
Buf *dynamic_linker;
ZigWindowsSDK *win_sdk;
}; };
enum VarLinkage { enum VarLinkage {
VarLinkageInternal, VarLinkageInternal,
VarLinkageExport, VarLinkageExportStrong,
VarLinkageExportWeak,
VarLinkageExportLinkOnce,
VarLinkageExternal, VarLinkageExternal,
}; };
@ -2084,6 +2105,11 @@ struct IrBasicBlock {
IrInstruction *must_be_comptime_source_instr; IrInstruction *must_be_comptime_source_instr;
}; };
enum LVal {
LValNone,
LValPtr,
};
// These instructions are in transition to having "pass 1" instructions // These instructions are in transition to having "pass 1" instructions
// and "pass 2" instructions. The pass 1 instructions are suffixed with Src // and "pass 2" instructions. The pass 1 instructions are suffixed with Src
// and pass 2 are suffixed with Gen. // and pass 2 are suffixed with Gen.
@ -2106,6 +2132,7 @@ enum IrInstructionId {
IrInstructionIdUnOp, IrInstructionIdUnOp,
IrInstructionIdBinOp, IrInstructionIdBinOp,
IrInstructionIdLoadPtr, IrInstructionIdLoadPtr,
IrInstructionIdLoadPtrGen,
IrInstructionIdStorePtr, IrInstructionIdStorePtr,
IrInstructionIdFieldPtr, IrInstructionIdFieldPtr,
IrInstructionIdStructFieldPtr, IrInstructionIdStructFieldPtr,
@ -2116,6 +2143,7 @@ enum IrInstructionId {
IrInstructionIdConst, IrInstructionIdConst,
IrInstructionIdReturn, IrInstructionIdReturn,
IrInstructionIdCast, IrInstructionIdCast,
IrInstructionIdResizeSlice,
IrInstructionIdContainerInitList, IrInstructionIdContainerInitList,
IrInstructionIdContainerInitFields, IrInstructionIdContainerInitFields,
IrInstructionIdStructInit, IrInstructionIdStructInit,
@ -2183,6 +2211,7 @@ enum IrInstructionId {
IrInstructionIdPtrCastSrc, IrInstructionIdPtrCastSrc,
IrInstructionIdPtrCastGen, IrInstructionIdPtrCastGen,
IrInstructionIdBitCast, IrInstructionIdBitCast,
IrInstructionIdBitCastGen,
IrInstructionIdWidenOrShorten, IrInstructionIdWidenOrShorten,
IrInstructionIdIntToPtr, IrInstructionIdIntToPtr,
IrInstructionIdPtrToInt, IrInstructionIdPtrToInt,
@ -2347,6 +2376,7 @@ struct IrInstructionUnOp {
IrUnOp op_id; IrUnOp op_id;
IrInstruction *value; IrInstruction *value;
LVal lval;
}; };
enum IrBinOp { enum IrBinOp {
@ -2399,6 +2429,13 @@ struct IrInstructionLoadPtr {
IrInstruction *ptr; IrInstruction *ptr;
}; };
struct IrInstructionLoadPtrGen {
IrInstruction base;
IrInstruction *ptr;
LLVMValueRef tmp_ptr;
};
struct IrInstructionStorePtr { struct IrInstructionStorePtr {
IrInstruction base; IrInstruction base;
@ -2476,6 +2513,18 @@ struct IrInstructionReturn {
IrInstruction *value; IrInstruction *value;
}; };
enum CastOp {
CastOpNoCast, // signifies the function call expression is not a cast
CastOpNoop, // fn call expr is a cast, but does nothing
CastOpIntToFloat,
CastOpFloatToInt,
CastOpBoolToInt,
CastOpNumLitToConcrete,
CastOpErrSet,
CastOpBitCast,
CastOpPtrOfArrayToSlice,
};
// TODO get rid of this instruction, replace with instructions for each op code // TODO get rid of this instruction, replace with instructions for each op code
struct IrInstructionCast { struct IrInstructionCast {
IrInstruction base; IrInstruction base;
@ -2486,6 +2535,13 @@ struct IrInstructionCast {
LLVMValueRef tmp_ptr; LLVMValueRef tmp_ptr;
}; };
struct IrInstructionResizeSlice {
IrInstruction base;
IrInstruction *operand;
LLVMValueRef tmp_ptr;
};
struct IrInstructionContainerInitList { struct IrInstructionContainerInitList {
IrInstruction base; IrInstruction base;
@ -2591,6 +2647,7 @@ struct IrInstructionPtrType {
PtrLen ptr_len; PtrLen ptr_len;
bool is_const; bool is_const;
bool is_volatile; bool is_volatile;
bool allow_zero;
}; };
struct IrInstructionPromiseType { struct IrInstructionPromiseType {
@ -2606,6 +2663,7 @@ struct IrInstructionSliceType {
IrInstruction *child_type; IrInstruction *child_type;
bool is_const; bool is_const;
bool is_volatile; bool is_volatile;
bool allow_zero;
}; };
struct IrInstructionAsm { struct IrInstructionAsm {
@ -2994,12 +3052,14 @@ struct IrInstructionPtrCastSrc {
IrInstruction *dest_type; IrInstruction *dest_type;
IrInstruction *ptr; IrInstruction *ptr;
bool safety_check_on;
}; };
struct IrInstructionPtrCastGen { struct IrInstructionPtrCastGen {
IrInstruction base; IrInstruction base;
IrInstruction *ptr; IrInstruction *ptr;
bool safety_check_on;
}; };
struct IrInstructionBitCast { struct IrInstructionBitCast {
@ -3009,6 +3069,13 @@ struct IrInstructionBitCast {
IrInstruction *value; IrInstruction *value;
}; };
struct IrInstructionBitCastGen {
IrInstruction base;
IrInstruction *operand;
LLVMValueRef tmp_ptr;
};
struct IrInstructionWidenOrShorten { struct IrInstructionWidenOrShorten {
IrInstruction base; IrInstruction base;
@ -3079,11 +3146,6 @@ struct IrInstructionTypeName {
IrInstruction *type_value; IrInstruction *type_value;
}; };
enum LVal {
LValNone,
LValPtr,
};
struct IrInstructionDeclRef { struct IrInstructionDeclRef {
IrInstruction base; IrInstruction base;

View File

@ -356,7 +356,7 @@ uint64_t type_size(CodeGen *g, ZigType *type_entry) {
} }
} }
return LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref); return LLVMABISizeOfType(g->target_data_ref, type_entry->type_ref);
} }
uint64_t type_size_bits(CodeGen *g, ZigType *type_entry) { uint64_t type_size_bits(CodeGen *g, ZigType *type_entry) {
@ -365,20 +365,20 @@ uint64_t type_size_bits(CodeGen *g, ZigType *type_entry) {
if (!type_has_bits(type_entry)) if (!type_has_bits(type_entry))
return 0; return 0;
if (type_entry->id == ZigTypeIdStruct && type_entry->data.structure.layout == ContainerLayoutPacked) { if (type_entry->id == ZigTypeIdStruct) {
if (type_entry->data.structure.layout == ContainerLayoutPacked) {
uint64_t result = 0; uint64_t result = 0;
for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) { for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) {
result += type_size_bits(g, type_entry->data.structure.fields[i].type_entry); result += type_size_bits(g, type_entry->data.structure.fields[i].type_entry);
} }
return result; return result;
} else if (type_entry->data.structure.layout == ContainerLayoutExtern) {
return type_size(g, type_entry) * 8;
}
} else if (type_entry->id == ZigTypeIdArray) { } else if (type_entry->id == ZigTypeIdArray) {
ZigType *child_type = type_entry->data.array.child_type; ZigType *child_type = type_entry->data.array.child_type;
if (child_type->id == ZigTypeIdStruct &&
child_type->data.structure.layout == ContainerLayoutPacked)
{
return type_entry->data.array.len * type_size_bits(g, child_type); return type_entry->data.array.len * type_size_bits(g, child_type);
} }
}
return LLVMSizeOfTypeInBits(g->target_data_ref, type_entry->type_ref); return LLVMSizeOfTypeInBits(g->target_data_ref, type_entry->type_ref);
} }
@ -417,10 +417,25 @@ ZigType *get_promise_type(CodeGen *g, ZigType *result_type) {
return entry; return entry;
} }
static const char *ptr_len_to_star_str(PtrLen ptr_len) {
switch (ptr_len) {
case PtrLenSingle:
return "*";
case PtrLenUnknown:
return "[*]";
case PtrLenC:
return "[*c]";
}
zig_unreachable();
}
ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const, ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const,
bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment,
uint32_t bit_offset_in_host, uint32_t host_int_bytes) uint32_t bit_offset_in_host, uint32_t host_int_bytes)
{ {
// TODO when implementing https://github.com/ziglang/zig/issues/1953
// move this to a parameter
bool allow_zero = (ptr_len == PtrLenC);
assert(!type_is_invalid(child_type)); assert(!type_is_invalid(child_type));
assert(ptr_len == PtrLenSingle || child_type->id != ZigTypeIdOpaque); assert(ptr_len == PtrLenSingle || child_type->id != ZigTypeIdOpaque);
@ -440,7 +455,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
TypeId type_id = {}; TypeId type_id = {};
ZigType **parent_pointer = nullptr; ZigType **parent_pointer = nullptr;
if (host_int_bytes != 0 || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle) { if (host_int_bytes != 0 || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle || allow_zero) {
type_id.id = ZigTypeIdPointer; type_id.id = ZigTypeIdPointer;
type_id.data.pointer.child_type = child_type; type_id.data.pointer.child_type = child_type;
type_id.data.pointer.is_const = is_const; type_id.data.pointer.is_const = is_const;
@ -449,6 +464,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
type_id.data.pointer.bit_offset_in_host = bit_offset_in_host; type_id.data.pointer.bit_offset_in_host = bit_offset_in_host;
type_id.data.pointer.host_int_bytes = host_int_bytes; type_id.data.pointer.host_int_bytes = host_int_bytes;
type_id.data.pointer.ptr_len = ptr_len; type_id.data.pointer.ptr_len = ptr_len;
type_id.data.pointer.allow_zero = allow_zero;
auto existing_entry = g->type_table.maybe_get(type_id); auto existing_entry = g->type_table.maybe_get(type_id);
if (existing_entry) if (existing_entry)
@ -466,21 +482,31 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
ZigType *entry = new_type_table_entry(ZigTypeIdPointer); ZigType *entry = new_type_table_entry(ZigTypeIdPointer);
const char *star_str = ptr_len == PtrLenSingle ? "*" : "[*]"; const char *star_str = ptr_len_to_star_str(ptr_len);
const char *const_str = is_const ? "const " : ""; const char *const_str = is_const ? "const " : "";
const char *volatile_str = is_volatile ? "volatile " : ""; const char *volatile_str = is_volatile ? "volatile " : "";
const char *allow_zero_str;
if (ptr_len == PtrLenC) {
assert(allow_zero);
allow_zero_str = "";
} else {
allow_zero_str = allow_zero ? "allowzero " : "";
}
buf_resize(&entry->name, 0); buf_resize(&entry->name, 0);
if (host_int_bytes == 0 && byte_alignment == 0) { if (host_int_bytes == 0 && byte_alignment == 0) {
buf_appendf(&entry->name, "%s%s%s%s", star_str, const_str, volatile_str, buf_ptr(&child_type->name)); buf_appendf(&entry->name, "%s%s%s%s%s",
star_str, const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name));
} else if (host_int_bytes == 0) { } else if (host_int_bytes == 0) {
buf_appendf(&entry->name, "%salign(%" PRIu32 ") %s%s%s", star_str, byte_alignment, buf_appendf(&entry->name, "%salign(%" PRIu32 ") %s%s%s%s", star_str, byte_alignment,
const_str, volatile_str, buf_ptr(&child_type->name)); const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name));
} else if (byte_alignment == 0) { } else if (byte_alignment == 0) {
buf_appendf(&entry->name, "%salign(:%" PRIu32 ":%" PRIu32 ") %s%s%s", star_str, buf_appendf(&entry->name, "%salign(:%" PRIu32 ":%" PRIu32 ") %s%s%s%s", star_str,
bit_offset_in_host, host_int_bytes, const_str, volatile_str, buf_ptr(&child_type->name)); bit_offset_in_host, host_int_bytes, const_str, volatile_str, allow_zero_str,
buf_ptr(&child_type->name));
} else { } else {
buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s", star_str, byte_alignment, buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s%s", star_str, byte_alignment,
bit_offset_in_host, host_int_bytes, const_str, volatile_str, buf_ptr(&child_type->name)); bit_offset_in_host, host_int_bytes, const_str, volatile_str, allow_zero_str,
buf_ptr(&child_type->name));
} }
assert(child_type->id != ZigTypeIdInvalid); assert(child_type->id != ZigTypeIdInvalid);
@ -488,7 +514,9 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
entry->zero_bits = !type_has_bits(child_type); entry->zero_bits = !type_has_bits(child_type);
if (!entry->zero_bits) { if (!entry->zero_bits) {
if (is_const || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle || bit_offset_in_host != 0) { if (is_const || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle ||
bit_offset_in_host != 0 || allow_zero)
{
ZigType *peer_type = get_pointer_to_type_extra(g, child_type, false, false, ZigType *peer_type = get_pointer_to_type_extra(g, child_type, false, false,
PtrLenSingle, 0, 0, host_int_bytes); PtrLenSingle, 0, 0, host_int_bytes);
entry->type_ref = peer_type->type_ref; entry->type_ref = peer_type->type_ref;
@ -522,6 +550,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
entry->data.pointer.explicit_alignment = byte_alignment; entry->data.pointer.explicit_alignment = byte_alignment;
entry->data.pointer.bit_offset_in_host = bit_offset_in_host; entry->data.pointer.bit_offset_in_host = bit_offset_in_host;
entry->data.pointer.host_int_bytes = host_int_bytes; entry->data.pointer.host_int_bytes = host_int_bytes;
entry->data.pointer.allow_zero = allow_zero;
if (parent_pointer) { if (parent_pointer) {
*parent_pointer = entry; *parent_pointer = entry;
@ -838,7 +867,7 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) {
ZigType *child_type = ptr_type->data.pointer.child_type; ZigType *child_type = ptr_type->data.pointer.child_type;
if (ptr_type->data.pointer.is_const || ptr_type->data.pointer.is_volatile || if (ptr_type->data.pointer.is_const || ptr_type->data.pointer.is_volatile ||
ptr_type->data.pointer.explicit_alignment != 0) ptr_type->data.pointer.explicit_alignment != 0 || ptr_type->data.pointer.allow_zero)
{ {
ZigType *peer_ptr_type = get_pointer_to_type_extra(g, child_type, false, false, ZigType *peer_ptr_type = get_pointer_to_type_extra(g, child_type, false, false,
PtrLenUnknown, 0, 0, 0); PtrLenUnknown, 0, 0, 0);
@ -861,7 +890,7 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) {
ZigType *child_ptr_type = child_type->data.structure.fields[slice_ptr_index].type_entry; ZigType *child_ptr_type = child_type->data.structure.fields[slice_ptr_index].type_entry;
assert(child_ptr_type->id == ZigTypeIdPointer); assert(child_ptr_type->id == ZigTypeIdPointer);
if (child_ptr_type->data.pointer.is_const || child_ptr_type->data.pointer.is_volatile || if (child_ptr_type->data.pointer.is_const || child_ptr_type->data.pointer.is_volatile ||
child_ptr_type->data.pointer.explicit_alignment != 0) child_ptr_type->data.pointer.explicit_alignment != 0 || child_ptr_type->data.pointer.allow_zero)
{ {
ZigType *grand_child_type = child_ptr_type->data.pointer.child_type; ZigType *grand_child_type = child_ptr_type->data.pointer.child_type;
ZigType *bland_child_ptr_type = get_pointer_to_type_extra(g, grand_child_type, false, false, ZigType *bland_child_ptr_type = get_pointer_to_type_extra(g, grand_child_type, false, false,
@ -1073,10 +1102,10 @@ bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) {
if (type_is_c_abi_int(g, fn_type_id->return_type)) { if (type_is_c_abi_int(g, fn_type_id->return_type)) {
return false; return false;
} }
if (g->zig_target.arch.arch == ZigLLVM_x86_64) { if (g->zig_target->arch == ZigLLVM_x86_64) {
X64CABIClass abi_class = type_c_abi_x86_64_class(g, fn_type_id->return_type); X64CABIClass abi_class = type_c_abi_x86_64_class(g, fn_type_id->return_type);
return abi_class == X64CABIClass_MEMORY; return abi_class == X64CABIClass_MEMORY;
} else if (target_is_arm(&g->zig_target)) { } else if (target_is_arm(g->zig_target)) {
return type_size(g, fn_type_id->return_type) > 16; return type_size(g, fn_type_id->return_type) > 16;
} }
zig_panic("TODO implement C ABI for this architecture. See https://github.com/ziglang/zig/issues/1481"); zig_panic("TODO implement C ABI for this architecture. See https://github.com/ziglang/zig/issues/1481");
@ -1300,7 +1329,7 @@ static ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *no
size_t backward_branch_count = 0; size_t backward_branch_count = 0;
return ir_eval_const_value(g, scope, node, type_entry, return ir_eval_const_value(g, scope, node, type_entry,
&backward_branch_count, default_backward_branch_quota, &backward_branch_count, default_backward_branch_quota,
nullptr, nullptr, node, type_name, nullptr); nullptr, nullptr, node, type_name, nullptr, nullptr);
} }
ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) { ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) {
@ -1415,7 +1444,10 @@ static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf **
return true; return true;
} }
static bool type_allowed_in_packed_struct(ZigType *type_entry) { static Error emit_error_unless_type_allowed_in_packed_struct(CodeGen *g, ZigType *type_entry,
AstNode *source_node)
{
Error err;
switch (type_entry->id) { switch (type_entry->id) {
case ZigTypeIdInvalid: case ZigTypeIdInvalid:
zig_unreachable(); zig_unreachable();
@ -1432,32 +1464,79 @@ static bool type_allowed_in_packed_struct(ZigType *type_entry) {
case ZigTypeIdArgTuple: case ZigTypeIdArgTuple:
case ZigTypeIdOpaque: case ZigTypeIdOpaque:
case ZigTypeIdPromise: case ZigTypeIdPromise:
return false; add_node_error(g, source_node,
buf_sprintf("type '%s' not allowed in packed struct; no guaranteed in-memory representation",
buf_ptr(&type_entry->name)));
return ErrorSemanticAnalyzeFail;
case ZigTypeIdVoid: case ZigTypeIdVoid:
case ZigTypeIdBool: case ZigTypeIdBool:
case ZigTypeIdInt: case ZigTypeIdInt:
case ZigTypeIdFloat: case ZigTypeIdFloat:
case ZigTypeIdPointer: case ZigTypeIdPointer:
case ZigTypeIdArray:
case ZigTypeIdFn: case ZigTypeIdFn:
case ZigTypeIdVector: case ZigTypeIdVector:
return true; return ErrorNone;
case ZigTypeIdStruct: case ZigTypeIdArray: {
return type_entry->data.structure.layout == ContainerLayoutPacked; ZigType *elem_type = type_entry->data.array.child_type;
case ZigTypeIdUnion: if ((err = emit_error_unless_type_allowed_in_packed_struct(g, elem_type, source_node)))
return type_entry->data.unionation.layout == ContainerLayoutPacked; return err;
case ZigTypeIdOptional: if (type_size(g, type_entry) * 8 == type_size_bits(g, type_entry))
{ return ErrorNone;
ZigType *child_type = type_entry->data.maybe.child_type; add_node_error(g, source_node,
return type_is_codegen_pointer(child_type); buf_sprintf("array of '%s' not allowed in packed struct due to padding bits",
buf_ptr(&elem_type->name)));
return ErrorSemanticAnalyzeFail;
}
case ZigTypeIdStruct:
switch (type_entry->data.structure.layout) {
case ContainerLayoutPacked:
case ContainerLayoutExtern:
return ErrorNone;
case ContainerLayoutAuto:
add_node_error(g, source_node,
buf_sprintf("non-packed, non-extern struct '%s' not allowed in packed struct; no guaranteed in-memory representation",
buf_ptr(&type_entry->name)));
return ErrorSemanticAnalyzeFail;
}
zig_unreachable();
case ZigTypeIdUnion:
switch (type_entry->data.unionation.layout) {
case ContainerLayoutPacked:
case ContainerLayoutExtern:
return ErrorNone;
case ContainerLayoutAuto:
add_node_error(g, source_node,
buf_sprintf("non-packed, non-extern union '%s' not allowed in packed struct; no guaranteed in-memory representation",
buf_ptr(&type_entry->name)));
return ErrorSemanticAnalyzeFail;
}
zig_unreachable();
case ZigTypeIdOptional:
if (get_codegen_ptr_type(type_entry) != nullptr) {
return ErrorNone;
} else {
add_node_error(g, source_node,
buf_sprintf("type '%s' not allowed in packed struct; no guaranteed in-memory representation",
buf_ptr(&type_entry->name)));
return ErrorSemanticAnalyzeFail;
}
case ZigTypeIdEnum: {
AstNode *decl_node = type_entry->data.enumeration.decl_node;
if (decl_node->data.container_decl.init_arg_expr != nullptr) {
return ErrorNone;
}
ErrorMsg *msg = add_node_error(g, source_node,
buf_sprintf("type '%s' not allowed in packed struct; no guaranteed in-memory representation",
buf_ptr(&type_entry->name)));
add_error_note(g, msg, decl_node,
buf_sprintf("enum declaration does not specify an integer tag type"));
return ErrorSemanticAnalyzeFail;
} }
case ZigTypeIdEnum:
return type_entry->data.enumeration.decl_node->data.container_decl.init_arg_expr != nullptr;
} }
zig_unreachable(); zig_unreachable();
} }
static bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) { bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) {
switch (type_entry->id) { switch (type_entry->id) {
case ZigTypeIdInvalid: case ZigTypeIdInvalid:
zig_unreachable(); zig_unreachable();
@ -1583,7 +1662,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
} }
} else if (param_node->data.param_decl.var_token != nullptr) { } else if (param_node->data.param_decl.var_token != nullptr) {
if (!calling_convention_allows_zig_types(fn_type_id.cc)) { if (!calling_convention_allows_zig_types(fn_type_id.cc)) {
add_node_error(g, param_node->data.param_decl.type, add_node_error(g, param_node,
buf_sprintf("parameter of type 'var' not allowed in function with calling convention '%s'", buf_sprintf("parameter of type 'var' not allowed in function with calling convention '%s'",
calling_convention_name(fn_type_id.cc))); calling_convention_name(fn_type_id.cc)));
return g->builtin_types.entry_invalid; return g->builtin_types.entry_invalid;
@ -2022,11 +2101,8 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
type_struct_field->gen_index = gen_field_index; type_struct_field->gen_index = gen_field_index;
if (packed) { if (packed) {
if (!type_allowed_in_packed_struct(field_type)) {
AstNode *field_source_node = decl_node->data.container_decl.fields.at(i); AstNode *field_source_node = decl_node->data.container_decl.fields.at(i);
add_node_error(g, field_source_node, if ((err = emit_error_unless_type_allowed_in_packed_struct(g, field_type, field_source_node))) {
buf_sprintf("packed structs cannot contain fields of type '%s'",
buf_ptr(&field_type->name)));
struct_type->data.structure.resolve_status = ResolveStatusInvalid; struct_type->data.structure.resolve_status = ResolveStatusInvalid;
break; break;
} }
@ -2650,6 +2726,13 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
buf_sprintf("enums, not structs, support field assignment")); buf_sprintf("enums, not structs, support field assignment"));
} }
if (field_type->id == ZigTypeIdOpaque) {
add_node_error(g, field_node->data.struct_field.type,
buf_sprintf("opaque types have unknown size and therefore cannot be directly embedded in structs"));
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
continue;
}
switch (type_requires_comptime(g, field_type)) { switch (type_requires_comptime(g, field_type)) {
case ReqCompTimeYes: case ReqCompTimeYes:
struct_type->data.structure.requires_comptime = true; struct_type->data.structure.requires_comptime = true;
@ -2828,7 +2911,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
union_type->data.unionation.have_explicit_tag_type = decl_node->data.container_decl.auto_enum || union_type->data.unionation.have_explicit_tag_type = decl_node->data.container_decl.auto_enum ||
enum_type_node != nullptr; enum_type_node != nullptr;
bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto); bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto);
bool want_safety = (field_count >= 2) && (auto_layout || enum_type_node != nullptr); bool want_safety = (field_count >= 2) && (auto_layout || enum_type_node != nullptr) && !(g->build_mode == BuildModeFastRelease || g->build_mode == BuildModeSmallRelease);
ZigType *tag_type; ZigType *tag_type;
bool create_enum_type = decl_node->data.container_decl.auto_enum || (enum_type_node == nullptr && want_safety); bool create_enum_type = decl_node->data.container_decl.auto_enum || (enum_type_node == nullptr && want_safety);
bool *covered_enum_fields; bool *covered_enum_fields;
@ -2934,6 +3017,13 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
} }
union_field->type_entry = field_type; union_field->type_entry = field_type;
if (field_type->id == ZigTypeIdOpaque) {
add_node_error(g, field_node->data.struct_field.type,
buf_sprintf("opaque types have unknown size and therefore cannot be directly embedded in unions"));
union_type->data.unionation.is_invalid = true;
continue;
}
switch (type_requires_comptime(g, field_type)) { switch (type_requires_comptime(g, field_type)) {
case ReqCompTimeInvalid: case ReqCompTimeInvalid:
union_type->data.unionation.is_invalid = true; union_type->data.unionation.is_invalid = true;
@ -3182,36 +3272,19 @@ static bool scope_is_root_decls(Scope *scope) {
zig_unreachable(); zig_unreachable();
} }
static void wrong_panic_prototype(CodeGen *g, AstNode *proto_node, ZigType *fn_type) { void typecheck_panic_fn(CodeGen *g, TldFn *tld_fn, ZigFn *panic_fn) {
add_node_error(g, proto_node, ConstExprValue *panic_fn_type_val = get_builtin_value(g, "PanicFn");
buf_sprintf("expected 'fn([]const u8, ?*builtin.StackTrace) noreturn', found '%s'", assert(panic_fn_type_val != nullptr);
buf_ptr(&fn_type->name))); assert(panic_fn_type_val->type->id == ZigTypeIdMetaType);
} ZigType *panic_fn_type = panic_fn_type_val->data.x_type;
static void typecheck_panic_fn(CodeGen *g, ZigFn *panic_fn) { AstNode *fake_decl = allocate<AstNode>(1);
AstNode *proto_node = panic_fn->proto_node; *fake_decl = *panic_fn->proto_node;
assert(proto_node->type == NodeTypeFnProto); fake_decl->type = NodeTypeSymbol;
ZigType *fn_type = panic_fn->type_entry; fake_decl->data.symbol_expr.symbol = &panic_fn->symbol_name;
FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
if (fn_type_id->param_count != 2) {
return wrong_panic_prototype(g, proto_node, fn_type);
}
ZigType *const_u8_ptr = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
PtrLenUnknown, 0, 0, 0);
ZigType *const_u8_slice = get_slice_type(g, const_u8_ptr);
if (fn_type_id->param_info[0].type != const_u8_slice) {
return wrong_panic_prototype(g, proto_node, fn_type);
}
ZigType *optional_ptr_to_stack_trace_type = get_optional_type(g, get_ptr_to_stack_trace_type(g)); // call this for the side effects of casting to panic_fn_type
if (fn_type_id->param_info[1].type != optional_ptr_to_stack_trace_type) { analyze_const_value(g, tld_fn->base.parent_scope, fake_decl, panic_fn_type, nullptr);
return wrong_panic_prototype(g, proto_node, fn_type);
}
ZigType *actual_return_type = fn_type_id->return_type;
if (actual_return_type != g->builtin_types.entry_unreachable) {
return wrong_panic_prototype(g, proto_node, fn_type);
}
} }
ZigType *get_test_fn_type(CodeGen *g) { ZigType *get_test_fn_type(CodeGen *g) {
@ -3231,16 +3304,16 @@ void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, Buf *symbol_name, GlobalLi
g->have_c_main = true; g->have_c_main = true;
g->subsystem = TargetSubsystemConsole; g->subsystem = TargetSubsystemConsole;
} else if (buf_eql_str(symbol_name, "WinMain") && } else if (buf_eql_str(symbol_name, "WinMain") &&
g->zig_target.os == OsWindows) g->zig_target->os == OsWindows)
{ {
g->have_winmain = true; g->have_winmain = true;
g->subsystem = TargetSubsystemWindows; g->subsystem = TargetSubsystemWindows;
} else if (buf_eql_str(symbol_name, "WinMainCRTStartup") && } else if (buf_eql_str(symbol_name, "WinMainCRTStartup") &&
g->zig_target.os == OsWindows) g->zig_target->os == OsWindows)
{ {
g->have_winmain_crt_startup = true; g->have_winmain_crt_startup = true;
} else if (buf_eql_str(symbol_name, "DllMainCRTStartup") && } else if (buf_eql_str(symbol_name, "DllMainCRTStartup") &&
g->zig_target.os == OsWindows) g->zig_target->os == OsWindows)
{ {
g->have_dllmain_crt_startup = true; g->have_dllmain_crt_startup = true;
} }
@ -3306,6 +3379,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
if (!fn_table_entry->type_entry->data.fn.is_generic) { if (!fn_table_entry->type_entry->data.fn.is_generic) {
if (fn_def_node) if (fn_def_node)
g->fn_defs.append(fn_table_entry); g->fn_defs.append(fn_table_entry);
}
if (scope_is_root_decls(tld_fn->base.parent_scope) && if (scope_is_root_decls(tld_fn->base.parent_scope) &&
(import == g->root_import || import->package == g->panic_package)) (import == g->root_import || import->package == g->panic_package))
@ -3316,8 +3390,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
buf_eql_str(&fn_table_entry->symbol_name, "panic")) buf_eql_str(&fn_table_entry->symbol_name, "panic"))
{ {
g->panic_fn = fn_table_entry; g->panic_fn = fn_table_entry;
typecheck_panic_fn(g, fn_table_entry); g->panic_tld_fn = tld_fn;
}
} }
} }
} else if (source_node->type == NodeTypeTestDecl) { } else if (source_node->type == NodeTypeTestDecl) {
@ -3366,9 +3439,9 @@ static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) {
if (is_export) { if (is_export) {
g->resolve_queue.append(tld); g->resolve_queue.append(tld);
auto entry = g->exported_symbol_names.put_unique(tld->name, tld->source_node); auto entry = g->exported_symbol_names.put_unique(tld->name, tld);
if (entry) { if (entry) {
AstNode *other_source_node = entry->value; AstNode *other_source_node = entry->value->source_node;
ErrorMsg *msg = add_node_error(g, tld->source_node, ErrorMsg *msg = add_node_error(g, tld->source_node,
buf_sprintf("exported symbol collision: '%s'", buf_ptr(tld->name))); buf_sprintf("exported symbol collision: '%s'", buf_ptr(tld->name)));
add_error_note(g, msg, other_source_node, buf_sprintf("other symbol here")); add_error_note(g, msg, other_source_node, buf_sprintf("other symbol here"));
@ -3698,7 +3771,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
VarLinkage linkage; VarLinkage linkage;
if (is_export) { if (is_export) {
linkage = VarLinkageExport; linkage = VarLinkageExportStrong;
} else if (is_extern) { } else if (is_extern) {
linkage = VarLinkageExternal; linkage = VarLinkageExternal;
} else { } else {
@ -4041,7 +4114,9 @@ ZigType *get_src_ptr_type(ZigType *type) {
if (type->id == ZigTypeIdFn) return type; if (type->id == ZigTypeIdFn) return type;
if (type->id == ZigTypeIdPromise) return type; if (type->id == ZigTypeIdPromise) return type;
if (type->id == ZigTypeIdOptional) { if (type->id == ZigTypeIdOptional) {
if (type->data.maybe.child_type->id == ZigTypeIdPointer) return type->data.maybe.child_type; if (type->data.maybe.child_type->id == ZigTypeIdPointer) {
return type->data.maybe.child_type->data.pointer.allow_zero ? nullptr : type->data.maybe.child_type;
}
if (type->data.maybe.child_type->id == ZigTypeIdFn) return type->data.maybe.child_type; if (type->data.maybe.child_type->id == ZigTypeIdFn) return type->data.maybe.child_type;
if (type->data.maybe.child_type->id == ZigTypeIdPromise) return type->data.maybe.child_type; if (type->data.maybe.child_type->id == ZigTypeIdPromise) return type->data.maybe.child_type;
} }
@ -4055,6 +4130,10 @@ ZigType *get_codegen_ptr_type(ZigType *type) {
return ty; return ty;
} }
bool type_is_nonnull_ptr(ZigType *type) {
return type_is_codegen_pointer(type) && !ptr_allows_addr_zero(type);
}
bool type_is_codegen_pointer(ZigType *type) { bool type_is_codegen_pointer(ZigType *type) {
return get_codegen_ptr_type(type) == type; return get_codegen_ptr_type(type) == type;
} }
@ -4572,185 +4651,6 @@ bool handle_is_ptr(ZigType *type_entry) {
zig_unreachable(); zig_unreachable();
} }
static ZigWindowsSDK *get_windows_sdk(CodeGen *g) {
if (g->win_sdk == nullptr) {
if (zig_find_windows_sdk(&g->win_sdk)) {
fprintf(stderr, "unable to determine windows sdk path\n");
exit(1);
}
}
assert(g->win_sdk != nullptr);
return g->win_sdk;
}
static Buf *get_linux_libc_lib_path(const char *o_file) {
const char *cc_exe = getenv("CC");
cc_exe = (cc_exe == nullptr) ? "cc" : cc_exe;
ZigList<const char *> args = {};
args.append(buf_ptr(buf_sprintf("-print-file-name=%s", o_file)));
Termination term;
Buf *out_stderr = buf_alloc();
Buf *out_stdout = buf_alloc();
Error err;
if ((err = os_exec_process(cc_exe, args, &term, out_stderr, out_stdout))) {
zig_panic("unable to determine libc lib path: executing C compiler: %s", err_str(err));
}
if (term.how != TerminationIdClean || term.code != 0) {
zig_panic("unable to determine libc lib path: executing C compiler command failed");
}
if (buf_ends_with_str(out_stdout, "\n")) {
buf_resize(out_stdout, buf_len(out_stdout) - 1);
}
if (buf_len(out_stdout) == 0 || buf_eql_str(out_stdout, o_file)) {
zig_panic("unable to determine libc lib path: C compiler could not find %s", o_file);
}
Buf *result = buf_alloc();
os_path_dirname(out_stdout, result);
return result;
}
static Buf *get_posix_libc_include_path(void) {
const char *cc_exe = getenv("CC");
cc_exe = (cc_exe == nullptr) ? "cc" : cc_exe;
ZigList<const char *> args = {};
args.append("-E");
args.append("-Wp,-v");
args.append("-xc");
args.append("/dev/null");
Termination term;
Buf *out_stderr = buf_alloc();
Buf *out_stdout = buf_alloc();
Error err;
if ((err = os_exec_process(cc_exe, args, &term, out_stderr, out_stdout))) {
zig_panic("unable to determine libc include path: executing C compiler: %s", err_str(err));
}
if (term.how != TerminationIdClean || term.code != 0) {
zig_panic("unable to determine libc include path: executing C compiler command failed");
}
char *prev_newline = buf_ptr(out_stderr);
ZigList<const char *> search_paths = {};
for (;;) {
char *newline = strchr(prev_newline, '\n');
if (newline == nullptr) {
break;
}
*newline = 0;
if (prev_newline[0] == ' ') {
search_paths.append(prev_newline);
}
prev_newline = newline + 1;
}
if (search_paths.length == 0) {
zig_panic("unable to determine libc include path: even C compiler does not know where libc headers are");
}
for (size_t i = 0; i < search_paths.length; i += 1) {
// search in reverse order
const char *search_path = search_paths.items[search_paths.length - i - 1];
// cut off spaces
while (*search_path == ' ') {
search_path += 1;
}
Buf *stdlib_path = buf_sprintf("%s/stdlib.h", search_path);
bool exists;
if ((err = os_file_exists(stdlib_path, &exists))) {
exists = false;
}
if (exists) {
return buf_create_from_str(search_path);
}
}
zig_panic("unable to determine libc include path: stdlib.h not found in C compiler search paths");
}
void find_libc_include_path(CodeGen *g) {
if (g->libc_include_dir == nullptr) {
if (!g->is_native_target) {
return;
}
if (g->zig_target.os == OsWindows) {
ZigWindowsSDK *sdk = get_windows_sdk(g);
g->libc_include_dir = buf_alloc();
if (os_get_win32_ucrt_include_path(sdk, g->libc_include_dir)) {
fprintf(stderr, "Unable to determine libc include path. --libc-include-dir");
exit(1);
}
} else if (g->zig_target.os == OsLinux ||
g->zig_target.os == OsMacOSX ||
g->zig_target.os == OsFreeBSD)
{
g->libc_include_dir = get_posix_libc_include_path();
} else {
fprintf(stderr, "Unable to determine libc include path.\n"
"TODO: implement finding libc at runtime for other operating systems.\n"
"in the meantime, you can use as a workaround: --libc-include-dir\n");
exit(1);
}
}
assert(buf_len(g->libc_include_dir) != 0);
}
void find_libc_lib_path(CodeGen *g) {
// later we can handle this better by reporting an error via the normal mechanism
if (g->libc_lib_dir == nullptr ||
(g->zig_target.os == OsWindows && (g->msvc_lib_dir == nullptr || g->kernel32_lib_dir == nullptr)))
{
if (g->zig_target.os == OsWindows) {
ZigWindowsSDK *sdk = get_windows_sdk(g);
if (g->msvc_lib_dir == nullptr) {
if (sdk->msvc_lib_dir_ptr == nullptr) {
fprintf(stderr, "Unable to determine vcruntime path. --msvc-lib-dir");
exit(1);
}
g->msvc_lib_dir = buf_create_from_mem(sdk->msvc_lib_dir_ptr, sdk->msvc_lib_dir_len);
}
if (g->libc_lib_dir == nullptr) {
Buf* ucrt_lib_path = buf_alloc();
if (os_get_win32_ucrt_lib_path(sdk, ucrt_lib_path, g->zig_target.arch.arch)) {
fprintf(stderr, "Unable to determine ucrt path. --libc-lib-dir");
exit(1);
}
g->libc_lib_dir = ucrt_lib_path;
}
if (g->kernel32_lib_dir == nullptr) {
Buf* kern_lib_path = buf_alloc();
if (os_get_win32_kern32_path(sdk, kern_lib_path, g->zig_target.arch.arch)) {
fprintf(stderr, "Unable to determine kernel32 path. --kernel32-lib-dir");
exit(1);
}
g->kernel32_lib_dir = kern_lib_path;
}
} else if (g->zig_target.os == OsLinux) {
g->libc_lib_dir = get_linux_libc_lib_path("crt1.o");
} else if (g->zig_target.os == OsFreeBSD) {
g->libc_lib_dir = buf_create_from_str("/usr/lib");
} else {
zig_panic("Unable to determine libc lib path.");
}
} else {
assert(buf_len(g->libc_lib_dir) != 0);
}
if (g->libc_static_lib_dir == nullptr) {
if ((g->zig_target.os == OsWindows) && (g->msvc_lib_dir != NULL)) {
return;
} else if (g->zig_target.os == OsLinux) {
g->libc_static_lib_dir = get_linux_libc_lib_path("crtbegin.o");
} else if (g->zig_target.os == OsFreeBSD) {
g->libc_static_lib_dir = buf_create_from_str("/usr/lib");
} else {
zig_panic("Unable to determine libc static lib path.");
}
} else {
assert(buf_len(g->libc_static_lib_dir) != 0);
}
}
static uint32_t hash_ptr(void *ptr) { static uint32_t hash_ptr(void *ptr) {
return (uint32_t)(((uintptr_t)ptr) % UINT32_MAX); return (uint32_t)(((uintptr_t)ptr) % UINT32_MAX);
} }
@ -5229,6 +5129,10 @@ bool type_has_bits(ZigType *type_entry) {
// Whether you can infer the value based solely on the type. // Whether you can infer the value based solely on the type.
OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) { OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) {
assert(type_entry != nullptr); assert(type_entry != nullptr);
if (type_entry->one_possible_value != OnePossibleValueInvalid)
return type_entry->one_possible_value;
Error err; Error err;
if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown)))
return OnePossibleValueInvalid; return OnePossibleValueInvalid;
@ -5276,8 +5180,14 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) {
case ZigTypeIdInt: case ZigTypeIdInt:
case ZigTypeIdVector: case ZigTypeIdVector:
return type_has_bits(type_entry) ? OnePossibleValueNo : OnePossibleValueYes; return type_has_bits(type_entry) ? OnePossibleValueNo : OnePossibleValueYes;
case ZigTypeIdPointer: case ZigTypeIdPointer: {
return type_has_one_possible_value(g, type_entry->data.pointer.child_type); ZigType *elem_type = type_entry->data.pointer.child_type;
// If the recursive function call asks, then we are not one possible value.
type_entry->one_possible_value = OnePossibleValueNo;
// Now update it to be the value of the recursive call.
type_entry->one_possible_value = type_has_one_possible_value(g, elem_type);
return type_entry->one_possible_value;
}
case ZigTypeIdUnion: case ZigTypeIdUnion:
if (type_entry->data.unionation.src_field_count > 1) if (type_entry->data.unionation.src_field_count > 1)
return OnePossibleValueNo; return OnePossibleValueNo;
@ -6010,16 +5920,20 @@ static void render_const_val_err_set(CodeGen *g, Buf *buf, ConstExprValue *const
} }
} }
static void render_const_val_array(CodeGen *g, Buf *buf, ConstExprValue *const_val, size_t len) { static void render_const_val_array(CodeGen *g, Buf *buf, Buf *type_name, ConstExprValue *const_val, uint64_t start, uint64_t len) {
switch (const_val->data.x_array.special) { ConstArrayValue *array = &const_val->data.x_array;
switch (array->special) {
case ConstArraySpecialUndef: case ConstArraySpecialUndef:
buf_append_str(buf, "undefined"); buf_append_str(buf, "undefined");
return; return;
case ConstArraySpecialBuf: { case ConstArraySpecialBuf: {
Buf *array_buf = const_val->data.x_array.data.s_buf; Buf *array_buf = array->data.s_buf;
const char *base = &buf_ptr(array_buf)[start];
assert(start + len <= buf_len(array_buf));
buf_append_char(buf, '"'); buf_append_char(buf, '"');
for (size_t i = 0; i < buf_len(array_buf); i += 1) { for (size_t i = 0; i < len; i += 1) {
uint8_t c = buf_ptr(array_buf)[i]; uint8_t c = base[i];
if (c == '"') { if (c == '"') {
buf_append_str(buf, "\\\""); buf_append_str(buf, "\\\"");
} else { } else {
@ -6030,12 +5944,13 @@ static void render_const_val_array(CodeGen *g, Buf *buf, ConstExprValue *const_v
return; return;
} }
case ConstArraySpecialNone: { case ConstArraySpecialNone: {
buf_appendf(buf, "%s{", buf_ptr(&const_val->type->name)); ConstExprValue *base = &array->data.s_none.elements[start];
assert(start + len <= const_val->type->data.array.len);
buf_appendf(buf, "%s{", buf_ptr(type_name));
for (uint64_t i = 0; i < len; i += 1) { for (uint64_t i = 0; i < len; i += 1) {
if (i != 0) if (i != 0) buf_appendf(buf, ",");
buf_appendf(buf, ","); render_const_value(g, buf, &base[i]);
ConstExprValue *child_value = &const_val->data.x_array.data.s_none.elements[i];
render_const_value(g, buf, child_value);
} }
buf_appendf(buf, "}"); buf_appendf(buf, "}");
return; return;
@ -6124,10 +6039,16 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
} }
case ZigTypeIdPointer: case ZigTypeIdPointer:
return render_const_val_ptr(g, buf, const_val, type_entry); return render_const_val_ptr(g, buf, const_val, type_entry);
case ZigTypeIdVector: case ZigTypeIdArray: {
return render_const_val_array(g, buf, const_val, type_entry->data.vector.len); uint64_t len = type_entry->data.array.len;
case ZigTypeIdArray: render_const_val_array(g, buf, &type_entry->name, const_val, 0, len);
return render_const_val_array(g, buf, const_val, type_entry->data.array.len); return;
}
case ZigTypeIdVector: {
uint32_t len = type_entry->data.vector.len;
render_const_val_array(g, buf, &type_entry->name, const_val, 0, len);
return;
}
case ZigTypeIdNull: case ZigTypeIdNull:
{ {
buf_appendf(buf, "null"); buf_appendf(buf, "null");
@ -6169,7 +6090,24 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
} }
case ZigTypeIdStruct: case ZigTypeIdStruct:
{ {
if (is_slice(type_entry)) {
ConstExprValue *len_val = &const_val->data.x_struct.fields[slice_len_index];
size_t len = bigint_as_unsigned(&len_val->data.x_bigint);
ConstExprValue *ptr_val = &const_val->data.x_struct.fields[slice_ptr_index];
if (ptr_val->special == ConstValSpecialUndef) {
assert(len == 0);
buf_appendf(buf, "((%s)(undefined))[0..0]", buf_ptr(&type_entry->name));
return;
}
assert(ptr_val->data.x_ptr.special == ConstPtrSpecialBaseArray);
ConstExprValue *array = ptr_val->data.x_ptr.data.base_array.array_val;
size_t start = ptr_val->data.x_ptr.data.base_array.elem_index;
render_const_val_array(g, buf, &type_entry->name, array, start, len);
} else {
buf_appendf(buf, "(struct %s constant)", buf_ptr(&type_entry->name)); buf_appendf(buf, "(struct %s constant)", buf_ptr(&type_entry->name));
}
return; return;
} }
case ZigTypeIdEnum: case ZigTypeIdEnum:
@ -6193,8 +6131,8 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
} }
case ZigTypeIdUnion: case ZigTypeIdUnion:
{ {
uint64_t tag = bigint_as_unsigned(&const_val->data.x_union.tag); const BigInt *tag = &const_val->data.x_union.tag;
TypeUnionField *field = &type_entry->data.unionation.fields[tag]; TypeUnionField *field = find_union_field_by_tag(type_entry, tag);
buf_appendf(buf, "%s { .%s = ", buf_ptr(&type_entry->name), buf_ptr(field->name)); buf_appendf(buf, "%s { .%s = ", buf_ptr(&type_entry->name), buf_ptr(field->name));
render_const_value(g, buf, const_val->data.x_union.payload); render_const_value(g, buf, const_val->data.x_union.payload);
buf_append_str(buf, "}"); buf_append_str(buf, "}");
@ -6277,6 +6215,7 @@ uint32_t type_id_hash(TypeId x) {
((x.data.pointer.ptr_len == PtrLenSingle) ? (uint32_t)1120226602 : (uint32_t)3200913342) + ((x.data.pointer.ptr_len == PtrLenSingle) ? (uint32_t)1120226602 : (uint32_t)3200913342) +
(x.data.pointer.is_const ? (uint32_t)2749109194 : (uint32_t)4047371087) + (x.data.pointer.is_const ? (uint32_t)2749109194 : (uint32_t)4047371087) +
(x.data.pointer.is_volatile ? (uint32_t)536730450 : (uint32_t)1685612214) + (x.data.pointer.is_volatile ? (uint32_t)536730450 : (uint32_t)1685612214) +
(x.data.pointer.allow_zero ? (uint32_t)3324284834 : (uint32_t)3584904923) +
(((uint32_t)x.data.pointer.alignment) ^ (uint32_t)0x777fbe0e) + (((uint32_t)x.data.pointer.alignment) ^ (uint32_t)0x777fbe0e) +
(((uint32_t)x.data.pointer.bit_offset_in_host) ^ (uint32_t)2639019452) + (((uint32_t)x.data.pointer.bit_offset_in_host) ^ (uint32_t)2639019452) +
(((uint32_t)x.data.pointer.host_int_bytes) ^ (uint32_t)529908881); (((uint32_t)x.data.pointer.host_int_bytes) ^ (uint32_t)529908881);
@ -6327,6 +6266,7 @@ bool type_id_eql(TypeId a, TypeId b) {
a.data.pointer.ptr_len == b.data.pointer.ptr_len && a.data.pointer.ptr_len == b.data.pointer.ptr_len &&
a.data.pointer.is_const == b.data.pointer.is_const && a.data.pointer.is_const == b.data.pointer.is_const &&
a.data.pointer.is_volatile == b.data.pointer.is_volatile && a.data.pointer.is_volatile == b.data.pointer.is_volatile &&
a.data.pointer.allow_zero == b.data.pointer.allow_zero &&
a.data.pointer.alignment == b.data.pointer.alignment && a.data.pointer.alignment == b.data.pointer.alignment &&
a.data.pointer.bit_offset_in_host == b.data.pointer.bit_offset_in_host && a.data.pointer.bit_offset_in_host == b.data.pointer.bit_offset_in_host &&
a.data.pointer.host_int_bytes == b.data.pointer.host_int_bytes; a.data.pointer.host_int_bytes == b.data.pointer.host_int_bytes;
@ -6626,12 +6566,6 @@ LinkLib *add_link_lib(CodeGen *g, Buf *name) {
if (is_libc && g->libc_link_lib != nullptr) if (is_libc && g->libc_link_lib != nullptr)
return g->libc_link_lib; return g->libc_link_lib;
if (g->enable_cache && is_libc && g->zig_target.os != OsMacOSX && g->zig_target.os != OsIOS && g->zig_target.os != OsFreeBSD) {
fprintf(stderr, "TODO linking against libc is currently incompatible with `--cache on`.\n"
"Zig is not yet capable of determining whether the libc installation has changed on subsequent builds.\n");
exit(1);
}
for (size_t i = 0; i < g->link_libs_list.length; i += 1) { for (size_t i = 0; i < g->link_libs_list.length; i += 1) {
LinkLib *existing_lib = g->link_libs_list.at(i); LinkLib *existing_lib = g->link_libs_list.at(i);
if (buf_eql_buf(existing_lib->name, name)) { if (buf_eql_buf(existing_lib->name, name)) {
@ -6860,3 +6794,21 @@ Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_no
return ErrorNone; return ErrorNone;
} }
const char *container_string(ContainerKind kind) {
switch (kind) {
case ContainerKindEnum: return "enum";
case ContainerKindStruct: return "struct";
case ContainerKindUnion: return "union";
}
zig_unreachable();
}
bool ptr_allows_addr_zero(ZigType *ptr_type) {
if (ptr_type->id == ZigTypeIdPointer) {
return ptr_type->data.pointer.allow_zero;
} else if (ptr_type->id == ZigTypeIdOptional) {
return true;
}
return false;
}

View File

@ -40,11 +40,11 @@ ZigType *get_promise_type(CodeGen *g, ZigType *result_type);
ZigType *get_promise_frame_type(CodeGen *g, ZigType *return_type); ZigType *get_promise_frame_type(CodeGen *g, ZigType *return_type);
ZigType *get_test_fn_type(CodeGen *g); ZigType *get_test_fn_type(CodeGen *g);
bool handle_is_ptr(ZigType *type_entry); bool handle_is_ptr(ZigType *type_entry);
void find_libc_include_path(CodeGen *g);
void find_libc_lib_path(CodeGen *g);
bool type_has_bits(ZigType *type_entry); bool type_has_bits(ZigType *type_entry);
bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry);
bool ptr_allows_addr_zero(ZigType *ptr_type);
bool type_is_nonnull_ptr(ZigType *type);
ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *abs_full_path, Buf *source_code); ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *abs_full_path, Buf *source_code);
@ -215,6 +215,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk);
X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty); X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty);
bool type_is_c_abi_int(CodeGen *g, ZigType *ty); bool type_is_c_abi_int(CodeGen *g, ZigType *ty);
bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id); bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id);
const char *container_string(ContainerKind kind);
uint32_t get_host_int_bytes(CodeGen *g, ZigType *struct_type, TypeStructField *field); uint32_t get_host_int_bytes(CodeGen *g, ZigType *struct_type, TypeStructField *field);
@ -225,14 +226,10 @@ enum ReqCompTime {
}; };
ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry); ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry);
enum OnePossibleValue {
OnePossibleValueInvalid,
OnePossibleValueNo,
OnePossibleValueYes,
};
OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry); OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry);
Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node,
ConstExprValue *const_val, ZigType *wanted_type); ConstExprValue *const_val, ZigType *wanted_type);
void typecheck_panic_fn(CodeGen *g, TldFn *tld_fn, ZigFn *panic_fn);
#endif #endif

View File

@ -136,13 +136,19 @@ static const char *thread_local_string(Token *tok) {
return (tok == nullptr) ? "" : "threadlocal "; return (tok == nullptr) ? "" : "threadlocal ";
} }
const char *container_string(ContainerKind kind) { static const char *token_to_ptr_len_str(Token *tok) {
switch (kind) { assert(tok != nullptr);
case ContainerKindEnum: return "enum"; switch (tok->id) {
case ContainerKindStruct: return "struct"; case TokenIdStar:
case ContainerKindUnion: return "union"; case TokenIdStarStar:
} return "*";
case TokenIdBracketStarBracket:
return "[*]";
case TokenIdBracketStarCBracket:
return "[*c]";
default:
zig_unreachable(); zig_unreachable();
}
} }
static const char *node_type_str(NodeType node_type) { static const char *node_type_str(NodeType node_type) {
@ -644,13 +650,8 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
case NodeTypePointerType: case NodeTypePointerType:
{ {
if (!grouped) fprintf(ar->f, "("); if (!grouped) fprintf(ar->f, "(");
const char *star = "[*]"; const char *ptr_len_str = token_to_ptr_len_str(node->data.pointer_type.star_token);
if (node->data.pointer_type.star_token != nullptr && fprintf(ar->f, "%s", ptr_len_str);
(node->data.pointer_type.star_token->id == TokenIdStar || node->data.pointer_type.star_token->id == TokenIdStarStar))
{
star = "*";
}
fprintf(ar->f, "%s", star);
if (node->data.pointer_type.align_expr != nullptr) { if (node->data.pointer_type.align_expr != nullptr) {
fprintf(ar->f, "align("); fprintf(ar->f, "align(");
render_node_grouped(ar, node->data.pointer_type.align_expr); render_node_grouped(ar, node->data.pointer_type.align_expr);

View File

@ -17,7 +17,4 @@ void ast_print(FILE *f, AstNode *node, int indent);
void ast_render(CodeGen *codegen, FILE *f, AstNode *node, int indent_size); void ast_render(CodeGen *codegen, FILE *f, AstNode *node, int indent_size);
const char *container_string(ContainerKind kind);
#endif #endif

View File

@ -1665,7 +1665,6 @@ int64_t bigint_as_signed(const BigInt *bigint) {
return 0; return 0;
} else if (bigint->digit_count == 1) { } else if (bigint->digit_count == 1) {
if (bigint->is_negative) { if (bigint->is_negative) {
// TODO this code path is untested
if (bigint->data.digit <= 9223372036854775808ULL) { if (bigint->data.digit <= 9223372036854775808ULL) {
return (-((int64_t)(bigint->data.digit - 1))) - 1; return (-((int64_t)(bigint->data.digit - 1))) - 1;
} else { } else {

View File

@ -132,9 +132,7 @@ void buf_appendf(Buf *buf, const char *format, ...)
static inline bool buf_eql_mem(Buf *buf, const char *mem, size_t mem_len) { static inline bool buf_eql_mem(Buf *buf, const char *mem, size_t mem_len) {
assert(buf->list.length); assert(buf->list.length);
if (buf_len(buf) != mem_len) return mem_eql_mem(buf_ptr(buf), buf_len(buf), mem, mem_len);
return false;
return memcmp(buf_ptr(buf), mem, mem_len) == 0;
} }
static inline bool buf_eql_str(Buf *buf, const char *str) { static inline bool buf_eql_str(Buf *buf, const char *str) {

View File

@ -414,6 +414,39 @@ Error cache_add_file(CacheHash *ch, Buf *path) {
return cache_add_file_fetch(ch, resolved_path, nullptr); return cache_add_file_fetch(ch, resolved_path, nullptr);
} }
Error cache_add_dep_file(CacheHash *ch, Buf *dep_file_path, bool verbose) {
Error err;
Buf *contents = buf_alloc();
if ((err = os_fetch_file_path(dep_file_path, contents, false))) {
if (verbose) {
fprintf(stderr, "unable to read .d file: %s\n", err_str(err));
}
return ErrorReadingDepFile;
}
SplitIterator it = memSplit(buf_to_slice(contents), str("\n"));
// skip first line
SplitIterator_next(&it);
for (;;) {
Optional<Slice<uint8_t>> opt_line = SplitIterator_next(&it);
if (!opt_line.is_some)
break;
if (opt_line.value.len == 0)
continue;
SplitIterator line_it = memSplit(opt_line.value, str(" \t"));
Slice<uint8_t> filename;
if (!SplitIterator_next(&line_it).unwrap(&filename))
continue;
Buf *filename_buf = buf_create_from_slice(filename);
if ((err = cache_add_file(ch, filename_buf))) {
if (verbose) {
fprintf(stderr, "unable to add %s to cache: %s\n", buf_ptr(filename_buf), err_str(err));
}
return err;
}
}
return ErrorNone;
}
static Error write_manifest_file(CacheHash *ch) { static Error write_manifest_file(CacheHash *ch) {
Error err; Error err;
Buf contents = BUF_INIT; Buf contents = BUF_INIT;
@ -464,3 +497,4 @@ void cache_release(CacheHash *ch) {
os_file_close(ch->manifest_file); os_file_close(ch->manifest_file);
} }

View File

@ -56,6 +56,8 @@ Error ATTRIBUTE_MUST_USE cache_hit(CacheHash *ch, Buf *out_b64_digest);
// If you did not get a cache hit, call this function for every file // If you did not get a cache hit, call this function for every file
// that is depended on, and then finish with cache_final. // that is depended on, and then finish with cache_final.
Error ATTRIBUTE_MUST_USE cache_add_file(CacheHash *ch, Buf *path); Error ATTRIBUTE_MUST_USE cache_add_file(CacheHash *ch, Buf *path);
// This opens a file created by -MD -MF args to Clang
Error ATTRIBUTE_MUST_USE cache_add_dep_file(CacheHash *ch, Buf *path, bool verbose);
// This variant of cache_add_file returns the file contents. // This variant of cache_add_file returns the file contents.
// Also the file path argument must be already resolved. // Also the file path argument must be already resolved.

File diff suppressed because it is too large Load Diff

View File

@ -11,11 +11,12 @@
#include "parser.hpp" #include "parser.hpp"
#include "errmsg.hpp" #include "errmsg.hpp"
#include "target.hpp" #include "target.hpp"
#include "libc_installation.hpp"
#include <stdio.h> #include <stdio.h>
CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode, CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode,
Buf *zig_lib_dir, Buf *override_std_dir); Buf *zig_lib_dir, Buf *override_std_dir, ZigLibCInstallation *libc);
void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len); void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len);
void codegen_set_llvm_argv(CodeGen *codegen, const char **args, size_t len); void codegen_set_llvm_argv(CodeGen *codegen, const char **args, size_t len);
@ -27,12 +28,6 @@ void codegen_set_is_static(CodeGen *codegen, bool is_static);
void codegen_set_strip(CodeGen *codegen, bool strip); void codegen_set_strip(CodeGen *codegen, bool strip);
void codegen_set_errmsg_color(CodeGen *codegen, ErrColor err_color); void codegen_set_errmsg_color(CodeGen *codegen, ErrColor err_color);
void codegen_set_out_name(CodeGen *codegen, Buf *out_name); void codegen_set_out_name(CodeGen *codegen, Buf *out_name);
void codegen_set_libc_lib_dir(CodeGen *codegen, Buf *libc_lib_dir);
void codegen_set_libc_static_lib_dir(CodeGen *g, Buf *libc_static_lib_dir);
void codegen_set_libc_include_dir(CodeGen *codegen, Buf *libc_include_dir);
void codegen_set_msvc_lib_dir(CodeGen *g, Buf *msvc_lib_dir);
void codegen_set_kernel32_lib_dir(CodeGen *codegen, Buf *kernel32_lib_dir);
void codegen_set_dynamic_linker(CodeGen *g, Buf *dynamic_linker);
void codegen_add_lib_dir(CodeGen *codegen, const char *dir); void codegen_add_lib_dir(CodeGen *codegen, const char *dir);
void codegen_add_forbidden_lib(CodeGen *codegen, Buf *lib); void codegen_add_forbidden_lib(CodeGen *codegen, Buf *lib);
LinkLib *codegen_add_link_lib(CodeGen *codegen, Buf *lib); LinkLib *codegen_add_link_lib(CodeGen *codegen, Buf *lib);
@ -46,6 +41,7 @@ void codegen_set_test_filter(CodeGen *g, Buf *filter);
void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix); void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix);
void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patch); void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patch);
void codegen_set_output_h_path(CodeGen *g, Buf *h_path); void codegen_set_output_h_path(CodeGen *g, Buf *h_path);
void codegen_set_output_lib_path(CodeGen *g, Buf *lib_path);
void codegen_set_output_path(CodeGen *g, Buf *path); void codegen_set_output_path(CodeGen *g, Buf *path);
void codegen_add_time_event(CodeGen *g, const char *name); void codegen_add_time_event(CodeGen *g, const char *name);
void codegen_print_timing_report(CodeGen *g, FILE *f); void codegen_print_timing_report(CodeGen *g, FILE *f);

View File

@ -34,6 +34,15 @@ const char *err_str(Error err) {
case ErrorPipeBusy: return "pipe busy"; case ErrorPipeBusy: return "pipe busy";
case ErrorPrimitiveTypeNotFound: return "primitive type not found"; case ErrorPrimitiveTypeNotFound: return "primitive type not found";
case ErrorCacheUnavailable: return "cache unavailable"; case ErrorCacheUnavailable: return "cache unavailable";
case ErrorPathTooLong: return "path too long";
case ErrorCCompilerCannotFindFile: return "C compiler cannot find file";
case ErrorReadingDepFile: return "failed to read .d file";
case ErrorMissingArchitecture: return "missing architecture";
case ErrorMissingOperatingSystem: return "missing operating system";
case ErrorUnknownArchitecture: return "unrecognized architecture";
case ErrorUnknownOperatingSystem: return "unrecognized operating system";
case ErrorUnknownABI: return "unrecognized C ABI";
case ErrorInvalidFilename: return "invalid filename";
} }
return "(invalid error)"; return "(invalid error)";
} }

View File

@ -36,6 +36,15 @@ enum Error {
ErrorPipeBusy, ErrorPipeBusy,
ErrorPrimitiveTypeNotFound, ErrorPrimitiveTypeNotFound,
ErrorCacheUnavailable, ErrorCacheUnavailable,
ErrorPathTooLong,
ErrorCCompilerCannotFindFile,
ErrorReadingDepFile,
ErrorMissingArchitecture,
ErrorMissingOperatingSystem,
ErrorUnknownArchitecture,
ErrorUnknownOperatingSystem,
ErrorUnknownABI,
ErrorInvalidFilename,
}; };
const char *err_str(Error err); const char *err_str(Error err);

1361
src/ir.cpp

File diff suppressed because it is too large Load Diff

View File

@ -16,7 +16,7 @@ bool ir_gen_fn(CodeGen *g, ZigFn *fn_entry);
ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,
ZigType *expected_type, size_t *backward_branch_count, size_t backward_branch_quota, ZigType *expected_type, size_t *backward_branch_count, size_t backward_branch_quota,
ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name,
IrExecutable *parent_exec); IrExecutable *parent_exec, AstNode *expected_type_source_node);
ZigType *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutable *new_executable, ZigType *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutable *new_executable,
ZigType *expected_type, AstNode *expected_type_source_node); ZigType *expected_type, AstNode *expected_type_source_node);

View File

@ -336,6 +336,11 @@ static void ir_print_load_ptr(IrPrint *irp, IrInstructionLoadPtr *instruction) {
fprintf(irp->f, ".*"); fprintf(irp->f, ".*");
} }
static void ir_print_load_ptr_gen(IrPrint *irp, IrInstructionLoadPtrGen *instruction) {
ir_print_other_instruction(irp, instruction->ptr);
fprintf(irp->f, ".*");
}
static void ir_print_store_ptr(IrPrint *irp, IrInstructionStorePtr *instruction) { static void ir_print_store_ptr(IrPrint *irp, IrInstructionStorePtr *instruction) {
fprintf(irp->f, "*"); fprintf(irp->f, "*");
ir_print_var_instruction(irp, instruction->ptr); ir_print_var_instruction(irp, instruction->ptr);
@ -915,14 +920,18 @@ static void ir_print_ptr_cast_gen(IrPrint *irp, IrInstructionPtrCastGen *instruc
static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) { static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) {
fprintf(irp->f, "@bitCast("); fprintf(irp->f, "@bitCast(");
if (instruction->dest_type) {
ir_print_other_instruction(irp, instruction->dest_type); ir_print_other_instruction(irp, instruction->dest_type);
}
fprintf(irp->f, ","); fprintf(irp->f, ",");
ir_print_other_instruction(irp, instruction->value); ir_print_other_instruction(irp, instruction->value);
fprintf(irp->f, ")"); fprintf(irp->f, ")");
} }
static void ir_print_bit_cast_gen(IrPrint *irp, IrInstructionBitCastGen *instruction) {
fprintf(irp->f, "@bitCast(");
ir_print_other_instruction(irp, instruction->operand);
fprintf(irp->f, ")");
}
static void ir_print_widen_or_shorten(IrPrint *irp, IrInstructionWidenOrShorten *instruction) { static void ir_print_widen_or_shorten(IrPrint *irp, IrInstructionWidenOrShorten *instruction) {
fprintf(irp->f, "WidenOrShorten("); fprintf(irp->f, "WidenOrShorten(");
ir_print_other_instruction(irp, instruction->target); ir_print_other_instruction(irp, instruction->target);
@ -990,6 +999,12 @@ static void ir_print_assert_zero(IrPrint *irp, IrInstructionAssertZero *instruct
fprintf(irp->f, ")"); fprintf(irp->f, ")");
} }
static void ir_print_resize_slice(IrPrint *irp, IrInstructionResizeSlice *instruction) {
fprintf(irp->f, "@resizeSlice(");
ir_print_other_instruction(irp, instruction->operand);
fprintf(irp->f, ")");
}
static void ir_print_int_to_err(IrPrint *irp, IrInstructionIntToErr *instruction) { static void ir_print_int_to_err(IrPrint *irp, IrInstructionIntToErr *instruction) {
fprintf(irp->f, "inttoerr "); fprintf(irp->f, "inttoerr ");
ir_print_other_instruction(irp, instruction->target); ir_print_other_instruction(irp, instruction->target);
@ -1462,6 +1477,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdLoadPtr: case IrInstructionIdLoadPtr:
ir_print_load_ptr(irp, (IrInstructionLoadPtr *)instruction); ir_print_load_ptr(irp, (IrInstructionLoadPtr *)instruction);
break; break;
case IrInstructionIdLoadPtrGen:
ir_print_load_ptr_gen(irp, (IrInstructionLoadPtrGen *)instruction);
break;
case IrInstructionIdStorePtr: case IrInstructionIdStorePtr:
ir_print_store_ptr(irp, (IrInstructionStorePtr *)instruction); ir_print_store_ptr(irp, (IrInstructionStorePtr *)instruction);
break; break;
@ -1678,6 +1696,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdBitCast: case IrInstructionIdBitCast:
ir_print_bit_cast(irp, (IrInstructionBitCast *)instruction); ir_print_bit_cast(irp, (IrInstructionBitCast *)instruction);
break; break;
case IrInstructionIdBitCastGen:
ir_print_bit_cast_gen(irp, (IrInstructionBitCastGen *)instruction);
break;
case IrInstructionIdWidenOrShorten: case IrInstructionIdWidenOrShorten:
ir_print_widen_or_shorten(irp, (IrInstructionWidenOrShorten *)instruction); ir_print_widen_or_shorten(irp, (IrInstructionWidenOrShorten *)instruction);
break; break;
@ -1852,6 +1873,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdAssertZero: case IrInstructionIdAssertZero:
ir_print_assert_zero(irp, (IrInstructionAssertZero *)instruction); ir_print_assert_zero(irp, (IrInstructionAssertZero *)instruction);
break; break;
case IrInstructionIdResizeSlice:
ir_print_resize_slice(irp, (IrInstructionResizeSlice *)instruction);
break;
} }
fprintf(irp->f, "\n"); fprintf(irp->f, "\n");
} }

498
src/libc_installation.cpp Normal file
View File

@ -0,0 +1,498 @@
/*
* Copyright (c) 2019 Andrew Kelley
*
* This file is part of zig, which is MIT licensed.
* See http://opensource.org/licenses/MIT
*/
#include "libc_installation.hpp"
#include "os.hpp"
#include "windows_sdk.h"
#include "target.hpp"
static const char *zig_libc_keys[] = {
"include_dir",
"sys_include_dir",
"crt_dir",
"lib_dir",
"static_lib_dir",
"msvc_lib_dir",
"kernel32_lib_dir",
"dynamic_linker_path",
};
static const size_t zig_libc_keys_len = array_length(zig_libc_keys);
static bool zig_libc_match_key(Slice<uint8_t> name, Slice<uint8_t> value, bool *found_keys,
size_t index, Buf *field_ptr)
{
if (!memEql(name, str(zig_libc_keys[index]))) return false;
buf_init_from_mem(field_ptr, (const char*)value.ptr, value.len);
found_keys[index] = true;
return true;
}
static void zig_libc_init_empty(ZigLibCInstallation *libc) {
*libc = {};
buf_init_from_str(&libc->include_dir, "");
buf_init_from_str(&libc->sys_include_dir, "");
buf_init_from_str(&libc->crt_dir, "");
buf_init_from_str(&libc->lib_dir, "");
buf_init_from_str(&libc->static_lib_dir, "");
buf_init_from_str(&libc->msvc_lib_dir, "");
buf_init_from_str(&libc->kernel32_lib_dir, "");
buf_init_from_str(&libc->dynamic_linker_path, "");
}
Error zig_libc_parse(ZigLibCInstallation *libc, Buf *libc_file, const ZigTarget *target, bool verbose) {
Error err;
zig_libc_init_empty(libc);
bool found_keys[array_length(zig_libc_keys)] = {};
Buf *contents = buf_alloc();
if ((err = os_fetch_file_path(libc_file, contents, false))) {
if (err != ErrorFileNotFound && verbose) {
fprintf(stderr, "Unable to read '%s': %s\n", buf_ptr(libc_file), err_str(err));
}
return err;
}
SplitIterator it = memSplit(buf_to_slice(contents), str("\n"));
for (;;) {
Optional<Slice<uint8_t>> opt_line = SplitIterator_next(&it);
if (!opt_line.is_some)
break;
if (opt_line.value.len == 0 || opt_line.value.ptr[0] == '#')
continue;
SplitIterator line_it = memSplit(opt_line.value, str("="));
Slice<uint8_t> name;
if (!SplitIterator_next(&line_it).unwrap(&name)) {
if (verbose) {
fprintf(stderr, "missing equal sign after field name\n");
}
return ErrorSemanticAnalyzeFail;
}
Slice<uint8_t> value = SplitIterator_rest(&line_it);
bool match = false;
match = match || zig_libc_match_key(name, value, found_keys, 0, &libc->include_dir);
match = match || zig_libc_match_key(name, value, found_keys, 1, &libc->sys_include_dir);
match = match || zig_libc_match_key(name, value, found_keys, 2, &libc->crt_dir);
match = match || zig_libc_match_key(name, value, found_keys, 3, &libc->lib_dir);
match = match || zig_libc_match_key(name, value, found_keys, 4, &libc->static_lib_dir);
match = match || zig_libc_match_key(name, value, found_keys, 5, &libc->msvc_lib_dir);
match = match || zig_libc_match_key(name, value, found_keys, 6, &libc->kernel32_lib_dir);
match = match || zig_libc_match_key(name, value, found_keys, 7, &libc->dynamic_linker_path);
}
for (size_t i = 0; i < zig_libc_keys_len; i += 1) {
if (!found_keys[i]) {
if (verbose) {
fprintf(stderr, "missing field: %s\n", zig_libc_keys[i]);
}
return ErrorSemanticAnalyzeFail;
}
}
if (buf_len(&libc->include_dir) == 0) {
if (verbose) {
fprintf(stderr, "include_dir may not be empty\n");
}
return ErrorSemanticAnalyzeFail;
}
if (buf_len(&libc->sys_include_dir) == 0) {
if (verbose) {
fprintf(stderr, "sys_include_dir may not be empty\n");
}
return ErrorSemanticAnalyzeFail;
}
if (buf_len(&libc->crt_dir) == 0) {
if (!target_is_darwin(target)) {
if (verbose) {
fprintf(stderr, "crt_dir may not be empty for %s\n", target_os_name(target->os));
}
return ErrorSemanticAnalyzeFail;
}
}
if (buf_len(&libc->lib_dir) == 0) {
if (!target_is_darwin(target) && target->os != OsWindows) {
if (verbose) {
fprintf(stderr, "lib_dir may not be empty for %s\n", target_os_name(target->os));
}
return ErrorSemanticAnalyzeFail;
}
}
if (buf_len(&libc->static_lib_dir) == 0) {
if (!target_is_darwin(target) && target->os != OsWindows) {
if (verbose) {
fprintf(stderr, "static_lib_dir may not be empty for %s\n", target_os_name(target->os));
}
return ErrorSemanticAnalyzeFail;
}
}
if (buf_len(&libc->msvc_lib_dir) == 0) {
if (target->os == OsWindows) {
if (verbose) {
fprintf(stderr, "msvc_lib_dir may not be empty for %s\n", target_os_name(target->os));
}
return ErrorSemanticAnalyzeFail;
}
}
if (buf_len(&libc->kernel32_lib_dir) == 0) {
if (target->os == OsWindows) {
if (verbose) {
fprintf(stderr, "kernel32_lib_dir may not be empty for %s\n", target_os_name(target->os));
}
return ErrorSemanticAnalyzeFail;
}
}
if (buf_len(&libc->dynamic_linker_path) == 0) {
if (!target_is_darwin(target) && target->os != OsWindows) {
if (verbose) {
fprintf(stderr, "dynamic_linker_path may not be empty for %s\n", target_os_name(target->os));
}
return ErrorSemanticAnalyzeFail;
}
}
return ErrorNone;
}
#if defined(ZIG_OS_WINDOWS)
static Error zig_libc_find_native_include_dir_windows(ZigLibCInstallation *self, ZigWindowsSDK *sdk, bool verbose) {
Error err;
if ((err = os_get_win32_ucrt_include_path(sdk, &self->include_dir))) {
if (verbose) {
fprintf(stderr, "Unable to determine libc include path: %s\n", err_str(err));
}
return err;
}
return ErrorNone;
}
static Error zig_libc_find_crt_dir_windows(ZigLibCInstallation *self, ZigWindowsSDK *sdk, ZigTarget *target,
bool verbose)
{
Error err;
if ((err = os_get_win32_ucrt_lib_path(sdk, &self->crt_dir, target->arch))) {
if (verbose) {
fprintf(stderr, "Unable to determine ucrt path: %s\n", err_str(err));
}
return err;
}
return ErrorNone;
}
static Error zig_libc_find_kernel32_lib_dir(ZigLibCInstallation *self, ZigWindowsSDK *sdk, ZigTarget *target,
bool verbose)
{
Error err;
if ((err = os_get_win32_kern32_path(sdk, &self->kernel32_lib_dir, target->arch))) {
if (verbose) {
fprintf(stderr, "Unable to determine kernel32 path: %s\n", err_str(err));
}
return err;
}
return ErrorNone;
}
static Error zig_libc_find_native_msvc_lib_dir(ZigLibCInstallation *self, ZigWindowsSDK *sdk, bool verbose) {
if (sdk->msvc_lib_dir_ptr == nullptr) {
if (verbose) {
fprintf(stderr, "Unable to determine vcruntime.lib path\n");
}
return ErrorFileNotFound;
}
buf_init_from_mem(&self->msvc_lib_dir, sdk->msvc_lib_dir_ptr, sdk->msvc_lib_dir_len);
return ErrorNone;
}
static Error zig_libc_find_native_msvc_include_dir(ZigLibCInstallation *self, ZigWindowsSDK *sdk, bool verbose) {
Error err;
if (sdk->msvc_lib_dir_ptr == nullptr) {
if (verbose) {
fprintf(stderr, "Unable to determine vcruntime.h path\n");
}
return ErrorFileNotFound;
}
Buf search_path = BUF_INIT;
buf_init_from_mem(&search_path, sdk->msvc_lib_dir_ptr, sdk->msvc_lib_dir_len);
buf_append_str(&search_path, "\\..\\..\\include");
Buf *vcruntime_path = buf_sprintf("%s\\vcruntime.h", buf_ptr(&search_path));
bool exists;
if ((err = os_file_exists(vcruntime_path, &exists))) {
exists = false;
}
if (exists) {
self->sys_include_dir = search_path;
return ErrorNone;
}
if (verbose) {
fprintf(stderr, "Unable to determine vcruntime.h path\n");
}
return ErrorFileNotFound;
}
#else
static Error zig_libc_find_native_include_dir_posix(ZigLibCInstallation *self, bool verbose) {
const char *cc_exe = getenv("CC");
cc_exe = (cc_exe == nullptr) ? "cc" : cc_exe;
ZigList<const char *> args = {};
args.append("-E");
args.append("-Wp,-v");
args.append("-xc");
args.append("/dev/null");
Termination term;
Buf *out_stderr = buf_alloc();
Buf *out_stdout = buf_alloc();
Error err;
if ((err = os_exec_process(cc_exe, args, &term, out_stderr, out_stdout))) {
if (verbose) {
fprintf(stderr, "unable to determine libc include path: executing '%s': %s\n", cc_exe, err_str(err));
}
return err;
}
if (term.how != TerminationIdClean || term.code != 0) {
if (verbose) {
fprintf(stderr, "unable to determine libc include path: executing '%s' failed\n", cc_exe);
}
return ErrorCCompileErrors;
}
char *prev_newline = buf_ptr(out_stderr);
ZigList<const char *> search_paths = {};
for (;;) {
char *newline = strchr(prev_newline, '\n');
if (newline == nullptr) {
break;
}
*newline = 0;
if (prev_newline[0] == ' ') {
search_paths.append(prev_newline);
}
prev_newline = newline + 1;
}
if (search_paths.length == 0) {
if (verbose) {
fprintf(stderr, "unable to determine libc include path: '%s' cannot find libc headers\n", cc_exe);
}
return ErrorCCompileErrors;
}
for (size_t i = 0; i < search_paths.length; i += 1) {
// search in reverse order
const char *search_path = search_paths.items[search_paths.length - i - 1];
// cut off spaces
while (*search_path == ' ') {
search_path += 1;
}
if (buf_len(&self->include_dir) == 0) {
Buf *stdlib_path = buf_sprintf("%s/stdlib.h", search_path);
bool exists;
if ((err = os_file_exists(stdlib_path, &exists))) {
exists = false;
}
if (exists) {
buf_init_from_str(&self->include_dir, search_path);
}
}
if (buf_len(&self->sys_include_dir) == 0) {
Buf *stdlib_path = buf_sprintf("%s/sys/errno.h", search_path);
bool exists;
if ((err = os_file_exists(stdlib_path, &exists))) {
exists = false;
}
if (exists) {
buf_init_from_str(&self->sys_include_dir, search_path);
}
}
if (buf_len(&self->include_dir) != 0 && buf_len(&self->sys_include_dir) != 0) {
return ErrorNone;
}
}
if (verbose) {
if (buf_len(&self->include_dir) == 0) {
fprintf(stderr, "unable to determine libc include path: stdlib.h not found in '%s' search paths\n", cc_exe);
}
if (buf_len(&self->sys_include_dir) == 0) {
fprintf(stderr, "unable to determine libc include path: sys/errno.h not found in '%s' search paths\n", cc_exe);
}
}
return ErrorFileNotFound;
}
#if !defined(ZIG_OS_DARWIN) && !defined(ZIG_OS_FREEBSD) && !defined(ZIG_OS_NETBSD)
static Error zig_libc_cc_print_file_name(const char *o_file, Buf *out, bool want_dirname, bool verbose) {
const char *cc_exe = getenv("CC");
cc_exe = (cc_exe == nullptr) ? "cc" : cc_exe;
ZigList<const char *> args = {};
args.append(buf_ptr(buf_sprintf("-print-file-name=%s", o_file)));
Termination term;
Buf *out_stderr = buf_alloc();
Buf *out_stdout = buf_alloc();
Error err;
if ((err = os_exec_process(cc_exe, args, &term, out_stderr, out_stdout))) {
if (verbose) {
fprintf(stderr, "unable to determine libc include path: executing '%s': %s\n", cc_exe, err_str(err));
}
return err;
}
if (term.how != TerminationIdClean || term.code != 0) {
if (verbose) {
fprintf(stderr, "unable to determine libc include path: executing '%s' failed\n", cc_exe);
}
return ErrorCCompileErrors;
}
if (buf_ends_with_str(out_stdout, "\n")) {
buf_resize(out_stdout, buf_len(out_stdout) - 1);
}
if (buf_len(out_stdout) == 0 || buf_eql_str(out_stdout, o_file)) {
return ErrorCCompilerCannotFindFile;
}
if (want_dirname) {
os_path_dirname(out_stdout, out);
} else {
buf_init_from_buf(out, out_stdout);
}
return ErrorNone;
}
static Error zig_libc_find_native_crt_dir_posix(ZigLibCInstallation *self, bool verbose) {
return zig_libc_cc_print_file_name("crt1.o", &self->crt_dir, true, verbose);
}
static Error zig_libc_find_native_lib_dir_posix(ZigLibCInstallation *self, bool verbose) {
return zig_libc_cc_print_file_name("libgcc_s.so", &self->lib_dir, true, verbose);
}
static Error zig_libc_find_native_static_lib_dir_posix(ZigLibCInstallation *self, bool verbose) {
return zig_libc_cc_print_file_name("crtbegin.o", &self->static_lib_dir, true, verbose);
}
#endif
static Error zig_libc_find_native_dynamic_linker_posix(ZigLibCInstallation *self, bool verbose) {
#if defined(ZIG_OS_LINUX)
Error err;
static const char *dyn_tests[] = {
"ld-linux-x86-64.so.2",
"ld-musl-x86_64.so.1",
};
for (size_t i = 0; i < array_length(dyn_tests); i += 1) {
const char *lib_name = dyn_tests[i];
if ((err = zig_libc_cc_print_file_name(lib_name, &self->dynamic_linker_path, false, true))) {
if (err != ErrorCCompilerCannotFindFile)
return err;
continue;
}
return ErrorNone;
}
#endif
ZigTarget native_target;
get_native_target(&native_target);
const char *dynamic_linker_path = target_dynamic_linker(&native_target);
if (dynamic_linker_path != nullptr) {
buf_init_from_str(&self->dynamic_linker_path, dynamic_linker_path);
}
return ErrorNone;
}
#endif
void zig_libc_render(ZigLibCInstallation *self, FILE *file) {
fprintf(file,
"# The directory that contains `stdlib.h`.\n"
"# On POSIX, include directories be found with: `cc -E -Wp,-v -xc /dev/null`\n"
"include_dir=%s\n"
"# The system-specific include directory. May be the same as `include_dir`.\n"
"# On Windows it's the directory that includes `vcruntime.h`.\n"
"# On POSIX it's the directory that includes `sys/errno.h`.\n"
"sys_include_dir=%s\n"
"\n"
"# The directory that contains `crt1.o`.\n"
"# On POSIX, can be found with `cc -print-file-name=crt1.o`.\n"
"# Not needed when targeting MacOS.\n"
"crt_dir=%s\n"
"\n"
"# The directory that contains `libgcc_s.so`.\n"
"# On POSIX, can be found with `cc -print-file-name=libgcc_s.so`.\n"
"# Not needed when targeting MacOS or Windows.\n"
"lib_dir=%s\n"
"\n"
"# The directory that contains `crtbegin.o`.\n"
"# On POSIX, can be found with `cc -print-file-name=crtbegin.o`.\n"
"# Not needed when targeting MacOS or Windows.\n"
"static_lib_dir=%s\n"
"\n"
"# The directory that contains `vcruntime.lib`.\n"
"# Only needed when targeting Windows.\n"
"msvc_lib_dir=%s\n"
"\n"
"# The directory that contains `kernel32.lib`.\n"
"# Only needed when targeting Windows.\n"
"kernel32_lib_dir=%s\n"
"\n"
"# The full path to the dynamic linker, on the target system.\n"
"# Not needed when targeting MacOS or Windows.\n"
"dynamic_linker_path=%s\n"
"\n"
,
buf_ptr(&self->include_dir),
buf_ptr(&self->sys_include_dir),
buf_ptr(&self->crt_dir),
buf_ptr(&self->lib_dir),
buf_ptr(&self->static_lib_dir),
buf_ptr(&self->msvc_lib_dir),
buf_ptr(&self->kernel32_lib_dir),
buf_ptr(&self->dynamic_linker_path)
);
}
Error zig_libc_find_native(ZigLibCInstallation *self, bool verbose) {
Error err;
zig_libc_init_empty(self);
#if defined(ZIG_OS_WINDOWS)
ZigTarget native_target;
get_native_target(&native_target);
ZigWindowsSDK *sdk;
switch (zig_find_windows_sdk(&sdk)) {
case ZigFindWindowsSdkErrorNone:
if ((err = zig_libc_find_native_msvc_include_dir(self, sdk, verbose)))
return err;
if ((err = zig_libc_find_native_msvc_lib_dir(self, sdk, verbose)))
return err;
if ((err = zig_libc_find_kernel32_lib_dir(self, sdk, &native_target, verbose)))
return err;
if ((err = zig_libc_find_native_include_dir_windows(self, sdk, verbose)))
return err;
if ((err = zig_libc_find_crt_dir_windows(self, sdk, &native_target, verbose)))
return err;
return ErrorNone;
case ZigFindWindowsSdkErrorOutOfMemory:
return ErrorNoMem;
case ZigFindWindowsSdkErrorNotFound:
return ErrorFileNotFound;
case ZigFindWindowsSdkErrorPathTooLong:
return ErrorPathTooLong;
}
zig_unreachable();
#else
if ((err = zig_libc_find_native_include_dir_posix(self, verbose)))
return err;
#if defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD)
buf_init_from_str(&self->crt_dir, "/usr/lib");
buf_init_from_str(&self->lib_dir, "/usr/lib");
buf_init_from_str(&self->static_lib_dir, "/usr/lib");
#elif !defined(ZIG_OS_DARWIN)
if ((err = zig_libc_find_native_crt_dir_posix(self, verbose)))
return err;
if ((err = zig_libc_find_native_lib_dir_posix(self, verbose)))
return err;
if ((err = zig_libc_find_native_static_lib_dir_posix(self, verbose)))
return err;
#endif
if ((err = zig_libc_find_native_dynamic_linker_posix(self, verbose)))
return err;
return ErrorNone;
#endif
}

35
src/libc_installation.hpp Normal file
View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2019 Andrew Kelley
*
* This file is part of zig, which is MIT licensed.
* See http://opensource.org/licenses/MIT
*/
#ifndef ZIG_LIBC_INSTALLATION_HPP
#define ZIG_LIBC_INSTALLATION_HPP
#include <stdio.h>
#include "buffer.hpp"
#include "error.hpp"
#include "target.hpp"
// Must be synchronized with zig_libc_keys
struct ZigLibCInstallation {
Buf include_dir;
Buf sys_include_dir;
Buf crt_dir;
Buf lib_dir;
Buf static_lib_dir;
Buf msvc_lib_dir;
Buf kernel32_lib_dir;
Buf dynamic_linker_path;
};
Error ATTRIBUTE_MUST_USE zig_libc_parse(ZigLibCInstallation *libc, Buf *libc_file,
const ZigTarget *target, bool verbose);
void zig_libc_render(ZigLibCInstallation *self, FILE *file);
Error ATTRIBUTE_MUST_USE zig_libc_find_native(ZigLibCInstallation *self, bool verbose);
#endif

View File

@ -17,32 +17,33 @@ struct LinkJob {
HashMap<Buf *, bool, buf_hash, buf_eql_buf> rpath_table; HashMap<Buf *, bool, buf_hash, buf_eql_buf> rpath_table;
}; };
static const char *get_libc_file(CodeGen *g, const char *file) { static const char *get_libc_crt_file(CodeGen *g, const char *file) {
assert(g->libc != nullptr);
Buf *out_buf = buf_alloc(); Buf *out_buf = buf_alloc();
os_path_join(g->libc_lib_dir, buf_create_from_str(file), out_buf); os_path_join(&g->libc->crt_dir, buf_create_from_str(file), out_buf);
return buf_ptr(out_buf); return buf_ptr(out_buf);
} }
static const char *get_libc_static_file(CodeGen *g, const char *file) { static const char *get_libc_static_file(CodeGen *g, const char *file) {
assert(g->libc != nullptr);
Buf *out_buf = buf_alloc(); Buf *out_buf = buf_alloc();
os_path_join(g->libc_static_lib_dir, buf_create_from_str(file), out_buf); os_path_join(&g->libc->static_lib_dir, buf_create_from_str(file), out_buf);
return buf_ptr(out_buf); return buf_ptr(out_buf);
} }
static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path) { static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path) {
ZigTarget *child_target = parent_gen->is_native_target ? nullptr : &parent_gen->zig_target;
// The Mach-O LLD code is not well maintained, and trips an assertion // The Mach-O LLD code is not well maintained, and trips an assertion
// when we link compiler_rt and builtin as libraries rather than objects. // when we link compiler_rt and builtin as libraries rather than objects.
// Here we workaround this by having compiler_rt and builtin be objects. // Here we workaround this by having compiler_rt and builtin be objects.
// TODO write our own linker. https://github.com/ziglang/zig/issues/1535 // TODO write our own linker. https://github.com/ziglang/zig/issues/1535
OutType child_out_type = OutTypeLib; OutType child_out_type = OutTypeLib;
if (parent_gen->zig_target.os == OsMacOSX) { if (parent_gen->zig_target->os == OsMacOSX) {
child_out_type = OutTypeObj; child_out_type = OutTypeObj;
} }
CodeGen *child_gen = codegen_create(full_path, child_target, child_out_type, CodeGen *child_gen = codegen_create(full_path, parent_gen->zig_target, child_out_type,
parent_gen->build_mode, parent_gen->zig_lib_dir, parent_gen->zig_std_dir); parent_gen->build_mode, parent_gen->zig_lib_dir, parent_gen->zig_std_dir,
parent_gen->libc);
child_gen->out_h_path = nullptr; child_gen->out_h_path = nullptr;
child_gen->verbose_tokenize = parent_gen->verbose_tokenize; child_gen->verbose_tokenize = parent_gen->verbose_tokenize;
@ -55,6 +56,7 @@ static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path)
codegen_set_strip(child_gen, parent_gen->strip_debug_symbols); codegen_set_strip(child_gen, parent_gen->strip_debug_symbols);
codegen_set_is_static(child_gen, true); codegen_set_is_static(child_gen, true);
child_gen->disable_pic = parent_gen->disable_pic; child_gen->disable_pic = parent_gen->disable_pic;
child_gen->valgrind_support = ValgrindSupportDisabled;
codegen_set_out_name(child_gen, buf_create_from_str(aname)); codegen_set_out_name(child_gen, buf_create_from_str(aname));
@ -94,7 +96,7 @@ static Buf *build_compiler_rt(CodeGen *parent_gen) {
} }
static const char *get_darwin_arch_string(const ZigTarget *t) { static const char *get_darwin_arch_string(const ZigTarget *t) {
switch (t->arch.arch) { switch (t->arch) {
case ZigLLVM_aarch64: case ZigLLVM_aarch64:
return "arm64"; return "arm64";
case ZigLLVM_thumb: case ZigLLVM_thumb:
@ -107,13 +109,13 @@ static const char *get_darwin_arch_string(const ZigTarget *t) {
case ZigLLVM_ppc64le: case ZigLLVM_ppc64le:
return "ppc64le"; return "ppc64le";
default: default:
return ZigLLVMGetArchTypeName(t->arch.arch); return ZigLLVMGetArchTypeName(t->arch);
} }
} }
static const char *getLDMOption(const ZigTarget *t) { static const char *getLDMOption(const ZigTarget *t) {
switch (t->arch.arch) { switch (t->arch) {
case ZigLLVM_x86: case ZigLLVM_x86:
return "elf_i386"; return "elf_i386";
case ZigLLVM_aarch64: case ZigLLVM_aarch64:
@ -147,7 +149,7 @@ static const char *getLDMOption(const ZigTarget *t) {
case ZigLLVM_systemz: case ZigLLVM_systemz:
return "elf64_s390"; return "elf64_s390";
case ZigLLVM_x86_64: case ZigLLVM_x86_64:
if (t->env_type == ZigLLVM_GNUX32) { if (t->abi == ZigLLVM_GNUX32) {
return "elf32_x86_64"; return "elf32_x86_64";
} }
// Any target elf will use the freebsd osabi if suffixed with "_fbsd". // Any target elf will use the freebsd osabi if suffixed with "_fbsd".
@ -170,78 +172,27 @@ static void add_rpath(LinkJob *lj, Buf *rpath) {
lj->rpath_table.put(rpath, true); lj->rpath_table.put(rpath, true);
} }
static Buf *try_dynamic_linker_path(const char *ld_name) {
const char *cc_exe = getenv("CC");
cc_exe = (cc_exe == nullptr) ? "cc" : cc_exe;
ZigList<const char *> args = {};
args.append(buf_ptr(buf_sprintf("-print-file-name=%s", ld_name)));
Termination term;
Buf *out_stderr = buf_alloc();
Buf *out_stdout = buf_alloc();
int err;
if ((err = os_exec_process(cc_exe, args, &term, out_stderr, out_stdout))) {
return nullptr;
}
if (term.how != TerminationIdClean || term.code != 0) {
return nullptr;
}
if (buf_ends_with_str(out_stdout, "\n")) {
buf_resize(out_stdout, buf_len(out_stdout) - 1);
}
if (buf_len(out_stdout) == 0 || buf_eql_str(out_stdout, ld_name)) {
return nullptr;
}
return out_stdout;
}
static Buf *get_dynamic_linker_path(CodeGen *g) {
if (g->zig_target.os == OsFreeBSD) {
return buf_create_from_str("/libexec/ld-elf.so.1");
}
if (g->is_native_target && g->zig_target.arch.arch == ZigLLVM_x86_64) {
static const char *ld_names[] = {
"ld-linux-x86-64.so.2",
"ld-musl-x86_64.so.1",
};
for (size_t i = 0; i < array_length(ld_names); i += 1) {
const char *ld_name = ld_names[i];
Buf *result = try_dynamic_linker_path(ld_name);
if (result != nullptr) {
return result;
}
}
}
return target_dynamic_linker(&g->zig_target);
}
static void construct_linker_job_elf(LinkJob *lj) { static void construct_linker_job_elf(LinkJob *lj) {
CodeGen *g = lj->codegen; CodeGen *g = lj->codegen;
lj->args.append("-error-limit=0"); lj->args.append("-error-limit=0");
if (g->libc_link_lib != nullptr) {
find_libc_lib_path(g);
}
if (g->linker_script) { if (g->linker_script) {
lj->args.append("-T"); lj->args.append("-T");
lj->args.append(g->linker_script); lj->args.append(g->linker_script);
} }
if (g->no_rosegment_workaround) {
lj->args.append("--no-rosegment");
}
lj->args.append("--gc-sections"); lj->args.append("--gc-sections");
lj->args.append("-m"); lj->args.append("-m");
lj->args.append(getLDMOption(&g->zig_target)); lj->args.append(getLDMOption(g->zig_target));
bool is_lib = g->out_type == OutTypeLib; bool is_lib = g->out_type == OutTypeLib;
bool shared = !g->is_static && is_lib; bool shared = !g->is_static && is_lib;
Buf *soname = nullptr; Buf *soname = nullptr;
if (g->is_static) { if (g->is_static) {
if (g->zig_target.arch.arch == ZigLLVM_arm || g->zig_target.arch.arch == ZigLLVM_armeb || if (g->zig_target->arch == ZigLLVM_arm || g->zig_target->arch == ZigLLVM_armeb ||
g->zig_target.arch.arch == ZigLLVM_thumb || g->zig_target.arch.arch == ZigLLVM_thumbeb) g->zig_target->arch == ZigLLVM_thumb || g->zig_target->arch == ZigLLVM_thumbeb)
{ {
lj->args.append("-Bstatic"); lj->args.append("-Bstatic");
} else { } else {
@ -263,15 +214,18 @@ static void construct_linker_job_elf(LinkJob *lj) {
if (lj->link_in_crt) { if (lj->link_in_crt) {
const char *crt1o; const char *crt1o;
const char *crtbegino; const char *crtbegino;
if (g->is_static) { if (g->zig_target->os == OsNetBSD) {
crt1o = "crt0.o";
crtbegino = "crtbegin.o";
} else if (g->is_static) {
crt1o = "crt1.o"; crt1o = "crt1.o";
crtbegino = "crtbeginT.o"; crtbegino = "crtbeginT.o";
} else { } else {
crt1o = "Scrt1.o"; crt1o = "Scrt1.o";
crtbegino = "crtbegin.o"; crtbegino = "crtbegin.o";
} }
lj->args.append(get_libc_file(g, crt1o)); lj->args.append(get_libc_crt_file(g, crt1o));
lj->args.append(get_libc_file(g, "crti.o")); lj->args.append(get_libc_crt_file(g, "crti.o"));
lj->args.append(get_libc_static_file(g, crtbegino)); lj->args.append(get_libc_static_file(g, crtbegino));
} }
@ -307,23 +261,24 @@ static void construct_linker_job_elf(LinkJob *lj) {
} }
if (g->libc_link_lib != nullptr) { if (g->libc_link_lib != nullptr) {
assert(g->libc != nullptr);
lj->args.append("-L"); lj->args.append("-L");
lj->args.append(buf_ptr(g->libc_lib_dir)); lj->args.append(buf_ptr(&g->libc->crt_dir));
if (!buf_eql_buf(&g->libc->crt_dir, &g->libc->lib_dir)) {
lj->args.append("-L");
lj->args.append(buf_ptr(&g->libc->lib_dir));
}
lj->args.append("-L"); lj->args.append("-L");
lj->args.append(buf_ptr(g->libc_static_lib_dir)); lj->args.append(buf_ptr(&g->libc->static_lib_dir));
}
if (!g->is_static) { if (!g->is_static) {
if (g->dynamic_linker != nullptr) { assert(buf_len(&g->libc->dynamic_linker_path) != 0);
assert(buf_len(g->dynamic_linker) != 0);
lj->args.append("-dynamic-linker"); lj->args.append("-dynamic-linker");
lj->args.append(buf_ptr(g->dynamic_linker)); lj->args.append(buf_ptr(&g->libc->dynamic_linker_path));
} else {
Buf *resolved_dynamic_linker = get_dynamic_linker_path(g);
lj->args.append("-dynamic-linker");
lj->args.append(buf_ptr(resolved_dynamic_linker));
} }
} }
if (shared) { if (shared) {
@ -390,14 +345,14 @@ static void construct_linker_job_elf(LinkJob *lj) {
// crt end // crt end
if (lj->link_in_crt) { if (lj->link_in_crt) {
lj->args.append(get_libc_static_file(g, "crtend.o")); lj->args.append(get_libc_static_file(g, "crtend.o"));
lj->args.append(get_libc_file(g, "crtn.o")); lj->args.append(get_libc_crt_file(g, "crtn.o"));
} }
if (!g->is_native_target) { if (!g->zig_target->is_native) {
lj->args.append("--allow-shlib-undefined"); lj->args.append("--allow-shlib-undefined");
} }
if (g->zig_target.os == OsZen) { if (g->zig_target->os == OsZen) {
lj->args.append("-e"); lj->args.append("-e");
lj->args.append("_start"); lj->args.append("_start");
@ -420,16 +375,16 @@ static void construct_linker_job_wasm(LinkJob *lj) {
} }
//static bool is_target_cyg_mingw(const ZigTarget *target) { //static bool is_target_cyg_mingw(const ZigTarget *target) {
// return (target->os == ZigLLVM_Win32 && target->env_type == ZigLLVM_Cygnus) || // return (target->os == ZigLLVM_Win32 && target->abi == ZigLLVM_Cygnus) ||
// (target->os == ZigLLVM_Win32 && target->env_type == ZigLLVM_GNU); // (target->os == ZigLLVM_Win32 && target->abi == ZigLLVM_GNU);
//} //}
static void coff_append_machine_arg(CodeGen *g, ZigList<const char *> *list) { static void coff_append_machine_arg(CodeGen *g, ZigList<const char *> *list) {
if (g->zig_target.arch.arch == ZigLLVM_x86) { if (g->zig_target->arch == ZigLLVM_x86) {
list->append("-MACHINE:X86"); list->append("-MACHINE:X86");
} else if (g->zig_target.arch.arch == ZigLLVM_x86_64) { } else if (g->zig_target->arch == ZigLLVM_x86_64) {
list->append("-MACHINE:X64"); list->append("-MACHINE:X64");
} else if (g->zig_target.arch.arch == ZigLLVM_arm) { } else if (g->zig_target->arch == ZigLLVM_arm) {
list->append("-MACHINE:ARM"); list->append("-MACHINE:ARM");
} }
} }
@ -515,7 +470,7 @@ static void add_nt_link_args(LinkJob *lj, bool is_library) {
// lj->args.append("-Bdynamic"); // lj->args.append("-Bdynamic");
// if (dll || shared) { // if (dll || shared) {
// lj->args.append("-e"); // lj->args.append("-e");
// if (g->zig_target.arch.arch == ZigLLVM_x86) { // if (g->zig_target.arch == ZigLLVM_x86) {
// lj->args.append("_DllMainCRTStartup@12"); // lj->args.append("_DllMainCRTStartup@12");
// } else { // } else {
// lj->args.append("DllMainCRTStartup"); // lj->args.append("DllMainCRTStartup");
@ -541,7 +496,7 @@ static void add_nt_link_args(LinkJob *lj, bool is_library) {
//lj->args.append("-lmingw32"); //lj->args.append("-lmingw32");
//lj->args.append("-lgcc"); //lj->args.append("-lgcc");
//bool is_android = (g->zig_target.env_type == ZigLLVM_Android); //bool is_android = (g->zig_target.abi == ZigLLVM_Android);
//bool is_cyg_ming = is_target_cyg_mingw(&g->zig_target); //bool is_cyg_ming = is_target_cyg_mingw(&g->zig_target);
//if (!g->is_static && !is_android) { //if (!g->is_static && !is_android) {
// if (!is_cyg_ming) { // if (!is_cyg_ming) {
@ -588,10 +543,6 @@ static void construct_linker_job_coff(LinkJob *lj) {
lj->args.append("/ERRORLIMIT:0"); lj->args.append("/ERRORLIMIT:0");
if (g->libc_link_lib != nullptr) {
find_libc_lib_path(g);
}
lj->args.append("/NOLOGO"); lj->args.append("/NOLOGO");
if (!g->strip_debug_symbols) { if (!g->strip_debug_symbols) {
@ -608,6 +559,11 @@ static void construct_linker_job_coff(LinkJob *lj) {
bool is_library = g->out_type == OutTypeLib; bool is_library = g->out_type == OutTypeLib;
switch (g->subsystem) { switch (g->subsystem) {
case TargetSubsystemAuto: case TargetSubsystemAuto:
if (g->zig_target->os == OsUefi) {
add_uefi_link_args(lj);
} else {
add_nt_link_args(lj, is_library);
}
break; break;
case TargetSubsystemConsole: case TargetSubsystemConsole:
lj->args.append("/SUBSYSTEM:console"); lj->args.append("/SUBSYSTEM:console");
@ -646,13 +602,11 @@ static void construct_linker_job_coff(LinkJob *lj) {
lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->output_file_path)))); lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->output_file_path))));
if (g->libc_link_lib != nullptr) { if (g->libc_link_lib != nullptr) {
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->msvc_lib_dir)))); assert(g->libc != nullptr);
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->kernel32_lib_dir))));
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_lib_dir)))); lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->msvc_lib_dir))));
if (g->libc_static_lib_dir != nullptr) { lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->kernel32_lib_dir))));
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_static_lib_dir)))); lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->crt_dir))));
}
} }
if (is_library && !g->is_static) { if (is_library && !g->is_static) {
@ -687,7 +641,7 @@ static void construct_linker_job_coff(LinkJob *lj) {
continue; continue;
} }
if (link_lib->provided_explicitly) { if (link_lib->provided_explicitly) {
if (lj->codegen->zig_target.env_type == ZigLLVM_GNU) { if (lj->codegen->zig_target->abi == ZigLLVM_GNU) {
Buf *arg = buf_sprintf("-l%s", buf_ptr(link_lib->name)); Buf *arg = buf_sprintf("-l%s", buf_ptr(link_lib->name));
lj->args.append(buf_ptr(arg)); lj->args.append(buf_ptr(arg));
} }
@ -717,7 +671,8 @@ static void construct_linker_job_coff(LinkJob *lj) {
gen_lib_args.append(buf_ptr(buf_sprintf("-DEF:%s", buf_ptr(def_path)))); gen_lib_args.append(buf_ptr(buf_sprintf("-DEF:%s", buf_ptr(def_path))));
gen_lib_args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(generated_lib_path)))); gen_lib_args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(generated_lib_path))));
Buf diag = BUF_INIT; Buf diag = BUF_INIT;
if (!zig_lld_link(g->zig_target.oformat, gen_lib_args.items, gen_lib_args.length, &diag)) { ZigLLVM_ObjectFormatType target_ofmt = target_object_format(g->zig_target);
if (!zig_lld_link(target_ofmt, gen_lib_args.items, gen_lib_args.length, &diag)) {
fprintf(stderr, "%s\n", buf_ptr(&diag)); fprintf(stderr, "%s\n", buf_ptr(&diag));
exit(1); exit(1);
} }
@ -786,7 +741,7 @@ static void get_darwin_platform(LinkJob *lj, DarwinPlatform *platform) {
platform->kind = MacOS; platform->kind = MacOS;
} else if (g->mios_version_min) { } else if (g->mios_version_min) {
platform->kind = IPhoneOS; platform->kind = IPhoneOS;
} else if (g->zig_target.os == OsMacOSX) { } else if (g->zig_target->os == OsMacOSX) {
platform->kind = MacOS; platform->kind = MacOS;
g->mmacosx_version_min = buf_create_from_str("10.10"); g->mmacosx_version_min = buf_create_from_str("10.10");
} else { } else {
@ -813,8 +768,8 @@ static void get_darwin_platform(LinkJob *lj, DarwinPlatform *platform) {
} }
if (platform->kind == IPhoneOS && if (platform->kind == IPhoneOS &&
(g->zig_target.arch.arch == ZigLLVM_x86 || (g->zig_target->arch == ZigLLVM_x86 ||
g->zig_target.arch.arch == ZigLLVM_x86_64)) g->zig_target->arch == ZigLLVM_x86_64))
{ {
platform->kind = IPhoneOSSimulator; platform->kind = IPhoneOSSimulator;
} }
@ -878,7 +833,7 @@ static void construct_linker_job_macho(LinkJob *lj) {
} }
lj->args.append("-arch"); lj->args.append("-arch");
lj->args.append(get_darwin_arch_string(&g->zig_target)); lj->args.append(get_darwin_arch_string(g->zig_target));
DarwinPlatform platform; DarwinPlatform platform;
get_darwin_platform(lj, &platform); get_darwin_platform(lj, &platform);
@ -893,7 +848,11 @@ static void construct_linker_job_macho(LinkJob *lj) {
lj->args.append("-ios_simulator_version_min"); lj->args.append("-ios_simulator_version_min");
break; break;
} }
lj->args.append(buf_ptr(buf_sprintf("%d.%d.%d", platform.major, platform.minor, platform.micro))); Buf *version_string = buf_sprintf("%d.%d.%d", platform.major, platform.minor, platform.micro);
lj->args.append(buf_ptr(version_string));
lj->args.append("-sdk_version");
lj->args.append(buf_ptr(version_string));
if (g->out_type == OutTypeExe) { if (g->out_type == OutTypeExe) {
@ -914,7 +873,9 @@ static void construct_linker_job_macho(LinkJob *lj) {
add_rpath(lj, &g->output_file_path); add_rpath(lj, &g->output_file_path);
if (shared) { if (shared) {
if (g->system_linker_hack) {
lj->args.append("-headerpad_max_install_names"); lj->args.append("-headerpad_max_install_names");
}
} else if (g->is_static) { } else if (g->is_static) {
lj->args.append("-lcrt0.o"); lj->args.append("-lcrt0.o");
} else { } else {
@ -929,7 +890,7 @@ static void construct_linker_job_macho(LinkJob *lj) {
} }
break; break;
case IPhoneOS: case IPhoneOS:
if (g->zig_target.arch.arch == ZigLLVM_aarch64) { if (g->zig_target->arch == ZigLLVM_aarch64) {
// iOS does not need any crt1 files for arm64 // iOS does not need any crt1 files for arm64
} else if (darwin_version_lt(&platform, 3, 1)) { } else if (darwin_version_lt(&platform, 3, 1)) {
lj->args.append("-lcrt1.o"); lj->args.append("-lcrt1.o");
@ -959,7 +920,7 @@ static void construct_linker_job_macho(LinkJob *lj) {
lj->args.append(buf_ptr(compiler_rt_o_path)); lj->args.append(buf_ptr(compiler_rt_o_path));
} }
if (g->is_native_target) { if (g->zig_target->is_native) {
for (size_t lib_i = 0; lib_i < g->link_libs_list.length; lib_i += 1) { for (size_t lib_i = 0; lib_i < g->link_libs_list.length; lib_i += 1) {
LinkLib *link_lib = g->link_libs_list.at(lib_i); LinkLib *link_lib = g->link_libs_list.at(lib_i);
if (buf_eql_str(link_lib->name, "c")) { if (buf_eql_str(link_lib->name, "c")) {
@ -1000,7 +961,7 @@ static void construct_linker_job_macho(LinkJob *lj) {
} }
static void construct_linker_job(LinkJob *lj) { static void construct_linker_job(LinkJob *lj) {
switch (lj->codegen->zig_target.oformat) { switch (target_object_format(lj->codegen->zig_target)) {
case ZigLLVM_UnknownObjectFormat: case ZigLLVM_UnknownObjectFormat:
zig_unreachable(); zig_unreachable();
@ -1040,7 +1001,7 @@ void codegen_link(CodeGen *g) {
for (size_t i = 0; i < g->link_objects.length; i += 1) { for (size_t i = 0; i < g->link_objects.length; i += 1) {
file_names.append((const char *)buf_ptr(g->link_objects.at(i))); file_names.append((const char *)buf_ptr(g->link_objects.at(i)));
} }
ZigLLVM_OSType os_type = get_llvm_os_type(g->zig_target.os); ZigLLVM_OSType os_type = get_llvm_os_type(g->zig_target->os);
codegen_add_time_event(g, "LLVM Link"); codegen_add_time_event(g, "LLVM Link");
if (ZigLLVMWriteArchive(buf_ptr(&g->output_file_path), file_names.items, file_names.length, os_type)) { if (ZigLLVMWriteArchive(buf_ptr(&g->output_file_path), file_names.items, file_names.length, os_type)) {
fprintf(stderr, "Unable to write archive '%s'\n", buf_ptr(&g->output_file_path)); fprintf(stderr, "Unable to write archive '%s'\n", buf_ptr(&g->output_file_path));
@ -1065,7 +1026,7 @@ void codegen_link(CodeGen *g) {
Buf diag = BUF_INIT; Buf diag = BUF_INIT;
codegen_add_time_event(g, "LLVM Link"); codegen_add_time_event(g, "LLVM Link");
if (g->system_linker_hack && g->zig_target.os == OsMacOSX) { if (g->system_linker_hack && g->zig_target->os == OsMacOSX) {
Termination term; Termination term;
ZigList<const char *> args = {}; ZigList<const char *> args = {};
for (size_t i = 1; i < lj.args.length; i += 1) { for (size_t i = 1; i < lj.args.length; i += 1) {
@ -1075,7 +1036,7 @@ void codegen_link(CodeGen *g) {
if (term.how != TerminationIdClean || term.code != 0) { if (term.how != TerminationIdClean || term.code != 0) {
exit(1); exit(1);
} }
} else if (!zig_lld_link(g->zig_target.oformat, lj.args.items, lj.args.length, &diag)) { } else if (!zig_lld_link(target_object_format(g->zig_target), lj.args.items, lj.args.length, &diag)) {
fprintf(stderr, "%s\n", buf_ptr(&diag)); fprintf(stderr, "%s\n", buf_ptr(&diag));
exit(1); exit(1);
} }

View File

@ -13,16 +13,17 @@
#include "error.hpp" #include "error.hpp"
#include "os.hpp" #include "os.hpp"
#include "target.hpp" #include "target.hpp"
#include "libc_installation.hpp"
#include <stdio.h> #include <stdio.h>
static int print_error_usage(const char *arg0) { static int print_error_usage(const char *arg0) {
fprintf(stderr, "See `%s help` for detailed usage information\n", arg0); fprintf(stderr, "See `%s --help` for detailed usage information\n", arg0);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
static int print_full_usage(const char *arg0) { static int print_full_usage(const char *arg0, FILE *file, int return_code) {
fprintf(stdout, fprintf(file,
"Usage: %s [command] [options]\n" "Usage: %s [command] [options]\n"
"\n" "\n"
"Commands:\n" "Commands:\n"
@ -31,10 +32,12 @@ static int print_full_usage(const char *arg0) {
" build-lib [source] create library from source or object files\n" " build-lib [source] create library from source or object files\n"
" build-obj [source] create object from source or assembly\n" " build-obj [source] create object from source or assembly\n"
" builtin show the source code of that @import(\"builtin\")\n" " builtin show the source code of that @import(\"builtin\")\n"
" help show this usage information\n" " cc C compiler\n"
" fmt parse files and render in canonical zig format\n"
" id print the base64-encoded compiler id\n" " id print the base64-encoded compiler id\n"
" init-exe initialize a `zig build` application in the cwd\n" " init-exe initialize a `zig build` application in the cwd\n"
" init-lib initialize a `zig build` library in the cwd\n" " init-lib initialize a `zig build` library in the cwd\n"
" libc [paths_file] Display native libc paths file or validate one\n"
" run [source] create executable and run immediately\n" " run [source] create executable and run immediately\n"
" translate-c [source] convert c code to zig code\n" " translate-c [source] convert c code to zig code\n"
" targets list available compilation targets\n" " targets list available compilation targets\n"
@ -44,16 +47,20 @@ static int print_full_usage(const char *arg0) {
"\n" "\n"
"Compile Options:\n" "Compile Options:\n"
" --assembly [source] add assembly file to build\n" " --assembly [source] add assembly file to build\n"
" --c-source [options] [file] compile C source code\n"
" --cache-dir [path] override the cache directory\n" " --cache-dir [path] override the cache directory\n"
" --cache [auto|off|on] build in global cache, print out paths to stdout\n" " --cache [auto|off|on] build in global cache, print out paths to stdout\n"
" --color [auto|off|on] enable or disable colored error messages\n" " --color [auto|off|on] enable or disable colored error messages\n"
" --disable-pic disable Position Independent Code for libraries\n" " --disable-pic disable Position Independent Code for libraries\n"
" --disable-valgrind omit valgrind client requests in debug builds\n"
" --enable-valgrind include valgrind client requests release builds\n"
" --emit [asm|bin|llvm-ir] emit a specific file format as compilation output\n" " --emit [asm|bin|llvm-ir] emit a specific file format as compilation output\n"
" -ftime-report print timing diagnostics\n" " -ftime-report print timing diagnostics\n"
" --libc-include-dir [path] directory where libc stdlib.h resides\n" " --libc [file] Provide a file which specifies libc paths\n"
" --name [name] override output name\n" " --name [name] override output name\n"
" --output [file] override destination path\n" " --output [file] override destination path\n"
" --output-h [file] generate header file\n" " --output-h [file] generate header file\n"
" --output-lib [file] override import library path\n"
" --pkg-begin [name] [path] make pkg available to import and push current pkg\n" " --pkg-begin [name] [path] make pkg available to import and push current pkg\n"
" --pkg-end pop current pkg\n" " --pkg-end pop current pkg\n"
" --release-fast build with optimizations on and safety off\n" " --release-fast build with optimizations on and safety off\n"
@ -62,15 +69,14 @@ static int print_full_usage(const char *arg0) {
" --single-threaded source may assume it is only used single-threaded\n" " --single-threaded source may assume it is only used single-threaded\n"
" --static output will be statically linked\n" " --static output will be statically linked\n"
" --strip exclude debug symbols\n" " --strip exclude debug symbols\n"
" --target-arch [name] specify target architecture\n" " -target [name] <arch><sub>-<os>-<abi> see the targets command\n"
" --target-environ [name] specify target environment\n"
" --target-os [name] specify target operating system\n"
" --verbose-tokenize enable compiler debug output for tokenization\n" " --verbose-tokenize enable compiler debug output for tokenization\n"
" --verbose-ast enable compiler debug output for AST parsing\n" " --verbose-ast enable compiler debug output for AST parsing\n"
" --verbose-link enable compiler debug output for linking\n" " --verbose-link enable compiler debug output for linking\n"
" --verbose-ir enable compiler debug output for Zig IR\n" " --verbose-ir enable compiler debug output for Zig IR\n"
" --verbose-llvm-ir enable compiler debug output for LLVM IR\n" " --verbose-llvm-ir enable compiler debug output for LLVM IR\n"
" --verbose-cimport enable compiler debug output for C imports\n" " --verbose-cimport enable compiler debug output for C imports\n"
" --verbose-cc enable compiler debug output for C compilation\n"
" -dirafter [dir] same as -isystem but do it last\n" " -dirafter [dir] same as -isystem but do it last\n"
" -isystem [dir] add additional search path for other .h files\n" " -isystem [dir] add additional search path for other .h files\n"
" -mllvm [arg] forward an arg to LLVM's option processing\n" " -mllvm [arg] forward an arg to LLVM's option processing\n"
@ -79,10 +85,6 @@ static int print_full_usage(const char *arg0) {
"Link Options:\n" "Link Options:\n"
" --dynamic-linker [path] set the path to ld.so\n" " --dynamic-linker [path] set the path to ld.so\n"
" --each-lib-rpath add rpath for each used dynamic library\n" " --each-lib-rpath add rpath for each used dynamic library\n"
" --libc-lib-dir [path] directory where libc crt1.o resides\n"
" --libc-static-lib-dir [path] directory where libc crtbegin.o resides\n"
" --msvc-lib-dir [path] (windows) directory where vcruntime.lib resides\n"
" --kernel32-lib-dir [path] (windows) directory where kernel32.lib resides\n"
" --library [lib] link against lib\n" " --library [lib] link against lib\n"
" --forbid-library [lib] make it an error to link against lib\n" " --forbid-library [lib] make it an error to link against lib\n"
" --library-path [dir] add a directory to the library search path\n" " --library-path [dir] add a directory to the library search path\n"
@ -91,7 +93,6 @@ static int print_full_usage(const char *arg0) {
" -L[dir] alias for --library-path\n" " -L[dir] alias for --library-path\n"
" -rdynamic add all symbols to the dynamic symbol table\n" " -rdynamic add all symbols to the dynamic symbol table\n"
" -rpath [path] add directory to the runtime library search path\n" " -rpath [path] add directory to the runtime library search path\n"
" --no-rosegment compromise security to workaround valgrind bug\n"
" --subsystem [subsystem] (windows) /SUBSYSTEM:<subsystem> to the linker\n" " --subsystem [subsystem] (windows) /SUBSYSTEM:<subsystem> to the linker\n"
" -framework [name] (darwin) link against framework\n" " -framework [name] (darwin) link against framework\n"
" -mios-version-min [ver] (darwin) set iOS deployment target\n" " -mios-version-min [ver] (darwin) set iOS deployment target\n"
@ -106,7 +107,27 @@ static int print_full_usage(const char *arg0) {
" --test-cmd [arg] specify test execution command one arg at a time\n" " --test-cmd [arg] specify test execution command one arg at a time\n"
" --test-cmd-bin appends test binary path to test cmd args\n" " --test-cmd-bin appends test binary path to test cmd args\n"
, arg0); , arg0);
return EXIT_SUCCESS; return return_code;
}
static int print_libc_usage(const char *arg0, FILE *file, int return_code) {
fprintf(file,
"Usage: %s libc\n"
"\n"
"Detect the native libc installation and print the resulting paths to stdout.\n"
"You can save this into a file and then edit the paths to create a cross\n"
"compilation libc kit. Then you can pass `--libc [file]` for Zig to use it.\n"
"\n"
"When compiling natively and no `--libc` argument provided, Zig automatically\n"
"creates zig-cache/native_libc.txt so that it does not have to detect libc\n"
"on every invocation. You can remove this file to have Zig re-detect the\n"
"native libc.\n"
"\n\n"
"Usage: %s libc [file]\n"
"\n"
"Parse a libc installation text file and validate it.\n"
, arg0, arg0);
return return_code;
} }
static const char *ZIG_ZEN = "\n" static const char *ZIG_ZEN = "\n"
@ -122,6 +143,14 @@ static const char *ZIG_ZEN = "\n"
" * Minimize energy spent on coding style.\n" " * Minimize energy spent on coding style.\n"
" * Together we serve end users.\n"; " * Together we serve end users.\n";
static bool arch_available_in_llvm(ZigLLVM_ArchType arch) {
LLVMTargetRef target_ref;
char *err_msg = nullptr;
char triple_string[128];
sprintf(triple_string, "%s-unknown-unknown-unknown", ZigLLVMGetArchTypeName(arch));
return !LLVMGetTargetFromTriple(triple_string, &target_ref, &err_msg);
}
static int print_target_list(FILE *f) { static int print_target_list(FILE *f) {
ZigTarget native; ZigTarget native;
get_native_target(&native); get_native_target(&native);
@ -129,28 +158,36 @@ static int print_target_list(FILE *f) {
fprintf(f, "Architectures:\n"); fprintf(f, "Architectures:\n");
size_t arch_count = target_arch_count(); size_t arch_count = target_arch_count();
for (size_t arch_i = 0; arch_i < arch_count; arch_i += 1) { for (size_t arch_i = 0; arch_i < arch_count; arch_i += 1) {
const ArchType *arch = get_target_arch(arch_i); ZigLLVM_ArchType arch = target_arch_enum(arch_i);
char arch_name[50]; if (!arch_available_in_llvm(arch))
get_arch_name(arch_name, arch); continue;
const char *native_str = (native.arch.arch == arch->arch && native.arch.sub_arch == arch->sub_arch) ? const char *arch_name = target_arch_name(arch);
" (native)" : ""; SubArchList sub_arch_list = target_subarch_list(arch);
fprintf(f, " %s%s\n", arch_name, native_str); size_t sub_count = target_subarch_count(sub_arch_list);
const char *arch_native_str = (native.arch == arch) ? " (native)" : "";
fprintf(stderr, " %s%s\n", arch_name, arch_native_str);
for (size_t sub_i = 0; sub_i < sub_count; sub_i += 1) {
ZigLLVM_SubArchType sub = target_subarch_enum(sub_arch_list, sub_i);
const char *sub_name = target_subarch_name(sub);
const char *sub_native_str = (native.arch == arch && native.sub_arch == sub) ? " (native)" : "";
fprintf(f, " %s%s\n", sub_name, sub_native_str);
}
} }
fprintf(f, "\nOperating Systems:\n"); fprintf(f, "\nOperating Systems:\n");
size_t os_count = target_os_count(); size_t os_count = target_os_count();
for (size_t i = 0; i < os_count; i += 1) { for (size_t i = 0; i < os_count; i += 1) {
Os os_type = get_target_os(i); Os os_type = target_os_enum(i);
const char *native_str = (native.os == os_type) ? " (native)" : ""; const char *native_str = (native.os == os_type) ? " (native)" : "";
fprintf(f, " %s%s\n", get_target_os_name(os_type), native_str); fprintf(f, " %s%s\n", target_os_name(os_type), native_str);
} }
fprintf(f, "\nEnvironments:\n"); fprintf(f, "\nC ABIs:\n");
size_t environ_count = target_environ_count(); size_t abi_count = target_abi_count();
for (size_t i = 0; i < environ_count; i += 1) { for (size_t i = 0; i < abi_count; i += 1) {
ZigLLVM_EnvironmentType environ_type = get_target_environ(i); ZigLLVM_EnvironmentType abi = target_abi_enum(i);
const char *native_str = (native.env_type == environ_type) ? " (native)" : ""; const char *native_str = (native.abi == abi) ? " (native)" : "";
fprintf(f, " %s%s\n", ZigLLVMGetEnvironmentTypeName(environ_type), native_str); fprintf(f, " %s%s\n", target_abi_name(abi), native_str);
} }
return EXIT_SUCCESS; return EXIT_SUCCESS;
@ -160,13 +197,13 @@ enum Cmd {
CmdNone, CmdNone,
CmdBuild, CmdBuild,
CmdBuiltin, CmdBuiltin,
CmdHelp,
CmdRun, CmdRun,
CmdTargets, CmdTargets,
CmdTest, CmdTest,
CmdTranslateC, CmdTranslateC,
CmdVersion, CmdVersion,
CmdZen, CmdZen,
CmdLibC,
}; };
static const char *default_zig_cache_name = "zig-cache"; static const char *default_zig_cache_name = "zig-cache";
@ -219,6 +256,8 @@ static bool get_cache_opt(CacheOpt opt, bool default_value) {
zig_unreachable(); zig_unreachable();
} }
extern "C" int ZigClang_main(int argc, char **argv);
int main(int argc, char **argv) { int main(int argc, char **argv) {
char *arg0 = argv[0]; char *arg0 = argv[0];
Error err; Error err;
@ -236,6 +275,12 @@ int main(int argc, char **argv) {
return 0; return 0;
} }
if (argc >= 2 && (strcmp(argv[1], "cc") == 0 ||
strcmp(argv[1], "-cc1") == 0 || strcmp(argv[1], "-cc1as") == 0))
{
return ZigClang_main(argc, argv);
}
// Must be before all os.hpp function calls. // Must be before all os.hpp function calls.
os_init(); os_init();
@ -345,6 +390,7 @@ int main(int argc, char **argv) {
const char *in_file = nullptr; const char *in_file = nullptr;
const char *out_file = nullptr; const char *out_file = nullptr;
const char *out_file_h = nullptr; const char *out_file_h = nullptr;
const char *out_file_lib = nullptr;
bool strip = false; bool strip = false;
bool is_static = false; bool is_static = false;
OutType out_type = OutTypeUnknown; OutType out_type = OutTypeUnknown;
@ -355,23 +401,17 @@ int main(int argc, char **argv) {
bool verbose_ir = false; bool verbose_ir = false;
bool verbose_llvm_ir = false; bool verbose_llvm_ir = false;
bool verbose_cimport = false; bool verbose_cimport = false;
bool verbose_cc = false;
ErrColor color = ErrColorAuto; ErrColor color = ErrColorAuto;
CacheOpt enable_cache = CacheOptAuto; CacheOpt enable_cache = CacheOptAuto;
const char *libc_lib_dir = nullptr; const char *libc_txt = nullptr;
const char *libc_static_lib_dir = nullptr;
const char *libc_include_dir = nullptr;
const char *msvc_lib_dir = nullptr;
const char *kernel32_lib_dir = nullptr;
const char *dynamic_linker = nullptr;
ZigList<const char *> clang_argv = {0}; ZigList<const char *> clang_argv = {0};
ZigList<const char *> llvm_argv = {0}; ZigList<const char *> llvm_argv = {0};
ZigList<const char *> lib_dirs = {0}; ZigList<const char *> lib_dirs = {0};
ZigList<const char *> link_libs = {0}; ZigList<const char *> link_libs = {0};
ZigList<const char *> forbidden_link_libs = {0}; ZigList<const char *> forbidden_link_libs = {0};
ZigList<const char *> frameworks = {0}; ZigList<const char *> frameworks = {0};
const char *target_arch = nullptr; const char *target_string = nullptr;
const char *target_os = nullptr;
const char *target_environ = nullptr;
bool rdynamic = false; bool rdynamic = false;
const char *mmacosx_version_min = nullptr; const char *mmacosx_version_min = nullptr;
const char *mios_version_min = nullptr; const char *mios_version_min = nullptr;
@ -379,6 +419,7 @@ int main(int argc, char **argv) {
ZigList<const char *> rpath_list = {0}; ZigList<const char *> rpath_list = {0};
bool each_lib_rpath = false; bool each_lib_rpath = false;
ZigList<const char *> objects = {0}; ZigList<const char *> objects = {0};
ZigList<CFile *> c_source_files = {0};
ZigList<const char *> asm_files = {0}; ZigList<const char *> asm_files = {0};
const char *test_filter = nullptr; const char *test_filter = nullptr;
const char *test_name_prefix = nullptr; const char *test_name_prefix = nullptr;
@ -392,11 +433,11 @@ int main(int argc, char **argv) {
BuildMode build_mode = BuildModeDebug; BuildMode build_mode = BuildModeDebug;
ZigList<const char *> test_exec_args = {0}; ZigList<const char *> test_exec_args = {0};
int runtime_args_start = -1; int runtime_args_start = -1;
bool no_rosegment_workaround = false;
bool system_linker_hack = false; bool system_linker_hack = false;
TargetSubsystem subsystem = TargetSubsystemAuto; TargetSubsystem subsystem = TargetSubsystemAuto;
bool is_single_threaded = false; bool is_single_threaded = false;
Buf *override_std_dir = nullptr; Buf *override_std_dir = nullptr;
ValgrindSupport valgrind_support = ValgrindSupportAuto;
if (argc >= 2 && strcmp(argv[1], "build") == 0) { if (argc >= 2 && strcmp(argv[1], "build") == 0) {
Buf zig_exe_path_buf = BUF_INIT; Buf zig_exe_path_buf = BUF_INIT;
@ -432,8 +473,11 @@ int main(int argc, char **argv) {
Buf *build_runner_path = buf_alloc(); Buf *build_runner_path = buf_alloc();
os_path_join(get_zig_special_dir(), buf_create_from_str("build_runner.zig"), build_runner_path); os_path_join(get_zig_special_dir(), buf_create_from_str("build_runner.zig"), build_runner_path);
CodeGen *g = codegen_create(build_runner_path, nullptr, OutTypeExe, BuildModeDebug, get_zig_lib_dir(), ZigTarget target;
override_std_dir); get_native_target(&target);
CodeGen *g = codegen_create(build_runner_path, &target, OutTypeExe, BuildModeDebug, get_zig_lib_dir(),
override_std_dir, nullptr);
g->valgrind_support = valgrind_support;
g->enable_time_report = timing_info; g->enable_time_report = timing_info;
buf_init_from_str(&g->cache_dir, cache_dir ? cache_dir : default_zig_cache_name); buf_init_from_str(&g->cache_dir, cache_dir ? cache_dir : default_zig_cache_name);
codegen_set_out_name(g, buf_create_from_str("build")); codegen_set_out_name(g, buf_create_from_str("build"));
@ -484,6 +528,7 @@ int main(int argc, char **argv) {
" --verbose-ir Enable compiler debug output for Zig IR\n" " --verbose-ir Enable compiler debug output for Zig IR\n"
" --verbose-llvm-ir Enable compiler debug output for LLVM IR\n" " --verbose-llvm-ir Enable compiler debug output for LLVM IR\n"
" --verbose-cimport Enable compiler debug output for C imports\n" " --verbose-cimport Enable compiler debug output for C imports\n"
" --verbose-cc Enable compiler debug output for C compilation\n"
"\n" "\n"
, zig_exe_path); , zig_exe_path);
return EXIT_SUCCESS; return EXIT_SUCCESS;
@ -493,7 +538,7 @@ int main(int argc, char **argv) {
"No 'build.zig' file found.\n" "No 'build.zig' file found.\n"
"Initialize a 'build.zig' template file with `zig init-lib` or `zig init-exe`,\n" "Initialize a 'build.zig' template file with `zig init-lib` or `zig init-exe`,\n"
"or build an executable directly with `zig build-exe $FILENAME.zig`.\n" "or build an executable directly with `zig build-exe $FILENAME.zig`.\n"
"See: `zig build --help` or `zig help` for more options.\n" "See: `zig build --help` or `zig --help` for more options.\n"
); );
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@ -515,6 +560,37 @@ int main(int argc, char **argv) {
fprintf(stderr, "\n"); fprintf(stderr, "\n");
} }
return (term.how == TerminationIdClean) ? term.code : -1; return (term.how == TerminationIdClean) ? term.code : -1;
} else if (argc >= 2 && strcmp(argv[1], "fmt") == 0) {
init_all_targets();
ZigTarget target;
get_native_target(&target);
Buf *fmt_runner_path = buf_alloc();
os_path_join(get_zig_special_dir(), buf_create_from_str("fmt_runner.zig"), fmt_runner_path);
CodeGen *g = codegen_create(fmt_runner_path, &target, OutTypeExe, BuildModeDebug, get_zig_lib_dir(),
nullptr, nullptr);
buf_init_from_str(&g->cache_dir, cache_dir ? cache_dir : default_zig_cache_name);
g->valgrind_support = valgrind_support;
g->is_single_threaded = true;
codegen_set_out_name(g, buf_create_from_str("fmt"));
g->enable_cache = true;
codegen_build_and_link(g);
// TODO standardize os.cpp so that the args are supposed to have the exe
ZigList<const char*> args_with_exe = {0};
ZigList<const char*> args_without_exe = {0};
const char *exec_path = buf_ptr(&g->output_file_path);
args_with_exe.append(exec_path);
for (int i = 2; i < argc; i += 1) {
args_with_exe.append(argv[i]);
args_without_exe.append(argv[i]);
}
args_with_exe.append(nullptr);
os_execv(exec_path, args_with_exe.items);
Termination term;
os_spawn_process(exec_path, args_without_exe, &term);
return term.code;
} }
for (int i = 1; i < argc; i += 1) { for (int i = 1; i < argc; i += 1) {
@ -527,6 +603,12 @@ int main(int argc, char **argv) {
build_mode = BuildModeSafeRelease; build_mode = BuildModeSafeRelease;
} else if (strcmp(arg, "--release-small") == 0) { } else if (strcmp(arg, "--release-small") == 0) {
build_mode = BuildModeSmallRelease; build_mode = BuildModeSmallRelease;
} else if (strcmp(arg, "--help") == 0) {
if (cmd == CmdLibC) {
return print_libc_usage(arg0, stdout, EXIT_SUCCESS);
} else {
return print_full_usage(arg0, stdout, EXIT_SUCCESS);
}
} else if (strcmp(arg, "--strip") == 0) { } else if (strcmp(arg, "--strip") == 0) {
strip = true; strip = true;
} else if (strcmp(arg, "--static") == 0) { } else if (strcmp(arg, "--static") == 0) {
@ -543,16 +625,20 @@ int main(int argc, char **argv) {
verbose_llvm_ir = true; verbose_llvm_ir = true;
} else if (strcmp(arg, "--verbose-cimport") == 0) { } else if (strcmp(arg, "--verbose-cimport") == 0) {
verbose_cimport = true; verbose_cimport = true;
} else if (strcmp(arg, "--verbose-cc") == 0) {
verbose_cc = true;
} else if (strcmp(arg, "-rdynamic") == 0) { } else if (strcmp(arg, "-rdynamic") == 0) {
rdynamic = true; rdynamic = true;
} else if (strcmp(arg, "--no-rosegment") == 0) {
no_rosegment_workaround = true;
} else if (strcmp(arg, "--each-lib-rpath") == 0) { } else if (strcmp(arg, "--each-lib-rpath") == 0) {
each_lib_rpath = true; each_lib_rpath = true;
} else if (strcmp(arg, "-ftime-report") == 0) { } else if (strcmp(arg, "-ftime-report") == 0) {
timing_info = true; timing_info = true;
} else if (strcmp(arg, "--disable-pic") == 0) { } else if (strcmp(arg, "--disable-pic") == 0) {
disable_pic = true; disable_pic = true;
} else if (strcmp(arg, "--enable-valgrind") == 0) {
valgrind_support = ValgrindSupportEnabled;
} else if (strcmp(arg, "--disable-valgrind") == 0) {
valgrind_support = ValgrindSupportDisabled;
} else if (strcmp(arg, "--system-linker-hack") == 0) { } else if (strcmp(arg, "--system-linker-hack") == 0) {
system_linker_hack = true; system_linker_hack = true;
} else if (strcmp(arg, "--single-threaded") == 0) { } else if (strcmp(arg, "--single-threaded") == 0) {
@ -590,6 +676,8 @@ int main(int argc, char **argv) {
out_file = argv[i]; out_file = argv[i];
} else if (strcmp(arg, "--output-h") == 0) { } else if (strcmp(arg, "--output-h") == 0) {
out_file_h = argv[i]; out_file_h = argv[i];
} else if (strcmp(arg, "--output-lib") == 0) {
out_file_lib = argv[i];
} else if (strcmp(arg, "--color") == 0) { } else if (strcmp(arg, "--color") == 0) {
if (strcmp(argv[i], "auto") == 0) { if (strcmp(argv[i], "auto") == 0) {
color = ErrColorAuto; color = ErrColorAuto;
@ -625,18 +713,8 @@ int main(int argc, char **argv) {
} }
} else if (strcmp(arg, "--name") == 0) { } else if (strcmp(arg, "--name") == 0) {
out_name = argv[i]; out_name = argv[i];
} else if (strcmp(arg, "--libc-lib-dir") == 0) { } else if (strcmp(arg, "--libc") == 0) {
libc_lib_dir = argv[i]; libc_txt = argv[i];
} else if (strcmp(arg, "--libc-static-lib-dir") == 0) {
libc_static_lib_dir = argv[i];
} else if (strcmp(arg, "--libc-include-dir") == 0) {
libc_include_dir = argv[i];
} else if (strcmp(arg, "--msvc-lib-dir") == 0) {
msvc_lib_dir = argv[i];
} else if (strcmp(arg, "--kernel32-lib-dir") == 0) {
kernel32_lib_dir = argv[i];
} else if (strcmp(arg, "--dynamic-linker") == 0) {
dynamic_linker = argv[i];
} else if (strcmp(arg, "-isystem") == 0) { } else if (strcmp(arg, "-isystem") == 0) {
clang_argv.append("-isystem"); clang_argv.append("-isystem");
clang_argv.append(argv[i]); clang_argv.append(argv[i]);
@ -658,16 +736,25 @@ int main(int argc, char **argv) {
forbidden_link_libs.append(argv[i]); forbidden_link_libs.append(argv[i]);
} else if (strcmp(arg, "--object") == 0) { } else if (strcmp(arg, "--object") == 0) {
objects.append(argv[i]); objects.append(argv[i]);
} else if (strcmp(arg, "--c-source") == 0) {
CFile *c_file = allocate<CFile>(1);
for (;;) {
if (argv[i][0] == '-') {
c_file->args.append(argv[i]);
i += 1;
continue;
} else {
c_file->source_path = argv[i];
c_source_files.append(c_file);
break;
}
}
} else if (strcmp(arg, "--assembly") == 0) { } else if (strcmp(arg, "--assembly") == 0) {
asm_files.append(argv[i]); asm_files.append(argv[i]);
} else if (strcmp(arg, "--cache-dir") == 0) { } else if (strcmp(arg, "--cache-dir") == 0) {
cache_dir = argv[i]; cache_dir = argv[i];
} else if (strcmp(arg, "--target-arch") == 0) { } else if (strcmp(arg, "-target") == 0) {
target_arch = argv[i]; target_string = argv[i];
} else if (strcmp(arg, "--target-os") == 0) {
target_os = argv[i];
} else if (strcmp(arg, "--target-environ") == 0) {
target_environ = argv[i];
} else if (strcmp(arg, "-mmacosx-version-min") == 0) { } else if (strcmp(arg, "-mmacosx-version-min") == 0) {
mmacosx_version_min = argv[i]; mmacosx_version_min = argv[i];
} else if (strcmp(arg, "-mios-version-min") == 0) { } else if (strcmp(arg, "-mios-version-min") == 0) {
@ -736,8 +823,6 @@ int main(int argc, char **argv) {
} else if (strcmp(arg, "build-lib") == 0) { } else if (strcmp(arg, "build-lib") == 0) {
cmd = CmdBuild; cmd = CmdBuild;
out_type = OutTypeLib; out_type = OutTypeLib;
} else if (strcmp(arg, "help") == 0) {
cmd = CmdHelp;
} else if (strcmp(arg, "run") == 0) { } else if (strcmp(arg, "run") == 0) {
cmd = CmdRun; cmd = CmdRun;
out_type = OutTypeExe; out_type = OutTypeExe;
@ -745,6 +830,8 @@ int main(int argc, char **argv) {
cmd = CmdVersion; cmd = CmdVersion;
} else if (strcmp(arg, "zen") == 0) { } else if (strcmp(arg, "zen") == 0) {
cmd = CmdZen; cmd = CmdZen;
} else if (strcmp(arg, "libc") == 0) {
cmd = CmdLibC;
} else if (strcmp(arg, "translate-c") == 0) { } else if (strcmp(arg, "translate-c") == 0) {
cmd = CmdTranslateC; cmd = CmdTranslateC;
} else if (strcmp(arg, "test") == 0) { } else if (strcmp(arg, "test") == 0) {
@ -764,6 +851,7 @@ int main(int argc, char **argv) {
case CmdRun: case CmdRun:
case CmdTranslateC: case CmdTranslateC:
case CmdTest: case CmdTest:
case CmdLibC:
if (!in_file) { if (!in_file) {
in_file = arg; in_file = arg;
if (cmd == CmdRun) { if (cmd == CmdRun) {
@ -776,7 +864,6 @@ int main(int argc, char **argv) {
} }
break; break;
case CmdBuiltin: case CmdBuiltin:
case CmdHelp:
case CmdVersion: case CmdVersion:
case CmdZen: case CmdZen:
case CmdTargets: case CmdTargets:
@ -795,36 +882,34 @@ int main(int argc, char **argv) {
init_all_targets(); init_all_targets();
ZigTarget alloc_target; ZigTarget target;
ZigTarget *target; if (target_string == nullptr) {
if (!target_arch && !target_os && !target_environ) { get_native_target(&target);
target = nullptr;
} else { } else {
target = &alloc_target; if ((err = target_parse_triple(&target, target_string))) {
get_unknown_target(target); fprintf(stderr, "invalid target: %s\n", err_str(err));
if (target_arch) {
if (parse_target_arch(target_arch, &target->arch)) {
fprintf(stderr, "invalid --target-arch argument\n");
return print_error_usage(arg0); return print_error_usage(arg0);
} }
} }
if (target_os) {
if (parse_target_os(target_os, &target->os)) {
fprintf(stderr, "invalid --target-os argument\n");
return print_error_usage(arg0);
}
}
if (target_environ) {
if (parse_target_environ(target_environ, &target->env_type)) {
fprintf(stderr, "invalid --target-environ argument\n");
return print_error_usage(arg0);
}
}
}
switch (cmd) { switch (cmd) {
case CmdLibC: {
if (in_file) {
ZigLibCInstallation libc;
if ((err = zig_libc_parse(&libc, buf_create_from_str(in_file), &target, true)))
return EXIT_FAILURE;
return EXIT_SUCCESS;
}
ZigLibCInstallation libc;
if ((err = zig_libc_find_native(&libc, true)))
return EXIT_FAILURE;
zig_libc_render(&libc, stdout);
return EXIT_SUCCESS;
}
case CmdBuiltin: { case CmdBuiltin: {
CodeGen *g = codegen_create(nullptr, target, out_type, build_mode, get_zig_lib_dir(), override_std_dir); CodeGen *g = codegen_create(nullptr, &target, out_type, build_mode, get_zig_lib_dir(), override_std_dir,
nullptr);
g->valgrind_support = valgrind_support;
g->is_single_threaded = is_single_threaded; g->is_single_threaded = is_single_threaded;
Buf *builtin_source = codegen_generate_builtin_source(g); Buf *builtin_source = codegen_generate_builtin_source(g);
if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) { if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) {
@ -838,16 +923,44 @@ int main(int argc, char **argv) {
case CmdTranslateC: case CmdTranslateC:
case CmdTest: case CmdTest:
{ {
if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0) { if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0 &&
fprintf(stderr, "Expected source file argument or at least one --object or --assembly argument.\n"); c_source_files.length == 0)
{
fprintf(stderr,
"Expected at least one of these things:\n"
" * Zig root source file argument\n"
" * --object argument\n"
" * --assembly argument\n"
" * --c-source argument\n");
return print_error_usage(arg0); return print_error_usage(arg0);
} else if ((cmd == CmdTranslateC || cmd == CmdTest || cmd == CmdRun) && !in_file) { } else if ((cmd == CmdTranslateC || cmd == CmdTest || cmd == CmdRun) && !in_file) {
fprintf(stderr, "Expected source file argument.\n"); fprintf(stderr, "Expected source file argument.\n");
return print_error_usage(arg0); return print_error_usage(arg0);
} else if (cmd == CmdBuild && out_type == OutTypeObj && objects.length != 0) { } else if (cmd == CmdBuild && out_type == OutTypeObj) {
fprintf(stderr, "When building an object file, --object arguments are invalid.\n"); if (objects.length != 0) {
fprintf(stderr,
"When building an object file, --object arguments are invalid.\n"
"Consider building a static library instead.\n");
return print_error_usage(arg0); return print_error_usage(arg0);
} }
size_t zig_root_src_count = in_file ? 1 : 0;
if (zig_root_src_count + c_source_files.length > 1) {
fprintf(stderr,
"When building an object file, only one of these allowed:\n"
" * Zig root source file argument\n"
" * --c-source argument\n"
"Consider building a static library instead.\n");
return print_error_usage(arg0);
}
if (c_source_files.length != 0 && asm_files.length != 0) {
fprintf(stderr,
"When building an object file, only one of these allowed:\n"
" * --assembly argument\n"
" * --c-source argument\n"
"Consider building a static library instead.\n");
return print_error_usage(arg0);
}
}
assert(cmd != CmdBuild || out_type != OutTypeUnknown); assert(cmd != CmdBuild || out_type != OutTypeUnknown);
@ -873,6 +986,13 @@ int main(int argc, char **argv) {
} }
} }
if (need_name && buf_out_name == nullptr && c_source_files.length == 1) {
Buf basename = BUF_INIT;
os_path_split(buf_create_from_str(c_source_files.at(0)->source_path), nullptr, &basename);
buf_out_name = buf_alloc();
os_path_extname(&basename, buf_out_name, nullptr);
}
if (need_name && buf_out_name == nullptr) { if (need_name && buf_out_name == nullptr) {
fprintf(stderr, "--name [name] not provided and unable to infer\n\n"); fprintf(stderr, "--name [name] not provided and unable to infer\n\n");
return print_error_usage(arg0); return print_error_usage(arg0);
@ -883,8 +1003,17 @@ int main(int argc, char **argv) {
if (cmd == CmdRun && buf_out_name == nullptr) { if (cmd == CmdRun && buf_out_name == nullptr) {
buf_out_name = buf_create_from_str("run"); buf_out_name = buf_create_from_str("run");
} }
CodeGen *g = codegen_create(zig_root_source_file, target, out_type, build_mode, get_zig_lib_dir(), ZigLibCInstallation *libc = nullptr;
override_std_dir); if (libc_txt != nullptr) {
libc = allocate<ZigLibCInstallation>(1);
if ((err = zig_libc_parse(libc, buf_create_from_str(libc_txt), &target, true))) {
fprintf(stderr, "Unable to parse --libc text file: %s\n", err_str(err));
return EXIT_FAILURE;
}
}
CodeGen *g = codegen_create(zig_root_source_file, &target, out_type, build_mode, get_zig_lib_dir(),
override_std_dir, libc);
g->valgrind_support = valgrind_support;
g->subsystem = subsystem; g->subsystem = subsystem;
if (disable_pic) { if (disable_pic) {
@ -909,24 +1038,13 @@ int main(int argc, char **argv) {
codegen_set_llvm_argv(g, llvm_argv.items, llvm_argv.length); codegen_set_llvm_argv(g, llvm_argv.items, llvm_argv.length);
codegen_set_strip(g, strip); codegen_set_strip(g, strip);
codegen_set_is_static(g, is_static); codegen_set_is_static(g, is_static);
if (libc_lib_dir)
codegen_set_libc_lib_dir(g, buf_create_from_str(libc_lib_dir));
if (libc_static_lib_dir)
codegen_set_libc_static_lib_dir(g, buf_create_from_str(libc_static_lib_dir));
if (libc_include_dir)
codegen_set_libc_include_dir(g, buf_create_from_str(libc_include_dir));
if (msvc_lib_dir)
codegen_set_msvc_lib_dir(g, buf_create_from_str(msvc_lib_dir));
if (kernel32_lib_dir)
codegen_set_kernel32_lib_dir(g, buf_create_from_str(kernel32_lib_dir));
if (dynamic_linker)
codegen_set_dynamic_linker(g, buf_create_from_str(dynamic_linker));
g->verbose_tokenize = verbose_tokenize; g->verbose_tokenize = verbose_tokenize;
g->verbose_ast = verbose_ast; g->verbose_ast = verbose_ast;
g->verbose_link = verbose_link; g->verbose_link = verbose_link;
g->verbose_ir = verbose_ir; g->verbose_ir = verbose_ir;
g->verbose_llvm_ir = verbose_llvm_ir; g->verbose_llvm_ir = verbose_llvm_ir;
g->verbose_cimport = verbose_cimport; g->verbose_cimport = verbose_cimport;
g->verbose_cc = verbose_cc;
codegen_set_errmsg_color(g, color); codegen_set_errmsg_color(g, color);
g->system_linker_hack = system_linker_hack; g->system_linker_hack = system_linker_hack;
@ -949,7 +1067,6 @@ int main(int argc, char **argv) {
} }
codegen_set_rdynamic(g, rdynamic); codegen_set_rdynamic(g, rdynamic);
g->no_rosegment_workaround = no_rosegment_workaround;
if (mmacosx_version_min && mios_version_min) { if (mmacosx_version_min && mios_version_min) {
fprintf(stderr, "-mmacosx-version-min and -mios-version-min options not allowed together\n"); fprintf(stderr, "-mmacosx-version-min and -mios-version-min options not allowed together\n");
return EXIT_FAILURE; return EXIT_FAILURE;
@ -975,11 +1092,14 @@ int main(int argc, char **argv) {
codegen_set_output_path(g, buf_create_from_str(out_file)); codegen_set_output_path(g, buf_create_from_str(out_file));
if (out_file_h != nullptr && (out_type == OutTypeObj || out_type == OutTypeLib)) if (out_file_h != nullptr && (out_type == OutTypeObj || out_type == OutTypeLib))
codegen_set_output_h_path(g, buf_create_from_str(out_file_h)); codegen_set_output_h_path(g, buf_create_from_str(out_file_h));
if (out_file_lib != nullptr && out_type == OutTypeLib && !is_static)
codegen_set_output_lib_path(g, buf_create_from_str(out_file_lib));
add_package(g, cur_pkg, g->root_package); add_package(g, cur_pkg, g->root_package);
if (cmd == CmdBuild || cmd == CmdRun || cmd == CmdTest) { if (cmd == CmdBuild || cmd == CmdRun || cmd == CmdTest) {
g->c_source_files = c_source_files;
for (size_t i = 0; i < objects.length; i += 1) { for (size_t i = 0; i < objects.length; i += 1) {
codegen_add_object(g, buf_create_from_str(objects.at(i))); codegen_add_object(g, buf_create_from_str(objects.at(i)));
} }
@ -1052,7 +1172,7 @@ int main(int argc, char **argv) {
} }
} }
if (!target_can_exec(&native, target)) { if (!target_can_exec(&native, &target)) {
fprintf(stderr, "Created %s but skipping execution because it is non-native.\n", fprintf(stderr, "Created %s but skipping execution because it is non-native.\n",
buf_ptr(test_exe_path)); buf_ptr(test_exe_path));
return 0; return 0;
@ -1079,8 +1199,6 @@ int main(int argc, char **argv) {
zig_unreachable(); zig_unreachable();
} }
} }
case CmdHelp:
return print_full_usage(arg0);
case CmdVersion: case CmdVersion:
printf("%s\n", ZIG_VERSION_STRING); printf("%s\n", ZIG_VERSION_STRING);
return EXIT_SUCCESS; return EXIT_SUCCESS;
@ -1090,7 +1208,6 @@ int main(int argc, char **argv) {
case CmdTargets: case CmdTargets:
return print_target_list(stdout); return print_target_list(stdout);
case CmdNone: case CmdNone:
fprintf(stderr, "Zig programming language\n"); return print_full_usage(arg0, stderr, EXIT_FAILURE);
return print_error_usage(arg0);
} }
} }

View File

@ -50,11 +50,11 @@ typedef SSIZE_T ssize_t;
#endif #endif
#if defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD) #if defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD)
#include <link.h> #include <link.h>
#endif #endif
#if defined(ZIG_OS_FREEBSD) #if defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD)
#include <sys/sysctl.h> #include <sys/sysctl.h>
#endif #endif
@ -78,7 +78,7 @@ static clock_serv_t cclock;
#if defined(__APPLE__) && !defined(environ) #if defined(__APPLE__) && !defined(environ)
#include <crt_externs.h> #include <crt_externs.h>
#define environ (*_NSGetEnviron()) #define environ (*_NSGetEnviron())
#elif defined(ZIG_OS_FREEBSD) #elif defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD)
extern char **environ; extern char **environ;
#endif #endif
@ -1099,7 +1099,7 @@ Error os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang) {
case EINTR: case EINTR:
return ErrorInterrupted; return ErrorInterrupted;
case EINVAL: case EINVAL:
zig_unreachable(); return ErrorInvalidFilename;
case ENFILE: case ENFILE:
case ENOMEM: case ENOMEM:
return ErrorSystemResources; return ErrorSystemResources;
@ -1232,6 +1232,18 @@ static Error os_buf_to_tmp_file_posix(Buf *contents, Buf *suffix, Buf *out_tmp_p
} }
#endif #endif
Buf *os_tmp_filename(Buf *prefix, Buf *suffix) {
Buf *result = buf_create_from_buf(prefix);
const char base64[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
assert(array_length(base64) == 64 + 1);
for (size_t i = 0; i < 12; i += 1) {
buf_append_char(result, base64[rand() % 64]);
}
buf_append_buf(result, suffix);
return result;
}
#if defined(ZIG_OS_WINDOWS) #if defined(ZIG_OS_WINDOWS)
static Error os_buf_to_tmp_file_windows(Buf *contents, Buf *suffix, Buf *out_tmp_path) { static Error os_buf_to_tmp_file_windows(Buf *contents, Buf *suffix, Buf *out_tmp_path) {
char tmp_dir[MAX_PATH + 1]; char tmp_dir[MAX_PATH + 1];
@ -1458,6 +1470,15 @@ Error os_self_exe_path(Buf *out_path) {
} }
buf_resize(out_path, cb - 1); buf_resize(out_path, cb - 1);
return ErrorNone; return ErrorNone;
#elif defined(ZIG_OS_NETBSD)
buf_resize(out_path, PATH_MAX);
int mib[4] = { CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME };
size_t cb = PATH_MAX;
if (sysctl(mib, 4, buf_ptr(out_path), &cb, nullptr, 0) != 0) {
return ErrorUnexpected;
}
buf_resize(out_path, cb - 1);
return ErrorNone;
#endif #endif
return ErrorFileNotFound; return ErrorFileNotFound;
} }
@ -1541,7 +1562,7 @@ void os_stderr_set_color(TermColor color) {
#endif #endif
} }
int os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchType platform_type) { Error os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchType platform_type) {
#if defined(ZIG_OS_WINDOWS) #if defined(ZIG_OS_WINDOWS)
buf_resize(output_buf, 0); buf_resize(output_buf, 0);
buf_appendf(output_buf, "%s\\Lib\\%s\\ucrt\\", sdk->path10_ptr, sdk->version10_ptr); buf_appendf(output_buf, "%s\\Lib\\%s\\ucrt\\", sdk->path10_ptr, sdk->version10_ptr);
@ -1562,7 +1583,7 @@ int os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_Arch
buf_init_from_buf(tmp_buf, output_buf); buf_init_from_buf(tmp_buf, output_buf);
buf_append_str(tmp_buf, "ucrt.lib"); buf_append_str(tmp_buf, "ucrt.lib");
if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) { if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) {
return 0; return ErrorNone;
} }
else { else {
buf_resize(output_buf, 0); buf_resize(output_buf, 0);
@ -1573,12 +1594,12 @@ int os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_Arch
#endif #endif
} }
int os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf* output_buf) { Error os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf* output_buf) {
#if defined(ZIG_OS_WINDOWS) #if defined(ZIG_OS_WINDOWS)
buf_resize(output_buf, 0); buf_resize(output_buf, 0);
buf_appendf(output_buf, "%s\\Include\\%s\\ucrt", sdk->path10_ptr, sdk->version10_ptr); buf_appendf(output_buf, "%s\\Include\\%s\\ucrt", sdk->path10_ptr, sdk->version10_ptr);
if (GetFileAttributesA(buf_ptr(output_buf)) != INVALID_FILE_ATTRIBUTES) { if (GetFileAttributesA(buf_ptr(output_buf)) != INVALID_FILE_ATTRIBUTES) {
return 0; return ErrorNone;
} }
else { else {
buf_resize(output_buf, 0); buf_resize(output_buf, 0);
@ -1589,7 +1610,7 @@ int os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf* output_buf) {
#endif #endif
} }
int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchType platform_type) { Error os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchType platform_type) {
#if defined(ZIG_OS_WINDOWS) #if defined(ZIG_OS_WINDOWS)
{ {
buf_resize(output_buf, 0); buf_resize(output_buf, 0);
@ -1611,7 +1632,7 @@ int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchTy
buf_init_from_buf(tmp_buf, output_buf); buf_init_from_buf(tmp_buf, output_buf);
buf_append_str(tmp_buf, "kernel32.lib"); buf_append_str(tmp_buf, "kernel32.lib");
if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) { if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) {
return 0; return ErrorNone;
} }
} }
{ {
@ -1634,7 +1655,7 @@ int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchTy
buf_init_from_buf(tmp_buf, output_buf); buf_init_from_buf(tmp_buf, output_buf);
buf_append_str(tmp_buf, "kernel32.lib"); buf_append_str(tmp_buf, "kernel32.lib");
if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) { if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) {
return 0; return ErrorNone;
} }
} }
return ErrorFileNotFound; return ErrorFileNotFound;
@ -1776,7 +1797,7 @@ Error os_get_app_data_dir(Buf *out_path, const char *appname) {
} }
#if defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD) #if defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD)
static int self_exe_shared_libs_callback(struct dl_phdr_info *info, size_t size, void *data) { static int self_exe_shared_libs_callback(struct dl_phdr_info *info, size_t size, void *data) {
ZigList<Buf *> *libs = reinterpret_cast< ZigList<Buf *> *>(data); ZigList<Buf *> *libs = reinterpret_cast< ZigList<Buf *> *>(data);
if (info->dlpi_name[0] == '/') { if (info->dlpi_name[0] == '/') {
@ -1787,7 +1808,7 @@ static int self_exe_shared_libs_callback(struct dl_phdr_info *info, size_t size,
#endif #endif
Error os_self_exe_shared_libs(ZigList<Buf *> &paths) { Error os_self_exe_shared_libs(ZigList<Buf *> &paths) {
#if defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD) #if defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD)
paths.resize(0); paths.resize(0);
dl_iterate_phdr(self_exe_shared_libs_callback, &paths); dl_iterate_phdr(self_exe_shared_libs_callback, &paths);
return ErrorNone; return ErrorNone;

View File

@ -25,6 +25,8 @@
#define ZIG_OS_LINUX #define ZIG_OS_LINUX
#elif defined(__FreeBSD__) #elif defined(__FreeBSD__)
#define ZIG_OS_FREEBSD #define ZIG_OS_FREEBSD
#elif defined(__NetBSD__)
#define ZIG_OS_NETBSD
#else #else
#define ZIG_OS_UNKNOWN #define ZIG_OS_UNKNOWN
#endif #endif
@ -119,6 +121,7 @@ Error ATTRIBUTE_MUST_USE os_get_cwd(Buf *out_cwd);
bool os_stderr_tty(void); bool os_stderr_tty(void);
void os_stderr_set_color(TermColor color); void os_stderr_set_color(TermColor color);
Buf *os_tmp_filename(Buf *prefix, Buf *suffix);
Error os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path); Error os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path);
Error os_delete_file(Buf *path); Error os_delete_file(Buf *path);
@ -133,9 +136,9 @@ Error ATTRIBUTE_MUST_USE os_self_exe_path(Buf *out_path);
Error ATTRIBUTE_MUST_USE os_get_app_data_dir(Buf *out_path, const char *appname); Error ATTRIBUTE_MUST_USE os_get_app_data_dir(Buf *out_path, const char *appname);
int os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf *output_buf); Error ATTRIBUTE_MUST_USE os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf *output_buf);
int os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type); Error ATTRIBUTE_MUST_USE os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);
int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type); Error ATTRIBUTE_MUST_USE os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);
Error ATTRIBUTE_MUST_USE os_self_exe_shared_libs(ZigList<Buf *> &paths); Error ATTRIBUTE_MUST_USE os_self_exe_shared_libs(ZigList<Buf *> &paths);

View File

@ -2739,6 +2739,7 @@ static AstNode *ast_parse_async_prefix(ParseContext *pc) {
AstNode *res = ast_create_node(pc, NodeTypeFnCallExpr, async); AstNode *res = ast_create_node(pc, NodeTypeFnCallExpr, async);
res->data.fn_call_expr.is_async = true; res->data.fn_call_expr.is_async = true;
res->data.fn_call_expr.seen = false;
if (eat_token_if(pc, TokenIdCmpLessThan) != nullptr) { if (eat_token_if(pc, TokenIdCmpLessThan) != nullptr) {
AstNode *prefix_expr = ast_expect(pc, ast_parse_prefix_expr); AstNode *prefix_expr = ast_expect(pc, ast_parse_prefix_expr);
expect_token(pc, TokenIdCmpGreaterThan); expect_token(pc, TokenIdCmpGreaterThan);
@ -2759,6 +2760,7 @@ static AstNode *ast_parse_fn_call_argumnets(ParseContext *pc) {
AstNode *res = ast_create_node(pc, NodeTypeFnCallExpr, paren); AstNode *res = ast_create_node(pc, NodeTypeFnCallExpr, paren);
res->data.fn_call_expr.params = params; res->data.fn_call_expr.params = params;
res->data.fn_call_expr.seen = false;
return res; return res;
} }
@ -2778,7 +2780,8 @@ static AstNode *ast_parse_array_type_start(ParseContext *pc) {
// PtrTypeStart // PtrTypeStart
// <- ASTERISK // <- ASTERISK
// / ASTERISK2 // / ASTERISK2
// / LBRACKET ASTERISK RBRACKET // / PTRUNKNOWN
// / PTRC
static AstNode *ast_parse_ptr_type_start(ParseContext *pc) { static AstNode *ast_parse_ptr_type_start(ParseContext *pc) {
Token *asterisk = eat_token_if(pc, TokenIdStar); Token *asterisk = eat_token_if(pc, TokenIdStar);
if (asterisk != nullptr) { if (asterisk != nullptr) {
@ -2804,6 +2807,13 @@ static AstNode *ast_parse_ptr_type_start(ParseContext *pc) {
return res; return res;
} }
Token *cptr = eat_token_if(pc, TokenIdBracketStarCBracket);
if (cptr != nullptr) {
AstNode *res = ast_create_node(pc, NodeTypePointerType, cptr);
res->data.pointer_type.star_token = cptr;
return res;
}
return nullptr; return nullptr;
} }

File diff suppressed because it is too large Load Diff

View File

@ -12,11 +12,6 @@
struct Buf; struct Buf;
struct ArchType {
ZigLLVM_ArchType arch;
ZigLLVM_SubArchType sub_arch;
};
// Synchronize with target.cpp::os_list // Synchronize with target.cpp::os_list
enum Os { enum Os {
OsFreestanding, OsFreestanding,
@ -57,6 +52,15 @@ enum Os {
OsUefi, OsUefi,
}; };
// Synchronize with target.cpp::subarch_list_list
enum SubArchList {
SubArchListNone,
SubArchListArm32,
SubArchListArm64,
SubArchListKalimba,
SubArchListMips,
};
enum TargetSubsystem { enum TargetSubsystem {
TargetSubsystemAuto, // Zig should infer the subsystem TargetSubsystemAuto, // Zig should infer the subsystem
TargetSubsystemConsole, TargetSubsystemConsole,
@ -70,11 +74,12 @@ enum TargetSubsystem {
}; };
struct ZigTarget { struct ZigTarget {
ArchType arch; ZigLLVM_ArchType arch;
ZigLLVM_SubArchType sub_arch;
ZigLLVM_VendorType vendor; ZigLLVM_VendorType vendor;
Os os; Os os;
ZigLLVM_EnvironmentType env_type; ZigLLVM_EnvironmentType abi;
ZigLLVM_ObjectFormatType oformat; bool is_native;
}; };
enum CIntType { enum CIntType {
@ -90,53 +95,71 @@ enum CIntType {
CIntTypeCount, CIntTypeCount,
}; };
size_t target_arch_count(void); Error target_parse_triple(ZigTarget *target, const char *triple);
const ArchType *get_target_arch(size_t index); Error target_parse_archsub(ZigLLVM_ArchType *arch, ZigLLVM_SubArchType *sub,
void get_arch_name(char *out_str, const ArchType *arch); const char *archsub_ptr, size_t archsub_len);
Error target_parse_os(Os *os, const char *os_ptr, size_t os_len);
Error target_parse_abi(ZigLLVM_EnvironmentType *abi, const char *abi_ptr, size_t abi_len);
const char *arch_stack_pointer_register_name(const ArchType *arch); size_t target_arch_count(void);
ZigLLVM_ArchType target_arch_enum(size_t index);
const char *target_arch_name(ZigLLVM_ArchType arch);
SubArchList target_subarch_list(ZigLLVM_ArchType arch);
size_t target_subarch_count(SubArchList sub_arch_list);
ZigLLVM_SubArchType target_subarch_enum(SubArchList subarch_list, size_t index);
const char *target_subarch_name(ZigLLVM_SubArchType subarch);
size_t target_subarch_list_count(void);
SubArchList target_subarch_list_enum(size_t index);
const char *target_subarch_list_name(SubArchList sub_arch_list);
const char *arch_stack_pointer_register_name(ZigLLVM_ArchType arch);
size_t target_vendor_count(void); size_t target_vendor_count(void);
ZigLLVM_VendorType get_target_vendor(size_t index); ZigLLVM_VendorType target_vendor_enum(size_t index);
size_t target_os_count(void); size_t target_os_count(void);
Os get_target_os(size_t index); Os target_os_enum(size_t index);
const char *get_target_os_name(Os os_type); const char *target_os_name(Os os_type);
size_t target_environ_count(void); size_t target_abi_count(void);
ZigLLVM_EnvironmentType get_target_environ(size_t index); ZigLLVM_EnvironmentType target_abi_enum(size_t index);
const char *target_abi_name(ZigLLVM_EnvironmentType abi);
ZigLLVM_EnvironmentType target_default_abi(ZigLLVM_ArchType arch, Os os);
size_t target_oformat_count(void); size_t target_oformat_count(void);
const ZigLLVM_ObjectFormatType get_target_oformat(size_t index); ZigLLVM_ObjectFormatType target_oformat_enum(size_t index);
const char *get_target_oformat_name(ZigLLVM_ObjectFormatType oformat); const char *target_oformat_name(ZigLLVM_ObjectFormatType oformat);
ZigLLVM_ObjectFormatType target_object_format(const ZigTarget *target);
void get_native_target(ZigTarget *target); void get_native_target(ZigTarget *target);
void get_unknown_target(ZigTarget *target); void get_target_triple(Buf *triple, const ZigTarget *target);
int parse_target_arch(const char *str, ArchType *arch);
int parse_target_os(const char *str, Os *os);
int parse_target_environ(const char *str, ZigLLVM_EnvironmentType *env_type);
void init_all_targets(void); void init_all_targets(void);
void get_target_triple(Buf *triple, const ZigTarget *target);
void resolve_target_object_format(ZigTarget *target); void resolve_target_object_format(ZigTarget *target);
uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id); uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id);
const char *target_o_file_ext(ZigTarget *target); const char *target_o_file_ext(const ZigTarget *target);
const char *target_asm_file_ext(ZigTarget *target); const char *target_asm_file_ext(const ZigTarget *target);
const char *target_llvm_ir_file_ext(ZigTarget *target); const char *target_llvm_ir_file_ext(const ZigTarget *target);
const char *target_exe_file_ext(ZigTarget *target); const char *target_exe_file_ext(const ZigTarget *target);
const char *target_lib_file_ext(ZigTarget *target, bool is_static, size_t version_major, size_t version_minor, size_t version_patch); const char *target_lib_file_ext(const ZigTarget *target, bool is_static,
size_t version_major, size_t version_minor, size_t version_patch);
Buf *target_dynamic_linker(ZigTarget *target); const char *target_dynamic_linker(const ZigTarget *target);
bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target); bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target);
ZigLLVM_OSType get_llvm_os_type(Os os_type); ZigLLVM_OSType get_llvm_os_type(Os os_type);
bool target_is_arm(const ZigTarget *target); bool target_is_arm(const ZigTarget *target);
bool target_allows_addr_zero(const ZigTarget *target);
bool target_has_valgrind_support(const ZigTarget *target);
bool target_is_darwin(const ZigTarget *target);
bool target_requires_libc(const ZigTarget *target);
bool target_supports_fpic(const ZigTarget *target);
#endif #endif

View File

@ -221,6 +221,7 @@ enum TokenizeState {
TokenizeStateError, TokenizeStateError,
TokenizeStateLBracket, TokenizeStateLBracket,
TokenizeStateLBracketStar, TokenizeStateLBracketStar,
TokenizeStateLBracketStarC,
}; };
@ -846,7 +847,6 @@ void tokenize(Buf *buf, Tokenization *out) {
switch (c) { switch (c) {
case '*': case '*':
t.state = TokenizeStateLBracketStar; t.state = TokenizeStateLBracketStar;
set_token_id(&t, t.cur_tok, TokenIdBracketStarBracket);
break; break;
default: default:
// reinterpret as just an lbracket // reinterpret as just an lbracket
@ -857,6 +857,21 @@ void tokenize(Buf *buf, Tokenization *out) {
} }
break; break;
case TokenizeStateLBracketStar: case TokenizeStateLBracketStar:
switch (c) {
case 'c':
t.state = TokenizeStateLBracketStarC;
set_token_id(&t, t.cur_tok, TokenIdBracketStarCBracket);
break;
case ']':
set_token_id(&t, t.cur_tok, TokenIdBracketStarBracket);
end_token(&t);
t.state = TokenizeStateStart;
break;
default:
invalid_char_error(&t, c);
}
break;
case TokenizeStateLBracketStarC:
switch (c) { switch (c) {
case ']': case ']':
end_token(&t); end_token(&t);
@ -1491,6 +1506,7 @@ void tokenize(Buf *buf, Tokenization *out) {
case TokenizeStateLineStringContinue: case TokenizeStateLineStringContinue:
case TokenizeStateLineStringContinueC: case TokenizeStateLineStringContinueC:
case TokenizeStateLBracketStar: case TokenizeStateLBracketStar:
case TokenizeStateLBracketStarC:
tokenize_error(&t, "unexpected EOF"); tokenize_error(&t, "unexpected EOF");
break; break;
case TokenizeStateLineComment: case TokenizeStateLineComment:
@ -1528,6 +1544,7 @@ const char * token_name(TokenId id) {
case TokenIdBitShiftRightEq: return ">>="; case TokenIdBitShiftRightEq: return ">>=";
case TokenIdBitXorEq: return "^="; case TokenIdBitXorEq: return "^=";
case TokenIdBracketStarBracket: return "[*]"; case TokenIdBracketStarBracket: return "[*]";
case TokenIdBracketStarCBracket: return "[*c]";
case TokenIdCharLiteral: return "CharLiteral"; case TokenIdCharLiteral: return "CharLiteral";
case TokenIdCmpEq: return "=="; case TokenIdCmpEq: return "==";
case TokenIdCmpGreaterOrEq: return ">="; case TokenIdCmpGreaterOrEq: return ">=";

View File

@ -29,6 +29,7 @@ enum TokenId {
TokenIdBitShiftRightEq, TokenIdBitShiftRightEq,
TokenIdBitXorEq, TokenIdBitXorEq,
TokenIdBracketStarBracket, TokenIdBracketStarBracket,
TokenIdBracketStarCBracket,
TokenIdCharLiteral, TokenIdCharLiteral,
TokenIdCmpEq, TokenIdCmpEq,
TokenIdCmpGreaterOrEq, TokenIdCmpGreaterOrEq,

File diff suppressed because it is too large Load Diff

View File

@ -147,11 +147,14 @@ static inline T clamp(T min_value, T value, T max_value) {
return max(min(value, max_value), min_value); return max(min(value, max_value), min_value);
} }
static inline bool mem_eql_str(const char *mem, size_t mem_len, const char *str) { static inline bool mem_eql_mem(const char *a_ptr, size_t a_len, const char *b_ptr, size_t b_len) {
size_t str_len = strlen(str); if (a_len != b_len)
if (str_len != mem_len)
return false; return false;
return memcmp(mem, str, mem_len) == 0; return memcmp(a_ptr, b_ptr, a_len) == 0;
}
static inline bool mem_eql_str(const char *mem, size_t mem_len, const char *str) {
return mem_eql_mem(mem, mem_len, str, strlen(str));
} }
static inline bool is_power_of_2(uint64_t x) { static inline bool is_power_of_2(uint64_t x) {

214
src/zig_clang.cpp Normal file
View File

@ -0,0 +1,214 @@
/*
* Copyright (c) 2019 Andrew Kelley
*
* This file is part of zig, which is MIT licensed.
* See http://opensource.org/licenses/MIT
*/
/*
* The point of this file is to contain all the Clang C++ API interaction so that:
* 1. The compile time of other files is kept under control.
* 2. Provide a C interface to the Clang functions we need for self-hosting purposes.
* 3. Prevent C++ from infecting the rest of the project.
*/
#include "zig_clang.h"
#if __GNUC__ >= 8
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wclass-memaccess"
#endif
#include <clang/Frontend/ASTUnit.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/AST/Expr.h>
#if __GNUC__ >= 8
#pragma GCC diagnostic pop
#endif
// Detect additions to the enum
void zig2clang_BO(ZigClangBO op) {
switch (op) {
case ZigClangBO_PtrMemD:
case ZigClangBO_PtrMemI:
case ZigClangBO_Cmp:
case ZigClangBO_Mul:
case ZigClangBO_Div:
case ZigClangBO_Rem:
case ZigClangBO_Add:
case ZigClangBO_Sub:
case ZigClangBO_Shl:
case ZigClangBO_Shr:
case ZigClangBO_LT:
case ZigClangBO_GT:
case ZigClangBO_LE:
case ZigClangBO_GE:
case ZigClangBO_EQ:
case ZigClangBO_NE:
case ZigClangBO_And:
case ZigClangBO_Xor:
case ZigClangBO_Or:
case ZigClangBO_LAnd:
case ZigClangBO_LOr:
case ZigClangBO_Assign:
case ZigClangBO_Comma:
case ZigClangBO_MulAssign:
case ZigClangBO_DivAssign:
case ZigClangBO_RemAssign:
case ZigClangBO_AddAssign:
case ZigClangBO_SubAssign:
case ZigClangBO_ShlAssign:
case ZigClangBO_ShrAssign:
case ZigClangBO_AndAssign:
case ZigClangBO_XorAssign:
case ZigClangBO_OrAssign:
break;
}
}
static_assert((clang::BinaryOperatorKind)ZigClangBO_Add == clang::BO_Add, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_AddAssign == clang::BO_AddAssign, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_And == clang::BO_And, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_AndAssign == clang::BO_AndAssign, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_Assign == clang::BO_Assign, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_Cmp == clang::BO_Cmp, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_Comma == clang::BO_Comma, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_Div == clang::BO_Div, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_DivAssign == clang::BO_DivAssign, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_EQ == clang::BO_EQ, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_GE == clang::BO_GE, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_GT == clang::BO_GT, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_LAnd == clang::BO_LAnd, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_LE == clang::BO_LE, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_LOr == clang::BO_LOr, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_LT == clang::BO_LT, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_Mul == clang::BO_Mul, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_MulAssign == clang::BO_MulAssign, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_NE == clang::BO_NE, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_Or == clang::BO_Or, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_OrAssign == clang::BO_OrAssign, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_PtrMemD == clang::BO_PtrMemD, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_PtrMemI == clang::BO_PtrMemI, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_Rem == clang::BO_Rem, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_RemAssign == clang::BO_RemAssign, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_Shl == clang::BO_Shl, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_ShlAssign == clang::BO_ShlAssign, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_Shr == clang::BO_Shr, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_ShrAssign == clang::BO_ShrAssign, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_Sub == clang::BO_Sub, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_SubAssign == clang::BO_SubAssign, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_Xor == clang::BO_Xor, "");
static_assert((clang::BinaryOperatorKind)ZigClangBO_XorAssign == clang::BO_XorAssign, "");
// This function detects additions to the enum
void zig2clang_UO(ZigClangUO op) {
switch (op) {
case ZigClangUO_AddrOf:
case ZigClangUO_Coawait:
case ZigClangUO_Deref:
case ZigClangUO_Extension:
case ZigClangUO_Imag:
case ZigClangUO_LNot:
case ZigClangUO_Minus:
case ZigClangUO_Not:
case ZigClangUO_Plus:
case ZigClangUO_PostDec:
case ZigClangUO_PostInc:
case ZigClangUO_PreDec:
case ZigClangUO_PreInc:
case ZigClangUO_Real:
break;
}
}
static_assert((clang::UnaryOperatorKind)ZigClangUO_AddrOf == clang::UO_AddrOf, "");
static_assert((clang::UnaryOperatorKind)ZigClangUO_Coawait == clang::UO_Coawait, "");
static_assert((clang::UnaryOperatorKind)ZigClangUO_Deref == clang::UO_Deref, "");
static_assert((clang::UnaryOperatorKind)ZigClangUO_Extension == clang::UO_Extension, "");
static_assert((clang::UnaryOperatorKind)ZigClangUO_Imag == clang::UO_Imag, "");
static_assert((clang::UnaryOperatorKind)ZigClangUO_LNot == clang::UO_LNot, "");
static_assert((clang::UnaryOperatorKind)ZigClangUO_Minus == clang::UO_Minus, "");
static_assert((clang::UnaryOperatorKind)ZigClangUO_Not == clang::UO_Not, "");
static_assert((clang::UnaryOperatorKind)ZigClangUO_Plus == clang::UO_Plus, "");
static_assert((clang::UnaryOperatorKind)ZigClangUO_PostDec == clang::UO_PostDec, "");
static_assert((clang::UnaryOperatorKind)ZigClangUO_PostInc == clang::UO_PostInc, "");
static_assert((clang::UnaryOperatorKind)ZigClangUO_PreDec == clang::UO_PreDec, "");
static_assert((clang::UnaryOperatorKind)ZigClangUO_PreInc == clang::UO_PreInc, "");
static_assert((clang::UnaryOperatorKind)ZigClangUO_Real == clang::UO_Real, "");
static_assert(sizeof(ZigClangSourceLocation) == sizeof(clang::SourceLocation), "");
static ZigClangSourceLocation bitcast(clang::SourceLocation src) {
ZigClangSourceLocation dest;
memcpy(&dest, static_cast<void *>(&src), sizeof(ZigClangSourceLocation));
return dest;
}
static clang::SourceLocation bitcast(ZigClangSourceLocation src) {
clang::SourceLocation dest;
memcpy(&dest, static_cast<void *>(&src), sizeof(ZigClangSourceLocation));
return dest;
}
static_assert(sizeof(ZigClangQualType) == sizeof(clang::QualType), "");
static ZigClangQualType bitcast(clang::QualType src) {
ZigClangQualType dest;
memcpy(&dest, static_cast<void *>(&src), sizeof(ZigClangQualType));
return dest;
}
static clang::QualType bitcast(ZigClangQualType src) {
clang::QualType dest;
memcpy(&dest, static_cast<void *>(&src), sizeof(ZigClangQualType));
return dest;
}
ZigClangSourceLocation ZigClangSourceManager_getSpellingLoc(const ZigClangSourceManager *self,
ZigClangSourceLocation Loc)
{
return bitcast(reinterpret_cast<const clang::SourceManager *>(self)->getSpellingLoc(bitcast(Loc)));
}
const char *ZigClangSourceManager_getFilename(const ZigClangSourceManager *self,
ZigClangSourceLocation SpellingLoc)
{
StringRef s = reinterpret_cast<const clang::SourceManager *>(self)->getFilename(bitcast(SpellingLoc));
return (const char *)s.bytes_begin();
}
unsigned ZigClangSourceManager_getSpellingLineNumber(const ZigClangSourceManager *self,
ZigClangSourceLocation Loc)
{
return reinterpret_cast<const clang::SourceManager *>(self)->getSpellingLineNumber(bitcast(Loc));
}
unsigned ZigClangSourceManager_getSpellingColumnNumber(const ZigClangSourceManager *self,
ZigClangSourceLocation Loc)
{
return reinterpret_cast<const clang::SourceManager *>(self)->getSpellingColumnNumber(bitcast(Loc));
}
const char* ZigClangSourceManager_getCharacterData(const ZigClangSourceManager *self,
ZigClangSourceLocation SL)
{
return reinterpret_cast<const clang::SourceManager *>(self)->getCharacterData(bitcast(SL));
}
ZigClangQualType ZigClangASTContext_getPointerType(const ZigClangASTContext* self, ZigClangQualType T) {
return bitcast(reinterpret_cast<const clang::ASTContext *>(self)->getPointerType(bitcast(T)));
}
ZigClangASTContext *ZigClangASTUnit_getASTContext(ZigClangASTUnit *self) {
clang::ASTContext *result = &reinterpret_cast<clang::ASTUnit *>(self)->getASTContext();
return reinterpret_cast<ZigClangASTContext *>(result);
}
ZigClangSourceManager *ZigClangASTUnit_getSourceManager(ZigClangASTUnit *self) {
clang::SourceManager *result = &reinterpret_cast<clang::ASTUnit *>(self)->getSourceManager();
return reinterpret_cast<ZigClangSourceManager *>(result);
}
bool ZigClangASTUnit_visitLocalTopLevelDecls(ZigClangASTUnit *self, void *context,
bool (*Fn)(void *context, const ZigClangDecl *decl))
{
return reinterpret_cast<clang::ASTUnit *>(self)->visitLocalTopLevelDecls(context,
reinterpret_cast<bool (*)(void *, const clang::Decl *)>(Fn));
}

259
src/zig_clang.h Normal file
View File

@ -0,0 +1,259 @@
/*
* Copyright (c) 2019 Andrew Kelley
*
* This file is part of zig, which is MIT licensed.
* See http://opensource.org/licenses/MIT
*/
#ifndef ZIG_ZIG_CLANG_H
#define ZIG_ZIG_CLANG_H
#ifdef __cplusplus
#define ZIG_EXTERN_C extern "C"
#else
#define ZIG_EXTERN_C
#endif
// ATTENTION: If you modify this file, be sure to update the corresponding
// extern function declarations in the self-hosted compiler.
struct ZigClangSourceLocation {
unsigned ID;
};
struct ZigClangQualType {
void *ptr;
};
struct ZigClangAPValue;
struct ZigClangASTContext;
struct ZigClangASTUnit;
struct ZigClangArraySubscriptExpr;
struct ZigClangArrayType;
struct ZigClangAttributedType;
struct ZigClangBinaryOperator;
struct ZigClangBreakStmt;
struct ZigClangBuiltinType;
struct ZigClangCStyleCastExpr;
struct ZigClangCallExpr;
struct ZigClangCaseStmt;
struct ZigClangCompoundAssignOperator;
struct ZigClangCompoundStmt;
struct ZigClangConditionalOperator;
struct ZigClangConstantArrayType;
struct ZigClangContinueStmt;
struct ZigClangDecayedType;
struct ZigClangDecl;
struct ZigClangDeclRefExpr;
struct ZigClangDeclStmt;
struct ZigClangDefaultStmt;
struct ZigClangDiagnosticOptions;
struct ZigClangDiagnosticsEngine;
struct ZigClangDoStmt;
struct ZigClangElaboratedType;
struct ZigClangEnumConstantDecl;
struct ZigClangEnumDecl;
struct ZigClangEnumType;
struct ZigClangExpr;
struct ZigClangFieldDecl;
struct ZigClangFileID;
struct ZigClangForStmt;
struct ZigClangFullSourceLoc;
struct ZigClangFunctionDecl;
struct ZigClangFunctionProtoType;
struct ZigClangIfStmt;
struct ZigClangImplicitCastExpr;
struct ZigClangIncompleteArrayType;
struct ZigClangIntegerLiteral;
struct ZigClangMacroDefinitionRecord;
struct ZigClangMemberExpr;
struct ZigClangNamedDecl;
struct ZigClangNone;
struct ZigClangPCHContainerOperations;
struct ZigClangParenExpr;
struct ZigClangParenType;
struct ZigClangParmVarDecl;
struct ZigClangPointerType;
struct ZigClangPreprocessedEntity;
struct ZigClangRecordDecl;
struct ZigClangRecordType;
struct ZigClangReturnStmt;
struct ZigClangSkipFunctionBodiesScope;
struct ZigClangSourceManager;
struct ZigClangSourceRange;
struct ZigClangStmt;
struct ZigClangStorageClass;
struct ZigClangStringLiteral;
struct ZigClangStringRef;
struct ZigClangSwitchStmt;
struct ZigClangType;
struct ZigClangTypedefNameDecl;
struct ZigClangTypedefType;
struct ZigClangUnaryExprOrTypeTraitExpr;
struct ZigClangUnaryOperator;
struct ZigClangValueDecl;
struct ZigClangVarDecl;
struct ZigClangWhileStmt;
enum ZigClangBO {
ZigClangBO_PtrMemD,
ZigClangBO_PtrMemI,
ZigClangBO_Mul,
ZigClangBO_Div,
ZigClangBO_Rem,
ZigClangBO_Add,
ZigClangBO_Sub,
ZigClangBO_Shl,
ZigClangBO_Shr,
ZigClangBO_Cmp,
ZigClangBO_LT,
ZigClangBO_GT,
ZigClangBO_LE,
ZigClangBO_GE,
ZigClangBO_EQ,
ZigClangBO_NE,
ZigClangBO_And,
ZigClangBO_Xor,
ZigClangBO_Or,
ZigClangBO_LAnd,
ZigClangBO_LOr,
ZigClangBO_Assign,
ZigClangBO_MulAssign,
ZigClangBO_DivAssign,
ZigClangBO_RemAssign,
ZigClangBO_AddAssign,
ZigClangBO_SubAssign,
ZigClangBO_ShlAssign,
ZigClangBO_ShrAssign,
ZigClangBO_AndAssign,
ZigClangBO_XorAssign,
ZigClangBO_OrAssign,
ZigClangBO_Comma,
};
enum ZigClangUO {
ZigClangUO_PostInc,
ZigClangUO_PostDec,
ZigClangUO_PreInc,
ZigClangUO_PreDec,
ZigClangUO_AddrOf,
ZigClangUO_Deref,
ZigClangUO_Plus,
ZigClangUO_Minus,
ZigClangUO_Not,
ZigClangUO_LNot,
ZigClangUO_Real,
ZigClangUO_Imag,
ZigClangUO_Extension,
ZigClangUO_Coawait,
};
//struct ZigClangCC_AAPCS;
//struct ZigClangCC_AAPCS_VFP;
//struct ZigClangCC_C;
//struct ZigClangCC_IntelOclBicc;
//struct ZigClangCC_OpenCLKernel;
//struct ZigClangCC_PreserveAll;
//struct ZigClangCC_PreserveMost;
//struct ZigClangCC_SpirFunction;
//struct ZigClangCC_Swift;
//struct ZigClangCC_Win64;
//struct ZigClangCC_X86FastCall;
//struct ZigClangCC_X86Pascal;
//struct ZigClangCC_X86RegCall;
//struct ZigClangCC_X86StdCall;
//struct ZigClangCC_X86ThisCall;
//struct ZigClangCC_X86VectorCall;
//struct ZigClangCC_X86_64SysV;
//struct ZigClangCK_ARCConsumeObject;
//struct ZigClangCK_ARCExtendBlockObject;
//struct ZigClangCK_ARCProduceObject;
//struct ZigClangCK_ARCReclaimReturnedObject;
//struct ZigClangCK_AddressSpaceConversion;
//struct ZigClangCK_AnyPointerToBlockPointerCast;
//struct ZigClangCK_ArrayToPointerDecay;
//struct ZigClangCK_AtomicToNonAtomic;
//struct ZigClangCK_BaseToDerived;
//struct ZigClangCK_BaseToDerivedMemberPointer;
//struct ZigClangCK_BitCast;
//struct ZigClangCK_BlockPointerToObjCPointerCast;
//struct ZigClangCK_BooleanToSignedIntegral;
//struct ZigClangCK_BuiltinFnToFnPtr;
//struct ZigClangCK_CPointerToObjCPointerCast;
//struct ZigClangCK_ConstructorConversion;
//struct ZigClangCK_CopyAndAutoreleaseBlockObject;
//struct ZigClangCK_Dependent;
//struct ZigClangCK_DerivedToBase;
//struct ZigClangCK_DerivedToBaseMemberPointer;
//struct ZigClangCK_Dynamic;
//struct ZigClangCK_FloatingCast;
//struct ZigClangCK_FloatingComplexCast;
//struct ZigClangCK_FloatingComplexToBoolean;
//struct ZigClangCK_FloatingComplexToIntegralComplex;
//struct ZigClangCK_FloatingComplexToReal;
//struct ZigClangCK_FloatingRealToComplex;
//struct ZigClangCK_FloatingToBoolean;
//struct ZigClangCK_FloatingToIntegral;
//struct ZigClangCK_FunctionToPointerDecay;
//struct ZigClangCK_IntToOCLSampler;
//struct ZigClangCK_IntegralCast;
//struct ZigClangCK_IntegralComplexCast;
//struct ZigClangCK_IntegralComplexToBoolean;
//struct ZigClangCK_IntegralComplexToFloatingComplex;
//struct ZigClangCK_IntegralComplexToReal;
//struct ZigClangCK_IntegralRealToComplex;
//struct ZigClangCK_IntegralToBoolean;
//struct ZigClangCK_IntegralToFloating;
//struct ZigClangCK_IntegralToPointer;
//struct ZigClangCK_LValueBitCast;
//struct ZigClangCK_LValueToRValue;
//struct ZigClangCK_MemberPointerToBoolean;
//struct ZigClangCK_NoOp;
//struct ZigClangCK_NonAtomicToAtomic;
//struct ZigClangCK_NullToMemberPointer;
//struct ZigClangCK_NullToPointer;
//struct ZigClangCK_ObjCObjectLValueCast;
//struct ZigClangCK_PointerToBoolean;
//struct ZigClangCK_PointerToIntegral;
//struct ZigClangCK_ReinterpretMemberPointer;
//struct ZigClangCK_ToUnion;
//struct ZigClangCK_ToVoid;
//struct ZigClangCK_UncheckedDerivedToBase;
//struct ZigClangCK_UserDefinedConversion;
//struct ZigClangCK_VectorSplat;
//struct ZigClangCK_ZeroToOCLEvent;
//struct ZigClangCK_ZeroToOCLQueue;
//struct ZigClangETK_Class;
//struct ZigClangETK_Enum;
//struct ZigClangETK_Interface;
//struct ZigClangETK_None;
//struct ZigClangETK_Struct;
//struct ZigClangETK_Typename;
//struct ZigClangETK_Union;
//struct ZigClangSC_None;
//struct ZigClangSC_PrivateExtern;
//struct ZigClangSC_Static;
//struct ZigClangTU_Complete;
ZIG_EXTERN_C ZigClangSourceLocation ZigClangSourceManager_getSpellingLoc(const ZigClangSourceManager *,
ZigClangSourceLocation Loc);
ZIG_EXTERN_C const char *ZigClangSourceManager_getFilename(const ZigClangSourceManager *,
ZigClangSourceLocation SpellingLoc);
ZIG_EXTERN_C unsigned ZigClangSourceManager_getSpellingLineNumber(const ZigClangSourceManager *,
ZigClangSourceLocation Loc);
ZIG_EXTERN_C unsigned ZigClangSourceManager_getSpellingColumnNumber(const ZigClangSourceManager *,
ZigClangSourceLocation Loc);
ZIG_EXTERN_C const char* ZigClangSourceManager_getCharacterData(const ZigClangSourceManager *,
ZigClangSourceLocation SL);
ZIG_EXTERN_C ZigClangQualType ZigClangASTContext_getPointerType(const ZigClangASTContext*, ZigClangQualType T);
ZIG_EXTERN_C ZigClangASTContext *ZigClangASTUnit_getASTContext(ZigClangASTUnit *);
ZIG_EXTERN_C ZigClangSourceManager *ZigClangASTUnit_getSourceManager(ZigClangASTUnit *);
ZIG_EXTERN_C bool ZigClangASTUnit_visitLocalTopLevelDecls(ZigClangASTUnit *, void *context,
bool (*Fn)(void *context, const ZigClangDecl *decl));
#endif

226
src/zig_clang_cc1_main.cpp Normal file
View File

@ -0,0 +1,226 @@
//===-- cc1_main.cpp - Clang CC1 Compiler Frontend ------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This is the entry point to the clang -cc1 functionality, which implements the
// core compiler functionality along with a number of additional tools for
// demonstration and testing purposes.
//
//===----------------------------------------------------------------------===//
#include "llvm/Option/Arg.h"
#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
#include "clang/Config/config.h"
#include "clang/Basic/Stack.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/TextDiagnosticBuffer.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/Utils.h"
#include "clang/FrontendTool/Utils.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/LinkAllPasses.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdio>
#ifdef CLANG_HAVE_RLIMITS
#include <sys/resource.h>
#endif
using namespace clang;
using namespace llvm::opt;
//===----------------------------------------------------------------------===//
// Main driver
//===----------------------------------------------------------------------===//
static void LLVMErrorHandler(void *UserData, const std::string &Message,
bool GenCrashDiag) {
DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData);
Diags.Report(diag::err_fe_error_backend) << Message;
// Run the interrupt handlers to make sure any special cleanups get done, in
// particular that we remove files registered with RemoveFileOnSignal.
llvm::sys::RunInterruptHandlers();
// We cannot recover from llvm errors. When reporting a fatal error, exit
// with status 70 to generate crash diagnostics. For BSD systems this is
// defined as an internal software error. Otherwise, exit with status 1.
exit(GenCrashDiag ? 70 : 1);
}
#ifdef CLANG_HAVE_RLIMITS
#if defined(__linux__) && defined(__PIE__)
static size_t getCurrentStackAllocation() {
// If we can't compute the current stack usage, allow for 512K of command
// line arguments and environment.
size_t Usage = 512 * 1024;
if (FILE *StatFile = fopen("/proc/self/stat", "r")) {
// We assume that the stack extends from its current address to the end of
// the environment space. In reality, there is another string literal (the
// program name) after the environment, but this is close enough (we only
// need to be within 100K or so).
unsigned long StackPtr, EnvEnd;
// Disable silly GCC -Wformat warning that complains about length
// modifiers on ignored format specifiers. We want to retain these
// for documentation purposes even though they have no effect.
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
#endif
if (fscanf(StatFile,
"%*d %*s %*c %*d %*d %*d %*d %*d %*u %*lu %*lu %*lu %*lu %*lu "
"%*lu %*ld %*ld %*ld %*ld %*ld %*ld %*llu %*lu %*ld %*lu %*lu "
"%*lu %*lu %lu %*lu %*lu %*lu %*lu %*lu %*llu %*lu %*lu %*d %*d "
"%*u %*u %*llu %*lu %*ld %*lu %*lu %*lu %*lu %*lu %*lu %lu %*d",
&StackPtr, &EnvEnd) == 2) {
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
Usage = StackPtr < EnvEnd ? EnvEnd - StackPtr : StackPtr - EnvEnd;
}
fclose(StatFile);
}
return Usage;
}
#include <alloca.h>
LLVM_ATTRIBUTE_NOINLINE
static void ensureStackAddressSpace() {
// Linux kernels prior to 4.1 will sometimes locate the heap of a PIE binary
// relatively close to the stack (they are only guaranteed to be 128MiB
// apart). This results in crashes if we happen to heap-allocate more than
// 128MiB before we reach our stack high-water mark.
//
// To avoid these crashes, ensure that we have sufficient virtual memory
// pages allocated before we start running.
size_t Curr = getCurrentStackAllocation();
const int kTargetStack = DesiredStackSize - 256 * 1024;
if (Curr < kTargetStack) {
volatile char *volatile Alloc =
static_cast<volatile char *>(alloca(kTargetStack - Curr));
Alloc[0] = 0;
Alloc[kTargetStack - Curr - 1] = 0;
}
}
#else
static void ensureStackAddressSpace() {}
#endif
/// Attempt to ensure that we have at least 8MiB of usable stack space.
static void ensureSufficientStack() {
struct rlimit rlim;
if (getrlimit(RLIMIT_STACK, &rlim) != 0)
return;
// Increase the soft stack limit to our desired level, if necessary and
// possible.
if (rlim.rlim_cur != RLIM_INFINITY &&
rlim.rlim_cur < rlim_t(DesiredStackSize)) {
// Try to allocate sufficient stack.
if (rlim.rlim_max == RLIM_INFINITY ||
rlim.rlim_max >= rlim_t(DesiredStackSize))
rlim.rlim_cur = DesiredStackSize;
else if (rlim.rlim_cur == rlim.rlim_max)
return;
else
rlim.rlim_cur = rlim.rlim_max;
if (setrlimit(RLIMIT_STACK, &rlim) != 0 ||
rlim.rlim_cur != DesiredStackSize)
return;
}
// We should now have a stack of size at least DesiredStackSize. Ensure
// that we can actually use that much, if necessary.
ensureStackAddressSpace();
}
#else
static void ensureSufficientStack() {}
#endif
int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
ensureSufficientStack();
std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
// Register the support for object-file-wrapped Clang modules.
auto PCHOps = Clang->getPCHContainerOperations();
PCHOps->registerWriter(llvm::make_unique<ObjectFilePCHContainerWriter>());
PCHOps->registerReader(llvm::make_unique<ObjectFilePCHContainerReader>());
// Initialize targets first, so that --version shows registered targets.
llvm::InitializeAllTargets();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllAsmPrinters();
llvm::InitializeAllAsmParsers();
// Buffer diagnostics from argument parsing so that we can output them using a
// well formed diagnostic object.
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
bool Success = CompilerInvocation::CreateFromArgs(
Clang->getInvocation(), Argv.begin(), Argv.end(), Diags);
// Infer the builtin include path if unspecified.
if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
Clang->getHeaderSearchOpts().ResourceDir.empty())
Clang->getHeaderSearchOpts().ResourceDir =
CompilerInvocation::GetResourcesPath(Argv0, MainAddr);
// Create the actual diagnostics engine.
Clang->createDiagnostics();
if (!Clang->hasDiagnostics())
return 1;
// Set an error handler, so that any LLVM backend diagnostics go through our
// error handler.
llvm::install_fatal_error_handler(LLVMErrorHandler,
static_cast<void*>(&Clang->getDiagnostics()));
DiagsBuffer->FlushDiagnostics(Clang->getDiagnostics());
if (!Success)
return 1;
// Execute the frontend actions.
Success = ExecuteCompilerInvocation(Clang.get());
// If any timers were active but haven't been destroyed yet, print their
// results now. This happens in -disable-free mode.
llvm::TimerGroup::printAll(llvm::errs());
// Our error handler depends on the Diagnostics object, which we're
// potentially about to delete. Uninstall the handler now so that any
// later errors use the default handling behavior instead.
llvm::remove_fatal_error_handler();
// When running with -disable-free, don't do any destruction or shutdown.
if (Clang->getFrontendOpts().DisableFree) {
BuryPointer(std::move(Clang));
return !Success;
}
return !Success;
}

View File

@ -0,0 +1,573 @@
//===-- cc1as_main.cpp - Clang Assembler ---------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This is the entry point to the clang -cc1as functionality, which implements
// the direct interface to the LLVM MC based assembler.
//
//===----------------------------------------------------------------------===//
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/Utils.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCParser/MCAsmParser.h"
#include "llvm/MC/MCParser/MCTargetAsmParser.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCTargetOptions.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
#include <system_error>
using namespace clang;
using namespace clang::driver;
using namespace clang::driver::options;
using namespace llvm;
using namespace llvm::opt;
namespace {
/// Helper class for representing a single invocation of the assembler.
struct AssemblerInvocation {
/// @name Target Options
/// @{
/// The name of the target triple to assemble for.
std::string Triple;
/// If given, the name of the target CPU to determine which instructions
/// are legal.
std::string CPU;
/// The list of target specific features to enable or disable -- this should
/// be a list of strings starting with '+' or '-'.
std::vector<std::string> Features;
/// The list of symbol definitions.
std::vector<std::string> SymbolDefs;
/// @}
/// @name Language Options
/// @{
std::vector<std::string> IncludePaths;
unsigned NoInitialTextSection : 1;
unsigned SaveTemporaryLabels : 1;
unsigned GenDwarfForAssembly : 1;
unsigned RelaxELFRelocations : 1;
unsigned DwarfVersion;
std::string DwarfDebugFlags;
std::string DwarfDebugProducer;
std::string DebugCompilationDir;
std::map<const std::string, const std::string> DebugPrefixMap;
llvm::DebugCompressionType CompressDebugSections =
llvm::DebugCompressionType::None;
std::string MainFileName;
std::string SplitDwarfFile;
/// @}
/// @name Frontend Options
/// @{
std::string InputFile;
std::vector<std::string> LLVMArgs;
std::string OutputPath;
enum FileType {
FT_Asm, ///< Assembly (.s) output, transliterate mode.
FT_Null, ///< No output, for timing purposes.
FT_Obj ///< Object file output.
};
FileType OutputType;
unsigned ShowHelp : 1;
unsigned ShowVersion : 1;
/// @}
/// @name Transliterate Options
/// @{
unsigned OutputAsmVariant;
unsigned ShowEncoding : 1;
unsigned ShowInst : 1;
/// @}
/// @name Assembler Options
/// @{
unsigned RelaxAll : 1;
unsigned NoExecStack : 1;
unsigned FatalWarnings : 1;
unsigned IncrementalLinkerCompatible : 1;
/// The name of the relocation model to use.
std::string RelocationModel;
/// @}
public:
AssemblerInvocation() {
Triple = "";
NoInitialTextSection = 0;
InputFile = "-";
OutputPath = "-";
OutputType = FT_Asm;
OutputAsmVariant = 0;
ShowInst = 0;
ShowEncoding = 0;
RelaxAll = 0;
NoExecStack = 0;
FatalWarnings = 0;
IncrementalLinkerCompatible = 0;
DwarfVersion = 0;
}
static bool CreateFromArgs(AssemblerInvocation &Res,
ArrayRef<const char *> Argv,
DiagnosticsEngine &Diags);
};
}
bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
ArrayRef<const char *> Argv,
DiagnosticsEngine &Diags) {
bool Success = true;
// Parse the arguments.
std::unique_ptr<OptTable> OptTbl(createDriverOptTable());
const unsigned IncludedFlagsBitmask = options::CC1AsOption;
unsigned MissingArgIndex, MissingArgCount;
InputArgList Args = OptTbl->ParseArgs(Argv, MissingArgIndex, MissingArgCount,
IncludedFlagsBitmask);
// Check for missing argument error.
if (MissingArgCount) {
Diags.Report(diag::err_drv_missing_argument)
<< Args.getArgString(MissingArgIndex) << MissingArgCount;
Success = false;
}
// Issue errors on unknown arguments.
for (const Arg *A : Args.filtered(OPT_UNKNOWN)) {
auto ArgString = A->getAsString(Args);
std::string Nearest;
if (OptTbl->findNearest(ArgString, Nearest, IncludedFlagsBitmask) > 1)
Diags.Report(diag::err_drv_unknown_argument) << ArgString;
else
Diags.Report(diag::err_drv_unknown_argument_with_suggestion)
<< ArgString << Nearest;
Success = false;
}
// Construct the invocation.
// Target Options
Opts.Triple = llvm::Triple::normalize(Args.getLastArgValue(OPT_triple));
Opts.CPU = Args.getLastArgValue(OPT_target_cpu);
Opts.Features = Args.getAllArgValues(OPT_target_feature);
// Use the default target triple if unspecified.
if (Opts.Triple.empty())
Opts.Triple = llvm::sys::getDefaultTargetTriple();
// Language Options
Opts.IncludePaths = Args.getAllArgValues(OPT_I);
Opts.NoInitialTextSection = Args.hasArg(OPT_n);
Opts.SaveTemporaryLabels = Args.hasArg(OPT_msave_temp_labels);
// Any DebugInfoKind implies GenDwarfForAssembly.
Opts.GenDwarfForAssembly = Args.hasArg(OPT_debug_info_kind_EQ);
if (const Arg *A = Args.getLastArg(OPT_compress_debug_sections,
OPT_compress_debug_sections_EQ)) {
if (A->getOption().getID() == OPT_compress_debug_sections) {
// TODO: be more clever about the compression type auto-detection
Opts.CompressDebugSections = llvm::DebugCompressionType::GNU;
} else {
Opts.CompressDebugSections =
llvm::StringSwitch<llvm::DebugCompressionType>(A->getValue())
.Case("none", llvm::DebugCompressionType::None)
.Case("zlib", llvm::DebugCompressionType::Z)
.Case("zlib-gnu", llvm::DebugCompressionType::GNU)
.Default(llvm::DebugCompressionType::None);
}
}
Opts.RelaxELFRelocations = Args.hasArg(OPT_mrelax_relocations);
Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 2, Diags);
Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags);
Opts.DwarfDebugProducer = Args.getLastArgValue(OPT_dwarf_debug_producer);
Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir);
Opts.MainFileName = Args.getLastArgValue(OPT_main_file_name);
for (const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ))
Opts.DebugPrefixMap.insert(StringRef(Arg).split('='));
// Frontend Options
if (Args.hasArg(OPT_INPUT)) {
bool First = true;
for (const Arg *A : Args.filtered(OPT_INPUT)) {
if (First) {
Opts.InputFile = A->getValue();
First = false;
} else {
Diags.Report(diag::err_drv_unknown_argument) << A->getAsString(Args);
Success = false;
}
}
}
Opts.LLVMArgs = Args.getAllArgValues(OPT_mllvm);
Opts.OutputPath = Args.getLastArgValue(OPT_o);
Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file);
if (Arg *A = Args.getLastArg(OPT_filetype)) {
StringRef Name = A->getValue();
unsigned OutputType = StringSwitch<unsigned>(Name)
.Case("asm", FT_Asm)
.Case("null", FT_Null)
.Case("obj", FT_Obj)
.Default(~0U);
if (OutputType == ~0U) {
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
Success = false;
} else
Opts.OutputType = FileType(OutputType);
}
Opts.ShowHelp = Args.hasArg(OPT_help);
Opts.ShowVersion = Args.hasArg(OPT_version);
// Transliterate Options
Opts.OutputAsmVariant =
getLastArgIntValue(Args, OPT_output_asm_variant, 0, Diags);
Opts.ShowEncoding = Args.hasArg(OPT_show_encoding);
Opts.ShowInst = Args.hasArg(OPT_show_inst);
// Assemble Options
Opts.RelaxAll = Args.hasArg(OPT_mrelax_all);
Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack);
Opts.FatalWarnings = Args.hasArg(OPT_massembler_fatal_warnings);
Opts.RelocationModel = Args.getLastArgValue(OPT_mrelocation_model, "pic");
Opts.IncrementalLinkerCompatible =
Args.hasArg(OPT_mincremental_linker_compatible);
Opts.SymbolDefs = Args.getAllArgValues(OPT_defsym);
return Success;
}
static std::unique_ptr<raw_fd_ostream>
getOutputStream(StringRef Path, DiagnosticsEngine &Diags, bool Binary) {
// Make sure that the Out file gets unlinked from the disk if we get a
// SIGINT.
if (Path != "-")
sys::RemoveFileOnSignal(Path);
std::error_code EC;
auto Out = llvm::make_unique<raw_fd_ostream>(
Path, EC, (Binary ? sys::fs::F_None : sys::fs::F_Text));
if (EC) {
Diags.Report(diag::err_fe_unable_to_open_output) << Path << EC.message();
return nullptr;
}
return Out;
}
static bool ExecuteAssembler(AssemblerInvocation &Opts,
DiagnosticsEngine &Diags) {
// Get the target specific parser.
std::string Error;
const Target *TheTarget = TargetRegistry::lookupTarget(Opts.Triple, Error);
if (!TheTarget)
return Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
MemoryBuffer::getFileOrSTDIN(Opts.InputFile);
if (std::error_code EC = Buffer.getError()) {
Error = EC.message();
return Diags.Report(diag::err_fe_error_reading) << Opts.InputFile;
}
SourceMgr SrcMgr;
// Tell SrcMgr about this buffer, which is what the parser will pick up.
SrcMgr.AddNewSourceBuffer(std::move(*Buffer), SMLoc());
// Record the location of the include directories so that the lexer can find
// it later.
SrcMgr.setIncludeDirs(Opts.IncludePaths);
std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(Opts.Triple));
assert(MRI && "Unable to create target register info!");
std::unique_ptr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, Opts.Triple));
assert(MAI && "Unable to create target asm info!");
// Ensure MCAsmInfo initialization occurs before any use, otherwise sections
// may be created with a combination of default and explicit settings.
MAI->setCompressDebugSections(Opts.CompressDebugSections);
MAI->setRelaxELFRelocations(Opts.RelaxELFRelocations);
bool IsBinary = Opts.OutputType == AssemblerInvocation::FT_Obj;
if (Opts.OutputPath.empty())
Opts.OutputPath = "-";
std::unique_ptr<raw_fd_ostream> FDOS =
getOutputStream(Opts.OutputPath, Diags, IsBinary);
if (!FDOS)
return true;
std::unique_ptr<raw_fd_ostream> DwoOS;
if (!Opts.SplitDwarfFile.empty())
DwoOS = getOutputStream(Opts.SplitDwarfFile, Diags, IsBinary);
// FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
// MCObjectFileInfo needs a MCContext reference in order to initialize itself.
std::unique_ptr<MCObjectFileInfo> MOFI(new MCObjectFileInfo());
MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &SrcMgr);
bool PIC = false;
if (Opts.RelocationModel == "static") {
PIC = false;
} else if (Opts.RelocationModel == "pic") {
PIC = true;
} else {
assert(Opts.RelocationModel == "dynamic-no-pic" &&
"Invalid PIC model!");
PIC = false;
}
MOFI->InitMCObjectFileInfo(Triple(Opts.Triple), PIC, Ctx);
if (Opts.SaveTemporaryLabels)
Ctx.setAllowTemporaryLabels(false);
if (Opts.GenDwarfForAssembly)
Ctx.setGenDwarfForAssembly(true);
if (!Opts.DwarfDebugFlags.empty())
Ctx.setDwarfDebugFlags(StringRef(Opts.DwarfDebugFlags));
if (!Opts.DwarfDebugProducer.empty())
Ctx.setDwarfDebugProducer(StringRef(Opts.DwarfDebugProducer));
if (!Opts.DebugCompilationDir.empty())
Ctx.setCompilationDir(Opts.DebugCompilationDir);
if (!Opts.DebugPrefixMap.empty())
for (const auto &KV : Opts.DebugPrefixMap)
Ctx.addDebugPrefixMapEntry(KV.first, KV.second);
if (!Opts.MainFileName.empty())
Ctx.setMainFileName(StringRef(Opts.MainFileName));
Ctx.setDwarfVersion(Opts.DwarfVersion);
// Build up the feature string from the target feature list.
std::string FS;
if (!Opts.Features.empty()) {
FS = Opts.Features[0];
for (unsigned i = 1, e = Opts.Features.size(); i != e; ++i)
FS += "," + Opts.Features[i];
}
std::unique_ptr<MCStreamer> Str;
std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
std::unique_ptr<MCSubtargetInfo> STI(
TheTarget->createMCSubtargetInfo(Opts.Triple, Opts.CPU, FS));
raw_pwrite_stream *Out = FDOS.get();
std::unique_ptr<buffer_ostream> BOS;
// FIXME: There is a bit of code duplication with addPassesToEmitFile.
if (Opts.OutputType == AssemblerInvocation::FT_Asm) {
MCInstPrinter *IP = TheTarget->createMCInstPrinter(
llvm::Triple(Opts.Triple), Opts.OutputAsmVariant, *MAI, *MCII, *MRI);
std::unique_ptr<MCCodeEmitter> CE;
if (Opts.ShowEncoding)
CE.reset(TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx));
MCTargetOptions MCOptions;
std::unique_ptr<MCAsmBackend> MAB(
TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
auto FOut = llvm::make_unique<formatted_raw_ostream>(*Out);
Str.reset(TheTarget->createAsmStreamer(
Ctx, std::move(FOut), /*asmverbose*/ true,
/*useDwarfDirectory*/ true, IP, std::move(CE), std::move(MAB),
Opts.ShowInst));
} else if (Opts.OutputType == AssemblerInvocation::FT_Null) {
Str.reset(createNullStreamer(Ctx));
} else {
assert(Opts.OutputType == AssemblerInvocation::FT_Obj &&
"Invalid file type!");
if (!FDOS->supportsSeeking()) {
BOS = make_unique<buffer_ostream>(*FDOS);
Out = BOS.get();
}
std::unique_ptr<MCCodeEmitter> CE(
TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx));
MCTargetOptions MCOptions;
std::unique_ptr<MCAsmBackend> MAB(
TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
std::unique_ptr<MCObjectWriter> OW =
DwoOS ? MAB->createDwoObjectWriter(*Out, *DwoOS)
: MAB->createObjectWriter(*Out);
Triple T(Opts.Triple);
Str.reset(TheTarget->createMCObjectStreamer(
T, Ctx, std::move(MAB), std::move(OW), std::move(CE), *STI,
Opts.RelaxAll, Opts.IncrementalLinkerCompatible,
/*DWARFMustBeAtTheEnd*/ true));
Str.get()->InitSections(Opts.NoExecStack);
}
// Assembly to object compilation should leverage assembly info.
Str->setUseAssemblerInfoForParsing(true);
bool Failed = false;
std::unique_ptr<MCAsmParser> Parser(
createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI));
// FIXME: init MCTargetOptions from sanitizer flags here.
MCTargetOptions Options;
std::unique_ptr<MCTargetAsmParser> TAP(
TheTarget->createMCAsmParser(*STI, *Parser, *MCII, Options));
if (!TAP)
Failed = Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
// Set values for symbols, if any.
for (auto &S : Opts.SymbolDefs) {
auto Pair = StringRef(S).split('=');
auto Sym = Pair.first;
auto Val = Pair.second;
int64_t Value;
// We have already error checked this in the driver.
Val.getAsInteger(0, Value);
Ctx.setSymbolValue(Parser->getStreamer(), Sym, Value);
}
if (!Failed) {
Parser->setTargetParser(*TAP.get());
Failed = Parser->Run(Opts.NoInitialTextSection);
}
// Close Streamer first.
// It might have a reference to the output stream.
Str.reset();
// Close the output stream early.
BOS.reset();
FDOS.reset();
// Delete output file if there were errors.
if (Failed) {
if (Opts.OutputPath != "-")
sys::fs::remove(Opts.OutputPath);
if (!Opts.SplitDwarfFile.empty() && Opts.SplitDwarfFile != "-")
sys::fs::remove(Opts.SplitDwarfFile);
}
return Failed;
}
static void LLVMErrorHandler(void *UserData, const std::string &Message,
bool GenCrashDiag) {
DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData);
Diags.Report(diag::err_fe_error_backend) << Message;
// We cannot recover from llvm errors.
exit(1);
}
int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
// Initialize targets and assembly printers/parsers.
InitializeAllTargetInfos();
InitializeAllTargetMCs();
InitializeAllAsmParsers();
// Construct our diagnostic client.
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
TextDiagnosticPrinter *DiagClient
= new TextDiagnosticPrinter(errs(), &*DiagOpts);
DiagClient->setPrefix("clang -cc1as");
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
// Set an error handler, so that any LLVM backend diagnostics go through our
// error handler.
ScopedFatalErrorHandler FatalErrorHandler
(LLVMErrorHandler, static_cast<void*>(&Diags));
// Parse the arguments.
AssemblerInvocation Asm;
if (!AssemblerInvocation::CreateFromArgs(Asm, Argv, Diags))
return 1;
if (Asm.ShowHelp) {
std::unique_ptr<OptTable> Opts(driver::createDriverOptTable());
Opts->PrintHelp(llvm::outs(), "clang -cc1as", "Clang Integrated Assembler",
/*Include=*/driver::options::CC1AsOption, /*Exclude=*/0,
/*ShowAllAliases=*/false);
return 0;
}
// Honor -version.
//
// FIXME: Use a better -version message?
if (Asm.ShowVersion) {
llvm::cl::PrintVersionMessage();
return 0;
}
// Honor -mllvm.
//
// FIXME: Remove this, one day.
if (!Asm.LLVMArgs.empty()) {
unsigned NumArgs = Asm.LLVMArgs.size();
auto Args = llvm::make_unique<const char*[]>(NumArgs + 2);
Args[0] = "clang (LLVM option parsing)";
for (unsigned i = 0; i != NumArgs; ++i)
Args[i + 1] = Asm.LLVMArgs[i].c_str();
Args[NumArgs + 1] = nullptr;
llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get());
}
// Execute the invocation, unless there were parsing errors.
bool Failed = Diags.hasErrorOccurred() || ExecuteAssembler(Asm, Diags);
// If any timers were active but haven't been destroyed yet, print their
// results now.
TimerGroup::printAll(errs());
return !!Failed;
}

513
src/zig_clang_driver.cpp Normal file
View File

@ -0,0 +1,513 @@
//===-- driver.cpp - Clang GCC-Compatible Driver --------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This is the entry point to the clang driver; it is a thin wrapper
// for functionality in the Driver clang library.
//
//===----------------------------------------------------------------------===//
#include "clang/Driver/Driver.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/ToolChain.h"
#include "clang/Frontend/ChainedDiagnosticConsumer.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/SerializedDiagnosticPrinter.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/Utils.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/StringSaver.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
#include <set>
#include <system_error>
using namespace clang;
using namespace clang::driver;
using namespace llvm::opt;
std::string GetExecutablePath(const char *Argv0, bool CanonicalPrefixes) {
if (!CanonicalPrefixes) {
SmallString<128> ExecutablePath(Argv0);
// Do a PATH lookup if Argv0 isn't a valid path.
if (!llvm::sys::fs::exists(ExecutablePath))
if (llvm::ErrorOr<std::string> P =
llvm::sys::findProgramByName(ExecutablePath))
ExecutablePath = *P;
return ExecutablePath.str();
}
// This just needs to be some symbol in the binary; C++ doesn't
// allow taking the address of ::main however.
void *P = (void*) (intptr_t) GetExecutablePath;
return llvm::sys::fs::getMainExecutable(Argv0, P);
}
static const char *GetStableCStr(std::set<std::string> &SavedStrings,
StringRef S) {
return SavedStrings.insert(S).first->c_str();
}
/// ApplyQAOverride - Apply a list of edits to the input argument lists.
///
/// The input string is a space separate list of edits to perform,
/// they are applied in order to the input argument lists. Edits
/// should be one of the following forms:
///
/// '#': Silence information about the changes to the command line arguments.
///
/// '^': Add FOO as a new argument at the beginning of the command line.
///
/// '+': Add FOO as a new argument at the end of the command line.
///
/// 's/XXX/YYY/': Substitute the regular expression XXX with YYY in the command
/// line.
///
/// 'xOPTION': Removes all instances of the literal argument OPTION.
///
/// 'XOPTION': Removes all instances of the literal argument OPTION,
/// and the following argument.
///
/// 'Ox': Removes all flags matching 'O' or 'O[sz0-9]' and adds 'Ox'
/// at the end of the command line.
///
/// \param OS - The stream to write edit information to.
/// \param Args - The vector of command line arguments.
/// \param Edit - The override command to perform.
/// \param SavedStrings - Set to use for storing string representations.
static void ApplyOneQAOverride(raw_ostream &OS,
SmallVectorImpl<const char*> &Args,
StringRef Edit,
std::set<std::string> &SavedStrings) {
// This does not need to be efficient.
if (Edit[0] == '^') {
const char *Str =
GetStableCStr(SavedStrings, Edit.substr(1));
OS << "### Adding argument " << Str << " at beginning\n";
Args.insert(Args.begin() + 1, Str);
} else if (Edit[0] == '+') {
const char *Str =
GetStableCStr(SavedStrings, Edit.substr(1));
OS << "### Adding argument " << Str << " at end\n";
Args.push_back(Str);
} else if (Edit[0] == 's' && Edit[1] == '/' && Edit.endswith("/") &&
Edit.slice(2, Edit.size()-1).find('/') != StringRef::npos) {
StringRef MatchPattern = Edit.substr(2).split('/').first;
StringRef ReplPattern = Edit.substr(2).split('/').second;
ReplPattern = ReplPattern.slice(0, ReplPattern.size()-1);
for (unsigned i = 1, e = Args.size(); i != e; ++i) {
// Ignore end-of-line response file markers
if (Args[i] == nullptr)
continue;
std::string Repl = llvm::Regex(MatchPattern).sub(ReplPattern, Args[i]);
if (Repl != Args[i]) {
OS << "### Replacing '" << Args[i] << "' with '" << Repl << "'\n";
Args[i] = GetStableCStr(SavedStrings, Repl);
}
}
} else if (Edit[0] == 'x' || Edit[0] == 'X') {
auto Option = Edit.substr(1);
for (unsigned i = 1; i < Args.size();) {
if (Option == Args[i]) {
OS << "### Deleting argument " << Args[i] << '\n';
Args.erase(Args.begin() + i);
if (Edit[0] == 'X') {
if (i < Args.size()) {
OS << "### Deleting argument " << Args[i] << '\n';
Args.erase(Args.begin() + i);
} else
OS << "### Invalid X edit, end of command line!\n";
}
} else
++i;
}
} else if (Edit[0] == 'O') {
for (unsigned i = 1; i < Args.size();) {
const char *A = Args[i];
// Ignore end-of-line response file markers
if (A == nullptr)
continue;
if (A[0] == '-' && A[1] == 'O' &&
(A[2] == '\0' ||
(A[3] == '\0' && (A[2] == 's' || A[2] == 'z' ||
('0' <= A[2] && A[2] <= '9'))))) {
OS << "### Deleting argument " << Args[i] << '\n';
Args.erase(Args.begin() + i);
} else
++i;
}
OS << "### Adding argument " << Edit << " at end\n";
Args.push_back(GetStableCStr(SavedStrings, '-' + Edit.str()));
} else {
OS << "### Unrecognized edit: " << Edit << "\n";
}
}
/// ApplyQAOverride - Apply a comma separate list of edits to the
/// input argument lists. See ApplyOneQAOverride.
static void ApplyQAOverride(SmallVectorImpl<const char*> &Args,
const char *OverrideStr,
std::set<std::string> &SavedStrings) {
raw_ostream *OS = &llvm::errs();
if (OverrideStr[0] == '#') {
++OverrideStr;
OS = &llvm::nulls();
}
*OS << "### CCC_OVERRIDE_OPTIONS: " << OverrideStr << "\n";
// This does not need to be efficient.
const char *S = OverrideStr;
while (*S) {
const char *End = ::strchr(S, ' ');
if (!End)
End = S + strlen(S);
if (End != S)
ApplyOneQAOverride(*OS, Args, std::string(S, End), SavedStrings);
S = End;
if (*S != '\0')
++S;
}
}
extern int cc1_main(ArrayRef<const char *> Argv, const char *Argv0,
void *MainAddr);
extern int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0,
void *MainAddr);
static void insertTargetAndModeArgs(const ParsedClangName &NameParts,
SmallVectorImpl<const char *> &ArgVector,
std::set<std::string> &SavedStrings) {
// Put target and mode arguments at the start of argument list so that
// arguments specified in command line could override them. Avoid putting
// them at index 0, as an option like '-cc1' must remain the first.
int InsertionPoint = 0;
if (ArgVector.size() > 0)
++InsertionPoint;
if (NameParts.DriverMode) {
// Add the mode flag to the arguments.
ArgVector.insert(ArgVector.begin() + InsertionPoint,
GetStableCStr(SavedStrings, NameParts.DriverMode));
}
if (NameParts.TargetIsValid) {
const char *arr[] = {"-target", GetStableCStr(SavedStrings,
NameParts.TargetPrefix)};
ArgVector.insert(ArgVector.begin() + InsertionPoint,
std::begin(arr), std::end(arr));
}
}
static void getCLEnvVarOptions(std::string &EnvValue, llvm::StringSaver &Saver,
SmallVectorImpl<const char *> &Opts) {
llvm::cl::TokenizeWindowsCommandLine(EnvValue, Saver, Opts);
// The first instance of '#' should be replaced with '=' in each option.
for (const char *Opt : Opts)
if (char *NumberSignPtr = const_cast<char *>(::strchr(Opt, '#')))
*NumberSignPtr = '=';
}
static void SetBackdoorDriverOutputsFromEnvVars(Driver &TheDriver) {
// Handle CC_PRINT_OPTIONS and CC_PRINT_OPTIONS_FILE.
TheDriver.CCPrintOptions = !!::getenv("CC_PRINT_OPTIONS");
if (TheDriver.CCPrintOptions)
TheDriver.CCPrintOptionsFilename = ::getenv("CC_PRINT_OPTIONS_FILE");
// Handle CC_PRINT_HEADERS and CC_PRINT_HEADERS_FILE.
TheDriver.CCPrintHeaders = !!::getenv("CC_PRINT_HEADERS");
if (TheDriver.CCPrintHeaders)
TheDriver.CCPrintHeadersFilename = ::getenv("CC_PRINT_HEADERS_FILE");
// Handle CC_LOG_DIAGNOSTICS and CC_LOG_DIAGNOSTICS_FILE.
TheDriver.CCLogDiagnostics = !!::getenv("CC_LOG_DIAGNOSTICS");
if (TheDriver.CCLogDiagnostics)
TheDriver.CCLogDiagnosticsFilename = ::getenv("CC_LOG_DIAGNOSTICS_FILE");
}
static void FixupDiagPrefixExeName(TextDiagnosticPrinter *DiagClient,
const std::string &Path) {
// If the clang binary happens to be named cl.exe for compatibility reasons,
// use clang-cl.exe as the prefix to avoid confusion between clang and MSVC.
StringRef ExeBasename(llvm::sys::path::filename(Path));
if (ExeBasename.equals_lower("cl.exe"))
ExeBasename = "clang-cl.exe";
DiagClient->setPrefix(ExeBasename);
}
// This lets us create the DiagnosticsEngine with a properly-filled-out
// DiagnosticOptions instance.
static DiagnosticOptions *
CreateAndPopulateDiagOpts(ArrayRef<const char *> argv) {
auto *DiagOpts = new DiagnosticOptions;
std::unique_ptr<OptTable> Opts(createDriverOptTable());
unsigned MissingArgIndex, MissingArgCount;
InputArgList Args =
Opts->ParseArgs(argv.slice(1), MissingArgIndex, MissingArgCount);
// We ignore MissingArgCount and the return value of ParseDiagnosticArgs.
// Any errors that would be diagnosed here will also be diagnosed later,
// when the DiagnosticsEngine actually exists.
(void)ParseDiagnosticArgs(*DiagOpts, Args);
return DiagOpts;
}
static void SetInstallDir(SmallVectorImpl<const char *> &argv,
Driver &TheDriver, bool CanonicalPrefixes) {
// Attempt to find the original path used to invoke the driver, to determine
// the installed path. We do this manually, because we want to support that
// path being a symlink.
SmallString<128> InstalledPath(argv[0]);
// Do a PATH lookup, if there are no directory components.
if (llvm::sys::path::filename(InstalledPath) == InstalledPath)
if (llvm::ErrorOr<std::string> Tmp = llvm::sys::findProgramByName(
llvm::sys::path::filename(InstalledPath.str())))
InstalledPath = *Tmp;
// FIXME: We don't actually canonicalize this, we just make it absolute.
if (CanonicalPrefixes)
llvm::sys::fs::make_absolute(InstalledPath);
StringRef InstalledPathParent(llvm::sys::path::parent_path(InstalledPath));
if (llvm::sys::fs::exists(InstalledPathParent))
TheDriver.setInstalledDir(InstalledPathParent);
}
static int ExecuteCC1Tool(ArrayRef<const char *> argv, StringRef Tool) {
void *GetExecutablePathVP = (void *)(intptr_t) GetExecutablePath;
if (Tool == "")
return cc1_main(argv.slice(2), argv[0], GetExecutablePathVP);
if (Tool == "as")
return cc1as_main(argv.slice(2), argv[0], GetExecutablePathVP);
// Reject unknown tools.
llvm::errs() << "error: unknown integrated tool '" << Tool << "'. "
<< "Valid tools include '-cc1' and '-cc1as'.\n";
return 1;
}
extern "C" int ZigClang_main(int argc_, const char **argv_);
int ZigClang_main(int argc_, const char **argv_) {
llvm::InitLLVM X(argc_, argv_);
size_t argv_offset = (strcmp(argv_[1], "-cc1") == 0 || strcmp(argv_[1], "-cc1as") == 0) ? 0 : 1;
SmallVector<const char *, 256> argv(argv_ + argv_offset, argv_ + argc_);
if (llvm::sys::Process::FixupStandardFileDescriptors())
return 1;
llvm::InitializeAllTargets();
auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(argv[0]);
llvm::BumpPtrAllocator A;
llvm::StringSaver Saver(A);
// Parse response files using the GNU syntax, unless we're in CL mode. There
// are two ways to put clang in CL compatibility mode: argv[0] is either
// clang-cl or cl, or --driver-mode=cl is on the command line. The normal
// command line parsing can't happen until after response file parsing, so we
// have to manually search for a --driver-mode=cl argument the hard way.
// Finally, our -cc1 tools don't care which tokenization mode we use because
// response files written by clang will tokenize the same way in either mode.
bool ClangCLMode = false;
if (StringRef(TargetAndMode.DriverMode).equals("--driver-mode=cl") ||
std::find_if(argv.begin(), argv.end(), [](const char *F) {
return F && strcmp(F, "--driver-mode=cl") == 0;
}) != argv.end()) {
ClangCLMode = true;
}
enum { Default, POSIX, Windows } RSPQuoting = Default;
for (const char *F : argv) {
if (strcmp(F, "--rsp-quoting=posix") == 0)
RSPQuoting = POSIX;
else if (strcmp(F, "--rsp-quoting=windows") == 0)
RSPQuoting = Windows;
}
// Determines whether we want nullptr markers in argv to indicate response
// files end-of-lines. We only use this for the /LINK driver argument with
// clang-cl.exe on Windows.
bool MarkEOLs = ClangCLMode;
llvm::cl::TokenizerCallback Tokenizer;
if (RSPQuoting == Windows || (RSPQuoting == Default && ClangCLMode))
Tokenizer = &llvm::cl::TokenizeWindowsCommandLine;
else
Tokenizer = &llvm::cl::TokenizeGNUCommandLine;
if (MarkEOLs && argv.size() > 1 && StringRef(argv[1]).startswith("-cc1"))
MarkEOLs = false;
llvm::cl::ExpandResponseFiles(Saver, Tokenizer, argv, MarkEOLs);
// Handle -cc1 integrated tools, even if -cc1 was expanded from a response
// file.
auto FirstArg = std::find_if(argv.begin() + 1, argv.end(),
[](const char *A) { return A != nullptr; });
if (FirstArg != argv.end() && StringRef(*FirstArg).startswith("-cc1")) {
// If -cc1 came from a response file, remove the EOL sentinels.
if (MarkEOLs) {
auto newEnd = std::remove(argv.begin(), argv.end(), nullptr);
argv.resize(newEnd - argv.begin());
}
return ExecuteCC1Tool(argv, argv[1] + 4);
}
bool CanonicalPrefixes = true;
for (int i = 1, size = argv.size(); i < size; ++i) {
// Skip end-of-line response file markers
if (argv[i] == nullptr)
continue;
if (StringRef(argv[i]) == "-no-canonical-prefixes") {
CanonicalPrefixes = false;
break;
}
}
// Handle CL and _CL_ which permits additional command line options to be
// prepended or appended.
if (ClangCLMode) {
// Arguments in "CL" are prepended.
llvm::Optional<std::string> OptCL = llvm::sys::Process::GetEnv("CL");
if (OptCL.hasValue()) {
SmallVector<const char *, 8> PrependedOpts;
getCLEnvVarOptions(OptCL.getValue(), Saver, PrependedOpts);
// Insert right after the program name to prepend to the argument list.
argv.insert(argv.begin() + 1, PrependedOpts.begin(), PrependedOpts.end());
}
// Arguments in "_CL_" are appended.
llvm::Optional<std::string> Opt_CL_ = llvm::sys::Process::GetEnv("_CL_");
if (Opt_CL_.hasValue()) {
SmallVector<const char *, 8> AppendedOpts;
getCLEnvVarOptions(Opt_CL_.getValue(), Saver, AppendedOpts);
// Insert at the end of the argument list to append.
argv.append(AppendedOpts.begin(), AppendedOpts.end());
}
}
std::set<std::string> SavedStrings;
// Handle CCC_OVERRIDE_OPTIONS, used for editing a command line behind the
// scenes.
if (const char *OverrideStr = ::getenv("CCC_OVERRIDE_OPTIONS")) {
// FIXME: Driver shouldn't take extra initial argument.
ApplyQAOverride(argv, OverrideStr, SavedStrings);
}
std::string Path = GetExecutablePath(argv[0], CanonicalPrefixes);
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
CreateAndPopulateDiagOpts(argv);
TextDiagnosticPrinter *DiagClient
= new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
FixupDiagPrefixExeName(DiagClient, Path);
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
if (!DiagOpts->DiagnosticSerializationFile.empty()) {
auto SerializedConsumer =
clang::serialized_diags::create(DiagOpts->DiagnosticSerializationFile,
&*DiagOpts, /*MergeChildRecords=*/true);
Diags.setClient(new ChainedDiagnosticConsumer(
Diags.takeClient(), std::move(SerializedConsumer)));
}
ProcessWarningOptions(Diags, *DiagOpts, /*ReportDiags=*/false);
Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags);
SetInstallDir(argv, TheDriver, CanonicalPrefixes);
TheDriver.setTargetAndMode(TargetAndMode);
insertTargetAndModeArgs(TargetAndMode, argv, SavedStrings);
SetBackdoorDriverOutputsFromEnvVars(TheDriver);
std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(argv));
int Res = 1;
if (C && !C->containsError()) {
SmallVector<std::pair<int, const Command *>, 4> FailingCommands;
Res = TheDriver.ExecuteCompilation(*C, FailingCommands);
// Force a crash to test the diagnostics.
if (TheDriver.GenReproducer) {
Diags.Report(diag::err_drv_force_crash)
<< !::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH");
// Pretend that every command failed.
FailingCommands.clear();
for (const auto &J : C->getJobs())
if (const Command *C = dyn_cast<Command>(&J))
FailingCommands.push_back(std::make_pair(-1, C));
}
for (const auto &P : FailingCommands) {
int CommandRes = P.first;
const Command *FailingCommand = P.second;
if (!Res)
Res = CommandRes;
// If result status is < 0, then the driver command signalled an error.
// If result status is 70, then the driver command reported a fatal error.
// On Windows, abort will return an exit code of 3. In these cases,
// generate additional diagnostic information if possible.
bool DiagnoseCrash = CommandRes < 0 || CommandRes == 70;
#ifdef _WIN32
DiagnoseCrash |= CommandRes == 3;
#endif
if (DiagnoseCrash) {
TheDriver.generateCompilationDiagnostics(*C, *FailingCommand);
break;
}
}
}
Diags.getClient()->finish();
// If any timers were active but haven't been destroyed yet, print their
// results now. This happens in -disable-free mode.
llvm::TimerGroup::printAll(llvm::errs());
#ifdef _WIN32
// Exit status should not be negative on Win32, unless abnormal termination.
// Once abnormal termiation was caught, negative status should not be
// propagated.
if (Res < 0)
Res = 1;
#endif
// If we have multiple failing commands, we return the result of the first
// failing command.
return Res;
}

View File

@ -732,7 +732,7 @@ void ZigLLVMGetNativeTarget(ZigLLVM_ArchType *arch_type, ZigLLVM_SubArchType *su
const char *ZigLLVMGetSubArchTypeName(ZigLLVM_SubArchType sub_arch) { const char *ZigLLVMGetSubArchTypeName(ZigLLVM_SubArchType sub_arch) {
switch (sub_arch) { switch (sub_arch) {
case ZigLLVM_NoSubArch: case ZigLLVM_NoSubArch:
return "(none)"; return "";
case ZigLLVM_ARMSubArch_v8_5a: case ZigLLVM_ARMSubArch_v8_5a:
return "v8_5a"; return "v8_5a";
case ZigLLVM_ARMSubArch_v8_4a: case ZigLLVM_ARMSubArch_v8_4a:

View File

@ -215,7 +215,7 @@ ZIG_EXTERN_C void ZigLLVMParseCommandLineOptions(size_t argc, const char *const
// copied from include/llvm/ADT/Triple.h // copied from include/llvm/ADT/Triple.h
// synchronize with target.cpp::arch_list
enum ZigLLVM_ArchType { enum ZigLLVM_ArchType {
ZigLLVM_UnknownArch, ZigLLVM_UnknownArch,
@ -272,6 +272,7 @@ enum ZigLLVM_ArchType {
ZigLLVM_LastArchType = ZigLLVM_renderscript64 ZigLLVM_LastArchType = ZigLLVM_renderscript64
}; };
// synchronize with lists in target.cpp
enum ZigLLVM_SubArchType { enum ZigLLVM_SubArchType {
ZigLLVM_NoSubArch, ZigLLVM_NoSubArch,
@ -409,7 +410,7 @@ ZIG_EXTERN_C const char *ZigLLVMGetArchTypeName(enum ZigLLVM_ArchType arch);
ZIG_EXTERN_C const char *ZigLLVMGetSubArchTypeName(enum ZigLLVM_SubArchType sub_arch); ZIG_EXTERN_C const char *ZigLLVMGetSubArchTypeName(enum ZigLLVM_SubArchType sub_arch);
ZIG_EXTERN_C const char *ZigLLVMGetVendorTypeName(enum ZigLLVM_VendorType vendor); ZIG_EXTERN_C const char *ZigLLVMGetVendorTypeName(enum ZigLLVM_VendorType vendor);
ZIG_EXTERN_C const char *ZigLLVMGetOSTypeName(enum ZigLLVM_OSType os); ZIG_EXTERN_C const char *ZigLLVMGetOSTypeName(enum ZigLLVM_OSType os);
ZIG_EXTERN_C const char *ZigLLVMGetEnvironmentTypeName(enum ZigLLVM_EnvironmentType env_type); ZIG_EXTERN_C const char *ZigLLVMGetEnvironmentTypeName(enum ZigLLVM_EnvironmentType abi);
ZIG_EXTERN_C bool ZigLLDLink(enum ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_count, ZIG_EXTERN_C bool ZigLLDLink(enum ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_count,
void (*append_diagnostic)(void *, const char *, size_t), void *context); void (*append_diagnostic)(void *, const char *, size_t), void *context);

View File

@ -32,6 +32,10 @@ pub const BufSet = struct {
} }
} }
pub fn exists(self: BufSet, key: []const u8) bool {
return self.hash_map.get(key) != null;
}
pub fn delete(self: *BufSet, key: []const u8) void { pub fn delete(self: *BufSet, key: []const u8) void {
const entry = self.hash_map.remove(key) orelse return; const entry = self.hash_map.remove(key) orelse return;
self.free(entry.key); self.free(entry.key);

File diff suppressed because it is too large Load Diff

35
std/build/fmt.zig Normal file
View File

@ -0,0 +1,35 @@
const std = @import("../index.zig");
const build = @import("../build.zig");
const Step = build.Step;
const Builder = build.Builder;
const BufMap = std.BufMap;
const mem = std.mem;
pub const FmtStep = struct {
step: Step,
builder: *Builder,
argv: [][]const u8,
pub fn create(builder: *Builder, paths: []const []const u8) *FmtStep {
const self = builder.allocator.create(FmtStep) catch unreachable;
const name = "zig fmt";
self.* = FmtStep{
.step = Step.init(name, builder.allocator, make),
.builder = builder,
.argv = builder.allocator.alloc([]u8, paths.len + 2) catch unreachable,
};
self.argv[0] = builder.zig_exe;
self.argv[1] = "fmt";
for (paths) |path, i| {
self.argv[2 + i] = builder.pathFromRoot(path);
}
return self;
}
fn make(step: *Step) !void {
const self = @fieldParentPtr(FmtStep, "step", step);
return self.builder.spawnChild(self.argv);
}
};

View File

@ -36,11 +36,20 @@ pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usi
pub extern "c" fn bind(socket: c_int, address: ?*const sockaddr, address_len: socklen_t) c_int; pub extern "c" fn bind(socket: c_int, address: ?*const sockaddr, address_len: socklen_t) c_int;
pub extern "c" fn socket(domain: c_int, type: c_int, protocol: c_int) c_int; pub extern "c" fn socket(domain: c_int, type: c_int, protocol: c_int) c_int;
const mach_hdr = if (@sizeOf(usize) == 8) mach_header_64 else mach_header;
/// The value of the link editor defined symbol _MH_EXECUTE_SYM is the address /// The value of the link editor defined symbol _MH_EXECUTE_SYM is the address
/// of the mach header in a Mach-O executable file type. It does not appear in /// of the mach header in a Mach-O executable file type. It does not appear in
/// any file type other than a MH_EXECUTE file type. The type of the symbol is /// any file type other than a MH_EXECUTE file type. The type of the symbol is
/// absolute as the header is not part of any section. /// absolute as the header is not part of any section.
pub extern "c" var _mh_execute_header: if (@sizeOf(usize) == 8) mach_header_64 else mach_header; /// This symbol is populated when linking the system's libc, which is guaranteed
/// on this operating system. However when building object files or libraries,
/// the system libc won't be linked until the final executable. So we
/// export a weak symbol here, to be overridden by the real one.
pub extern "c" var _mh_execute_header: mach_hdr = undefined;
comptime {
@export("__mh_execute_header", _mh_execute_header, @import("builtin").GlobalLinkage.Weak);
}
pub const mach_header_64 = macho.mach_header_64; pub const mach_header_64 = macho.mach_header_64;
pub const mach_header = macho.mach_header; pub const mach_header = macho.mach_header;

View File

@ -6,6 +6,7 @@ pub use switch (builtin.os) {
Os.windows => @import("windows.zig"), Os.windows => @import("windows.zig"),
Os.macosx, Os.ios => @import("darwin.zig"), Os.macosx, Os.ios => @import("darwin.zig"),
Os.freebsd => @import("freebsd.zig"), Os.freebsd => @import("freebsd.zig"),
Os.netbsd => @import("netbsd.zig"),
else => empty_import, else => empty_import,
}; };
const empty_import = @import("../empty.zig"); const empty_import = @import("../empty.zig");

116
std/c/netbsd.zig Normal file
View File

@ -0,0 +1,116 @@
extern "c" fn __errno() *c_int;
pub const _errno = __errno;
pub extern "c" fn kqueue() c_int;
pub extern "c" fn kevent(
kq: c_int,
changelist: [*]const Kevent,
nchanges: c_int,
eventlist: [*]Kevent,
nevents: c_int,
timeout: ?*const timespec,
) c_int;
pub extern "c" fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int;
pub extern "c" fn getdirentries(fd: c_int, buf_ptr: [*]u8, nbytes: usize, basep: *i64) usize;
pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) usize;
pub extern "c" fn pipe2(arg0: *[2]c_int, arg1: u32) c_int;
pub extern "c" fn preadv(fd: c_int, iov: *const c_void, iovcnt: c_int, offset: usize) isize;
pub extern "c" fn pwritev(fd: c_int, iov: *const c_void, iovcnt: c_int, offset: usize) isize;
pub extern "c" fn openat(fd: c_int, path: ?[*]const u8, flags: c_int) c_int;
pub extern "c" fn setgid(ruid: c_uint, euid: c_uint) c_int;
pub extern "c" fn setuid(uid: c_uint) c_int;
pub extern "c" fn kill(pid: c_int, sig: c_int) c_int;
pub extern "c" fn clock_gettime(clk_id: c_int, tp: *timespec) c_int;
pub extern "c" fn clock_getres(clk_id: c_int, tp: *timespec) c_int;
/// Renamed from `kevent` to `Kevent` to avoid conflict with function name.
pub const Kevent = extern struct {
ident: usize,
filter: i32,
flags: u32,
fflags: u32,
data: i64,
udata: usize,
};
pub const pthread_attr_t = extern struct {
pta_magic: u32,
pta_flags: c_int,
pta_private: *c_void,
};
pub const msghdr = extern struct {
msg_name: *u8,
msg_namelen: socklen_t,
msg_iov: *iovec,
msg_iovlen: i32,
__pad1: i32,
msg_control: *u8,
msg_controllen: socklen_t,
__pad2: socklen_t,
msg_flags: i32,
};
pub const Stat = extern struct {
dev: u64,
mode: u32,
ino: u64,
nlink: usize,
uid: u32,
gid: u32,
rdev: u64,
atim: timespec,
mtim: timespec,
ctim: timespec,
birthtim: timespec,
size: i64,
blocks: i64,
blksize: isize,
flags: u32,
gen: u32,
__spare: [2]u32,
};
pub const timespec = extern struct {
tv_sec: i64,
tv_nsec: isize,
};
pub const dirent = extern struct {
d_fileno: u64,
d_reclen: u16,
d_namlen: u16,
d_type: u8,
d_off: i64,
d_name: [512]u8,
};
pub const in_port_t = u16;
pub const sa_family_t = u8;
pub const sockaddr = extern union {
in: sockaddr_in,
in6: sockaddr_in6,
};
pub const sockaddr_in = extern struct {
len: u8,
family: sa_family_t,
port: in_port_t,
addr: u32,
zero: [8]u8,
};
pub const sockaddr_in6 = extern struct {
len: u8,
family: sa_family_t,
port: in_port_t,
flowinfo: u32,
addr: [16]u8,
scope_id: u32,
};

View File

@ -90,9 +90,60 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
}; };
} }
/// Returns a slice with the same pointer as addresses, with a potentially smaller len.
/// On Windows, when first_address is not null, we ask for at least 32 stack frames,
/// and then try to find the first address. If addresses.len is more than 32, we
/// capture that many stack frames exactly, and then look for the first address,
/// chopping off the irrelevant frames and shifting so that the returned addresses pointer
/// equals the passed in addresses pointer.
pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace) void {
switch (builtin.os) {
builtin.Os.windows => {
const addrs = stack_trace.instruction_addresses;
const u32_addrs_len = @intCast(u32, addrs.len);
const first_addr = first_address orelse {
stack_trace.index = windows.RtlCaptureStackBackTrace(
0,
u32_addrs_len,
@ptrCast(**c_void, addrs.ptr),
null,
);
return;
};
var addr_buf_stack: [32]usize = undefined;
const addr_buf = if (addr_buf_stack.len > addrs.len) addr_buf_stack[0..] else addrs;
const n = windows.RtlCaptureStackBackTrace(0, u32_addrs_len, @ptrCast(**c_void, addr_buf.ptr), null);
const first_index = for (addr_buf[0..n]) |addr, i| {
if (addr == first_addr) {
break i;
}
} else {
stack_trace.index = 0;
return;
};
const slice = addr_buf[first_index..n];
// We use a for loop here because slice and addrs may alias.
for (slice) |addr, i| {
addrs[i] = addr;
}
stack_trace.index = slice.len;
},
else => {
var it = StackIterator.init(first_address);
for (stack_trace.instruction_addresses) |*addr, i| {
addr.* = it.next() orelse {
stack_trace.index = i;
return;
};
}
stack_trace.index = stack_trace.instruction_addresses.len;
},
}
}
/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned. /// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.
/// TODO multithreaded awareness /// TODO multithreaded awareness
pub fn dumpStackTrace(stack_trace: *const builtin.StackTrace) void { pub fn dumpStackTrace(stack_trace: builtin.StackTrace) void {
const stderr = getStderrStream() catch return; const stderr = getStderrStream() catch return;
const debug_info = getSelfDebugInfo() catch |err| { const debug_info = getSelfDebugInfo() catch |err| {
stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return; stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;
@ -141,7 +192,7 @@ pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, c
const stderr = getStderrStream() catch os.abort(); const stderr = getStderrStream() catch os.abort();
stderr.print(format ++ "\n", args) catch os.abort(); stderr.print(format ++ "\n", args) catch os.abort();
if (trace) |t| { if (trace) |t| {
dumpStackTrace(t); dumpStackTrace(t.*);
} }
dumpCurrentStackTrace(first_trace_addr); dumpCurrentStackTrace(first_trace_addr);
@ -155,16 +206,15 @@ const WHITE = "\x1b[37;1m";
const DIM = "\x1b[2m"; const DIM = "\x1b[2m";
const RESET = "\x1b[0m"; const RESET = "\x1b[0m";
pub fn writeStackTrace(stack_trace: *const builtin.StackTrace, out_stream: var, allocator: *mem.Allocator, debug_info: *DebugInfo, tty_color: bool) !void { pub fn writeStackTrace(
var frame_index: usize = undefined; stack_trace: builtin.StackTrace,
var frames_left: usize = undefined; out_stream: var,
if (stack_trace.index < stack_trace.instruction_addresses.len) { allocator: *mem.Allocator,
frame_index = 0; debug_info: *DebugInfo,
frames_left = stack_trace.index; tty_color: bool,
} else { ) !void {
frame_index = (stack_trace.index + 1) % stack_trace.instruction_addresses.len; var frame_index: usize = 0;
frames_left = stack_trace.instruction_addresses.len; var frames_left: usize = stack_trace.index;
}
while (frames_left != 0) : ({ while (frames_left != 0) : ({
frames_left -= 1; frames_left -= 1;
@ -240,7 +290,7 @@ pub fn writeCurrentStackTraceWindows(
pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void { pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
switch (builtin.os) { switch (builtin.os) {
builtin.Os.macosx => return printSourceAtAddressMacOs(debug_info, out_stream, address, tty_color), builtin.Os.macosx => return printSourceAtAddressMacOs(debug_info, out_stream, address, tty_color),
builtin.Os.linux, builtin.Os.freebsd => return printSourceAtAddressLinux(debug_info, out_stream, address, tty_color), builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => return printSourceAtAddressLinux(debug_info, out_stream, address, tty_color),
builtin.Os.windows => return printSourceAtAddressWindows(debug_info, out_stream, address, tty_color), builtin.Os.windows => return printSourceAtAddressWindows(debug_info, out_stream, address, tty_color),
else => return error.UnsupportedOperatingSystem, else => return error.UnsupportedOperatingSystem,
} }
@ -574,7 +624,7 @@ fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const Mach
} }
fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void { fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
const base_addr = @ptrToInt(&std.c._mh_execute_header); const base_addr = std.os.getBaseAddress();
const adjusted_addr = 0x100000000 + (address - base_addr); const adjusted_addr = 0x100000000 + (address - base_addr);
const symbol = machoSearchSymbols(di.symbols, adjusted_addr) orelse { const symbol = machoSearchSymbols(di.symbols, adjusted_addr) orelse {
@ -717,7 +767,7 @@ pub const OpenSelfDebugInfoError = error{
pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo { pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo {
switch (builtin.os) { switch (builtin.os) {
builtin.Os.linux, builtin.Os.freebsd => return openSelfDebugInfoLinux(allocator), builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => return openSelfDebugInfoLinux(allocator),
builtin.Os.macosx, builtin.Os.ios => return openSelfDebugInfoMacOs(allocator), builtin.Os.macosx, builtin.Os.ios => return openSelfDebugInfoMacOs(allocator),
builtin.Os.windows => return openSelfDebugInfoWindows(allocator), builtin.Os.windows => return openSelfDebugInfoWindows(allocator),
else => return error.UnsupportedOperatingSystem, else => return error.UnsupportedOperatingSystem,
@ -1141,7 +1191,7 @@ pub const DebugInfo = switch (builtin.os) {
sect_contribs: []pdb.SectionContribEntry, sect_contribs: []pdb.SectionContribEntry,
modules: []Module, modules: []Module,
}, },
builtin.Os.linux, builtin.Os.freebsd => DwarfInfo, builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => DwarfInfo,
else => @compileError("Unsupported OS"), else => @compileError("Unsupported OS"),
}; };

View File

@ -85,6 +85,7 @@ pub async fn pwritev(loop: *Loop, fd: os.FileHandle, data: []const []const u8, o
builtin.Os.macosx, builtin.Os.macosx,
builtin.Os.linux, builtin.Os.linux,
builtin.Os.freebsd, builtin.Os.freebsd,
builtin.Os.netbsd,
=> { => {
const iovecs = try loop.allocator.alloc(os.posix.iovec_const, data.len); const iovecs = try loop.allocator.alloc(os.posix.iovec_const, data.len);
defer loop.allocator.free(iovecs); defer loop.allocator.free(iovecs);
@ -222,6 +223,7 @@ pub async fn preadv(loop: *Loop, fd: os.FileHandle, data: []const []u8, offset:
builtin.Os.macosx, builtin.Os.macosx,
builtin.Os.linux, builtin.Os.linux,
builtin.Os.freebsd, builtin.Os.freebsd,
builtin.Os.netbsd,
=> { => {
const iovecs = try loop.allocator.alloc(os.posix.iovec, data.len); const iovecs = try loop.allocator.alloc(os.posix.iovec, data.len);
defer loop.allocator.free(iovecs); defer loop.allocator.free(iovecs);
@ -402,7 +404,11 @@ pub async fn openPosix(
pub async fn openRead(loop: *Loop, path: []const u8) os.File.OpenError!os.FileHandle { pub async fn openRead(loop: *Loop, path: []const u8) os.File.OpenError!os.FileHandle {
switch (builtin.os) { switch (builtin.os) {
builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd => { builtin.Os.macosx,
builtin.Os.linux,
builtin.Os.freebsd,
builtin.Os.netbsd
=> {
const flags = posix.O_LARGEFILE | posix.O_RDONLY | posix.O_CLOEXEC; const flags = posix.O_LARGEFILE | posix.O_RDONLY | posix.O_CLOEXEC;
return await (async openPosix(loop, path, flags, os.File.default_mode) catch unreachable); return await (async openPosix(loop, path, flags, os.File.default_mode) catch unreachable);
}, },
@ -431,6 +437,7 @@ pub async fn openWriteMode(loop: *Loop, path: []const u8, mode: os.File.Mode) os
builtin.Os.macosx, builtin.Os.macosx,
builtin.Os.linux, builtin.Os.linux,
builtin.Os.freebsd, builtin.Os.freebsd,
builtin.Os.netbsd,
=> { => {
const flags = posix.O_LARGEFILE | posix.O_WRONLY | posix.O_CREAT | posix.O_CLOEXEC | posix.O_TRUNC; const flags = posix.O_LARGEFILE | posix.O_WRONLY | posix.O_CREAT | posix.O_CLOEXEC | posix.O_TRUNC;
return await (async openPosix(loop, path, flags, os.File.default_mode) catch unreachable); return await (async openPosix(loop, path, flags, os.File.default_mode) catch unreachable);
@ -453,7 +460,7 @@ pub async fn openReadWrite(
mode: os.File.Mode, mode: os.File.Mode,
) os.File.OpenError!os.FileHandle { ) os.File.OpenError!os.FileHandle {
switch (builtin.os) { switch (builtin.os) {
builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd => { builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => {
const flags = posix.O_LARGEFILE | posix.O_RDWR | posix.O_CREAT | posix.O_CLOEXEC; const flags = posix.O_LARGEFILE | posix.O_RDWR | posix.O_CREAT | posix.O_CLOEXEC;
return await (async openPosix(loop, path, flags, mode) catch unreachable); return await (async openPosix(loop, path, flags, mode) catch unreachable);
}, },
@ -481,7 +488,7 @@ pub const CloseOperation = struct {
os_data: OsData, os_data: OsData,
const OsData = switch (builtin.os) { const OsData = switch (builtin.os) {
builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd => OsDataPosix, builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => OsDataPosix,
builtin.Os.windows => struct { builtin.Os.windows => struct {
handle: ?os.FileHandle, handle: ?os.FileHandle,
@ -500,7 +507,7 @@ pub const CloseOperation = struct {
self.* = CloseOperation{ self.* = CloseOperation{
.loop = loop, .loop = loop,
.os_data = switch (builtin.os) { .os_data = switch (builtin.os) {
builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd => initOsDataPosix(self), builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => initOsDataPosix(self),
builtin.Os.windows => OsData{ .handle = null }, builtin.Os.windows => OsData{ .handle = null },
else => @compileError("Unsupported OS"), else => @compileError("Unsupported OS"),
}, },
@ -530,6 +537,7 @@ pub const CloseOperation = struct {
builtin.Os.linux, builtin.Os.linux,
builtin.Os.macosx, builtin.Os.macosx,
builtin.Os.freebsd, builtin.Os.freebsd,
builtin.Os.netbsd,
=> { => {
if (self.os_data.have_fd) { if (self.os_data.have_fd) {
self.loop.posixFsRequest(&self.os_data.close_req_node); self.loop.posixFsRequest(&self.os_data.close_req_node);
@ -552,6 +560,7 @@ pub const CloseOperation = struct {
builtin.Os.linux, builtin.Os.linux,
builtin.Os.macosx, builtin.Os.macosx,
builtin.Os.freebsd, builtin.Os.freebsd,
builtin.Os.netbsd,
=> { => {
self.os_data.close_req_node.data.msg.Close.fd = handle; self.os_data.close_req_node.data.msg.Close.fd = handle;
self.os_data.have_fd = true; self.os_data.have_fd = true;
@ -569,6 +578,7 @@ pub const CloseOperation = struct {
builtin.Os.linux, builtin.Os.linux,
builtin.Os.macosx, builtin.Os.macosx,
builtin.Os.freebsd, builtin.Os.freebsd,
builtin.Os.netbsd,
=> { => {
self.os_data.have_fd = false; self.os_data.have_fd = false;
}, },
@ -584,6 +594,7 @@ pub const CloseOperation = struct {
builtin.Os.linux, builtin.Os.linux,
builtin.Os.macosx, builtin.Os.macosx,
builtin.Os.freebsd, builtin.Os.freebsd,
builtin.Os.netbsd,
=> { => {
assert(self.os_data.have_fd); assert(self.os_data.have_fd);
return self.os_data.close_req_node.data.msg.Close.fd; return self.os_data.close_req_node.data.msg.Close.fd;
@ -608,6 +619,7 @@ pub async fn writeFileMode(loop: *Loop, path: []const u8, contents: []const u8,
builtin.Os.linux, builtin.Os.linux,
builtin.Os.macosx, builtin.Os.macosx,
builtin.Os.freebsd, builtin.Os.freebsd,
builtin.Os.netbsd,
=> return await (async writeFileModeThread(loop, path, contents, mode) catch unreachable), => return await (async writeFileModeThread(loop, path, contents, mode) catch unreachable),
builtin.Os.windows => return await (async writeFileWindows(loop, path, contents) catch unreachable), builtin.Os.windows => return await (async writeFileWindows(loop, path, contents) catch unreachable),
else => @compileError("Unsupported OS"), else => @compileError("Unsupported OS"),
@ -713,7 +725,7 @@ pub fn Watch(comptime V: type) type {
os_data: OsData, os_data: OsData,
const OsData = switch (builtin.os) { const OsData = switch (builtin.os) {
builtin.Os.macosx, builtin.Os.freebsd => struct { builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => struct {
file_table: FileTable, file_table: FileTable,
table_lock: event.Lock, table_lock: event.Lock,
@ -802,7 +814,7 @@ pub fn Watch(comptime V: type) type {
return self; return self;
}, },
builtin.Os.macosx, builtin.Os.freebsd => { builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
const self = try loop.allocator.create(Self); const self = try loop.allocator.create(Self);
errdefer loop.allocator.destroy(self); errdefer loop.allocator.destroy(self);
@ -822,7 +834,7 @@ pub fn Watch(comptime V: type) type {
/// All addFile calls and removeFile calls must have completed. /// All addFile calls and removeFile calls must have completed.
pub fn destroy(self: *Self) void { pub fn destroy(self: *Self) void {
switch (builtin.os) { switch (builtin.os) {
builtin.Os.macosx, builtin.Os.freebsd => { builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
// TODO we need to cancel the coroutines before destroying the lock // TODO we need to cancel the coroutines before destroying the lock
self.os_data.table_lock.deinit(); self.os_data.table_lock.deinit();
var it = self.os_data.file_table.iterator(); var it = self.os_data.file_table.iterator();
@ -864,7 +876,10 @@ pub fn Watch(comptime V: type) type {
pub async fn addFile(self: *Self, file_path: []const u8, value: V) !?V { pub async fn addFile(self: *Self, file_path: []const u8, value: V) !?V {
switch (builtin.os) { switch (builtin.os) {
builtin.Os.macosx, builtin.Os.freebsd => return await (async addFileKEvent(self, file_path, value) catch unreachable), builtin.Os.macosx,
builtin.Os.freebsd,
builtin.Os.netbsd
=> return await (async addFileKEvent(self, file_path, value) catch unreachable),
builtin.Os.linux => return await (async addFileLinux(self, file_path, value) catch unreachable), builtin.Os.linux => return await (async addFileLinux(self, file_path, value) catch unreachable),
builtin.Os.windows => return await (async addFileWindows(self, file_path, value) catch unreachable), builtin.Os.windows => return await (async addFileWindows(self, file_path, value) catch unreachable),
else => @compileError("Unsupported OS"), else => @compileError("Unsupported OS"),

View File

@ -50,7 +50,7 @@ pub const Loop = struct {
}; };
pub const EventFd = switch (builtin.os) { pub const EventFd = switch (builtin.os) {
builtin.Os.macosx, builtin.Os.freebsd => KEventFd, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => KEventFd,
builtin.Os.linux => struct { builtin.Os.linux => struct {
base: ResumeNode, base: ResumeNode,
epoll_op: u32, epoll_op: u32,
@ -69,7 +69,7 @@ pub const Loop = struct {
}; };
pub const Basic = switch (builtin.os) { pub const Basic = switch (builtin.os) {
builtin.Os.macosx, builtin.Os.freebsd => KEventBasic, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => KEventBasic,
builtin.Os.linux => struct { builtin.Os.linux => struct {
base: ResumeNode, base: ResumeNode,
}, },
@ -221,7 +221,7 @@ pub const Loop = struct {
self.extra_threads[extra_thread_index] = try os.spawnThread(self, workerRun); self.extra_threads[extra_thread_index] = try os.spawnThread(self, workerRun);
} }
}, },
builtin.Os.macosx, builtin.Os.freebsd => { builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
self.os_data.kqfd = try os.bsdKQueue(); self.os_data.kqfd = try os.bsdKQueue();
errdefer os.close(self.os_data.kqfd); errdefer os.close(self.os_data.kqfd);
@ -386,7 +386,7 @@ pub const Loop = struct {
os.close(self.os_data.epollfd); os.close(self.os_data.epollfd);
self.allocator.free(self.eventfd_resume_nodes); self.allocator.free(self.eventfd_resume_nodes);
}, },
builtin.Os.macosx, builtin.Os.freebsd => { builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
os.close(self.os_data.kqfd); os.close(self.os_data.kqfd);
os.close(self.os_data.fs_kqfd); os.close(self.os_data.fs_kqfd);
}, },
@ -501,7 +501,7 @@ pub const Loop = struct {
const eventfd_node = &resume_stack_node.data; const eventfd_node = &resume_stack_node.data;
eventfd_node.base.handle = next_tick_node.data; eventfd_node.base.handle = next_tick_node.data;
switch (builtin.os) { switch (builtin.os) {
builtin.Os.macosx, builtin.Os.freebsd => { builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
const kevent_array = (*[1]posix.Kevent)(&eventfd_node.kevent); const kevent_array = (*[1]posix.Kevent)(&eventfd_node.kevent);
const empty_kevs = ([*]posix.Kevent)(undefined)[0..0]; const empty_kevs = ([*]posix.Kevent)(undefined)[0..0];
_ = os.bsdKEvent(self.os_data.kqfd, kevent_array, empty_kevs, null) catch { _ = os.bsdKEvent(self.os_data.kqfd, kevent_array, empty_kevs, null) catch {
@ -564,6 +564,7 @@ pub const Loop = struct {
builtin.Os.linux, builtin.Os.linux,
builtin.Os.macosx, builtin.Os.macosx,
builtin.Os.freebsd, builtin.Os.freebsd,
builtin.Os.netbsd,
=> self.os_data.fs_thread.wait(), => self.os_data.fs_thread.wait(),
else => {}, else => {},
} }
@ -628,7 +629,7 @@ pub const Loop = struct {
os.posixWrite(self.os_data.final_eventfd, wakeup_bytes) catch unreachable; os.posixWrite(self.os_data.final_eventfd, wakeup_bytes) catch unreachable;
return; return;
}, },
builtin.Os.macosx, builtin.Os.freebsd => { builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
self.posixFsRequest(&self.os_data.fs_end_request); self.posixFsRequest(&self.os_data.fs_end_request);
const final_kevent = (*[1]posix.Kevent)(&self.os_data.final_kevent); const final_kevent = (*[1]posix.Kevent)(&self.os_data.final_kevent);
const empty_kevs = ([*]posix.Kevent)(undefined)[0..0]; const empty_kevs = ([*]posix.Kevent)(undefined)[0..0];
@ -686,7 +687,7 @@ pub const Loop = struct {
} }
} }
}, },
builtin.Os.macosx, builtin.Os.freebsd => { builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
var eventlist: [1]posix.Kevent = undefined; var eventlist: [1]posix.Kevent = undefined;
const empty_kevs = ([*]posix.Kevent)(undefined)[0..0]; const empty_kevs = ([*]posix.Kevent)(undefined)[0..0];
const count = os.bsdKEvent(self.os_data.kqfd, empty_kevs, eventlist[0..], null) catch unreachable; const count = os.bsdKEvent(self.os_data.kqfd, empty_kevs, eventlist[0..], null) catch unreachable;
@ -749,7 +750,7 @@ pub const Loop = struct {
self.beginOneEvent(); // finished in posixFsRun after processing the msg self.beginOneEvent(); // finished in posixFsRun after processing the msg
self.os_data.fs_queue.put(request_node); self.os_data.fs_queue.put(request_node);
switch (builtin.os) { switch (builtin.os) {
builtin.Os.macosx, builtin.Os.freebsd => { builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
const fs_kevs = (*[1]posix.Kevent)(&self.os_data.fs_kevent_wake); const fs_kevs = (*[1]posix.Kevent)(&self.os_data.fs_kevent_wake);
const empty_kevs = ([*]posix.Kevent)(undefined)[0..0]; const empty_kevs = ([*]posix.Kevent)(undefined)[0..0];
_ = os.bsdKEvent(self.os_data.fs_kqfd, fs_kevs, empty_kevs, null) catch unreachable; _ = os.bsdKEvent(self.os_data.fs_kqfd, fs_kevs, empty_kevs, null) catch unreachable;
@ -819,7 +820,7 @@ pub const Loop = struct {
else => unreachable, else => unreachable,
} }
}, },
builtin.Os.macosx, builtin.Os.freebsd => { builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
const fs_kevs = (*[1]posix.Kevent)(&self.os_data.fs_kevent_wait); const fs_kevs = (*[1]posix.Kevent)(&self.os_data.fs_kevent_wait);
var out_kevs: [1]posix.Kevent = undefined; var out_kevs: [1]posix.Kevent = undefined;
_ = os.bsdKEvent(self.os_data.fs_kqfd, fs_kevs, out_kevs[0..], null) catch unreachable; _ = os.bsdKEvent(self.os_data.fs_kqfd, fs_kevs, out_kevs[0..], null) catch unreachable;
@ -831,7 +832,7 @@ pub const Loop = struct {
const OsData = switch (builtin.os) { const OsData = switch (builtin.os) {
builtin.Os.linux => LinuxOsData, builtin.Os.linux => LinuxOsData,
builtin.Os.macosx, builtin.Os.freebsd => KEventData, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => KEventData,
builtin.Os.windows => struct { builtin.Os.windows => struct {
io_port: windows.HANDLE, io_port: windows.HANDLE,
extra_thread_count: usize, extra_thread_count: usize,

View File

@ -236,6 +236,9 @@ pub fn formatType(
const casted_value = ([]const u8)(value); const casted_value = ([]const u8)(value);
return output(context, casted_value); return output(context, casted_value);
}, },
builtin.TypeInfo.Pointer.Size.C => {
return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
},
}, },
builtin.TypeId.Array => |info| { builtin.TypeId.Array => |info| {
if (info.child == u8) { if (info.child == u8) {
@ -828,7 +831,7 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsigned
return x; return x;
} }
test "parseUnsigned" { test "fmt.parseUnsigned" {
testing.expect((try parseUnsigned(u16, "050124", 10)) == 50124); testing.expect((try parseUnsigned(u16, "050124", 10)) == 50124);
testing.expect((try parseUnsigned(u16, "65535", 10)) == 65535); testing.expect((try parseUnsigned(u16, "65535", 10)) == 65535);
testing.expectError(error.Overflow, parseUnsigned(u16, "65536", 10)); testing.expectError(error.Overflow, parseUnsigned(u16, "65536", 10));
@ -855,6 +858,12 @@ test "parseUnsigned" {
testing.expectError(error.Overflow, parseUnsigned(u2, "4", 16)); testing.expectError(error.Overflow, parseUnsigned(u2, "4", 16));
} }
pub const parseFloat = @import("parse_float.zig").parseFloat;
test "fmt.parseFloat" {
_ = @import("parse_float.zig");
}
pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) { pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {
const value = switch (c) { const value = switch (c) {
'0'...'9' => c - '0', '0'...'9' => c - '0',
@ -1109,7 +1118,7 @@ test "fmt.format" {
const result = try bufPrint(buf1[0..], "f64: {}\n", math.nan_f64); const result = try bufPrint(buf1[0..], "f64: {}\n", math.nan_f64);
testing.expect(mem.eql(u8, result, "f64: nan\n")); testing.expect(mem.eql(u8, result, "f64: nan\n"));
} }
if (builtin.arch != builtin.Arch.armv8) { if (builtin.arch != builtin.Arch.arm) {
// negative nan is not defined by IEE 754, // negative nan is not defined by IEE 754,
// and ARM thus normalizes it to positive nan // and ARM thus normalizes it to positive nan
var buf1: [32]u8 = undefined; var buf1: [32]u8 = undefined;

420
std/fmt/parse_float.zig Normal file
View File

@ -0,0 +1,420 @@
// Adapted from https://github.com/grzegorz-kraszewski/stringtofloat.
// MIT License
//
// Copyright (c) 2016 Grzegorz Kraszewski
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// Be aware that this implementation has the following limitations:
//
// - Is not round-trip accurate for all values
// - Only supports round-to-zero
// - Does not handle denormals
const std = @import("../index.zig");
const max_digits = 25;
const f64_plus_zero: u64 = 0x0000000000000000;
const f64_minus_zero: u64 = 0x8000000000000000;
const f64_plus_infinity: u64 = 0x7FF0000000000000;
const f64_minus_infinity: u64 = 0xFFF0000000000000;
const Z96 = struct {
d0: u32,
d1: u32,
d2: u32,
// d = s >> 1
inline fn shiftRight1(d: *Z96, s: Z96) void {
d.d0 = (s.d0 >> 1) | ((s.d1 & 1) << 31);
d.d1 = (s.d1 >> 1) | ((s.d2 & 1) << 31);
d.d2 = s.d2 >> 1;
}
// d = s << 1
inline fn shiftLeft1(d: *Z96, s: Z96) void {
d.d2 = (s.d2 << 1) | ((s.d1 & (1 << 31)) >> 31);
d.d1 = (s.d1 << 1) | ((s.d0 & (1 << 31)) >> 31);
d.d0 = s.d0 << 1;
}
// d += s
inline fn add(d: *Z96, s: Z96) void {
var w = u64(d.d0) + u64(s.d0);
d.d0 = @truncate(u32, w);
w >>= 32;
w += u64(d.d1) + u64(s.d1);
d.d1 = @truncate(u32, w);
w >>= 32;
w += u64(d.d2) + u64(s.d2);
d.d2 = @truncate(u32, w);
}
// d -= s
inline fn sub(d: *Z96, s: Z96) void {
var w = u64(d.d0) -% u64(s.d0);
d.d0 = @truncate(u32, w);
w >>= 32;
w += u64(d.d1) -% u64(s.d1);
d.d1 = @truncate(u32, w);
w >>= 32;
w += u64(d.d2) -% u64(s.d2);
d.d2 = @truncate(u32, w);
}
};
const FloatRepr = struct {
negative: bool,
exponent: i32,
mantissa: u64,
};
fn convertRepr(comptime T: type, n: FloatRepr) T {
const mask28: u32 = 0xf << 28;
var s: Z96 = undefined;
var q: Z96 = undefined;
var r: Z96 = undefined;
s.d0 = @truncate(u32, n.mantissa);
s.d1 = @truncate(u32, n.mantissa >> 32);
s.d2 = 0;
var binary_exponent: u64 = 92;
var exp = n.exponent;
while (exp > 0) : (exp -= 1) {
q.shiftLeft1(s); // q = p << 1
r.shiftLeft1(q); // r = p << 2
s.shiftLeft1(r); // p = p << 3
q.add(s); // p = (p << 3) + (p << 1)
exp -= 1;
while (s.d2 & mask28 != 0) {
q.shiftRight1(s);
binary_exponent += 1;
s = q;
}
}
while (exp < 0) {
while (s.d2 & (1 << 31) == 0) {
q.shiftLeft1(s);
binary_exponent -= 1;
s = q;
}
q.d2 = s.d2 / 10;
r.d1 = s.d2 % 10;
r.d2 = (s.d1 >> 8) | (r.d1 << 24);
q.d1 = r.d2 / 10;
r.d1 = r.d2 % 10;
r.d2 = ((s.d1 & 0xff) << 16) | (s.d0 >> 16) | (r.d1 << 24);
r.d0 = r.d2 / 10;
r.d1 = r.d2 % 10;
q.d1 = (q.d1 << 8) | ((r.d0 & 0x00ff0000) >> 16);
q.d0 = r.d0 << 16;
r.d2 = (s.d0 *% 0xffff) | (r.d1 << 16);
q.d0 |= r.d2 / 10;
s = q;
exp += 1;
}
if (s.d0 != 0 or s.d1 != 0 or s.d2 != 0) {
while (s.d2 & mask28 == 0) {
q.shiftLeft1(s);
binary_exponent -= 1;
s = q;
}
}
binary_exponent += 1023;
const repr: u64 = blk: {
if (binary_exponent > 2046) {
break :blk if (n.negative) f64_minus_infinity else f64_plus_infinity;
} else if (binary_exponent < 1) {
break :blk if (n.negative) f64_minus_zero else f64_plus_zero;
} else if (s.d2 != 0) {
const binexs2 = u64(binary_exponent) << 52;
const rr = (u64(s.d2 & ~mask28) << 24) | ((u64(s.d1) + 128) >> 8) | binexs2;
break :blk if (n.negative) rr | (1 << 63) else rr;
} else {
break :blk 0;
}
};
const f = @bitCast(f64, repr);
return @floatCast(T, f);
}
const State = enum {
MaybeSign,
LeadingMantissaZeros,
LeadingFractionalZeros,
MantissaIntegral,
MantissaFractional,
ExponentSign,
LeadingExponentZeros,
Exponent,
};
const ParseResult = enum {
Ok,
PlusZero,
MinusZero,
PlusInf,
MinusInf,
};
inline fn isDigit(c: u8) bool {
return c >= '0' and c <= '9';
}
inline fn isSpace(c: u8) bool {
return (c >= 0x09 and c <= 0x13) or c == 0x20;
}
fn parseRepr(s: []const u8, n: *FloatRepr) !ParseResult {
var digit_index: usize = 0;
var negative = false;
var negative_exp = false;
var exponent: i32 = 0;
var state = State.MaybeSign;
var i: usize = 0;
loop: while (i < s.len) {
const c = s[i];
switch (state) {
State.MaybeSign => {
state = State.LeadingMantissaZeros;
if (c == '+') {
i += 1;
} else if (c == '-') {
n.negative = true;
i += 1;
} else if (isDigit(c) or c == '.') {
// continue
} else {
return error.InvalidCharacter;
}
},
State.LeadingMantissaZeros => {
if (c == '0') {
i += 1;
} else if (c == '.') {
i += 1;
state = State.LeadingFractionalZeros;
} else {
state = State.MantissaIntegral;
}
},
State.LeadingFractionalZeros => {
if (c == '0') {
i += 1;
if (n.exponent > std.math.minInt(i32)) {
n.exponent -= 1;
}
} else {
state = State.MantissaFractional;
}
},
State.MantissaIntegral => {
if (isDigit(c)) {
if (digit_index < max_digits) {
n.mantissa *%= 10;
n.mantissa += s[i] - '0';
digit_index += 1;
} else if (n.exponent < std.math.maxInt(i32)) {
n.exponent += 1;
}
i += 1;
} else if (c == '.') {
i += 1;
state = State.MantissaFractional;
} else {
state = State.MantissaFractional;
}
},
State.MantissaFractional => {
if (isDigit(c)) {
if (digit_index < max_digits) {
n.mantissa *%= 10;
n.mantissa += c - '0';
n.exponent -%= 1;
digit_index += 1;
}
i += 1;
} else if (c == 'e' or c == 'E') {
i += 1;
state = State.ExponentSign;
} else {
state = State.ExponentSign;
}
},
State.ExponentSign => {
if (c == '+') {
i += 1;
} else if (c == '-') {
negative_exp = true;
i += 1;
}
state = State.LeadingExponentZeros;
},
State.LeadingExponentZeros => {
if (c == '0') {
i += 1;
} else {
state = State.Exponent;
}
},
State.Exponent => {
if (isDigit(c)) {
if (exponent < std.math.maxInt(i32)) {
exponent *= 10;
exponent += @intCast(i32, c - '0');
}
i += 1;
} else {
return error.InvalidCharacter;
}
},
}
}
if (negative_exp) exponent = -exponent;
n.exponent += exponent;
if (n.mantissa == 0) {
return if (n.negative) ParseResult.MinusZero else ParseResult.PlusZero;
} else if (n.exponent > 309) {
return if (n.negative) ParseResult.MinusInf else ParseResult.PlusInf;
} else if (n.exponent < -328) {
return if (n.negative) ParseResult.MinusZero else ParseResult.PlusZero;
}
return ParseResult.Ok;
}
inline fn isLower(c: u8) bool {
return c -% 'a' < 26;
}
inline fn toUpper(c: u8) u8 {
return if (isLower(c)) (c & 0x5f) else c;
}
fn caseInEql(a: []const u8, b: []const u8) bool {
if (a.len != b.len) return false;
for (a) |_, i| {
if (toUpper(a[i]) != toUpper(b[i])) {
return false;
}
}
return true;
}
pub fn parseFloat(comptime T: type, s: []const u8) !T {
if (s.len == 0) {
return error.InvalidCharacter;
}
if (caseInEql(s, "nan")) {
return std.math.nan(T);
} else if (caseInEql(s, "inf") or caseInEql(s, "+inf")) {
return std.math.inf(T);
} else if (caseInEql(s, "-inf")) {
return -std.math.inf(T);
}
var r = FloatRepr{
.negative = false,
.exponent = 0,
.mantissa = 0,
};
return switch (try parseRepr(s, &r)) {
ParseResult.Ok => convertRepr(T, r),
ParseResult.PlusZero => 0.0,
ParseResult.MinusZero => -T(0.0),
ParseResult.PlusInf => std.math.inf(T),
ParseResult.MinusInf => -std.math.inf(T),
};
}
test "fmt.parseFloat" {
const testing = std.testing;
const expect = testing.expect;
const expectEqual = testing.expectEqual;
const approxEq = std.math.approxEq;
const epsilon = 1e-7;
inline for ([]type{ f16, f32, f64, f128 }) |T| {
const Z = @IntType(false, T.bit_count);
testing.expectError(error.InvalidCharacter, parseFloat(T, ""));
testing.expectError(error.InvalidCharacter, parseFloat(T, " 1"));
testing.expectError(error.InvalidCharacter, parseFloat(T, "1abc"));
expectEqual(try parseFloat(T, "0"), 0.0);
expectEqual((try parseFloat(T, "0")), 0.0);
expectEqual((try parseFloat(T, "+0")), 0.0);
expectEqual((try parseFloat(T, "-0")), 0.0);
expect(approxEq(T, try parseFloat(T, "3.141"), 3.141, epsilon));
expect(approxEq(T, try parseFloat(T, "-3.141"), -3.141, epsilon));
expectEqual((try parseFloat(T, "1e-700")), 0);
expectEqual((try parseFloat(T, "1e+700")), std.math.inf(T));
expectEqual(@bitCast(Z, try parseFloat(T, "nAn")), @bitCast(Z, std.math.nan(T)));
expectEqual((try parseFloat(T, "inF")), std.math.inf(T));
expectEqual((try parseFloat(T, "-INF")), -std.math.inf(T));
if (T != f16) {
expect(approxEq(T, try parseFloat(T, "123142.1"), 123142.1, epsilon));
expect(approxEq(T, try parseFloat(T, "-123142.1124"), T(-123142.1124), epsilon));
}
}
}

View File

@ -496,6 +496,7 @@ pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type
builtin.TypeId.Pointer => |info| switch (info.size) { builtin.TypeId.Pointer => |info| switch (info.size) {
builtin.TypeInfo.Pointer.Size.One => @compileError("TODO auto hash for single item pointers"), builtin.TypeInfo.Pointer.Size.One => @compileError("TODO auto hash for single item pointers"),
builtin.TypeInfo.Pointer.Size.Many => @compileError("TODO auto hash for many item pointers"), builtin.TypeInfo.Pointer.Size.Many => @compileError("TODO auto hash for many item pointers"),
builtin.TypeInfo.Pointer.Size.C => @compileError("TODO auto hash C pointers"),
builtin.TypeInfo.Pointer.Size.Slice => { builtin.TypeInfo.Pointer.Size.Slice => {
const interval = std.math.max(1, key.len / 256); const interval = std.math.max(1, key.len / 256);
var i: usize = 0; var i: usize = 0;
@ -543,6 +544,7 @@ pub fn autoEql(a: var, b: @typeOf(a)) bool {
builtin.TypeId.Pointer => |info| switch (info.size) { builtin.TypeId.Pointer => |info| switch (info.size) {
builtin.TypeInfo.Pointer.Size.One => @compileError("TODO auto eql for single item pointers"), builtin.TypeInfo.Pointer.Size.One => @compileError("TODO auto eql for single item pointers"),
builtin.TypeInfo.Pointer.Size.Many => @compileError("TODO auto eql for many item pointers"), builtin.TypeInfo.Pointer.Size.Many => @compileError("TODO auto eql for many item pointers"),
builtin.TypeInfo.Pointer.Size.C => @compileError("TODO auto eql for C pointers"),
builtin.TypeInfo.Pointer.Size.Slice => { builtin.TypeInfo.Pointer.Size.Slice => {
if (a.len != b.len) return false; if (a.len != b.len) return false;
for (a) |a_item, i| { for (a) |a_item, i| {

View File

@ -71,7 +71,7 @@ pub const DirectAllocator = struct {
const self = @fieldParentPtr(DirectAllocator, "allocator", allocator); const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);
switch (builtin.os) { switch (builtin.os) {
Os.linux, Os.macosx, Os.ios, Os.freebsd => { Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
const p = os.posix; const p = os.posix;
const alloc_size = if (alignment <= os.page_size) n else n + alignment; const alloc_size = if (alignment <= os.page_size) n else n + alignment;
const addr = p.mmap(null, alloc_size, p.PROT_READ | p.PROT_WRITE, p.MAP_PRIVATE | p.MAP_ANONYMOUS, -1, 0); const addr = p.mmap(null, alloc_size, p.PROT_READ | p.PROT_WRITE, p.MAP_PRIVATE | p.MAP_ANONYMOUS, -1, 0);
@ -120,7 +120,7 @@ pub const DirectAllocator = struct {
const self = @fieldParentPtr(DirectAllocator, "allocator", allocator); const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);
switch (builtin.os) { switch (builtin.os) {
Os.linux, Os.macosx, Os.ios, Os.freebsd => { Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
if (new_size <= old_mem.len) { if (new_size <= old_mem.len) {
const base_addr = @ptrToInt(old_mem.ptr); const base_addr = @ptrToInt(old_mem.ptr);
const old_addr_end = base_addr + old_mem.len; const old_addr_end = base_addr + old_mem.len;
@ -164,7 +164,7 @@ pub const DirectAllocator = struct {
const self = @fieldParentPtr(DirectAllocator, "allocator", allocator); const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);
switch (builtin.os) { switch (builtin.os) {
Os.linux, Os.macosx, Os.ios, Os.freebsd => { Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
_ = os.posix.munmap(@ptrToInt(bytes.ptr), bytes.len); _ = os.posix.munmap(@ptrToInt(bytes.ptr), bytes.len);
}, },
Os.windows => { Os.windows => {

View File

@ -9,6 +9,7 @@ pub const DynLib = @import("dynamic_library.zig").DynLib;
pub const HashMap = @import("hash_map.zig").HashMap; pub const HashMap = @import("hash_map.zig").HashMap;
pub const LinkedList = @import("linked_list.zig").LinkedList; pub const LinkedList = @import("linked_list.zig").LinkedList;
pub const Mutex = @import("mutex.zig").Mutex; pub const Mutex = @import("mutex.zig").Mutex;
pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue;
pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex; pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex;
pub const SegmentedList = @import("segmented_list.zig").SegmentedList; pub const SegmentedList = @import("segmented_list.zig").SegmentedList;
pub const SpinLock = @import("spinlock.zig").SpinLock; pub const SpinLock = @import("spinlock.zig").SpinLock;
@ -85,6 +86,7 @@ test "std" {
_ = @import("net.zig"); _ = @import("net.zig");
_ = @import("os/index.zig"); _ = @import("os/index.zig");
_ = @import("pdb.zig"); _ = @import("pdb.zig");
_ = @import("priority_queue.zig");
_ = @import("rand/index.zig"); _ = @import("rand/index.zig");
_ = @import("sort.zig"); _ = @import("sort.zig");
_ = @import("testing.zig"); _ = @import("testing.zig");

View File

@ -343,7 +343,12 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type)
const amt_buffered = self.end_index - self.start_index; const amt_buffered = self.end_index - self.start_index;
if (amt_buffered == 0) { if (amt_buffered == 0) {
assert(self.end_index <= buffer_size); assert(self.end_index <= buffer_size);
if (self.end_index == buffer_size) { // Make sure the last read actually gave us some data
if (self.end_index == 0) {
// reading from the unbuffered stream returned nothing
// so we have nothing left to read.
return dest_index;
}
// we can read more data from the unbuffered stream // we can read more data from the unbuffered stream
if (dest_space < buffer_size) { if (dest_space < buffer_size) {
self.start_index = 0; self.start_index = 0;
@ -354,12 +359,8 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type)
const amt_read = try self.unbuffered_in_stream.read(dest[dest_index..]); const amt_read = try self.unbuffered_in_stream.read(dest[dest_index..]);
return dest_index + amt_read; return dest_index + amt_read;
} }
} else {
// reading from the unbuffered stream returned less than we asked for
// so we cannot read any more data.
return dest_index;
}
} }
const copy_amount = math.min(dest_space, amt_buffered); const copy_amount = math.min(dest_space, amt_buffered);
const copy_end_index = self.start_index + copy_amount; const copy_end_index = self.start_index + copy_amount;
mem.copy(u8, dest[dest_index..], self.buffer[self.start_index..copy_end_index]); mem.copy(u8, dest[dest_index..], self.buffer[self.start_index..copy_end_index]);
@ -370,6 +371,46 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type)
}; };
} }
test "io.BufferedInStream" {
const OneByteReadInStream = struct {
const Error = error{NoError};
const Stream = InStream(Error);
stream: Stream,
str: []const u8,
curr: usize,
fn init(str: []const u8) @This() {
return @This(){
.stream = Stream{ .readFn = readFn },
.str = str,
.curr = 0,
};
}
fn readFn(in_stream: *Stream, dest: []u8) Error!usize {
const self = @fieldParentPtr(@This(), "stream", in_stream);
if (self.str.len <= self.curr or dest.len == 0)
return 0;
dest[0] = self.str[self.curr];
self.curr += 1;
return 1;
}
};
var buf: [100]u8 = undefined;
const allocator = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
const str = "This is a test";
var one_byte_stream = OneByteReadInStream.init(str);
var buf_in_stream = BufferedInStream(OneByteReadInStream.Error).init(&one_byte_stream.stream);
const stream = &buf_in_stream.stream;
const res = try stream.readAllAlloc(allocator, str.len + 1);
testing.expectEqualSlices(u8, str, res);
}
/// Creates a stream which supports 'un-reading' data, so that it can be read again. /// Creates a stream which supports 'un-reading' data, so that it can be read again.
/// This makes look-ahead style parsing much easier. /// This makes look-ahead style parsing much easier.
pub fn PeekStream(comptime buffer_size: usize, comptime InStreamError: type) type { pub fn PeekStream(comptime buffer_size: usize, comptime InStreamError: type) type {
@ -935,8 +976,6 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type {
}; };
} }
pub const BufferedAtomicFile = struct { pub const BufferedAtomicFile = struct {
atomic_file: os.AtomicFile, atomic_file: os.AtomicFile,
file_stream: os.File.OutStream, file_stream: os.File.OutStream,
@ -978,7 +1017,6 @@ pub const BufferedAtomicFile = struct {
} }
}; };
pub fn readLine(buf: *std.Buffer) ![]u8 { pub fn readLine(buf: *std.Buffer) ![]u8 {
var stdin = try getStdIn(); var stdin = try getStdIn();
var stdin_stream = stdin.inStream(); var stdin_stream = stdin.inStream();
@ -1075,7 +1113,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, is_packed: bool, comptime E
} }
pub fn alignToByte(self: *Self) void { pub fn alignToByte(self: *Self) void {
if(!is_packed) return; if (!is_packed) return;
self.in_stream.alignToByte(); self.in_stream.alignToByte();
} }
@ -1088,7 +1126,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, is_packed: bool, comptime E
const U = @IntType(false, t_bit_count); const U = @IntType(false, t_bit_count);
const Log2U = math.Log2Int(U); const Log2U = math.Log2Int(U);
const int_size = @sizeOf(U); const int_size = (U.bit_count + 7) / 8;
if (is_packed) { if (is_packed) {
const result = try self.in_stream.readBitsNoEof(U, t_bit_count); const result = try self.in_stream.readBitsNoEof(U, t_bit_count);
@ -1301,7 +1339,7 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime is_packed: bool, com
const U = @IntType(false, t_bit_count); const U = @IntType(false, t_bit_count);
const Log2U = math.Log2Int(U); const Log2U = math.Log2Int(U);
const int_size = @sizeOf(U); const int_size = (U.bit_count + 7) / 8;
const u_value = @bitCast(U, value); const u_value = @bitCast(U, value);
@ -1414,3 +1452,4 @@ test "import io tests" {
_ = @import("io_test.zig"); _ = @import("io_test.zig");
} }
} }

View File

@ -29,6 +29,17 @@ test "write a file, read it, then delete it" {
try st.print("end"); try st.print("end");
try buf_stream.flush(); try buf_stream.flush();
} }
{
// make sure openWriteNoClobber doesn't harm the file
if (os.File.openWriteNoClobber(tmp_file_name, os.File.default_mode)) |file| {
unreachable;
}
else |err| {
std.debug.assert(err == os.File.OpenError.PathAlreadyExists);
}
}
{ {
var file = try os.File.openRead(tmp_file_name); var file = try os.File.openRead(tmp_file_name);
defer file.close(); defer file.close();

View File

@ -1345,7 +1345,7 @@ pub const Parser = struct {
return if (token.number_is_integer) return if (token.number_is_integer)
Value{ .Integer = try std.fmt.parseInt(i64, token.slice(input, i), 10) } Value{ .Integer = try std.fmt.parseInt(i64, token.slice(input, i), 10) }
else else
@panic("TODO: fmt.parseFloat not yet implemented"); Value{ .Float = try std.fmt.parseFloat(f64, token.slice(input, i)) };
} }
}; };
@ -1366,7 +1366,8 @@ test "json.parser.dynamic" {
\\ }, \\ },
\\ "Animated" : false, \\ "Animated" : false,
\\ "IDs": [116, 943, 234, 38793], \\ "IDs": [116, 943, 234, 38793],
\\ "ArrayOfObject": [{"n": "m"}] \\ "ArrayOfObject": [{"n": "m"}],
\\ "double": 1.3412
\\ } \\ }
\\} \\}
; ;
@ -1395,4 +1396,7 @@ test "json.parser.dynamic" {
const obj0 = array_of_object.Array.at(0).Object.get("n").?.value; const obj0 = array_of_object.Array.at(0).Object.get("n").?.value;
testing.expect(mem.eql(u8, obj0.String, "m")); testing.expect(mem.eql(u8, obj0.String, "m"));
const double = image.Object.get("double").?.value;
testing.expect(double.Float == 1.3412);
} }

View File

@ -14,6 +14,7 @@ pub fn fabs(x: var) @typeOf(x) {
f16 => fabs16(x), f16 => fabs16(x),
f32 => fabs32(x), f32 => fabs32(x),
f64 => fabs64(x), f64 => fabs64(x),
f128 => fabs128(x),
else => @compileError("fabs not implemented for " ++ @typeName(T)), else => @compileError("fabs not implemented for " ++ @typeName(T)),
}; };
} }
@ -36,10 +37,17 @@ fn fabs64(x: f64) f64 {
return @bitCast(f64, u); return @bitCast(f64, u);
} }
fn fabs128(x: f128) f128 {
var u = @bitCast(u128, x);
u &= maxInt(u128) >> 1;
return @bitCast(f128, u);
}
test "math.fabs" { test "math.fabs" {
expect(fabs(f16(1.0)) == fabs16(1.0)); expect(fabs(f16(1.0)) == fabs16(1.0));
expect(fabs(f32(1.0)) == fabs32(1.0)); expect(fabs(f32(1.0)) == fabs32(1.0));
expect(fabs(f64(1.0)) == fabs64(1.0)); expect(fabs(f64(1.0)) == fabs64(1.0));
expect(fabs(f128(1.0)) == fabs128(1.0));
} }
test "math.fabs16" { test "math.fabs16" {
@ -57,6 +65,11 @@ test "math.fabs64" {
expect(fabs64(-1.0) == 1.0); expect(fabs64(-1.0) == 1.0);
} }
test "math.fabs128" {
expect(fabs128(1.0) == 1.0);
expect(fabs128(-1.0) == 1.0);
}
test "math.fabs16.special" { test "math.fabs16.special" {
expect(math.isPositiveInf(fabs(math.inf(f16)))); expect(math.isPositiveInf(fabs(math.inf(f16))));
expect(math.isPositiveInf(fabs(-math.inf(f16)))); expect(math.isPositiveInf(fabs(-math.inf(f16))));
@ -74,3 +87,9 @@ test "math.fabs64.special" {
expect(math.isPositiveInf(fabs(-math.inf(f64)))); expect(math.isPositiveInf(fabs(-math.inf(f64))));
expect(math.isNan(fabs(math.nan(f64)))); expect(math.isNan(fabs(math.nan(f64))));
} }
test "math.fabs128.special" {
expect(math.isPositiveInf(fabs(math.inf(f128))));
expect(math.isPositiveInf(fabs(-math.inf(f128))));
expect(math.isNan(fabs(math.nan(f128))));
}

View File

@ -51,6 +51,12 @@ pub const nan_f64 = @bitCast(f64, nan_u64);
pub const inf_u64 = u64(0x7FF << 52); pub const inf_u64 = u64(0x7FF << 52);
pub const inf_f64 = @bitCast(f64, inf_u64); pub const inf_f64 = @bitCast(f64, inf_u64);
pub const nan_u128 = u128(0x7fff0000000000000000000000000001);
pub const nan_f128 = @bitCast(f128, nan_u128);
pub const inf_u128 = u128(0x7fff0000000000000000000000000000);
pub const inf_f128 = @bitCast(f128, inf_u128);
pub const nan = @import("nan.zig").nan; pub const nan = @import("nan.zig").nan;
pub const snan = @import("nan.zig").snan; pub const snan = @import("nan.zig").snan;
pub const inf = @import("inf.zig").inf; pub const inf = @import("inf.zig").inf;
@ -379,7 +385,7 @@ pub fn IntFittingRange(comptime from: comptime_int, comptime to: comptime_int) t
return u0; return u0;
} }
const is_signed = from < 0; const is_signed = from < 0;
const largest_positive_integer = max(if (from<0) (-from)-1 else from, to); // two's complement const largest_positive_integer = max(if (from < 0) (-from) - 1 else from, to); // two's complement
const base = log2(largest_positive_integer); const base = log2(largest_positive_integer);
const upper = (1 << base) - 1; const upper = (1 << base) - 1;
var magnitude_bits = if (upper >= largest_positive_integer) base else base + 1; var magnitude_bits = if (upper >= largest_positive_integer) base else base + 1;
@ -752,6 +758,7 @@ test "minInt and maxInt" {
testing.expect(maxInt(u16) == 65535); testing.expect(maxInt(u16) == 65535);
testing.expect(maxInt(u32) == 4294967295); testing.expect(maxInt(u32) == 4294967295);
testing.expect(maxInt(u64) == 18446744073709551615); testing.expect(maxInt(u64) == 18446744073709551615);
testing.expect(maxInt(u128) == 340282366920938463463374607431768211455);
testing.expect(maxInt(i0) == 0); testing.expect(maxInt(i0) == 0);
testing.expect(maxInt(i1) == 0); testing.expect(maxInt(i1) == 0);
@ -760,6 +767,7 @@ test "minInt and maxInt" {
testing.expect(maxInt(i32) == 2147483647); testing.expect(maxInt(i32) == 2147483647);
testing.expect(maxInt(i63) == 4611686018427387903); testing.expect(maxInt(i63) == 4611686018427387903);
testing.expect(maxInt(i64) == 9223372036854775807); testing.expect(maxInt(i64) == 9223372036854775807);
testing.expect(maxInt(i128) == 170141183460469231731687303715884105727);
testing.expect(minInt(u0) == 0); testing.expect(minInt(u0) == 0);
testing.expect(minInt(u1) == 0); testing.expect(minInt(u1) == 0);
@ -768,6 +776,7 @@ test "minInt and maxInt" {
testing.expect(minInt(u32) == 0); testing.expect(minInt(u32) == 0);
testing.expect(minInt(u63) == 0); testing.expect(minInt(u63) == 0);
testing.expect(minInt(u64) == 0); testing.expect(minInt(u64) == 0);
testing.expect(minInt(u128) == 0);
testing.expect(minInt(i0) == 0); testing.expect(minInt(i0) == 0);
testing.expect(minInt(i1) == -1); testing.expect(minInt(i1) == -1);
@ -776,6 +785,7 @@ test "minInt and maxInt" {
testing.expect(minInt(i32) == -2147483648); testing.expect(minInt(i32) == -2147483648);
testing.expect(minInt(i63) == -4611686018427387904); testing.expect(minInt(i63) == -4611686018427387904);
testing.expect(minInt(i64) == -9223372036854775808); testing.expect(minInt(i64) == -9223372036854775808);
testing.expect(minInt(i128) == -170141183460469231731687303715884105728);
} }
test "max value type" { test "max value type" {

View File

@ -3,9 +3,10 @@ const math = std.math;
pub fn inf(comptime T: type) T { pub fn inf(comptime T: type) T {
return switch (T) { return switch (T) {
f16 => @bitCast(f16, math.inf_u16), f16 => math.inf_f16,
f32 => @bitCast(f32, math.inf_u32), f32 => math.inf_f32,
f64 => @bitCast(f64, math.inf_u64), f64 => math.inf_f64,
f128 => math.inf_f128,
else => @compileError("inf not implemented for " ++ @typeName(T)), else => @compileError("inf not implemented for " ++ @typeName(T)),
}; };
} }

View File

@ -18,6 +18,10 @@ pub fn isInf(x: var) bool {
const bits = @bitCast(u64, x); const bits = @bitCast(u64, x);
return bits & (maxInt(u64) >> 1) == (0x7FF << 52); return bits & (maxInt(u64) >> 1) == (0x7FF << 52);
}, },
f128 => {
const bits = @bitCast(u128, x);
return bits & (maxInt(u128) >> 1) == (0x7FFF << 112);
},
else => { else => {
@compileError("isInf not implemented for " ++ @typeName(T)); @compileError("isInf not implemented for " ++ @typeName(T));
}, },
@ -36,6 +40,9 @@ pub fn isPositiveInf(x: var) bool {
f64 => { f64 => {
return @bitCast(u64, x) == 0x7FF << 52; return @bitCast(u64, x) == 0x7FF << 52;
}, },
f128 => {
return @bitCast(u128, x) == 0x7FFF << 112;
},
else => { else => {
@compileError("isPositiveInf not implemented for " ++ @typeName(T)); @compileError("isPositiveInf not implemented for " ++ @typeName(T));
}, },
@ -54,6 +61,9 @@ pub fn isNegativeInf(x: var) bool {
f64 => { f64 => {
return @bitCast(u64, x) == 0xFFF << 52; return @bitCast(u64, x) == 0xFFF << 52;
}, },
f128 => {
return @bitCast(u128, x) == 0xFFFF << 112;
},
else => { else => {
@compileError("isNegativeInf not implemented for " ++ @typeName(T)); @compileError("isNegativeInf not implemented for " ++ @typeName(T));
}, },
@ -67,12 +77,16 @@ test "math.isInf" {
expect(!isInf(f32(-0.0))); expect(!isInf(f32(-0.0)));
expect(!isInf(f64(0.0))); expect(!isInf(f64(0.0)));
expect(!isInf(f64(-0.0))); expect(!isInf(f64(-0.0)));
expect(!isInf(f128(0.0)));
expect(!isInf(f128(-0.0)));
expect(isInf(math.inf(f16))); expect(isInf(math.inf(f16)));
expect(isInf(-math.inf(f16))); expect(isInf(-math.inf(f16)));
expect(isInf(math.inf(f32))); expect(isInf(math.inf(f32)));
expect(isInf(-math.inf(f32))); expect(isInf(-math.inf(f32)));
expect(isInf(math.inf(f64))); expect(isInf(math.inf(f64)));
expect(isInf(-math.inf(f64))); expect(isInf(-math.inf(f64)));
expect(isInf(math.inf(f128)));
expect(isInf(-math.inf(f128)));
} }
test "math.isPositiveInf" { test "math.isPositiveInf" {
@ -82,12 +96,16 @@ test "math.isPositiveInf" {
expect(!isPositiveInf(f32(-0.0))); expect(!isPositiveInf(f32(-0.0)));
expect(!isPositiveInf(f64(0.0))); expect(!isPositiveInf(f64(0.0)));
expect(!isPositiveInf(f64(-0.0))); expect(!isPositiveInf(f64(-0.0)));
expect(!isPositiveInf(f128(0.0)));
expect(!isPositiveInf(f128(-0.0)));
expect(isPositiveInf(math.inf(f16))); expect(isPositiveInf(math.inf(f16)));
expect(!isPositiveInf(-math.inf(f16))); expect(!isPositiveInf(-math.inf(f16)));
expect(isPositiveInf(math.inf(f32))); expect(isPositiveInf(math.inf(f32)));
expect(!isPositiveInf(-math.inf(f32))); expect(!isPositiveInf(-math.inf(f32)));
expect(isPositiveInf(math.inf(f64))); expect(isPositiveInf(math.inf(f64)));
expect(!isPositiveInf(-math.inf(f64))); expect(!isPositiveInf(-math.inf(f64)));
expect(isPositiveInf(math.inf(f128)));
expect(!isPositiveInf(-math.inf(f128)));
} }
test "math.isNegativeInf" { test "math.isNegativeInf" {
@ -97,10 +115,14 @@ test "math.isNegativeInf" {
expect(!isNegativeInf(f32(-0.0))); expect(!isNegativeInf(f32(-0.0)));
expect(!isNegativeInf(f64(0.0))); expect(!isNegativeInf(f64(0.0)));
expect(!isNegativeInf(f64(-0.0))); expect(!isNegativeInf(f64(-0.0)));
expect(!isNegativeInf(f128(0.0)));
expect(!isNegativeInf(f128(-0.0)));
expect(!isNegativeInf(math.inf(f16))); expect(!isNegativeInf(math.inf(f16)));
expect(isNegativeInf(-math.inf(f16))); expect(isNegativeInf(-math.inf(f16)));
expect(!isNegativeInf(math.inf(f32))); expect(!isNegativeInf(math.inf(f32)));
expect(isNegativeInf(-math.inf(f32))); expect(isNegativeInf(-math.inf(f32)));
expect(!isNegativeInf(math.inf(f64))); expect(!isNegativeInf(math.inf(f64)));
expect(isNegativeInf(-math.inf(f64))); expect(isNegativeInf(-math.inf(f64)));
expect(!isNegativeInf(math.inf(f128)));
expect(isNegativeInf(-math.inf(f128)));
} }

View File

@ -18,6 +18,10 @@ pub fn isNan(x: var) bool {
const bits = @bitCast(u64, x); const bits = @bitCast(u64, x);
return (bits & (maxInt(u64) >> 1)) > (u64(0x7FF) << 52); return (bits & (maxInt(u64) >> 1)) > (u64(0x7FF) << 52);
}, },
f128 => {
const bits = @bitCast(u128, x);
return (bits & (maxInt(u128) >> 1)) > (u128(0x7FFF) << 112);
},
else => { else => {
@compileError("isNan not implemented for " ++ @typeName(T)); @compileError("isNan not implemented for " ++ @typeName(T));
}, },
@ -34,7 +38,9 @@ test "math.isNan" {
expect(isNan(math.nan(f16))); expect(isNan(math.nan(f16)));
expect(isNan(math.nan(f32))); expect(isNan(math.nan(f32)));
expect(isNan(math.nan(f64))); expect(isNan(math.nan(f64)));
expect(isNan(math.nan(f128)));
expect(!isNan(f16(1.0))); expect(!isNan(f16(1.0)));
expect(!isNan(f32(1.0))); expect(!isNan(f32(1.0)));
expect(!isNan(f64(1.0))); expect(!isNan(f64(1.0)));
expect(!isNan(f128(1.0)));
} }

View File

@ -2,9 +2,10 @@ const math = @import("index.zig");
pub fn nan(comptime T: type) T { pub fn nan(comptime T: type) T {
return switch (T) { return switch (T) {
f16 => @bitCast(f16, math.nan_u16), f16 => math.nan_f16,
f32 => @bitCast(f32, math.nan_u32), f32 => math.nan_f32,
f64 => @bitCast(f64, math.nan_u64), f64 => math.nan_f64,
f128 => math.nan_f128,
else => @compileError("nan not implemented for " ++ @typeName(T)), else => @compileError("nan not implemented for " ++ @typeName(T)),
}; };
} }

View File

@ -25,7 +25,7 @@ pub fn powi(comptime T: type, x: T, y: T) (error{
// powi(x, +-0) = 1 for any x // powi(x, +-0) = 1 for any x
if (y == 0 or y == -0) { if (y == 0 or y == -0) {
return 0; return 1;
} }
switch (x) { switch (x) {
@ -174,4 +174,11 @@ test "math.powi.special" {
testing.expectError(error.Overflow, powi(u64, 2, 64)); testing.expectError(error.Overflow, powi(u64, 2, 64));
testing.expectError(error.Overflow, powi(u17, 2, 17)); testing.expectError(error.Overflow, powi(u17, 2, 17));
testing.expectError(error.Overflow, powi(u42, 2, 42)); testing.expectError(error.Overflow, powi(u42, 2, 42));
testing.expect((try powi(u8, 6, 0)) == 1);
testing.expect((try powi(u16, 5, 0)) == 1);
testing.expect((try powi(u32, 12, 0)) == 1);
testing.expect((try powi(u64, 34, 0)) == 1);
testing.expect((try powi(u17, 16, 0)) == 1);
testing.expect((try powi(u42, 34, 0)) == 1);
} }

View File

@ -423,8 +423,7 @@ pub fn readVarInt(comptime ReturnType: type, bytes: []const u8, endian: builtin.
/// This function cannot fail and cannot cause undefined behavior. /// This function cannot fail and cannot cause undefined behavior.
/// Assumes the endianness of memory is native. This means the function can /// Assumes the endianness of memory is native. This means the function can
/// simply pointer cast memory. /// simply pointer cast memory.
pub fn readIntNative(comptime T: type, bytes: *const [@sizeOf(T)]u8) T { pub fn readIntNative(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)]u8) T {
comptime assert(T.bit_count % 8 == 0);
return @ptrCast(*align(1) const T, bytes).*; return @ptrCast(*align(1) const T, bytes).*;
} }
@ -432,7 +431,7 @@ pub fn readIntNative(comptime T: type, bytes: *const [@sizeOf(T)]u8) T {
/// The bit count of T must be evenly divisible by 8. /// The bit count of T must be evenly divisible by 8.
/// 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 [@sizeOf(T)]u8) T { pub fn readIntForeign(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)]u8) T {
return @bswap(T, readIntNative(T, bytes)); return @bswap(T, readIntNative(T, bytes));
} }
@ -446,22 +445,20 @@ pub const readIntBig = switch (builtin.endian) {
builtin.Endian.Big => readIntNative, builtin.Endian.Big => readIntNative,
}; };
/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0 /// Asserts that bytes.len >= T.bit_count / 8. Reads the integer starting from index 0
/// and ignores extra bytes. /// and ignores extra bytes.
/// Note that @sizeOf(u24) is 3.
/// 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 native. This means the function can /// Assumes the endianness of memory is native. This means the function can
/// simply pointer cast memory. /// simply pointer cast memory.
pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T { pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T {
assert(@sizeOf(u24) == 3); const n = @divExact(T.bit_count, 8);
assert(bytes.len >= @sizeOf(T)); assert(bytes.len >= n);
// TODO https://github.com/ziglang/zig/issues/863 // TODO https://github.com/ziglang/zig/issues/863
return readIntNative(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr)); return readIntNative(T, @ptrCast(*const [n]u8, bytes.ptr));
} }
/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0 /// Asserts that bytes.len >= T.bit_count / 8. Reads the integer starting from index 0
/// and ignores extra bytes. /// and ignores extra bytes.
/// Note that @sizeOf(u24) is 3.
/// 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 {
@ -481,7 +478,7 @@ pub const readIntSliceBig = switch (builtin.endian) {
/// Reads an integer from memory with bit count specified by T. /// Reads an integer from memory with bit count specified by T.
/// The bit count of T must be evenly divisible by 8. /// The bit count of T must be evenly divisible by 8.
/// This function cannot fail and cannot cause undefined behavior. /// This function cannot fail and cannot cause undefined behavior.
pub fn readInt(comptime T: type, bytes: *const [@sizeOf(T)]u8, endian: builtin.Endian) T { pub fn readInt(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)]u8, endian: builtin.Endian) T {
if (endian == builtin.endian) { if (endian == builtin.endian) {
return readIntNative(T, bytes); return readIntNative(T, bytes);
} else { } else {
@ -489,15 +486,14 @@ pub fn readInt(comptime T: type, bytes: *const [@sizeOf(T)]u8, endian: builtin.E
} }
} }
/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0 /// Asserts that bytes.len >= T.bit_count / 8. Reads the integer starting from index 0
/// and ignores extra bytes. /// and ignores extra bytes.
/// Note that @sizeOf(u24) is 3.
/// The bit count of T must be evenly divisible by 8. /// The bit count of T must be evenly divisible by 8.
pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) T { pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) T {
assert(@sizeOf(u24) == 3); const n = @divExact(T.bit_count, 8);
assert(bytes.len >= @sizeOf(T)); assert(bytes.len >= n);
// TODO https://github.com/ziglang/zig/issues/863 // TODO https://github.com/ziglang/zig/issues/863
return readInt(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr), endian); return readInt(T, @ptrCast(*const [n]u8, bytes.ptr), endian);
} }
test "comptime read/write int" { test "comptime read/write int" {
@ -540,7 +536,7 @@ test "readIntBig and readIntLittle" {
/// accepts any integer bit width. /// accepts any integer bit width.
/// This function stores in native endian, which means it is implemented as a simple /// This function stores in native endian, which means it is implemented as a simple
/// memory store. /// memory store.
pub fn writeIntNative(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { pub fn writeIntNative(comptime T: type, buf: *[(T.bit_count + 7) / 8]u8, value: T) void {
@ptrCast(*align(1) T, buf).* = value; @ptrCast(*align(1) T, buf).* = value;
} }
@ -548,7 +544,7 @@ pub fn writeIntNative(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void {
/// This function always succeeds, has defined behavior for all inputs, but /// This function always succeeds, has defined behavior for all inputs, but
/// 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 @bswap first. /// This function stores in foreign endian, which means it does a @bswap first.
pub fn writeIntForeign(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { pub fn writeIntForeign(comptime T: type, buf: *[@divExact(T.bit_count, 8)]u8, value: T) void {
writeIntNative(T, buf, @bswap(T, value)); writeIntNative(T, buf, @bswap(T, value));
} }
@ -565,8 +561,7 @@ pub const writeIntBig = switch (builtin.endian) {
/// Writes an integer to memory, storing it in twos-complement. /// Writes an integer to memory, storing it in twos-complement.
/// This function always succeeds, has defined behavior for all inputs, but /// This function always succeeds, has defined behavior for all inputs, but
/// the integer bit width must be divisible by 8. /// the integer bit width must be divisible by 8.
pub fn writeInt(comptime T: type, buffer: *[@sizeOf(T)]u8, value: T, endian: builtin.Endian) void { pub fn writeInt(comptime T: type, buffer: *[@divExact(T.bit_count, 8)]u8, value: T, endian: builtin.Endian) void {
comptime assert(T.bit_count % 8 == 0);
if (endian == builtin.endian) { if (endian == builtin.endian) {
return writeIntNative(T, buffer, value); return writeIntNative(T, buffer, value);
} else { } else {
@ -575,15 +570,13 @@ pub fn writeInt(comptime T: type, buffer: *[@sizeOf(T)]u8, value: T, endian: bui
} }
/// Writes a twos-complement little-endian integer to memory. /// Writes a twos-complement little-endian integer to memory.
/// Asserts that buf.len >= @sizeOf(T). Note that @sizeOf(u24) is 3. /// Asserts that buf.len >= T.bit_count / 8.
/// The bit count of T must be divisible by 8. /// The bit count of T must be divisible by 8.
/// Any extra bytes in buffer after writing the integer are set to zero. To /// Any extra bytes in buffer after writing the integer are set to zero. To
/// avoid the branch to check for extra buffer bytes, use writeIntLittle /// avoid the branch to check for extra buffer bytes, use writeIntLittle
/// instead. /// instead.
pub fn writeIntSliceLittle(comptime T: type, buffer: []u8, value: T) void { pub fn writeIntSliceLittle(comptime T: type, buffer: []u8, value: T) void {
comptime assert(@sizeOf(u24) == 3); assert(buffer.len >= @divExact(T.bit_count, 8));
comptime assert(T.bit_count % 8 == 0);
assert(buffer.len >= @sizeOf(T));
// TODO I want to call writeIntLittle here but comptime eval facilities aren't good enough // TODO I want to call writeIntLittle here but comptime eval facilities aren't good enough
const uint = @IntType(false, T.bit_count); const uint = @IntType(false, T.bit_count);
@ -595,14 +588,12 @@ pub fn writeIntSliceLittle(comptime T: type, buffer: []u8, value: T) void {
} }
/// Writes a twos-complement big-endian integer to memory. /// Writes a twos-complement big-endian integer to memory.
/// Asserts that buffer.len >= @sizeOf(T). Note that @sizeOf(u24) is 3. /// Asserts that buffer.len >= T.bit_count / 8.
/// The bit count of T must be divisible by 8. /// The bit count of T must be divisible by 8.
/// Any extra bytes in buffer before writing the integer are set to zero. To /// Any extra bytes in buffer before writing the integer are set to zero. To
/// avoid the branch to check for extra buffer bytes, use writeIntBig instead. /// avoid the branch to check for extra buffer bytes, use writeIntBig instead.
pub fn writeIntSliceBig(comptime T: type, buffer: []u8, value: T) void { pub fn writeIntSliceBig(comptime T: type, buffer: []u8, value: T) void {
comptime assert(@sizeOf(u24) == 3); assert(buffer.len >= @divExact(T.bit_count, 8));
comptime assert(T.bit_count % 8 == 0);
assert(buffer.len >= @sizeOf(T));
// TODO I want to call writeIntBig here but comptime eval facilities aren't good enough // TODO I want to call writeIntBig here but comptime eval facilities aren't good enough
const uint = @IntType(false, T.bit_count); const uint = @IntType(false, T.bit_count);
@ -626,7 +617,7 @@ pub const writeIntSliceForeign = switch (builtin.endian) {
}; };
/// Writes a twos-complement integer to memory, with the specified endianness. /// Writes a twos-complement integer to memory, with the specified endianness.
/// Asserts that buf.len >= @sizeOf(T). Note that @sizeOf(u24) is 3. /// Asserts that buf.len >= T.bit_count / 8.
/// The bit count of T must be evenly divisible by 8. /// The bit count of T must be evenly divisible by 8.
/// Any extra bytes in buffer not part of the integer are set to zero, with /// Any extra bytes in buffer not part of the integer are set to zero, with
/// respect to endianness. To avoid the branch to check for extra buffer bytes, /// respect to endianness. To avoid the branch to check for extra buffer bytes,

View File

@ -463,13 +463,16 @@ pub fn eql(a: var, b: @typeOf(a)) bool {
builtin.TypeId.Pointer => { builtin.TypeId.Pointer => {
const info = @typeInfo(T).Pointer; const info = @typeInfo(T).Pointer;
switch (info.size) { switch (info.size) {
builtin.TypeInfo.Pointer.Size.One, builtin.TypeInfo.Pointer.Size.Many => return a == b, builtin.TypeInfo.Pointer.Size.One,
builtin.TypeInfo.Pointer.Size.Many,
builtin.TypeInfo.Pointer.Size.C,
=> return a == b,
builtin.TypeInfo.Pointer.Size.Slice => return a.ptr == b.ptr and a.len == b.len, builtin.TypeInfo.Pointer.Size.Slice => return a.ptr == b.ptr and a.len == b.len,
} }
}, },
builtin.TypeId.Optional => { builtin.TypeId.Optional => {
if(a == null and b == null) return true; if (a == null and b == null) return true;
if(a == null or b == null) return false; if (a == null or b == null) return false;
return eql(a.?, b.?); return eql(a.?, b.?);
}, },
else => return a == b, else => return a == b,

View File

@ -665,7 +665,7 @@ pub fn pwrite(fd: i32, buf: [*]const u8, nbyte: usize, offset: u64) usize {
pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize { pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
const ptr_result = c.mmap( const ptr_result = c.mmap(
@ptrCast(*c_void, address), @ptrCast(?*c_void, address),
length, length,
@bitCast(c_int, @intCast(c_uint, prot)), @bitCast(c_int, @intCast(c_uint, prot)),
@bitCast(c_int, c_uint(flags)), @bitCast(c_int, c_uint(flags)),

View File

@ -105,7 +105,7 @@ pub const File = struct {
pub fn openWriteNoClobber(path: []const u8, file_mode: Mode) OpenError!File { pub fn openWriteNoClobber(path: []const u8, file_mode: Mode) OpenError!File {
if (is_posix) { if (is_posix) {
const path_c = try os.toPosixPath(path); const path_c = try os.toPosixPath(path);
return openWriteNoClobberC(path_c, file_mode); return openWriteNoClobberC(&path_c, file_mode);
} else if (is_windows) { } else if (is_windows) {
const path_w = try windows_util.sliceToPrefixedFileW(path); const path_w = try windows_util.sliceToPrefixedFileW(path);
return openWriteNoClobberW(&path_w, file_mode); return openWriteNoClobberW(&path_w, file_mode);
@ -237,7 +237,7 @@ pub const File = struct {
pub fn seekForward(self: File, amount: isize) SeekError!void { pub fn seekForward(self: File, amount: isize) SeekError!void {
switch (builtin.os) { switch (builtin.os) {
Os.linux, Os.macosx, Os.ios, Os.freebsd => { Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
const result = posix.lseek(self.handle, amount, posix.SEEK_CUR); const result = posix.lseek(self.handle, amount, posix.SEEK_CUR);
const err = posix.getErrno(result); const err = posix.getErrno(result);
if (err > 0) { if (err > 0) {
@ -268,7 +268,7 @@ pub const File = struct {
pub fn seekTo(self: File, pos: usize) SeekError!void { pub fn seekTo(self: File, pos: usize) SeekError!void {
switch (builtin.os) { switch (builtin.os) {
Os.linux, Os.macosx, Os.ios, Os.freebsd => { Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
const ipos = try math.cast(isize, pos); const ipos = try math.cast(isize, pos);
const result = posix.lseek(self.handle, ipos, posix.SEEK_SET); const result = posix.lseek(self.handle, ipos, posix.SEEK_SET);
const err = posix.getErrno(result); const err = posix.getErrno(result);
@ -309,7 +309,7 @@ pub const File = struct {
pub fn getPos(self: File) GetSeekPosError!usize { pub fn getPos(self: File) GetSeekPosError!usize {
switch (builtin.os) { switch (builtin.os) {
Os.linux, Os.macosx, Os.ios, Os.freebsd => { Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
const result = posix.lseek(self.handle, 0, posix.SEEK_CUR); const result = posix.lseek(self.handle, 0, posix.SEEK_CUR);
const err = posix.getErrno(result); const err = posix.getErrno(result);
if (err > 0) { if (err > 0) {

View File

@ -617,7 +617,7 @@ pub fn mkdir(path: [*]const u8, mode: u32) usize {
pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize { pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
const ptr_result = c.mmap( const ptr_result = c.mmap(
@ptrCast(*c_void, address), @ptrCast(?*c_void, address),
length, length,
@bitCast(c_int, @intCast(c_uint, prot)), @bitCast(c_int, @intCast(c_uint, prot)),
@bitCast(c_int, c_uint(flags)), @bitCast(c_int, c_uint(flags)),

View File

@ -43,7 +43,7 @@ pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataD
}; };
return os.path.join(allocator, [][]const u8{ home_dir, "Library", "Application Support", appname }); return os.path.join(allocator, [][]const u8{ home_dir, "Library", "Application Support", appname });
}, },
builtin.Os.linux, builtin.Os.freebsd => { builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => {
const home_dir = os.getEnvPosix("HOME") orelse { const home_dir = os.getEnvPosix("HOME") orelse {
// TODO look in /etc/passwd // TODO look in /etc/passwd
return error.AppDataDirUnavailable; return error.AppDataDirUnavailable;

View File

@ -11,7 +11,7 @@ pub const UserInfo = struct {
/// POSIX function which gets a uid from username. /// POSIX function which gets a uid from username.
pub fn getUserInfo(name: []const u8) !UserInfo { pub fn getUserInfo(name: []const u8) !UserInfo {
return switch (builtin.os) { return switch (builtin.os) {
Os.linux, Os.macosx, Os.ios, Os.freebsd => posixGetUserInfo(name), Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => posixGetUserInfo(name),
else => @compileError("Unsupported OS"), else => @compileError("Unsupported OS"),
}; };
} }

View File

@ -3,7 +3,7 @@ const builtin = @import("builtin");
const Os = builtin.Os; const Os = builtin.Os;
const is_windows = builtin.os == Os.windows; const is_windows = builtin.os == Os.windows;
const is_posix = switch (builtin.os) { const is_posix = switch (builtin.os) {
builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd => true, builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => true,
else => false, else => false,
}; };
const os = @This(); const os = @This();
@ -30,6 +30,7 @@ pub const windows = @import("windows/index.zig");
pub const darwin = @import("darwin.zig"); pub const darwin = @import("darwin.zig");
pub const linux = @import("linux/index.zig"); pub const linux = @import("linux/index.zig");
pub const freebsd = @import("freebsd/index.zig"); pub const freebsd = @import("freebsd/index.zig");
pub const netbsd = @import("netbsd/index.zig");
pub const zen = @import("zen.zig"); pub const zen = @import("zen.zig");
pub const uefi = @import("uefi.zig"); pub const uefi = @import("uefi.zig");
@ -37,6 +38,7 @@ pub const posix = switch (builtin.os) {
Os.linux => linux, Os.linux => linux,
Os.macosx, Os.ios => darwin, Os.macosx, Os.ios => darwin,
Os.freebsd => freebsd, Os.freebsd => freebsd,
Os.netbsd => netbsd,
Os.zen => zen, Os.zen => zen,
else => @compileError("Unsupported OS"), else => @compileError("Unsupported OS"),
}; };
@ -50,7 +52,7 @@ pub const time = @import("time.zig");
pub const page_size = 4 * 1024; pub const page_size = 4 * 1024;
pub const MAX_PATH_BYTES = switch (builtin.os) { pub const MAX_PATH_BYTES = switch (builtin.os) {
Os.linux, Os.macosx, Os.ios, Os.freebsd => posix.PATH_MAX, Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => posix.PATH_MAX,
// Each UTF-16LE character may be expanded to 3 UTF-8 bytes. // Each UTF-16LE character may be expanded to 3 UTF-8 bytes.
// If it would require 4 UTF-8 bytes, then there would be a surrogate // If it would require 4 UTF-8 bytes, then there would be a surrogate
// pair in the UTF-16LE, and we (over)account 3 bytes for it that way. // pair in the UTF-16LE, and we (over)account 3 bytes for it that way.
@ -125,7 +127,7 @@ pub fn getRandomBytes(buf: []u8) !void {
else => return unexpectedErrorPosix(errno), else => return unexpectedErrorPosix(errno),
} }
}, },
Os.macosx, Os.ios, Os.freebsd => return getRandomBytesDevURandom(buf), Os.macosx, Os.ios, Os.freebsd, Os.netbsd => return getRandomBytesDevURandom(buf),
Os.windows => { Os.windows => {
// Call RtlGenRandom() instead of CryptGetRandom() on Windows // Call RtlGenRandom() instead of CryptGetRandom() on Windows
// https://github.com/rust-lang-nursery/rand/issues/111 // https://github.com/rust-lang-nursery/rand/issues/111
@ -185,7 +187,7 @@ pub fn abort() noreturn {
c.abort(); c.abort();
} }
switch (builtin.os) { switch (builtin.os) {
Os.linux, Os.macosx, Os.ios, Os.freebsd => { Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
_ = posix.raise(posix.SIGABRT); _ = posix.raise(posix.SIGABRT);
_ = posix.raise(posix.SIGKILL); _ = posix.raise(posix.SIGKILL);
while (true) {} while (true) {}
@ -211,7 +213,7 @@ pub fn exit(status: u8) noreturn {
c.exit(status); c.exit(status);
} }
switch (builtin.os) { switch (builtin.os) {
Os.linux, Os.macosx, Os.ios, Os.freebsd => { Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
posix.exit(status); posix.exit(status);
}, },
Os.windows => { Os.windows => {
@ -327,7 +329,7 @@ pub fn posix_preadv(fd: i32, iov: [*]const posix.iovec, count: usize, offset: u6
} }
} }
}, },
builtin.Os.linux, builtin.Os.freebsd => while (true) { builtin.Os.linux, builtin.Os.freebsd, Os.netbsd => while (true) {
const rc = posix.preadv(fd, iov, count, offset); const rc = posix.preadv(fd, iov, count, offset);
const err = posix.getErrno(rc); const err = posix.getErrno(rc);
switch (err) { switch (err) {
@ -434,7 +436,7 @@ pub fn posix_pwritev(fd: i32, iov: [*]const posix.iovec_const, count: usize, off
} }
} }
}, },
builtin.Os.linux, builtin.Os.freebsd => while (true) { builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => while (true) {
const rc = posix.pwritev(fd, iov, count, offset); const rc = posix.pwritev(fd, iov, count, offset);
const err = posix.getErrno(rc); const err = posix.getErrno(rc);
switch (err) { switch (err) {
@ -699,7 +701,9 @@ pub fn getBaseAddress() usize {
const phdr = linuxGetAuxVal(std.elf.AT_PHDR); const phdr = linuxGetAuxVal(std.elf.AT_PHDR);
return phdr - @sizeOf(std.elf.Ehdr); return phdr - @sizeOf(std.elf.Ehdr);
}, },
builtin.Os.macosx, builtin.Os.freebsd => return @ptrToInt(&std.c._mh_execute_header), builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
return @ptrToInt(&std.c._mh_execute_header);
},
builtin.Os.windows => return @ptrToInt(windows.GetModuleHandleW(null)), builtin.Os.windows => return @ptrToInt(windows.GetModuleHandleW(null)),
else => @compileError("Unsupported OS"), else => @compileError("Unsupported OS"),
} }
@ -1339,7 +1343,7 @@ pub fn deleteDirC(dir_path: [*]const u8) DeleteDirError!void {
const dir_path_w = try windows_util.cStrToPrefixedFileW(dir_path); const dir_path_w = try windows_util.cStrToPrefixedFileW(dir_path);
return deleteDirW(&dir_path_w); return deleteDirW(&dir_path_w);
}, },
Os.linux, Os.macosx, Os.ios, Os.freebsd => { Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
const err = posix.getErrno(posix.rmdir(dir_path)); const err = posix.getErrno(posix.rmdir(dir_path));
switch (err) { switch (err) {
0 => return, 0 => return,
@ -1382,7 +1386,7 @@ pub fn deleteDir(dir_path: []const u8) DeleteDirError!void {
const dir_path_w = try windows_util.sliceToPrefixedFileW(dir_path); const dir_path_w = try windows_util.sliceToPrefixedFileW(dir_path);
return deleteDirW(&dir_path_w); return deleteDirW(&dir_path_w);
}, },
Os.linux, Os.macosx, Os.ios, Os.freebsd => { Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
const dir_path_c = try toPosixPath(dir_path); const dir_path_c = try toPosixPath(dir_path);
return deleteDirC(&dir_path_c); return deleteDirC(&dir_path_c);
}, },
@ -1501,7 +1505,7 @@ pub const Dir = struct {
allocator: *Allocator, allocator: *Allocator,
pub const Handle = switch (builtin.os) { pub const Handle = switch (builtin.os) {
Os.macosx, Os.ios, Os.freebsd => struct { Os.macosx, Os.ios, Os.freebsd, Os.netbsd => struct {
fd: i32, fd: i32,
seek: i64, seek: i64,
buf: []u8, buf: []u8,
@ -1578,7 +1582,7 @@ pub const Dir = struct {
.name_data = undefined, .name_data = undefined,
}; };
}, },
Os.macosx, Os.ios, Os.freebsd => Handle{ Os.macosx, Os.ios, Os.freebsd, Os.netbsd => Handle{
.fd = try posixOpen( .fd = try posixOpen(
dir_path, dir_path,
posix.O_RDONLY | posix.O_NONBLOCK | posix.O_DIRECTORY | posix.O_CLOEXEC, posix.O_RDONLY | posix.O_NONBLOCK | posix.O_DIRECTORY | posix.O_CLOEXEC,
@ -1609,7 +1613,7 @@ pub const Dir = struct {
Os.windows => { Os.windows => {
_ = windows.FindClose(self.handle.handle); _ = windows.FindClose(self.handle.handle);
}, },
Os.macosx, Os.ios, Os.linux, Os.freebsd => { Os.macosx, Os.ios, Os.linux, Os.freebsd, Os.netbsd => {
self.allocator.free(self.handle.buf); self.allocator.free(self.handle.buf);
os.close(self.handle.fd); os.close(self.handle.fd);
}, },
@ -1625,6 +1629,7 @@ pub const Dir = struct {
Os.macosx, Os.ios => return self.nextDarwin(), Os.macosx, Os.ios => return self.nextDarwin(),
Os.windows => return self.nextWindows(), Os.windows => return self.nextWindows(),
Os.freebsd => return self.nextFreebsd(), Os.freebsd => return self.nextFreebsd(),
Os.netbsd => return self.nextFreebsd(),
else => @compileError("unimplemented"), else => @compileError("unimplemented"),
} }
} }
@ -2256,7 +2261,7 @@ pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError {
pub fn openSelfExe() !os.File { pub fn openSelfExe() !os.File {
switch (builtin.os) { switch (builtin.os) {
Os.linux => return os.File.openReadC(c"/proc/self/exe"), Os.linux => return os.File.openReadC(c"/proc/self/exe"),
Os.macosx, Os.ios, Os.freebsd => { Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
var buf: [MAX_PATH_BYTES]u8 = undefined; var buf: [MAX_PATH_BYTES]u8 = undefined;
const self_exe_path = try selfExePath(&buf); const self_exe_path = try selfExePath(&buf);
buf[self_exe_path.len] = 0; buf[self_exe_path.len] = 0;
@ -2317,6 +2322,19 @@ pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
else => unexpectedErrorPosix(err), else => unexpectedErrorPosix(err),
}; };
}, },
Os.netbsd => {
var mib = [4]c_int{ posix.CTL_KERN, posix.KERN_PROC_ARGS, -1, posix.KERN_PROC_PATHNAME };
var out_len: usize = out_buffer.len;
const err = posix.getErrno(posix.sysctl(&mib, 4, out_buffer, &out_len, null, 0));
if (err == 0) return mem.toSlice(u8, out_buffer);
return switch (err) {
posix.EFAULT => error.BadAdress,
posix.EPERM => error.PermissionDenied,
else => unexpectedErrorPosix(err),
};
},
Os.windows => { Os.windows => {
var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined; var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
const utf16le_slice = try selfExePathW(&utf16le_buf); const utf16le_slice = try selfExePathW(&utf16le_buf);
@ -2355,7 +2373,7 @@ pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) ![]const u8 {
// will not return null. // will not return null.
return path.dirname(full_exe_path).?; return path.dirname(full_exe_path).?;
}, },
Os.windows, Os.macosx, Os.ios, Os.freebsd => { Os.windows, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
const self_exe_path = try selfExePath(out_buffer); const self_exe_path = try selfExePath(out_buffer);
// Assume that the OS APIs return absolute paths, and therefore dirname // Assume that the OS APIs return absolute paths, and therefore dirname
// will not return null. // will not return null.
@ -3227,7 +3245,7 @@ pub const CpuCountError = error{
pub fn cpuCount(fallback_allocator: *mem.Allocator) CpuCountError!usize { pub fn cpuCount(fallback_allocator: *mem.Allocator) CpuCountError!usize {
switch (builtin.os) { switch (builtin.os) {
builtin.Os.macosx, builtin.Os.freebsd => { builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
var count: c_int = undefined; var count: c_int = undefined;
var count_len: usize = @sizeOf(c_int); var count_len: usize = @sizeOf(c_int);
const rc = posix.sysctlbyname(switch (builtin.os) { const rc = posix.sysctlbyname(switch (builtin.os) {

View File

@ -6,7 +6,7 @@ const vdso = @import("vdso.zig");
pub use switch (builtin.arch) { pub use switch (builtin.arch) {
builtin.Arch.x86_64 => @import("x86_64.zig"), builtin.Arch.x86_64 => @import("x86_64.zig"),
builtin.Arch.i386 => @import("i386.zig"), builtin.Arch.i386 => @import("i386.zig"),
builtin.Arch.aarch64v8 => @import("arm64.zig"), builtin.Arch.aarch64 => @import("arm64.zig"),
else => @compileError("unsupported arch"), else => @compileError("unsupported arch"),
}; };
pub use @import("errno.zig"); pub use @import("errno.zig");

134
std/os/netbsd/errno.zig Normal file
View File

@ -0,0 +1,134 @@
pub const EPERM = 1; // Operation not permitted
pub const ENOENT = 2; // No such file or directory
pub const ESRCH = 3; // No such process
pub const EINTR = 4; // Interrupted system call
pub const EIO = 5; // Input/output error
pub const ENXIO = 6; // Device not configured
pub const E2BIG = 7; // Argument list too long
pub const ENOEXEC = 8; // Exec format error
pub const EBADF = 9; // Bad file descriptor
pub const ECHILD = 10; // No child processes
pub const EDEADLK = 11; // Resource deadlock avoided
// 11 was EAGAIN
pub const ENOMEM = 12; // Cannot allocate memory
pub const EACCES = 13; // Permission denied
pub const EFAULT = 14; // Bad address
pub const ENOTBLK = 15; // Block device required
pub const EBUSY = 16; // Device busy
pub const EEXIST = 17; // File exists
pub const EXDEV = 18; // Cross-device link
pub const ENODEV = 19; // Operation not supported by device
pub const ENOTDIR = 20; // Not a directory
pub const EISDIR = 21; // Is a directory
pub const EINVAL = 22; // Invalid argument
pub const ENFILE = 23; // Too many open files in system
pub const EMFILE = 24; // Too many open files
pub const ENOTTY = 25; // Inappropriate ioctl for device
pub const ETXTBSY = 26; // Text file busy
pub const EFBIG = 27; // File too large
pub const ENOSPC = 28; // No space left on device
pub const ESPIPE = 29; // Illegal seek
pub const EROFS = 30; // Read-only file system
pub const EMLINK = 31; // Too many links
pub const EPIPE = 32; // Broken pipe
// math software
pub const EDOM = 33; // Numerical argument out of domain
pub const ERANGE = 34; // Result too large or too small
// non-blocking and interrupt i/o
pub const EAGAIN = 35; // Resource temporarily unavailable
pub const EWOULDBLOCK = EAGAIN; // Operation would block
pub const EINPROGRESS = 36; // Operation now in progress
pub const EALREADY = 37; // Operation already in progress
// ipc/network software -- argument errors
pub const ENOTSOCK = 38; // Socket operation on non-socket
pub const EDESTADDRREQ = 39; // Destination address required
pub const EMSGSIZE = 40; // Message too long
pub const EPROTOTYPE = 41; // Protocol wrong type for socket
pub const ENOPROTOOPT = 42; // Protocol option not available
pub const EPROTONOSUPPORT = 43; // Protocol not supported
pub const ESOCKTNOSUPPORT = 44; // Socket type not supported
pub const EOPNOTSUPP = 45; // Operation not supported
pub const EPFNOSUPPORT = 46; // Protocol family not supported
pub const EAFNOSUPPORT = 47; // Address family not supported by protocol family
pub const EADDRINUSE = 48; // Address already in use
pub const EADDRNOTAVAIL = 49; // Can't assign requested address
// ipc/network software -- operational errors
pub const ENETDOWN = 50; // Network is down
pub const ENETUNREACH = 51; // Network is unreachable
pub const ENETRESET = 52; // Network dropped connection on reset
pub const ECONNABORTED = 53; // Software caused connection abort
pub const ECONNRESET = 54; // Connection reset by peer
pub const ENOBUFS = 55; // No buffer space available
pub const EISCONN = 56; // Socket is already connected
pub const ENOTCONN = 57; // Socket is not connected
pub const ESHUTDOWN = 58; // Can't send after socket shutdown
pub const ETOOMANYREFS = 59; // Too many references: can't splice
pub const ETIMEDOUT = 60; // Operation timed out
pub const ECONNREFUSED = 61; // Connection refused
pub const ELOOP = 62; // Too many levels of symbolic links
pub const ENAMETOOLONG = 63; // File name too long
// should be rearranged
pub const EHOSTDOWN = 64; // Host is down
pub const EHOSTUNREACH = 65; // No route to host
pub const ENOTEMPTY = 66; // Directory not empty
// quotas & mush
pub const EPROCLIM = 67; // Too many processes
pub const EUSERS = 68; // Too many users
pub const EDQUOT = 69; // Disc quota exceeded
// Network File System
pub const ESTALE = 70; // Stale NFS file handle
pub const EREMOTE = 71; // Too many levels of remote in path
pub const EBADRPC = 72; // RPC struct is bad
pub const ERPCMISMATCH = 73; // RPC version wrong
pub const EPROGUNAVAIL = 74; // RPC prog. not avail
pub const EPROGMISMATCH = 75; // Program version wrong
pub const EPROCUNAVAIL = 76; // Bad procedure for program
pub const ENOLCK = 77; // No locks available
pub const ENOSYS = 78; // Function not implemented
pub const EFTYPE = 79; // Inappropriate file type or format
pub const EAUTH = 80; // Authentication error
pub const ENEEDAUTH = 81; // Need authenticator
// SystemV IPC
pub const EIDRM = 82; // Identifier removed
pub const ENOMSG = 83; // No message of desired type
pub const EOVERFLOW = 84; // Value too large to be stored in data type
// Wide/multibyte-character handling, ISO/IEC 9899/AMD1:1995
pub const EILSEQ = 85; // Illegal byte sequence
// From IEEE Std 1003.1-2001
// Base, Realtime, Threads or Thread Priority Scheduling option errors
pub const ENOTSUP = 86; // Not supported
// Realtime option errors
pub const ECANCELED = 87; // Operation canceled
// Realtime, XSI STREAMS option errors
pub const EBADMSG = 88; // Bad or Corrupt message
// XSI STREAMS option errors
pub const ENODATA = 89; // No message available
pub const ENOSR = 90; // No STREAM resources
pub const ENOSTR = 91; // Not a STREAM
pub const ETIME = 92; // STREAM ioctl timeout
// File system extended attribute errors
pub const ENOATTR = 93; // Attribute not found
// Realtime, XSI STREAMS option errors
pub const EMULTIHOP = 94; // Multihop attempted
pub const ENOLINK = 95; // Link has been severed
pub const EPROTO = 96; // Protocol error
pub const ELAST = 96; // Must equal largest errno

725
std/os/netbsd/index.zig Normal file
View File

@ -0,0 +1,725 @@
const builtin = @import("builtin");
pub use @import("errno.zig");
const std = @import("../../index.zig");
const c = std.c;
const assert = std.debug.assert;
const maxInt = std.math.maxInt;
pub const Kevent = c.Kevent;
pub const CTL_KERN = 1;
pub const CTL_DEBUG = 5;
pub const KERN_PROC_ARGS = 48; // struct: process argv/env
pub const KERN_PROC_PATHNAME = 5; // path to executable
pub const PATH_MAX = 1024;
pub const STDIN_FILENO = 0;
pub const STDOUT_FILENO = 1;
pub const STDERR_FILENO = 2;
pub const PROT_NONE = 0;
pub const PROT_READ = 1;
pub const PROT_WRITE = 2;
pub const PROT_EXEC = 4;
pub const CLOCK_REALTIME = 0;
pub const CLOCK_VIRTUAL = 1;
pub const CLOCK_PROF = 2;
pub const CLOCK_MONOTONIC = 3;
pub const CLOCK_THREAD_CPUTIME_ID = 0x20000000;
pub const CLOCK_PROCESS_CPUTIME_ID = 0x40000000;
pub const MAP_FAILED = maxInt(usize);
pub const MAP_SHARED = 0x0001;
pub const MAP_PRIVATE = 0x0002;
pub const MAP_REMAPDUP = 0x0004;
pub const MAP_FIXED = 0x0010;
pub const MAP_RENAME = 0x0020;
pub const MAP_NORESERVE = 0x0040;
pub const MAP_INHERIT = 0x0080;
pub const MAP_HASSEMAPHORE = 0x0200;
pub const MAP_TRYFIXED = 0x0400;
pub const MAP_WIRED = 0x0800;
pub const MAP_FILE = 0x0000;
pub const MAP_NOSYNC = 0x0800;
pub const MAP_ANON = 0x1000;
pub const MAP_ANONYMOUS = MAP_ANON;
pub const MAP_STACK = 0x2000;
pub const WNOHANG = 0x00000001;
pub const WUNTRACED = 0x00000002;
pub const WSTOPPED = WUNTRACED;
pub const WCONTINUED = 0x00000010;
pub const WNOWAIT = 0x00010000;
pub const WEXITED = 0x00000020;
pub const WTRAPPED = 0x00000040;
pub const SA_ONSTACK = 0x0001;
pub const SA_RESTART = 0x0002;
pub const SA_RESETHAND = 0x0004;
pub const SA_NOCLDSTOP = 0x0008;
pub const SA_NODEFER = 0x0010;
pub const SA_NOCLDWAIT = 0x0020;
pub const SA_SIGINFO = 0x0040;
pub const SIGHUP = 1;
pub const SIGINT = 2;
pub const SIGQUIT = 3;
pub const SIGILL = 4;
pub const SIGTRAP = 5;
pub const SIGABRT = 6;
pub const SIGIOT = SIGABRT;
pub const SIGEMT = 7;
pub const SIGFPE = 8;
pub const SIGKILL = 9;
pub const SIGBUS = 10;
pub const SIGSEGV = 11;
pub const SIGSYS = 12;
pub const SIGPIPE = 13;
pub const SIGALRM = 14;
pub const SIGTERM = 15;
pub const SIGURG = 16;
pub const SIGSTOP = 17;
pub const SIGTSTP = 18;
pub const SIGCONT = 19;
pub const SIGCHLD = 20;
pub const SIGTTIN = 21;
pub const SIGTTOU = 22;
pub const SIGIO = 23;
pub const SIGXCPU = 24;
pub const SIGXFSZ = 25;
pub const SIGVTALRM = 26;
pub const SIGPROF = 27;
pub const SIGWINCH = 28;
pub const SIGINFO = 29;
pub const SIGUSR1 = 30;
pub const SIGUSR2 = 31;
pub const SIGPWR = 32;
pub const SIGRTMIN = 33;
pub const SIGRTMAX = 63;
// access function
pub const F_OK = 0; // test for existence of file
pub const X_OK = 1; // test for execute or search permission
pub const W_OK = 2; // test for write permission
pub const R_OK = 4; // test for read permission
pub const O_RDONLY = 0x0000;
pub const O_WRONLY = 0x0001;
pub const O_RDWR = 0x0002;
pub const O_ACCMODE = 0x0003;
pub const O_CREAT = 0x0200;
pub const O_EXCL = 0x0800;
pub const O_NOCTTY = 0x8000;
pub const O_TRUNC = 0x0400;
pub const O_APPEND = 0x0008;
pub const O_NONBLOCK = 0x0004;
pub const O_DSYNC = 0x00010000;
pub const O_SYNC = 0x0080;
pub const O_RSYNC = 0x00020000;
pub const O_DIRECTORY = 0x00080000;
pub const O_NOFOLLOW = 0x00000100;
pub const O_CLOEXEC = 0x00400000;
pub const O_ASYNC = 0x0040;
pub const O_DIRECT = 0x00080000;
pub const O_LARGEFILE = 0;
pub const O_NOATIME = 0;
pub const O_PATH = 0;
pub const O_TMPFILE = 0;
pub const O_NDELAY = O_NONBLOCK;
pub const F_DUPFD = 0;
pub const F_GETFD = 1;
pub const F_SETFD = 2;
pub const F_GETFL = 3;
pub const F_SETFL = 4;
pub const F_GETOWN = 5;
pub const F_SETOWN = 6;
pub const F_GETLK = 7;
pub const F_SETLK = 8;
pub const F_SETLKW = 9;
pub const SEEK_SET = 0;
pub const SEEK_CUR = 1;
pub const SEEK_END = 2;
pub const SIG_BLOCK = 1;
pub const SIG_UNBLOCK = 2;
pub const SIG_SETMASK = 3;
pub const SOCK_STREAM = 1;
pub const SOCK_DGRAM = 2;
pub const SOCK_RAW = 3;
pub const SOCK_RDM = 4;
pub const SOCK_SEQPACKET = 5;
pub const SOCK_CLOEXEC = 0x10000000;
pub const SOCK_NONBLOCK = 0x20000000;
pub const PROTO_ip = 0;
pub const PROTO_icmp = 1;
pub const PROTO_igmp = 2;
pub const PROTO_ggp = 3;
pub const PROTO_ipencap = 4;
pub const PROTO_tcp = 6;
pub const PROTO_egp = 8;
pub const PROTO_pup = 12;
pub const PROTO_udp = 17;
pub const PROTO_xns_idp = 22;
pub const PROTO_iso_tp4 = 29;
pub const PROTO_ipv6 = 41;
pub const PROTO_ipv6_route = 43;
pub const PROTO_ipv6_frag = 44;
pub const PROTO_rsvp = 46;
pub const PROTO_gre = 47;
pub const PROTO_esp = 50;
pub const PROTO_ah = 51;
pub const PROTO_ipv6_icmp = 58;
pub const PROTO_ipv6_nonxt = 59;
pub const PROTO_ipv6_opts = 60;
pub const PROTO_encap = 98;
pub const PROTO_pim = 103;
pub const PROTO_raw = 255;
pub const PF_UNSPEC = 0;
pub const PF_LOCAL = 1;
pub const PF_UNIX = PF_LOCAL;
pub const PF_FILE = PF_LOCAL;
pub const PF_INET = 2;
pub const PF_APPLETALK = 16;
pub const PF_INET6 = 24;
pub const PF_DECnet = 12;
pub const PF_KEY = 29;
pub const PF_ROUTE = 34;
pub const PF_SNA = 11;
pub const PF_MPLS = 33;
pub const PF_CAN = 35;
pub const PF_BLUETOOTH = 31;
pub const PF_ISDN = 26;
pub const PF_MAX = 37;
pub const AF_UNSPEC = PF_UNSPEC;
pub const AF_LOCAL = PF_LOCAL;
pub const AF_UNIX = AF_LOCAL;
pub const AF_FILE = AF_LOCAL;
pub const AF_INET = PF_INET;
pub const AF_APPLETALK = PF_APPLETALK;
pub const AF_INET6 = PF_INET6;
pub const AF_KEY = PF_KEY;
pub const AF_ROUTE = PF_ROUTE;
pub const AF_SNA = PF_SNA;
pub const AF_MPLS = PF_MPLS;
pub const AF_CAN = PF_CAN;
pub const AF_BLUETOOTH = PF_BLUETOOTH;
pub const AF_ISDN = PF_ISDN;
pub const AF_MAX = PF_MAX;
pub const DT_UNKNOWN = 0;
pub const DT_FIFO = 1;
pub const DT_CHR = 2;
pub const DT_DIR = 4;
pub const DT_BLK = 6;
pub const DT_REG = 8;
pub const DT_LNK = 10;
pub const DT_SOCK = 12;
pub const DT_WHT = 14;
/// add event to kq (implies enable)
pub const EV_ADD = 0x0001;
/// delete event from kq
pub const EV_DELETE = 0x0002;
/// enable event
pub const EV_ENABLE = 0x0004;
/// disable event (not reported)
pub const EV_DISABLE = 0x0008;
/// only report one occurrence
pub const EV_ONESHOT = 0x0010;
/// clear event state after reporting
pub const EV_CLEAR = 0x0020;
/// force immediate event output
/// ... with or without EV_ERROR
/// ... use KEVENT_FLAG_ERROR_EVENTS
/// on syscalls supporting flags
pub const EV_RECEIPT = 0x0040;
/// disable event after reporting
pub const EV_DISPATCH = 0x0080;
pub const EVFILT_READ = 0;
pub const EVFILT_WRITE = 1;
/// attached to aio requests
pub const EVFILT_AIO = 2;
/// attached to vnodes
pub const EVFILT_VNODE = 3;
/// attached to struct proc
pub const EVFILT_PROC = 4;
/// attached to struct proc
pub const EVFILT_SIGNAL = 5;
/// timers
pub const EVFILT_TIMER = 6;
/// Filesystem events
pub const EVFILT_FS = 7;
/// On input, NOTE_TRIGGER causes the event to be triggered for output.
pub const NOTE_TRIGGER = 0x08000000;
/// low water mark
pub const NOTE_LOWAT = 0x00000001;
/// vnode was removed
pub const NOTE_DELETE = 0x00000001;
/// data contents changed
pub const NOTE_WRITE = 0x00000002;
/// size increased
pub const NOTE_EXTEND = 0x00000004;
/// attributes changed
pub const NOTE_ATTRIB = 0x00000008;
/// link count changed
pub const NOTE_LINK = 0x00000010;
/// vnode was renamed
pub const NOTE_RENAME = 0x00000020;
/// vnode access was revoked
pub const NOTE_REVOKE = 0x00000040;
/// process exited
pub const NOTE_EXIT = 0x80000000;
/// process forked
pub const NOTE_FORK = 0x40000000;
/// process exec'd
pub const NOTE_EXEC = 0x20000000;
/// mask for signal & exit status
pub const NOTE_PDATAMASK = 0x000fffff;
pub const NOTE_PCTRLMASK = 0xf0000000;
pub const TIOCCBRK = 0x2000747a;
pub const TIOCCDTR = 0x20007478;
pub const TIOCCONS = 0x80047462;
pub const TIOCDCDTIMESTAMP = 0x40107458;
pub const TIOCDRAIN = 0x2000745e;
pub const TIOCEXCL = 0x2000740d;
pub const TIOCEXT = 0x80047460;
pub const TIOCFLAG_CDTRCTS = 0x10;
pub const TIOCFLAG_CLOCAL = 0x2;
pub const TIOCFLAG_CRTSCTS = 0x4;
pub const TIOCFLAG_MDMBUF = 0x8;
pub const TIOCFLAG_SOFTCAR = 0x1;
pub const TIOCFLUSH = 0x80047410;
pub const TIOCGETA = 0x402c7413;
pub const TIOCGETD = 0x4004741a;
pub const TIOCGFLAGS = 0x4004745d;
pub const TIOCGLINED = 0x40207442;
pub const TIOCGPGRP = 0x40047477;
pub const TIOCGQSIZE = 0x40047481;
pub const TIOCGRANTPT = 0x20007447;
pub const TIOCGSID = 0x40047463;
pub const TIOCGSIZE = 0x40087468;
pub const TIOCGWINSZ = 0x40087468;
pub const TIOCMBIC = 0x8004746b;
pub const TIOCMBIS = 0x8004746c;
pub const TIOCMGET = 0x4004746a;
pub const TIOCMSET = 0x8004746d;
pub const TIOCM_CAR = 0x40;
pub const TIOCM_CD = 0x40;
pub const TIOCM_CTS = 0x20;
pub const TIOCM_DSR = 0x100;
pub const TIOCM_DTR = 0x2;
pub const TIOCM_LE = 0x1;
pub const TIOCM_RI = 0x80;
pub const TIOCM_RNG = 0x80;
pub const TIOCM_RTS = 0x4;
pub const TIOCM_SR = 0x10;
pub const TIOCM_ST = 0x8;
pub const TIOCNOTTY = 0x20007471;
pub const TIOCNXCL = 0x2000740e;
pub const TIOCOUTQ = 0x40047473;
pub const TIOCPKT = 0x80047470;
pub const TIOCPKT_DATA = 0x0;
pub const TIOCPKT_DOSTOP = 0x20;
pub const TIOCPKT_FLUSHREAD = 0x1;
pub const TIOCPKT_FLUSHWRITE = 0x2;
pub const TIOCPKT_IOCTL = 0x40;
pub const TIOCPKT_NOSTOP = 0x10;
pub const TIOCPKT_START = 0x8;
pub const TIOCPKT_STOP = 0x4;
pub const TIOCPTMGET = 0x40287446;
pub const TIOCPTSNAME = 0x40287448;
pub const TIOCRCVFRAME = 0x80087445;
pub const TIOCREMOTE = 0x80047469;
pub const TIOCSBRK = 0x2000747b;
pub const TIOCSCTTY = 0x20007461;
pub const TIOCSDTR = 0x20007479;
pub const TIOCSETA = 0x802c7414;
pub const TIOCSETAF = 0x802c7416;
pub const TIOCSETAW = 0x802c7415;
pub const TIOCSETD = 0x8004741b;
pub const TIOCSFLAGS = 0x8004745c;
pub const TIOCSIG = 0x2000745f;
pub const TIOCSLINED = 0x80207443;
pub const TIOCSPGRP = 0x80047476;
pub const TIOCSQSIZE = 0x80047480;
pub const TIOCSSIZE = 0x80087467;
pub const TIOCSTART = 0x2000746e;
pub const TIOCSTAT = 0x80047465;
pub const TIOCSTI = 0x80017472;
pub const TIOCSTOP = 0x2000746f;
pub const TIOCSWINSZ = 0x80087467;
pub const TIOCUCNTL = 0x80047466;
pub const TIOCXMTFRAME = 0x80087444;
pub const sockaddr = c.sockaddr;
pub const sockaddr_in = c.sockaddr_in;
pub const sockaddr_in6 = c.sockaddr_in6;
fn unsigned(s: i32) u32 {
return @bitCast(u32, s);
}
fn signed(s: u32) i32 {
return @bitCast(i32, s);
}
pub fn WEXITSTATUS(s: i32) i32 {
return signed((unsigned(s) >> 8) & 0xff);
}
pub fn WTERMSIG(s: i32) i32 {
return signed(unsigned(s) & 0x7f);
}
pub fn WSTOPSIG(s: i32) i32 {
return WEXITSTATUS(s);
}
pub fn WIFEXITED(s: i32) bool {
return WTERMSIG(s) == 0;
}
pub fn WIFCONTINUED(s: i32) bool {
return ((s & 0x7f) == 0xffff);
}
pub fn WIFSTOPPED(s: i32) bool {
return ((s & 0x7f != 0x7f) and !WIFCONTINUED(s));
}
pub fn WIFSIGNALED(s: i32) bool {
return !WIFSTOPPED(s) and !WIFCONTINUED(s) and !WIFEXITED(s);
}
pub const winsize = extern struct {
ws_row: u16,
ws_col: u16,
ws_xpixel: u16,
ws_ypixel: u16,
};
/// Get the errno from a syscall return value, or 0 for no error.
pub fn getErrno(r: usize) usize {
const signed_r = @bitCast(isize, r);
return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
}
pub fn dup2(old: i32, new: i32) usize {
return errnoWrap(c.dup2(old, new));
}
pub fn chdir(path: [*]const u8) usize {
return errnoWrap(c.chdir(path));
}
pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize {
return errnoWrap(c.execve(path, argv, envp));
}
pub fn fork() usize {
return errnoWrap(c.fork());
}
pub fn access(path: [*]const u8, mode: u32) usize {
return errnoWrap(c.access(path, mode));
}
pub fn getcwd(buf: [*]u8, size: usize) usize {
return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
}
pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize {
return errnoWrap(@bitCast(isize, c.getdents(fd, drip, count)));
}
pub fn getdirentries(fd: i32, buf_ptr: [*]u8, buf_len: usize, basep: *i64) usize {
return errnoWrap(@bitCast(isize, c.getdirentries(fd, buf_ptr, buf_len, basep)));
}
pub fn realpath(noalias filename: [*]const u8, noalias resolved_name: [*]u8) usize {
return if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
}
pub fn isatty(fd: i32) bool {
return c.isatty(fd) != 0;
}
pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
return errnoWrap(c.readlink(path, buf_ptr, buf_len));
}
pub fn mkdir(path: [*]const u8, mode: u32) usize {
return errnoWrap(c.mkdir(path, mode));
}
pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
const ptr_result = c.mmap(
@ptrCast(?*c_void, address),
length,
@bitCast(c_int, @intCast(c_uint, prot)),
@bitCast(c_int, c_uint(flags)),
fd,
offset,
);
const isize_result = @bitCast(isize, @ptrToInt(ptr_result));
return errnoWrap(isize_result);
}
pub fn munmap(address: usize, length: usize) usize {
return errnoWrap(c.munmap(@intToPtr(*c_void, address), length));
}
pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize {
return errnoWrap(c.read(fd, @ptrCast(*c_void, buf), nbyte));
}
pub fn rmdir(path: [*]const u8) usize {
return errnoWrap(c.rmdir(path));
}
pub fn symlink(existing: [*]const u8, new: [*]const u8) usize {
return errnoWrap(c.symlink(existing, new));
}
pub fn pread(fd: i32, buf: [*]u8, nbyte: usize, offset: u64) usize {
return errnoWrap(c.pread(fd, @ptrCast(*c_void, buf), nbyte, offset));
}
pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: usize) usize {
return errnoWrap(c.preadv(fd, @ptrCast(*const c_void, iov), @intCast(c_int, count), offset));
}
pub fn pipe(fd: *[2]i32) usize {
return pipe2(fd, 0);
}
pub fn pipe2(fd: *[2]i32, flags: u32) usize {
comptime assert(i32.bit_count == c_int.bit_count);
return errnoWrap(c.pipe2(@ptrCast(*[2]c_int, fd), flags));
}
pub fn write(fd: i32, buf: [*]const u8, nbyte: usize) usize {
return errnoWrap(c.write(fd, @ptrCast(*const c_void, buf), nbyte));
}
pub fn pwrite(fd: i32, buf: [*]const u8, nbyte: usize, offset: u64) usize {
return errnoWrap(c.pwrite(fd, @ptrCast(*const c_void, buf), nbyte, offset));
}
pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: usize) usize {
return errnoWrap(c.pwritev(fd, @ptrCast(*const c_void, iov), @intCast(c_int, count), offset));
}
pub fn rename(old: [*]const u8, new: [*]const u8) usize {
return errnoWrap(c.rename(old, new));
}
pub fn open(path: [*]const u8, flags: u32, mode: usize) usize {
return errnoWrap(c.open(path, @bitCast(c_int, flags), mode));
}
pub fn create(path: [*]const u8, perm: usize) usize {
return arch.syscall2(SYS_creat, @ptrToInt(path), perm);
}
pub fn openat(dirfd: i32, path: [*]const u8, flags: usize, mode: usize) usize {
return errnoWrap(c.openat(@bitCast(usize, isize(dirfd)), @ptrToInt(path), flags, mode));
}
pub fn close(fd: i32) usize {
return errnoWrap(c.close(fd));
}
pub fn lseek(fd: i32, offset: isize, whence: c_int) usize {
return errnoWrap(c.lseek(fd, offset, whence));
}
pub fn exit(code: i32) noreturn {
c.exit(code);
}
pub fn kill(pid: i32, sig: i32) usize {
return errnoWrap(c.kill(pid, sig));
}
pub fn unlink(path: [*]const u8) usize {
return errnoWrap(c.unlink(path));
}
pub fn waitpid(pid: i32, status: *i32, options: u32) usize {
comptime assert(i32.bit_count == c_int.bit_count);
return errnoWrap(c.waitpid(pid, @ptrCast(*c_int, status), @bitCast(c_int, options)));
}
pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize {
return errnoWrap(c.nanosleep(req, rem));
}
pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {
return errnoWrap(c.clock_gettime(clk_id, tp));
}
pub fn clock_getres(clk_id: i32, tp: *timespec) usize {
return errnoWrap(c.clock_getres(clk_id, tp));
}
pub fn setuid(uid: u32) usize {
return errnoWrap(c.setuid(uid));
}
pub fn setgid(gid: u32) usize {
return errnoWrap(c.setgid(gid));
}
pub fn setreuid(ruid: u32, euid: u32) usize {
return errnoWrap(c.setreuid(ruid, euid));
}
pub fn setregid(rgid: u32, egid: u32) usize {
return errnoWrap(c.setregid(rgid, egid));
}
const NSIG = 32;
pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize));
pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
pub const Sigaction = extern struct {
/// signal handler
__sigaction_u: extern union {
__sa_handler: extern fn (i32) void,
__sa_sigaction: extern fn (i32, *__siginfo, usize) void,
},
/// see signal options
sa_flags: u32,
/// signal mask to apply
sa_mask: sigset_t,
};
pub const _SIG_WORDS = 4;
pub const _SIG_MAXSIG = 128;
pub inline fn _SIG_IDX(sig: usize) usize {
return sig - 1;
}
pub inline fn _SIG_WORD(sig: usize) usize {
return_SIG_IDX(sig) >> 5;
}
pub inline fn _SIG_BIT(sig: usize) usize {
return 1 << (_SIG_IDX(sig) & 31);
}
pub inline fn _SIG_VALID(sig: usize) usize {
return sig <= _SIG_MAXSIG and sig > 0;
}
pub const sigset_t = extern struct {
__bits: [_SIG_WORDS]u32,
};
pub fn raise(sig: i32) usize {
return errnoWrap(c.raise(sig));
}
pub const Stat = c.Stat;
pub const dirent = c.dirent;
pub const timespec = c.timespec;
pub fn fstat(fd: i32, buf: *c.Stat) usize {
return errnoWrap(c.fstat(fd, buf));
}
pub const iovec = extern struct {
iov_base: [*]u8,
iov_len: usize,
};
pub const iovec_const = extern struct {
iov_base: [*]const u8,
iov_len: usize,
};
// TODO avoid libc dependency
pub fn kqueue() usize {
return errnoWrap(c.kqueue());
}
// TODO avoid libc dependency
pub fn kevent(kq: i32, changelist: []const Kevent, eventlist: []Kevent, timeout: ?*const timespec) usize {
return errnoWrap(c.kevent(
kq,
changelist.ptr,
@intCast(c_int, changelist.len),
eventlist.ptr,
@intCast(c_int, eventlist.len),
timeout,
));
}
// TODO avoid libc dependency
pub fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
return errnoWrap(c.sysctl(name, namelen, oldp, oldlenp, newp, newlen));
}
// TODO avoid libc dependency
pub fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
return errnoWrap(c.sysctlbyname(name, oldp, oldlenp, newp, newlen));
}
// TODO avoid libc dependency
pub fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) usize {
return errnoWrap(c.sysctlnametomib(name, wibp, sizep));
}
// TODO avoid libc dependency
/// Takes the return value from a syscall and formats it back in the way
/// that the kernel represents it to libc. Errno was a mistake, let's make
/// it go away forever.
fn errnoWrap(value: isize) usize {
return @bitCast(usize, if (value == -1) -isize(c._errno().*) else value);
}

View File

@ -1226,7 +1226,7 @@ pub fn realC(out_buffer: *[os.MAX_PATH_BYTES]u8, pathname: [*]const u8) RealErro
const pathname_w = try windows_util.cStrToPrefixedFileW(pathname); const pathname_w = try windows_util.cStrToPrefixedFileW(pathname);
return realW(out_buffer, pathname_w); return realW(out_buffer, pathname_w);
}, },
Os.freebsd, Os.macosx, Os.ios => { Os.freebsd, Os.netbsd, Os.macosx, Os.ios => {
// TODO instead of calling the libc function here, port the implementation to Zig // TODO instead of calling the libc function here, port the implementation to Zig
const err = posix.getErrno(posix.realpath(pathname, out_buffer)); const err = posix.getErrno(posix.realpath(pathname, out_buffer));
switch (err) { switch (err) {
@ -1267,7 +1267,7 @@ pub fn real(out_buffer: *[os.MAX_PATH_BYTES]u8, pathname: []const u8) RealError!
const pathname_w = try windows_util.sliceToPrefixedFileW(pathname); const pathname_w = try windows_util.sliceToPrefixedFileW(pathname);
return realW(out_buffer, &pathname_w); return realW(out_buffer, &pathname_w);
}, },
Os.macosx, Os.ios, Os.linux, Os.freebsd => { Os.macosx, Os.ios, Os.linux, Os.freebsd, Os.netbsd => {
const pathname_c = try os.toPosixPath(pathname); const pathname_c = try os.toPosixPath(pathname);
return realC(out_buffer, &pathname_c); return realC(out_buffer, &pathname_c);
}, },

View File

@ -14,7 +14,7 @@ pub const epoch = @import("epoch.zig");
/// Sleep for the specified duration /// Sleep for the specified duration
pub fn sleep(nanoseconds: u64) void { pub fn sleep(nanoseconds: u64) void {
switch (builtin.os) { switch (builtin.os) {
Os.linux, Os.macosx, Os.ios, Os.freebsd => { Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
const s = nanoseconds / ns_per_s; const s = nanoseconds / ns_per_s;
const ns = nanoseconds % ns_per_s; const ns = nanoseconds % ns_per_s;
posixSleep(@intCast(u63, s), @intCast(u63, ns)); posixSleep(@intCast(u63, s), @intCast(u63, ns));
@ -62,7 +62,7 @@ pub fn timestamp() u64 {
/// Get the posix timestamp, UTC, in milliseconds /// Get the posix timestamp, UTC, in milliseconds
pub const milliTimestamp = switch (builtin.os) { pub const milliTimestamp = switch (builtin.os) {
Os.windows => milliTimestampWindows, Os.windows => milliTimestampWindows,
Os.linux, Os.freebsd => milliTimestampPosix, Os.linux, Os.freebsd, Os.netbsd => milliTimestampPosix,
Os.macosx, Os.ios => milliTimestampDarwin, Os.macosx, Os.ios => milliTimestampDarwin,
else => @compileError("Unsupported OS"), else => @compileError("Unsupported OS"),
}; };
@ -178,7 +178,7 @@ pub const Timer = struct {
debug.assert(err != windows.FALSE); debug.assert(err != windows.FALSE);
self.start_time = @intCast(u64, start_time); self.start_time = @intCast(u64, start_time);
}, },
Os.linux, Os.freebsd => { Os.linux, Os.freebsd, Os.netbsd => {
//On Linux, seccomp can do arbitrary things to our ability to call //On Linux, seccomp can do arbitrary things to our ability to call
// syscalls, including return any errno value it wants and // syscalls, including return any errno value it wants and
// inconsistently throwing errors. Since we can't account for // inconsistently throwing errors. Since we can't account for
@ -214,7 +214,7 @@ pub const Timer = struct {
var clock = clockNative() - self.start_time; var clock = clockNative() - self.start_time;
return switch (builtin.os) { return switch (builtin.os) {
Os.windows => @divFloor(clock * ns_per_s, self.frequency), Os.windows => @divFloor(clock * ns_per_s, self.frequency),
Os.linux, Os.freebsd => clock, Os.linux, Os.freebsd, Os.netbsd => clock,
Os.macosx, Os.ios => @divFloor(clock * self.frequency.numer, self.frequency.denom), Os.macosx, Os.ios => @divFloor(clock * self.frequency.numer, self.frequency.denom),
else => @compileError("Unsupported OS"), else => @compileError("Unsupported OS"),
}; };
@ -235,7 +235,7 @@ pub const Timer = struct {
const clockNative = switch (builtin.os) { const clockNative = switch (builtin.os) {
Os.windows => clockWindows, Os.windows => clockWindows,
Os.linux, Os.freebsd => clockLinux, Os.linux, Os.freebsd, Os.netbsd => clockLinux,
Os.macosx, Os.ios => clockDarwin, Os.macosx, Os.ios => clockDarwin,
else => @compileError("Unsupported OS"), else => @compileError("Unsupported OS"),
}; };

331
std/priority_queue.zig Normal file
View File

@ -0,0 +1,331 @@
const std = @import("index.zig");
const Allocator = std.mem.Allocator;
const debug = std.debug;
const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual;
pub fn PriorityQueue(comptime T: type) type {
return struct {
const Self = @This();
items: []T,
len: usize,
allocator: *Allocator,
compareFn: fn (a: T, b: T) bool,
pub fn init(allocator: *Allocator, compareFn: fn (a: T, b: T) bool) Self {
return Self{
.items = []T{},
.len = 0,
.allocator = allocator,
.compareFn = compareFn,
};
}
pub fn deinit(self: Self) void {
self.allocator.free(self.items);
}
pub fn add(self: *Self, elem: T) !void {
try ensureCapacity(self, self.len + 1);
self.items[self.len] = elem;
var child_index = self.len;
while (child_index > 0) {
var parent_index = ((child_index - 1) >> 1);
const child = self.items[child_index];
const parent = self.items[parent_index];
if (!self.compareFn(child, parent)) break;
self.items[parent_index] = child;
self.items[child_index] = parent;
child_index = parent_index;
}
self.len += 1;
}
pub fn peek(self: *Self) ?T {
return if (self.len > 0) self.items[0] else null;
}
pub fn removeOrNull(self: *Self) ?T {
return if (self.len > 0) self.remove() else null;
}
pub fn remove(self: *Self) T {
const first = self.items[0];
const last = self.items[self.len - 1];
self.items[0] = last;
self.len -= 1;
siftDown(self);
return first;
}
pub fn count(self: Self) usize {
return self.len;
}
pub fn capacity(self: Self) usize {
return self.items.len;
}
fn siftDown(self: *Self) void {
var index: usize = 0;
const half = self.len >> 1;
while (true) {
var left_index = (index << 1) + 1;
var right_index = left_index + 1;
var left = if (left_index < self.len) self.items[left_index] else null;
var right = if (right_index < self.len) self.items[right_index] else null;
var smallest_index = index;
var smallest = self.items[index];
if (left) |e| {
if (self.compareFn(e, smallest)) {
smallest_index = left_index;
smallest = e;
}
}
if (right) |e| {
if (self.compareFn(e, smallest)) {
smallest_index = right_index;
smallest = e;
}
}
if (smallest_index == index) return;
self.items[smallest_index] = self.items[index];
self.items[index] = smallest;
index = smallest_index;
if (index >= half) return;
}
}
pub fn ensureCapacity(self: *Self, new_capacity: usize) !void {
var better_capacity = self.capacity();
if (better_capacity >= new_capacity) return;
while (true) {
better_capacity += better_capacity / 2 + 8;
if (better_capacity >= new_capacity) break;
}
self.items = try self.allocator.realloc(T, self.items, better_capacity);
}
pub fn resize(self: *Self, new_len: usize) !void {
try self.ensureCapacity(new_len);
self.len = new_len;
}
pub fn shrink(self: *Self, new_len: usize) void {
assert(new_len <= self.len);
self.len = new_len;
}
const Iterator = struct {
queue: *PriorityQueue(T),
count: usize,
fn next(it: *Iterator) ?T {
if (it.count > it.queue.len - 1) return null;
const out = it.count;
it.count += 1;
return it.queue.items[out];
}
fn reset(it: *Iterator) void {
it.count = 0;
}
};
pub fn iterator(self: *Self) Iterator {
return Iterator{
.queue = self,
.count = 0,
};
}
fn dump(self: *Self) void {
warn("{{ ");
warn("items: ");
for (self.items) |e, i| {
if (i >= self.len) break;
warn("{}, ", e);
}
warn("array: ");
for (self.items) |e, i| {
warn("{}, ", e);
}
warn("len: {} ", self.len);
warn("capacity: {}", self.capacity());
warn(" }}\n");
}
};
}
fn lessThan(a: u32, b: u32) bool {
return a < b;
}
fn greaterThan(a: u32, b: u32) bool {
return a > b;
}
const PQ = PriorityQueue(u32);
test "std.PriorityQueue: add and remove min heap" {
var queue = PQ.init(debug.global_allocator, lessThan);
defer queue.deinit();
try queue.add(54);
try queue.add(12);
try queue.add(7);
try queue.add(23);
try queue.add(25);
try queue.add(13);
expectEqual(u32(7), queue.remove());
expectEqual(u32(12), queue.remove());
expectEqual(u32(13), queue.remove());
expectEqual(u32(23), queue.remove());
expectEqual(u32(25), queue.remove());
expectEqual(u32(54), queue.remove());
}
test "std.PriorityQueue: add and remove same min heap" {
var queue = PQ.init(debug.global_allocator, lessThan);
defer queue.deinit();
try queue.add(1);
try queue.add(1);
try queue.add(2);
try queue.add(2);
try queue.add(1);
try queue.add(1);
expectEqual(u32(1), queue.remove());
expectEqual(u32(1), queue.remove());
expectEqual(u32(1), queue.remove());
expectEqual(u32(1), queue.remove());
expectEqual(u32(2), queue.remove());
expectEqual(u32(2), queue.remove());
}
test "std.PriorityQueue: removeOrNull on empty" {
var queue = PQ.init(debug.global_allocator, lessThan);
defer queue.deinit();
expect(queue.removeOrNull() == null);
}
test "std.PriorityQueue: edge case 3 elements" {
var queue = PQ.init(debug.global_allocator, lessThan);
defer queue.deinit();
try queue.add(9);
try queue.add(3);
try queue.add(2);
expectEqual(u32(2), queue.remove());
expectEqual(u32(3), queue.remove());
expectEqual(u32(9), queue.remove());
}
test "std.PriorityQueue: peek" {
var queue = PQ.init(debug.global_allocator, lessThan);
defer queue.deinit();
expect(queue.peek() == null);
try queue.add(9);
try queue.add(3);
try queue.add(2);
expectEqual(u32(2), queue.peek().?);
expectEqual(u32(2), queue.peek().?);
}
test "std.PriorityQueue: sift up with odd indices" {
var queue = PQ.init(debug.global_allocator, lessThan);
defer queue.deinit();
const items = []u32{ 15, 7, 21, 14, 13, 22, 12, 6, 7, 25, 5, 24, 11, 16, 15, 24, 2, 1 };
for (items) |e| {
try queue.add(e);
}
expectEqual(u32(1), queue.remove());
expectEqual(u32(2), queue.remove());
expectEqual(u32(5), queue.remove());
expectEqual(u32(6), queue.remove());
expectEqual(u32(7), queue.remove());
expectEqual(u32(7), queue.remove());
expectEqual(u32(11), queue.remove());
expectEqual(u32(12), queue.remove());
expectEqual(u32(13), queue.remove());
expectEqual(u32(14), queue.remove());
expectEqual(u32(15), queue.remove());
expectEqual(u32(15), queue.remove());
expectEqual(u32(16), queue.remove());
expectEqual(u32(21), queue.remove());
expectEqual(u32(22), queue.remove());
expectEqual(u32(24), queue.remove());
expectEqual(u32(24), queue.remove());
expectEqual(u32(25), queue.remove());
}
test "std.PriorityQueue: add and remove max heap" {
var queue = PQ.init(debug.global_allocator, greaterThan);
defer queue.deinit();
try queue.add(54);
try queue.add(12);
try queue.add(7);
try queue.add(23);
try queue.add(25);
try queue.add(13);
expectEqual(u32(54), queue.remove());
expectEqual(u32(25), queue.remove());
expectEqual(u32(23), queue.remove());
expectEqual(u32(13), queue.remove());
expectEqual(u32(12), queue.remove());
expectEqual(u32(7), queue.remove());
}
test "std.PriorityQueue: add and remove same max heap" {
var queue = PQ.init(debug.global_allocator, greaterThan);
defer queue.deinit();
try queue.add(1);
try queue.add(1);
try queue.add(2);
try queue.add(2);
try queue.add(1);
try queue.add(1);
expectEqual(u32(2), queue.remove());
expectEqual(u32(2), queue.remove());
expectEqual(u32(1), queue.remove());
expectEqual(u32(1), queue.remove());
expectEqual(u32(1), queue.remove());
expectEqual(u32(1), queue.remove());
}
test "std.PriorityQueue: iterator" {
var queue = PQ.init(debug.global_allocator, lessThan);
var map = std.AutoHashMap(u32, void).init(debug.global_allocator);
defer {
queue.deinit();
map.deinit();
}
const items = []u32{ 54, 12, 7, 23, 25, 13 };
for (items) |e| {
_ = try queue.add(e);
_ = try map.put(e, {});
}
var it = queue.iterator();
while (it.next()) |e| {
_ = map.remove(e);
}
expectEqual(usize(0), map.count());
}

View File

@ -31,7 +31,7 @@ nakedcc fn _start() noreturn {
: [argc] "=r" (-> [*]usize) : [argc] "=r" (-> [*]usize)
); );
}, },
builtin.Arch.aarch64v8 => { builtin.Arch.aarch64, builtin.Arch.aarch64_be => {
argc_ptr = asm ("mov %[argc], sp" argc_ptr = asm ("mov %[argc], sp"
: [argc] "=r" (-> [*]usize) : [argc] "=r" (-> [*]usize)
); );
@ -123,7 +123,7 @@ inline fn callMain() u8 {
std.debug.warn("error: {}\n", @errorName(err)); std.debug.warn("error: {}\n", @errorName(err));
if (builtin.os != builtin.Os.zen) { if (builtin.os != builtin.Os.zen) {
if (@errorReturnTrace()) |trace| { if (@errorReturnTrace()) |trace| {
std.debug.dumpStackTrace(trace); std.debug.dumpStackTrace(trace.*);
} }
} }
return 1; return 1;
@ -142,7 +142,10 @@ fn linuxInitializeThreadLocalStorage(at_phdr: usize, at_phnum: usize, at_phent:
var phdr_addr = at_phdr; var phdr_addr = at_phdr;
var n = at_phnum; var n = at_phnum;
var base: usize = 0; var base: usize = 0;
while (n != 0) : ({n -= 1; phdr_addr += at_phent;}) { while (n != 0) : ({
n -= 1;
phdr_addr += at_phent;
}) {
const phdr = @intToPtr(*std.elf.Phdr, phdr_addr); const phdr = @intToPtr(*std.elf.Phdr, phdr_addr);
// TODO look for PT_DYNAMIC when we have https://github.com/ziglang/zig/issues/1917 // TODO look for PT_DYNAMIC when we have https://github.com/ziglang/zig/issues/1917
switch (phdr.p_type) { switch (phdr.p_type) {

View File

@ -0,0 +1,191 @@
// Ported from:
//
// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/lib/builtins/fp_add_impl.inc
const std = @import("std");
const builtin = @import("builtin");
const compiler_rt = @import("index.zig");
pub extern fn __addtf3(a: f128, b: f128) f128 {
return addXf3(f128, a, b);
}
pub extern fn __subtf3(a: f128, b: f128) f128 {
const neg_b = @bitCast(f128, @bitCast(u128, b) ^ (u128(1) << 127));
return addXf3(f128, a, neg_b);
}
inline fn normalize(comptime T: type, significand: *@IntType(false, T.bit_count)) i32 {
const Z = @IntType(false, T.bit_count);
const significandBits = std.math.floatMantissaBits(T);
const implicitBit = Z(1) << significandBits;
const shift = @clz(significand.*) - @clz(implicitBit);
significand.* <<= @intCast(u7, shift);
return 1 - shift;
}
inline fn addXf3(comptime T: type, a: T, b: T) T {
const Z = @IntType(false, T.bit_count);
const typeWidth = T.bit_count;
const significandBits = std.math.floatMantissaBits(T);
const exponentBits = std.math.floatExponentBits(T);
const signBit = (Z(1) << (significandBits + exponentBits));
const maxExponent = ((1 << exponentBits) - 1);
const exponentBias = (maxExponent >> 1);
const implicitBit = (Z(1) << significandBits);
const quietBit = implicitBit >> 1;
const significandMask = implicitBit - 1;
const absMask = signBit - 1;
const exponentMask = absMask ^ significandMask;
const qnanRep = exponentMask | quietBit;
var aRep = @bitCast(Z, a);
var bRep = @bitCast(Z, b);
const aAbs = aRep & absMask;
const bAbs = bRep & absMask;
const negative = (aRep & signBit) != 0;
const exponent = @intCast(i32, aAbs >> significandBits) - exponentBias;
const significand = (aAbs & significandMask) | implicitBit;
const infRep = @bitCast(Z, std.math.inf(T));
// Detect if a or b is zero, infinity, or NaN.
if (aAbs - Z(1) >= infRep - Z(1) or
bAbs - Z(1) >= infRep - Z(1))
{
// NaN + anything = qNaN
if (aAbs > infRep) return @bitCast(T, @bitCast(Z, a) | quietBit);
// anything + NaN = qNaN
if (bAbs > infRep) return @bitCast(T, @bitCast(Z, b) | quietBit);
if (aAbs == infRep) {
// +/-infinity + -/+infinity = qNaN
if ((@bitCast(Z, a) ^ @bitCast(Z, b)) == signBit) {
return @bitCast(T, qnanRep);
}
// +/-infinity + anything remaining = +/- infinity
else {
return a;
}
}
// anything remaining + +/-infinity = +/-infinity
if (bAbs == infRep) return b;
// zero + anything = anything
if (aAbs == 0) {
// but we need to get the sign right for zero + zero
if (bAbs == 0) {
return @bitCast(T, @bitCast(Z, a) & @bitCast(Z, b));
} else {
return b;
}
}
// anything + zero = anything
if (bAbs == 0) return a;
}
// Swap a and b if necessary so that a has the larger absolute value.
if (bAbs > aAbs) {
const temp = aRep;
aRep = bRep;
bRep = temp;
}
// Extract the exponent and significand from the (possibly swapped) a and b.
var aExponent = @intCast(i32, (aRep >> significandBits) & maxExponent);
var bExponent = @intCast(i32, (bRep >> significandBits) & maxExponent);
var aSignificand = aRep & significandMask;
var bSignificand = bRep & significandMask;
// Normalize any denormals, and adjust the exponent accordingly.
if (aExponent == 0) aExponent = normalize(T, &aSignificand);
if (bExponent == 0) bExponent = normalize(T, &bSignificand);
// The sign of the result is the sign of the larger operand, a. If they
// have opposite signs, we are performing a subtraction; otherwise addition.
const resultSign = aRep & signBit;
const subtraction = (aRep ^ bRep) & signBit != 0;
// Shift the significands to give us round, guard and sticky, and or in the
// implicit significand bit. (If we fell through from the denormal path it
// was already set by normalize( ), but setting it twice won't hurt
// anything.)
aSignificand = (aSignificand | implicitBit) << 3;
bSignificand = (bSignificand | implicitBit) << 3;
// Shift the significand of b by the difference in exponents, with a sticky
// bottom bit to get rounding correct.
const @"align" = @intCast(Z, aExponent - bExponent);
if (@"align" != 0) {
if (@"align" < typeWidth) {
const sticky = if (bSignificand << @intCast(u7, typeWidth - @"align") != 0) Z(1) else 0;
bSignificand = (bSignificand >> @truncate(u7, @"align")) | sticky;
} else {
bSignificand = 1; // sticky; b is known to be non-zero.
}
}
if (subtraction) {
aSignificand -= bSignificand;
// If a == -b, return +zero.
if (aSignificand == 0) return @bitCast(T, Z(0));
// If partial cancellation occured, we need to left-shift the result
// and adjust the exponent:
if (aSignificand < implicitBit << 3) {
const shift = @intCast(i32, @clz(aSignificand)) - @intCast(i32, @clz(implicitBit << 3));
aSignificand <<= @intCast(u7, shift);
aExponent -= shift;
}
} else { // addition
aSignificand += bSignificand;
// If the addition carried up, we need to right-shift the result and
// adjust the exponent:
if (aSignificand & (implicitBit << 4) != 0) {
const sticky = aSignificand & 1;
aSignificand = aSignificand >> 1 | sticky;
aExponent += 1;
}
}
// If we have overflowed the type, return +/- infinity:
if (aExponent >= maxExponent) return @bitCast(T, infRep | resultSign);
if (aExponent <= 0) {
// Result is denormal before rounding; the exponent is zero and we
// need to shift the significand.
const shift = @intCast(Z, 1 - aExponent);
const sticky = if (aSignificand << @intCast(u7, typeWidth - shift) != 0) Z(1) else 0;
aSignificand = aSignificand >> @intCast(u7, shift | sticky);
aExponent = 0;
}
// Low three bits are round, guard, and sticky.
const roundGuardSticky = aSignificand & 0x7;
// Shift the significand into place, and mask off the implicit bit.
var result = (aSignificand >> 3) & significandMask;
// Insert the exponent and sign.
result |= @intCast(Z, aExponent) << significandBits;
result |= resultSign;
// Final rounding. The result may overflow to infinity, but that is the
// correct result in that case.
if (roundGuardSticky > 0x4) result += 1;
if (roundGuardSticky == 0x4) result += result & 1;
return @bitCast(T, result);
}
test "import addXf3" {
_ = @import("addXf3_test.zig");
}

View File

@ -0,0 +1,85 @@
// Ported from:
//
// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/test/builtins/Unit/addtf3_test.c
// https://github.com/llvm/llvm-project/blob/02d85149a05cb1f6dc49f0ba7a2ceca53718ae17/compiler-rt/test/builtins/Unit/subtf3_test.c
const qnan128 = @bitCast(f128, u128(0x7fff800000000000) << 64);
const inf128 = @bitCast(f128, u128(0x7fff000000000000) << 64);
const __addtf3 = @import("addXf3.zig").__addtf3;
fn test__addtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) void {
const x = __addtf3(a, b);
const rep = @bitCast(u128, x);
const hi = @intCast(u64, rep >> 64);
const lo = @truncate(u64, rep);
if (hi == expected_hi and lo == expected_lo) {
return;
}
// test other possible NaN representation (signal NaN)
else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) {
if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and
((hi & 0xffffffffffff) > 0 or lo > 0))
{
return;
}
}
@panic("__addtf3 test failure");
}
test "addtf3" {
test__addtf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0);
// NaN + any = NaN
test__addtf3(@bitCast(f128, (u128(0x7fff000000000000) << 64) | u128(0x800030000000)), 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0);
// inf + inf = inf
test__addtf3(inf128, inf128, 0x7fff000000000000, 0x0);
// inf + any = inf
test__addtf3(inf128, 0x1.2335653452436234723489432abcdefp+5, 0x7fff000000000000, 0x0);
// any + any
test__addtf3(0x1.23456734245345543849abcdefp+5, 0x1.edcba52449872455634654321fp-1, 0x40042afc95c8b579, 0x61e58dd6c51eb77c);
}
const __subtf3 = @import("addXf3.zig").__subtf3;
fn test__subtf3(a: f128, b: f128, expected_hi: u64, expected_lo: u64) void {
const x = __subtf3(a, b);
const rep = @bitCast(u128, x);
const hi = @intCast(u64, rep >> 64);
const lo = @truncate(u64, rep);
if (hi == expected_hi and lo == expected_lo) {
return;
}
// test other possible NaN representation (signal NaN)
else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) {
if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and
((hi & 0xffffffffffff) > 0 or lo > 0))
{
return;
}
}
@panic("__subtf3 test failure");
}
test "subtf3" {
// qNaN - any = qNaN
test__subtf3(qnan128, 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0);
// NaN + any = NaN
test__subtf3(@bitCast(f128, (u128(0x7fff000000000000) << 64) | u128(0x800030000000)), 0x1.23456789abcdefp+5, 0x7fff800000000000, 0x0);
// inf - any = inf
test__subtf3(inf128, 0x1.23456789abcdefp+5, 0x7fff000000000000, 0x0);
// any + any
test__subtf3(0x1.234567829a3bcdef5678ade36734p+5, 0x1.ee9d7c52354a6936ab8d7654321fp-1, 0x40041b8af1915166, 0xa44a7bca780a166c);
}

View File

@ -21,6 +21,9 @@ comptime {
@export("__unordtf2", @import("comparetf2.zig").__unordtf2, linkage); @export("__unordtf2", @import("comparetf2.zig").__unordtf2, linkage);
@export("__addtf3", @import("addXf3.zig").__addtf3, linkage);
@export("__subtf3", @import("addXf3.zig").__subtf3, linkage);
@export("__floattitf", @import("floattitf.zig").__floattitf, linkage); @export("__floattitf", @import("floattitf.zig").__floattitf, linkage);
@export("__floattidf", @import("floattidf.zig").__floattidf, linkage); @export("__floattidf", @import("floattidf.zig").__floattidf, linkage);
@export("__floattisf", @import("floattisf.zig").__floattisf, linkage); @export("__floattisf", @import("floattisf.zig").__floattisf, linkage);
@ -37,6 +40,7 @@ comptime {
@export("__extendhfsf2", @import("extendXfYf2.zig").__extendhfsf2, linkage); @export("__extendhfsf2", @import("extendXfYf2.zig").__extendhfsf2, linkage);
@export("__truncsfhf2", @import("truncXfYf2.zig").__truncsfhf2, linkage); @export("__truncsfhf2", @import("truncXfYf2.zig").__truncsfhf2, linkage);
@export("__truncdfhf2", @import("truncXfYf2.zig").__truncdfhf2, linkage);
@export("__trunctfdf2", @import("truncXfYf2.zig").__trunctfdf2, linkage); @export("__trunctfdf2", @import("truncXfYf2.zig").__trunctfdf2, linkage);
@export("__trunctfsf2", @import("truncXfYf2.zig").__trunctfsf2, linkage); @export("__trunctfsf2", @import("truncXfYf2.zig").__trunctfsf2, linkage);
@ -180,60 +184,10 @@ const is_arm_64 = switch (builtin.arch) {
}; };
const is_arm_arch = switch (builtin.arch) { const is_arm_arch = switch (builtin.arch) {
builtin.Arch.armv8_3a, builtin.Arch.arm,
builtin.Arch.armv8_2a, builtin.Arch.armeb,
builtin.Arch.armv8_1a, builtin.Arch.aarch64,
builtin.Arch.armv8, builtin.Arch.aarch64_be,
builtin.Arch.armv8r,
builtin.Arch.armv8m_baseline,
builtin.Arch.armv8m_mainline,
builtin.Arch.armv7,
builtin.Arch.armv7em,
builtin.Arch.armv7m,
builtin.Arch.armv7s,
builtin.Arch.armv7k,
builtin.Arch.armv7ve,
builtin.Arch.armv6,
builtin.Arch.armv6m,
builtin.Arch.armv6k,
builtin.Arch.armv6t2,
builtin.Arch.armv5,
builtin.Arch.armv5te,
builtin.Arch.armv4t,
builtin.Arch.armebv8_3a,
builtin.Arch.armebv8_2a,
builtin.Arch.armebv8_1a,
builtin.Arch.armebv8,
builtin.Arch.armebv8r,
builtin.Arch.armebv8m_baseline,
builtin.Arch.armebv8m_mainline,
builtin.Arch.armebv7,
builtin.Arch.armebv7em,
builtin.Arch.armebv7m,
builtin.Arch.armebv7s,
builtin.Arch.armebv7k,
builtin.Arch.armebv7ve,
builtin.Arch.armebv6,
builtin.Arch.armebv6m,
builtin.Arch.armebv6k,
builtin.Arch.armebv6t2,
builtin.Arch.armebv5,
builtin.Arch.armebv5te,
builtin.Arch.armebv4t,
builtin.Arch.aarch64v8_3a,
builtin.Arch.aarch64v8_2a,
builtin.Arch.aarch64v8_1a,
builtin.Arch.aarch64v8,
builtin.Arch.aarch64v8r,
builtin.Arch.aarch64v8m_baseline,
builtin.Arch.aarch64v8m_mainline,
builtin.Arch.aarch64_bev8_3a,
builtin.Arch.aarch64_bev8_2a,
builtin.Arch.aarch64_bev8_1a,
builtin.Arch.aarch64_bev8,
builtin.Arch.aarch64_bev8r,
builtin.Arch.aarch64_bev8m_baseline,
builtin.Arch.aarch64_bev8m_mainline,
builtin.Arch.thumb, builtin.Arch.thumb,
builtin.Arch.thumbeb, builtin.Arch.thumbeb,
=> true, => true,

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