commit 2dcf1a239250e60ec9d8865e16528049074ec4b0 (tree)
parent 7a8f391b0fa397eea4a9602a0132e0247d0f67b7
Author: Andrew Kelley <andrew@ziglang.org>
Date: Thu, 28 Feb 2019 09:19:18 -0500
Merge remote-tracking branch 'origin/master' into llvm8
Diffstat:
133 files changed, 11458 insertions(+), 4956 deletions(-)
diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml
@@ -4,7 +4,7 @@ packages:
- ninja
- llvm70
sources:
- - https://github.com/ziglang/zig.git
+ - https://github.com/ziglang/zig
tasks:
- build: |
cd zig && mkdir build && cd build
diff --git a/.gitignore b/.gitignore
@@ -10,6 +10,6 @@
# -andrewrk
zig-cache/
-build/
-build-*/
-docgen_tmp/
+/build/
+/build-*/
+/docgen_tmp/
diff --git a/CMakeLists.txt b/CMakeLists.txt
@@ -417,6 +417,7 @@ set(ZIG_SOURCES
"${CMAKE_SOURCE_DIR}/src/error.cpp"
"${CMAKE_SOURCE_DIR}/src/ir.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/main.cpp"
"${CMAKE_SOURCE_DIR}/src/os.cpp"
@@ -432,6 +433,10 @@ set(BLAKE_SOURCES
)
set(ZIG_CPP_SOURCES
"${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"
)
@@ -446,10 +451,12 @@ set(ZIG_STD_FILES
"buf_set.zig"
"buffer.zig"
"build.zig"
+ "build/fmt.zig"
"c/darwin.zig"
"c/freebsd.zig"
"c/index.zig"
"c/linux.zig"
+ "c/netbsd.zig"
"c/windows.zig"
"coff.zig"
"crypto/blake2.zig"
@@ -485,6 +492,7 @@ set(ZIG_STD_FILES
"fmt/errol/index.zig"
"fmt/errol/lookup.zig"
"fmt/index.zig"
+ "fmt/parse_float.zig"
"hash/adler.zig"
"hash/crc.zig"
"hash/fnv.zig"
@@ -589,6 +597,8 @@ set(ZIG_STD_FILES
"os/linux/index.zig"
"os/linux/vdso.zig"
"os/linux/x86_64.zig"
+ "os/netbsd/errno.zig"
+ "os/netbsd/index.zig"
"os/path.zig"
"os/time.zig"
"os/uefi.zig"
@@ -603,6 +613,7 @@ set(ZIG_STD_FILES
"os/windows/util.zig"
"os/zen.zig"
"pdb.zig"
+ "priority_queue.zig"
"rand/index.zig"
"rand/ziggurat.zig"
"segmented_list.zig"
@@ -611,6 +622,7 @@ set(ZIG_STD_FILES
"special/bootstrap_lib.zig"
"special/build_runner.zig"
"special/builtin.zig"
+ "special/compiler_rt/addXf3.zig"
"special/compiler_rt/aulldiv.zig"
"special/compiler_rt/aullrem.zig"
"special/compiler_rt/comparetf2.zig"
@@ -653,6 +665,7 @@ set(ZIG_STD_FILES
"special/compiler_rt/udivmodti4.zig"
"special/compiler_rt/udivti3.zig"
"special/compiler_rt/umodti3.zig"
+ "special/fmt_runner.zig"
"special/init-exe/build.zig"
"special/init-exe/src/main.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)
install(FILES "${CMAKE_SOURCE_DIR}/std/${file}" DESTINATION "${file_dir}")
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/")
diff --git a/README.md b/README.md
@@ -3,7 +3,7 @@
A programming language designed for robustness, optimality, and
clarity.
-[ziglang.org](https://ziglang.org)
+[Download & Documentation](https://ziglang.org/download/)
## Feature Highlights
@@ -77,36 +77,54 @@ clarity.
- what sizes are the C integer types
- C ABI calling convention for this target
- bootstrap code and default panic handler
+ * `zig targets` is guaranteed to include this target.
#### Tier 4 Support
* Support for these targets is entirely experimental.
* 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
- 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
-| | freestanding | linux | macosx | windows | freebsd | UEFI | other |
-|--------|--------------|--------|--------|---------|---------|--------|--------|
-|x86_64 | Tier 2 | Tier 1 | Tier 1 | Tier 1 | Tier 2 | Tier 2 | Tier 3 |
-|i386 | Tier 2 | Tier 2 | Tier 2 | Tier 2 | Tier 3 | Tier 3 | Tier 3 |
-|arm | Tier 2 | 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 |
-|bpf | 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 | Tier 3 |
-|mips | 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 | Tier 3 |
-|r600 | 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 | Tier 3 |
-|sparc | 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 | 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 | Tier 3 |
-|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 |
-|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 |
+| | freestanding | linux | macosx | windows | freebsd | netbsd | UEFI | other |
+|-------------|--------------|--------|--------|---------|---------|------- | -------|--------|
+|x86_64 | Tier 2 | Tier 1 | Tier 1 | Tier 1 | Tier 2 | Tier 2 | Tier 2 | 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 | Tier 3 |
+|arm64 | Tier 2 | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 |
+|avr | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 | N/A | Tier 3 |
+|bpf | 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 | N/A | Tier 3 |
+|mips | 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 | N/A | 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 | N/A | Tier 3 |
+|s390x | 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 | N/A | Tier 3 |
+|wasm32 | 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 | N/A |
+|riscv32 | 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 | 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
diff --git a/build.zig b/build.zig
@@ -49,13 +49,14 @@ pub fn build(b: *Builder) !void {
.c_header_files = nextValue(&index, build_info),
.dia_guids_lib = nextValue(&index, build_info),
.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);
var test_stage2 = b.addTest("src-self-hosted/test.zig");
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");
exe.setBuildMode(mode);
@@ -107,6 +108,11 @@ pub fn build(b: *Builder) !void {
}
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, "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 {
- exe.setNoRoSegment(ctx.no_rosegment);
-
exe.addIncludeDir("src");
exe.addIncludeDir(ctx.cmake_binary_dir);
addCppLib(b, exe, ctx.cmake_binary_dir, "zig_cpp");
@@ -375,5 +379,4 @@ const Context = struct {
c_header_files: []const u8,
dia_guids_lib: []const u8,
llvm: LibraryDep,
- no_rosegment: bool,
};
diff --git a/cmake/Findclang.cmake b/cmake/Findclang.cmake
@@ -11,17 +11,28 @@ if(MSVC)
find_package(CLANG REQUIRED CONFIG)
set(CLANG_LIBRARIES
+ clangFrontendTool
+ clangCodeGen
clangFrontend
clangDriver
clangSerialization
clangSema
+ clangStaticAnalyzerFrontend
+ clangStaticAnalyzerCheckers
+ clangStaticAnalyzerCore
clangAnalysis
+ clangASTMatchers
clangAST
clangParse
clangSema
clangBasic
clangEdit
clangLex
+ clangARCMigrate
+ clangRewriteFrontend
+ clangRewrite
+ clangCrossTU
+ clangIndex
)
else()
@@ -50,17 +61,28 @@ else()
endif()
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(clangDriver)
FIND_AND_ADD_CLANG_LIB(clangSerialization)
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(clangASTMatchers)
FIND_AND_ADD_CLANG_LIB(clangAST)
FIND_AND_ADD_CLANG_LIB(clangParse)
FIND_AND_ADD_CLANG_LIB(clangSema)
FIND_AND_ADD_CLANG_LIB(clangBasic)
FIND_AND_ADD_CLANG_LIB(clangEdit)
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()
include(FindPackageHandleStandardArgs)
diff --git a/doc/docgen.zig b/doc/docgen.zig
@@ -916,6 +916,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
std.zig.Token.Id.AngleBracketAngleBracketRightEqual,
std.zig.Token.Id.Tilde,
std.zig.Token.Id.BracketStarBracket,
+ std.zig.Token.Id.BracketStarCBracket,
=> try writeEscaped(out, src[token.start..token.end]),
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) {
- try test_args.appendSlice([][]const u8{
- "--target-os",
- "windows",
- "--target-arch",
- "x86_64",
- "--target-environ",
- "msvc",
- });
+ try test_args.appendSlice([][]const u8{ "-target", "x86_64-windows" });
}
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);
diff --git a/doc/langref.html.in b/doc/langref.html.in
@@ -8,13 +8,7 @@
body{
background-color:#111;
color: #bbb;
- font-family: system-ui,
- /* 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;
+ font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
}
a {
color: #88f;
@@ -243,8 +237,9 @@ const Timestamp = struct {
{#header_close#}
{#header_open|Values#}
{#code_begin|exe|values#}
-const std = @import("std");
+// Top-level declarations are order-independent:
const warn = std.debug.warn;
+const std = @import("std");
const os = std.os;
const assert = std.debug.assert;
@@ -262,7 +257,7 @@ pub fn main() void {
true and false,
true or false,
!true);
-
+
// optional
var optional_value: ?[]const u8 = null;
assert(optional_value == null);
@@ -281,7 +276,7 @@ pub fn main() void {
warn("\nerror union 1\ntype: {}\nvalue: {}\n",
@typeName(@typeOf(number_or_error)), number_or_error);
-
+
number_or_error = 1234;
warn("\nerror union 2\ntype: {}\nvalue: {}\n",
@@ -706,15 +701,21 @@ fn divide(a: i32, b: i32) i32 {
{#code_end#}
<p>
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
- division by zero.
+ and thus this division operation is vulnerable to both {#link|Integer Overflow#} and
+ {#link|Division by Zero#}.
</p>
<p>
Operators such as {#syntax#}+{#endsyntax#} and {#syntax#}-{#endsyntax#} cause undefined behavior on
integer overflow. Also available are operations such as {#syntax#}+%{#endsyntax#} and
{#syntax#}-%{#endsyntax#} which are defined to have wrapping arithmetic on all targets.
</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_open|Floats#}
@@ -1651,7 +1652,7 @@ test "pointer slicing" {
assert(array[3] == 5);
}
{#code_end#}
- <p>Pointers work at compile-time too, as long as the code does not depend on
+ <p>Pointers work at compile-time too, as long as the code does not depend on
an undefined memory layout:</p>
{#code_begin|test#}
const assert = @import("std").debug.assert;
@@ -1694,7 +1695,7 @@ test "comptime @intToPtr" {
}
}
{#code_end#}
- {#see_also|Optional Pointers#}
+ {#see_also|Optional Pointers|@intToPtr|@ptrToInt#}
{#header_open|volatile#}
<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#}.
@@ -1823,7 +1824,9 @@ fn foo(bytes: []u8) u32 {
}
{#code_end#}
{#header_close#}
+ {#see_also|C Pointers|Pointers to Zero Bit Types#}
{#header_close#}
+
{#header_open|Slices#}
{#code_begin|test_safety|index out of bounds#}
const assert = @import("std").debug.assert;
@@ -2043,14 +2046,211 @@ test "linked list" {
assert(list2.first.?.data == 1234);
}
{#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#}
- <p>{#syntax#}packed{#endsyntax#} structs have guaranteed in-memory layout.</p>
- <p>TODO bit fields</p>
- <p>TODO alignment</p>
- <p>TODO endianness</p>
- <p>TODO @bitOffsetOf and @byteOffsetOf</p>
- <p>TODO mention how volatile loads and stores of bit packed fields could be more efficient when
- done by hand instead of with packed struct</p>
+ <p>
+ Unlike normal structs, {#syntax#}packed{#endsyntax#} structs have guaranteed in-memory layout:
+ </p>
+ <ul>
+ <li>Fields remain in the order declared.</li>
+ <li>There is no padding between fields.</li>
+ <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_open|struct Naming#}
<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_open|packed enum#}
<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
- of the enum:</p>
+ <p>{#syntax#}packed enum{#endsyntax#} causes the size of the enum to be the same as the size of the
+ integer tag type of the enum:</p>
{#code_begin|test#}
const std = @import("std");
@@ -2214,131 +2414,179 @@ test "packed enum" {
std.debug.assert(@sizeOf(Number) == @sizeOf(u8));
}
{#code_end#}
+ <p>This makes the enum eligible to be in a {#link|packed struct#}.</p>
{#header_close#}
{#see_also|@memberName|@memberCount|@tagName|@sizeOf#}
{#header_close#}
{#header_open|union#}
- {#code_begin|test|union#}
-const assert = @import("std").debug.assert;
-const mem = @import("std").mem;
+ <p>
+ A bare {#syntax#}union{#endsyntax#} defines a set of possible types that a value
+ 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.
+ 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 {
+ Int: i64,
+ Float: f64,
+ Bool: bool,
+};
+test "simple union" {
+ var payload = Payload{ .Int = 1234 };
+ 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;
-// A union has only 1 active field at a time.
const Payload = union {
Int: i64,
Float: f64,
Bool: bool,
};
test "simple union" {
- var payload = Payload {.Int = 1234};
- // payload.Float = 12.34; // ERROR! field not active
+ var payload = 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);
}
+ {#code_end#}
+ <p>
+ In order to use {#link|switch#} with a union, it must be a {#link|Tagged union#}.
+ </p>
+
+ {#header_open|Tagged union#}
+ <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;
-// Unions can be given an enum tag type:
-const ComplexTypeTag = enum { Ok, NotOk };
+const ComplexTypeTag = enum {
+ Ok,
+ NotOk,
+};
const ComplexType = union(ComplexTypeTag) {
Ok: u8,
NotOk: void,
};
-// Declare a specific instance of the union variant.
-test "declare union value" {
- const c = ComplexType { .Ok = 0 };
+test "switch on tagged union" {
+ const c = ComplexType{ .Ok = 42 };
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" {
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 Foo = union(enum) {
- String: []const u8,
- Number: u64,
-
- // void can be omitted when inferring enum tag type.
- None,
+const ComplexTypeTag = enum {
+ Ok,
+ NotOk,
+};
+const ComplexType = union(ComplexTypeTag) {
+ Ok: u8,
+ 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
- Foo.Number => |x| blk: {
- assert(x == 54);
- break :blk "this is a number";
- },
+test "modify tagged union in switch" {
+ var c = ComplexType{ .Ok = 42 };
+ assert(ComplexTypeTag(c) == ComplexTypeTag.Ok);
- Foo.None => blk: {
- break :blk "this is a none";
- },
- };
- assert(mem.eql(u8, what_is_it, "this is a number"));
-}
+ switch (c) {
+ ComplexTypeTag.Ok => |*value| value.* += 1,
+ ComplexTypeTag.NotOk => unreachable,
+ }
-// Unions can have methods just like structs and enums:
+ assert(c.Ok == 43);
+}
+ {#code_end#}
+ <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) {
Int: i32,
Bool: bool,
+ // void can be omitted when inferring enum tag type.
+ None,
+
fn truthy(self: Variant) bool {
return switch (self) {
Variant.Int => |x_int| x_int != 0,
Variant.Bool => |x_bool| x_bool,
+ Variant.None => false,
};
}
};
test "union method" {
- var v1 = Variant { .Int = 1 };
- var v2 = Variant { .Bool = false };
+ var v1 = Variant{ .Int = 1 };
+ var v2 = Variant{ .Bool = false };
assert(v1.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) {
A: i32,
B: bool,
C: u8,
};
test "@tagName" {
- assert(mem.eql(u8, @tagName(Small2.C), "C"));
+ assert(std.mem.eql(u8, @tagName(Small2.C), "C"));
}
{#code_end#}
+ {#header_close#}
+
+ {#header_open|extern union#}
<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.
+ 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#}
<p>
Blocks are used to limit the scope of variable declarations:
@@ -2371,7 +2619,36 @@ test "labeled break from labeled block expression" {
{#code_end#}
<p>Here, {#syntax#}blk{#endsyntax#} can be any name.</p>
{#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_open|switch#}
{#code_begin|test|switch#}
const assert = @import("std").debug.assert;
@@ -2392,7 +2669,7 @@ test "switch simple" {
// Ranges can be specified using the ... syntax. These are inclusive
// both ends.
- 5 ... 100 => 1,
+ 5...100 => 1,
// Branches can be arbitrarily complex.
101 => blk: {
@@ -2418,14 +2695,47 @@ test "switch simple" {
assert(b == 1);
}
-test "switch enum" {
+// Switch expressions can be used outside a function:
+const os_msg = switch (builtin.os) {
+ builtin.Os.linux => "we found a linux user",
+ else => "not a linux user",
+};
+
+// Inside a function, switch statements implicitly are compile-time
+// evaluated if the target expression is compile-time known.
+test "switch inside function" {
+ switch (builtin.os) {
+ builtin.Os.fuchsia => {
+ // On an OS other than fuchsia, block is not even analyzed,
+ // so this compile error is not triggered.
+ // On fuchsia this compile error would be triggered.
+ @compileError("fuchsia not supported");
+ },
+ 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: struct { x: u8, y: u8 },
+ C: Point,
D,
};
- var a = Item { .A = 3 };
+ var a = Item{ .C = Point{ .x = 1, .y = 2 } };
// Switching on more complex enums is allowed.
const b = switch (a) {
@@ -2443,27 +2753,8 @@ test "switch enum" {
Item.D => 8,
};
- assert(b == 3);
-}
-
-// Switch expressions can be used outside a function:
-const os_msg = switch (builtin.os) {
- builtin.Os.linux => "we found a linux user",
- else => "not a linux user",
-};
-
-// Inside a function, switch statements implicitly are compile-time
-// evaluated if the target expression is compile-time known.
-test "switch inside function" {
- switch (builtin.os) {
- builtin.Os.fuchsia => {
- // On an OS other than fuchsia, block is not even analyzed,
- // so this compile error is not triggered.
- // On fuchsia this compile error would be triggered.
- @compileError("fuchsia not supported");
- },
- else => {},
- }
+ assert(b == 6);
+ assert(a.C.x == 2);
}
{#code_end#}
{#see_also|comptime|enum|@compileError|Compile Variables#}
@@ -3134,7 +3425,6 @@ const assert = @import("std").debug.assert;
// Functions are declared like this
fn add(a: i8, b: i8) i8 {
if (a == 0) {
- // You can still return manually if needed.
return b;
}
@@ -3158,12 +3448,18 @@ fn abort() noreturn {
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.
nakedcc fn _start() noreturn {
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.
// Another file can use @import and call sub2
pub fn sub2(a: i8, b: i8) i8 { return a - b; }
@@ -3731,7 +4027,7 @@ fn bang2() void {
Here, the stack trace does not explain how the control
flow in {#syntax#}bar{#endsyntax#} got to the {#syntax#}hello(){#endsyntax#} call.
One would have to open a debugger or further instrument the application
- in order to find out. The error return trace, on the other hand,
+ in order to find out. The error return trace, on the other hand,
shows exactly how the error bubbled up.
</p>
<p>
@@ -3923,7 +4219,7 @@ test "optional type" {
cast it to a different type:
</p>
{#code_begin|syntax#}
-const optional_value: ?i32 = null;
+const optional_value: ?i32 = null;
{#code_end#}
{#header_close#}
{#header_open|Optional Pointers#}
@@ -3981,7 +4277,7 @@ test "implicit cast - invoke a type as a function" {
{#code_end#}
<p>
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>
{#header_open|Implicit Cast: Stricter Qualification#}
<p>
@@ -4228,9 +4524,20 @@ fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 {
{#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>
- {#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:
</p>
{#code_begin|syntax#}
@@ -4240,8 +4547,8 @@ export fn entry() void {
x = y;
}
{#code_end#}
- <p>When this turns into LLVM IR, there is no code generated in the body of {#syntax#}entry{#endsyntax#},
- even in debug mode. For example, on x86_64:</p>
+ <p>When this turns into machine code, there is no code generated in the
+ body of {#syntax#}entry{#endsyntax#}, even in {#link|Debug#} mode. For example, on x86_64:</p>
<pre><code>0000000000000010 <entry>:
10: 55 push %rbp
11: 48 89 e5 mov %rsp,%rbp
@@ -4249,6 +4556,8 @@ export fn entry() void {
15: c3 retq </code></pre>
<p>These assembly instructions do not have any code associated with the void values -
they only perform the function call prologue and epilog.</p>
+
+ {#header_open|void#}
<p>
{#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#}
@@ -4320,6 +4629,38 @@ fn foo() i32 {
{#code_end#}
{#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#}
<p>
Zig places importance on the concept of whether an expression is known at compile-time.
@@ -5101,7 +5442,7 @@ async fn testResumeFromSuspend(my_result: *i32) void {
<p>
{#syntax#}await{#endsyntax#} is valid only in an {#syntax#}async{#endsyntax#} function, and it takes
as an operand a promise handle.
- If the async function associated with the promise handle has already returned,
+ If the async function associated with the promise handle has already returned,
then {#syntax#}await{#endsyntax#} destroys the target async function, and gives the return value.
Otherwise, {#syntax#}await{#endsyntax#} suspends the current async function, registering its
promise handle with the target coroutine. It becomes the target coroutine's responsibility
@@ -5185,7 +5526,7 @@ fn seq(c: u8) void {
</li>
</ul>
{#header_close#}
-
+
{#header_close#}
{#header_open|Builtin Functions#}
<p>
@@ -5540,13 +5881,13 @@ const warn = @import("std").debug.warn;
const num1 = blk: {
var val1: i32 = 99;
- @compileLog("comptime val1 = ", val1);
+ @compileLog("comptime val1 = ", val1);
val1 = val1 + 1;
break :blk val1;
};
test "main" {
- @compileLog("comptime in main");
+ @compileLog("comptime in main");
warn("Runtime in main, num1 = {}.\n", num1);
}
@@ -5556,10 +5897,10 @@ test "main" {
will ouput:
</p>
<p>
- If all {#syntax#}@compileLog{#endsyntax#} calls are removed or
+ If all {#syntax#}@compileLog{#endsyntax#} calls are removed or
not encountered by analysis, the
program compiles successfully and the generated executable prints:
- </p>
+ </p>
{#code_begin|test#}
const warn = @import("std").debug.warn;
@@ -5658,12 +5999,13 @@ test "main" {
{#header_close#}
{#header_open|@enumToInt#}
- <pre>{#syntax#}@enumToInt(enum_value: var) var{#endsyntax#}</pre>
+ <pre>{#syntax#}@enumToInt(enum_or_tagged_union: var) var{#endsyntax#}</pre>
<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>
- 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#}.
</p>
{#see_also|@intToEnum#}
@@ -6104,6 +6446,10 @@ test "call foo" {
<p>
Converts a pointer of one type to a pointer of another type.
</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_open|@ptrToInt#}
@@ -6293,10 +6639,15 @@ pub const FloatMode = enum {
<pre>{#syntax#}@sizeOf(comptime T: type) comptime_int{#endsyntax#}</pre>
<p>
This function returns the number of bytes it takes to store {#syntax#}T{#endsyntax#} in memory.
+ The result is a target-specific compile time constant.
</p>
<p>
- The result is a target-specific compile time constant.
+ 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_open|@sliceToBytes#}
@@ -6375,7 +6726,7 @@ fn List(comptime T: type) type {
<p>
When {#syntax#}@This(){#endsyntax#} is used at global scope, it returns a reference to the
current import. There is a proposal to remove the import type and use an empty struct
- type instead. See
+ type instead. See
<a href="https://github.com/ziglang/zig/issues/1047">#1047</a> for details.
</p>
{#header_close#}
@@ -6730,11 +7081,7 @@ pub fn build(b: *Builder) void {
{#header_open|Single Threaded Builds#}
<p>Zig has a compile option <code>--single-threaded</code> which has the following effects:
<ul>
- <li>{#link|@atomicLoad#} is emitted as a normal load.</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>Variables which have Thread Local Storage instead become globals.</li>
<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>
<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;
}
{#code_end#}
+ {#see_also|union|extern union#}
{#header_close#}
- {#header_open|Out of Bounds Float To Integer Cast#}
+ {#header_open|Out of Bounds Float to Integer Cast#}
<p>TODO</p>
{#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_open|Memory#}
<p>TODO: explain no default allocator in zig</p>
@@ -7439,6 +7804,7 @@ pub fn main() void {
{#code_end#}
{#see_also|String Literals#}
{#header_close#}
+
{#header_open|Import from C Header File#}
<p>
The {#syntax#}@cImport{#endsyntax#} builtin function can be used
@@ -7477,6 +7843,36 @@ const c = @cImport({
{#code_end#}
{#see_also|@cImport|@cInclude|@cDefine|@cUndef|@import#}
{#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#}
<p>
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
opencl</code></pre>
<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.
Not all standard library code requires operating system abstractions, however,
so things such as generic data structures work an all above platforms.
@@ -8164,7 +8560,8 @@ ArrayTypeStart <- LBRACKET Expr? RBRACKET
PtrTypeStart
<- ASTERISK
/ ASTERISK2
- / LBRACKET ASTERISK RBRACKET
+ / PTRUNKNOWN
+ / PTRC
# ContainerDecl specific
ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE
@@ -8262,7 +8659,7 @@ LARROW2 <- '<<' ![=] skip
LARROW2EQUAL <- '<<=' skip
LARROWEQUAL <- '<=' skip
LBRACE <- '{' skip
-LBRACKET <- '[' skip
+LBRACKET <- '[' ![*] skip
LPAREN <- '(' skip
MINUS <- '-' ![%=>] skip
MINUSEQUAL <- '-=' skip
@@ -8279,6 +8676,8 @@ PLUS2 <- '++' skip
PLUSEQUAL <- '+=' skip
PLUSPERCENT <- '+%' ![=] skip
PLUSPERCENTEQUAL <- '+%=' skip
+PTRC <- '[*c]' skip
+PTRUNKNOWN <- '[*]' skip
QUESTIONMARK <- '?' skip
RARROW <- '>' ![>=] skip
RARROW2 <- '>>' ![=] skip
diff --git a/example/mix_o_files/build.zig b/example/mix_o_files/build.zig
@@ -3,10 +3,10 @@ const Builder = @import("std").build.Builder;
pub fn build(b: *Builder) void {
const obj = b.addObject("base64", "base64.zig");
- const exe = b.addCExecutable("test");
- exe.addCompileFlags([][]const u8{"-std=c99"});
- exe.addSourceFile("test.c");
+ const exe = b.addExecutable("test", null);
+ exe.addCSourceFile("test.c",[][]const u8{"-std=c99"});
exe.addObject(obj);
+ exe.linkSystemLibrary("c");
b.default_step.dependOn(&exe.step);
diff --git a/example/shared_library/build.zig b/example/shared_library/build.zig
@@ -3,10 +3,10 @@ const Builder = @import("std").build.Builder;
pub fn build(b: *Builder) void {
const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0));
- const exe = b.addCExecutable("test");
- exe.addCompileFlags([][]const u8{"-std=c99"});
- exe.addSourceFile("test.c");
+ const exe = b.addExecutable("test", null);
+ exe.addCSourceFile("test.c", [][]const u8{"-std=c99"});
exe.linkLibrary(lib);
+ exe.linkSystemLibrary("c");
b.default_step.dependOn(&exe.step);
diff --git a/example/shared_library/mathtest.zig b/example/shared_library/mathtest.zig
@@ -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 {
return a + b;
}
diff --git a/src-self-hosted/codegen.zig b/src-self-hosted/codegen.zig
@@ -137,10 +137,10 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code)
pub const ObjectFile = struct {
comp: *Compilation,
- module: llvm.ModuleRef,
- builder: llvm.BuilderRef,
+ module: *llvm.Module,
+ builder: *llvm.Builder,
dibuilder: *llvm.DIBuilder,
- context: llvm.ContextRef,
+ context: *llvm.Context,
lock: event.Lock,
arena: *std.mem.Allocator,
@@ -323,7 +323,7 @@ pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code)
fn addLLVMAttr(
ofile: *ObjectFile,
- val: llvm.ValueRef,
+ val: *llvm.Value,
attr_index: llvm.AttributeIndex,
attr_name: []const u8,
) !void {
@@ -335,7 +335,7 @@ fn addLLVMAttr(
fn addLLVMAttrStr(
ofile: *ObjectFile,
- val: llvm.ValueRef,
+ val: *llvm.Value,
attr_index: llvm.AttributeIndex,
attr_name: []const u8,
attr_val: []const u8,
@@ -351,7 +351,7 @@ fn addLLVMAttrStr(
}
fn addLLVMAttrInt(
- val: llvm.ValueRef,
+ val: *llvm.Value,
attr_index: llvm.AttributeIndex,
attr_name: []const u8,
attr_val: u64,
@@ -362,25 +362,25 @@ fn addLLVMAttrInt(
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);
}
-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);
}
-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);
}
fn renderLoadUntyped(
ofile: *ObjectFile,
- ptr: llvm.ValueRef,
+ ptr: *llvm.Value,
alignment: Type.Pointer.Align,
vol: Type.Pointer.Vol,
name: [*]const u8,
-) !llvm.ValueRef {
+) !*llvm.Value {
const result = llvm.BuildLoad(ofile.builder, ptr, name) orelse return error.OutOfMemory;
switch (vol) {
Type.Pointer.Vol.Non => {},
@@ -390,11 +390,11 @@ fn renderLoadUntyped(
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);
}
-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;
if (!child_type.hasBits()) {
return null;
@@ -407,11 +407,11 @@ pub fn getHandleValue(ofile: *ObjectFile, ptr: llvm.ValueRef, ptr_type: *Type.Po
pub fn renderStoreUntyped(
ofile: *ObjectFile,
- value: llvm.ValueRef,
- ptr: llvm.ValueRef,
+ value: *llvm.Value,
+ ptr: *llvm.Value,
alignment: Type.Pointer.Align,
vol: Type.Pointer.Vol,
-) !llvm.ValueRef {
+) !*llvm.Value {
const result = llvm.BuildStore(ofile.builder, value, ptr) orelse return error.OutOfMemory;
switch (vol) {
Type.Pointer.Vol.Non => {},
@@ -423,10 +423,10 @@ pub fn renderStoreUntyped(
pub fn renderStore(
ofile: *ObjectFile,
- value: llvm.ValueRef,
- ptr: llvm.ValueRef,
+ value: *llvm.Value,
+ ptr: *llvm.Value,
ptr_type: *Type.Pointer,
-) !llvm.ValueRef {
+) !*llvm.Value {
return renderStoreUntyped(ofile, value, ptr, ptr_type.key.alignment, ptr_type.key.vol);
}
@@ -435,7 +435,7 @@ pub fn renderAlloca(
var_type: *Type,
name: []const u8,
alignment: Type.Pointer.Align,
-) !llvm.ValueRef {
+) !*llvm.Value {
const llvm_var_type = try var_type.getLlvmType(ofile.arena, ofile.context);
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;
@@ -443,7 +443,7 @@ pub fn renderAlloca(
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) {
Type.Pointer.Align.Abi => return llvm.ABIAlignmentOfType(ofile.comp.target_data_ref, llvm_type),
Type.Pointer.Align.Override => |a| a,
diff --git a/src-self-hosted/compilation.zig b/src-self-hosted/compilation.zig
@@ -37,7 +37,7 @@ const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB
/// Data that is local to the event loop.
pub const ZigCompiler = struct {
loop: *event.Loop,
- llvm_handle_pool: std.atomic.Stack(llvm.ContextRef),
+ llvm_handle_pool: std.atomic.Stack(*llvm.Context),
lld_lock: event.Lock,
/// TODO pool these so that it doesn't have to lock
@@ -60,7 +60,7 @@ pub const ZigCompiler = struct {
return ZigCompiler{
.loop = 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)),
.native_libc = event.Future(LibCInstallation).init(loop),
};
@@ -70,7 +70,7 @@ pub const ZigCompiler = struct {
fn deinit(self: *ZigCompiler) void {
self.lld_lock.deinit();
while (self.llvm_handle_pool.pop()) |node| {
- c.LLVMContextDispose(node.data);
+ llvm.ContextDispose(node.data);
self.loop.allocator.destroy(node);
}
}
@@ -80,11 +80,11 @@ pub const ZigCompiler = struct {
pub fn getAnyLlvmContext(self: *ZigCompiler) !LlvmHandle {
if (self.llvm_handle_pool.pop()) |node| return LlvmHandle{ .node = node };
- const context_ref = c.LLVMContextCreate() orelse return error.OutOfMemory;
- errdefer c.LLVMContextDispose(context_ref);
+ const context_ref = llvm.ContextCreate() orelse return error.OutOfMemory;
+ errdefer llvm.ContextDispose(context_ref);
- const node = try self.loop.allocator.create(std.atomic.Stack(llvm.ContextRef).Node);
- node.* = std.atomic.Stack(llvm.ContextRef).Node{
+ const node = try self.loop.allocator.create(std.atomic.Stack(*llvm.Context).Node);
+ node.* = std.atomic.Stack(*llvm.Context).Node{
.next = undefined,
.data = context_ref,
};
@@ -114,7 +114,7 @@ pub const ZigCompiler = 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 {
zig_compiler.llvm_handle_pool.push(self.node);
@@ -128,7 +128,7 @@ pub const Compilation = struct {
llvm_triple: Buffer,
root_src_path: ?[]const u8,
target: Target,
- llvm_target: llvm.TargetRef,
+ llvm_target: *llvm.Target,
build_mode: builtin.Mode,
zig_lib_dir: []const u8,
zig_std_dir: []const u8,
@@ -212,8 +212,8 @@ pub const Compilation = struct {
false_value: *Value.Bool,
noreturn_value: *Value.NoReturn,
- target_machine: llvm.TargetMachineRef,
- target_data_ref: llvm.TargetDataRef,
+ target_machine: *llvm.TargetMachine,
+ target_data_ref: *llvm.TargetData,
target_layout_str: [*]u8,
target_ptr_bits: u32,
diff --git a/src-self-hosted/ir.zig b/src-self-hosted/ir.zig
@@ -67,7 +67,7 @@ pub const Inst = struct {
parent: ?*Inst,
/// populated durign codegen
- llvm_value: ?llvm.ValueRef,
+ llvm_value: ?*llvm.Value,
pub fn cast(base: *Inst, comptime T: type) ?*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) {
Id.Return => return @fieldParentPtr(Return, "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;
}
- 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 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| {
args[i] = arg.llvm_value.?;
}
@@ -360,7 +360,7 @@ pub const Inst = struct {
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);
}
};
@@ -392,7 +392,7 @@ pub const Inst = struct {
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 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) {
Scope.Var.Data.Const => unreachable, // turned into Inst.Const in analyze pass
Scope.Var.Data.Param => |param| return param.llvm_value,
@@ -596,7 +596,7 @@ pub const Inst = struct {
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();
if (!child_type.hasBits()) {
return null;
@@ -935,8 +935,8 @@ pub const BasicBlock = struct {
ref_instruction: ?*Inst,
/// for codegen
- llvm_block: llvm.BasicBlockRef,
- llvm_exit_block: llvm.BasicBlockRef,
+ llvm_block: *llvm.BasicBlock,
+ llvm_exit_block: *llvm.BasicBlock,
/// the basic block that is derived from this one in analysis
child: ?*BasicBlock,
diff --git a/src-self-hosted/libc_installation.zig b/src-self-hosted/libc_installation.zig
@@ -154,8 +154,8 @@ pub const LibCInstallation = struct {
c.ZigFindWindowsSdkError.None => {
windows_sdk = sdk;
- if (sdk.msvc_lib_dir_ptr) |ptr| {
- self.msvc_lib_dir = try std.mem.dupe(loop.allocator, u8, ptr[0..sdk.msvc_lib_dir_len]);
+ if (sdk.msvc_lib_dir_ptr != 0) {
+ 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(findNativeIncludeDirWindows, self, loop, sdk);
@@ -172,7 +172,7 @@ pub const LibCInstallation = struct {
try group.call(findNativeStaticLibDir, 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");
},
else => @compileError("unimplemented: find libc for this OS"),
@@ -283,7 +283,7 @@ pub const LibCInstallation = struct {
switch (builtin.arch) {
builtin.Arch.i386 => try stream.write("x86"),
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,
}
const ucrt_lib_path = try std.os.path.join(
@@ -361,7 +361,7 @@ pub const LibCInstallation = struct {
switch (builtin.arch) {
builtin.Arch.i386 => try stream.write("x86\\"),
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,
}
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 {
var search_end: usize = 0;
- if (sdk.path10_ptr) |path10_ptr| {
- if (sdk.version10_ptr) |ver10_ptr| {
+ if (sdk.path10_ptr != 0) {
+ if (sdk.version10_ptr != 0) {
search_buf[search_end] = Search{
- .path = path10_ptr[0..sdk.path10_len],
- .version = ver10_ptr[0..sdk.version10_len],
+ .path = sdk.path10_ptr[0..sdk.path10_len],
+ .version = sdk.version10_ptr[0..sdk.version10_len],
};
search_end += 1;
}
}
- if (sdk.path81_ptr) |path81_ptr| {
- if (sdk.version81_ptr) |ver81_ptr| {
+ if (sdk.path81_ptr != 0) {
+ if (sdk.version81_ptr != 0) {
search_buf[search_end] = Search{
- .path = path81_ptr[0..sdk.path81_len],
- .version = ver81_ptr[0..sdk.version81_len],
+ .path = sdk.path81_ptr[0..sdk.path81_len],
+ .version = sdk.version81_ptr[0..sdk.version81_len],
};
search_end += 1;
}
diff --git a/src-self-hosted/link.zig b/src-self-hosted/link.zig
@@ -145,10 +145,6 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
// lj->args.append("-T");
// lj->args.append(g->linker_script);
//}
-
- //if (g->no_rosegment_workaround) {
- // lj->args.append("--no-rosegment");
- //}
try ctx.args.append(c"--gc-sections");
//lj->args.append("-m");
@@ -330,7 +326,7 @@ fn constructLinkerArgsCoff(ctx: *Context) !void {
switch (ctx.comp.target.getArch()) {
builtin.Arch.i386 => try ctx.args.append(c"-MACHINE:X86"),
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,
}
@@ -556,7 +552,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {
}
},
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
} else if (platform.versionLessThan(3, 1)) {
try ctx.args.append(c"-lcrt1.o");
diff --git a/src-self-hosted/llvm.zig b/src-self-hosted/llvm.zig
@@ -11,45 +11,31 @@ const assert = @import("std").debug.assert;
pub const AttributeIndex = c_uint;
pub const Bool = c_int;
-pub const BuilderRef = removeNullability(c.LLVMBuilderRef);
-pub const ContextRef = removeNullability(c.LLVMContextRef);
-pub const ModuleRef = removeNullability(c.LLVMModuleRef);
-pub const ValueRef = removeNullability(c.LLVMValueRef);
-pub const TypeRef = removeNullability(c.LLVMTypeRef);
-pub const BasicBlockRef = removeNullability(c.LLVMBasicBlockRef);
-pub const AttributeRef = removeNullability(c.LLVMAttributeRef);
-pub const TargetRef = removeNullability(c.LLVMTargetRef);
-pub const TargetMachineRef = removeNullability(c.LLVMTargetMachineRef);
-pub const TargetDataRef = removeNullability(c.LLVMTargetDataRef);
+pub const Builder = c.LLVMBuilderRef.Child.Child;
+pub const Context = c.LLVMContextRef.Child.Child;
+pub const Module = c.LLVMModuleRef.Child.Child;
+pub const Value = c.LLVMValueRef.Child.Child;
+pub const Type = c.LLVMTypeRef.Child.Child;
+pub const BasicBlock = c.LLVMBasicBlockRef.Child.Child;
+pub const Attribute = c.LLVMAttributeRef.Child.Child;
+pub const Target = c.LLVMTargetRef.Child.Child;
+pub const TargetMachine = c.LLVMTargetMachineRef.Child.Child;
+pub const TargetData = c.LLVMTargetDataRef.Child.Child;
pub const DIBuilder = c.ZigLLVMDIBuilder;
+pub const DIFile = c.ZigLLVMDIFile;
+pub const DICompileUnit = c.ZigLLVMDICompileUnit;
pub const ABIAlignmentOfType = c.LLVMABIAlignmentOfType;
pub const AddAttributeAtIndex = c.LLVMAddAttributeAtIndex;
-pub const AddFunction = c.LLVMAddFunction;
-pub const AddGlobal = c.LLVMAddGlobal;
pub const AddModuleCodeViewFlag = c.ZigLLVMAddModuleCodeViewFlag;
pub const AddModuleDebugInfoFlag = c.ZigLLVMAddModuleDebugInfoFlag;
-pub const ArrayType = c.LLVMArrayType;
-pub const BuildLoad = c.LLVMBuildLoad;
pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation;
pub const ConstAllOnes = c.LLVMConstAllOnes;
pub const ConstArray = c.LLVMConstArray;
pub const ConstBitCast = c.LLVMConstBitCast;
-pub const ConstInt = c.LLVMConstInt;
pub const ConstIntOfArbitraryPrecision = c.LLVMConstIntOfArbitraryPrecision;
pub const ConstNeg = c.LLVMConstNeg;
-pub const ConstNull = c.LLVMConstNull;
-pub const ConstStringInContext = c.LLVMConstStringInContext;
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 DisposeBuilder = c.LLVMDisposeBuilder;
pub const DisposeDIBuilder = c.ZigLLVMDisposeDIBuilder;
@@ -62,9 +48,7 @@ pub const DumpModule = c.LLVMDumpModule;
pub const FP128TypeInContext = c.LLVMFP128TypeInContext;
pub const FloatTypeInContext = c.LLVMFloatTypeInContext;
pub const GetEnumAttributeKindForName = c.LLVMGetEnumAttributeKindForName;
-pub const GetHostCPUName = c.ZigLLVMGetHostCPUName;
pub const GetMDKindIDInContext = c.LLVMGetMDKindIDInContext;
-pub const GetNativeFeatures = c.ZigLLVMGetNativeFeatures;
pub const GetUndef = c.LLVMGetUndef;
pub const HalfTypeInContext = c.LLVMHalfTypeInContext;
pub const InitializeAllAsmParsers = c.LLVMInitializeAllAsmParsers;
@@ -81,14 +65,11 @@ pub const Int64TypeInContext = c.LLVMInt64TypeInContext;
pub const Int8TypeInContext = c.LLVMInt8TypeInContext;
pub const IntPtrTypeForASInContext = c.LLVMIntPtrTypeForASInContext;
pub const IntPtrTypeInContext = c.LLVMIntPtrTypeInContext;
-pub const IntTypeInContext = c.LLVMIntTypeInContext;
pub const LabelTypeInContext = c.LLVMLabelTypeInContext;
pub const MDNodeInContext = c.LLVMMDNodeInContext;
pub const MDStringInContext = c.LLVMMDStringInContext;
pub const MetadataTypeInContext = c.LLVMMetadataTypeInContext;
-pub const ModuleCreateWithNameInContext = c.LLVMModuleCreateWithNameInContext;
pub const PPCFP128TypeInContext = c.LLVMPPCFP128TypeInContext;
-pub const PointerType = c.LLVMPointerType;
pub const SetAlignment = c.LLVMSetAlignment;
pub const SetDataLayout = c.LLVMSetDataLayout;
pub const SetGlobalConstant = c.LLVMSetGlobalConstant;
@@ -99,50 +80,146 @@ pub const SetUnnamedAddr = c.LLVMSetUnnamedAddr;
pub const SetVolatile = c.LLVMSetVolatile;
pub const StructTypeInContext = c.LLVMStructTypeInContext;
pub const TokenTypeInContext = c.LLVMTokenTypeInContext;
-pub const VoidTypeInContext = c.LLVMVoidTypeInContext;
pub const X86FP80TypeInContext = c.LLVMX86FP80TypeInContext;
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;
-extern fn LLVMGetElementType(Ty: TypeRef) TypeRef;
+extern fn LLVMGetElementType(Ty: *Type) *Type;
pub const TypeOf = LLVMTypeOf;
-extern fn LLVMTypeOf(Val: ValueRef) TypeRef;
+extern fn LLVMTypeOf(Val: *Value) *Type;
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;
-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 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;
-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;
-extern fn LLVMVerifyModule(M: ModuleRef, Action: VerifierFailureAction, OutMessage: *?[*]u8) Bool;
+extern fn LLVMVerifyModule(M: *Module, Action: VerifierFailureAction, OutMessage: *?[*]u8) Bool;
pub const GetInsertBlock = LLVMGetInsertBlock;
-extern fn LLVMGetInsertBlock(Builder: BuilderRef) BasicBlockRef;
+extern fn LLVMGetInsertBlock(Builder: *Builder) *BasicBlock;
pub const FunctionType = LLVMFunctionType;
extern fn LLVMFunctionType(
- ReturnType: TypeRef,
- ParamTypes: [*]TypeRef,
+ ReturnType: *Type,
+ ParamTypes: [*]*Type,
ParamCount: c_uint,
IsVarArg: Bool,
-) ?TypeRef;
+) ?*Type;
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;
-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;
-extern fn LLVMPositionBuilderAtEnd(Builder: BuilderRef, Block: BasicBlockRef) void;
+extern fn LLVMPositionBuilderAtEnd(Builder: *Builder, Block: *BasicBlock) void;
pub const AbortProcessAction = VerifierFailureAction.LLVMAbortProcessAction;
pub const PrintMessageAction = VerifierFailureAction.LLVMPrintMessageAction;
@@ -190,17 +267,17 @@ pub const FnInline = extern enum {
};
fn removeNullability(comptime T: type) type {
- comptime assert(@typeId(T) == builtin.TypeId.Optional);
- return T.Child;
+ comptime assert(@typeInfo(T).Pointer.size == @import("builtin").TypeInfo.Pointer.Size.C);
+ return *T.Child;
}
pub const BuildRet = LLVMBuildRet;
-extern fn LLVMBuildRet(arg0: BuilderRef, V: ?ValueRef) ?ValueRef;
+extern fn LLVMBuildRet(arg0: *Builder, V: ?*Value) ?*Value;
pub const TargetMachineEmitToFile = ZigLLVMTargetMachineEmitToFile;
extern fn ZigLLVMTargetMachineEmitToFile(
- targ_machine_ref: TargetMachineRef,
- module_ref: ModuleRef,
+ targ_machine_ref: *TargetMachine,
+ module_ref: *Module,
filename: [*]const u8,
output_type: EmitOutputType,
error_message: *[*]u8,
@@ -209,6 +286,6 @@ extern fn ZigLLVMTargetMachineEmitToFile(
) bool;
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;
diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig
@@ -24,7 +24,7 @@ var stderr_file: os.File = undefined;
var stderr: *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 =
\\usage: zig [command] [options]
@@ -154,9 +154,7 @@ const usage_build_generic =
\\ release-small optimize for small binary, safety off
\\ --static Output will be statically linked
\\ --strip Exclude debug symbols
- \\ --target-arch [name] Specify target architecture
- \\ --target-environ [name] Specify target environment
- \\ --target-os [name] Specify target operating system
+ \\ -target [name] <arch><sub>-<os>-<abi> see the targets command
\\ --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-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("--static"),
Flag.Bool("--strip"),
- Flag.Arg1("--target-arch"),
- Flag.Arg1("--target-environ"),
- Flag.Arg1("--target-os"),
+ Flag.Arg1("-target"),
Flag.Bool("--verbose-tokenize"),
Flag.Bool("--verbose-ast-tree"),
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);
}
-const usage_fmt =
+pub const usage_fmt =
\\usage: zig fmt [file]...
\\
\\ 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("--check"),
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("Environments:\n");
+ try stdout.write("C ABIs:\n");
{
comptime var i: usize = 0;
- inline while (i < @memberCount(builtin.Environ)) : (i += 1) {
- comptime const environ_tag = @memberName(builtin.Environ, i);
+ inline while (i < @memberCount(builtin.Abi)) : (i += 1) {
+ comptime const abi_tag = @memberName(builtin.Abi, i);
// 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);
}
}
}
diff --git a/src-self-hosted/scope.zig b/src-self-hosted/scope.zig
@@ -362,7 +362,7 @@ pub const Scope = struct {
pub const Param = struct {
index: usize,
typ: *Type,
- llvm_value: llvm.ValueRef,
+ llvm_value: *llvm.Value,
};
pub fn createParam(
diff --git a/src-self-hosted/target.zig b/src-self-hosted/target.zig
@@ -16,7 +16,7 @@ pub const Target = union(enum) {
pub const Cross = struct {
arch: builtin.Arch,
os: builtin.Os,
- environ: builtin.Environ,
+ abi: builtin.Abi,
object_format: builtin.ObjectFormat,
};
@@ -49,16 +49,16 @@ pub const Target = union(enum) {
}
pub fn getArch(self: Target) builtin.Arch {
- return switch (self) {
- Target.Native => builtin.arch,
- @TagType(Target).Cross => |t| t.arch,
- };
+ switch (self) {
+ Target.Native => return builtin.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) {
- Target.Native => builtin.environ,
- @TagType(Target).Cross => |t| t.environ,
+ Target.Native => builtin.abi,
+ @TagType(Target).Cross => |t| t.abi,
};
}
@@ -93,50 +93,10 @@ pub const Target = union(enum) {
/// TODO expose the arch and subarch separately
pub fn isArmOrThumb(self: Target) bool {
return switch (self.getArch()) {
- builtin.Arch.armv8_5a,
- 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.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.arm,
+ builtin.Arch.armeb,
+ builtin.Arch.aarch64,
+ builtin.Arch.aarch64_be,
builtin.Arch.thumb,
builtin.Arch.thumbeb,
=> true,
@@ -159,14 +119,14 @@ pub const Target = union(enum) {
// LLVM WebAssembly output support requires the target to be activated at
// 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
// LLVM 6 sets the wasm arch output incorrectly to ELF. We need to
// 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
// 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;
try out.print("{}-unknown-{}-{}", @tagName(self.getArch()), @tagName(self.getOs()), env_name);
@@ -185,50 +145,8 @@ pub const Target = union(enum) {
=> return 16,
builtin.Arch.arc,
- builtin.Arch.armv8_5a,
- 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.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.arm,
+ builtin.Arch.armeb,
builtin.Arch.hexagon,
builtin.Arch.le32,
builtin.Arch.mipsr6,
@@ -248,35 +166,17 @@ pub const Target = union(enum) {
builtin.Arch.amdil,
builtin.Arch.hsail,
builtin.Arch.spir,
- builtin.Arch.kalimbav3,
- builtin.Arch.kalimbav4,
- builtin.Arch.kalimbav5,
+ builtin.Arch.kalimba,
builtin.Arch.shave,
builtin.Arch.lanai,
builtin.Arch.wasm32,
builtin.Arch.renderscript32,
=> return 32,
- builtin.Arch.aarch64v8_5a,
- 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,
- 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.aarch64,
+ builtin.Arch.aarch64_be,
+ builtin.Arch.mips64,
+ builtin.Arch.mips64el,
builtin.Arch.powerpc64,
builtin.Arch.powerpc64le,
builtin.Arch.riscv64,
@@ -298,17 +198,17 @@ pub const Target = union(enum) {
}
pub fn getFloatAbi(self: Target) FloatAbi {
- return switch (self.getEnviron()) {
- builtin.Environ.gnueabihf,
- builtin.Environ.eabihf,
- builtin.Environ.musleabihf,
+ return switch (self.getAbi()) {
+ builtin.Abi.gnueabihf,
+ builtin.Abi.eabihf,
+ builtin.Abi.musleabihf,
=> FloatAbi.Hard,
else => FloatAbi.Soft,
};
}
pub fn getDynamicLinkerPath(self: Target) ?[]const u8 {
- const env = self.getEnviron();
+ const env = self.getAbi();
const arch = self.getArch();
const os = self.getOs();
switch (os) {
@@ -317,21 +217,21 @@ pub const Target = union(enum) {
},
builtin.Os.linux => {
switch (env) {
- builtin.Environ.android => {
+ builtin.Abi.android => {
if (self.is64bit()) {
return "/system/bin/linker64";
} else {
return "/system/bin/linker";
}
},
- builtin.Environ.gnux32 => {
+ builtin.Abi.gnux32 => {
if (arch == builtin.Arch.x86_64) {
return "/libx32/ld-linux-x32.so.2";
}
},
- builtin.Environ.musl,
- builtin.Environ.musleabi,
- builtin.Environ.musleabihf,
+ builtin.Abi.musl,
+ builtin.Abi.musleabi,
+ builtin.Abi.musleabihf,
=> {
if (arch == builtin.Arch.x86_64) {
return "/lib/ld-musl-x86_64.so.1";
@@ -345,73 +245,18 @@ pub const Target = union(enum) {
builtin.Arch.sparcel,
=> return "/lib/ld-linux.so.2",
- builtin.Arch.aarch64v8_5a,
- 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_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.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.aarch64 => return "/lib/ld-linux-aarch64.so.1",
+
+ builtin.Arch.aarch64_be => return "/lib/ld-linux-aarch64_be.so.1",
+
+ builtin.Arch.arm,
builtin.Arch.thumb,
- 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,
+ => return switch (self.getFloatAbi()) {
+ FloatAbi.Hard => return "/lib/ld-linux-armhf.so.3",
+ else => return "/lib/ld-linux.so.3",
+ },
+
+ builtin.Arch.armeb,
builtin.Arch.thumbeb,
=> return switch (self.getFloatAbi()) {
FloatAbi.Hard => return "/lib/ld-linux-armhf.so.3",
@@ -454,9 +299,7 @@ pub const Target = union(enum) {
builtin.Arch.hsail64,
builtin.Arch.spir,
builtin.Arch.spir64,
- builtin.Arch.kalimbav3,
- builtin.Arch.kalimbav4,
- builtin.Arch.kalimbav5,
+ builtin.Arch.kalimba,
builtin.Arch.shave,
builtin.Arch.lanai,
builtin.Arch.wasm32,
@@ -470,8 +313,8 @@ pub const Target = union(enum) {
}
}
- pub fn llvmTargetFromTriple(triple: std.Buffer) !llvm.TargetRef {
- var result: llvm.TargetRef = undefined;
+ pub fn llvmTargetFromTriple(triple: std.Buffer) !*llvm.Target {
+ var result: *llvm.Target = undefined;
var err_msg: [*]u8 = undefined;
if (llvm.GetTargetFromTriple(triple.ptr(), &result, &err_msg) != 0) {
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 {
const arch = self.getArch();
switch (arch) {
- builtin.Arch.aarch64v8_5a,
- 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.aarch64 => return "arm64",
builtin.Arch.thumb,
- builtin.Arch.armv8_5a,
- 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.arm,
=> return "arm",
builtin.Arch.powerpc => return "ppc",
builtin.Arch.powerpc64 => return "ppc64",
diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig
@@ -51,8 +51,8 @@ pub const Type = struct {
pub fn getLlvmType(
base: *Type,
allocator: *Allocator,
- llvm_context: llvm.ContextRef,
- ) (error{OutOfMemory}!llvm.TypeRef) {
+ llvm_context: *llvm.Context,
+ ) (error{OutOfMemory}!*llvm.Type) {
switch (base.id) {
Id.Struct => return @fieldParentPtr(Struct, "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.
- 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.*;
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.
- 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);
return @intCast(u32, llvm.ABIAlignmentOfType(comp.target_data_ref, llvm_type));
}
@@ -218,7 +218,7 @@ pub const Type = struct {
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");
}
};
@@ -496,13 +496,13 @@ pub const Type = struct {
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 llvm_return_type = switch (normal.return_type.id) {
Type.Id.Void => llvm.VoidTypeInContext(llvm_context) orelse return error.OutOfMemory,
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);
for (llvm_param_types) |*llvm_param_type, i| {
llvm_param_type.* = try normal.params[i].typ.getLlvmType(allocator, llvm_context);
@@ -559,7 +559,7 @@ pub const Type = struct {
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");
}
};
@@ -658,7 +658,7 @@ pub const Type = struct {
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;
}
};
@@ -670,7 +670,7 @@ pub const Type = struct {
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");
}
};
@@ -794,6 +794,7 @@ pub const Type = struct {
Size.One => "*",
Size.Many => "[*]",
Size.Slice => "[]",
+ Size.C => "[*c]",
};
const mut_str = switch (self.key.mut) {
Mut.Const => "const ",
@@ -835,7 +836,7 @@ pub const Type = struct {
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);
return llvm.PointerType(elem_llvm_type, 0) orelse return error.OutOfMemory;
}
@@ -903,7 +904,7 @@ pub const Type = struct {
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);
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);
}
- 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");
}
};
@@ -966,7 +967,7 @@ pub const Type = struct {
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");
}
};
@@ -978,7 +979,7 @@ pub const Type = struct {
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");
}
};
@@ -990,7 +991,7 @@ pub const Type = struct {
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");
}
};
@@ -1002,7 +1003,7 @@ pub const Type = struct {
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");
}
};
@@ -1014,7 +1015,7 @@ pub const Type = struct {
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");
}
};
@@ -1034,7 +1035,7 @@ pub const Type = struct {
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");
}
};
@@ -1054,7 +1055,7 @@ pub const Type = struct {
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");
}
};
@@ -1066,7 +1067,7 @@ pub const Type = struct {
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");
}
};
@@ -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.Many => @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),
diff --git a/src-self-hosted/value.zig b/src-self-hosted/value.zig
@@ -57,7 +57,7 @@ pub const Value = struct {
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) {
Id.Type => unreachable,
Id.Fn => return @fieldParentPtr(Fn, "base", base).getLlvmConst(ofile),
@@ -153,7 +153,7 @@ pub const Value = struct {
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 = llvm.AddFunction(
ofile.module,
@@ -238,7 +238,7 @@ pub const Value = struct {
/// 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.
/// 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 = llvm.AddFunction(
ofile.module,
@@ -283,8 +283,8 @@ pub const Value = struct {
comp.gpa().destroy(self);
}
- pub fn getLlvmConst(self: *Bool, ofile: *ObjectFile) ?llvm.ValueRef {
- const llvm_type = llvm.Int1TypeInContext(ofile.context);
+ pub fn getLlvmConst(self: *Bool, ofile: *ObjectFile) !?*llvm.Value {
+ const llvm_type = llvm.Int1TypeInContext(ofile.context) orelse return error.OutOfMemory;
if (self.x) {
return llvm.ConstAllOnes(llvm_type);
} else {
@@ -381,7 +381,7 @@ pub const Value = struct {
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);
// TODO carefully port the logic from codegen.cpp:gen_const_val_ptr
switch (self.special) {
@@ -391,7 +391,7 @@ pub const Value = struct {
const array_llvm_value = (try base_array.val.getLlvmConst(ofile)).?;
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 indices = []llvm.ValueRef{
+ const indices = []*llvm.Value{
llvm.ConstNull(usize_llvm_type) 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);
}
- pub fn getLlvmConst(self: *Array, ofile: *ObjectFile) !?llvm.ValueRef {
+ pub fn getLlvmConst(self: *Array, ofile: *ObjectFile) !?*llvm.Value {
switch (self.special) {
Special.Undefined => {
const llvm_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
@@ -534,7 +534,7 @@ pub const Value = struct {
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) {
Type.Id.Int => {
const type_ref = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
diff --git a/src/all_types.hpp b/src/all_types.hpp
@@ -18,6 +18,7 @@
#include "bigfloat.hpp"
#include "target.hpp"
#include "tokenizer.hpp"
+#include "libc_installation.hpp"
struct AstNode;
struct ImportTableEntry;
@@ -630,24 +631,12 @@ struct AstNodeUnwrapOptional {
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 {
AstNode *fn_ref_expr;
ZigList<AstNode *> params;
bool is_builtin;
bool is_async;
+ bool seen; // used by @compileLog
AstNode *async_allocator;
};
@@ -691,15 +680,17 @@ struct AstNodePointerType {
AstNode *align_expr;
BigInt *bit_offset_start;
BigInt *host_int_bytes;
+ AstNode *op_expr;
+ Token *allow_zero_token;
bool is_const;
bool is_volatile;
- AstNode *op_expr;
};
struct AstNodeArrayType {
AstNode *size;
AstNode *child_type;
AstNode *align_expr;
+ Token *allow_zero_token;
bool is_const;
bool is_volatile;
};
@@ -1038,6 +1029,7 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b);
enum PtrLen {
PtrLenUnknown,
PtrLenSingle,
+ PtrLenC,
};
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
bool is_const;
bool is_volatile;
+ bool allow_zero;
};
struct ZigTypeInt {
@@ -1247,6 +1240,12 @@ enum ZigTypeId {
ZigTypeIdVector,
};
+enum OnePossibleValue {
+ OnePossibleValueInvalid,
+ OnePossibleValueNo,
+ OnePossibleValueYes,
+};
+
struct ZigType {
ZigTypeId id;
Buf name;
@@ -1254,9 +1253,6 @@ struct ZigType {
LLVMTypeRef type_ref;
ZigLLVMDIType *di_type;
- bool zero_bits; // this is denormalized data
- bool gen_h_loop_flag;
-
union {
ZigTypePointer pointer;
ZigTypeInt integral;
@@ -1282,6 +1278,11 @@ struct ZigType {
// If we generate a constant name value for this type, we memoize it here.
// The type of this is array
ConstExprValue *cached_const_name_val;
+
+ OnePossibleValue one_possible_value;
+
+ bool zero_bits; // this is denormalized data
+ bool gen_h_loop_flag;
};
struct PackageTableEntry {
@@ -1340,15 +1341,11 @@ struct ZigFn {
// in the case of async functions this is the implicit return type according to the
// zig source code, not according to zig ir
ZigType *src_implicit_return_type;
- bool is_test;
- FnInline fn_inline;
- FnAnalState anal_state;
IrExecutable ir_executable;
IrExecutable analyzed_executable;
size_t prealloc_bbc;
AstNode **param_source_nodes;
Buf **param_names;
- uint32_t align_bytes;
AstNode *fn_no_inline_set_node;
AstNode *fn_static_eval_set_node;
@@ -1358,13 +1355,22 @@ struct ZigFn {
Buf *section_name;
AstNode *set_alignstack_node;
- uint32_t alignstack_value;
AstNode *set_cold_node;
- bool is_cold;
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 is_cold;
+ bool is_test;
};
uint32_t fn_table_entry_hash(ZigFn*);
@@ -1484,6 +1490,7 @@ enum PanicMsgId {
PanicMsgIdBadUnionField,
PanicMsgIdBadEnumValue,
PanicMsgIdFloatToInt,
+ PanicMsgIdPtrCastNull,
PanicMsgIdCount,
};
@@ -1498,11 +1505,12 @@ struct TypeId {
struct {
ZigType *child_type;
PtrLen ptr_len;
- bool is_const;
- bool is_volatile;
uint32_t alignment;
uint32_t bit_offset_in_host;
uint32_t host_int_bytes;
+ bool is_const;
+ bool is_volatile;
+ bool allow_zero;
} pointer;
struct {
ZigType *child_type;
@@ -1605,6 +1613,17 @@ struct LinkLib {
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
struct CodeGen {
//////////////////////////// Runtime State
@@ -1660,7 +1679,7 @@ struct CodeGen {
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<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 *, ConstExprValue *, buf_hash, buf_eql_buf> string_literals_table;
HashMap<const ZigType *, ConstExprValue *, type_ptr_hash, type_ptr_eql> type_info_cache;
@@ -1732,12 +1751,16 @@ struct CodeGen {
Buf triple_str;
Buf global_asm;
Buf *out_h_path;
+ Buf *out_lib_path;
Buf artifact_dir;
Buf output_file_path;
Buf o_file_output_path;
Buf *wanted_output_file_path;
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 *unreach_instruction;
@@ -1752,6 +1775,7 @@ struct CodeGen {
ZigFn *cur_fn;
ZigFn *main_fn;
ZigFn *panic_fn;
+ TldFn *panic_tld_fn;
AstNode *root_export_decl;
CacheHash cache_hash;
@@ -1760,7 +1784,8 @@ struct CodeGen {
unsigned pointer_size_bytes;
uint32_t target_os_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;
bool is_big_endian;
bool have_pub_main;
@@ -1778,13 +1803,17 @@ struct CodeGen {
bool verbose_ir;
bool verbose_llvm_ir;
bool verbose_cimport;
+ bool verbose_cc;
bool error_during_imports;
bool generate_error_name_table;
bool enable_cache;
bool enable_time_report;
bool system_linker_hack;
+ bool reported_bad_link_libc_error;
//////////////////////////// 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;
// add -framework [name] args to linker
ZigList<Buf *> darwin_frameworks;
@@ -1793,8 +1822,11 @@ struct CodeGen {
ZigList<Buf *> forbidden_libs;
ZigList<Buf *> link_objects;
ZigList<Buf *> assembly_files;
+ ZigList<CFile *> c_source_files;
ZigList<const char *> lib_dirs;
+ ZigLibCInstallation *libc;
+
size_t version_major;
size_t version_minor;
size_t version_patch;
@@ -1803,15 +1835,14 @@ struct CodeGen {
EmitFileType emit_file_type;
BuildMode build_mode;
OutType out_type;
- ZigTarget zig_target;
+ const ZigTarget *zig_target;
TargetSubsystem subsystem;
+ ValgrindSupport valgrind_support;
bool is_static;
bool strip_debug_symbols;
bool is_test_build;
bool is_single_threaded;
- bool is_native_target;
bool linker_rdynamic;
- bool no_rosegment_workaround;
bool each_lib_rpath;
bool disable_pic;
@@ -1821,31 +1852,21 @@ struct CodeGen {
Buf *test_filter;
Buf *test_name_prefix;
PackageTableEntry *root_package;
+ Buf *zig_lib_dir;
+ Buf *zig_std_dir;
const char **llvm_argv;
size_t llvm_argv_len;
const char **clang_argv;
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 {
VarLinkageInternal,
- VarLinkageExport,
+ VarLinkageExportStrong,
+ VarLinkageExportWeak,
+ VarLinkageExportLinkOnce,
VarLinkageExternal,
};
@@ -2084,6 +2105,11 @@ struct IrBasicBlock {
IrInstruction *must_be_comptime_source_instr;
};
+enum LVal {
+ LValNone,
+ LValPtr,
+};
+
// 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 are suffixed with Gen.
@@ -2106,6 +2132,7 @@ enum IrInstructionId {
IrInstructionIdUnOp,
IrInstructionIdBinOp,
IrInstructionIdLoadPtr,
+ IrInstructionIdLoadPtrGen,
IrInstructionIdStorePtr,
IrInstructionIdFieldPtr,
IrInstructionIdStructFieldPtr,
@@ -2116,6 +2143,7 @@ enum IrInstructionId {
IrInstructionIdConst,
IrInstructionIdReturn,
IrInstructionIdCast,
+ IrInstructionIdResizeSlice,
IrInstructionIdContainerInitList,
IrInstructionIdContainerInitFields,
IrInstructionIdStructInit,
@@ -2183,6 +2211,7 @@ enum IrInstructionId {
IrInstructionIdPtrCastSrc,
IrInstructionIdPtrCastGen,
IrInstructionIdBitCast,
+ IrInstructionIdBitCastGen,
IrInstructionIdWidenOrShorten,
IrInstructionIdIntToPtr,
IrInstructionIdPtrToInt,
@@ -2347,6 +2376,7 @@ struct IrInstructionUnOp {
IrUnOp op_id;
IrInstruction *value;
+ LVal lval;
};
enum IrBinOp {
@@ -2399,6 +2429,13 @@ struct IrInstructionLoadPtr {
IrInstruction *ptr;
};
+struct IrInstructionLoadPtrGen {
+ IrInstruction base;
+
+ IrInstruction *ptr;
+ LLVMValueRef tmp_ptr;
+};
+
struct IrInstructionStorePtr {
IrInstruction base;
@@ -2476,6 +2513,18 @@ struct IrInstructionReturn {
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
struct IrInstructionCast {
IrInstruction base;
@@ -2486,6 +2535,13 @@ struct IrInstructionCast {
LLVMValueRef tmp_ptr;
};
+struct IrInstructionResizeSlice {
+ IrInstruction base;
+
+ IrInstruction *operand;
+ LLVMValueRef tmp_ptr;
+};
+
struct IrInstructionContainerInitList {
IrInstruction base;
@@ -2591,6 +2647,7 @@ struct IrInstructionPtrType {
PtrLen ptr_len;
bool is_const;
bool is_volatile;
+ bool allow_zero;
};
struct IrInstructionPromiseType {
@@ -2606,6 +2663,7 @@ struct IrInstructionSliceType {
IrInstruction *child_type;
bool is_const;
bool is_volatile;
+ bool allow_zero;
};
struct IrInstructionAsm {
@@ -2994,12 +3052,14 @@ struct IrInstructionPtrCastSrc {
IrInstruction *dest_type;
IrInstruction *ptr;
+ bool safety_check_on;
};
struct IrInstructionPtrCastGen {
IrInstruction base;
IrInstruction *ptr;
+ bool safety_check_on;
};
struct IrInstructionBitCast {
@@ -3009,6 +3069,13 @@ struct IrInstructionBitCast {
IrInstruction *value;
};
+struct IrInstructionBitCastGen {
+ IrInstruction base;
+
+ IrInstruction *operand;
+ LLVMValueRef tmp_ptr;
+};
+
struct IrInstructionWidenOrShorten {
IrInstruction base;
@@ -3079,11 +3146,6 @@ struct IrInstructionTypeName {
IrInstruction *type_value;
};
-enum LVal {
- LValNone,
- LValPtr,
-};
-
struct IrInstructionDeclRef {
IrInstruction base;
diff --git a/src/analyze.cpp b/src/analyze.cpp
@@ -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) {
@@ -365,19 +365,19 @@ uint64_t type_size_bits(CodeGen *g, ZigType *type_entry) {
if (!type_has_bits(type_entry))
return 0;
- if (type_entry->id == ZigTypeIdStruct && type_entry->data.structure.layout == ContainerLayoutPacked) {
- uint64_t result = 0;
- 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);
+ if (type_entry->id == ZigTypeIdStruct) {
+ if (type_entry->data.structure.layout == ContainerLayoutPacked) {
+ uint64_t result = 0;
+ 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);
+ }
+ return result;
+ } else if (type_entry->data.structure.layout == ContainerLayoutExtern) {
+ return type_size(g, type_entry) * 8;
}
- return result;
} else if (type_entry->id == ZigTypeIdArray) {
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);
@@ -417,10 +417,25 @@ ZigType *get_promise_type(CodeGen *g, ZigType *result_type) {
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,
bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment,
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(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 = {};
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.data.pointer.child_type = child_type;
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.host_int_bytes = host_int_bytes;
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);
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);
- 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 *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);
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) {
- buf_appendf(&entry->name, "%salign(%" PRIu32 ") %s%s%s", star_str, byte_alignment,
- const_str, volatile_str, buf_ptr(&child_type->name));
+ buf_appendf(&entry->name, "%salign(%" PRIu32 ") %s%s%s%s", star_str, byte_alignment,
+ const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name));
} else if (byte_alignment == 0) {
- buf_appendf(&entry->name, "%salign(:%" PRIu32 ":%" PRIu32 ") %s%s%s", star_str,
- bit_offset_in_host, host_int_bytes, const_str, volatile_str, buf_ptr(&child_type->name));
+ buf_appendf(&entry->name, "%salign(:%" PRIu32 ":%" PRIu32 ") %s%s%s%s", star_str,
+ bit_offset_in_host, host_int_bytes, const_str, volatile_str, allow_zero_str,
+ buf_ptr(&child_type->name));
} else {
- buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s", star_str, byte_alignment,
- bit_offset_in_host, host_int_bytes, const_str, volatile_str, buf_ptr(&child_type->name));
+ 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, allow_zero_str,
+ buf_ptr(&child_type->name));
}
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);
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,
PtrLenSingle, 0, 0, host_int_bytes);
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.bit_offset_in_host = bit_offset_in_host;
entry->data.pointer.host_int_bytes = host_int_bytes;
+ entry->data.pointer.allow_zero = allow_zero;
if (parent_pointer) {
*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;
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,
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;
assert(child_ptr_type->id == ZigTypeIdPointer);
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 *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)) {
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);
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;
}
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;
return ir_eval_const_value(g, scope, node, type_entry,
&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) {
@@ -1415,7 +1444,10 @@ static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf **
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) {
case ZigTypeIdInvalid:
zig_unreachable();
@@ -1432,32 +1464,79 @@ static bool type_allowed_in_packed_struct(ZigType *type_entry) {
case ZigTypeIdArgTuple:
case ZigTypeIdOpaque:
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 ZigTypeIdBool:
case ZigTypeIdInt:
case ZigTypeIdFloat:
case ZigTypeIdPointer:
- case ZigTypeIdArray:
case ZigTypeIdFn:
case ZigTypeIdVector:
- return true;
+ return ErrorNone;
+ case ZigTypeIdArray: {
+ ZigType *elem_type = type_entry->data.array.child_type;
+ if ((err = emit_error_unless_type_allowed_in_packed_struct(g, elem_type, source_node)))
+ return err;
+ if (type_size(g, type_entry) * 8 == type_size_bits(g, type_entry))
+ return ErrorNone;
+ add_node_error(g, source_node,
+ buf_sprintf("array of '%s' not allowed in packed struct due to padding bits",
+ buf_ptr(&elem_type->name)));
+ return ErrorSemanticAnalyzeFail;
+ }
case ZigTypeIdStruct:
- return type_entry->data.structure.layout == ContainerLayoutPacked;
+ 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:
- return type_entry->data.unionation.layout == ContainerLayoutPacked;
+ 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:
- {
- ZigType *child_type = type_entry->data.maybe.child_type;
- return type_is_codegen_pointer(child_type);
+ 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:
- return type_entry->data.enumeration.decl_node->data.container_decl.init_arg_expr != nullptr;
+ 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;
+ }
}
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) {
case ZigTypeIdInvalid:
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) {
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'",
calling_convention_name(fn_type_id.cc)));
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;
if (packed) {
- if (!type_allowed_in_packed_struct(field_type)) {
- AstNode *field_source_node = decl_node->data.container_decl.fields.at(i);
- add_node_error(g, field_source_node,
- buf_sprintf("packed structs cannot contain fields of type '%s'",
- buf_ptr(&field_type->name)));
+ AstNode *field_source_node = decl_node->data.container_decl.fields.at(i);
+ if ((err = emit_error_unless_type_allowed_in_packed_struct(g, field_type, field_source_node))) {
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
break;
}
@@ -2650,6 +2726,13 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
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)) {
case ReqCompTimeYes:
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 ||
enum_type_node != nullptr;
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;
bool create_enum_type = decl_node->data.container_decl.auto_enum || (enum_type_node == nullptr && want_safety);
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;
+ 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)) {
case ReqCompTimeInvalid:
union_type->data.unionation.is_invalid = true;
@@ -3182,36 +3272,19 @@ static bool scope_is_root_decls(Scope *scope) {
zig_unreachable();
}
-static void wrong_panic_prototype(CodeGen *g, AstNode *proto_node, ZigType *fn_type) {
- add_node_error(g, proto_node,
- buf_sprintf("expected 'fn([]const u8, ?*builtin.StackTrace) noreturn', found '%s'",
- buf_ptr(&fn_type->name)));
-}
-
-static void typecheck_panic_fn(CodeGen *g, ZigFn *panic_fn) {
- AstNode *proto_node = panic_fn->proto_node;
- assert(proto_node->type == NodeTypeFnProto);
- ZigType *fn_type = panic_fn->type_entry;
- 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);
- }
+void typecheck_panic_fn(CodeGen *g, TldFn *tld_fn, ZigFn *panic_fn) {
+ ConstExprValue *panic_fn_type_val = get_builtin_value(g, "PanicFn");
+ assert(panic_fn_type_val != nullptr);
+ assert(panic_fn_type_val->type->id == ZigTypeIdMetaType);
+ ZigType *panic_fn_type = panic_fn_type_val->data.x_type;
- ZigType *optional_ptr_to_stack_trace_type = get_optional_type(g, get_ptr_to_stack_trace_type(g));
- if (fn_type_id->param_info[1].type != optional_ptr_to_stack_trace_type) {
- return wrong_panic_prototype(g, proto_node, fn_type);
- }
+ AstNode *fake_decl = allocate<AstNode>(1);
+ *fake_decl = *panic_fn->proto_node;
+ fake_decl->type = NodeTypeSymbol;
+ fake_decl->data.symbol_expr.symbol = &panic_fn->symbol_name;
- 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);
- }
+ // call this for the side effects of casting to panic_fn_type
+ analyze_const_value(g, tld_fn->base.parent_scope, fake_decl, panic_fn_type, nullptr);
}
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->subsystem = TargetSubsystemConsole;
} else if (buf_eql_str(symbol_name, "WinMain") &&
- g->zig_target.os == OsWindows)
+ g->zig_target->os == OsWindows)
{
g->have_winmain = true;
g->subsystem = TargetSubsystemWindows;
} else if (buf_eql_str(symbol_name, "WinMainCRTStartup") &&
- g->zig_target.os == OsWindows)
+ g->zig_target->os == OsWindows)
{
g->have_winmain_crt_startup = true;
} else if (buf_eql_str(symbol_name, "DllMainCRTStartup") &&
- g->zig_target.os == OsWindows)
+ g->zig_target->os == OsWindows)
{
g->have_dllmain_crt_startup = true;
}
@@ -3306,18 +3379,18 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
if (!fn_table_entry->type_entry->data.fn.is_generic) {
if (fn_def_node)
g->fn_defs.append(fn_table_entry);
+ }
- if (scope_is_root_decls(tld_fn->base.parent_scope) &&
- (import == g->root_import || import->package == g->panic_package))
+ if (scope_is_root_decls(tld_fn->base.parent_scope) &&
+ (import == g->root_import || import->package == g->panic_package))
+ {
+ if (g->have_pub_main && buf_eql_str(&fn_table_entry->symbol_name, "main")) {
+ g->main_fn = fn_table_entry;
+ } else if ((import->package == g->panic_package || g->have_pub_panic) &&
+ buf_eql_str(&fn_table_entry->symbol_name, "panic"))
{
- if (g->have_pub_main && buf_eql_str(&fn_table_entry->symbol_name, "main")) {
- g->main_fn = fn_table_entry;
- } else if ((import->package == g->panic_package || g->have_pub_panic) &&
- buf_eql_str(&fn_table_entry->symbol_name, "panic"))
- {
- g->panic_fn = fn_table_entry;
- typecheck_panic_fn(g, fn_table_entry);
- }
+ g->panic_fn = fn_table_entry;
+ g->panic_tld_fn = tld_fn;
}
}
} 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) {
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) {
- AstNode *other_source_node = entry->value;
+ AstNode *other_source_node = entry->value->source_node;
ErrorMsg *msg = add_node_error(g, tld->source_node,
buf_sprintf("exported symbol collision: '%s'", buf_ptr(tld->name)));
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;
if (is_export) {
- linkage = VarLinkageExport;
+ linkage = VarLinkageExportStrong;
} else if (is_extern) {
linkage = VarLinkageExternal;
} else {
@@ -4041,7 +4114,9 @@ ZigType *get_src_ptr_type(ZigType *type) {
if (type->id == ZigTypeIdFn) return type;
if (type->id == ZigTypeIdPromise) return type;
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 == ZigTypeIdPromise) return type->data.maybe.child_type;
}
@@ -4055,6 +4130,10 @@ ZigType *get_codegen_ptr_type(ZigType *type) {
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) {
return get_codegen_ptr_type(type) == type;
}
@@ -4572,185 +4651,6 @@ bool handle_is_ptr(ZigType *type_entry) {
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) {
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.
OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) {
assert(type_entry != nullptr);
+
+ if (type_entry->one_possible_value != OnePossibleValueInvalid)
+ return type_entry->one_possible_value;
+
Error err;
if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown)))
return OnePossibleValueInvalid;
@@ -5276,8 +5180,14 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) {
case ZigTypeIdInt:
case ZigTypeIdVector:
return type_has_bits(type_entry) ? OnePossibleValueNo : OnePossibleValueYes;
- case ZigTypeIdPointer:
- return type_has_one_possible_value(g, type_entry->data.pointer.child_type);
+ case ZigTypeIdPointer: {
+ 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:
if (type_entry->data.unionation.src_field_count > 1)
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) {
- switch (const_val->data.x_array.special) {
+static void render_const_val_array(CodeGen *g, Buf *buf, Buf *type_name, ConstExprValue *const_val, uint64_t start, uint64_t len) {
+ ConstArrayValue *array = &const_val->data.x_array;
+ switch (array->special) {
case ConstArraySpecialUndef:
buf_append_str(buf, "undefined");
return;
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, '"');
- for (size_t i = 0; i < buf_len(array_buf); i += 1) {
- uint8_t c = buf_ptr(array_buf)[i];
+ for (size_t i = 0; i < len; i += 1) {
+ uint8_t c = base[i];
if (c == '"') {
buf_append_str(buf, "\\\"");
} else {
@@ -6030,12 +5944,13 @@ static void render_const_val_array(CodeGen *g, Buf *buf, ConstExprValue *const_v
return;
}
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) {
- if (i != 0)
- buf_appendf(buf, ",");
- ConstExprValue *child_value = &const_val->data.x_array.data.s_none.elements[i];
- render_const_value(g, buf, child_value);
+ if (i != 0) buf_appendf(buf, ",");
+ render_const_value(g, buf, &base[i]);
}
buf_appendf(buf, "}");
return;
@@ -6124,10 +6039,16 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
}
case ZigTypeIdPointer:
return render_const_val_ptr(g, buf, const_val, type_entry);
- case ZigTypeIdVector:
- return render_const_val_array(g, buf, const_val, type_entry->data.vector.len);
- case ZigTypeIdArray:
- return render_const_val_array(g, buf, const_val, type_entry->data.array.len);
+ case ZigTypeIdArray: {
+ uint64_t len = type_entry->data.array.len;
+ render_const_val_array(g, buf, &type_entry->name, const_val, 0, 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:
{
buf_appendf(buf, "null");
@@ -6169,7 +6090,24 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
}
case ZigTypeIdStruct:
{
- buf_appendf(buf, "(struct %s constant)", buf_ptr(&type_entry->name));
+ 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));
+ }
return;
}
case ZigTypeIdEnum:
@@ -6193,8 +6131,8 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
}
case ZigTypeIdUnion:
{
- uint64_t tag = bigint_as_unsigned(&const_val->data.x_union.tag);
- TypeUnionField *field = &type_entry->data.unionation.fields[tag];
+ const BigInt *tag = &const_val->data.x_union.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));
render_const_value(g, buf, const_val->data.x_union.payload);
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.is_const ? (uint32_t)2749109194 : (uint32_t)4047371087) +
(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.bit_offset_in_host) ^ (uint32_t)2639019452) +
(((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.is_const == b.data.pointer.is_const &&
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.bit_offset_in_host == b.data.pointer.bit_offset_in_host &&
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)
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) {
LinkLib *existing_lib = g->link_libs_list.at(i);
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;
}
+
+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;
+}
diff --git a/src/analyze.hpp b/src/analyze.hpp
@@ -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_test_fn_type(CodeGen *g);
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_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);
@@ -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);
bool type_is_c_abi_int(CodeGen *g, ZigType *ty);
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);
@@ -225,14 +226,10 @@ enum ReqCompTime {
};
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);
Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node,
ConstExprValue *const_val, ZigType *wanted_type);
+void typecheck_panic_fn(CodeGen *g, TldFn *tld_fn, ZigFn *panic_fn);
#endif
diff --git a/src/ast_render.cpp b/src/ast_render.cpp
@@ -136,13 +136,19 @@ static const char *thread_local_string(Token *tok) {
return (tok == nullptr) ? "" : "threadlocal ";
}
-const char *container_string(ContainerKind kind) {
- switch (kind) {
- case ContainerKindEnum: return "enum";
- case ContainerKindStruct: return "struct";
- case ContainerKindUnion: return "union";
+static const char *token_to_ptr_len_str(Token *tok) {
+ assert(tok != nullptr);
+ switch (tok->id) {
+ case TokenIdStar:
+ case TokenIdStarStar:
+ return "*";
+ case TokenIdBracketStarBracket:
+ return "[*]";
+ case TokenIdBracketStarCBracket:
+ return "[*c]";
+ default:
+ zig_unreachable();
}
- zig_unreachable();
}
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:
{
if (!grouped) fprintf(ar->f, "(");
- const char *star = "[*]";
- if (node->data.pointer_type.star_token != nullptr &&
- (node->data.pointer_type.star_token->id == TokenIdStar || node->data.pointer_type.star_token->id == TokenIdStarStar))
- {
- star = "*";
- }
- fprintf(ar->f, "%s", star);
+ const char *ptr_len_str = token_to_ptr_len_str(node->data.pointer_type.star_token);
+ fprintf(ar->f, "%s", ptr_len_str);
if (node->data.pointer_type.align_expr != nullptr) {
fprintf(ar->f, "align(");
render_node_grouped(ar, node->data.pointer_type.align_expr);
diff --git a/src/ast_render.hpp b/src/ast_render.hpp
@@ -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);
-const char *container_string(ContainerKind kind);
-
#endif
-
diff --git a/src/bigint.cpp b/src/bigint.cpp
@@ -1665,7 +1665,6 @@ int64_t bigint_as_signed(const BigInt *bigint) {
return 0;
} else if (bigint->digit_count == 1) {
if (bigint->is_negative) {
- // TODO this code path is untested
if (bigint->data.digit <= 9223372036854775808ULL) {
return (-((int64_t)(bigint->data.digit - 1))) - 1;
} else {
diff --git a/src/buffer.hpp b/src/buffer.hpp
@@ -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) {
assert(buf->list.length);
- if (buf_len(buf) != mem_len)
- return false;
- return memcmp(buf_ptr(buf), mem, mem_len) == 0;
+ return mem_eql_mem(buf_ptr(buf), buf_len(buf), mem, mem_len);
}
static inline bool buf_eql_str(Buf *buf, const char *str) {
diff --git a/src/cache_hash.cpp b/src/cache_hash.cpp
@@ -414,6 +414,39 @@ Error cache_add_file(CacheHash *ch, Buf *path) {
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) {
Error err;
Buf contents = BUF_INIT;
@@ -464,3 +497,4 @@ void cache_release(CacheHash *ch) {
os_file_close(ch->manifest_file);
}
+
diff --git a/src/cache_hash.hpp b/src/cache_hash.hpp
@@ -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
// that is depended on, and then finish with cache_final.
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.
// Also the file path argument must be already resolved.
diff --git a/src/codegen.cpp b/src/codegen.cpp
@@ -29,9 +29,9 @@ static void init_darwin_native(CodeGen *g) {
// Allow conflicts among OSX and iOS, but choose the default platform.
if (osx_target && ios_target) {
- if (g->zig_target.arch.arch == ZigLLVM_arm ||
- g->zig_target.arch.arch == ZigLLVM_aarch64 ||
- g->zig_target.arch.arch == ZigLLVM_thumb)
+ if (g->zig_target->arch == ZigLLVM_arm ||
+ g->zig_target->arch == ZigLLVM_aarch64 ||
+ g->zig_target->arch == ZigLLVM_thumb)
{
osx_target = nullptr;
} else {
@@ -43,7 +43,7 @@ static void init_darwin_native(CodeGen *g) {
g->mmacosx_version_min = buf_create_from_str(osx_target);
} else if (ios_target) {
g->mios_version_min = buf_create_from_str(ios_target);
- } else if (g->zig_target.os != OsIOS) {
+ } else if (g->zig_target->os != OsIOS) {
g->mmacosx_version_min = buf_create_from_str("10.10");
}
}
@@ -88,13 +88,15 @@ static const char *symbols_that_llvm_depends_on[] = {
};
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)
{
CodeGen *g = allocate<CodeGen>(1);
codegen_add_time_event(g, "Initialize");
+ g->libc = libc;
g->zig_lib_dir = zig_lib_dir;
+ g->zig_target = target;
if (override_std_dir == nullptr) {
g->zig_std_dir = buf_alloc();
@@ -149,43 +151,19 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
g->zig_std_special_dir = buf_alloc();
os_path_join(g->zig_std_dir, buf_sprintf("special"), g->zig_std_special_dir);
- if (target) {
- // cross compiling, so we can't rely on all the configured stuff since
- // that's for native compilation
- g->zig_target = *target;
- resolve_target_object_format(&g->zig_target);
- g->dynamic_linker = nullptr;
- g->libc_lib_dir = nullptr;
- g->libc_static_lib_dir = nullptr;
- g->libc_include_dir = nullptr;
- g->msvc_lib_dir = nullptr;
- g->kernel32_lib_dir = nullptr;
+ assert(target != nullptr);
+ if (!target->is_native) {
g->each_lib_rpath = false;
} else {
- // native compilation, we can rely on the configuration stuff
- g->is_native_target = true;
- get_native_target(&g->zig_target);
- g->dynamic_linker = nullptr; // find it at runtime
- g->libc_lib_dir = nullptr; // find it at runtime
- g->libc_static_lib_dir = nullptr; // find it at runtime
- g->libc_include_dir = nullptr; // find it at runtime
- g->msvc_lib_dir = nullptr; // find it at runtime
- g->kernel32_lib_dir = nullptr; // find it at runtime
g->each_lib_rpath = true;
- if (g->zig_target.os == OsMacOSX ||
- g->zig_target.os == OsIOS)
- {
+ if (target_is_darwin(g->zig_target)) {
init_darwin_native(g);
}
}
- // On Darwin/MacOS/iOS, we always link libSystem which contains libc.
- if (g->zig_target.os == OsMacOSX ||
- g->zig_target.os == OsIOS ||
- g->zig_target.os == OsFreeBSD)
- {
+ if (target_requires_libc(g->zig_target)) {
g->libc_link_lib = create_link_lib(buf_create_from_str("c"));
g->link_libs_list.append(g->libc_link_lib);
}
@@ -197,6 +175,10 @@ void codegen_set_output_h_path(CodeGen *g, Buf *h_path) {
g->out_h_path = h_path;
}
+void codegen_set_output_lib_path(CodeGen *g, Buf *lib_path) {
+ g->out_lib_path = lib_path;
+}
+
void codegen_set_output_path(CodeGen *g, Buf *path) {
g->wanted_output_file_path = path;
}
@@ -253,30 +235,6 @@ void codegen_set_out_name(CodeGen *g, Buf *out_name) {
g->root_out_name = out_name;
}
-void codegen_set_libc_lib_dir(CodeGen *g, Buf *libc_lib_dir) {
- g->libc_lib_dir = libc_lib_dir;
-}
-
-void codegen_set_libc_static_lib_dir(CodeGen *g, Buf *libc_static_lib_dir) {
- g->libc_static_lib_dir = libc_static_lib_dir;
-}
-
-void codegen_set_libc_include_dir(CodeGen *g, Buf *libc_include_dir) {
- g->libc_include_dir = libc_include_dir;
-}
-
-void codegen_set_msvc_lib_dir(CodeGen *g, Buf *msvc_lib_dir) {
- g->msvc_lib_dir = msvc_lib_dir;
-}
-
-void codegen_set_kernel32_lib_dir(CodeGen *g, Buf *kernel32_lib_dir) {
- g->kernel32_lib_dir = kernel32_lib_dir;
-}
-
-void codegen_set_dynamic_linker(CodeGen *g, Buf *dynamic_linker) {
- g->dynamic_linker = dynamic_linker;
-}
-
void codegen_add_lib_dir(CodeGen *g, const char *dir) {
g->lib_dirs.append(dir);
}
@@ -389,11 +347,11 @@ static LLVMCallConv get_llvm_cc(CodeGen *g, CallingConvention cc) {
case CallingConventionC: return LLVMCCallConv;
case CallingConventionCold:
// cold calling convention only works on x86.
- if (g->zig_target.arch.arch == ZigLLVM_x86 ||
- g->zig_target.arch.arch == ZigLLVM_x86_64)
+ if (g->zig_target->arch == ZigLLVM_x86 ||
+ g->zig_target->arch == ZigLLVM_x86_64)
{
// cold calling convention is not supported on windows
- if (g->zig_target.os == OsWindows) {
+ if (g->zig_target->os == OsWindows) {
return LLVMCCallConv;
} else {
return LLVMColdCallConv;
@@ -406,7 +364,7 @@ static LLVMCallConv get_llvm_cc(CodeGen *g, CallingConvention cc) {
zig_unreachable();
case CallingConventionStdcall:
// stdcall calling convention only works on x86.
- if (g->zig_target.arch.arch == ZigLLVM_x86) {
+ if (g->zig_target->arch == ZigLLVM_x86) {
return LLVMX86StdcallCallConv;
} else {
return LLVMCCallConv;
@@ -418,7 +376,7 @@ static LLVMCallConv get_llvm_cc(CodeGen *g, CallingConvention cc) {
}
static void add_uwtable_attr(CodeGen *g, LLVMValueRef fn_val) {
- if (g->zig_target.os == OsWindows) {
+ if (g->zig_target->os == OsWindows) {
addLLVMFnAttr(fn_val, "uwtable");
}
}
@@ -454,13 +412,13 @@ static uint32_t get_err_ret_trace_arg_index(CodeGen *g, ZigFn *fn_table_entry) {
}
static void maybe_export_dll(CodeGen *g, LLVMValueRef global_value, GlobalLinkageId linkage) {
- if (linkage != GlobalLinkageIdInternal && g->zig_target.os == OsWindows) {
+ if (linkage != GlobalLinkageIdInternal && g->zig_target->os == OsWindows) {
LLVMSetDLLStorageClass(global_value, LLVMDLLExportStorageClass);
}
}
static void maybe_import_dll(CodeGen *g, LLVMValueRef global_value, GlobalLinkageId linkage) {
- if (linkage != GlobalLinkageIdInternal && g->zig_target.os == OsWindows) {
+ if (linkage != GlobalLinkageIdInternal && g->zig_target->os == OsWindows) {
// TODO come up with a good explanation/understanding for why we never do
// DLLImportStorageClass. Empirically it only causes problems. But let's have
// this documented and then clean up the code accordingly.
@@ -505,7 +463,7 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
bool external_linkage = linkage != GlobalLinkageIdInternal;
CallingConvention cc = fn_table_entry->type_entry->data.fn.fn_type_id.cc;
if (cc == CallingConventionStdcall && external_linkage &&
- g->zig_target.arch.arch == ZigLLVM_x86)
+ g->zig_target->arch == ZigLLVM_x86)
{
// prevent llvm name mangling
symbol_name = buf_sprintf("\x01_%s", buf_ptr(symbol_name));
@@ -520,10 +478,23 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
fn_table_entry->llvm_value = LLVMConstBitCast(existing_llvm_fn, LLVMPointerType(fn_llvm_type, 0));
return fn_table_entry->llvm_value;
} else {
- fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);
+ auto entry = g->exported_symbol_names.maybe_get(symbol_name);
+ if (entry == nullptr) {
+ fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);
+ } else {
+ assert(entry->value->id == TldIdFn);
+ TldFn *tld_fn = reinterpret_cast<TldFn *>(entry->value);
+ tld_fn->fn_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name),
+ tld_fn->fn_entry->type_entry->data.fn.raw_type_ref);
+ fn_table_entry->llvm_value = LLVMConstBitCast(tld_fn->fn_entry->llvm_value,
+ LLVMPointerType(fn_llvm_type, 0));
+ return fn_table_entry->llvm_value;
+ }
}
} else {
- fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);
+ if (fn_table_entry->llvm_value == nullptr) {
+ fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);
+ }
for (size_t i = 1; i < fn_table_entry->export_list.length; i += 1) {
FnExport *fn_export = &fn_table_entry->export_list.items[i];
@@ -617,9 +588,10 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
unsigned init_gen_i = 0;
if (!type_has_bits(return_type)) {
// nothing to do
- } else if (type_is_codegen_pointer(return_type)) {
+ } else if (type_is_nonnull_ptr(return_type)) {
addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull");
} else if (want_first_arg_sret(g, &fn_type->data.fn.fn_type_id)) {
+ // Sret pointers must not be address 0
addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull");
addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret");
if (cc_want_sret_attr(cc)) {
@@ -637,6 +609,8 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);
if (err_ret_trace_arg_index != UINT32_MAX) {
+ // Error return trace memory is in the stack, which is impossible to be at address 0
+ // on any architecture.
addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)err_ret_trace_arg_index, "nonnull");
}
@@ -950,6 +924,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
return buf_create_from_str("invalid enum value");
case PanicMsgIdFloatToInt:
return buf_create_from_str("integer part of floating point value out of bounds");
+ case PanicMsgIdPtrCastNull:
+ return buf_create_from_str("cast causes pointer to be null");
}
zig_unreachable();
}
@@ -1244,6 +1220,8 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {
LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
addLLVMFnAttr(fn_val, "nounwind");
add_uwtable_attr(g, fn_val);
+ // Error return trace memory is in the stack, which is impossible to be at address 0
+ // on any architecture.
addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
if (g->build_mode == BuildModeDebug) {
ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
@@ -1318,9 +1296,13 @@ static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) {
LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
addLLVMFnAttr(fn_val, "nounwind");
add_uwtable_attr(g, fn_val);
+ // Error return trace memory is in the stack, which is impossible to be at address 0
+ // on any architecture.
addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
addLLVMArgAttr(fn_val, (unsigned)0, "noalias");
addLLVMArgAttr(fn_val, (unsigned)0, "writeonly");
+ // Error return trace memory is in the stack, which is impossible to be at address 0
+ // on any architecture.
addLLVMArgAttr(fn_val, (unsigned)1, "nonnull");
addLLVMArgAttr(fn_val, (unsigned)1, "noalias");
addLLVMArgAttr(fn_val, (unsigned)1, "readonly");
@@ -1448,6 +1430,8 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
addLLVMFnAttr(fn_val, "nounwind");
add_uwtable_attr(g, fn_val);
+ // Error return trace memory is in the stack, which is impossible to be at address 0
+ // on any architecture.
addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
if (g->build_mode == BuildModeDebug) {
ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
@@ -2049,7 +2033,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
case FnWalkIdAttrs: {
ZigType *ptr_type = get_codegen_ptr_type(ty);
if (ptr_type != nullptr) {
- if (ty->id != ZigTypeIdOptional) {
+ if (type_is_nonnull_ptr(ty)) {
addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull");
}
if (ptr_type->data.pointer.is_const) {
@@ -2093,6 +2077,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
assert(handle_is_ptr(ty));
switch (fn_walk->id) {
case FnWalkIdAttrs:
+ // arrays passed to C ABI functions may not be at address 0
addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull");
addLLVMArgAttrInt(llvm_fn, fn_walk->data.attrs.gen_i, "align", get_abi_alignment(g, ty));
fn_walk->data.attrs.gen_i += 1;
@@ -2123,7 +2108,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
return true;
}
- 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, ty);
size_t ty_size = type_size(g, ty);
if (abi_class == X64CABIClass_MEMORY) {
@@ -2132,6 +2117,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
case FnWalkIdAttrs:
addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "byval");
addLLVMArgAttrInt(llvm_fn, fn_walk->data.attrs.gen_i, "align", get_abi_alignment(g, ty));
+ // Byvalue parameters must not have address 0
addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull");
fn_walk->data.attrs.gen_i += 1;
break;
@@ -2264,7 +2250,10 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {
if ((param_type->id == ZigTypeIdPointer && param_type->data.pointer.is_const) || is_byval) {
addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "readonly");
}
- if (param_type->id == ZigTypeIdPointer) {
+ if (get_codegen_ptr_type(param_type) != nullptr) {
+ addLLVMArgAttrInt(llvm_fn, (unsigned)gen_index, "align", get_ptr_align(g, param_type));
+ }
+ if (type_is_nonnull_ptr(param_type)) {
addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "nonnull");
}
break;
@@ -2657,7 +2646,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
(op1->value.type->id == ZigTypeIdErrorSet && op2->value.type->id == ZigTypeIdErrorSet) ||
(op1->value.type->id == ZigTypeIdPointer &&
(op_id == IrBinOpAdd || op_id == IrBinOpSub) &&
- op1->value.type->data.pointer.ptr_len == PtrLenUnknown)
+ op1->value.type->data.pointer.ptr_len != PtrLenSingle)
);
ZigType *operand_type = op1->value.type;
ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type;
@@ -2716,7 +2705,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
AddSubMulMul;
if (scalar_type->id == ZigTypeIdPointer) {
- assert(scalar_type->data.pointer.ptr_len == PtrLenUnknown);
+ assert(scalar_type->data.pointer.ptr_len != PtrLenSingle);
LLVMValueRef subscript_value;
if (operand_type->id == ZigTypeIdVector)
zig_panic("TODO: Implement vector operations on pointers.");
@@ -2863,6 +2852,76 @@ static void add_error_range_check(CodeGen *g, ZigType *err_set_type, ZigType *in
}
}
+static LLVMValueRef ir_render_resize_slice(CodeGen *g, IrExecutable *executable,
+ IrInstructionResizeSlice *instruction)
+{
+ ZigType *actual_type = instruction->operand->value.type;
+ ZigType *wanted_type = instruction->base.value.type;
+ LLVMValueRef expr_val = ir_llvm_value(g, instruction->operand);
+ assert(expr_val);
+
+ assert(instruction->tmp_ptr);
+ assert(wanted_type->id == ZigTypeIdStruct);
+ assert(wanted_type->data.structure.is_slice);
+ assert(actual_type->id == ZigTypeIdStruct);
+ assert(actual_type->data.structure.is_slice);
+
+ ZigType *actual_pointer_type = actual_type->data.structure.fields[0].type_entry;
+ ZigType *actual_child_type = actual_pointer_type->data.pointer.child_type;
+ ZigType *wanted_pointer_type = wanted_type->data.structure.fields[0].type_entry;
+ ZigType *wanted_child_type = wanted_pointer_type->data.pointer.child_type;
+
+
+ size_t actual_ptr_index = actual_type->data.structure.fields[slice_ptr_index].gen_index;
+ size_t actual_len_index = actual_type->data.structure.fields[slice_len_index].gen_index;
+ size_t wanted_ptr_index = wanted_type->data.structure.fields[slice_ptr_index].gen_index;
+ size_t wanted_len_index = wanted_type->data.structure.fields[slice_len_index].gen_index;
+
+ LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP(g->builder, expr_val, (unsigned)actual_ptr_index, "");
+ LLVMValueRef src_ptr = gen_load_untyped(g, src_ptr_ptr, 0, false, "");
+ LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, src_ptr,
+ wanted_type->data.structure.fields[0].type_entry->type_ref, "");
+ LLVMValueRef dest_ptr_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr,
+ (unsigned)wanted_ptr_index, "");
+ gen_store_untyped(g, src_ptr_casted, dest_ptr_ptr, 0, false);
+
+ LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, expr_val, (unsigned)actual_len_index, "");
+ LLVMValueRef src_len = gen_load_untyped(g, src_len_ptr, 0, false, "");
+ uint64_t src_size = type_size(g, actual_child_type);
+ uint64_t dest_size = type_size(g, wanted_child_type);
+
+ LLVMValueRef new_len;
+ if (dest_size == 1) {
+ LLVMValueRef src_size_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, src_size, false);
+ new_len = LLVMBuildMul(g->builder, src_len, src_size_val, "");
+ } else if (src_size == 1) {
+ LLVMValueRef dest_size_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, dest_size, false);
+ if (ir_want_runtime_safety(g, &instruction->base)) {
+ LLVMValueRef remainder_val = LLVMBuildURem(g->builder, src_len, dest_size_val, "");
+ LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_usize->type_ref);
+ LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, "");
+ LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "SliceWidenOk");
+ LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "SliceWidenFail");
+ LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
+
+ LLVMPositionBuilderAtEnd(g->builder, fail_block);
+ gen_safety_crash(g, PanicMsgIdSliceWidenRemainder);
+
+ LLVMPositionBuilderAtEnd(g->builder, ok_block);
+ }
+ new_len = LLVMBuildExactUDiv(g->builder, src_len, dest_size_val, "");
+ } else {
+ zig_unreachable();
+ }
+
+ LLVMValueRef dest_len_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr,
+ (unsigned)wanted_len_index, "");
+ gen_store_untyped(g, new_len, dest_len_ptr, 0, false);
+
+
+ return instruction->tmp_ptr;
+}
+
static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
IrInstructionCast *cast_instruction)
{
@@ -2877,69 +2936,6 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
zig_unreachable();
case CastOpNoop:
return expr_val;
- case CastOpResizeSlice:
- {
- assert(cast_instruction->tmp_ptr);
- assert(wanted_type->id == ZigTypeIdStruct);
- assert(wanted_type->data.structure.is_slice);
- assert(actual_type->id == ZigTypeIdStruct);
- assert(actual_type->data.structure.is_slice);
-
- ZigType *actual_pointer_type = actual_type->data.structure.fields[0].type_entry;
- ZigType *actual_child_type = actual_pointer_type->data.pointer.child_type;
- ZigType *wanted_pointer_type = wanted_type->data.structure.fields[0].type_entry;
- ZigType *wanted_child_type = wanted_pointer_type->data.pointer.child_type;
-
-
- size_t actual_ptr_index = actual_type->data.structure.fields[slice_ptr_index].gen_index;
- size_t actual_len_index = actual_type->data.structure.fields[slice_len_index].gen_index;
- size_t wanted_ptr_index = wanted_type->data.structure.fields[slice_ptr_index].gen_index;
- size_t wanted_len_index = wanted_type->data.structure.fields[slice_len_index].gen_index;
-
- LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP(g->builder, expr_val, (unsigned)actual_ptr_index, "");
- LLVMValueRef src_ptr = gen_load_untyped(g, src_ptr_ptr, 0, false, "");
- LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, src_ptr,
- wanted_type->data.structure.fields[0].type_entry->type_ref, "");
- LLVMValueRef dest_ptr_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr,
- (unsigned)wanted_ptr_index, "");
- gen_store_untyped(g, src_ptr_casted, dest_ptr_ptr, 0, false);
-
- LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, expr_val, (unsigned)actual_len_index, "");
- LLVMValueRef src_len = gen_load_untyped(g, src_len_ptr, 0, false, "");
- uint64_t src_size = type_size(g, actual_child_type);
- uint64_t dest_size = type_size(g, wanted_child_type);
-
- LLVMValueRef new_len;
- if (dest_size == 1) {
- LLVMValueRef src_size_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, src_size, false);
- new_len = LLVMBuildMul(g->builder, src_len, src_size_val, "");
- } else if (src_size == 1) {
- LLVMValueRef dest_size_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, dest_size, false);
- if (ir_want_runtime_safety(g, &cast_instruction->base)) {
- LLVMValueRef remainder_val = LLVMBuildURem(g->builder, src_len, dest_size_val, "");
- LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_usize->type_ref);
- LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, "");
- LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "SliceWidenOk");
- LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "SliceWidenFail");
- LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
-
- LLVMPositionBuilderAtEnd(g->builder, fail_block);
- gen_safety_crash(g, PanicMsgIdSliceWidenRemainder);
-
- LLVMPositionBuilderAtEnd(g->builder, ok_block);
- }
- new_len = LLVMBuildExactUDiv(g->builder, src_len, dest_size_val, "");
- } else {
- zig_unreachable();
- }
-
- LLVMValueRef dest_len_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr,
- (unsigned)wanted_len_index, "");
- gen_store_untyped(g, new_len, dest_len_ptr, 0, false);
-
-
- return cast_instruction->tmp_ptr;
- }
case CastOpIntToFloat:
assert(actual_type->id == ZigTypeIdInt);
if (actual_type->data.integral.is_signed) {
@@ -3028,15 +3024,51 @@ static LLVMValueRef ir_render_ptr_cast(CodeGen *g, IrExecutable *executable,
return nullptr;
}
LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
- return LLVMBuildBitCast(g->builder, ptr, wanted_type->type_ref, "");
+ LLVMValueRef result_ptr = LLVMBuildBitCast(g->builder, ptr, wanted_type->type_ref, "");
+ bool want_safety_check = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base);
+ if (!want_safety_check || ptr_allows_addr_zero(wanted_type))
+ return result_ptr;
+
+ LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(result_ptr));
+ LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntNE, result_ptr, zero, "");
+ LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "PtrCastFail");
+ LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "PtrCastOk");
+ LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
+
+ LLVMPositionBuilderAtEnd(g->builder, fail_block);
+ gen_safety_crash(g, PanicMsgIdPtrCastNull);
+
+ LLVMPositionBuilderAtEnd(g->builder, ok_block);
+ return result_ptr;
}
static LLVMValueRef ir_render_bit_cast(CodeGen *g, IrExecutable *executable,
- IrInstructionBitCast *instruction)
+ IrInstructionBitCastGen *instruction)
{
ZigType *wanted_type = instruction->base.value.type;
- LLVMValueRef value = ir_llvm_value(g, instruction->value);
- return LLVMBuildBitCast(g->builder, value, wanted_type->type_ref, "");
+ ZigType *actual_type = instruction->operand->value.type;
+ LLVMValueRef value = ir_llvm_value(g, instruction->operand);
+
+ bool wanted_is_ptr = handle_is_ptr(wanted_type);
+ bool actual_is_ptr = handle_is_ptr(actual_type);
+ if (wanted_is_ptr == actual_is_ptr) {
+ // We either bitcast the value directly or bitcast the pointer which does a pointer cast
+ LLVMTypeRef wanted_type_ref = wanted_is_ptr ?
+ LLVMPointerType(wanted_type->type_ref, 0) : wanted_type->type_ref;
+ return LLVMBuildBitCast(g->builder, value, wanted_type_ref, "");
+ } else if (actual_is_ptr) {
+ LLVMTypeRef wanted_ptr_type_ref = LLVMPointerType(wanted_type->type_ref, 0);
+ LLVMValueRef bitcasted_ptr = LLVMBuildBitCast(g->builder, value, wanted_ptr_type_ref, "");
+ uint32_t alignment = get_abi_alignment(g, actual_type);
+ return gen_load_untyped(g, bitcasted_ptr, alignment, false, "");
+ } else {
+ assert(instruction->tmp_ptr != nullptr);
+ LLVMTypeRef wanted_ptr_type_ref = LLVMPointerType(actual_type->type_ref, 0);
+ LLVMValueRef bitcasted_ptr = LLVMBuildBitCast(g->builder, instruction->tmp_ptr, wanted_ptr_type_ref, "");
+ uint32_t alignment = get_abi_alignment(g, wanted_type);
+ gen_store_untyped(g, value, bitcasted_ptr, alignment, false);
+ return instruction->tmp_ptr;
+ }
}
static LLVMValueRef ir_render_widen_or_shorten(CodeGen *g, IrExecutable *executable,
@@ -3167,7 +3199,8 @@ static LLVMValueRef ir_render_br(CodeGen *g, IrExecutable *executable, IrInstruc
static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInstructionUnOp *un_op_instruction) {
IrUnOp op_id = un_op_instruction->op_id;
LLVMValueRef expr = ir_llvm_value(g, un_op_instruction->value);
- ZigType *expr_type = un_op_instruction->value->value.type;
+ ZigType *operand_type = un_op_instruction->value->value.type;
+ ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type;
switch (op_id) {
case IrUnOpInvalid:
@@ -3177,16 +3210,16 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst
case IrUnOpNegation:
case IrUnOpNegationWrap:
{
- if (expr_type->id == ZigTypeIdFloat) {
+ if (scalar_type->id == ZigTypeIdFloat) {
ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &un_op_instruction->base));
return LLVMBuildFNeg(g->builder, expr, "");
- } else if (expr_type->id == ZigTypeIdInt) {
+ } else if (scalar_type->id == ZigTypeIdInt) {
if (op_id == IrUnOpNegationWrap) {
return LLVMBuildNeg(g->builder, expr, "");
} else if (ir_want_runtime_safety(g, &un_op_instruction->base)) {
LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(expr));
- return gen_overflow_op(g, expr_type, AddSubMulSub, zero, expr);
- } else if (expr_type->data.integral.is_signed) {
+ return gen_overflow_op(g, operand_type, AddSubMulSub, zero, expr);
+ } else if (scalar_type->data.integral.is_signed) {
return LLVMBuildNSWNeg(g->builder, expr, "");
} else {
return LLVMBuildNUWNeg(g->builder, expr, "");
@@ -3237,7 +3270,7 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
return nullptr;
}
-static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrInstructionLoadPtr *instruction) {
+static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrInstructionLoadPtrGen *instruction) {
ZigType *child_type = instruction->base.value.type;
if (!type_has_bits(child_type))
return nullptr;
@@ -3252,7 +3285,6 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI
bool big_endian = g->is_big_endian;
- assert(!handle_is_ptr(child_type));
LLVMValueRef containing_int = gen_load(g, ptr, ptr_type, "");
uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int));
assert(host_bit_count == host_int_bytes * 8);
@@ -3264,7 +3296,16 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI
LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false);
LLVMValueRef shifted_value = LLVMBuildLShr(g->builder, containing_int, shift_amt_val, "");
- return LLVMBuildTrunc(g->builder, shifted_value, child_type->type_ref, "");
+ if (!handle_is_ptr(child_type))
+ return LLVMBuildTrunc(g->builder, shifted_value, child_type->type_ref, "");
+
+ assert(instruction->tmp_ptr != nullptr);
+ LLVMTypeRef same_size_int = LLVMIntType(size_in_bits);
+ LLVMValueRef truncated_int = LLVMBuildTrunc(g->builder, shifted_value, same_size_int, "");
+ LLVMValueRef bitcasted_ptr = LLVMBuildBitCast(g->builder, instruction->tmp_ptr,
+ LLVMPointerType(same_size_int, 0), "");
+ LLVMBuildStore(g->builder, truncated_int, bitcasted_ptr);
+ return instruction->tmp_ptr;
}
static bool value_is_all_undef_array(ConstExprValue *const_val, size_t len) {
@@ -3307,6 +3348,77 @@ static bool value_is_all_undef(ConstExprValue *const_val) {
zig_unreachable();
}
+static LLVMValueRef gen_valgrind_client_request(CodeGen *g, LLVMValueRef default_value, LLVMValueRef request,
+ LLVMValueRef a1, LLVMValueRef a2, LLVMValueRef a3, LLVMValueRef a4, LLVMValueRef a5)
+{
+ if (!target_has_valgrind_support(g->zig_target)) {
+ return default_value;
+ }
+ LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->type_ref;
+ bool asm_has_side_effects = true;
+ bool asm_is_alignstack = false;
+ if (g->zig_target->arch == ZigLLVM_x86_64) {
+ if (g->zig_target->os == OsLinux || target_is_darwin(g->zig_target) || g->zig_target->os == OsSolaris ||
+ (g->zig_target->os == OsWindows && g->zig_target->abi != ZigLLVM_MSVC))
+ {
+ if (g->cur_fn->valgrind_client_request_array == nullptr) {
+ LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
+ LLVMBasicBlockRef entry_block = LLVMGetEntryBasicBlock(g->cur_fn->llvm_value);
+ LLVMValueRef first_inst = LLVMGetFirstInstruction(entry_block);
+ LLVMPositionBuilderBefore(g->builder, first_inst);
+ LLVMTypeRef array_type_ref = LLVMArrayType(usize_type_ref, 6);
+ g->cur_fn->valgrind_client_request_array = LLVMBuildAlloca(g->builder, array_type_ref, "");
+ LLVMPositionBuilderAtEnd(g->builder, prev_block);
+ }
+ LLVMValueRef array_ptr = g->cur_fn->valgrind_client_request_array;
+ LLVMValueRef array_elements[] = {request, a1, a2, a3, a4, a5};
+ LLVMValueRef zero = LLVMConstInt(usize_type_ref, 0, false);
+ for (unsigned i = 0; i < 6; i += 1) {
+ LLVMValueRef indexes[] = {
+ zero,
+ LLVMConstInt(usize_type_ref, i, false),
+ };
+ LLVMValueRef elem_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indexes, 2, "");
+ LLVMBuildStore(g->builder, array_elements[i], elem_ptr);
+ }
+
+ Buf *asm_template = buf_create_from_str(
+ "rolq $$3, %rdi ; rolq $$13, %rdi\n"
+ "rolq $$61, %rdi ; rolq $$51, %rdi\n"
+ "xchgq %rbx,%rbx\n"
+ );
+ Buf *asm_constraints = buf_create_from_str(
+ "={rdx},{rax},0,~{cc},~{memory}"
+ );
+ unsigned input_and_output_count = 2;
+ LLVMValueRef array_ptr_as_usize = LLVMBuildPtrToInt(g->builder, array_ptr, usize_type_ref, "");
+ LLVMValueRef param_values[] = { array_ptr_as_usize, default_value };
+ LLVMTypeRef param_types[] = {usize_type_ref, usize_type_ref};
+ LLVMTypeRef function_type = LLVMFunctionType(usize_type_ref, param_types,
+ input_and_output_count, false);
+ LLVMValueRef asm_fn = LLVMGetInlineAsm(function_type, buf_ptr(asm_template), buf_len(asm_template),
+ buf_ptr(asm_constraints), buf_len(asm_constraints), asm_has_side_effects, asm_is_alignstack,
+ LLVMInlineAsmDialectATT);
+ return LLVMBuildCall(g->builder, asm_fn, param_values, input_and_output_count, "");
+ }
+ }
+ zig_unreachable();
+}
+
+static bool want_valgrind_support(CodeGen *g) {
+ if (!target_has_valgrind_support(g->zig_target))
+ return false;
+ switch (g->valgrind_support) {
+ case ValgrindSupportDisabled:
+ return false;
+ case ValgrindSupportEnabled:
+ return true;
+ case ValgrindSupportAuto:
+ return g->build_mode == BuildModeDebug;
+ }
+ zig_unreachable();
+}
+
static void gen_undef_init(CodeGen *g, uint32_t ptr_align_bytes, ZigType *value_type, LLVMValueRef ptr) {
assert(type_has_bits(value_type));
uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, value_type->type_ref);
@@ -3319,6 +3431,14 @@ static void gen_undef_init(CodeGen *g, uint32_t ptr_align_bytes, ZigType *value_
ZigType *usize = g->builtin_types.entry_usize;
LLVMValueRef byte_count = LLVMConstInt(usize->type_ref, size_bytes, false);
ZigLLVMBuildMemSet(g->builder, dest_ptr, fill_char, byte_count, ptr_align_bytes, false);
+ // then tell valgrind that the memory is undefined even though we just memset it
+ if (want_valgrind_support(g)) {
+ static const uint32_t VG_USERREQ__MAKE_MEM_UNDEFINED = 1296236545;
+ LLVMValueRef zero = LLVMConstInt(usize->type_ref, 0, false);
+ LLVMValueRef req = LLVMConstInt(usize->type_ref, VG_USERREQ__MAKE_MEM_UNDEFINED, false);
+ LLVMValueRef ptr_as_usize = LLVMBuildPtrToInt(g->builder, dest_ptr, usize->type_ref, "");
+ gen_valgrind_client_request(g, zero, req, ptr_as_usize, byte_count, zero, zero, zero);
+ }
}
static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, IrInstructionStorePtr *instruction) {
@@ -3479,7 +3599,7 @@ static void gen_set_stack_pointer(CodeGen *g, LLVMValueRef aligned_end_addr) {
LLVMValueRef write_register_fn_val = get_write_register_fn_val(g);
if (g->sp_md_node == nullptr) {
- Buf *sp_reg_name = buf_create_from_str(arch_stack_pointer_register_name(&g->zig_target.arch));
+ Buf *sp_reg_name = buf_create_from_str(arch_stack_pointer_register_name(g->zig_target->arch));
LLVMValueRef str_node = LLVMMDString(buf_ptr(sp_reg_name), buf_len(sp_reg_name) + 1);
g->sp_md_node = LLVMMDNode(&str_node, 1);
}
@@ -5337,6 +5457,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdDeclVarSrc:
case IrInstructionIdPtrCastSrc:
case IrInstructionIdCmpxchgSrc:
+ case IrInstructionIdLoadPtr:
+ case IrInstructionIdBitCast:
zig_unreachable();
case IrInstructionIdDeclVarGen:
@@ -5355,8 +5477,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_br(g, executable, (IrInstructionBr *)instruction);
case IrInstructionIdUnOp:
return ir_render_un_op(g, executable, (IrInstructionUnOp *)instruction);
- case IrInstructionIdLoadPtr:
- return ir_render_load_ptr(g, executable, (IrInstructionLoadPtr *)instruction);
+ case IrInstructionIdLoadPtrGen:
+ return ir_render_load_ptr(g, executable, (IrInstructionLoadPtrGen *)instruction);
case IrInstructionIdStorePtr:
return ir_render_store_ptr(g, executable, (IrInstructionStorePtr *)instruction);
case IrInstructionIdVarPtr:
@@ -5433,8 +5555,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_union_init(g, executable, (IrInstructionUnionInit *)instruction);
case IrInstructionIdPtrCastGen:
return ir_render_ptr_cast(g, executable, (IrInstructionPtrCastGen *)instruction);
- case IrInstructionIdBitCast:
- return ir_render_bit_cast(g, executable, (IrInstructionBitCast *)instruction);
+ case IrInstructionIdBitCastGen:
+ return ir_render_bit_cast(g, executable, (IrInstructionBitCastGen *)instruction);
case IrInstructionIdWidenOrShorten:
return ir_render_widen_or_shorten(g, executable, (IrInstructionWidenOrShorten *)instruction);
case IrInstructionIdPtrToInt:
@@ -5509,6 +5631,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_vector_to_array(g, executable, (IrInstructionVectorToArray *)instruction);
case IrInstructionIdAssertZero:
return ir_render_assert_zero(g, executable, (IrInstructionAssertZero *)instruction);
+ case IrInstructionIdResizeSlice:
+ return ir_render_resize_slice(g, executable, (IrInstructionResizeSlice *)instruction);
}
zig_unreachable();
}
@@ -5711,8 +5835,32 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
LLVMValueRef ptr_size_int_val = LLVMConstPtrToInt(ptr_val, g->builtin_types.entry_usize->type_ref);
return LLVMConstZExt(ptr_size_int_val, big_int_type_ref);
}
- case ZigTypeIdArray:
- zig_panic("TODO bit pack an array");
+ case ZigTypeIdArray: {
+ LLVMValueRef val = LLVMConstInt(big_int_type_ref, 0, false);
+ if (const_val->data.x_array.special == ConstArraySpecialUndef) {
+ return val;
+ }
+ expand_undef_array(g, const_val);
+ bool is_big_endian = g->is_big_endian; // TODO get endianness from struct type
+ uint32_t packed_bits_size = type_size_bits(g, type_entry->data.array.child_type);
+ size_t used_bits = 0;
+ for (size_t i = 0; i < type_entry->data.array.len; i += 1) {
+ ConstExprValue *elem_val = &const_val->data.x_array.data.s_none.elements[i];
+ LLVMValueRef child_val = pack_const_int(g, big_int_type_ref, elem_val);
+
+ if (is_big_endian) {
+ LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, packed_bits_size, false);
+ val = LLVMConstShl(val, shift_amt);
+ val = LLVMConstOr(val, child_val);
+ } else {
+ LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, used_bits, false);
+ LLVMValueRef child_val_shifted = LLVMConstShl(child_val, shift_amt);
+ val = LLVMConstOr(val, child_val_shifted);
+ used_bits += packed_bits_size;
+ }
+ }
+ return val;
+ }
case ZigTypeIdVector:
zig_panic("TODO bit pack a vector");
case ZigTypeIdUnion:
@@ -6387,6 +6535,22 @@ static void set_global_tls(CodeGen *g, ZigVar *var, LLVMValueRef global_value) {
}
}
+static LLVMLinkage var_linkage_to_llvm(VarLinkage var_linkage) {
+ switch (var_linkage) {
+ case VarLinkageInternal:
+ return LLVMInternalLinkage;
+ case VarLinkageExportStrong:
+ return LLVMExternalLinkage;
+ case VarLinkageExportWeak:
+ return LLVMWeakODRLinkage;
+ case VarLinkageExportLinkOnce:
+ return LLVMLinkOnceODRLinkage;
+ case VarLinkageExternal:
+ return LLVMExternalLinkage;
+ }
+ zig_unreachable();
+}
+
static void do_code_gen(CodeGen *g) {
assert(!g->errors.length);
@@ -6467,21 +6631,21 @@ static void do_code_gen(CodeGen *g) {
global_value = LLVMAddGlobal(g->module, var->var_type->type_ref, buf_ptr(&var->name));
// TODO debug info for the extern variable
- LLVMSetLinkage(global_value, LLVMExternalLinkage);
+ LLVMSetLinkage(global_value, var_linkage_to_llvm(var->linkage));
maybe_import_dll(g, global_value, GlobalLinkageIdStrong);
LLVMSetAlignment(global_value, var->align_bytes);
LLVMSetGlobalConstant(global_value, var->gen_is_const);
set_global_tls(g, var, global_value);
}
} else {
- bool exported = (var->linkage == VarLinkageExport);
+ bool exported = (var->linkage != VarLinkageInternal);
const char *mangled_name = buf_ptr(get_mangled_name(g, &var->name, exported));
render_const_val(g, var->const_value, mangled_name);
render_const_val_global(g, var->const_value, mangled_name);
global_value = var->const_value->global_refs->llvm_global;
if (exported) {
- LLVMSetLinkage(global_value, LLVMExternalLinkage);
+ LLVMSetLinkage(global_value, var_linkage_to_llvm(var->linkage));
maybe_export_dll(g, global_value, GlobalLinkageIdStrong);
}
if (tld_var->section_name) {
@@ -6584,6 +6748,15 @@ static void do_code_gen(CodeGen *g) {
} else if (instruction->id == IrInstructionIdCmpxchgGen) {
IrInstructionCmpxchgGen *cmpxchg_instruction = (IrInstructionCmpxchgGen *)instruction;
slot = &cmpxchg_instruction->tmp_ptr;
+ } else if (instruction->id == IrInstructionIdResizeSlice) {
+ IrInstructionResizeSlice *resize_slice_instruction = (IrInstructionResizeSlice *)instruction;
+ slot = &resize_slice_instruction->tmp_ptr;
+ } else if (instruction->id == IrInstructionIdLoadPtrGen) {
+ IrInstructionLoadPtrGen *load_ptr_inst = (IrInstructionLoadPtrGen *)instruction;
+ slot = &load_ptr_inst->tmp_ptr;
+ } else if (instruction->id == IrInstructionIdBitCastGen) {
+ IrInstructionBitCastGen *bit_cast_inst = (IrInstructionBitCastGen *)instruction;
+ slot = &bit_cast_inst->tmp_ptr;
} else if (instruction->id == IrInstructionIdVectorToArray) {
IrInstructionVectorToArray *vector_to_array_instruction = (IrInstructionVectorToArray *)instruction;
alignment_bytes = get_abi_alignment(g, vector_to_array_instruction->vector->value.type);
@@ -6839,7 +7012,7 @@ static void define_builtin_types(CodeGen *g) {
for (size_t i = 0; i < array_length(c_int_type_infos); i += 1) {
const CIntTypeInfo *info = &c_int_type_infos[i];
- uint32_t size_in_bits = target_c_type_size_in_bits(&g->zig_target, info->id);
+ uint32_t size_in_bits = target_c_type_size_in_bits(g->zig_target, info->id);
bool is_signed = info->is_signed;
ZigType *entry = new_type_table_entry(ZigTypeIdInt);
@@ -7106,6 +7279,9 @@ static const char *build_mode_to_str(BuildMode build_mode) {
Buf *codegen_generate_builtin_source(CodeGen *g) {
Buf *contents = buf_alloc();
+ // NOTE: when editing this file, you may need to make modifications to the
+ // cache input parameters in define_builtin_compile_vars
+
// Modifications to this struct must be coordinated with code that does anything with
// g->stack_trace_type. There are hard-coded references to the field indexes.
buf_append_str(contents,
@@ -7114,16 +7290,18 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
" instruction_addresses: []usize,\n"
"};\n\n");
+ buf_append_str(contents, "pub const PanicFn = fn([]const u8, ?*StackTrace) noreturn;\n\n");
+
const char *cur_os = nullptr;
{
buf_appendf(contents, "pub const Os = enum {\n");
uint32_t field_count = (uint32_t)target_os_count();
for (uint32_t i = 0; i < field_count; i += 1) {
- Os os_type = get_target_os(i);
- const char *name = get_target_os_name(os_type);
+ Os os_type = target_os_enum(i);
+ const char *name = target_os_name(os_type);
buf_appendf(contents, " %s,\n", name);
- if (os_type == g->zig_target.os) {
+ if (os_type == g->zig_target->os) {
g->target_os_index = i;
cur_os = name;
}
@@ -7134,56 +7312,81 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
const char *cur_arch = nullptr;
{
- buf_appendf(contents, "pub const Arch = enum {\n");
+ buf_appendf(contents, "pub const Arch = union(enum) {\n");
uint32_t field_count = (uint32_t)target_arch_count();
- for (uint32_t i = 0; i < field_count; i += 1) {
- const ArchType *arch_type = get_target_arch(i);
- Buf *arch_name = buf_alloc();
- buf_resize(arch_name, 50);
- get_arch_name(buf_ptr(arch_name), arch_type);
- buf_resize(arch_name, strlen(buf_ptr(arch_name)));
-
- buf_appendf(contents, " %s,\n", buf_ptr(arch_name));
+ for (uint32_t arch_i = 0; arch_i < field_count; arch_i += 1) {
+ ZigLLVM_ArchType arch = target_arch_enum(arch_i);
+ const char *arch_name = target_arch_name(arch);
+ SubArchList sub_arch_list = target_subarch_list(arch);
+ if (sub_arch_list == SubArchListNone) {
+ buf_appendf(contents, " %s,\n", arch_name);
+ if (arch == g->zig_target->arch) {
+ g->target_arch_index = arch_i;
+ cur_arch = buf_ptr(buf_sprintf("Arch.%s", arch_name));
+ }
+ } else {
+ const char *sub_arch_list_name = target_subarch_list_name(sub_arch_list);
+ buf_appendf(contents, " %s: %s,\n", arch_name, sub_arch_list_name);
+ if (arch == g->zig_target->arch) {
+ size_t sub_count = target_subarch_count(sub_arch_list);
+ for (size_t sub_i = 0; sub_i < sub_count; sub_i += 1) {
+ ZigLLVM_SubArchType sub = target_subarch_enum(sub_arch_list, sub_i);
+ if (sub == g->zig_target->sub_arch) {
+ g->target_sub_arch_index = sub_i;
+ cur_arch = buf_ptr(buf_sprintf("Arch{ .%s = Arch.%s.%s }",
+ arch_name, sub_arch_list_name, target_subarch_name(sub)));
+ }
+ }
+ }
+ }
+ }
- if (arch_type->arch == g->zig_target.arch.arch &&
- arch_type->sub_arch == g->zig_target.arch.sub_arch)
- {
- g->target_arch_index = i;
- cur_arch = buf_ptr(arch_name);
+ uint32_t list_count = target_subarch_list_count();
+ // start at index 1 to skip None
+ for (uint32_t list_i = 1; list_i < list_count; list_i += 1) {
+ SubArchList sub_arch_list = target_subarch_list_enum(list_i);
+ const char *subarch_list_name = target_subarch_list_name(sub_arch_list);
+ buf_appendf(contents, " pub const %s = enum {\n", subarch_list_name);
+ size_t sub_count = target_subarch_count(sub_arch_list);
+ for (size_t sub_i = 0; sub_i < sub_count; sub_i += 1) {
+ ZigLLVM_SubArchType sub = target_subarch_enum(sub_arch_list, sub_i);
+ buf_appendf(contents, " %s,\n", target_subarch_name(sub));
}
+ buf_appendf(contents, " };\n");
}
buf_appendf(contents, "};\n\n");
}
assert(cur_arch != nullptr);
- const char *cur_environ = nullptr;
+ const char *cur_abi = nullptr;
{
- buf_appendf(contents, "pub const Environ = enum {\n");
- uint32_t field_count = (uint32_t)target_environ_count();
+ buf_appendf(contents, "pub const Abi = enum {\n");
+ uint32_t field_count = (uint32_t)target_abi_count();
for (uint32_t i = 0; i < field_count; i += 1) {
- ZigLLVM_EnvironmentType environ_type = get_target_environ(i);
- const char *name = ZigLLVMGetEnvironmentTypeName(environ_type);
+ ZigLLVM_EnvironmentType abi = target_abi_enum(i);
+ const char *name = target_abi_name(abi);
buf_appendf(contents, " %s,\n", name);
- if (environ_type == g->zig_target.env_type) {
- g->target_environ_index = i;
- cur_environ = name;
+ if (abi == g->zig_target->abi) {
+ g->target_abi_index = i;
+ cur_abi = name;
}
}
buf_appendf(contents, "};\n\n");
}
- assert(cur_environ != nullptr);
+ assert(cur_abi != nullptr);
const char *cur_obj_fmt = nullptr;
{
buf_appendf(contents, "pub const ObjectFormat = enum {\n");
uint32_t field_count = (uint32_t)target_oformat_count();
for (uint32_t i = 0; i < field_count; i += 1) {
- ZigLLVM_ObjectFormatType oformat = get_target_oformat(i);
- const char *name = get_target_oformat_name(oformat);
+ ZigLLVM_ObjectFormatType oformat = target_oformat_enum(i);
+ const char *name = target_oformat_name(oformat);
buf_appendf(contents, " %s,\n", name);
- if (oformat == g->zig_target.oformat) {
+ ZigLLVM_ObjectFormatType target_oformat = target_object_format(g->zig_target);
+ if (oformat == target_oformat) {
g->target_oformat_index = i;
cur_obj_fmt = name;
}
@@ -7294,6 +7497,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
" One,\n"
" Many,\n"
" Slice,\n"
+ " C,\n"
" };\n"
" };\n"
"\n"
@@ -7466,12 +7670,13 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
buf_appendf(contents, "pub const is_test = %s;\n", bool_to_str(g->is_test_build));
buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded));
buf_appendf(contents, "pub const os = Os.%s;\n", cur_os);
- buf_appendf(contents, "pub const arch = Arch.%s;\n", cur_arch);
- buf_appendf(contents, "pub const environ = Environ.%s;\n", cur_environ);
+ buf_appendf(contents, "pub const arch = %s;\n", cur_arch);
+ buf_appendf(contents, "pub const abi = Abi.%s;\n", cur_abi);
buf_appendf(contents, "pub const object_format = ObjectFormat.%s;\n", cur_obj_fmt);
buf_appendf(contents, "pub const mode = %s;\n", build_mode_to_str(g->build_mode));
buf_appendf(contents, "pub const link_libc = %s;\n", bool_to_str(g->libc_link_lib != nullptr));
buf_appendf(contents, "pub const have_error_return_tracing = %s;\n", bool_to_str(g->have_err_ret_tracing));
+ buf_appendf(contents, "pub const valgrind_support = %s;\n", bool_to_str(want_valgrind_support(g)));
buf_appendf(contents, "pub const __zig_test_fn_slice = {}; // overwritten later\n");
@@ -7500,14 +7705,15 @@ static Error define_builtin_compile_vars(CodeGen *g) {
cache_int(&cache_hash, g->build_mode);
cache_bool(&cache_hash, g->is_test_build);
cache_bool(&cache_hash, g->is_single_threaded);
- cache_int(&cache_hash, g->zig_target.arch.arch);
- cache_int(&cache_hash, g->zig_target.arch.sub_arch);
- cache_int(&cache_hash, g->zig_target.vendor);
- cache_int(&cache_hash, g->zig_target.os);
- cache_int(&cache_hash, g->zig_target.env_type);
- cache_int(&cache_hash, g->zig_target.oformat);
+ cache_int(&cache_hash, g->zig_target->is_native);
+ cache_int(&cache_hash, g->zig_target->arch);
+ cache_int(&cache_hash, g->zig_target->sub_arch);
+ cache_int(&cache_hash, g->zig_target->vendor);
+ cache_int(&cache_hash, g->zig_target->os);
+ cache_int(&cache_hash, g->zig_target->abi);
cache_bool(&cache_hash, g->have_err_ret_tracing);
cache_bool(&cache_hash, g->libc_link_lib != nullptr);
+ cache_bool(&cache_hash, g->valgrind_support);
Buf digest = BUF_INIT;
buf_resize(&digest, 0);
@@ -7576,11 +7782,11 @@ static void init(CodeGen *g) {
assert(g->root_out_name);
g->module = LLVMModuleCreateWithName(buf_ptr(g->root_out_name));
- get_target_triple(&g->triple_str, &g->zig_target);
+ get_target_triple(&g->triple_str, g->zig_target);
LLVMSetTarget(g->module, buf_ptr(&g->triple_str));
- if (g->zig_target.oformat == ZigLLVM_COFF) {
+ if (target_object_format(g->zig_target) == ZigLLVM_COFF) {
ZigLLVMAddModuleCodeViewFlag(g->module);
} else {
ZigLLVMAddModuleDebugInfoFlag(g->module);
@@ -7608,11 +7814,11 @@ static void init(CodeGen *g) {
const char *target_specific_cpu_args;
const char *target_specific_features;
- if (g->is_native_target) {
+ if (g->zig_target->is_native) {
// LLVM creates invalid binaries on Windows sometimes.
// See https://github.com/ziglang/zig/issues/508
// As a workaround we do not use target native features on Windows.
- if (g->zig_target.os == OsWindows || g->zig_target.os == OsUefi) {
+ if (g->zig_target->os == OsWindows || g->zig_target->os == OsUefi) {
target_specific_cpu_args = "";
target_specific_features = "";
} else {
@@ -7685,9 +7891,59 @@ static void init(CodeGen *g) {
}
}
-void codegen_translate_c(CodeGen *g, Buf *full_path) {
- find_libc_include_path(g);
+static void detect_libc(CodeGen *g) {
+ Error err;
+
+ if (g->libc != nullptr || g->libc_link_lib == nullptr)
+ return;
+
+ if (g->zig_target->is_native) {
+ g->libc = allocate<ZigLibCInstallation>(1);
+
+ // Look for zig-cache/native_libc.txt
+ Buf *native_libc_txt = buf_alloc();
+ os_path_join(&g->cache_dir, buf_create_from_str("native_libc.txt"), native_libc_txt);
+ if ((err = zig_libc_parse(g->libc, native_libc_txt, g->zig_target, false))) {
+ if ((err = zig_libc_find_native(g->libc, true))) {
+ fprintf(stderr,
+ "Unable to link against libc: Unable to find libc installation: %s\n"
+ "See `zig libc --help` for more details.\n", err_str(err));
+ exit(1);
+ }
+ if ((err = os_make_path(&g->cache_dir))) {
+ fprintf(stderr, "Unable to create %s directory: %s\n",
+ buf_ptr(&g->cache_dir), err_str(err));
+ exit(1);
+ }
+ Buf *native_libc_tmp = buf_sprintf("%s.tmp", buf_ptr(native_libc_txt));
+ FILE *file = fopen(buf_ptr(native_libc_tmp), "wb");
+ if (file == nullptr) {
+ fprintf(stderr, "Unable to open %s: %s\n", buf_ptr(native_libc_tmp), strerror(errno));
+ exit(1);
+ }
+ zig_libc_render(g->libc, file);
+ if (fclose(file) != 0) {
+ fprintf(stderr, "Unable to save %s: %s\n", buf_ptr(native_libc_tmp), strerror(errno));
+ exit(1);
+ }
+ if ((err = os_rename(native_libc_tmp, native_libc_txt))) {
+ fprintf(stderr, "Unable to create %s: %s\n", buf_ptr(native_libc_txt), err_str(err));
+ exit(1);
+ }
+ }
+ } else if ((g->out_type == OutTypeExe || (g->out_type == OutTypeLib && !g->is_static)) &&
+ !target_is_darwin(g->zig_target))
+ {
+ // Currently darwin is the only platform that we can link libc on when not compiling natively,
+ // without a cross compiling libc kit.
+ fprintf(stderr,
+ "Cannot link against libc for non-native OS '%s' without providing a libc installation file.\n"
+ "See `zig libc --help` for more details.\n", target_os_name(g->zig_target->os));
+ exit(1);
+ }
+}
+void codegen_translate_c(CodeGen *g, Buf *full_path) {
Buf *src_basename = buf_alloc();
Buf *src_dirname = buf_alloc();
os_path_split(full_path, src_dirname, src_basename);
@@ -7698,6 +7954,8 @@ void codegen_translate_c(CodeGen *g, Buf *full_path) {
g->root_import = import;
import->decls_scope = create_decls_scope(g, nullptr, nullptr, nullptr, import);
+ detect_libc(g);
+
init(g);
import->di_file = ZigLLVMCreateFile(g->dbuilder, buf_ptr(src_basename), buf_ptr(src_dirname));
@@ -7857,14 +8115,14 @@ static void gen_root_source(CodeGen *g) {
}
report_errors_and_maybe_exit(g);
- if (!g->is_test_build && g->zig_target.os != OsFreestanding &&
- g->zig_target.os != OsUefi &&
+ if (!g->is_test_build && g->zig_target->os != OsFreestanding &&
+ g->zig_target->os != OsUefi &&
!g->have_c_main && !g->have_winmain && !g->have_winmain_crt_startup &&
((g->have_pub_main && g->out_type == OutTypeObj) || g->out_type == OutTypeExe))
{
g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g, g->root_package), "bootstrap.zig");
}
- if (g->zig_target.os == OsWindows && !g->have_dllmain_crt_startup &&
+ if (g->zig_target->os == OsWindows && !g->have_dllmain_crt_startup &&
g->out_type == OutTypeLib && !g->is_static)
{
g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g, g->root_package), "bootstrap_lib.zig");
@@ -7882,6 +8140,8 @@ static void gen_root_source(CodeGen *g) {
}
}
+ typecheck_panic_fn(g, g->panic_tld_fn, g->panic_fn);
+
report_errors_and_maybe_exit(g);
}
@@ -7904,6 +8164,168 @@ static void gen_global_asm(CodeGen *g) {
}
}
+static void print_zig_cc_cmd(const char *zig_exe, ZigList<const char *> *args) {
+ fprintf(stderr, "%s", zig_exe);
+ for (size_t arg_i = 0; arg_i < args->length; arg_i += 1) {
+ fprintf(stderr, " %s", args->at(arg_i));
+ }
+ fprintf(stderr, "\n");
+}
+
+static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) {
+ Error err;
+
+ Buf *c_source_file = buf_create_from_str(c_file->source_path);
+ Buf *c_source_basename = buf_alloc();
+ os_path_split(c_source_file, nullptr, c_source_basename);
+ Buf *out_obj_name = buf_sprintf("%s%s", buf_ptr(c_source_basename), target_o_file_ext(g->zig_target));
+ Buf *out_obj_path = buf_alloc();
+ os_path_join(&g->cache_dir, out_obj_name, out_obj_path);
+ Buf *out_dep_name = buf_sprintf("%s.d", buf_ptr(c_source_file));
+ Buf *out_dep_path = buf_alloc();
+ os_path_join(&g->cache_dir, out_dep_name, out_dep_path);
+
+ Termination term;
+ ZigList<const char *> args = {};
+ args.append("cc");
+
+ if (g->enable_cache) {
+ args.append("-MD");
+ args.append("-MF");
+ args.append(buf_ptr(out_dep_path));
+ }
+
+ args.append("-nostdinc");
+ args.append("-fno-spell-checking");
+
+ switch (g->err_color) {
+ case ErrColorAuto:
+ break;
+ case ErrColorOff:
+ args.append("-fno-color-diagnostics");
+ args.append("-fno-caret-diagnostics");
+ break;
+ case ErrColorOn:
+ args.append("-fcolor-diagnostics");
+ args.append("-fcaret-diagnostics");
+ break;
+ }
+
+ args.append("-isystem");
+ args.append(buf_ptr(g->zig_c_headers_dir));
+
+ if (g->libc != nullptr) {
+ args.append("-isystem");
+ args.append(buf_ptr(&g->libc->include_dir));
+
+ if (!buf_eql_buf(&g->libc->include_dir, &g->libc->sys_include_dir)) {
+ args.append("-isystem");
+ args.append(buf_ptr(&g->libc->sys_include_dir));
+ }
+ }
+
+ if (g->zig_target->is_native) {
+ args.append("-march=native");
+ } else {
+ args.append("-target");
+ args.append(buf_ptr(&g->triple_str));
+ }
+
+ if (!g->strip_debug_symbols) {
+ args.append("-g");
+ }
+ switch (g->build_mode) {
+ case BuildModeDebug:
+ if (g->libc_link_lib != nullptr) {
+ args.append("-fstack-protector-strong");
+ args.append("--param");
+ args.append("ssp-buffer-size=4");
+ } else {
+ args.append("-fno-stack-protector");
+ }
+ break;
+ case BuildModeSafeRelease:
+ args.append("-O2");
+ if (g->libc_link_lib != nullptr) {
+ args.append("-D_FORTIFY_SOURCE=2");
+ args.append("-fstack-protector-strong");
+ args.append("--param");
+ args.append("ssp-buffer-size=4");
+ } else {
+ args.append("-fno-stack-protector");
+ }
+ break;
+ case BuildModeFastRelease:
+ args.append("-O2");
+ args.append("-fno-stack-protector");
+ break;
+ case BuildModeSmallRelease:
+ args.append("-Os");
+ args.append("-fno-stack-protector");
+ break;
+ }
+
+ args.append("-o");
+ args.append(buf_ptr(out_obj_path));
+
+ args.append("-c");
+ args.append(buf_ptr(c_source_file));
+
+ if (!g->disable_pic && target_supports_fpic(g->zig_target)) {
+ args.append("-fPIC");
+ }
+
+ for (size_t arg_i = 0; arg_i < g->clang_argv_len; arg_i += 1) {
+ args.append(g->clang_argv[arg_i]);
+ }
+
+ for (size_t arg_i = 0; arg_i < c_file->args.length; arg_i += 1) {
+ args.append(c_file->args.at(arg_i));
+ }
+
+ if (g->verbose_cc) {
+ print_zig_cc_cmd("zig", &args);
+ }
+ os_spawn_process(buf_ptr(self_exe_path), args, &term);
+ if (term.how != TerminationIdClean || term.code != 0) {
+ fprintf(stderr, "\nThe following command failed:\n");
+ print_zig_cc_cmd(buf_ptr(self_exe_path), &args);
+ exit(1);
+ }
+
+ g->link_objects.append(out_obj_path);
+
+ if (g->enable_cache) {
+ // add the files depended on to the cache system
+ if ((err = cache_add_file(&g->cache_hash, c_source_file))) {
+ fprintf(stderr, "unable to add %s to cache: %s\n", buf_ptr(c_source_file), err_str(err));
+ exit(1);
+ }
+ if ((err = cache_add_dep_file(&g->cache_hash, out_dep_path, true))) {
+ fprintf(stderr, "failed to add C source dependencies to cache: %s\n", err_str(err));
+ exit(1);
+ }
+ }
+}
+
+static void gen_c_objects(CodeGen *g) {
+ Error err;
+
+ if (g->c_source_files.length == 0)
+ return;
+
+ Buf *self_exe_path = buf_alloc();
+ if ((err = os_self_exe_path(self_exe_path))) {
+ fprintf(stderr, "Unable to get self exe path: %s\n", err_str(err));
+ exit(1);
+ }
+
+ for (size_t c_file_i = 0; c_file_i < g->c_source_files.length; c_file_i += 1) {
+ CFile *c_file = g->c_source_files.at(c_file_i);
+ gen_c_object(g, self_exe_path, c_file);
+ }
+}
+
void codegen_add_object(CodeGen *g, Buf *object_path) {
g->link_objects.append(object_path);
}
@@ -8410,31 +8832,39 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
}
cache_buf(ch, compiler_id);
cache_buf(ch, g->root_out_name);
+ cache_buf(ch, g->zig_lib_dir);
+ cache_buf(ch, g->zig_std_dir);
cache_list_of_link_lib(ch, g->link_libs_list.items, g->link_libs_list.length);
cache_list_of_buf(ch, g->darwin_frameworks.items, g->darwin_frameworks.length);
cache_list_of_buf(ch, g->rpath_list.items, g->rpath_list.length);
cache_list_of_buf(ch, g->forbidden_libs.items, g->forbidden_libs.length);
cache_list_of_file(ch, g->link_objects.items, g->link_objects.length);
cache_list_of_file(ch, g->assembly_files.items, g->assembly_files.length);
+ for (size_t c_file_i = 0; c_file_i < g->c_source_files.length; c_file_i += 1) {
+ CFile *c_file = g->c_source_files.at(c_file_i);
+ cache_file(ch, buf_create_from_str(c_file->source_path));
+ for (size_t opt_i = 0; opt_i < c_file->args.length; opt_i += 1) {
+ cache_buf(ch, buf_create_from_str(c_file->args.at(opt_i)));
+ }
+ }
cache_int(ch, g->emit_file_type);
cache_int(ch, g->build_mode);
cache_int(ch, g->out_type);
- cache_int(ch, g->zig_target.arch.arch);
- cache_int(ch, g->zig_target.arch.sub_arch);
- cache_int(ch, g->zig_target.vendor);
- cache_int(ch, g->zig_target.os);
- cache_int(ch, g->zig_target.env_type);
- cache_int(ch, g->zig_target.oformat);
+ cache_bool(ch, g->zig_target->is_native);
+ cache_int(ch, g->zig_target->arch);
+ cache_int(ch, g->zig_target->sub_arch);
+ cache_int(ch, g->zig_target->vendor);
+ cache_int(ch, g->zig_target->os);
+ cache_int(ch, g->zig_target->abi);
cache_int(ch, g->subsystem);
cache_bool(ch, g->is_static);
cache_bool(ch, g->strip_debug_symbols);
cache_bool(ch, g->is_test_build);
cache_bool(ch, g->is_single_threaded);
- cache_bool(ch, g->is_native_target);
cache_bool(ch, g->linker_rdynamic);
- cache_bool(ch, g->no_rosegment_workaround);
cache_bool(ch, g->each_lib_rpath);
cache_bool(ch, g->disable_pic);
+ cache_bool(ch, g->valgrind_support);
cache_buf_opt(ch, g->mmacosx_version_min);
cache_buf_opt(ch, g->mios_version_min);
cache_usize(ch, g->version_major);
@@ -8445,6 +8875,16 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
cache_list_of_str(ch, g->llvm_argv, g->llvm_argv_len);
cache_list_of_str(ch, g->clang_argv, g->clang_argv_len);
cache_list_of_str(ch, g->lib_dirs.items, g->lib_dirs.length);
+ if (g->libc) {
+ cache_buf(ch, &g->libc->include_dir);
+ cache_buf(ch, &g->libc->sys_include_dir);
+ cache_buf(ch, &g->libc->crt_dir);
+ cache_buf(ch, &g->libc->lib_dir);
+ cache_buf(ch, &g->libc->static_lib_dir);
+ cache_buf(ch, &g->libc->msvc_lib_dir);
+ cache_buf(ch, &g->libc->kernel32_lib_dir);
+ cache_buf(ch, &g->libc->dynamic_linker_path);
+ }
buf_resize(digest, 0);
if ((err = cache_hit(ch, digest)))
@@ -8459,19 +8899,19 @@ static void resolve_out_paths(CodeGen *g) {
switch (g->emit_file_type) {
case EmitFileTypeBinary:
{
- const char *o_ext = target_o_file_ext(&g->zig_target);
+ const char *o_ext = target_o_file_ext(g->zig_target);
buf_append_str(o_basename, o_ext);
break;
}
case EmitFileTypeAssembly:
{
- const char *asm_ext = target_asm_file_ext(&g->zig_target);
+ const char *asm_ext = target_asm_file_ext(g->zig_target);
buf_append_str(o_basename, asm_ext);
break;
}
case EmitFileTypeLLVMIr:
{
- const char *llvm_ir_ext = target_llvm_ir_file_ext(&g->zig_target);
+ const char *llvm_ir_ext = target_llvm_ir_file_ext(g->zig_target);
buf_append_str(o_basename, llvm_ir_ext);
break;
}
@@ -8497,7 +8937,7 @@ static void resolve_out_paths(CodeGen *g) {
Buf basename = BUF_INIT;
buf_init_from_buf(&basename, g->root_out_name);
- buf_append_str(&basename, target_exe_file_ext(&g->zig_target));
+ buf_append_str(&basename, target_exe_file_ext(g->zig_target));
if (g->enable_cache || g->is_test_build) {
os_path_join(&g->artifact_dir, &basename, &g->output_file_path);
} else {
@@ -8510,7 +8950,7 @@ static void resolve_out_paths(CodeGen *g) {
} else {
Buf basename = BUF_INIT;
buf_init_from_buf(&basename, g->root_out_name);
- buf_append_str(&basename, target_lib_file_ext(&g->zig_target, g->is_static,
+ buf_append_str(&basename, target_lib_file_ext(g->zig_target, g->is_static,
g->version_major, g->version_minor, g->version_patch));
if (g->enable_cache) {
os_path_join(&g->artifact_dir, &basename, &g->output_file_path);
@@ -8523,11 +8963,12 @@ static void resolve_out_paths(CodeGen *g) {
}
}
-
void codegen_build_and_link(CodeGen *g) {
Error err;
assert(g->out_type != OutTypeUnknown);
+ detect_libc(g);
+
Buf *stage1_dir = get_stage1_cache_path();
Buf *artifact_dir = buf_alloc();
Buf digest = BUF_INIT;
@@ -8559,6 +9000,7 @@ void codegen_build_and_link(CodeGen *g) {
gen_global_asm(g);
gen_root_source(g);
+ gen_c_objects(g);
if (g->enable_cache) {
if ((err = cache_final(&g->cache_hash, &digest))) {
@@ -8576,16 +9018,25 @@ void codegen_build_and_link(CodeGen *g) {
resolve_out_paths(g);
codegen_add_time_event(g, "Code Generation");
- do_code_gen(g);
- codegen_add_time_event(g, "LLVM Emit Output");
- zig_llvm_emit_output(g);
+ if (g->out_type == OutTypeObj && g->c_source_files.length == 1) {
+ assert(g->link_objects.length == 1);
+ if ((err = os_rename(g->link_objects.pop(), &g->o_file_output_path))) {
+ fprintf(stderr, "unable to move object to '%s': %s\n",
+ buf_ptr(&g->o_file_output_path), err_str(err));
+ exit(1);
+ }
+ } else {
+ do_code_gen(g);
+ codegen_add_time_event(g, "LLVM Emit Output");
+ zig_llvm_emit_output(g);
- if (g->out_h_path != nullptr) {
- codegen_add_time_event(g, "Generate .h");
- gen_h_file(g);
- }
- if (g->out_type != OutTypeObj && g->emit_file_type == EmitFileTypeBinary) {
- codegen_link(g);
+ if (g->out_h_path != nullptr) {
+ codegen_add_time_event(g, "Generate .h");
+ gen_h_file(g);
+ }
+ if (g->out_type != OutTypeObj && g->emit_file_type == EmitFileTypeBinary) {
+ codegen_link(g);
+ }
}
}
diff --git a/src/codegen.hpp b/src/codegen.hpp
@@ -11,11 +11,12 @@
#include "parser.hpp"
#include "errmsg.hpp"
#include "target.hpp"
+#include "libc_installation.hpp"
#include <stdio.h>
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_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_errmsg_color(CodeGen *codegen, ErrColor err_color);
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_forbidden_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_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_lib_path(CodeGen *g, Buf *lib_path);
void codegen_set_output_path(CodeGen *g, Buf *path);
void codegen_add_time_event(CodeGen *g, const char *name);
void codegen_print_timing_report(CodeGen *g, FILE *f);
diff --git a/src/error.cpp b/src/error.cpp
@@ -34,6 +34,15 @@ const char *err_str(Error err) {
case ErrorPipeBusy: return "pipe busy";
case ErrorPrimitiveTypeNotFound: return "primitive type not found";
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)";
}
diff --git a/src/error.hpp b/src/error.hpp
@@ -36,6 +36,15 @@ enum Error {
ErrorPipeBusy,
ErrorPrimitiveTypeNotFound,
ErrorCacheUnavailable,
+ ErrorPathTooLong,
+ ErrorCCompilerCannotFindFile,
+ ErrorReadingDepFile,
+ ErrorMissingArchitecture,
+ ErrorMissingOperatingSystem,
+ ErrorUnknownArchitecture,
+ ErrorUnknownOperatingSystem,
+ ErrorUnknownABI,
+ ErrorInvalidFilename,
};
const char *err_str(Error err);
diff --git a/src/ir.cpp b/src/ir.cpp
@@ -61,7 +61,7 @@ enum ConstCastResultId {
ConstCastResultIdType,
ConstCastResultIdUnresolvedInferredErrSet,
ConstCastResultIdAsyncAllocatorType,
- ConstCastResultIdNullWrapPtr
+ ConstCastResultIdBadAllowsZero,
};
struct ConstCastOnly;
@@ -83,6 +83,7 @@ struct ConstCastErrUnionErrSetMismatch;
struct ConstCastErrUnionPayloadMismatch;
struct ConstCastErrSetMismatch;
struct ConstCastTypeMismatch;
+struct ConstCastBadAllowsZero;
struct ConstCastOnly {
ConstCastResultId id;
@@ -99,6 +100,7 @@ struct ConstCastOnly {
ConstCastOnly *null_wrap_ptr_child;
ConstCastArg fn_arg;
ConstCastArgNoAlias arg_no_alias;
+ ConstCastBadAllowsZero *bad_allows_zero;
} data;
};
@@ -141,6 +143,12 @@ struct ConstCastErrSetMismatch {
ZigList<ErrorTableEntry *> missing_errors;
};
+struct ConstCastBadAllowsZero {
+ ZigType *wanted_type;
+ ZigType *actual_type;
+};
+
+
enum UndefAllowed {
UndefOk,
UndefBad,
@@ -164,11 +172,15 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node,
ConstExprValue *out_val, ConstExprValue *ptr_val);
static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *ptr,
- ZigType *dest_type, IrInstruction *dest_type_src);
+ ZigType *dest_type, IrInstruction *dest_type_src, bool safety_check_on);
static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed);
static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_global_refs);
static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align);
static void ir_add_alloca(IrAnalyze *ira, IrInstruction *instruction, ZigType *type_entry);
+static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target,
+ ZigType *ptr_type);
+static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
+ ZigType *dest_type);
static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) {
assert(get_src_ptr_type(const_val->type) != nullptr);
@@ -186,10 +198,11 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c
result = &array_val->data.x_array.data.s_none.elements[const_val->data.x_ptr.data.base_array.elem_index];
break;
}
- case ConstPtrSpecialBaseStruct:
- result = &const_val->data.x_ptr.data.base_struct.struct_val->data.x_struct.fields[
- const_val->data.x_ptr.data.base_struct.field_index];
+ case ConstPtrSpecialBaseStruct: {
+ ConstExprValue *struct_val = const_val->data.x_ptr.data.base_struct.struct_val;
+ result = &struct_val->data.x_struct.fields[const_val->data.x_ptr.data.base_struct.field_index];
break;
+ }
case ConstPtrSpecialBaseErrorUnionCode:
result = const_val->data.x_ptr.data.base_err_union_code.err_union_val->data.x_err_union.error_set;
break;
@@ -218,20 +231,55 @@ static bool is_opt_err_set(ZigType *ty) {
(ty->id == ZigTypeIdOptional && ty->data.maybe.child_type->id == ZigTypeIdErrorSet);
}
+// This function returns true when you can change the type of a ConstExprValue and the
+// value remains meaningful.
static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) {
if (a == b)
return true;
- if (a->id == b->id)
- return true;
-
if (get_codegen_ptr_type(a) != nullptr && get_codegen_ptr_type(b) != nullptr)
return true;
if (is_opt_err_set(a) && is_opt_err_set(b))
return true;
- return false;
+ if (a->id != b->id)
+ return false;
+
+ switch (a->id) {
+ case ZigTypeIdInvalid:
+ case ZigTypeIdUnreachable:
+ zig_unreachable();
+ case ZigTypeIdMetaType:
+ case ZigTypeIdVoid:
+ case ZigTypeIdBool:
+ case ZigTypeIdComptimeFloat:
+ case ZigTypeIdComptimeInt:
+ case ZigTypeIdPointer:
+ case ZigTypeIdUndefined:
+ case ZigTypeIdNull:
+ case ZigTypeIdNamespace:
+ case ZigTypeIdBoundFn:
+ case ZigTypeIdErrorSet:
+ case ZigTypeIdOpaque:
+ return true;
+ case ZigTypeIdFloat:
+ return a->data.floating.bit_count == b->data.floating.bit_count;
+ case ZigTypeIdInt:
+ return a->data.integral.is_signed == b->data.integral.is_signed;
+ case ZigTypeIdArray:
+ case ZigTypeIdStruct:
+ case ZigTypeIdOptional:
+ case ZigTypeIdErrorUnion:
+ case ZigTypeIdEnum:
+ case ZigTypeIdUnion:
+ case ZigTypeIdFn:
+ case ZigTypeIdArgTuple:
+ case ZigTypeIdPromise:
+ case ZigTypeIdVector:
+ return false;
+ }
+ zig_unreachable();
}
static bool ir_should_inline(IrExecutable *exec, Scope *scope) {
@@ -368,6 +416,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionLoadPtr *) {
return IrInstructionIdLoadPtr;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionLoadPtrGen *) {
+ return IrInstructionIdLoadPtrGen;
+}
+
static constexpr IrInstructionId ir_instruction_id(IrInstructionStorePtr *) {
return IrInstructionIdStorePtr;
}
@@ -408,6 +460,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCast *) {
return IrInstructionIdCast;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionResizeSlice *) {
+ return IrInstructionIdResizeSlice;
+}
+
static constexpr IrInstructionId ir_instruction_id(IrInstructionContainerInitList *) {
return IrInstructionIdContainerInitList;
}
@@ -688,6 +744,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCast *) {
return IrInstructionIdBitCast;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCastGen *) {
+ return IrInstructionIdBitCastGen;
+}
+
static constexpr IrInstructionId ir_instruction_id(IrInstructionWidenOrShorten *) {
return IrInstructionIdWidenOrShorten;
}
@@ -1291,14 +1351,23 @@ static IrInstruction *ir_build_ptr_type(IrBuilder *irb, Scope *scope, AstNode *s
return &ptr_type_of_instruction->base;
}
-static IrInstruction *ir_build_un_op(IrBuilder *irb, Scope *scope, AstNode *source_node, IrUnOp op_id, IrInstruction *value) {
- IrInstructionUnOp *br_instruction = ir_build_instruction<IrInstructionUnOp>(irb, scope, source_node);
- br_instruction->op_id = op_id;
- br_instruction->value = value;
+static IrInstruction *ir_build_un_op_lval(IrBuilder *irb, Scope *scope, AstNode *source_node, IrUnOp op_id,
+ IrInstruction *value, LVal lval)
+{
+ IrInstructionUnOp *instruction = ir_build_instruction<IrInstructionUnOp>(irb, scope, source_node);
+ instruction->op_id = op_id;
+ instruction->value = value;
+ instruction->lval = lval;
ir_ref_instruction(value, irb->current_basic_block);
- return &br_instruction->base;
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_un_op(IrBuilder *irb, Scope *scope, AstNode *source_node, IrUnOp op_id,
+ IrInstruction *value)
+{
+ return ir_build_un_op_lval(irb, scope, source_node, op_id, value, LValNone);
}
static IrInstruction *ir_build_container_init_list(IrBuilder *irb, Scope *scope, AstNode *source_node,
@@ -1418,6 +1487,19 @@ static IrInstruction *ir_build_var_decl_gen(IrAnalyze *ira, IrInstruction *sourc
return &decl_var_instruction->base;
}
+static IrInstruction *ir_build_resize_slice(IrAnalyze *ira, IrInstruction *source_instruction,
+ IrInstruction *operand, ZigType *ty)
+{
+ IrInstructionResizeSlice *instruction = ir_build_instruction<IrInstructionResizeSlice>(&ira->new_irb,
+ source_instruction->scope, source_instruction->source_node);
+ instruction->base.value.type = ty;
+ instruction->operand = operand;
+
+ ir_ref_instruction(operand, ira->new_irb.current_basic_block);
+
+ return &instruction->base;
+}
+
static IrInstruction *ir_build_export(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *name, IrInstruction *target, IrInstruction *linkage)
{
@@ -2190,12 +2272,13 @@ static IrInstruction *ir_build_test_comptime(IrBuilder *irb, Scope *scope, AstNo
}
static IrInstruction *ir_build_ptr_cast_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *dest_type, IrInstruction *ptr)
+ IrInstruction *dest_type, IrInstruction *ptr, bool safety_check_on)
{
IrInstructionPtrCastSrc *instruction = ir_build_instruction<IrInstructionPtrCastSrc>(
irb, scope, source_node);
instruction->dest_type = dest_type;
instruction->ptr = ptr;
+ instruction->safety_check_on = safety_check_on;
ir_ref_instruction(dest_type, irb->current_basic_block);
ir_ref_instruction(ptr, irb->current_basic_block);
@@ -2204,12 +2287,26 @@ static IrInstruction *ir_build_ptr_cast_src(IrBuilder *irb, Scope *scope, AstNod
}
static IrInstruction *ir_build_ptr_cast_gen(IrAnalyze *ira, IrInstruction *source_instruction,
- ZigType *ptr_type, IrInstruction *ptr)
+ ZigType *ptr_type, IrInstruction *ptr, bool safety_check_on)
{
IrInstructionPtrCastGen *instruction = ir_build_instruction<IrInstructionPtrCastGen>(
&ira->new_irb, source_instruction->scope, source_instruction->source_node);
instruction->base.value.type = ptr_type;
instruction->ptr = ptr;
+ instruction->safety_check_on = safety_check_on;
+
+ ir_ref_instruction(ptr, ira->new_irb.current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_load_ptr_gen(IrAnalyze *ira, IrInstruction *source_instruction,
+ IrInstruction *ptr, ZigType *ty)
+{
+ IrInstructionLoadPtrGen *instruction = ir_build_instruction<IrInstructionLoadPtrGen>(
+ &ira->new_irb, source_instruction->scope, source_instruction->source_node);
+ instruction->base.value.type = ty;
+ instruction->ptr = ptr;
ir_ref_instruction(ptr, ira->new_irb.current_basic_block);
@@ -2224,12 +2321,25 @@ static IrInstruction *ir_build_bit_cast(IrBuilder *irb, Scope *scope, AstNode *s
instruction->dest_type = dest_type;
instruction->value = value;
- if (dest_type) ir_ref_instruction(dest_type, irb->current_basic_block);
+ ir_ref_instruction(dest_type, irb->current_basic_block);
ir_ref_instruction(value, irb->current_basic_block);
return &instruction->base;
}
+static IrInstruction *ir_build_bit_cast_gen(IrAnalyze *ira, IrInstruction *source_instruction,
+ IrInstruction *operand, ZigType *ty)
+{
+ IrInstructionBitCastGen *instruction = ir_build_instruction<IrInstructionBitCastGen>(
+ &ira->new_irb, source_instruction->scope, source_instruction->source_node);
+ instruction->base.value.type = ty;
+ instruction->operand = operand;
+
+ ir_ref_instruction(operand, ira->new_irb.current_basic_block);
+
+ return &instruction->base;
+}
+
static IrInstruction *ir_build_widen_or_shorten(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *target)
{
@@ -2458,7 +2568,7 @@ static IrInstruction *ir_build_type_info(IrBuilder *irb, Scope *scope, AstNode *
ir_ref_instruction(type_value, irb->current_basic_block);
- return &instruction->base;
+ return &instruction->base;
}
static IrInstruction *ir_build_type_id(IrBuilder *irb, Scope *scope, AstNode *source_node,
@@ -3651,6 +3761,22 @@ static IrInstruction *ir_gen_null_literal(IrBuilder *irb, Scope *scope, AstNode
return ir_build_const_null(irb, scope, node);
}
+static void populate_invalid_variable_in_scope(CodeGen *g, Scope *scope, AstNode *node, Buf *var_name) {
+ ScopeDecls *scope_decls = nullptr;
+ while (scope != nullptr) {
+ if (scope->id == ScopeIdDecls) {
+ scope_decls = reinterpret_cast<ScopeDecls *>(scope);
+ }
+ scope = scope->parent;
+ }
+ TldVar *tld_var = allocate<TldVar>(1);
+ init_tld(&tld_var->base, TldIdVar, var_name, VisibModPub, node, &scope_decls->base);
+ tld_var->base.resolution = TldResolutionInvalid;
+ tld_var->var = add_variable(g, node, &scope_decls->base, var_name, false,
+ &g->invalid_instruction->value, &tld_var->base, g->builtin_types.entry_invalid);
+ scope_decls->decl_table.put(var_name, &tld_var->base);
+}
+
static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
Error err;
assert(node->type == NodeTypeSymbol);
@@ -3704,8 +3830,9 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node,
return irb->codegen->invalid_instruction;
}
- // TODO put a variable of same name with invalid type in global scope
+ // put a variable of same name with invalid type in global scope
// so that future references to this same name will find a variable with an invalid type
+ populate_invalid_variable_in_scope(irb->codegen, scope, node, variable_name);
add_node_error(irb->codegen, node, buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name)));
return irb->codegen->invalid_instruction;
}
@@ -4493,7 +4620,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
- IrInstruction *ptr_cast = ir_build_ptr_cast_src(irb, scope, node, arg0_value, arg1_value);
+ IrInstruction *ptr_cast = ir_build_ptr_cast_src(irb, scope, node, arg0_value, arg1_value, true);
return ir_lval_wrap(irb, scope, ptr_cast, lval);
}
case BuiltinFnIdBitCast:
@@ -5019,10 +5146,23 @@ static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *
return ir_build_ref(irb, scope, value->source_node, value, false, false);
}
+static PtrLen star_token_to_ptr_len(TokenId token_id) {
+ switch (token_id) {
+ case TokenIdStar:
+ case TokenIdStarStar:
+ return PtrLenSingle;
+ case TokenIdBracketStarBracket:
+ return PtrLenUnknown;
+ case TokenIdBracketStarCBracket:
+ return PtrLenC;
+ default:
+ zig_unreachable();
+ }
+}
+
static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode *node) {
assert(node->type == NodeTypePointerType);
- PtrLen ptr_len = (node->data.pointer_type.star_token->id == TokenIdStar ||
- node->data.pointer_type.star_token->id == TokenIdStarStar) ? PtrLenSingle : PtrLenUnknown;
+ PtrLen ptr_len = star_token_to_ptr_len(node->data.pointer_type.star_token->id);
bool is_const = node->data.pointer_type.is_const;
bool is_volatile = node->data.pointer_type.is_volatile;
AstNode *expr_node = node->data.pointer_type.op_expr;
@@ -6715,14 +6855,15 @@ static IrInstruction *ir_gen_cancel_target(IrBuilder *irb, Scope *scope, AstNode
IrInstruction *is_suspended_mask = ir_build_const_usize(irb, scope, node, 0x2); // 0b010
// TODO relies on Zig not re-ordering fields
- IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst);
+ IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst,
+ false);
IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst);
Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
atomic_state_field_name);
// set the is_canceled bit
- IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
+ IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
usize_type_val, atomic_state_ptr, nullptr, is_canceled_mask, nullptr,
AtomicRmwOp_or, AtomicOrderSeqCst);
@@ -6793,14 +6934,15 @@ static IrInstruction *ir_gen_resume_target(IrBuilder *irb, Scope *scope, AstNode
get_promise_type(irb->codegen, irb->codegen->builtin_types.entry_void));
// TODO relies on Zig not re-ordering fields
- IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst);
+ IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst,
+ false);
IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst);
Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
atomic_state_field_name);
// clear the is_suspended bit
- IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
+ IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
usize_type_val, atomic_state_ptr, nullptr, and_mask, nullptr,
AtomicRmwOp_and, AtomicOrderSeqCst);
@@ -6916,7 +7058,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
IrInstruction *coro_handle_addr = ir_build_ptr_to_int(irb, scope, node, irb->exec->coro_handle);
IrInstruction *mask_bits = ir_build_bin_op(irb, scope, node, IrBinOpBinOr, coro_handle_addr, await_mask, false);
- IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
+ IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
usize_type_val, atomic_state_ptr, nullptr, mask_bits, nullptr,
AtomicRmwOp_or, AtomicOrderSeqCst);
@@ -6959,7 +7101,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
ir_set_cursor_at_end_and_append_block(irb, yes_suspend_block);
- IrInstruction *my_prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
+ IrInstruction *my_prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
usize_type_val, irb->exec->atomic_state_field_ptr, nullptr, is_suspended_mask, nullptr,
AtomicRmwOp_or, AtomicOrderSeqCst);
IrInstruction *my_is_suspended_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, my_prev_atomic_value, is_suspended_mask, false);
@@ -6991,7 +7133,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
ir_set_cursor_at_end_and_append_block(irb, cleanup_block);
IrInstruction *my_mask_bits = ir_build_bin_op(irb, scope, node, IrBinOpBinOr, ptr_mask, is_canceled_mask, false);
- IrInstruction *b_my_prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
+ IrInstruction *b_my_prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
usize_type_val, irb->exec->atomic_state_field_ptr, nullptr, my_mask_bits, nullptr,
AtomicRmwOp_or, AtomicOrderSeqCst);
IrInstruction *my_await_handle_addr = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, b_my_prev_atomic_value, ptr_mask, false);
@@ -7194,7 +7336,10 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
if (value == irb->codegen->invalid_instruction)
return value;
- return ir_build_un_op(irb, scope, node, IrUnOpDereference, value);
+ // We essentially just converted any lvalue from &(x.*) to (&x).*;
+ // this inhibits checking that x is a pointer later, so we directly
+ // record whether the pointer check is needed
+ return ir_build_un_op_lval(irb, scope, node, IrUnOpDereference, value, lval);
}
case NodeTypeUnwrapOptional: {
AstNode *expr_node = node->data.unwrap_optional.expr;
@@ -7338,7 +7483,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
u8_ptr_type = ir_build_const_type(irb, coro_scope, node,
get_pointer_to_type(irb->codegen, irb->codegen->builtin_types.entry_u8, false));
- IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, coro_promise_ptr);
+ IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type,
+ coro_promise_ptr, false);
coro_id = ir_build_coro_id(irb, coro_scope, node, promise_as_u8_ptr);
coro_size_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
IrInstruction *coro_size = ir_build_coro_size(irb, coro_scope, node);
@@ -7362,7 +7508,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
ir_build_return(irb, coro_scope, node, undef);
ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block);
- IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr);
+ IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr,
+ false);
irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr);
Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
@@ -7440,9 +7587,10 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8,
false, false, PtrLenUnknown, 0, 0, 0));
IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr);
- IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, result_ptr);
- IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len,
- irb->exec->coro_result_field_ptr);
+ IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len,
+ result_ptr, false);
+ IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node,
+ u8_ptr_type_unknown_len, irb->exec->coro_result_field_ptr, false);
IrInstruction *return_type_inst = ir_build_const_type(irb, scope, node,
fn_entry->type_entry->data.fn.fn_type_id.return_type);
IrInstruction *size_of_ret_val = ir_build_size_of(irb, scope, node, return_type_inst);
@@ -7492,7 +7640,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node,
get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8,
false, false, PtrLenUnknown, 0, 0, 0));
- IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, coro_mem_ptr_maybe);
+ IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len,
+ coro_mem_ptr_maybe, false);
IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false);
IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var);
IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr);
@@ -8619,7 +8768,6 @@ static ZigType *get_error_set_intersection(IrAnalyze *ira, ZigType *set1, ZigTyp
return err_set_type;
}
-
static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted_type,
ZigType *actual_type, AstNode *source_node, bool wanted_is_mutable)
{
@@ -8632,53 +8780,63 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
if (wanted_type == actual_type)
return result;
- // *T and [*]T may const-cast-only to ?*U and ?[*]U, respectively
- // but not if we want a mutable pointer
- // and not if the actual pointer has zero bits
- if (!wanted_is_mutable && wanted_type->id == ZigTypeIdOptional &&
- wanted_type->data.maybe.child_type->id == ZigTypeIdPointer &&
- actual_type->id == ZigTypeIdPointer && type_has_bits(actual_type))
- {
- ConstCastOnly child = types_match_const_cast_only(ira,
- wanted_type->data.maybe.child_type, actual_type, source_node, wanted_is_mutable);
- if (child.id == ConstCastResultIdInvalid)
- return child;
- if (child.id != ConstCastResultIdOk) {
- result.id = ConstCastResultIdNullWrapPtr;
- result.data.null_wrap_ptr_child = allocate_nonzero<ConstCastOnly>(1);
- *result.data.null_wrap_ptr_child = child;
- }
- return result;
- }
-
- // pointer const
- if (wanted_type->id == ZigTypeIdPointer && actual_type->id == ZigTypeIdPointer) {
- ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
- actual_type->data.pointer.child_type, source_node, !wanted_type->data.pointer.is_const);
+ // If pointers have the same representation in memory, they can be "const-casted".
+ // `const` attribute can be gained
+ // `volatile` attribute can be gained
+ // `allowzero` attribute can be gained (whether from explicit attribute, C pointer, or optional pointer)
+ // but only if !wanted_is_mutable
+ // alignment can be decreased
+ // bit offset attributes must match exactly
+ // PtrLenSingle/PtrLenUnknown must match exactly, but PtrLenC matches either one
+ ZigType *wanted_ptr_type = get_src_ptr_type(wanted_type);
+ ZigType *actual_ptr_type = get_src_ptr_type(actual_type);
+ bool wanted_allows_zero = ptr_allows_addr_zero(wanted_type);
+ bool actual_allows_zero = ptr_allows_addr_zero(actual_type);
+ bool wanted_is_c_ptr = wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenC;
+ bool actual_is_c_ptr = actual_type->id == ZigTypeIdPointer && actual_type->data.pointer.ptr_len == PtrLenC;
+ bool wanted_opt_or_ptr = wanted_ptr_type != nullptr &&
+ (wanted_type->id == ZigTypeIdPointer || wanted_type->id == ZigTypeIdOptional);
+ bool actual_opt_or_ptr = actual_ptr_type != nullptr &&
+ (actual_type->id == ZigTypeIdPointer || actual_type->id == ZigTypeIdOptional);
+ if (wanted_opt_or_ptr && actual_opt_or_ptr) {
+ ConstCastOnly child = types_match_const_cast_only(ira, wanted_ptr_type->data.pointer.child_type,
+ actual_ptr_type->data.pointer.child_type, source_node, !wanted_ptr_type->data.pointer.is_const);
if (child.id == ConstCastResultIdInvalid)
return child;
if (child.id != ConstCastResultIdOk) {
result.id = ConstCastResultIdPointerChild;
result.data.pointer_mismatch = allocate_nonzero<ConstCastPointerMismatch>(1);
result.data.pointer_mismatch->child = child;
- result.data.pointer_mismatch->wanted_child = wanted_type->data.pointer.child_type;
- result.data.pointer_mismatch->actual_child = actual_type->data.pointer.child_type;
+ result.data.pointer_mismatch->wanted_child = wanted_ptr_type->data.pointer.child_type;
+ result.data.pointer_mismatch->actual_child = actual_ptr_type->data.pointer.child_type;
+ return result;
+ }
+ bool ok_allows_zero = (wanted_allows_zero &&
+ (actual_allows_zero || !wanted_is_mutable)) ||
+ (!wanted_allows_zero && !actual_allows_zero);
+ if (!ok_allows_zero) {
+ result.id = ConstCastResultIdBadAllowsZero;
+ result.data.bad_allows_zero = allocate_nonzero<ConstCastBadAllowsZero>(1);
+ result.data.bad_allows_zero->wanted_type = wanted_type;
+ result.data.bad_allows_zero->actual_type = actual_type;
return result;
}
- if ((err = type_resolve(g, actual_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) {
+ if ((err = type_resolve(g, actual_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) {
result.id = ConstCastResultIdInvalid;
return result;
}
- if ((err = type_resolve(g, wanted_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) {
+ if ((err = type_resolve(g, wanted_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) {
result.id = ConstCastResultIdInvalid;
return result;
}
- if ((actual_type->data.pointer.ptr_len == wanted_type->data.pointer.ptr_len) &&
- (!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const) &&
- (!actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile) &&
- actual_type->data.pointer.bit_offset_in_host == wanted_type->data.pointer.bit_offset_in_host &&
- actual_type->data.pointer.host_int_bytes == wanted_type->data.pointer.host_int_bytes &&
- get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, wanted_type))
+ bool ptr_lens_equal = actual_ptr_type->data.pointer.ptr_len == wanted_ptr_type->data.pointer.ptr_len;
+ if ((ptr_lens_equal || wanted_is_c_ptr || actual_is_c_ptr) &&
+ type_has_bits(wanted_type) == type_has_bits(actual_type) &&
+ (!actual_ptr_type->data.pointer.is_const || wanted_ptr_type->data.pointer.is_const) &&
+ (!actual_ptr_type->data.pointer.is_volatile || wanted_ptr_type->data.pointer.is_volatile) &&
+ actual_ptr_type->data.pointer.bit_offset_in_host == wanted_ptr_type->data.pointer.bit_offset_in_host &&
+ actual_ptr_type->data.pointer.host_int_bytes == wanted_ptr_type->data.pointer.host_int_bytes &&
+ get_ptr_align(ira->codegen, actual_ptr_type) >= get_ptr_align(ira->codegen, wanted_ptr_type))
{
return result;
}
@@ -8912,7 +9070,9 @@ static void update_errors_helper(CodeGen *g, ErrorTableEntry ***errors, size_t *
*errors = reallocate(*errors, old_errors_count, *errors_count);
}
-static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigType *expected_type, IrInstruction **instructions, size_t instruction_count) {
+static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigType *expected_type,
+ IrInstruction **instructions, size_t instruction_count)
+{
Error err;
assert(instruction_count >= 1);
IrInstruction *prev_inst = instructions[0];
@@ -9229,6 +9389,37 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
continue;
}
+ if (prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenC &&
+ (cur_type->id == ZigTypeIdComptimeInt || cur_type->id == ZigTypeIdInt))
+ {
+ continue;
+ }
+
+ if (cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenC &&
+ (prev_type->id == ZigTypeIdComptimeInt || prev_type->id == ZigTypeIdInt))
+ {
+ prev_inst = cur_inst;
+ continue;
+ }
+
+ if (prev_type->id == ZigTypeIdPointer && cur_type->id == ZigTypeIdPointer) {
+ if (prev_type->data.pointer.ptr_len == PtrLenC &&
+ types_match_const_cast_only(ira, prev_type->data.pointer.child_type,
+ cur_type->data.pointer.child_type, source_node,
+ !prev_type->data.pointer.is_const).id == ConstCastResultIdOk)
+ {
+ continue;
+ }
+ if (cur_type->data.pointer.ptr_len == PtrLenC &&
+ types_match_const_cast_only(ira, cur_type->data.pointer.child_type,
+ prev_type->data.pointer.child_type, source_node,
+ !cur_type->data.pointer.is_const).id == ConstCastResultIdOk)
+ {
+ prev_inst = cur_inst;
+ continue;
+ }
+ }
+
if (types_match_const_cast_only(ira, prev_type, cur_type, source_node, false).id == ConstCastResultIdOk) {
continue;
}
@@ -9534,9 +9725,6 @@ static bool eval_const_expr_implicit_cast(IrAnalyze *ira, IrInstruction *source_
}
const_val->type = new_type;
break;
- case CastOpResizeSlice:
- // can't do it
- zig_unreachable();
case CastOpIntToFloat:
{
assert(new_type->id == ZigTypeIdFloat);
@@ -9600,9 +9788,7 @@ static IrInstruction *ir_const(IrAnalyze *ira, IrInstruction *old_instruction, Z
static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
ZigType *wanted_type, CastOp cast_op, bool need_alloca)
{
- if ((instr_is_comptime(value) || !type_has_bits(wanted_type)) &&
- cast_op != CastOpResizeSlice)
- {
+ if (instr_is_comptime(value) || !type_has_bits(wanted_type)) {
IrInstruction *result = ir_const(ira, source_instr, wanted_type);
if (!eval_const_expr_implicit_cast(ira, source_instr, cast_op, &value->value, value->value.type,
&result->value, wanted_type))
@@ -9864,7 +10050,7 @@ static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, Un
if (undef_allowed == UndefOk) {
return &value->value;
} else {
- ir_add_error(ira, value, buf_sprintf("use of undefined value"));
+ ir_add_error(ira, value, buf_sprintf("use of undefined value here causes undefined behavior"));
return nullptr;
}
}
@@ -9874,7 +10060,7 @@ static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, Un
ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,
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,
- IrExecutable *parent_exec)
+ IrExecutable *parent_exec, AstNode *expected_type_source_node)
{
if (expected_type != nullptr && type_is_invalid(expected_type))
return &codegen->invalid_instruction->value;
@@ -9910,7 +10096,7 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod
analyzed_executable->backward_branch_count = backward_branch_count;
analyzed_executable->backward_branch_quota = backward_branch_quota;
analyzed_executable->begin_scope = scope;
- ZigType *result_type = ir_analyze(codegen, ir_executable, analyzed_executable, expected_type, node);
+ ZigType *result_type = ir_analyze(codegen, ir_executable, analyzed_executable, expected_type, expected_type_source_node);
if (type_is_invalid(result_type))
return &codegen->invalid_instruction->value;
@@ -10230,49 +10416,75 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s
return result;
}
-static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *source_instr,
- IrInstruction *target, ZigType *wanted_type)
-{
+static ZigType *ir_resolve_union_tag_type(IrAnalyze *ira, IrInstruction *source_instr, ZigType *union_type) {
+ assert(union_type->id == ZigTypeIdUnion);
+
Error err;
- assert(wanted_type->id == ZigTypeIdInt || wanted_type->id == ZigTypeIdComptimeInt);
+ if ((err = type_resolve(ira->codegen, union_type, ResolveStatusSizeKnown)))
+ return ira->codegen->builtin_types.entry_invalid;
- ZigType *actual_type = target->value.type;
- if ((err = ensure_complete_type(ira->codegen, actual_type)))
- return ira->codegen->invalid_instruction;
+ AstNode *decl_node = union_type->data.unionation.decl_node;
+ if (decl_node->data.container_decl.auto_enum || decl_node->data.container_decl.init_arg_expr != nullptr) {
+ assert(union_type->data.unionation.tag_type != nullptr);
+ return union_type->data.unionation.tag_type;
+ } else {
+ ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("union '%s' has no tag",
+ buf_ptr(&union_type->name)));
+ add_error_note(ira->codegen, msg, decl_node, buf_sprintf("consider 'union(enum)' here"));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+}
- if (wanted_type != actual_type->data.enumeration.tag_int_type) {
- ir_add_error(ira, source_instr,
- buf_sprintf("enum to integer cast to '%s' instead of its tag type, '%s'",
- buf_ptr(&wanted_type->name),
- buf_ptr(&actual_type->data.enumeration.tag_int_type->name)));
+static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target) {
+ Error err;
+
+ IrInstruction *enum_target;
+ ZigType *enum_type;
+ if (target->value.type->id == ZigTypeIdUnion) {
+ enum_type = ir_resolve_union_tag_type(ira, target, target->value.type);
+ if (type_is_invalid(enum_type))
+ return ira->codegen->invalid_instruction;
+ enum_target = ir_implicit_cast(ira, target, enum_type);
+ if (type_is_invalid(enum_target->value.type))
+ return ira->codegen->invalid_instruction;
+ } else if (target->value.type->id == ZigTypeIdEnum) {
+ enum_target = target;
+ enum_type = target->value.type;
+ } else {
+ ir_add_error(ira, target,
+ buf_sprintf("expected enum, found type '%s'", buf_ptr(&target->value.type->name)));
return ira->codegen->invalid_instruction;
}
- assert(actual_type->id == ZigTypeIdEnum);
+ if ((err = type_resolve(ira->codegen, enum_type, ResolveStatusSizeKnown)))
+ return ira->codegen->invalid_instruction;
- if (instr_is_comptime(target)) {
- ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
+ ZigType *tag_type = enum_type->data.enumeration.tag_int_type;
+ assert(tag_type->id == ZigTypeIdInt || tag_type->id == ZigTypeIdComptimeInt);
+
+ if (instr_is_comptime(enum_target)) {
+ ConstExprValue *val = ir_resolve_const(ira, enum_target, UndefBad);
if (!val)
return ira->codegen->invalid_instruction;
- IrInstruction *result = ir_const(ira, source_instr, wanted_type);
- init_const_bigint(&result->value, wanted_type, &val->data.x_enum_tag);
+ IrInstruction *result = ir_const(ira, source_instr, tag_type);
+ init_const_bigint(&result->value, tag_type, &val->data.x_enum_tag);
return result;
}
// If there is only one possible tag, then we know at comptime what it is.
- if (actual_type->data.enumeration.layout == ContainerLayoutAuto &&
- actual_type->data.enumeration.src_field_count == 1)
+ if (enum_type->data.enumeration.layout == ContainerLayoutAuto &&
+ enum_type->data.enumeration.src_field_count == 1)
{
- assert(wanted_type== ira->codegen->builtin_types.entry_num_lit_int);
- IrInstruction *result = ir_const(ira, source_instr, wanted_type);
- init_const_bigint(&result->value, wanted_type,
- &actual_type->data.enumeration.fields[0].value);
+ assert(tag_type == ira->codegen->builtin_types.entry_num_lit_int);
+ IrInstruction *result = ir_const(ira, source_instr, tag_type);
+ init_const_bigint(&result->value, tag_type,
+ &enum_type->data.enumeration.fields[0].value);
return result;
}
IrInstruction *result = ir_build_widen_or_shorten(&ira->new_irb, source_instr->scope,
- source_instr->source_node, target);
- result->value.type = wanted_type;
+ source_instr->source_node, enum_target);
+ result->value.type = tag_type;
return result;
}
@@ -10770,17 +10982,37 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa
report_recursive_error(ira, source_node, cast_result->data.fn_arg.child, msg);
break;
}
+ case ConstCastResultIdBadAllowsZero: {
+ ZigType *wanted_type = cast_result->data.bad_allows_zero->wanted_type;
+ ZigType *actual_type = cast_result->data.bad_allows_zero->actual_type;
+ bool wanted_allows_zero = ptr_allows_addr_zero(wanted_type);
+ bool actual_allows_zero = ptr_allows_addr_zero(actual_type);
+ if (actual_allows_zero && !wanted_allows_zero) {
+ add_error_note(ira->codegen, parent_msg, source_node,
+ buf_sprintf("'%s' could have null values which are illegal in type '%s'",
+ buf_ptr(&actual_type->name),
+ buf_ptr(&wanted_type->name)));
+ } else {
+ add_error_note(ira->codegen, parent_msg, source_node,
+ buf_sprintf("mutable '%s' allows illegal null values stored to type '%s'",
+ buf_ptr(&wanted_type->name),
+ buf_ptr(&actual_type->name)));
+ }
+ break;
+ }
+ case ConstCastResultIdFnIsGeneric:
+ add_error_note(ira->codegen, parent_msg, source_node,
+ buf_sprintf("only one of the functions is generic"));
+ break;
case ConstCastResultIdFnAlign: // TODO
case ConstCastResultIdFnCC: // TODO
case ConstCastResultIdFnVarArgs: // TODO
- case ConstCastResultIdFnIsGeneric: // TODO
case ConstCastResultIdFnReturnType: // TODO
case ConstCastResultIdFnArgCount: // TODO
case ConstCastResultIdFnGenericArgCount: // TODO
case ConstCastResultIdFnArgNoAlias: // TODO
case ConstCastResultIdUnresolvedInferredErrSet: // TODO
case ConstCastResultIdAsyncAllocatorType: // TODO
- case ConstCastResultIdNullWrapPtr: // TODO
break;
}
}
@@ -10811,6 +11043,39 @@ static IrInstruction *ir_analyze_vector_to_array(IrAnalyze *ira, IrInstruction *
return ir_build_vector_to_array(ira, source_instr, vector, array_type);
}
+static IrInstruction *ir_analyze_int_to_c_ptr(IrAnalyze *ira, IrInstruction *source_instr,
+ IrInstruction *integer, ZigType *dest_type)
+{
+ IrInstruction *unsigned_integer;
+ if (instr_is_comptime(integer)) {
+ unsigned_integer = integer;
+ } else {
+ assert(integer->value.type->id == ZigTypeIdInt);
+
+ if (integer->value.type->data.integral.bit_count >
+ ira->codegen->builtin_types.entry_usize->data.integral.bit_count)
+ {
+ ir_add_error(ira, source_instr,
+ buf_sprintf("integer type '%s' too big for implicit @intToPtr to type '%s'",
+ buf_ptr(&integer->value.type->name),
+ buf_ptr(&dest_type->name)));
+ return ira->codegen->invalid_instruction;
+ }
+
+ if (integer->value.type->data.integral.is_signed) {
+ ZigType *unsigned_int_type = get_int_type(ira->codegen, false,
+ integer->value.type->data.integral.bit_count);
+ unsigned_integer = ir_analyze_bit_cast(ira, source_instr, integer, unsigned_int_type);
+ if (type_is_invalid(unsigned_integer->value.type))
+ return ira->codegen->invalid_instruction;
+ } else {
+ unsigned_integer = integer;
+ }
+ }
+
+ return ir_analyze_int_to_ptr(ira, source_instr, unsigned_integer, dest_type);
+}
+
static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr,
ZigType *wanted_type, IrInstruction *value)
{
@@ -11182,7 +11447,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
actual_type->data.pointer.host_int_bytes == dest_ptr_type->data.pointer.host_int_bytes &&
get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, dest_ptr_type))
{
- return ir_analyze_ptr_cast(ira, source_instr, value, wanted_type, source_instr);
+ return ir_analyze_ptr_cast(ira, source_instr, value, wanted_type, source_instr, true);
}
}
@@ -11217,6 +11482,23 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
return ir_analyze_array_to_vector(ira, source_instr, value, wanted_type);
}
+ // casting between C pointers and normal pointers
+ if (wanted_type->id == ZigTypeIdPointer && actual_type->id == ZigTypeIdPointer &&
+ (wanted_type->data.pointer.ptr_len == PtrLenC || actual_type->data.pointer.ptr_len == PtrLenC) &&
+ types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
+ actual_type->data.pointer.child_type, source_node,
+ !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk)
+ {
+ return ir_analyze_ptr_cast(ira, source_instr, value, wanted_type, source_instr, true);
+ }
+
+ // cast from integer to C pointer
+ if (wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenC &&
+ (actual_type->id == ZigTypeIdInt || actual_type->id == ZigTypeIdComptimeInt))
+ {
+ return ir_analyze_int_to_c_ptr(ira, source_instr, value, wanted_type);
+ }
+
// cast from undefined to anything
if (actual_type->id == ZigTypeIdUndefined) {
return ir_analyze_undefined_to_anything(ira, source_instr, value, wanted_type);
@@ -11286,13 +11568,14 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
IrInstructionRef *ref_inst = reinterpret_cast<IrInstructionRef *>(ptr);
return ref_inst->value;
}
- IrInstruction *load_ptr_instruction = ir_build_load_ptr(&ira->new_irb, source_instruction->scope,
- source_instruction->source_node, ptr);
- load_ptr_instruction->value.type = child_type;
- return load_ptr_instruction;
+ IrInstruction *result = ir_build_load_ptr_gen(ira, source_instruction, ptr, child_type);
+ if (type_entry->data.pointer.host_int_bytes != 0 && handle_is_ptr(child_type)) {
+ ir_add_alloca(ira, result, child_type);
+ }
+ return result;
} else {
ir_add_error_node(ira, source_instruction->source_node,
- buf_sprintf("attempt to dereference non pointer type '%s'",
+ buf_sprintf("attempt to dereference non-pointer type '%s'",
buf_ptr(&type_entry->name)));
return ira->codegen->invalid_instruction;
}
@@ -11588,28 +11871,34 @@ static IrInstruction *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp
}
static bool resolve_cmp_op_id(IrBinOp op_id, Cmp cmp) {
- if (op_id == IrBinOpCmpEq) {
- return cmp == CmpEQ;
- } else if (op_id == IrBinOpCmpNotEq) {
- return cmp != CmpEQ;
- } else if (op_id == IrBinOpCmpLessThan) {
- return cmp == CmpLT;
- } else if (op_id == IrBinOpCmpGreaterThan) {
- return cmp == CmpGT;
- } else if (op_id == IrBinOpCmpLessOrEq) {
- return cmp != CmpGT;
- } else if (op_id == IrBinOpCmpGreaterOrEq) {
- return cmp != CmpLT;
- } else {
- zig_unreachable();
+ switch (op_id) {
+ case IrBinOpCmpEq:
+ return cmp == CmpEQ;
+ case IrBinOpCmpNotEq:
+ return cmp != CmpEQ;
+ case IrBinOpCmpLessThan:
+ return cmp == CmpLT;
+ case IrBinOpCmpGreaterThan:
+ return cmp == CmpGT;
+ case IrBinOpCmpLessOrEq:
+ return cmp != CmpGT;
+ case IrBinOpCmpGreaterOrEq:
+ return cmp != CmpLT;
+ default:
+ zig_unreachable();
}
}
static bool optional_value_is_null(ConstExprValue *val) {
assert(val->special == ConstValSpecialStatic);
if (get_codegen_ptr_type(val->type) != nullptr) {
- return val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr &&
- val->data.x_ptr.data.hard_coded_addr.addr == 0;
+ if (val->data.x_ptr.special == ConstPtrSpecialNull) {
+ return true;
+ } else if (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) {
+ return val->data.x_ptr.data.hard_coded_addr.addr == 0;
+ } else {
+ return false;
+ }
} else if (is_opt_err_set(val->type)) {
return val->data.x_err_set == nullptr;
} else {
@@ -11773,7 +12062,6 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
case ZigTypeIdBool:
case ZigTypeIdMetaType:
case ZigTypeIdVoid:
- case ZigTypeIdPointer:
case ZigTypeIdErrorSet:
case ZigTypeIdFn:
case ZigTypeIdOpaque:
@@ -11785,6 +12073,10 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
operator_allowed = is_equality_cmp;
break;
+ case ZigTypeIdPointer:
+ operator_allowed = is_equality_cmp || (resolved_type->data.pointer.ptr_len == PtrLenC);
+ break;
+
case ZigTypeIdUnreachable:
case ZigTypeIdArray:
case ZigTypeIdStruct:
@@ -11832,15 +12124,38 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
if (op2_val == nullptr)
return ira->codegen->invalid_instruction;
- bool answer;
if (resolved_type->id == ZigTypeIdComptimeFloat || resolved_type->id == ZigTypeIdFloat) {
Cmp cmp_result = float_cmp(op1_val, op2_val);
- answer = resolve_cmp_op_id(op_id, cmp_result);
+ bool answer = resolve_cmp_op_id(op_id, cmp_result);
+ return ir_const_bool(ira, &bin_op_instruction->base, answer);
} else if (resolved_type->id == ZigTypeIdComptimeInt || resolved_type->id == ZigTypeIdInt) {
Cmp cmp_result = bigint_cmp(&op1_val->data.x_bigint, &op2_val->data.x_bigint);
- answer = resolve_cmp_op_id(op_id, cmp_result);
+ bool answer = resolve_cmp_op_id(op_id, cmp_result);
+ return ir_const_bool(ira, &bin_op_instruction->base, answer);
+ } else if (resolved_type->id == ZigTypeIdPointer && op_id != IrBinOpCmpEq && op_id != IrBinOpCmpNotEq) {
+ if ((op1_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr ||
+ op1_val->data.x_ptr.special == ConstPtrSpecialNull) &&
+ (op2_val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr ||
+ op2_val->data.x_ptr.special == ConstPtrSpecialNull))
+ {
+ uint64_t op1_addr = op1_val->data.x_ptr.special == ConstPtrSpecialNull ?
+ 0 : op1_val->data.x_ptr.data.hard_coded_addr.addr;
+ uint64_t op2_addr = op2_val->data.x_ptr.special == ConstPtrSpecialNull ?
+ 0 : op2_val->data.x_ptr.data.hard_coded_addr.addr;
+ Cmp cmp_result;
+ if (op1_addr > op2_addr) {
+ cmp_result = CmpGT;
+ } else if (op1_addr < op2_addr) {
+ cmp_result = CmpLT;
+ } else {
+ cmp_result = CmpEQ;
+ }
+ bool answer = resolve_cmp_op_id(op_id, cmp_result);
+ return ir_const_bool(ira, &bin_op_instruction->base, answer);
+ }
} else {
bool are_equal = one_possible_value || const_values_equal(ira->codegen, op1_val, op2_val);
+ bool answer;
if (op_id == IrBinOpCmpEq) {
answer = are_equal;
} else if (op_id == IrBinOpCmpNotEq) {
@@ -11848,9 +12163,8 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
} else {
zig_unreachable();
}
+ return ir_const_bool(ira, &bin_op_instruction->base, answer);
}
-
- return ir_const_bool(ira, &bin_op_instruction->base, answer);
}
// some comparisons with unsigned numbers can be evaluated
@@ -12245,7 +12559,29 @@ static bool ok_float_op(IrBinOp op) {
zig_unreachable();
}
+static bool is_pointer_arithmetic_allowed(ZigType *lhs_type, IrBinOp op) {
+ if (lhs_type->id != ZigTypeIdPointer)
+ return false;
+ switch (op) {
+ case IrBinOpAdd:
+ case IrBinOpSub:
+ break;
+ default:
+ return false;
+ }
+ switch (lhs_type->data.pointer.ptr_len) {
+ case PtrLenSingle:
+ return false;
+ case PtrLenUnknown:
+ case PtrLenC:
+ break;
+ }
+ return true;
+}
+
static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *instruction) {
+ Error err;
+
IrInstruction *op1 = instruction->op1->child;
if (type_is_invalid(op1->value.type))
return ira->codegen->invalid_instruction;
@@ -12257,23 +12593,54 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
IrBinOp op_id = instruction->op_id;
// look for pointer math
- if (op1->value.type->id == ZigTypeIdPointer && op1->value.type->data.pointer.ptr_len == PtrLenUnknown &&
- (op_id == IrBinOpAdd || op_id == IrBinOpSub))
- {
+ if (is_pointer_arithmetic_allowed(op1->value.type, op_id)) {
IrInstruction *casted_op2 = ir_implicit_cast(ira, op2, ira->codegen->builtin_types.entry_usize);
- if (casted_op2 == ira->codegen->invalid_instruction)
+ if (type_is_invalid(casted_op2->value.type))
return ira->codegen->invalid_instruction;
- IrInstruction *result = ir_build_bin_op(&ira->new_irb, instruction->base.scope,
- instruction->base.source_node, op_id, op1, casted_op2, true);
- result->value.type = op1->value.type;
- return result;
- }
-
- IrInstruction *instructions[] = {op1, op2};
- ZigType *resolved_type = ir_resolve_peer_types(ira, instruction->base.source_node, nullptr, instructions, 2);
- if (type_is_invalid(resolved_type))
- return ira->codegen->invalid_instruction;
+ if (op1->value.special == ConstValSpecialUndef || casted_op2->value.special == ConstValSpecialUndef) {
+ IrInstruction *result = ir_const(ira, &instruction->base, op1->value.type);
+ result->value.special = ConstValSpecialUndef;
+ return result;
+ }
+ if (casted_op2->value.special == ConstValSpecialStatic && op1->value.special == ConstValSpecialStatic &&
+ (op1->value.data.x_ptr.special == ConstPtrSpecialHardCodedAddr ||
+ op1->value.data.x_ptr.special == ConstPtrSpecialNull))
+ {
+ uint64_t start_addr = (op1->value.data.x_ptr.special == ConstPtrSpecialNull) ?
+ 0 : op1->value.data.x_ptr.data.hard_coded_addr.addr;
+ uint64_t elem_offset;
+ if (!ir_resolve_usize(ira, casted_op2, &elem_offset))
+ return ira->codegen->invalid_instruction;
+ ZigType *elem_type = op1->value.type->data.pointer.child_type;
+ if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown)))
+ return ira->codegen->invalid_instruction;
+ uint64_t byte_offset = type_size(ira->codegen, elem_type) * elem_offset;
+ uint64_t new_addr;
+ if (op_id == IrBinOpAdd) {
+ new_addr = start_addr + byte_offset;
+ } else if (op_id == IrBinOpSub) {
+ new_addr = start_addr - byte_offset;
+ } else {
+ zig_unreachable();
+ }
+ IrInstruction *result = ir_const(ira, &instruction->base, op1->value.type);
+ result->value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr;
+ result->value.data.x_ptr.mut = ConstPtrMutRuntimeVar;
+ result->value.data.x_ptr.data.hard_coded_addr.addr = new_addr;
+ return result;
+ }
+
+ IrInstruction *result = ir_build_bin_op(&ira->new_irb, instruction->base.scope,
+ instruction->base.source_node, op_id, op1, casted_op2, true);
+ result->value.type = op1->value.type;
+ return result;
+ }
+
+ IrInstruction *instructions[] = {op1, op2};
+ ZigType *resolved_type = ir_resolve_peer_types(ira, instruction->base.source_node, nullptr, instructions, 2);
+ if (type_is_invalid(resolved_type))
+ return ira->codegen->invalid_instruction;
bool is_int = resolved_type->id == ZigTypeIdInt || resolved_type->id == ZigTypeIdComptimeInt;
bool is_float = resolved_type->id == ZigTypeIdFloat || resolved_type->id == ZigTypeIdComptimeFloat;
@@ -12878,6 +13245,20 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,
return ir_build_var_decl_gen(ira, &decl_var_instruction->base, var, casted_init_value);
}
+static VarLinkage global_linkage_to_var_linkage(GlobalLinkageId id) {
+ switch (id) {
+ case GlobalLinkageIdStrong:
+ return VarLinkageExportStrong;
+ case GlobalLinkageIdWeak:
+ return VarLinkageExportWeak;
+ case GlobalLinkageIdLinkOnce:
+ return VarLinkageExportLinkOnce;
+ case GlobalLinkageIdInternal:
+ return VarLinkageInternal;
+ }
+ zig_unreachable();
+}
+
static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructionExport *instruction) {
IrInstruction *name = instruction->name->child;
Buf *symbol_name = ir_resolve_str(ira, name);
@@ -12898,14 +13279,24 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
}
}
- auto entry = ira->codegen->exported_symbol_names.put_unique(symbol_name, instruction->base.source_node);
+ // TODO: This function needs to be audited.
+ // It's not clear how all the different types are supposed to be handled.
+ // Need comprehensive tests for exporting one thing in one file and declaring an extern var
+ // in another file.
+ TldFn *tld_fn = allocate<TldFn>(1);
+ tld_fn->base.id = TldIdFn;
+ tld_fn->base.source_node = instruction->base.source_node;
+
+ auto entry = ira->codegen->exported_symbol_names.put_unique(symbol_name, &tld_fn->base);
if (entry) {
- AstNode *other_export_node = entry->value;
+ AstNode *other_export_node = entry->value->source_node;
ErrorMsg *msg = ir_add_error(ira, &instruction->base,
buf_sprintf("exported symbol collision: '%s'", buf_ptr(symbol_name)));
add_error_note(ira->codegen, msg, other_export_node, buf_sprintf("other symbol is here"));
+ return ira->codegen->invalid_instruction;
}
+ bool want_var_export = false;
switch (target->value.type->id) {
case ZigTypeIdInvalid:
case ZigTypeIdUnreachable:
@@ -12913,6 +13304,7 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
case ZigTypeIdFn: {
assert(target->value.data.x_ptr.special == ConstPtrSpecialFunction);
ZigFn *fn_entry = target->value.data.x_ptr.data.fn.fn_entry;
+ tld_fn->fn_entry = fn_entry;
CallingConvention cc = fn_entry->type_entry->data.fn.fn_type_id.cc;
switch (cc) {
case CallingConventionUnspecified: {
@@ -12941,6 +13333,8 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
ErrorMsg *msg = ir_add_error(ira, target,
buf_sprintf("exported struct value must be declared extern"));
add_error_note(ira->codegen, msg, target->value.type->data.structure.decl_node, buf_sprintf("declared here"));
+ } else {
+ want_var_export = true;
}
break;
case ZigTypeIdUnion:
@@ -12948,6 +13342,8 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
ErrorMsg *msg = ir_add_error(ira, target,
buf_sprintf("exported union value must be declared extern"));
add_error_note(ira->codegen, msg, target->value.type->data.unionation.decl_node, buf_sprintf("declared here"));
+ } else {
+ want_var_export = true;
}
break;
case ZigTypeIdEnum:
@@ -12955,6 +13351,8 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
ErrorMsg *msg = ir_add_error(ira, target,
buf_sprintf("exported enum value must be declared extern"));
add_error_note(ira->codegen, msg, target->value.type->data.enumeration.decl_node, buf_sprintf("declared here"));
+ } else {
+ want_var_export = true;
}
break;
case ZigTypeIdMetaType: {
@@ -13044,6 +13442,16 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
break;
}
+ // TODO audit the various ways to use @export
+ if (want_var_export && target->id == IrInstructionIdLoadPtrGen) {
+ IrInstructionLoadPtrGen *load_ptr = reinterpret_cast<IrInstructionLoadPtrGen *>(target);
+ if (load_ptr->ptr->id == IrInstructionIdVarPtr) {
+ IrInstructionVarPtr *var_ptr = reinterpret_cast<IrInstructionVarPtr *>(load_ptr->ptr);
+ ZigVar *var = var_ptr->var;
+ var->linkage = global_linkage_to_var_linkage(global_linkage_id);
+ }
+ }
+
return ir_const_void(ira, &instruction->base);
}
@@ -13331,9 +13739,16 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
if (var->var_type == nullptr || type_is_invalid(var->var_type))
return ira->codegen->invalid_instruction;
+ ConstExprValue *mem_slot = nullptr;
+
bool comptime_var_mem = ir_get_var_is_comptime(var);
+ bool linkage_makes_it_runtime = var->linkage == VarLinkageExternal;
+ bool is_const = var->src_is_const;
+ bool is_volatile = false;
+
+ if (linkage_makes_it_runtime)
+ goto no_mem_slot;
- ConstExprValue *mem_slot = nullptr;
if (var->const_value->special == ConstValSpecialStatic) {
mem_slot = var->const_value;
} else {
@@ -13347,8 +13762,6 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
}
}
- bool is_const = var->src_is_const;
- bool is_volatile = false;
if (mem_slot != nullptr) {
switch (mem_slot->special) {
case ConstValSpecialRuntime:
@@ -13387,26 +13800,32 @@ no_mem_slot:
static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr,
IrInstruction *ptr, IrInstruction *uncasted_value)
{
- if (ptr->value.type->id != ZigTypeIdPointer) {
- ir_add_error(ira, ptr,
- buf_sprintf("attempt to dereference non pointer type '%s'", buf_ptr(&ptr->value.type->name)));
- return ira->codegen->invalid_instruction;
- }
+ assert(ptr->value.type->id == ZigTypeIdPointer);
if (ptr->value.data.x_ptr.special == ConstPtrSpecialDiscard) {
return ir_const_void(ira, source_instr);
}
+ ZigType *child_type = ptr->value.type->data.pointer.child_type;
+
if (ptr->value.type->data.pointer.is_const && !source_instr->is_gen) {
ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant"));
return ira->codegen->invalid_instruction;
}
- ZigType *child_type = ptr->value.type->data.pointer.child_type;
IrInstruction *value = ir_implicit_cast(ira, uncasted_value, child_type);
if (value == ira->codegen->invalid_instruction)
return ira->codegen->invalid_instruction;
+ switch (type_has_one_possible_value(ira->codegen, child_type)) {
+ case OnePossibleValueInvalid:
+ return ira->codegen->invalid_instruction;
+ case OnePossibleValueYes:
+ return ir_const_void(ira, source_instr);
+ case OnePossibleValueNo:
+ break;
+ }
+
if (instr_is_comptime(ptr) && ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst) {
ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant"));
@@ -13427,15 +13846,7 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source
bool same_global_refs = ptr->value.data.x_ptr.mut != ConstPtrMutComptimeVar;
copy_const_val(dest_val, &value->value, same_global_refs);
if (!ira->new_irb.current_basic_block->must_be_comptime_source_instr) {
- switch (type_has_one_possible_value(ira->codegen, child_type)) {
- case OnePossibleValueInvalid:
- return ira->codegen->invalid_instruction;
- case OnePossibleValueNo:
- ira->new_irb.current_basic_block->must_be_comptime_source_instr = source_instr;
- break;
- case OnePossibleValueYes:
- break;
- }
+ ira->new_irb.current_basic_block->must_be_comptime_source_instr = source_instr;
}
return ir_const_void(ira, source_instr);
}
@@ -13630,7 +14041,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
AstNode *body_node = fn_entry->body_node;
result = ir_eval_const_value(ira->codegen, exec_scope, body_node, return_type,
ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry,
- nullptr, call_instruction->base.source_node, nullptr, ira->new_irb.exec);
+ nullptr, call_instruction->base.source_node, nullptr, ira->new_irb.exec, return_type_node);
if (inferred_err_set_type != nullptr) {
inferred_err_set_type->data.error_set.infer_fn = nullptr;
@@ -13826,7 +14237,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
ConstExprValue *align_result = ir_eval_const_value(ira->codegen, impl_fn->child_scope,
fn_proto_node->data.fn_proto.align_expr, get_align_amt_type(ira->codegen),
ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota,
- nullptr, nullptr, fn_proto_node->data.fn_proto.align_expr, nullptr, ira->new_irb.exec);
+ nullptr, nullptr, fn_proto_node->data.fn_proto.align_expr, nullptr, ira->new_irb.exec, nullptr);
IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb,
impl_fn->child_scope, fn_proto_node->data.fn_proto.align_expr);
const_instruction->base.value = *align_result;
@@ -14108,12 +14519,11 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
size_t src_size = type_size(codegen, pointee->type);
size_t dst_size = type_size(codegen, out_val->type);
- if (src_size == dst_size && types_have_same_zig_comptime_repr(pointee->type, out_val->type)) {
- copy_const_val(out_val, pointee, ptr_val->data.x_ptr.mut == ConstPtrMutComptimeConst);
- return ErrorNone;
- }
-
if (dst_size <= src_size) {
+ if (src_size == dst_size && types_have_same_zig_comptime_repr(pointee->type, out_val->type)) {
+ copy_const_val(out_val, pointee, ptr_val->data.x_ptr.mut == ConstPtrMutComptimeConst);
+ return ErrorNone;
+ }
Buf buf = BUF_INIT;
buf_resize(&buf, src_size);
buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf), pointee);
@@ -14129,12 +14539,12 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
if (dst_size == 0)
return ErrorNone;
opt_ir_add_error_node(ira, codegen, source_node,
- buf_sprintf("attempt to read %zu bytes from null pointer",
+ buf_sprintf("attempt to read %" ZIG_PRI_usize " bytes from null pointer",
dst_size));
return ErrorSemanticAnalyzeFail;
case ConstPtrSpecialRef: {
opt_ir_add_error_node(ira, codegen, source_node,
- buf_sprintf("attempt to read %zu bytes from pointer to %s which is %zu bytes",
+ buf_sprintf("attempt to read %" ZIG_PRI_usize " bytes from pointer to %s which is %" ZIG_PRI_usize " bytes",
dst_size, buf_ptr(&pointee->type->name), src_size));
return ErrorSemanticAnalyzeFail;
}
@@ -14148,7 +14558,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
src_size = elem_size * (array_val->type->data.array.len - elem_index);
if (dst_size > src_size) {
opt_ir_add_error_node(ira, codegen, source_node,
- buf_sprintf("attempt to read %zu bytes from %s at index %" ZIG_PRI_usize " which is %zu bytes",
+ buf_sprintf("attempt to read %" ZIG_PRI_usize " bytes from %s at index %" ZIG_PRI_usize " which is %" ZIG_PRI_usize " bytes",
dst_size, buf_ptr(&array_val->type->name), elem_index, src_size));
return ErrorSemanticAnalyzeFail;
}
@@ -14220,6 +14630,41 @@ static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_
zig_unreachable();
}
+static ErrorMsg *ir_eval_negation_scalar(IrAnalyze *ira, IrInstruction *source_instr, ZigType *scalar_type,
+ ConstExprValue *operand_val, ConstExprValue *scalar_out_val, bool is_wrap_op)
+{
+ bool is_float = (scalar_type->id == ZigTypeIdFloat || scalar_type->id == ZigTypeIdComptimeFloat);
+
+ bool ok_type = ((scalar_type->id == ZigTypeIdInt && scalar_type->data.integral.is_signed) ||
+ scalar_type->id == ZigTypeIdComptimeInt || (is_float && !is_wrap_op));
+
+ if (!ok_type) {
+ const char *fmt = is_wrap_op ? "invalid wrapping negation type: '%s'" : "invalid negation type: '%s'";
+ return ir_add_error(ira, source_instr, buf_sprintf(fmt, buf_ptr(&scalar_type->name)));
+ }
+
+ if (is_float) {
+ float_negate(scalar_out_val, operand_val);
+ } else if (is_wrap_op) {
+ bigint_negate_wrap(&scalar_out_val->data.x_bigint, &operand_val->data.x_bigint,
+ scalar_type->data.integral.bit_count);
+ } else {
+ bigint_negate(&scalar_out_val->data.x_bigint, &operand_val->data.x_bigint);
+ }
+
+ scalar_out_val->type = scalar_type;
+ scalar_out_val->special = ConstValSpecialStatic;
+
+ if (is_wrap_op || is_float || scalar_type->id == ZigTypeIdComptimeInt) {
+ return nullptr;
+ }
+
+ if (!bigint_fits_in_bits(&scalar_out_val->data.x_bigint, scalar_type->data.integral.bit_count, true)) {
+ return ir_add_error(ira, source_instr, buf_sprintf("negation caused overflow"));
+ }
+ return nullptr;
+}
+
static IrInstruction *ir_analyze_negation(IrAnalyze *ira, IrInstructionUnOp *instruction) {
IrInstruction *value = instruction->value->child;
ZigType *expr_type = value->value.type;
@@ -14228,47 +14673,50 @@ static IrInstruction *ir_analyze_negation(IrAnalyze *ira, IrInstructionUnOp *ins
bool is_wrap_op = (instruction->op_id == IrUnOpNegationWrap);
- bool is_float = (expr_type->id == ZigTypeIdFloat || expr_type->id == ZigTypeIdComptimeFloat);
+ ZigType *scalar_type = (expr_type->id == ZigTypeIdVector) ? expr_type->data.vector.elem_type : expr_type;
- if ((expr_type->id == ZigTypeIdInt && expr_type->data.integral.is_signed) ||
- expr_type->id == ZigTypeIdComptimeInt || (is_float && !is_wrap_op))
- {
- if (instr_is_comptime(value)) {
- ConstExprValue *target_const_val = ir_resolve_const(ira, value, UndefBad);
- if (!target_const_val)
- return ira->codegen->invalid_instruction;
+ if (instr_is_comptime(value)) {
+ ConstExprValue *operand_val = ir_resolve_const(ira, value, UndefBad);
+ if (!operand_val)
+ return ira->codegen->invalid_instruction;
- IrInstruction *result = ir_const(ira, &instruction->base, expr_type);
- ConstExprValue *out_val = &result->value;
- if (is_float) {
- float_negate(out_val, target_const_val);
- } else if (is_wrap_op) {
- bigint_negate_wrap(&out_val->data.x_bigint, &target_const_val->data.x_bigint,
- expr_type->data.integral.bit_count);
- } else {
- bigint_negate(&out_val->data.x_bigint, &target_const_val->data.x_bigint);
- }
- if (is_wrap_op || is_float || expr_type->id == ZigTypeIdComptimeInt) {
- return result;
+ IrInstruction *result_instruction = ir_const(ira, &instruction->base, expr_type);
+ ConstExprValue *out_val = &result_instruction->value;
+ if (expr_type->id == ZigTypeIdVector) {
+ expand_undef_array(ira->codegen, operand_val);
+ out_val->special = ConstValSpecialUndef;
+ expand_undef_array(ira->codegen, out_val);
+ size_t len = expr_type->data.vector.len;
+ for (size_t i = 0; i < len; i += 1) {
+ ConstExprValue *scalar_operand_val = &operand_val->data.x_array.data.s_none.elements[i];
+ ConstExprValue *scalar_out_val = &out_val->data.x_array.data.s_none.elements[i];
+ assert(scalar_operand_val->type == scalar_type);
+ assert(scalar_out_val->type == scalar_type);
+ ErrorMsg *msg = ir_eval_negation_scalar(ira, &instruction->base, scalar_type,
+ scalar_operand_val, scalar_out_val, is_wrap_op);
+ if (msg != nullptr) {
+ add_error_note(ira->codegen, msg, instruction->base.source_node,
+ buf_sprintf("when computing vector element at index %" ZIG_PRI_usize, i));
+ return ira->codegen->invalid_instruction;
+ }
}
-
- if (!bigint_fits_in_bits(&out_val->data.x_bigint, expr_type->data.integral.bit_count, true)) {
- ir_add_error(ira, &instruction->base, buf_sprintf("negation caused overflow"));
+ out_val->type = expr_type;
+ out_val->special = ConstValSpecialStatic;
+ } else {
+ if (ir_eval_negation_scalar(ira, &instruction->base, scalar_type, operand_val, out_val,
+ is_wrap_op) != nullptr)
+ {
return ira->codegen->invalid_instruction;
}
- return result;
}
-
- IrInstruction *result = ir_build_un_op(&ira->new_irb,
- instruction->base.scope, instruction->base.source_node,
- instruction->op_id, value);
- result->value.type = expr_type;
- return result;
+ return result_instruction;
}
- const char *fmt = is_wrap_op ? "invalid wrapping negation type: '%s'" : "invalid negation type: '%s'";
- ir_add_error(ira, &instruction->base, buf_sprintf(fmt, buf_ptr(&expr_type->name)));
- return ira->codegen->invalid_instruction;
+ IrInstruction *result = ir_build_un_op(&ira->new_irb,
+ instruction->base.scope, instruction->base.source_node,
+ instruction->op_id, value);
+ result->value.type = expr_type;
+ return result;
}
static IrInstruction *ir_analyze_bin_not(IrAnalyze *ira, IrInstructionUnOp *instruction) {
@@ -14321,11 +14769,18 @@ static IrInstruction *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstruction
buf_ptr(&ptr_type->name)));
return ira->codegen->invalid_instruction;
}
- // this dereference is always an rvalue because in the IR gen we identify lvalue and emit
- // one of the ptr instructions
+
IrInstruction *result = ir_get_deref(ira, &instruction->base, ptr);
if (result == ira->codegen->invalid_instruction)
return ira->codegen->invalid_instruction;
+
+ // If the result needs to be an lvalue, type check it
+ if (instruction->lval == LValPtr && result->value.type->id != ZigTypeIdPointer) {
+ ir_add_error(ira, &instruction->base,
+ buf_sprintf("attempt to dereference non-pointer type '%s'", buf_ptr(&result->value.type->name)));
+ return ira->codegen->invalid_instruction;
+ }
+
return result;
}
case IrUnOpOptional:
@@ -14958,6 +15413,16 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
if (bare_type->id == ZigTypeIdStruct) {
TypeStructField *field = find_struct_type_field(bare_type, field_name);
if (field) {
+ switch (type_has_one_possible_value(ira->codegen, field->type_entry)) {
+ case OnePossibleValueInvalid:
+ return ira->codegen->invalid_instruction;
+ case OnePossibleValueYes: {
+ IrInstruction *elem = ir_const(ira, source_instr, field->type_entry);
+ return ir_get_ref(ira, source_instr, elem, false, false);
+ }
+ case OnePossibleValueNo:
+ break;
+ }
bool is_packed = (bare_type->data.structure.layout == ContainerLayoutPacked);
uint32_t align_bytes = is_packed ? 1 : get_abi_alignment(ira->codegen, field->type_entry);
uint32_t ptr_bit_offset = container_ptr->value.type->data.pointer.bit_offset_in_host;
@@ -15065,6 +15530,14 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
}
static void add_link_lib_symbol(IrAnalyze *ira, Buf *lib_name, Buf *symbol_name, AstNode *source_node) {
+ if (buf_eql_str(lib_name, "c") && ira->codegen->libc_link_lib == nullptr &&
+ !ira->codegen->reported_bad_link_libc_error)
+ {
+ ir_add_error_node(ira, source_node,
+ buf_sprintf("dependency on library c must be explicitly specified in the build command"));
+ ira->codegen->reported_bad_link_libc_error = true;
+ }
+
LinkLib *link_lib = add_link_lib(ira->codegen, lib_name);
for (size_t i = 0; i < link_lib->symbols.length; i += 1) {
Buf *existing_symbol_name = link_lib->symbols.at(i);
@@ -15151,12 +15624,6 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc
if (type_is_invalid(container_ptr->value.type))
return ira->codegen->invalid_instruction;
- if (container_ptr->value.type->id != ZigTypeIdPointer) {
- ir_add_error_node(ira, field_ptr_instruction->base.source_node,
- buf_sprintf("attempt to dereference non-pointer type '%s'",
- buf_ptr(&container_ptr->value.type->name)));
- return ira->codegen->invalid_instruction;
- }
ZigType *container_type = container_ptr->value.type->data.pointer.child_type;
Buf *field_name = field_ptr_instruction->field_name_buffer;
@@ -15572,6 +16039,8 @@ static IrInstruction *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructio
static IrInstruction *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira,
IrInstructionToPtrType *to_ptr_type_instruction)
{
+ Error err;
+
IrInstruction *value = to_ptr_type_instruction->value->child;
ZigType *type_entry = value->value.type;
if (type_is_invalid(type_entry))
@@ -15587,7 +16056,17 @@ static IrInstruction *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira,
ptr_type = get_pointer_to_type(ira->codegen,
type_entry->data.pointer.child_type->data.array.child_type, type_entry->data.pointer.is_const);
} else if (is_slice(type_entry)) {
- ptr_type = adjust_ptr_len(ira->codegen, type_entry->data.structure.fields[0].type_entry, PtrLenSingle);
+ ZigType *slice_ptr_type = type_entry->data.structure.fields[0].type_entry;
+ ptr_type = adjust_ptr_len(ira->codegen, slice_ptr_type, PtrLenSingle);
+ // If the pointer is over-aligned, we may have to reduce it based on the alignment of the element type.
+ if (slice_ptr_type->data.pointer.explicit_alignment != 0) {
+ ZigType *elem_type = slice_ptr_type->data.pointer.child_type;
+ if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusAlignmentKnown)))
+ return ira->codegen->invalid_instruction;
+ uint32_t elem_align = get_abi_alignment(ira->codegen, elem_type);
+ uint32_t reduced_align = min(elem_align, slice_ptr_type->data.pointer.explicit_alignment);
+ ptr_type = adjust_ptr_align(ira->codegen, ptr_type, reduced_align);
+ }
} else if (type_entry->id == ZigTypeIdArgTuple) {
ConstExprValue *arg_tuple_val = ir_resolve_const(ira, value, UndefBad);
if (!arg_tuple_val)
@@ -16355,18 +16834,13 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
return ir_const_type(ira, &switch_target_instruction->base, ptr_type->data.pointer.child_type);
}
- if (target_value_ptr->value.type->id != ZigTypeIdPointer) {
- ir_add_error(ira, target_value_ptr, buf_sprintf("invalid deref on switch target"));
- return ira->codegen->invalid_instruction;
- }
-
ZigType *target_type = target_value_ptr->value.type->data.pointer.child_type;
ConstExprValue *pointee_val = nullptr;
if (instr_is_comptime(target_value_ptr)) {
pointee_val = const_ptr_pointee(ira, ira->codegen, &target_value_ptr->value, target_value_ptr->source_node);
if (pointee_val == nullptr)
return ira->codegen->invalid_instruction;
-
+
if (pointee_val->special == ConstValSpecialRuntime)
pointee_val = nullptr;
}
@@ -16953,9 +17427,13 @@ static IrInstruction *ir_analyze_instruction_compile_log(IrAnalyze *ira, IrInstr
}
fprintf(stderr, "\n");
- // Here we bypass higher level functions such as ir_add_error because we do not want
- // invalidate_exec to be called.
- add_node_error(ira->codegen, instruction->base.source_node, buf_sprintf("found compile log statement"));
+ auto *expr = &instruction->base.source_node->data.fn_call_expr;
+ if (!expr->seen) {
+ // Here we bypass higher level functions such as ir_add_error because we do not want
+ // invalidate_exec to be called.
+ add_node_error(ira->codegen, instruction->base.source_node, buf_sprintf("found compile log statement"));
+ }
+ expr->seen = true;
return ir_const_void(ira, &instruction->base);
}
@@ -17116,7 +17594,7 @@ static IrInstruction *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira,
static TypeStructField *validate_byte_offset(IrAnalyze *ira,
IrInstruction *type_value,
IrInstruction *field_name_value,
- size_t *byte_offset)
+ size_t *byte_offset)
{
ZigType *container_type = ir_resolve_type(ira, type_value);
if (type_is_invalid(container_type))
@@ -17290,7 +17768,7 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco
// Loop through the definitions and generate info.
decl_it = decls_scope->decl_table.entry_iterator();
- curr_entry = nullptr;
+ curr_entry = nullptr;
int definition_index = 0;
while ((curr_entry = decl_it.next()) != nullptr) {
// Skip comptime blocks and test functions.
@@ -17469,6 +17947,18 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco
return ErrorNone;
}
+static uint32_t ptr_len_to_size_enum_index(PtrLen ptr_len) {
+ switch (ptr_len) {
+ case PtrLenSingle:
+ return 0;
+ case PtrLenUnknown:
+ return 1;
+ case PtrLenC:
+ return 3;
+ }
+ zig_unreachable();
+}
+
static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_type_entry) {
Error err;
ZigType *attrs_type;
@@ -17478,7 +17968,7 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_ty
size_enum_index = 2;
} else if (ptr_type_entry->id == ZigTypeIdPointer) {
attrs_type = ptr_type_entry;
- size_enum_index = (ptr_type_entry->data.pointer.ptr_len == PtrLenSingle) ? 0 : 1;
+ size_enum_index = ptr_len_to_size_enum_index(ptr_type_entry->data.pointer.ptr_len);
} else {
zig_unreachable();
}
@@ -18172,12 +18662,6 @@ static IrInstruction *ir_analyze_instruction_type_id(IrAnalyze *ira,
static IrInstruction *ir_analyze_instruction_set_eval_branch_quota(IrAnalyze *ira,
IrInstructionSetEvalBranchQuota *instruction)
{
- if (ira->new_irb.exec->parent_exec != nullptr && !ira->new_irb.exec->is_generic_instantiation) {
- ir_add_error(ira, &instruction->base,
- buf_sprintf("@setEvalBranchQuota must be called from the top of the comptime stack"));
- return ira->codegen->invalid_instruction;
- }
-
uint64_t new_quota;
if (!ir_resolve_usize(ira, instruction->new_quota->child, &new_quota))
return ira->codegen->invalid_instruction;
@@ -18204,12 +18688,6 @@ static IrInstruction *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstruc
}
static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstructionCImport *instruction) {
- if (ira->codegen->enable_cache) {
- ir_add_error(ira, &instruction->base,
- buf_sprintf("TODO @cImport is incompatible with --cache on. The cache system currently is unable to detect subsequent changes in .h files."));
- return ira->codegen->invalid_instruction;
- }
-
AstNode *node = instruction->base.source_node;
assert(node->type == NodeTypeFnCallExpr);
AstNode *block_node = node->data.fn_call_expr.params.at(0);
@@ -18220,12 +18698,10 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct
ZigType *void_type = ira->codegen->builtin_types.entry_void;
ConstExprValue *cimport_result = ir_eval_const_value(ira->codegen, &cimport_scope->base, block_node, void_type,
ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr,
- &cimport_scope->buf, block_node, nullptr, nullptr);
+ &cimport_scope->buf, block_node, nullptr, nullptr, nullptr);
if (type_is_invalid(cimport_result->type))
return ira->codegen->invalid_instruction;
- find_libc_include_path(ira->codegen);
-
ImportTableEntry *child_import = allocate<ImportTableEntry>(1);
child_import->decls_scope = create_decls_scope(ira->codegen, node, nullptr, nullptr, child_import);
child_import->c_import_node = node;
@@ -18247,6 +18723,10 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct
if (errors.length > 0) {
ErrorMsg *parent_err_msg = ir_add_error_node(ira, node, buf_sprintf("C import failed"));
+ if (ira->codegen->libc_link_lib == nullptr) {
+ add_error_note(ira->codegen, parent_err_msg, node,
+ buf_sprintf("libc headers not available; compilation does not link against libc"));
+ }
for (size_t i = 0; i < errors.length; i += 1) {
ErrorMsg *err_msg = errors.at(i);
err_msg_add_note(parent_err_msg, err_msg);
@@ -18713,7 +19193,9 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru
}
}
- return ir_resolve_cast(ira, &instruction->base, casted_value, dest_slice_type, CastOpResizeSlice, true);
+ IrInstruction *result = ir_build_resize_slice(ira, &instruction->base, casted_value, dest_slice_type);
+ ir_add_alloca(ira, result, dest_slice_type);
+ return result;
}
static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstructionToBytes *instruction) {
@@ -18740,7 +19222,34 @@ static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstruct
alignment, 0, 0);
ZigType *dest_slice_type = get_slice_type(ira->codegen, dest_ptr_type);
- return ir_resolve_cast(ira, &instruction->base, target, dest_slice_type, CastOpResizeSlice, true);
+ if (instr_is_comptime(target)) {
+ ConstExprValue *target_val = ir_resolve_const(ira, target, UndefBad);
+ if (target_val == nullptr)
+ return ira->codegen->invalid_instruction;
+
+ IrInstruction *result = ir_const(ira, &instruction->base, dest_slice_type);
+ result->value.data.x_struct.fields = create_const_vals(2);
+
+ ConstExprValue *ptr_val = &result->value.data.x_struct.fields[slice_ptr_index];
+ ConstExprValue *target_ptr_val = &target_val->data.x_struct.fields[slice_ptr_index];
+ copy_const_val(ptr_val, target_ptr_val, false);
+ ptr_val->type = dest_ptr_type;
+
+ ConstExprValue *len_val = &result->value.data.x_struct.fields[slice_len_index];
+ len_val->special = ConstValSpecialStatic;
+ len_val->type = ira->codegen->builtin_types.entry_usize;
+ ConstExprValue *target_len_val = &target_val->data.x_struct.fields[slice_len_index];
+ ZigType *elem_type = src_ptr_type->data.pointer.child_type;
+ BigInt elem_size_bigint;
+ bigint_init_unsigned(&elem_size_bigint, type_size(ira->codegen, elem_type));
+ bigint_mul(&len_val->data.x_bigint, &target_len_val->data.x_bigint, &elem_size_bigint);
+
+ return result;
+ }
+
+ IrInstruction *result = ir_build_resize_slice(ira, &instruction->base, target, dest_slice_type);
+ ir_add_alloca(ira, result, dest_slice_type);
+ return result;
}
static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) {
@@ -18952,10 +19461,12 @@ static IrInstruction *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructio
if (type_is_invalid(casted_count->value.type))
return ira->codegen->invalid_instruction;
+ // TODO test this at comptime with u8 and non-u8 types
if (casted_dest_ptr->value.special == ConstValSpecialStatic &&
casted_byte->value.special == ConstValSpecialStatic &&
casted_count->value.special == ConstValSpecialStatic &&
- casted_dest_ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr)
+ casted_dest_ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr &&
+ casted_dest_ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar)
{
ConstExprValue *dest_ptr_val = &casted_dest_ptr->value;
@@ -19074,6 +19585,8 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio
if (type_is_invalid(casted_count->value.type))
return ira->codegen->invalid_instruction;
+ // TODO test this at comptime with u8 and non-u8 types
+ // TODO test with dest ptr being a global runtime variable
if (casted_dest_ptr->value.special == ConstValSpecialStatic &&
casted_src_ptr->value.special == ConstValSpecialStatic &&
casted_count->value.special == ConstValSpecialStatic &&
@@ -20242,7 +20755,7 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
} else {
seenFalse += 1;
}
-
+
if ((seenTrue > 1) || (seenFalse > 1)) {
ir_add_error(ira, value, buf_sprintf("duplicate switch value"));
return ira->codegen->invalid_instruction;
@@ -20375,7 +20888,7 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3
}
static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *ptr,
- ZigType *dest_type, IrInstruction *dest_type_src)
+ ZigType *dest_type, IrInstruction *dest_type_src, bool safety_check_on)
{
Error err;
@@ -20385,12 +20898,14 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_
// We have a check for zero bits later so we use get_src_ptr_type to
// validate src_type and dest_type.
- if (get_src_ptr_type(src_type) == nullptr) {
+ ZigType *src_ptr_type = get_src_ptr_type(src_type);
+ if (src_ptr_type == nullptr) {
ir_add_error(ira, ptr, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name)));
return ira->codegen->invalid_instruction;
}
- if (get_src_ptr_type(dest_type) == nullptr) {
+ ZigType *dest_ptr_type = get_src_ptr_type(dest_type);
+ if (dest_ptr_type == nullptr) {
ir_add_error(ira, dest_type_src,
buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name)));
return ira->codegen->invalid_instruction;
@@ -20400,25 +20915,44 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_
ir_add_error(ira, source_instr, buf_sprintf("cast discards const qualifier"));
return ira->codegen->invalid_instruction;
}
+ uint32_t src_align_bytes;
+ if ((err = resolve_ptr_align(ira, src_type, &src_align_bytes)))
+ return ira->codegen->invalid_instruction;
+
+ uint32_t dest_align_bytes;
+ if ((err = resolve_ptr_align(ira, dest_type, &dest_align_bytes)))
+ return ira->codegen->invalid_instruction;
if (instr_is_comptime(ptr)) {
- ConstExprValue *val = ir_resolve_const(ira, ptr, UndefOk);
+ bool dest_allows_addr_zero = ptr_allows_addr_zero(dest_type);
+ UndefAllowed is_undef_allowed = dest_allows_addr_zero ? UndefOk : UndefBad;
+ ConstExprValue *val = ir_resolve_const(ira, ptr, is_undef_allowed);
if (!val)
return ira->codegen->invalid_instruction;
+ if (val->special == ConstValSpecialStatic) {
+ bool is_addr_zero = val->data.x_ptr.special == ConstPtrSpecialNull ||
+ (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr &&
+ val->data.x_ptr.data.hard_coded_addr.addr == 0);
+ if (is_addr_zero && !dest_allows_addr_zero) {
+ ir_add_error(ira, source_instr,
+ buf_sprintf("null pointer casted to type '%s'", buf_ptr(&dest_type->name)));
+ return ira->codegen->invalid_instruction;
+ }
+ }
+
IrInstruction *result = ir_const(ira, source_instr, dest_type);
copy_const_val(&result->value, val, false);
result->value.type = dest_type;
- return result;
- }
- uint32_t src_align_bytes;
- if ((err = resolve_ptr_align(ira, src_type, &src_align_bytes)))
- return ira->codegen->invalid_instruction;
+ // Keep the bigger alignment, it can only help-
+ // unless the target is zero bits.
+ if (src_align_bytes > dest_align_bytes && type_has_bits(dest_type)) {
+ result = ir_align_cast(ira, result, src_align_bytes, false);
+ }
- uint32_t dest_align_bytes;
- if ((err = resolve_ptr_align(ira, dest_type, &dest_align_bytes)))
- return ira->codegen->invalid_instruction;
+ return result;
+ }
if (dest_align_bytes > src_align_bytes) {
ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("cast increases pointer alignment"));
@@ -20429,7 +20963,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_
return ira->codegen->invalid_instruction;
}
- IrInstruction *casted_ptr = ir_build_ptr_cast_gen(ira, source_instr, dest_type, ptr);
+ IrInstruction *casted_ptr = ir_build_ptr_cast_gen(ira, source_instr, dest_type, ptr, safety_check_on);
if (type_has_bits(dest_type) && !type_has_bits(src_type)) {
ErrorMsg *msg = ir_add_error(ira, source_instr,
@@ -20466,7 +21000,8 @@ static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstruct
if (type_is_invalid(src_type))
return ira->codegen->invalid_instruction;
- return ir_analyze_ptr_cast(ira, &instruction->base, ptr, dest_type, dest_type_value);
+ return ir_analyze_ptr_cast(ira, &instruction->base, ptr, dest_type, dest_type_value,
+ instruction->safety_check_on);
}
static void buf_write_value_bytes_array(CodeGen *codegen, uint8_t *buf, ConstExprValue *val, size_t len) {
@@ -20529,7 +21064,79 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
case ZigTypeIdVector:
return buf_write_value_bytes_array(codegen, buf, val, val->type->data.vector.len);
case ZigTypeIdStruct:
- zig_panic("TODO buf_write_value_bytes struct type");
+ switch (val->type->data.structure.layout) {
+ case ContainerLayoutAuto:
+ zig_unreachable();
+ case ContainerLayoutExtern: {
+ size_t src_field_count = val->type->data.structure.src_field_count;
+ for (size_t field_i = 0; field_i < src_field_count; field_i += 1) {
+ TypeStructField *type_field = &val->type->data.structure.fields[field_i];
+ if (type_field->gen_index == SIZE_MAX)
+ continue;
+ ConstExprValue *field_val = &val->data.x_struct.fields[field_i];
+ size_t offset = LLVMOffsetOfElement(codegen->target_data_ref, val->type->type_ref,
+ type_field->gen_index);
+ buf_write_value_bytes(codegen, buf + offset, field_val);
+ }
+ return;
+ }
+ case ContainerLayoutPacked: {
+ size_t src_field_count = val->type->data.structure.src_field_count;
+ size_t gen_field_count = val->type->data.structure.gen_field_count;
+ size_t gen_i = 0;
+ size_t src_i = 0;
+ size_t offset = 0;
+ bool is_big_endian = codegen->is_big_endian;
+ uint8_t child_buf_prealloc[16];
+ size_t child_buf_len = 16;
+ uint8_t *child_buf = child_buf_prealloc;
+ while (gen_i < gen_field_count) {
+ LLVMTypeRef gen_llvm_int_type = LLVMStructGetTypeAtIndex(val->type->type_ref,
+ (unsigned)gen_i);
+ size_t big_int_bit_count = LLVMGetIntTypeWidth(gen_llvm_int_type);
+ size_t big_int_byte_count = big_int_bit_count / 8;
+ if (big_int_byte_count > child_buf_len) {
+ child_buf = allocate_nonzero<uint8_t>(big_int_byte_count);
+ child_buf_len = big_int_byte_count;
+ }
+ BigInt big_int;
+ bigint_init_unsigned(&big_int, 0);
+ size_t used_bits = 0;
+ while (src_i < src_field_count) {
+ TypeStructField *field = &val->type->data.structure.fields[src_i];
+ assert(field->gen_index != SIZE_MAX);
+ if (field->gen_index != gen_i)
+ break;
+ uint32_t packed_bits_size = type_size_bits(codegen, field->type_entry);
+ buf_write_value_bytes(codegen, child_buf, &val->data.x_struct.fields[src_i]);
+ BigInt child_val;
+ bigint_read_twos_complement(&child_val, child_buf, packed_bits_size, is_big_endian,
+ false);
+ if (is_big_endian) {
+ BigInt shift_amt;
+ bigint_init_unsigned(&shift_amt, packed_bits_size);
+ BigInt shifted;
+ bigint_shl(&shifted, &big_int, &shift_amt);
+ bigint_or(&big_int, &shifted, &child_val);
+ } else {
+ BigInt shift_amt;
+ bigint_init_unsigned(&shift_amt, used_bits);
+ BigInt child_val_shifted;
+ bigint_shl(&child_val_shifted, &child_val, &shift_amt);
+ BigInt tmp;
+ bigint_or(&tmp, &big_int, &child_val_shifted);
+ big_int = tmp;
+ used_bits += packed_bits_size;
+ }
+ src_i += 1;
+ }
+ bigint_write_twos_complement(&big_int, buf + offset, big_int_bit_count, is_big_endian);
+ offset += big_int_byte_count;
+ gen_i += 1;
+ }
+ return;
+ }
+ }
case ZigTypeIdOptional:
zig_panic("TODO buf_write_value_bytes maybe type");
case ZigTypeIdErrorUnion:
@@ -20656,8 +21263,62 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou
}
return ErrorNone;
}
- case ContainerLayoutPacked:
- zig_panic("TODO buf_read_value_bytes packed struct");
+ case ContainerLayoutPacked: {
+ size_t src_field_count = val->type->data.structure.src_field_count;
+ val->data.x_struct.fields = create_const_vals(src_field_count);
+ size_t gen_field_count = val->type->data.structure.gen_field_count;
+ size_t gen_i = 0;
+ size_t src_i = 0;
+ size_t offset = 0;
+ bool is_big_endian = codegen->is_big_endian;
+ uint8_t child_buf_prealloc[16];
+ size_t child_buf_len = 16;
+ uint8_t *child_buf = child_buf_prealloc;
+ while (gen_i < gen_field_count) {
+ LLVMTypeRef gen_llvm_int_type = LLVMStructGetTypeAtIndex(val->type->type_ref,
+ (unsigned)gen_i);
+ size_t big_int_bit_count = LLVMGetIntTypeWidth(gen_llvm_int_type);
+ size_t big_int_byte_count = big_int_bit_count / 8;
+ if (big_int_byte_count > child_buf_len) {
+ child_buf = allocate_nonzero<uint8_t>(big_int_byte_count);
+ child_buf_len = big_int_byte_count;
+ }
+ BigInt big_int;
+ bigint_read_twos_complement(&big_int, buf + offset, big_int_bit_count, is_big_endian, false);
+ while (src_i < src_field_count) {
+ TypeStructField *field = &val->type->data.structure.fields[src_i];
+ assert(field->gen_index != SIZE_MAX);
+ if (field->gen_index != gen_i)
+ break;
+ ConstExprValue *field_val = &val->data.x_struct.fields[src_i];
+ field_val->special = ConstValSpecialStatic;
+ field_val->type = field->type_entry;
+ uint32_t packed_bits_size = type_size_bits(codegen, field->type_entry);
+
+ BigInt child_val;
+ if (is_big_endian) {
+ zig_panic("TODO buf_read_value_bytes packed struct big endian");
+ } else {
+ BigInt packed_bits_size_bi;
+ bigint_init_unsigned(&packed_bits_size_bi, packed_bits_size);
+ bigint_truncate(&child_val, &big_int, packed_bits_size, false);
+ BigInt tmp;
+ bigint_shr(&tmp, &big_int, &packed_bits_size_bi);
+ big_int = tmp;
+ }
+
+ bigint_write_twos_complement(&child_val, child_buf, big_int_bit_count, is_big_endian);
+ if ((err = buf_read_value_bytes(ira, codegen, source_node, child_buf, field_val))) {
+ return err;
+ }
+
+ src_i += 1;
+ }
+ offset += big_int_byte_count;
+ gen_i += 1;
+ }
+ return ErrorNone;
+ }
}
zig_unreachable();
case ZigTypeIdOptional:
@@ -20674,32 +21335,10 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou
zig_unreachable();
}
-static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstructionBitCast *instruction) {
- Error err;
- IrInstruction *dest_type_value = instruction->dest_type->child;
- ZigType *dest_type = ir_resolve_type(ira, dest_type_value);
- if (type_is_invalid(dest_type))
- return ira->codegen->invalid_instruction;
-
- IrInstruction *value = instruction->value->child;
- ZigType *src_type = value->value.type;
- if (type_is_invalid(src_type))
- return ira->codegen->invalid_instruction;
-
- if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusSizeKnown)))
- return ira->codegen->invalid_instruction;
-
- if ((err = type_resolve(ira->codegen, src_type, ResolveStatusSizeKnown)))
- return ira->codegen->invalid_instruction;
-
- if (get_codegen_ptr_type(src_type) != nullptr) {
- ir_add_error(ira, value,
- buf_sprintf("unable to @bitCast from pointer type '%s'", buf_ptr(&src_type->name)));
- return ira->codegen->invalid_instruction;
- }
-
- switch (src_type->id) {
+static bool type_can_bit_cast(ZigType *t) {
+ switch (t->id) {
case ZigTypeIdInvalid:
+ zig_unreachable();
case ZigTypeIdMetaType:
case ZigTypeIdOpaque:
case ZigTypeIdBoundFn:
@@ -20710,42 +21349,36 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct
case ZigTypeIdComptimeInt:
case ZigTypeIdUndefined:
case ZigTypeIdNull:
- ir_add_error(ira, dest_type_value,
- buf_sprintf("unable to @bitCast from type '%s'", buf_ptr(&src_type->name)));
- return ira->codegen->invalid_instruction;
+ case ZigTypeIdPointer:
+ return false;
default:
- break;
+ // TODO list these types out explicitly, there are probably some other invalid ones here
+ return true;
}
+}
- if (get_codegen_ptr_type(dest_type) != nullptr) {
- ir_add_error(ira, dest_type_value,
- buf_sprintf("unable to @bitCast to pointer type '%s'", buf_ptr(&dest_type->name)));
+static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
+ ZigType *dest_type)
+{
+ Error err;
+
+ ZigType *src_type = value->value.type;
+ assert(get_codegen_ptr_type(src_type) == nullptr);
+ assert(type_can_bit_cast(src_type));
+ assert(get_codegen_ptr_type(dest_type) == nullptr);
+ assert(type_can_bit_cast(dest_type));
+
+ if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusSizeKnown)))
+ return ira->codegen->invalid_instruction;
+
+ if ((err = type_resolve(ira->codegen, src_type, ResolveStatusSizeKnown)))
return ira->codegen->invalid_instruction;
- }
- switch (dest_type->id) {
- case ZigTypeIdInvalid:
- case ZigTypeIdMetaType:
- case ZigTypeIdOpaque:
- case ZigTypeIdBoundFn:
- case ZigTypeIdArgTuple:
- case ZigTypeIdNamespace:
- case ZigTypeIdUnreachable:
- case ZigTypeIdComptimeFloat:
- case ZigTypeIdComptimeInt:
- case ZigTypeIdUndefined:
- case ZigTypeIdNull:
- ir_add_error(ira, dest_type_value,
- buf_sprintf("unable to @bitCast to type '%s'", buf_ptr(&dest_type->name)));
- return ira->codegen->invalid_instruction;
- default:
- break;
- }
uint64_t dest_size_bytes = type_size(ira->codegen, dest_type);
uint64_t src_size_bytes = type_size(ira->codegen, src_type);
if (dest_size_bytes != src_size_bytes) {
- ir_add_error(ira, &instruction->base,
+ ir_add_error(ira, source_instr,
buf_sprintf("destination type '%s' has size %" ZIG_PRI_u64 " but source type '%s' has size %" ZIG_PRI_u64,
buf_ptr(&dest_type->name), dest_size_bytes,
buf_ptr(&src_type->name), src_size_bytes));
@@ -20755,7 +21388,7 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct
uint64_t dest_size_bits = type_size_bits(ira->codegen, dest_type);
uint64_t src_size_bits = type_size_bits(ira->codegen, src_type);
if (dest_size_bits != src_size_bits) {
- ir_add_error(ira, &instruction->base,
+ ir_add_error(ira, source_instr,
buf_sprintf("destination type '%s' has %" ZIG_PRI_u64 " bits but source type '%s' has %" ZIG_PRI_u64 " bits",
buf_ptr(&dest_type->name), dest_size_bits,
buf_ptr(&src_type->name), src_size_bits));
@@ -20767,44 +21400,64 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct
if (!val)
return ira->codegen->invalid_instruction;
- IrInstruction *result = ir_const(ira, &instruction->base, dest_type);
+ IrInstruction *result = ir_const(ira, source_instr, dest_type);
uint8_t *buf = allocate_nonzero<uint8_t>(src_size_bytes);
buf_write_value_bytes(ira->codegen, buf, val);
- if ((err = buf_read_value_bytes(ira, ira->codegen, instruction->base.source_node, buf, &result->value)))
+ if ((err = buf_read_value_bytes(ira, ira->codegen, source_instr->source_node, buf, &result->value)))
return ira->codegen->invalid_instruction;
return result;
}
- IrInstruction *result = ir_build_bit_cast(&ira->new_irb, instruction->base.scope,
- instruction->base.source_node, nullptr, value);
- result->value.type = dest_type;
+ IrInstruction *result = ir_build_bit_cast_gen(ira, source_instr, value, dest_type);
+ if (handle_is_ptr(dest_type) && !handle_is_ptr(src_type)) {
+ ir_add_alloca(ira, result, dest_type);
+ }
return result;
}
-static IrInstruction *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, IrInstructionIntToPtr *instruction) {
- Error err;
+static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstructionBitCast *instruction) {
IrInstruction *dest_type_value = instruction->dest_type->child;
ZigType *dest_type = ir_resolve_type(ira, dest_type_value);
if (type_is_invalid(dest_type))
return ira->codegen->invalid_instruction;
- // We explicitly check for the size, so we can use get_src_ptr_type
- if (get_src_ptr_type(dest_type) == nullptr) {
- ir_add_error(ira, dest_type_value, buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name)));
+ IrInstruction *value = instruction->value->child;
+ ZigType *src_type = value->value.type;
+ if (type_is_invalid(src_type))
+ return ira->codegen->invalid_instruction;
+
+ if (get_codegen_ptr_type(src_type) != nullptr) {
+ ir_add_error(ira, value,
+ buf_sprintf("unable to @bitCast from pointer type '%s'", buf_ptr(&src_type->name)));
return ira->codegen->invalid_instruction;
}
- if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusZeroBitsKnown)))
+ if (!type_can_bit_cast(src_type)) {
+ ir_add_error(ira, dest_type_value,
+ buf_sprintf("unable to @bitCast from type '%s'", buf_ptr(&src_type->name)));
return ira->codegen->invalid_instruction;
- if (!type_has_bits(dest_type)) {
+ }
+
+ if (get_codegen_ptr_type(dest_type) != nullptr) {
ir_add_error(ira, dest_type_value,
- buf_sprintf("type '%s' has 0 bits and cannot store information", buf_ptr(&dest_type->name)));
+ buf_sprintf("unable to @bitCast to pointer type '%s'", buf_ptr(&dest_type->name)));
return ira->codegen->invalid_instruction;
}
- IrInstruction *target = instruction->target->child;
- if (type_is_invalid(target->value.type))
+ if (!type_can_bit_cast(dest_type)) {
+ ir_add_error(ira, dest_type_value,
+ buf_sprintf("unable to @bitCast to type '%s'", buf_ptr(&dest_type->name)));
return ira->codegen->invalid_instruction;
+ }
+
+ return ir_analyze_bit_cast(ira, &instruction->base, value, dest_type);
+}
+
+static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target,
+ ZigType *ptr_type)
+{
+ assert(get_src_ptr_type(ptr_type) != nullptr);
+ assert(type_has_bits(ptr_type));
IrInstruction *casted_int = ir_implicit_cast(ira, target, ira->codegen->builtin_types.entry_usize);
if (type_is_invalid(casted_int->value.type))
@@ -20815,19 +21468,48 @@ static IrInstruction *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, IrInstru
if (!val)
return ira->codegen->invalid_instruction;
- IrInstruction *result = ir_const(ira, &instruction->base, dest_type);
+ IrInstruction *result = ir_const(ira, source_instr, ptr_type);
result->value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr;
result->value.data.x_ptr.mut = ConstPtrMutRuntimeVar;
result->value.data.x_ptr.data.hard_coded_addr.addr = bigint_as_unsigned(&val->data.x_bigint);
return result;
}
- IrInstruction *result = ir_build_int_to_ptr(&ira->new_irb, instruction->base.scope,
- instruction->base.source_node, nullptr, casted_int);
- result->value.type = dest_type;
+ IrInstruction *result = ir_build_int_to_ptr(&ira->new_irb, source_instr->scope,
+ source_instr->source_node, nullptr, casted_int);
+ result->value.type = ptr_type;
return result;
}
+static IrInstruction *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, IrInstructionIntToPtr *instruction) {
+ Error err;
+ IrInstruction *dest_type_value = instruction->dest_type->child;
+ ZigType *dest_type = ir_resolve_type(ira, dest_type_value);
+ if (type_is_invalid(dest_type))
+ return ira->codegen->invalid_instruction;
+
+ // We explicitly check for the size, so we can use get_src_ptr_type
+ if (get_src_ptr_type(dest_type) == nullptr) {
+ ir_add_error(ira, dest_type_value, buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name)));
+ return ira->codegen->invalid_instruction;
+ }
+
+ if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusZeroBitsKnown)))
+ return ira->codegen->invalid_instruction;
+ if (!type_has_bits(dest_type)) {
+ ir_add_error(ira, dest_type_value,
+ buf_sprintf("type '%s' has 0 bits and cannot store information", buf_ptr(&dest_type->name)));
+ return ira->codegen->invalid_instruction;
+ }
+
+
+ IrInstruction *target = instruction->target->child;
+ if (type_is_invalid(target->value.type))
+ return ira->codegen->invalid_instruction;
+
+ return ir_analyze_int_to_ptr(ira, &instruction->base, target, dest_type);
+}
+
static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
IrInstructionDeclRef *instruction)
{
@@ -20931,6 +21613,15 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct
} else if (child_type->id == ZigTypeIdOpaque && instruction->ptr_len == PtrLenUnknown) {
ir_add_error(ira, &instruction->base, buf_sprintf("unknown-length pointer to opaque"));
return ira->codegen->invalid_instruction;
+ } else if (instruction->ptr_len == PtrLenC) {
+ if (!type_allowed_in_extern(ira->codegen, child_type)) {
+ ir_add_error(ira, &instruction->base,
+ buf_sprintf("C pointers cannot point to non-C-ABI-compatible type '%s'", buf_ptr(&child_type->name)));
+ return ira->codegen->invalid_instruction;
+ } else if (child_type->id == ZigTypeIdOpaque) {
+ ir_add_error(ira, &instruction->base, buf_sprintf("C pointers cannot point opaque types"));
+ return ira->codegen->invalid_instruction;
+ }
}
uint32_t align_bytes;
@@ -21068,20 +21759,10 @@ static IrInstruction *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstruct
return ir_const_type(ira, &instruction->base, enum_type->data.enumeration.tag_int_type);
} else if (enum_type->id == ZigTypeIdUnion) {
- if ((err = ensure_complete_type(ira->codegen, enum_type)))
- return ira->codegen->invalid_instruction;
-
- AstNode *decl_node = enum_type->data.unionation.decl_node;
- if (decl_node->data.container_decl.auto_enum || decl_node->data.container_decl.init_arg_expr != nullptr) {
- assert(enum_type->data.unionation.tag_type != nullptr);
-
- return ir_const_type(ira, &instruction->base, enum_type->data.unionation.tag_type);
- } else {
- ErrorMsg *msg = ir_add_error(ira, target_inst, buf_sprintf("union '%s' has no tag",
- buf_ptr(&enum_type->name)));
- add_error_note(ira->codegen, msg, decl_node, buf_sprintf("consider 'union(enum)' here"));
+ ZigType *tag_type = ir_resolve_union_tag_type(ira, instruction->target, enum_type);
+ if (type_is_invalid(tag_type))
return ira->codegen->invalid_instruction;
- }
+ return ir_const_type(ira, &instruction->base, tag_type);
} else {
ir_add_error(ira, target_inst, buf_sprintf("expected enum or union, found '%s'",
buf_ptr(&enum_type->name)));
@@ -21662,23 +22343,11 @@ static IrInstruction *ir_analyze_instruction_bit_reverse(IrAnalyze *ira, IrInstr
static IrInstruction *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstructionEnumToInt *instruction) {
- Error err;
IrInstruction *target = instruction->target->child;
if (type_is_invalid(target->value.type))
return ira->codegen->invalid_instruction;
- if (target->value.type->id != ZigTypeIdEnum) {
- ir_add_error(ira, instruction->target,
- buf_sprintf("expected enum, found type '%s'", buf_ptr(&target->value.type->name)));
- return ira->codegen->invalid_instruction;
- }
-
- if ((err = type_resolve(ira->codegen, target->value.type, ResolveStatusZeroBitsKnown)))
- return ira->codegen->invalid_instruction;
-
- ZigType *tag_type = target->value.type->data.enumeration.tag_int_type;
-
- return ir_analyze_enum_to_int(ira, &instruction->base, target, tag_type);
+ return ir_analyze_enum_to_int(ira, &instruction->base, target);
}
static IrInstruction *ir_analyze_instruction_int_to_enum(IrAnalyze *ira, IrInstructionIntToEnum *instruction) {
@@ -21750,6 +22419,9 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
case IrInstructionIdArrayToVector:
case IrInstructionIdVectorToArray:
case IrInstructionIdAssertZero:
+ case IrInstructionIdResizeSlice:
+ case IrInstructionIdLoadPtrGen:
+ case IrInstructionIdBitCastGen:
zig_unreachable();
case IrInstructionIdReturn:
@@ -22149,12 +22821,14 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdCmpxchgGen:
case IrInstructionIdCmpxchgSrc:
case IrInstructionIdAssertZero:
+ case IrInstructionIdResizeSlice:
return true;
case IrInstructionIdPhi:
case IrInstructionIdUnOp:
case IrInstructionIdBinOp:
case IrInstructionIdLoadPtr:
+ case IrInstructionIdLoadPtrGen:
case IrInstructionIdConst:
case IrInstructionIdCast:
case IrInstructionIdContainerInitList:
@@ -22205,6 +22879,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdPtrCastSrc:
case IrInstructionIdPtrCastGen:
case IrInstructionIdBitCast:
+ case IrInstructionIdBitCastGen:
case IrInstructionIdWidenOrShorten:
case IrInstructionIdPtrToInt:
case IrInstructionIdIntToPtr:
diff --git a/src/ir.hpp b/src/ir.hpp
@@ -16,7 +16,7 @@ bool ir_gen_fn(CodeGen *g, ZigFn *fn_entry);
ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,
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,
- IrExecutable *parent_exec);
+ IrExecutable *parent_exec, AstNode *expected_type_source_node);
ZigType *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutable *new_executable,
ZigType *expected_type, AstNode *expected_type_source_node);
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
@@ -336,6 +336,11 @@ static void ir_print_load_ptr(IrPrint *irp, IrInstructionLoadPtr *instruction) {
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) {
fprintf(irp->f, "*");
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) {
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, ",");
ir_print_other_instruction(irp, instruction->value);
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) {
fprintf(irp->f, "WidenOrShorten(");
ir_print_other_instruction(irp, instruction->target);
@@ -990,6 +999,12 @@ static void ir_print_assert_zero(IrPrint *irp, IrInstructionAssertZero *instruct
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) {
fprintf(irp->f, "inttoerr ");
ir_print_other_instruction(irp, instruction->target);
@@ -1462,6 +1477,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdLoadPtr:
ir_print_load_ptr(irp, (IrInstructionLoadPtr *)instruction);
break;
+ case IrInstructionIdLoadPtrGen:
+ ir_print_load_ptr_gen(irp, (IrInstructionLoadPtrGen *)instruction);
+ break;
case IrInstructionIdStorePtr:
ir_print_store_ptr(irp, (IrInstructionStorePtr *)instruction);
break;
@@ -1678,6 +1696,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdBitCast:
ir_print_bit_cast(irp, (IrInstructionBitCast *)instruction);
break;
+ case IrInstructionIdBitCastGen:
+ ir_print_bit_cast_gen(irp, (IrInstructionBitCastGen *)instruction);
+ break;
case IrInstructionIdWidenOrShorten:
ir_print_widen_or_shorten(irp, (IrInstructionWidenOrShorten *)instruction);
break;
@@ -1852,6 +1873,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdAssertZero:
ir_print_assert_zero(irp, (IrInstructionAssertZero *)instruction);
break;
+ case IrInstructionIdResizeSlice:
+ ir_print_resize_slice(irp, (IrInstructionResizeSlice *)instruction);
+ break;
}
fprintf(irp->f, "\n");
}
diff --git a/src/libc_installation.cpp b/src/libc_installation.cpp
@@ -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
+}
diff --git a/src/libc_installation.hpp b/src/libc_installation.hpp
@@ -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
diff --git a/src/link.cpp b/src/link.cpp
@@ -17,32 +17,33 @@ struct LinkJob {
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();
- 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);
}
static const char *get_libc_static_file(CodeGen *g, const char *file) {
+ assert(g->libc != nullptr);
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);
}
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
// when we link compiler_rt and builtin as libraries rather than 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
OutType child_out_type = OutTypeLib;
- if (parent_gen->zig_target.os == OsMacOSX) {
+ if (parent_gen->zig_target->os == OsMacOSX) {
child_out_type = OutTypeObj;
}
- CodeGen *child_gen = codegen_create(full_path, child_target, child_out_type,
- parent_gen->build_mode, parent_gen->zig_lib_dir, parent_gen->zig_std_dir);
+ 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->libc);
child_gen->out_h_path = nullptr;
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_is_static(child_gen, true);
child_gen->disable_pic = parent_gen->disable_pic;
+ child_gen->valgrind_support = ValgrindSupportDisabled;
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) {
- switch (t->arch.arch) {
+ switch (t->arch) {
case ZigLLVM_aarch64:
return "arm64";
case ZigLLVM_thumb:
@@ -107,13 +109,13 @@ static const char *get_darwin_arch_string(const ZigTarget *t) {
case ZigLLVM_ppc64le:
return "ppc64le";
default:
- return ZigLLVMGetArchTypeName(t->arch.arch);
+ return ZigLLVMGetArchTypeName(t->arch);
}
}
static const char *getLDMOption(const ZigTarget *t) {
- switch (t->arch.arch) {
+ switch (t->arch) {
case ZigLLVM_x86:
return "elf_i386";
case ZigLLVM_aarch64:
@@ -147,7 +149,7 @@ static const char *getLDMOption(const ZigTarget *t) {
case ZigLLVM_systemz:
return "elf64_s390";
case ZigLLVM_x86_64:
- if (t->env_type == ZigLLVM_GNUX32) {
+ if (t->abi == ZigLLVM_GNUX32) {
return "elf32_x86_64";
}
// 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);
}
-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) {
CodeGen *g = lj->codegen;
lj->args.append("-error-limit=0");
- if (g->libc_link_lib != nullptr) {
- find_libc_lib_path(g);
- }
-
if (g->linker_script) {
lj->args.append("-T");
lj->args.append(g->linker_script);
}
- if (g->no_rosegment_workaround) {
- lj->args.append("--no-rosegment");
- }
lj->args.append("--gc-sections");
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 shared = !g->is_static && is_lib;
Buf *soname = nullptr;
if (g->is_static) {
- if (g->zig_target.arch.arch == ZigLLVM_arm || g->zig_target.arch.arch == ZigLLVM_armeb ||
- g->zig_target.arch.arch == ZigLLVM_thumb || g->zig_target.arch.arch == ZigLLVM_thumbeb)
+ if (g->zig_target->arch == ZigLLVM_arm || g->zig_target->arch == ZigLLVM_armeb ||
+ g->zig_target->arch == ZigLLVM_thumb || g->zig_target->arch == ZigLLVM_thumbeb)
{
lj->args.append("-Bstatic");
} else {
@@ -263,15 +214,18 @@ static void construct_linker_job_elf(LinkJob *lj) {
if (lj->link_in_crt) {
const char *crt1o;
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";
crtbegino = "crtbeginT.o";
} else {
crt1o = "Scrt1.o";
crtbegino = "crtbegin.o";
}
- lj->args.append(get_libc_file(g, crt1o));
- lj->args.append(get_libc_file(g, "crti.o"));
+ lj->args.append(get_libc_crt_file(g, crt1o));
+ lj->args.append(get_libc_crt_file(g, "crti.o"));
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) {
+ assert(g->libc != nullptr);
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(buf_ptr(g->libc_static_lib_dir));
- }
+ lj->args.append(buf_ptr(&g->libc->static_lib_dir));
- if (!g->is_static) {
- if (g->dynamic_linker != nullptr) {
- assert(buf_len(g->dynamic_linker) != 0);
- lj->args.append("-dynamic-linker");
- lj->args.append(buf_ptr(g->dynamic_linker));
- } else {
- Buf *resolved_dynamic_linker = get_dynamic_linker_path(g);
+ if (!g->is_static) {
+ assert(buf_len(&g->libc->dynamic_linker_path) != 0);
lj->args.append("-dynamic-linker");
- lj->args.append(buf_ptr(resolved_dynamic_linker));
+ lj->args.append(buf_ptr(&g->libc->dynamic_linker_path));
}
+
}
if (shared) {
@@ -390,14 +345,14 @@ static void construct_linker_job_elf(LinkJob *lj) {
// crt end
if (lj->link_in_crt) {
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");
}
- if (g->zig_target.os == OsZen) {
+ if (g->zig_target->os == OsZen) {
lj->args.append("-e");
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) {
-// return (target->os == ZigLLVM_Win32 && target->env_type == ZigLLVM_Cygnus) ||
-// (target->os == ZigLLVM_Win32 && target->env_type == ZigLLVM_GNU);
+// return (target->os == ZigLLVM_Win32 && target->abi == ZigLLVM_Cygnus) ||
+// (target->os == ZigLLVM_Win32 && target->abi == ZigLLVM_GNU);
//}
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");
- } else if (g->zig_target.arch.arch == ZigLLVM_x86_64) {
+ } else if (g->zig_target->arch == ZigLLVM_x86_64) {
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");
}
}
@@ -515,7 +470,7 @@ static void add_nt_link_args(LinkJob *lj, bool is_library) {
// lj->args.append("-Bdynamic");
// if (dll || shared) {
// lj->args.append("-e");
-// if (g->zig_target.arch.arch == ZigLLVM_x86) {
+// if (g->zig_target.arch == ZigLLVM_x86) {
// lj->args.append("_DllMainCRTStartup@12");
// } else {
// 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("-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);
//if (!g->is_static && !is_android) {
// if (!is_cyg_ming) {
@@ -588,10 +543,6 @@ static void construct_linker_job_coff(LinkJob *lj) {
lj->args.append("/ERRORLIMIT:0");
- if (g->libc_link_lib != nullptr) {
- find_libc_lib_path(g);
- }
-
lj->args.append("/NOLOGO");
if (!g->strip_debug_symbols) {
@@ -608,6 +559,11 @@ static void construct_linker_job_coff(LinkJob *lj) {
bool is_library = g->out_type == OutTypeLib;
switch (g->subsystem) {
case TargetSubsystemAuto:
+ if (g->zig_target->os == OsUefi) {
+ add_uefi_link_args(lj);
+ } else {
+ add_nt_link_args(lj, is_library);
+ }
break;
case TargetSubsystemConsole:
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))));
if (g->libc_link_lib != nullptr) {
- lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->msvc_lib_dir))));
- lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->kernel32_lib_dir))));
+ assert(g->libc != nullptr);
- lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_lib_dir))));
- if (g->libc_static_lib_dir != nullptr) {
- 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->msvc_lib_dir))));
+ 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->crt_dir))));
}
if (is_library && !g->is_static) {
@@ -687,7 +641,7 @@ static void construct_linker_job_coff(LinkJob *lj) {
continue;
}
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));
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("-OUT:%s", buf_ptr(generated_lib_path))));
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));
exit(1);
}
@@ -786,7 +741,7 @@ static void get_darwin_platform(LinkJob *lj, DarwinPlatform *platform) {
platform->kind = MacOS;
} else if (g->mios_version_min) {
platform->kind = IPhoneOS;
- } else if (g->zig_target.os == OsMacOSX) {
+ } else if (g->zig_target->os == OsMacOSX) {
platform->kind = MacOS;
g->mmacosx_version_min = buf_create_from_str("10.10");
} else {
@@ -813,8 +768,8 @@ static void get_darwin_platform(LinkJob *lj, DarwinPlatform *platform) {
}
if (platform->kind == IPhoneOS &&
- (g->zig_target.arch.arch == ZigLLVM_x86 ||
- g->zig_target.arch.arch == ZigLLVM_x86_64))
+ (g->zig_target->arch == ZigLLVM_x86 ||
+ g->zig_target->arch == ZigLLVM_x86_64))
{
platform->kind = IPhoneOSSimulator;
}
@@ -878,7 +833,7 @@ static void construct_linker_job_macho(LinkJob *lj) {
}
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;
get_darwin_platform(lj, &platform);
@@ -893,7 +848,11 @@ static void construct_linker_job_macho(LinkJob *lj) {
lj->args.append("-ios_simulator_version_min");
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) {
@@ -914,7 +873,9 @@ static void construct_linker_job_macho(LinkJob *lj) {
add_rpath(lj, &g->output_file_path);
if (shared) {
- lj->args.append("-headerpad_max_install_names");
+ if (g->system_linker_hack) {
+ lj->args.append("-headerpad_max_install_names");
+ }
} else if (g->is_static) {
lj->args.append("-lcrt0.o");
} else {
@@ -929,7 +890,7 @@ static void construct_linker_job_macho(LinkJob *lj) {
}
break;
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
} else if (darwin_version_lt(&platform, 3, 1)) {
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));
}
- 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) {
LinkLib *link_lib = g->link_libs_list.at(lib_i);
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) {
- switch (lj->codegen->zig_target.oformat) {
+ switch (target_object_format(lj->codegen->zig_target)) {
case ZigLLVM_UnknownObjectFormat:
zig_unreachable();
@@ -1040,7 +1001,7 @@ void codegen_link(CodeGen *g) {
for (size_t i = 0; i < g->link_objects.length; i += 1) {
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");
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));
@@ -1065,7 +1026,7 @@ void codegen_link(CodeGen *g) {
Buf diag = BUF_INIT;
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;
ZigList<const char *> args = {};
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) {
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));
exit(1);
}
diff --git a/src/main.cpp b/src/main.cpp
@@ -13,16 +13,17 @@
#include "error.hpp"
#include "os.hpp"
#include "target.hpp"
+#include "libc_installation.hpp"
#include <stdio.h>
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;
}
-static int print_full_usage(const char *arg0) {
- fprintf(stdout,
+static int print_full_usage(const char *arg0, FILE *file, int return_code) {
+ fprintf(file,
"Usage: %s [command] [options]\n"
"\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-obj [source] create object from source or assembly\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"
" init-exe initialize a `zig build` application 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"
" translate-c [source] convert c code to zig code\n"
" targets list available compilation targets\n"
@@ -44,16 +47,20 @@ static int print_full_usage(const char *arg0) {
"\n"
"Compile Options:\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 [auto|off|on] build in global cache, print out paths to stdout\n"
" --color [auto|off|on] enable or disable colored error messages\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"
" -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"
" --output [file] override destination path\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-end pop current pkg\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"
" --static output will be statically linked\n"
" --strip exclude debug symbols\n"
- " --target-arch [name] specify target architecture\n"
- " --target-environ [name] specify target environment\n"
- " --target-os [name] specify target operating system\n"
+ " -target [name] <arch><sub>-<os>-<abi> see the targets command\n"
" --verbose-tokenize enable compiler debug output for tokenization\n"
" --verbose-ast enable compiler debug output for AST parsing\n"
" --verbose-link enable compiler debug output for linking\n"
" --verbose-ir enable compiler debug output for Zig IR\n"
" --verbose-llvm-ir enable compiler debug output for LLVM IR\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"
" -isystem [dir] add additional search path for other .h files\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"
" --dynamic-linker [path] set the path to ld.so\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"
" --forbid-library [lib] make it an error to link against lib\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"
" -rdynamic add all symbols to the dynamic symbol table\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"
" -framework [name] (darwin) link against framework\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-bin appends test binary path to test cmd args\n"
, 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"
@@ -122,6 +143,14 @@ static const char *ZIG_ZEN = "\n"
" * Minimize energy spent on coding style.\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) {
ZigTarget native;
get_native_target(&native);
@@ -129,28 +158,36 @@ static int print_target_list(FILE *f) {
fprintf(f, "Architectures:\n");
size_t arch_count = target_arch_count();
for (size_t arch_i = 0; arch_i < arch_count; arch_i += 1) {
- const ArchType *arch = get_target_arch(arch_i);
- char arch_name[50];
- get_arch_name(arch_name, arch);
- const char *native_str = (native.arch.arch == arch->arch && native.arch.sub_arch == arch->sub_arch) ?
- " (native)" : "";
- fprintf(f, " %s%s\n", arch_name, native_str);
+ ZigLLVM_ArchType arch = target_arch_enum(arch_i);
+ if (!arch_available_in_llvm(arch))
+ continue;
+ const char *arch_name = target_arch_name(arch);
+ SubArchList sub_arch_list = target_subarch_list(arch);
+ 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");
size_t os_count = target_os_count();
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)" : "";
- 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");
- size_t environ_count = target_environ_count();
- for (size_t i = 0; i < environ_count; i += 1) {
- ZigLLVM_EnvironmentType environ_type = get_target_environ(i);
- const char *native_str = (native.env_type == environ_type) ? " (native)" : "";
- fprintf(f, " %s%s\n", ZigLLVMGetEnvironmentTypeName(environ_type), native_str);
+ fprintf(f, "\nC ABIs:\n");
+ size_t abi_count = target_abi_count();
+ for (size_t i = 0; i < abi_count; i += 1) {
+ ZigLLVM_EnvironmentType abi = target_abi_enum(i);
+ const char *native_str = (native.abi == abi) ? " (native)" : "";
+ fprintf(f, " %s%s\n", target_abi_name(abi), native_str);
}
return EXIT_SUCCESS;
@@ -160,13 +197,13 @@ enum Cmd {
CmdNone,
CmdBuild,
CmdBuiltin,
- CmdHelp,
CmdRun,
CmdTargets,
CmdTest,
CmdTranslateC,
CmdVersion,
CmdZen,
+ CmdLibC,
};
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();
}
+extern "C" int ZigClang_main(int argc, char **argv);
+
int main(int argc, char **argv) {
char *arg0 = argv[0];
Error err;
@@ -236,6 +275,12 @@ int main(int argc, char **argv) {
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.
os_init();
@@ -345,6 +390,7 @@ int main(int argc, char **argv) {
const char *in_file = nullptr;
const char *out_file = nullptr;
const char *out_file_h = nullptr;
+ const char *out_file_lib = nullptr;
bool strip = false;
bool is_static = false;
OutType out_type = OutTypeUnknown;
@@ -355,23 +401,17 @@ int main(int argc, char **argv) {
bool verbose_ir = false;
bool verbose_llvm_ir = false;
bool verbose_cimport = false;
+ bool verbose_cc = false;
ErrColor color = ErrColorAuto;
CacheOpt enable_cache = CacheOptAuto;
- const char *libc_lib_dir = 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;
+ const char *libc_txt = nullptr;
ZigList<const char *> clang_argv = {0};
ZigList<const char *> llvm_argv = {0};
ZigList<const char *> lib_dirs = {0};
ZigList<const char *> link_libs = {0};
ZigList<const char *> forbidden_link_libs = {0};
ZigList<const char *> frameworks = {0};
- const char *target_arch = nullptr;
- const char *target_os = nullptr;
- const char *target_environ = nullptr;
+ const char *target_string = nullptr;
bool rdynamic = false;
const char *mmacosx_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};
bool each_lib_rpath = false;
ZigList<const char *> objects = {0};
+ ZigList<CFile *> c_source_files = {0};
ZigList<const char *> asm_files = {0};
const char *test_filter = nullptr;
const char *test_name_prefix = nullptr;
@@ -392,11 +433,11 @@ int main(int argc, char **argv) {
BuildMode build_mode = BuildModeDebug;
ZigList<const char *> test_exec_args = {0};
int runtime_args_start = -1;
- bool no_rosegment_workaround = false;
bool system_linker_hack = false;
TargetSubsystem subsystem = TargetSubsystemAuto;
bool is_single_threaded = false;
Buf *override_std_dir = nullptr;
+ ValgrindSupport valgrind_support = ValgrindSupportAuto;
if (argc >= 2 && strcmp(argv[1], "build") == 0) {
Buf zig_exe_path_buf = BUF_INIT;
@@ -432,8 +473,11 @@ int main(int argc, char **argv) {
Buf *build_runner_path = buf_alloc();
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(),
- override_std_dir);
+ ZigTarget target;
+ 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;
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"));
@@ -484,6 +528,7 @@ int main(int argc, char **argv) {
" --verbose-ir Enable compiler debug output for Zig IR\n"
" --verbose-llvm-ir Enable compiler debug output for LLVM IR\n"
" --verbose-cimport Enable compiler debug output for C imports\n"
+ " --verbose-cc Enable compiler debug output for C compilation\n"
"\n"
, zig_exe_path);
return EXIT_SUCCESS;
@@ -493,7 +538,7 @@ int main(int argc, char **argv) {
"No 'build.zig' file found.\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"
- "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;
}
@@ -515,6 +560,37 @@ int main(int argc, char **argv) {
fprintf(stderr, "\n");
}
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) {
@@ -527,6 +603,12 @@ int main(int argc, char **argv) {
build_mode = BuildModeSafeRelease;
} else if (strcmp(arg, "--release-small") == 0) {
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) {
strip = true;
} else if (strcmp(arg, "--static") == 0) {
@@ -543,16 +625,20 @@ int main(int argc, char **argv) {
verbose_llvm_ir = true;
} else if (strcmp(arg, "--verbose-cimport") == 0) {
verbose_cimport = true;
+ } else if (strcmp(arg, "--verbose-cc") == 0) {
+ verbose_cc = true;
} else if (strcmp(arg, "-rdynamic") == 0) {
rdynamic = true;
- } else if (strcmp(arg, "--no-rosegment") == 0) {
- no_rosegment_workaround = true;
} else if (strcmp(arg, "--each-lib-rpath") == 0) {
each_lib_rpath = true;
} else if (strcmp(arg, "-ftime-report") == 0) {
timing_info = true;
} else if (strcmp(arg, "--disable-pic") == 0) {
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) {
system_linker_hack = true;
} else if (strcmp(arg, "--single-threaded") == 0) {
@@ -590,6 +676,8 @@ int main(int argc, char **argv) {
out_file = argv[i];
} else if (strcmp(arg, "--output-h") == 0) {
out_file_h = argv[i];
+ } else if (strcmp(arg, "--output-lib") == 0) {
+ out_file_lib = argv[i];
} else if (strcmp(arg, "--color") == 0) {
if (strcmp(argv[i], "auto") == 0) {
color = ErrColorAuto;
@@ -625,18 +713,8 @@ int main(int argc, char **argv) {
}
} else if (strcmp(arg, "--name") == 0) {
out_name = argv[i];
- } else if (strcmp(arg, "--libc-lib-dir") == 0) {
- libc_lib_dir = 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, "--libc") == 0) {
+ libc_txt = argv[i];
} else if (strcmp(arg, "-isystem") == 0) {
clang_argv.append("-isystem");
clang_argv.append(argv[i]);
@@ -658,16 +736,25 @@ int main(int argc, char **argv) {
forbidden_link_libs.append(argv[i]);
} else if (strcmp(arg, "--object") == 0) {
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) {
asm_files.append(argv[i]);
} else if (strcmp(arg, "--cache-dir") == 0) {
cache_dir = argv[i];
- } else if (strcmp(arg, "--target-arch") == 0) {
- target_arch = 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, "-target") == 0) {
+ target_string = argv[i];
} else if (strcmp(arg, "-mmacosx-version-min") == 0) {
mmacosx_version_min = argv[i];
} 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) {
cmd = CmdBuild;
out_type = OutTypeLib;
- } else if (strcmp(arg, "help") == 0) {
- cmd = CmdHelp;
} else if (strcmp(arg, "run") == 0) {
cmd = CmdRun;
out_type = OutTypeExe;
@@ -745,6 +830,8 @@ int main(int argc, char **argv) {
cmd = CmdVersion;
} else if (strcmp(arg, "zen") == 0) {
cmd = CmdZen;
+ } else if (strcmp(arg, "libc") == 0) {
+ cmd = CmdLibC;
} else if (strcmp(arg, "translate-c") == 0) {
cmd = CmdTranslateC;
} else if (strcmp(arg, "test") == 0) {
@@ -764,6 +851,7 @@ int main(int argc, char **argv) {
case CmdRun:
case CmdTranslateC:
case CmdTest:
+ case CmdLibC:
if (!in_file) {
in_file = arg;
if (cmd == CmdRun) {
@@ -776,7 +864,6 @@ int main(int argc, char **argv) {
}
break;
case CmdBuiltin:
- case CmdHelp:
case CmdVersion:
case CmdZen:
case CmdTargets:
@@ -795,36 +882,34 @@ int main(int argc, char **argv) {
init_all_targets();
- ZigTarget alloc_target;
- ZigTarget *target;
- if (!target_arch && !target_os && !target_environ) {
- target = nullptr;
+ ZigTarget target;
+ if (target_string == nullptr) {
+ get_native_target(&target);
} else {
- target = &alloc_target;
- get_unknown_target(target);
- if (target_arch) {
- if (parse_target_arch(target_arch, &target->arch)) {
- fprintf(stderr, "invalid --target-arch argument\n");
- 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);
- }
+ if ((err = target_parse_triple(&target, target_string))) {
+ fprintf(stderr, "invalid target: %s\n", err_str(err));
+ return print_error_usage(arg0);
}
}
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: {
- 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;
Buf *builtin_source = codegen_generate_builtin_source(g);
if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) {
@@ -838,15 +923,43 @@ int main(int argc, char **argv) {
case CmdTranslateC:
case CmdTest:
{
- 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");
+ if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0 &&
+ 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);
} else if ((cmd == CmdTranslateC || cmd == CmdTest || cmd == CmdRun) && !in_file) {
fprintf(stderr, "Expected source file argument.\n");
return print_error_usage(arg0);
- } else if (cmd == CmdBuild && out_type == OutTypeObj && objects.length != 0) {
- fprintf(stderr, "When building an object file, --object arguments are invalid.\n");
- return print_error_usage(arg0);
+ } else if (cmd == CmdBuild && out_type == OutTypeObj) {
+ 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);
+ }
+ 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);
@@ -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) {
fprintf(stderr, "--name [name] not provided and unable to infer\n\n");
return print_error_usage(arg0);
@@ -883,8 +1003,17 @@ int main(int argc, char **argv) {
if (cmd == CmdRun && buf_out_name == nullptr) {
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(),
- override_std_dir);
+ ZigLibCInstallation *libc = nullptr;
+ 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;
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_strip(g, strip);
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_ast = verbose_ast;
g->verbose_link = verbose_link;
g->verbose_ir = verbose_ir;
g->verbose_llvm_ir = verbose_llvm_ir;
g->verbose_cimport = verbose_cimport;
+ g->verbose_cc = verbose_cc;
codegen_set_errmsg_color(g, color);
g->system_linker_hack = system_linker_hack;
@@ -949,7 +1067,6 @@ int main(int argc, char **argv) {
}
codegen_set_rdynamic(g, rdynamic);
- g->no_rosegment_workaround = no_rosegment_workaround;
if (mmacosx_version_min && mios_version_min) {
fprintf(stderr, "-mmacosx-version-min and -mios-version-min options not allowed together\n");
return EXIT_FAILURE;
@@ -975,11 +1092,14 @@ int main(int argc, char **argv) {
codegen_set_output_path(g, buf_create_from_str(out_file));
if (out_file_h != nullptr && (out_type == OutTypeObj || out_type == OutTypeLib))
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);
if (cmd == CmdBuild || cmd == CmdRun || cmd == CmdTest) {
+ g->c_source_files = c_source_files;
for (size_t i = 0; i < objects.length; i += 1) {
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",
buf_ptr(test_exe_path));
return 0;
@@ -1079,8 +1199,6 @@ int main(int argc, char **argv) {
zig_unreachable();
}
}
- case CmdHelp:
- return print_full_usage(arg0);
case CmdVersion:
printf("%s\n", ZIG_VERSION_STRING);
return EXIT_SUCCESS;
@@ -1090,7 +1208,6 @@ int main(int argc, char **argv) {
case CmdTargets:
return print_target_list(stdout);
case CmdNone:
- fprintf(stderr, "Zig programming language\n");
- return print_error_usage(arg0);
+ return print_full_usage(arg0, stderr, EXIT_FAILURE);
}
}
diff --git a/src/os.cpp b/src/os.cpp
@@ -50,11 +50,11 @@ typedef SSIZE_T ssize_t;
#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>
#endif
-#if defined(ZIG_OS_FREEBSD)
+#if defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD)
#include <sys/sysctl.h>
#endif
@@ -78,7 +78,7 @@ static clock_serv_t cclock;
#if defined(__APPLE__) && !defined(environ)
#include <crt_externs.h>
#define environ (*_NSGetEnviron())
-#elif defined(ZIG_OS_FREEBSD)
+#elif defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD)
extern char **environ;
#endif
@@ -1099,7 +1099,7 @@ Error os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang) {
case EINTR:
return ErrorInterrupted;
case EINVAL:
- zig_unreachable();
+ return ErrorInvalidFilename;
case ENFILE:
case ENOMEM:
return ErrorSystemResources;
@@ -1232,6 +1232,18 @@ static Error os_buf_to_tmp_file_posix(Buf *contents, Buf *suffix, Buf *out_tmp_p
}
#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)
static Error os_buf_to_tmp_file_windows(Buf *contents, Buf *suffix, Buf *out_tmp_path) {
char tmp_dir[MAX_PATH + 1];
@@ -1458,6 +1470,15 @@ Error os_self_exe_path(Buf *out_path) {
}
buf_resize(out_path, cb - 1);
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
return ErrorFileNotFound;
}
@@ -1541,7 +1562,7 @@ void os_stderr_set_color(TermColor color) {
#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)
buf_resize(output_buf, 0);
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_append_str(tmp_buf, "ucrt.lib");
if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) {
- return 0;
+ return ErrorNone;
}
else {
buf_resize(output_buf, 0);
@@ -1573,12 +1594,12 @@ int os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_Arch
#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)
buf_resize(output_buf, 0);
buf_appendf(output_buf, "%s\\Include\\%s\\ucrt", sdk->path10_ptr, sdk->version10_ptr);
if (GetFileAttributesA(buf_ptr(output_buf)) != INVALID_FILE_ATTRIBUTES) {
- return 0;
+ return ErrorNone;
}
else {
buf_resize(output_buf, 0);
@@ -1589,7 +1610,7 @@ int os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf* output_buf) {
#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)
{
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_append_str(tmp_buf, "kernel32.lib");
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_append_str(tmp_buf, "kernel32.lib");
if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) {
- return 0;
+ return ErrorNone;
}
}
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) {
ZigList<Buf *> *libs = reinterpret_cast< ZigList<Buf *> *>(data);
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
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);
dl_iterate_phdr(self_exe_shared_libs_callback, &paths);
return ErrorNone;
diff --git a/src/os.hpp b/src/os.hpp
@@ -25,6 +25,8 @@
#define ZIG_OS_LINUX
#elif defined(__FreeBSD__)
#define ZIG_OS_FREEBSD
+#elif defined(__NetBSD__)
+#define ZIG_OS_NETBSD
#else
#define ZIG_OS_UNKNOWN
#endif
@@ -119,6 +121,7 @@ Error ATTRIBUTE_MUST_USE os_get_cwd(Buf *out_cwd);
bool os_stderr_tty(void);
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_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);
-int 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);
-int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);
+Error ATTRIBUTE_MUST_USE os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf *output_buf);
+Error ATTRIBUTE_MUST_USE os_get_win32_ucrt_lib_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);
diff --git a/src/parser.cpp b/src/parser.cpp
@@ -2739,6 +2739,7 @@ static AstNode *ast_parse_async_prefix(ParseContext *pc) {
AstNode *res = ast_create_node(pc, NodeTypeFnCallExpr, async);
res->data.fn_call_expr.is_async = true;
+ res->data.fn_call_expr.seen = false;
if (eat_token_if(pc, TokenIdCmpLessThan) != nullptr) {
AstNode *prefix_expr = ast_expect(pc, ast_parse_prefix_expr);
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);
res->data.fn_call_expr.params = params;
+ res->data.fn_call_expr.seen = false;
return res;
}
@@ -2778,7 +2780,8 @@ static AstNode *ast_parse_array_type_start(ParseContext *pc) {
// PtrTypeStart
// <- ASTERISK
// / ASTERISK2
-// / LBRACKET ASTERISK RBRACKET
+// / PTRUNKNOWN
+// / PTRC
static AstNode *ast_parse_ptr_type_start(ParseContext *pc) {
Token *asterisk = eat_token_if(pc, TokenIdStar);
if (asterisk != nullptr) {
@@ -2804,6 +2807,13 @@ static AstNode *ast_parse_ptr_type_start(ParseContext *pc) {
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;
}
diff --git a/src/target.cpp b/src/target.cpp
@@ -9,127 +9,116 @@
#include "error.hpp"
#include "target.hpp"
#include "util.hpp"
+#include "os.hpp"
#include <stdio.h>
-static const ArchType arch_list[] = {
- {ZigLLVM_arm, ZigLLVM_ARMSubArch_v8_5a},
- {ZigLLVM_arm, ZigLLVM_ARMSubArch_v8_4a},
- {ZigLLVM_arm, ZigLLVM_ARMSubArch_v8_3a},
- {ZigLLVM_arm, ZigLLVM_ARMSubArch_v8_2a},
- {ZigLLVM_arm, ZigLLVM_ARMSubArch_v8_1a},
- {ZigLLVM_arm, ZigLLVM_ARMSubArch_v8},
- {ZigLLVM_arm, ZigLLVM_ARMSubArch_v8r},
- {ZigLLVM_arm, ZigLLVM_ARMSubArch_v8m_baseline},
- {ZigLLVM_arm, ZigLLVM_ARMSubArch_v8m_mainline},
- {ZigLLVM_arm, ZigLLVM_ARMSubArch_v7},
- {ZigLLVM_arm, ZigLLVM_ARMSubArch_v7em},
- {ZigLLVM_arm, ZigLLVM_ARMSubArch_v7m},
- {ZigLLVM_arm, ZigLLVM_ARMSubArch_v7s},
- {ZigLLVM_arm, ZigLLVM_ARMSubArch_v7k},
- {ZigLLVM_arm, ZigLLVM_ARMSubArch_v7ve},
- {ZigLLVM_arm, ZigLLVM_ARMSubArch_v6},
- {ZigLLVM_arm, ZigLLVM_ARMSubArch_v6m},
- {ZigLLVM_arm, ZigLLVM_ARMSubArch_v6k},
- {ZigLLVM_arm, ZigLLVM_ARMSubArch_v6t2},
- {ZigLLVM_arm, ZigLLVM_ARMSubArch_v5},
- {ZigLLVM_arm, ZigLLVM_ARMSubArch_v5te},
- {ZigLLVM_arm, ZigLLVM_ARMSubArch_v4t},
-
- {ZigLLVM_armeb, ZigLLVM_ARMSubArch_v8_5a},
- {ZigLLVM_armeb, ZigLLVM_ARMSubArch_v8_4a},
- {ZigLLVM_armeb, ZigLLVM_ARMSubArch_v8_3a},
- {ZigLLVM_armeb, ZigLLVM_ARMSubArch_v8_2a},
- {ZigLLVM_armeb, ZigLLVM_ARMSubArch_v8_1a},
- {ZigLLVM_armeb, ZigLLVM_ARMSubArch_v8},
- {ZigLLVM_armeb, ZigLLVM_ARMSubArch_v8r},
- {ZigLLVM_armeb, ZigLLVM_ARMSubArch_v8m_baseline},
- {ZigLLVM_armeb, ZigLLVM_ARMSubArch_v8m_mainline},
- {ZigLLVM_armeb, ZigLLVM_ARMSubArch_v7},
- {ZigLLVM_armeb, ZigLLVM_ARMSubArch_v7em},
- {ZigLLVM_armeb, ZigLLVM_ARMSubArch_v7m},
- {ZigLLVM_armeb, ZigLLVM_ARMSubArch_v7s},
- {ZigLLVM_armeb, ZigLLVM_ARMSubArch_v7k},
- {ZigLLVM_armeb, ZigLLVM_ARMSubArch_v7ve},
- {ZigLLVM_armeb, ZigLLVM_ARMSubArch_v6},
- {ZigLLVM_armeb, ZigLLVM_ARMSubArch_v6m},
- {ZigLLVM_armeb, ZigLLVM_ARMSubArch_v6k},
- {ZigLLVM_armeb, ZigLLVM_ARMSubArch_v6t2},
- {ZigLLVM_armeb, ZigLLVM_ARMSubArch_v5},
- {ZigLLVM_armeb, ZigLLVM_ARMSubArch_v5te},
- {ZigLLVM_armeb, ZigLLVM_ARMSubArch_v4t},
-
- {ZigLLVM_aarch64, ZigLLVM_ARMSubArch_v8_5a},
- {ZigLLVM_aarch64, ZigLLVM_ARMSubArch_v8_4a},
- {ZigLLVM_aarch64, ZigLLVM_ARMSubArch_v8_3a},
- {ZigLLVM_aarch64, ZigLLVM_ARMSubArch_v8_2a},
- {ZigLLVM_aarch64, ZigLLVM_ARMSubArch_v8_1a},
- {ZigLLVM_aarch64, ZigLLVM_ARMSubArch_v8},
- {ZigLLVM_aarch64, ZigLLVM_ARMSubArch_v8r},
- {ZigLLVM_aarch64, ZigLLVM_ARMSubArch_v8m_baseline},
- {ZigLLVM_aarch64, ZigLLVM_ARMSubArch_v8m_mainline},
-
- {ZigLLVM_aarch64_be, ZigLLVM_ARMSubArch_v8_5a},
- {ZigLLVM_aarch64_be, ZigLLVM_ARMSubArch_v8_4a},
- {ZigLLVM_aarch64_be, ZigLLVM_ARMSubArch_v8_3a},
- {ZigLLVM_aarch64_be, ZigLLVM_ARMSubArch_v8_2a},
- {ZigLLVM_aarch64_be, ZigLLVM_ARMSubArch_v8_1a},
- {ZigLLVM_aarch64_be, ZigLLVM_ARMSubArch_v8},
- {ZigLLVM_aarch64_be, ZigLLVM_ARMSubArch_v8r},
- {ZigLLVM_aarch64_be, ZigLLVM_ARMSubArch_v8m_baseline},
- {ZigLLVM_aarch64_be, ZigLLVM_ARMSubArch_v8m_mainline},
-
- {ZigLLVM_arc, ZigLLVM_NoSubArch},
- {ZigLLVM_avr, ZigLLVM_NoSubArch},
- {ZigLLVM_bpfel, ZigLLVM_NoSubArch},
- {ZigLLVM_bpfeb, ZigLLVM_NoSubArch},
- {ZigLLVM_hexagon, ZigLLVM_NoSubArch},
-
- {ZigLLVM_mips, ZigLLVM_MipsSubArch_r6},
- {ZigLLVM_mipsel, ZigLLVM_MipsSubArch_r6},
- {ZigLLVM_mips64, ZigLLVM_MipsSubArch_r6},
- {ZigLLVM_mips64el, ZigLLVM_MipsSubArch_r6},
-
- {ZigLLVM_msp430, ZigLLVM_NoSubArch},
- {ZigLLVM_ppc, ZigLLVM_NoSubArch},
- {ZigLLVM_ppc64, ZigLLVM_NoSubArch},
- {ZigLLVM_ppc64le, ZigLLVM_NoSubArch},
- {ZigLLVM_r600, ZigLLVM_NoSubArch},
- {ZigLLVM_amdgcn, ZigLLVM_NoSubArch},
- {ZigLLVM_riscv32, ZigLLVM_NoSubArch},
- {ZigLLVM_riscv64, ZigLLVM_NoSubArch},
- {ZigLLVM_sparc, ZigLLVM_NoSubArch},
- {ZigLLVM_sparcv9, ZigLLVM_NoSubArch},
- {ZigLLVM_sparcel, ZigLLVM_NoSubArch},
- {ZigLLVM_systemz, ZigLLVM_NoSubArch},
- {ZigLLVM_tce, ZigLLVM_NoSubArch},
- {ZigLLVM_tcele, ZigLLVM_NoSubArch},
- {ZigLLVM_thumb, ZigLLVM_NoSubArch},
- {ZigLLVM_thumbeb, ZigLLVM_NoSubArch},
- {ZigLLVM_x86, ZigLLVM_NoSubArch},
- {ZigLLVM_x86_64, ZigLLVM_NoSubArch},
- {ZigLLVM_xcore, ZigLLVM_NoSubArch},
- {ZigLLVM_nvptx, ZigLLVM_NoSubArch},
- {ZigLLVM_nvptx64, ZigLLVM_NoSubArch},
- {ZigLLVM_le32, ZigLLVM_NoSubArch},
- {ZigLLVM_le64, ZigLLVM_NoSubArch},
- {ZigLLVM_amdil, ZigLLVM_NoSubArch},
- {ZigLLVM_amdil64, ZigLLVM_NoSubArch},
- {ZigLLVM_hsail, ZigLLVM_NoSubArch},
- {ZigLLVM_hsail64, ZigLLVM_NoSubArch},
- {ZigLLVM_spir, ZigLLVM_NoSubArch},
- {ZigLLVM_spir64, ZigLLVM_NoSubArch},
-
- {ZigLLVM_kalimba, ZigLLVM_KalimbaSubArch_v3},
- {ZigLLVM_kalimba, ZigLLVM_KalimbaSubArch_v4},
- {ZigLLVM_kalimba, ZigLLVM_KalimbaSubArch_v5},
-
- {ZigLLVM_shave, ZigLLVM_NoSubArch},
- {ZigLLVM_lanai, ZigLLVM_NoSubArch},
- {ZigLLVM_wasm32, ZigLLVM_NoSubArch},
- {ZigLLVM_wasm64, ZigLLVM_NoSubArch},
- {ZigLLVM_renderscript32, ZigLLVM_NoSubArch},
- {ZigLLVM_renderscript64, ZigLLVM_NoSubArch},
+static const SubArchList subarch_list_list[] = {
+ SubArchListNone,
+ SubArchListArm32,
+ SubArchListArm64,
+ SubArchListKalimba,
+ SubArchListMips,
+};
+
+static const ZigLLVM_SubArchType subarch_list_arm32[] = {
+ ZigLLVM_ARMSubArch_v8_5a,
+ ZigLLVM_ARMSubArch_v8_4a,
+ ZigLLVM_ARMSubArch_v8_3a,
+ ZigLLVM_ARMSubArch_v8_2a,
+ ZigLLVM_ARMSubArch_v8_1a,
+ ZigLLVM_ARMSubArch_v8,
+ ZigLLVM_ARMSubArch_v8r,
+ ZigLLVM_ARMSubArch_v8m_baseline,
+ ZigLLVM_ARMSubArch_v8m_mainline,
+ ZigLLVM_ARMSubArch_v7,
+ ZigLLVM_ARMSubArch_v7em,
+ ZigLLVM_ARMSubArch_v7m,
+ ZigLLVM_ARMSubArch_v7s,
+ ZigLLVM_ARMSubArch_v7k,
+ ZigLLVM_ARMSubArch_v7ve,
+ ZigLLVM_ARMSubArch_v6,
+ ZigLLVM_ARMSubArch_v6m,
+ ZigLLVM_ARMSubArch_v6k,
+ ZigLLVM_ARMSubArch_v6t2,
+ ZigLLVM_ARMSubArch_v5,
+ ZigLLVM_ARMSubArch_v5te,
+ ZigLLVM_ARMSubArch_v4t,
+
+};
+
+static const ZigLLVM_SubArchType subarch_list_arm64[] = {
+ ZigLLVM_ARMSubArch_v8_5a,
+ ZigLLVM_ARMSubArch_v8_4a,
+ ZigLLVM_ARMSubArch_v8_3a,
+ ZigLLVM_ARMSubArch_v8_2a,
+ ZigLLVM_ARMSubArch_v8_1a,
+ ZigLLVM_ARMSubArch_v8,
+ ZigLLVM_ARMSubArch_v8r,
+ ZigLLVM_ARMSubArch_v8m_baseline,
+ ZigLLVM_ARMSubArch_v8m_mainline,
+};
+
+static const ZigLLVM_SubArchType subarch_list_kalimba[] = {
+ ZigLLVM_KalimbaSubArch_v5,
+ ZigLLVM_KalimbaSubArch_v4,
+ ZigLLVM_KalimbaSubArch_v3,
+};
+
+static const ZigLLVM_SubArchType subarch_list_mips[] = {
+ ZigLLVM_MipsSubArch_r6,
+};
+
+static const ZigLLVM_ArchType arch_list[] = {
+ ZigLLVM_arm, // ARM (little endian): arm, armv.*, xscale
+ ZigLLVM_armeb, // ARM (big endian): armeb
+ ZigLLVM_aarch64, // AArch64 (little endian): aarch64
+ ZigLLVM_aarch64_be, // AArch64 (big endian): aarch64_be
+ ZigLLVM_arc, // ARC: Synopsys ARC
+ ZigLLVM_avr, // AVR: Atmel AVR microcontroller
+ ZigLLVM_bpfel, // eBPF or extended BPF or 64-bit BPF (little endian)
+ ZigLLVM_bpfeb, // eBPF or extended BPF or 64-bit BPF (big endian)
+ ZigLLVM_hexagon, // Hexagon: hexagon
+ ZigLLVM_mips, // MIPS: mips, mipsallegrex, mipsr6
+ ZigLLVM_mipsel, // MIPSEL: mipsel, mipsallegrexe, mipsr6el
+ ZigLLVM_mips64, // MIPS64: mips64, mips64r6, mipsn32, mipsn32r6
+ ZigLLVM_mips64el, // MIPS64EL: mips64el, mips64r6el, mipsn32el, mipsn32r6el
+ ZigLLVM_msp430, // MSP430: msp430
+ ZigLLVM_ppc, // PPC: powerpc
+ ZigLLVM_ppc64, // PPC64: powerpc64, ppu
+ ZigLLVM_ppc64le, // PPC64LE: powerpc64le
+ ZigLLVM_r600, // R600: AMD GPUs HD2XXX - HD6XXX
+ ZigLLVM_amdgcn, // AMDGCN: AMD GCN GPUs
+ ZigLLVM_riscv32, // RISC-V (32-bit): riscv32
+ ZigLLVM_riscv64, // RISC-V (64-bit): riscv64
+ ZigLLVM_sparc, // Sparc: sparc
+ ZigLLVM_sparcv9, // Sparcv9: Sparcv9
+ ZigLLVM_sparcel, // Sparc: (endianness = little). NB: 'Sparcle' is a CPU variant
+ ZigLLVM_systemz, // SystemZ: s390x
+ ZigLLVM_tce, // TCE (http://tce.cs.tut.fi/): tce
+ ZigLLVM_tcele, // TCE little endian (http://tce.cs.tut.fi/): tcele
+ ZigLLVM_thumb, // Thumb (little endian): thumb, thumbv.*
+ ZigLLVM_thumbeb, // Thumb (big endian): thumbeb
+ ZigLLVM_x86, // X86: i[3-9]86
+ ZigLLVM_x86_64, // X86-64: amd64, x86_64
+ ZigLLVM_xcore, // XCore: xcore
+ ZigLLVM_nvptx, // NVPTX: 32-bit
+ ZigLLVM_nvptx64, // NVPTX: 64-bit
+ ZigLLVM_le32, // le32: generic little-endian 32-bit CPU (PNaCl)
+ ZigLLVM_le64, // le64: generic little-endian 64-bit CPU (PNaCl)
+ ZigLLVM_amdil, // AMDIL
+ ZigLLVM_amdil64, // AMDIL with 64-bit pointers
+ ZigLLVM_hsail, // AMD HSAIL
+ ZigLLVM_hsail64, // AMD HSAIL with 64-bit pointers
+ ZigLLVM_spir, // SPIR: standard portable IR for OpenCL 32-bit version
+ ZigLLVM_spir64, // SPIR: standard portable IR for OpenCL 64-bit version
+ ZigLLVM_kalimba, // Kalimba: generic kalimba
+ ZigLLVM_shave, // SHAVE: Movidius vector VLIW processors
+ ZigLLVM_lanai, // Lanai: Lanai 32-bit
+ ZigLLVM_wasm32, // WebAssembly with 32-bit pointers
+ ZigLLVM_wasm64, // WebAssembly with 64-bit pointers
+ ZigLLVM_renderscript32, // 32-bit RenderScript
+ ZigLLVM_renderscript64, // 64-bit RenderScript
};
static const ZigLLVM_VendorType vendor_list[] = {
@@ -190,7 +179,7 @@ static const Os os_list[] = {
};
// Coordinate with zig_llvm.h
-static const ZigLLVM_EnvironmentType environ_list[] = {
+static const ZigLLVM_EnvironmentType abi_list[] = {
ZigLLVM_UnknownEnvironment,
ZigLLVM_GNU,
@@ -225,11 +214,12 @@ size_t target_oformat_count(void) {
return array_length(oformat_list);
}
-const ZigLLVM_ObjectFormatType get_target_oformat(size_t index) {
+ZigLLVM_ObjectFormatType target_oformat_enum(size_t index) {
+ assert(index < array_length(oformat_list));
return oformat_list[index];
}
-const char *get_target_oformat_name(ZigLLVM_ObjectFormatType oformat) {
+const char *target_oformat_name(ZigLLVM_ObjectFormatType oformat) {
switch (oformat) {
case ZigLLVM_UnknownObjectFormat: return "unknown";
case ZigLLVM_COFF: return "coff";
@@ -244,22 +234,25 @@ size_t target_arch_count(void) {
return array_length(arch_list);
}
-const ArchType *get_target_arch(size_t index) {
- return &arch_list[index];
+ZigLLVM_ArchType target_arch_enum(size_t index) {
+ assert(index < array_length(arch_list));
+ return arch_list[index];
}
size_t target_vendor_count(void) {
return array_length(vendor_list);
}
-ZigLLVM_VendorType get_target_vendor(size_t index) {
+ZigLLVM_VendorType target_vendor_enum(size_t index) {
+ assert(index < array_length(vendor_list));
return vendor_list[index];
}
size_t target_os_count(void) {
return array_length(os_list);
}
-Os get_target_os(size_t index) {
+Os target_os_enum(size_t index) {
+ assert(index < array_length(os_list));
return os_list[index];
}
@@ -414,7 +407,7 @@ static Os get_zig_os_type(ZigLLVM_OSType os_type) {
zig_unreachable();
}
-const char *get_target_os_name(Os os_type) {
+const char *target_os_name(Os os_type) {
switch (os_type) {
case OsFreestanding:
return "freestanding";
@@ -460,78 +453,257 @@ const char *get_target_os_name(Os os_type) {
zig_unreachable();
}
-size_t target_environ_count(void) {
- return array_length(environ_list);
+size_t target_abi_count(void) {
+ return array_length(abi_list);
+}
+ZigLLVM_EnvironmentType target_abi_enum(size_t index) {
+ assert(index < array_length(abi_list));
+ return abi_list[index];
}
-ZigLLVM_EnvironmentType get_target_environ(size_t index) {
- return environ_list[index];
+const char *target_abi_name(ZigLLVM_EnvironmentType abi) {
+ if (abi == ZigLLVM_UnknownEnvironment)
+ return "none";
+ return ZigLLVMGetEnvironmentTypeName(abi);
}
void get_native_target(ZigTarget *target) {
ZigLLVM_OSType os_type;
+ ZigLLVM_ObjectFormatType oformat; // ignored; based on arch/os
ZigLLVMGetNativeTarget(
- &target->arch.arch,
- &target->arch.sub_arch,
+ &target->arch,
+ &target->sub_arch,
&target->vendor,
&os_type,
- &target->env_type,
- &target->oformat);
+ &target->abi,
+ &oformat);
target->os = get_zig_os_type(os_type);
+ target->is_native = true;
+ if (target->abi == ZigLLVM_UnknownEnvironment) {
+ target->abi = target_default_abi(target->arch, target->os);
+ }
}
-void get_unknown_target(ZigTarget *target) {
- target->arch.arch = ZigLLVM_UnknownArch;
- target->arch.sub_arch = ZigLLVM_NoSubArch;
- target->vendor = ZigLLVM_UnknownVendor;
- target->os = OsFreestanding;
- target->env_type = ZigLLVM_UnknownEnvironment;
- target->oformat = ZigLLVM_UnknownObjectFormat;
+Error target_parse_archsub(ZigLLVM_ArchType *out_arch, ZigLLVM_SubArchType *out_sub,
+ const char *archsub_ptr, size_t archsub_len)
+{
+ for (size_t arch_i = 0; arch_i < array_length(arch_list); arch_i += 1) {
+ ZigLLVM_ArchType arch = arch_list[arch_i];
+ SubArchList sub_arch_list = target_subarch_list(arch);
+ size_t subarch_count = target_subarch_count(sub_arch_list);
+ if (subarch_count == 0) {
+ if (mem_eql_str(archsub_ptr, archsub_len, target_arch_name(arch))) {
+ *out_arch = arch;
+ *out_sub = ZigLLVM_NoSubArch;
+ return ErrorNone;
+ }
+ continue;
+ }
+ for (size_t sub_i = 0; sub_i < subarch_count; sub_i += 1) {
+ ZigLLVM_SubArchType sub = target_subarch_enum(sub_arch_list, sub_i);
+ char arch_name[64];
+ int n = sprintf(arch_name, "%s%s", target_arch_name(arch), target_subarch_name(sub));
+ if (mem_eql_mem(arch_name, n, archsub_ptr, archsub_len)) {
+ *out_arch = arch;
+ *out_sub = sub;
+ return ErrorNone;
+ }
+ }
+ }
+ return ErrorUnknownArchitecture;
}
-static void get_arch_name_raw(char *out_str, ZigLLVM_ArchType arch, ZigLLVM_SubArchType sub_arch) {
- const char *sub_str = (sub_arch == ZigLLVM_NoSubArch) ? "" : ZigLLVMGetSubArchTypeName(sub_arch);
- sprintf(out_str, "%s%s", ZigLLVMGetArchTypeName(arch), sub_str);
-}
+SubArchList target_subarch_list(ZigLLVM_ArchType arch) {
+ switch (arch) {
+ case ZigLLVM_UnknownArch:
+ zig_unreachable();
+ case ZigLLVM_arm:
+ case ZigLLVM_armeb:
+ case ZigLLVM_thumb:
+ case ZigLLVM_thumbeb:
+ return SubArchListArm32;
+
+ case ZigLLVM_aarch64:
+ case ZigLLVM_aarch64_be:
+ return SubArchListArm64;
-void get_arch_name(char *out_str, const ArchType *arch) {
- return get_arch_name_raw(out_str, arch->arch, arch->sub_arch);
+ case ZigLLVM_kalimba:
+ return SubArchListKalimba;
+
+ case ZigLLVM_arc:
+ case ZigLLVM_avr:
+ case ZigLLVM_bpfel:
+ case ZigLLVM_bpfeb:
+ case ZigLLVM_hexagon:
+ case ZigLLVM_mips:
+ case ZigLLVM_mipsel:
+ case ZigLLVM_mips64:
+ case ZigLLVM_mips64el:
+ case ZigLLVM_msp430:
+ case ZigLLVM_ppc:
+ case ZigLLVM_ppc64:
+ case ZigLLVM_ppc64le:
+ case ZigLLVM_r600:
+ case ZigLLVM_amdgcn:
+ case ZigLLVM_riscv32:
+ case ZigLLVM_riscv64:
+ case ZigLLVM_sparc:
+ case ZigLLVM_sparcv9:
+ case ZigLLVM_sparcel:
+ case ZigLLVM_systemz:
+ case ZigLLVM_tce:
+ case ZigLLVM_tcele:
+ case ZigLLVM_x86:
+ case ZigLLVM_x86_64:
+ case ZigLLVM_xcore:
+ case ZigLLVM_nvptx:
+ case ZigLLVM_nvptx64:
+ case ZigLLVM_le32:
+ case ZigLLVM_le64:
+ case ZigLLVM_amdil:
+ case ZigLLVM_amdil64:
+ case ZigLLVM_hsail:
+ case ZigLLVM_hsail64:
+ case ZigLLVM_spir:
+ case ZigLLVM_spir64:
+ case ZigLLVM_shave:
+ case ZigLLVM_lanai:
+ case ZigLLVM_wasm32:
+ case ZigLLVM_wasm64:
+ case ZigLLVM_renderscript32:
+ case ZigLLVM_renderscript64:
+ return SubArchListNone;
+ }
+ zig_unreachable();
}
-int parse_target_arch(const char *str, ArchType *out_arch) {
- for (size_t i = 0; i < array_length(arch_list); i += 1) {
- const ArchType *arch = &arch_list[i];
- char arch_name[50];
- get_arch_name_raw(arch_name, arch->arch, arch->sub_arch);
- if (strcmp(arch_name, str) == 0) {
- *out_arch = *arch;
+size_t target_subarch_count(SubArchList sub_arch_list) {
+ switch (sub_arch_list) {
+ case SubArchListNone:
return 0;
- }
+ case SubArchListArm32:
+ return array_length(subarch_list_arm32);
+ case SubArchListArm64:
+ return array_length(subarch_list_arm64);
+ case SubArchListKalimba:
+ return array_length(subarch_list_kalimba);
+ case SubArchListMips:
+ return array_length(subarch_list_mips);
+ }
+ zig_unreachable();
+}
+
+ZigLLVM_SubArchType target_subarch_enum(SubArchList sub_arch_list, size_t i) {
+ switch (sub_arch_list) {
+ case SubArchListNone:
+ zig_unreachable();
+ case SubArchListArm32:
+ assert(i < array_length(subarch_list_arm32));
+ return subarch_list_arm32[i];
+ case SubArchListArm64:
+ assert(i < array_length(subarch_list_arm64));
+ return subarch_list_arm64[i];
+ case SubArchListKalimba:
+ assert(i < array_length(subarch_list_kalimba));
+ return subarch_list_kalimba[i];
+ case SubArchListMips:
+ assert(i < array_length(subarch_list_mips));
+ return subarch_list_mips[i];
}
- return ErrorFileNotFound;
+ zig_unreachable();
+}
+
+const char *target_subarch_name(ZigLLVM_SubArchType subarch) {
+ return ZigLLVMGetSubArchTypeName(subarch);
+}
+
+size_t target_subarch_list_count(void) {
+ return array_length(subarch_list_list);
+}
+
+SubArchList target_subarch_list_enum(size_t index) {
+ assert(index < array_length(subarch_list_list));
+ return subarch_list_list[index];
+}
+
+const char *target_subarch_list_name(SubArchList sub_arch_list) {
+ switch (sub_arch_list) {
+ case SubArchListNone:
+ return "None";
+ case SubArchListArm32:
+ return "Arm32";
+ case SubArchListArm64:
+ return "Arm64";
+ case SubArchListKalimba:
+ return "Kalimba";
+ case SubArchListMips:
+ return "Mips";
+ }
+ zig_unreachable();
}
-int parse_target_os(const char *str, Os *out_os) {
+Error target_parse_os(Os *out_os, const char *os_ptr, size_t os_len) {
for (size_t i = 0; i < array_length(os_list); i += 1) {
Os os = os_list[i];
- const char *os_name = get_target_os_name(os);
- if (strcmp(os_name, str) == 0) {
+ const char *os_name = target_os_name(os);
+ if (mem_eql_str(os_ptr, os_len, os_name)) {
*out_os = os;
- return 0;
+ return ErrorNone;
}
}
- return ErrorFileNotFound;
+ return ErrorUnknownOperatingSystem;
}
-int parse_target_environ(const char *str, ZigLLVM_EnvironmentType *out_environ) {
- for (size_t i = 0; i < array_length(environ_list); i += 1) {
- ZigLLVM_EnvironmentType env_type = environ_list[i];
- const char *environ_name = ZigLLVMGetEnvironmentTypeName(env_type);
- if (strcmp(environ_name, str) == 0) {
- *out_environ = env_type;
- return 0;
+Error target_parse_abi(ZigLLVM_EnvironmentType *out_abi, const char *abi_ptr, size_t abi_len) {
+ for (size_t i = 0; i < array_length(abi_list); i += 1) {
+ ZigLLVM_EnvironmentType abi = abi_list[i];
+ const char *abi_name = target_abi_name(abi);
+ if (mem_eql_str(abi_ptr, abi_len, abi_name)) {
+ *out_abi = abi;
+ return ErrorNone;
+ }
+ }
+ return ErrorUnknownABI;
+}
+
+Error target_parse_triple(ZigTarget *target, const char *triple) {
+ Error err;
+ SplitIterator it = memSplit(str(triple), str("-"));
+
+ Optional<Slice<uint8_t>> opt_archsub = SplitIterator_next(&it);
+ Optional<Slice<uint8_t>> opt_os = SplitIterator_next(&it);
+ Optional<Slice<uint8_t>> opt_abi = SplitIterator_next(&it);
+
+ if (!opt_archsub.is_some)
+ return ErrorMissingArchitecture;
+
+ if (!opt_os.is_some)
+ return ErrorMissingOperatingSystem;
+
+ if ((err = target_parse_archsub(&target->arch, &target->sub_arch,
+ (char*)opt_archsub.value.ptr, opt_archsub.value.len)))
+ {
+ return err;
+ }
+
+ if ((err = target_parse_os(&target->os, (char*)opt_os.value.ptr, opt_os.value.len))) {
+ return err;
+ }
+
+ if (opt_abi.is_some) {
+ if ((err = target_parse_abi(&target->abi, (char*)opt_abi.value.ptr, opt_abi.value.len))) {
+ return err;
}
+ } else {
+ target->abi = target_default_abi(target->arch, target->os);
}
- return ErrorFileNotFound;
+
+ target->vendor = ZigLLVM_UnknownVendor;
+ target->is_native = false;
+ return ErrorNone;
+}
+
+const char *target_arch_name(ZigLLVM_ArchType arch) {
+ return ZigLLVMGetArchTypeName(arch);
}
void init_all_targets(void) {
@@ -543,121 +715,39 @@ void init_all_targets(void) {
}
void get_target_triple(Buf *triple, const ZigTarget *target) {
- char arch_name[50];
- get_arch_name(arch_name, &target->arch);
-
buf_resize(triple, 0);
-
- // LLVM WebAssembly output support requires the target to be activated at
- // build type with -DCMAKE_LLVM_EXPIERMENTAL_TARGETS_TO_BUILD=WebAssembly.
- //
- // LLVM determines the output format based on the environment suffix,
- // 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
- // 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
- // using the target triple `wasm32-unknown-unknown-unknown`.
- if (!strncmp(arch_name, "wasm", 4)) {
- buf_appendf(triple, "%s-%s-%s-wasm", arch_name,
- ZigLLVMGetVendorTypeName(target->vendor),
- ZigLLVMGetOSTypeName(get_llvm_os_type(target->os)));
- } else {
- buf_appendf(triple, "%s-%s-%s-%s", arch_name,
- ZigLLVMGetVendorTypeName(target->vendor),
- ZigLLVMGetOSTypeName(get_llvm_os_type(target->os)),
- ZigLLVMGetEnvironmentTypeName(target->env_type));
- }
+ buf_appendf(triple, "%s%s-%s-%s-%s",
+ ZigLLVMGetArchTypeName(target->arch),
+ ZigLLVMGetSubArchTypeName(target->sub_arch),
+ ZigLLVMGetVendorTypeName(target->vendor),
+ ZigLLVMGetOSTypeName(get_llvm_os_type(target->os)),
+ ZigLLVMGetEnvironmentTypeName(target->abi));
}
-static bool is_os_darwin(ZigTarget *target) {
+bool target_is_darwin(const ZigTarget *target) {
switch (target->os) {
case OsMacOSX:
case OsIOS:
+ case OsWatchOS:
+ case OsTvOS:
return true;
default:
return false;
}
}
-void resolve_target_object_format(ZigTarget *target) {
- if (target->oformat != ZigLLVM_UnknownObjectFormat) {
- return;
+ZigLLVM_ObjectFormatType target_object_format(const ZigTarget *target) {
+ if (target->os == OsUefi || target->os == OsWindows) {
+ return ZigLLVM_COFF;
+ } else if (target_is_darwin(target)) {
+ return ZigLLVM_MachO;
}
-
- switch (target->arch.arch) {
- case ZigLLVM_UnknownArch:
- case ZigLLVM_aarch64:
- case ZigLLVM_arm:
- case ZigLLVM_thumb:
- case ZigLLVM_x86:
- case ZigLLVM_x86_64:
- if (is_os_darwin(target)) {
- target->oformat = ZigLLVM_MachO;
- } else if (target->os == OsWindows) {
- target->oformat = ZigLLVM_COFF;
- } else {
- target->oformat = ZigLLVM_ELF;
- }
- return;
-
- case ZigLLVM_aarch64_be:
- case ZigLLVM_amdgcn:
- case ZigLLVM_amdil:
- case ZigLLVM_amdil64:
- case ZigLLVM_armeb:
- case ZigLLVM_arc:
- case ZigLLVM_avr:
- case ZigLLVM_bpfeb:
- case ZigLLVM_bpfel:
- case ZigLLVM_hexagon:
- case ZigLLVM_lanai:
- case ZigLLVM_hsail:
- case ZigLLVM_hsail64:
- case ZigLLVM_kalimba:
- case ZigLLVM_le32:
- case ZigLLVM_le64:
- case ZigLLVM_mips:
- case ZigLLVM_mips64:
- case ZigLLVM_mips64el:
- case ZigLLVM_mipsel:
- case ZigLLVM_msp430:
- case ZigLLVM_nvptx:
- case ZigLLVM_nvptx64:
- case ZigLLVM_ppc64le:
- case ZigLLVM_r600:
- case ZigLLVM_renderscript32:
- case ZigLLVM_renderscript64:
- case ZigLLVM_riscv32:
- case ZigLLVM_riscv64:
- case ZigLLVM_shave:
- case ZigLLVM_sparc:
- case ZigLLVM_sparcel:
- case ZigLLVM_sparcv9:
- case ZigLLVM_spir:
- case ZigLLVM_spir64:
- case ZigLLVM_systemz:
- case ZigLLVM_tce:
- case ZigLLVM_tcele:
- case ZigLLVM_thumbeb:
- case ZigLLVM_xcore:
- target->oformat= ZigLLVM_ELF;
- return;
-
- case ZigLLVM_wasm32:
- case ZigLLVM_wasm64:
- target->oformat = ZigLLVM_Wasm;
- return;
-
- case ZigLLVM_ppc:
- case ZigLLVM_ppc64:
- if (is_os_darwin(target)) {
- target->oformat = ZigLLVM_MachO;
- } else {
- target->oformat= ZigLLVM_ELF;
- }
- return;
+ if (target->arch == ZigLLVM_wasm32 ||
+ target->arch == ZigLLVM_wasm64)
+ {
+ return ZigLLVM_Wasm;
}
+ return ZigLLVM_ELF;
}
// See lib/Support/Triple.cpp in LLVM for the source of this data.
@@ -728,7 +818,7 @@ static int get_arch_pointer_bit_width(ZigLLVM_ArchType arch) {
uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) {
switch (target->os) {
case OsFreestanding:
- switch (target->arch.arch) {
+ switch (target->arch) {
case ZigLLVM_msp430:
switch (id) {
case CIntTypeShort:
@@ -756,7 +846,7 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) {
return 32;
case CIntTypeLong:
case CIntTypeULong:
- return get_arch_pointer_bit_width(target->arch.arch);
+ return get_arch_pointer_bit_width(target->arch);
case CIntTypeLongLong:
case CIntTypeULongLong:
return 64;
@@ -768,6 +858,7 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) {
case OsMacOSX:
case OsZen:
case OsFreeBSD:
+ case OsNetBSD:
case OsOpenBSD:
switch (id) {
case CIntTypeShort:
@@ -778,7 +869,7 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) {
return 32;
case CIntTypeLong:
case CIntTypeULong:
- return get_arch_pointer_bit_width(target->arch.arch);
+ return get_arch_pointer_bit_width(target->arch);
case CIntTypeLongLong:
case CIntTypeULongLong:
return 64;
@@ -808,7 +899,6 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) {
case OsIOS:
case OsKFreeBSD:
case OsLv2:
- case OsNetBSD:
case OsSolaris:
case OsHaiku:
case OsMinix:
@@ -835,23 +925,27 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) {
zig_unreachable();
}
-const char *target_o_file_ext(ZigTarget *target) {
- if (target->env_type == ZigLLVM_MSVC || target->os == OsWindows || target->os == OsUefi) {
+bool target_allows_addr_zero(const ZigTarget *target) {
+ return target->os == OsFreestanding;
+}
+
+const char *target_o_file_ext(const ZigTarget *target) {
+ if (target->abi == ZigLLVM_MSVC || target->os == OsWindows || target->os == OsUefi) {
return ".obj";
} else {
return ".o";
}
}
-const char *target_asm_file_ext(ZigTarget *target) {
+const char *target_asm_file_ext(const ZigTarget *target) {
return ".s";
}
-const char *target_llvm_ir_file_ext(ZigTarget *target) {
+const char *target_llvm_ir_file_ext(const ZigTarget *target) {
return ".ll";
}
-const char *target_exe_file_ext(ZigTarget *target) {
+const char *target_exe_file_ext(const ZigTarget *target) {
if (target->os == OsWindows) {
return ".exe";
} else if (target->os == OsUefi) {
@@ -861,7 +955,9 @@ const char *target_exe_file_ext(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)
+{
if (target->os == OsWindows || target->os == OsUefi) {
if (is_static) {
return ".lib";
@@ -872,7 +968,7 @@ const char *target_lib_file_ext(ZigTarget *target, bool is_static, size_t versio
if (is_static) {
return ".a";
} else {
- return buf_ptr(buf_sprintf(".so.%zu", version_major));
+ return buf_ptr(buf_sprintf(".so.%" ZIG_PRI_usize, version_major));
}
}
}
@@ -883,8 +979,8 @@ enum FloatAbi {
FloatAbiSoftFp,
};
-static FloatAbi get_float_abi(ZigTarget *target) {
- const ZigLLVM_EnvironmentType env = target->env_type;
+static FloatAbi get_float_abi(const ZigTarget *target) {
+ const ZigLLVM_EnvironmentType env = target->abi;
if (env == ZigLLVM_GNUEABIHF ||
env == ZigLLVM_EABIHF ||
env == ZigLLVM_MuslEABIHF)
@@ -899,64 +995,153 @@ static bool is_64_bit(ZigLLVM_ArchType arch) {
return get_arch_pointer_bit_width(arch) == 64;
}
-Buf *target_dynamic_linker(ZigTarget *target) {
- const ZigLLVM_ArchType arch = target->arch.arch;
- const ZigLLVM_EnvironmentType env = target->env_type;
+const char *target_dynamic_linker(const ZigTarget *target) {
+ switch (target->os) {
+ case OsFreeBSD:
+ return "/libexec/ld-elf.so.1";
+ case OsNetBSD:
+ return "/libexec/ld.elf_so";
+ case OsLinux: {
+ const ZigLLVM_EnvironmentType abi = target->abi;
+ if (abi == ZigLLVM_Android) {
+ if (is_64_bit(target->arch)) {
+ return "/system/bin/linker64";
+ } else {
+ return "/system/bin/linker";
+ }
+ }
- if (env == ZigLLVM_Android) {
- if (is_64_bit(arch)) {
- return buf_create_from_str("/system/bin/linker64");
- } else {
- return buf_create_from_str("/system/bin/linker");
- }
- } else if (arch == ZigLLVM_x86 ||
- arch == ZigLLVM_sparc ||
- arch == ZigLLVM_sparcel)
- {
- return buf_create_from_str("/lib/ld-linux.so.2");
- } else if (arch == ZigLLVM_aarch64) {
- return buf_create_from_str("/lib/ld-linux-aarch64.so.1");
- } else if (arch == ZigLLVM_aarch64_be) {
- return buf_create_from_str("/lib/ld-linux-aarch64_be.so.1");
- } else if (arch == ZigLLVM_arm || arch == ZigLLVM_thumb) {
- if (get_float_abi(target) == FloatAbiHard) {
- return buf_create_from_str("/lib/ld-linux-armhf.so.3");
- } else {
- return buf_create_from_str("/lib/ld-linux.so.3");
- }
- } else if (arch == ZigLLVM_armeb || arch == ZigLLVM_thumbeb) {
- if (get_float_abi(target) == FloatAbiHard) {
- return buf_create_from_str("/lib/ld-linux-armhf.so.3");
- } else {
- return buf_create_from_str("/lib/ld-linux.so.3");
+ switch (target->arch) {
+ case ZigLLVM_UnknownArch:
+ zig_unreachable();
+ case ZigLLVM_x86:
+ case ZigLLVM_sparc:
+ case ZigLLVM_sparcel:
+ return "/lib/ld-linux.so.2";
+
+ case ZigLLVM_aarch64:
+ return "/lib/ld-linux-aarch64.so.1";
+
+ case ZigLLVM_aarch64_be:
+ return "/lib/ld-linux-aarch64_be.so.1";
+
+ case ZigLLVM_arm:
+ case ZigLLVM_thumb:
+ if (get_float_abi(target) == FloatAbiHard) {
+ return "/lib/ld-linux-armhf.so.3";
+ } else {
+ return "/lib/ld-linux.so.3";
+ }
+
+ case ZigLLVM_armeb:
+ case ZigLLVM_thumbeb:
+ if (get_float_abi(target) == FloatAbiHard) {
+ return "/lib/ld-linux-armhf.so.3";
+ } else {
+ return "/lib/ld-linux.so.3";
+ }
+
+ case ZigLLVM_mips:
+ case ZigLLVM_mipsel:
+ case ZigLLVM_mips64:
+ case ZigLLVM_mips64el:
+ zig_panic("TODO implement target_dynamic_linker for mips");
+
+ case ZigLLVM_ppc:
+ return "/lib/ld.so.1";
+
+ case ZigLLVM_ppc64:
+ return "/lib64/ld64.so.2";
+
+ case ZigLLVM_ppc64le:
+ return "/lib64/ld64.so.2";
+
+ case ZigLLVM_systemz:
+ return "/lib64/ld64.so.1";
+
+ case ZigLLVM_sparcv9:
+ return "/lib64/ld-linux.so.2";
+
+ case ZigLLVM_x86_64:
+ if (abi == ZigLLVM_GNUX32) {
+ return "/libx32/ld-linux-x32.so.2";
+ }
+ if (abi == ZigLLVM_Musl || abi == ZigLLVM_MuslEABI || abi == ZigLLVM_MuslEABIHF) {
+ return "/lib/ld-musl-x86_64.so.1";
+ }
+ return "/lib64/ld-linux-x86-64.so.2";
+
+ case ZigLLVM_wasm32:
+ case ZigLLVM_wasm64:
+ return nullptr;
+
+ case ZigLLVM_arc:
+ case ZigLLVM_avr:
+ case ZigLLVM_bpfel:
+ case ZigLLVM_bpfeb:
+ case ZigLLVM_hexagon:
+ case ZigLLVM_msp430:
+ case ZigLLVM_r600:
+ case ZigLLVM_amdgcn:
+ case ZigLLVM_riscv32:
+ case ZigLLVM_riscv64:
+ case ZigLLVM_tce:
+ case ZigLLVM_tcele:
+ case ZigLLVM_xcore:
+ case ZigLLVM_nvptx:
+ case ZigLLVM_nvptx64:
+ case ZigLLVM_le32:
+ case ZigLLVM_le64:
+ case ZigLLVM_amdil:
+ case ZigLLVM_amdil64:
+ case ZigLLVM_hsail:
+ case ZigLLVM_hsail64:
+ case ZigLLVM_spir:
+ case ZigLLVM_spir64:
+ case ZigLLVM_kalimba:
+ case ZigLLVM_shave:
+ case ZigLLVM_lanai:
+ case ZigLLVM_renderscript32:
+ case ZigLLVM_renderscript64:
+ zig_panic("TODO implement target_dynamic_linker for this arch");
+ }
+ zig_unreachable();
}
- } else if (arch == ZigLLVM_mips || arch == ZigLLVM_mipsel ||
- arch == ZigLLVM_mips64 || arch == ZigLLVM_mips64el)
- {
- // when you want to solve this TODO, grep clang codebase for
- // getLinuxDynamicLinker
- zig_panic("TODO figure out MIPS dynamic linker name");
- } else if (arch == ZigLLVM_ppc) {
- return buf_create_from_str("/lib/ld.so.1");
- } else if (arch == ZigLLVM_ppc64) {
- return buf_create_from_str("/lib64/ld64.so.2");
- } else if (arch == ZigLLVM_ppc64le) {
- return buf_create_from_str("/lib64/ld64.so.2");
- } else if (arch == ZigLLVM_systemz) {
- return buf_create_from_str("/lib64/ld64.so.1");
- } else if (arch == ZigLLVM_sparcv9) {
- return buf_create_from_str("/lib64/ld-linux.so.2");
- } else if (arch == ZigLLVM_x86_64 &&
- env == ZigLLVM_GNUX32)
- {
- return buf_create_from_str("/libx32/ld-linux-x32.so.2");
- } else if (arch == ZigLLVM_x86_64 &&
- (env == ZigLLVM_Musl || env == ZigLLVM_MuslEABI || env == ZigLLVM_MuslEABIHF))
- {
- return buf_create_from_str("/lib/ld-musl-x86_64.so.1");
- } else {
- return buf_create_from_str("/lib64/ld-linux-x86-64.so.2");
+ case OsFreestanding:
+ case OsIOS:
+ case OsTvOS:
+ case OsWatchOS:
+ case OsMacOSX:
+ return nullptr;
+
+ case OsAnanas:
+ case OsCloudABI:
+ case OsDragonFly:
+ case OsFuchsia:
+ case OsKFreeBSD:
+ case OsLv2:
+ case OsOpenBSD:
+ case OsSolaris:
+ case OsWindows:
+ case OsHaiku:
+ case OsMinix:
+ case OsRTEMS:
+ case OsNaCl:
+ case OsCNK:
+ case OsAIX:
+ case OsCUDA:
+ case OsNVCL:
+ case OsAMDHSA:
+ case OsPS4:
+ case OsELFIAMCU:
+ case OsMesa3D:
+ case OsContiki:
+ case OsAMDPAL:
+ case OsZen:
+ case OsUefi:
+ zig_panic("TODO implement target_dynamic_linker for this OS");
}
+ zig_unreachable();
}
bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target) {
@@ -967,15 +1152,15 @@ bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target
return true;
}
- if (guest_target->os == host_target->os && guest_target->arch.arch == host_target->arch.arch &&
- guest_target->arch.sub_arch == host_target->arch.sub_arch)
+ if (guest_target->os == host_target->os && guest_target->arch == host_target->arch &&
+ guest_target->sub_arch == host_target->sub_arch)
{
// OS, arch, and sub-arch match
return true;
}
if (guest_target->os == OsWindows && host_target->os == OsWindows &&
- host_target->arch.arch == ZigLLVM_x86_64 && guest_target->arch.arch == ZigLLVM_x86)
+ host_target->arch == ZigLLVM_x86_64 && guest_target->arch == ZigLLVM_x86)
{
// 64-bit windows can run 32-bit programs
return true;
@@ -984,8 +1169,8 @@ bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target
return false;
}
-const char *arch_stack_pointer_register_name(const ArchType *arch) {
- switch (arch->arch) {
+const char *arch_stack_pointer_register_name(ZigLLVM_ArchType arch) {
+ switch (arch) {
case ZigLLVM_UnknownArch:
zig_unreachable();
case ZigLLVM_x86:
@@ -1047,7 +1232,7 @@ const char *arch_stack_pointer_register_name(const ArchType *arch) {
}
bool target_is_arm(const ZigTarget *target) {
- switch (target->arch.arch) {
+ switch (target->arch) {
case ZigLLVM_UnknownArch:
zig_unreachable();
case ZigLLVM_aarch64:
@@ -1105,3 +1290,73 @@ bool target_is_arm(const ZigTarget *target) {
}
zig_unreachable();
}
+
+// Valgrind supports more, but Zig does not support them yet.
+bool target_has_valgrind_support(const ZigTarget *target) {
+ switch (target->arch) {
+ case ZigLLVM_UnknownArch:
+ zig_unreachable();
+ case ZigLLVM_x86_64:
+ return (target->os == OsLinux || target_is_darwin(target) || target->os == OsSolaris ||
+ (target->os == OsWindows && target->abi != ZigLLVM_MSVC));
+ default:
+ return false;
+ }
+ zig_unreachable();
+}
+
+bool target_requires_libc(const ZigTarget *target) {
+ // On Darwin, we always link libSystem which contains libc.
+ // Similarly on FreeBSD and NetBSD we always link system libc
+ // since this is the stable syscall interface.
+ return (target_is_darwin(target) || target->os == OsFreeBSD || target->os == OsNetBSD);
+}
+
+bool target_supports_fpic(const ZigTarget *target) {
+ // This is not whether the target supports Position Independent Code, but whether the -fPIC
+ // C compiler argument is valid.
+ return target->os != OsWindows;
+}
+
+ZigLLVM_EnvironmentType target_default_abi(ZigLLVM_ArchType arch, Os os) {
+ switch (os) {
+ case OsFreestanding:
+ case OsAnanas:
+ case OsCloudABI:
+ case OsDragonFly:
+ case OsLv2:
+ case OsSolaris:
+ case OsHaiku:
+ case OsMinix:
+ case OsRTEMS:
+ case OsNaCl:
+ case OsCNK:
+ case OsAIX:
+ case OsCUDA:
+ case OsNVCL:
+ case OsAMDHSA:
+ case OsPS4:
+ case OsELFIAMCU:
+ case OsMesa3D:
+ case OsContiki:
+ case OsAMDPAL:
+ case OsZen:
+ return ZigLLVM_EABI;
+ case OsOpenBSD:
+ case OsMacOSX:
+ case OsFreeBSD:
+ case OsIOS:
+ case OsTvOS:
+ case OsWatchOS:
+ case OsFuchsia:
+ case OsKFreeBSD:
+ case OsNetBSD:
+ return ZigLLVM_GNU;
+ case OsWindows:
+ case OsUefi:
+ return ZigLLVM_MSVC;
+ case OsLinux:
+ return ZigLLVM_Musl;
+ }
+ zig_unreachable();
+}
diff --git a/src/target.hpp b/src/target.hpp
@@ -12,11 +12,6 @@
struct Buf;
-struct ArchType {
- ZigLLVM_ArchType arch;
- ZigLLVM_SubArchType sub_arch;
-};
-
// Synchronize with target.cpp::os_list
enum Os {
OsFreestanding,
@@ -57,6 +52,15 @@ enum Os {
OsUefi,
};
+// Synchronize with target.cpp::subarch_list_list
+enum SubArchList {
+ SubArchListNone,
+ SubArchListArm32,
+ SubArchListArm64,
+ SubArchListKalimba,
+ SubArchListMips,
+};
+
enum TargetSubsystem {
TargetSubsystemAuto, // Zig should infer the subsystem
TargetSubsystemConsole,
@@ -70,11 +74,12 @@ enum TargetSubsystem {
};
struct ZigTarget {
- ArchType arch;
+ ZigLLVM_ArchType arch;
+ ZigLLVM_SubArchType sub_arch;
ZigLLVM_VendorType vendor;
Os os;
- ZigLLVM_EnvironmentType env_type;
- ZigLLVM_ObjectFormatType oformat;
+ ZigLLVM_EnvironmentType abi;
+ bool is_native;
};
enum CIntType {
@@ -90,53 +95,71 @@ enum CIntType {
CIntTypeCount,
};
+Error target_parse_triple(ZigTarget *target, const char *triple);
+Error target_parse_archsub(ZigLLVM_ArchType *arch, ZigLLVM_SubArchType *sub,
+ 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);
+
size_t target_arch_count(void);
-const ArchType *get_target_arch(size_t index);
-void get_arch_name(char *out_str, const ArchType *arch);
+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);
-const char *arch_stack_pointer_register_name(const ArchType *arch);
+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);
-ZigLLVM_VendorType get_target_vendor(size_t index);
+ZigLLVM_VendorType target_vendor_enum(size_t index);
size_t target_os_count(void);
-Os get_target_os(size_t index);
-const char *get_target_os_name(Os os_type);
+Os target_os_enum(size_t index);
+const char *target_os_name(Os os_type);
-size_t target_environ_count(void);
-ZigLLVM_EnvironmentType get_target_environ(size_t index);
+size_t target_abi_count(void);
+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);
-const ZigLLVM_ObjectFormatType get_target_oformat(size_t index);
-const char *get_target_oformat_name(ZigLLVM_ObjectFormatType oformat);
+ZigLLVM_ObjectFormatType target_oformat_enum(size_t index);
+const char *target_oformat_name(ZigLLVM_ObjectFormatType oformat);
+ZigLLVM_ObjectFormatType target_object_format(const ZigTarget *target);
void get_native_target(ZigTarget *target);
-void get_unknown_target(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 get_target_triple(Buf *triple, const ZigTarget *target);
void init_all_targets(void);
-void get_target_triple(Buf *triple, const ZigTarget *target);
-
void resolve_target_object_format(ZigTarget *target);
uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id);
-const char *target_o_file_ext(ZigTarget *target);
-const char *target_asm_file_ext(ZigTarget *target);
-const char *target_llvm_ir_file_ext(ZigTarget *target);
-const char *target_exe_file_ext(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_o_file_ext(const ZigTarget *target);
+const char *target_asm_file_ext(const ZigTarget *target);
+const char *target_llvm_ir_file_ext(const ZigTarget *target);
+const char *target_exe_file_ext(const ZigTarget *target);
+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);
ZigLLVM_OSType get_llvm_os_type(Os os_type);
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
diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp
@@ -221,6 +221,7 @@ enum TokenizeState {
TokenizeStateError,
TokenizeStateLBracket,
TokenizeStateLBracketStar,
+ TokenizeStateLBracketStarC,
};
@@ -846,7 +847,6 @@ void tokenize(Buf *buf, Tokenization *out) {
switch (c) {
case '*':
t.state = TokenizeStateLBracketStar;
- set_token_id(&t, t.cur_tok, TokenIdBracketStarBracket);
break;
default:
// reinterpret as just an lbracket
@@ -858,6 +858,21 @@ void tokenize(Buf *buf, Tokenization *out) {
break;
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) {
case ']':
end_token(&t);
t.state = TokenizeStateStart;
@@ -1491,6 +1506,7 @@ void tokenize(Buf *buf, Tokenization *out) {
case TokenizeStateLineStringContinue:
case TokenizeStateLineStringContinueC:
case TokenizeStateLBracketStar:
+ case TokenizeStateLBracketStarC:
tokenize_error(&t, "unexpected EOF");
break;
case TokenizeStateLineComment:
@@ -1528,6 +1544,7 @@ const char * token_name(TokenId id) {
case TokenIdBitShiftRightEq: return ">>=";
case TokenIdBitXorEq: return "^=";
case TokenIdBracketStarBracket: return "[*]";
+ case TokenIdBracketStarCBracket: return "[*c]";
case TokenIdCharLiteral: return "CharLiteral";
case TokenIdCmpEq: return "==";
case TokenIdCmpGreaterOrEq: return ">=";
diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp
@@ -29,6 +29,7 @@ enum TokenId {
TokenIdBitShiftRightEq,
TokenIdBitXorEq,
TokenIdBracketStarBracket,
+ TokenIdBracketStarCBracket,
TokenIdCharLiteral,
TokenIdCmpEq,
TokenIdCmpGreaterOrEq,
diff --git a/src/translate_c.cpp b/src/translate_c.cpp
@@ -4,7 +4,6 @@
* This file is part of zig, which is MIT licensed.
* See http://opensource.org/licenses/MIT
*/
-
#include "all_types.hpp"
#include "analyze.hpp"
#include "c_tokenizer.hpp"
@@ -13,7 +12,7 @@
#include "os.hpp"
#include "translate_c.hpp"
#include "parser.hpp"
-
+#include "zig_clang.h"
#if __GNUC__ >= 8
#pragma GCC diagnostic push
@@ -30,8 +29,6 @@
#include <string.h>
-using namespace clang;
-
struct Alias {
Buf *new_name;
Buf *canon_name;
@@ -87,13 +84,13 @@ struct Context {
HashMap<const void *, AstNode *, ptr_hash, ptr_eq> decl_table;
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> macro_table;
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> global_table;
- SourceManager *source_manager;
+ ZigClangSourceManager *source_manager;
ZigList<Alias> aliases;
AstNode *source_node;
bool warnings_on;
CodeGen *codegen;
- ASTContext *ctx;
+ ZigClangASTContext *ctx;
TransScopeRoot *global_scope;
HashMap<Buf *, bool, buf_hash, buf_eql_buf> ptr_params;
@@ -117,22 +114,38 @@ static TransScopeSwitch *trans_scope_switch_create(Context *c, TransScope *paren
static TransScopeBlock *trans_scope_block_find(TransScope *scope);
-static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl);
-static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl);
-static AstNode *resolve_typedef_decl(Context *c, const TypedefNameDecl *typedef_decl);
+static AstNode *resolve_record_decl(Context *c, const clang::RecordDecl *record_decl);
+static AstNode *resolve_enum_decl(Context *c, const clang::EnumDecl *enum_decl);
+static AstNode *resolve_typedef_decl(Context *c, const clang::TypedefNameDecl *typedef_decl);
-static int trans_stmt_extra(Context *c, TransScope *scope, const Stmt *stmt,
+static int trans_stmt_extra(Context *c, TransScope *scope, const clang::Stmt *stmt,
ResultUsed result_used, TransLRValue lrval,
AstNode **out_node, TransScope **out_child_scope,
TransScope **out_node_scope);
-static TransScope *trans_stmt(Context *c, TransScope *scope, const Stmt *stmt, AstNode **out_node);
-static AstNode *trans_expr(Context *c, ResultUsed result_used, TransScope *scope, const Expr *expr, TransLRValue lrval);
-static AstNode *trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc);
-static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *scope, const Expr *expr, TransLRValue lrval);
-static AstNode *trans_ap_value(Context *c, APValue *ap_value, QualType qt, const SourceLocation &source_loc);
+static TransScope *trans_stmt(Context *c, TransScope *scope, const clang::Stmt *stmt, AstNode **out_node);
+static AstNode *trans_expr(Context *c, ResultUsed result_used, TransScope *scope, const clang::Expr *expr, TransLRValue lrval);
+static AstNode *trans_qual_type(Context *c, clang::QualType qt, const clang::SourceLocation &source_loc);
+static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *scope, const clang::Expr *expr, TransLRValue lrval);
+static AstNode *trans_ap_value(Context *c, clang::APValue *ap_value, clang::QualType qt, const clang::SourceLocation &source_loc);
+
+static ZigClangSourceLocation bitcast(clang::SourceLocation src) {
+ ZigClangSourceLocation dest;
+ memcpy(&dest, static_cast<void *>(&src), sizeof(ZigClangSourceLocation));
+ return dest;
+}
+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;
+}
ATTRIBUTE_PRINTF(3, 4)
-static void emit_warning(Context *c, const SourceLocation &sl, const char *format, ...) {
+static void emit_warning(Context *c, const clang::SourceLocation &clang_sl, const char *format, ...) {
if (!c->warnings_on) {
return;
}
@@ -142,16 +155,17 @@ static void emit_warning(Context *c, const SourceLocation &sl, const char *forma
Buf *msg = buf_vprintf(format, ap);
va_end(ap);
- StringRef filename = c->source_manager->getFilename(c->source_manager->getSpellingLoc(sl));
- const char *filename_bytes = (const char *)filename.bytes_begin();
+ ZigClangSourceLocation sl = bitcast(clang_sl);
+ const char *filename_bytes = ZigClangSourceManager_getFilename(c->source_manager,
+ ZigClangSourceManager_getSpellingLoc(c->source_manager, sl));
Buf *path;
if (filename_bytes) {
path = buf_create_from_str(filename_bytes);
} else {
path = buf_sprintf("(no file)");
}
- unsigned line = c->source_manager->getSpellingLineNumber(sl);
- unsigned column = c->source_manager->getSpellingColumnNumber(sl);
+ unsigned line = ZigClangSourceManager_getSpellingLineNumber(c->source_manager, sl);
+ unsigned column = ZigClangSourceManager_getSpellingColumnNumber(c->source_manager, sl);
fprintf(stderr, "%s:%u:%u: warning: %s\n", buf_ptr(path), line, column, buf_ptr(msg));
}
@@ -292,11 +306,22 @@ static AstNode *maybe_suppress_result(Context *c, ResultUsed result_used, AstNod
node);
}
+static TokenId ptr_len_to_token_id(PtrLen ptr_len) {
+ switch (ptr_len) {
+ case PtrLenSingle:
+ return TokenIdStar;
+ case PtrLenUnknown:
+ return TokenIdBracketStarBracket;
+ case PtrLenC:
+ return TokenIdBracketStarCBracket;
+ }
+ zig_unreachable();
+}
+
static AstNode *trans_create_node_ptr_type(Context *c, bool is_const, bool is_volatile, AstNode *child_node, PtrLen ptr_len) {
AstNode *node = trans_create_node(c, NodeTypePointerType);
node->data.pointer_type.star_token = allocate<ZigToken>(1);
- node->data.pointer_type.star_token->id = (ptr_len == PtrLenSingle) ? TokenIdStar: TokenIdBracketStarBracket;
- node->data.pointer_type.is_const = is_const;
+ node->data.pointer_type.star_token->id = ptr_len_to_token_id(ptr_len);
node->data.pointer_type.is_const = is_const;
node->data.pointer_type.is_volatile = is_volatile;
node->data.pointer_type.op_expr = child_node;
@@ -461,15 +486,15 @@ static Buf *string_ref_to_buf(StringRef string_ref) {
return buf_create_from_mem((const char *)string_ref.bytes_begin(), string_ref.size());
}
-static const char *decl_name(const Decl *decl) {
- const NamedDecl *named_decl = static_cast<const NamedDecl *>(decl);
+static const char *decl_name(const clang::Decl *decl) {
+ const clang::NamedDecl *named_decl = static_cast<const clang::NamedDecl *>(decl);
return (const char *)named_decl->getName().bytes_begin();
}
static AstNode *trans_create_node_apint(Context *c, const llvm::APSInt &aps_int) {
AstNode *node = trans_create_node(c, NodeTypeIntLiteral);
node->data.int_literal.bigint = allocate<BigInt>(1);
- bool is_negative = aps_int.isNegative();
+ bool is_negative = aps_int.isSigned() && aps_int.isNegative();
if (!is_negative) {
bigint_init_data(node->data.int_literal.bigint, aps_int.getRawData(), aps_int.getNumWords(), false);
return node;
@@ -480,41 +505,41 @@ static AstNode *trans_create_node_apint(Context *c, const llvm::APSInt &aps_int)
}
-static const Type *qual_type_canon(QualType qt) {
+static const clang::Type *qual_type_canon(clang::QualType qt) {
return qt.getCanonicalType().getTypePtr();
}
-static QualType get_expr_qual_type(Context *c, const Expr *expr) {
+static clang::QualType get_expr_qual_type(Context *c, const clang::Expr *expr) {
// String literals in C are `char *` but they should really be `const char *`.
- if (expr->getStmtClass() == Stmt::ImplicitCastExprClass) {
- const ImplicitCastExpr *cast_expr = static_cast<const ImplicitCastExpr *>(expr);
- if (cast_expr->getCastKind() == CK_ArrayToPointerDecay) {
- const Expr *sub_expr = cast_expr->getSubExpr();
- if (sub_expr->getStmtClass() == Stmt::StringLiteralClass) {
- QualType array_qt = sub_expr->getType();
- const ArrayType *array_type = static_cast<const ArrayType *>(array_qt.getTypePtr());
- QualType pointee_qt = array_type->getElementType();
+ if (expr->getStmtClass() == clang::Stmt::ImplicitCastExprClass) {
+ const clang::ImplicitCastExpr *cast_expr = static_cast<const clang::ImplicitCastExpr *>(expr);
+ if (cast_expr->getCastKind() == clang::CK_ArrayToPointerDecay) {
+ const clang::Expr *sub_expr = cast_expr->getSubExpr();
+ if (sub_expr->getStmtClass() == clang::Stmt::StringLiteralClass) {
+ clang::QualType array_qt = sub_expr->getType();
+ const clang::ArrayType *array_type = static_cast<const clang::ArrayType *>(array_qt.getTypePtr());
+ clang::QualType pointee_qt = array_type->getElementType();
pointee_qt.addConst();
- return c->ctx->getPointerType(pointee_qt);
+ return bitcast(ZigClangASTContext_getPointerType(c->ctx, bitcast(pointee_qt)));
}
}
}
return expr->getType();
}
-static QualType get_expr_qual_type_before_implicit_cast(Context *c, const Expr *expr) {
- if (expr->getStmtClass() == Stmt::ImplicitCastExprClass) {
- const ImplicitCastExpr *cast_expr = static_cast<const ImplicitCastExpr *>(expr);
+static clang::QualType get_expr_qual_type_before_implicit_cast(Context *c, const clang::Expr *expr) {
+ if (expr->getStmtClass() == clang::Stmt::ImplicitCastExprClass) {
+ const clang::ImplicitCastExpr *cast_expr = static_cast<const clang::ImplicitCastExpr *>(expr);
return get_expr_qual_type(c, cast_expr->getSubExpr());
}
return expr->getType();
}
-static AstNode *get_expr_type(Context *c, const Expr *expr) {
+static AstNode *get_expr_type(Context *c, const clang::Expr *expr) {
return trans_qual_type(c, get_expr_qual_type(c, expr), expr->getBeginLoc());
}
-static bool qual_types_equal(QualType t1, QualType t2) {
+static bool qual_types_equal(clang::QualType t1, clang::QualType t2) {
if (t1.isConstQualified() != t2.isConstQualified()) {
return false;
}
@@ -531,37 +556,37 @@ static bool is_c_void_type(AstNode *node) {
return (node->type == NodeTypeSymbol && buf_eql_str(node->data.symbol_expr.symbol, "c_void"));
}
-static bool expr_types_equal(Context *c, const Expr *expr1, const Expr *expr2) {
- QualType t1 = get_expr_qual_type(c, expr1);
- QualType t2 = get_expr_qual_type(c, expr2);
+static bool expr_types_equal(Context *c, const clang::Expr *expr1, const clang::Expr *expr2) {
+ clang::QualType t1 = get_expr_qual_type(c, expr1);
+ clang::QualType t2 = get_expr_qual_type(c, expr2);
return qual_types_equal(t1, t2);
}
-static bool qual_type_is_ptr(QualType qt) {
- const Type *ty = qual_type_canon(qt);
- return ty->getTypeClass() == Type::Pointer;
+static bool qual_type_is_ptr(clang::QualType qt) {
+ const clang::Type *ty = qual_type_canon(qt);
+ return ty->getTypeClass() == clang::Type::Pointer;
}
-static const FunctionProtoType *qual_type_get_fn_proto(QualType qt, bool *is_ptr) {
- const Type *ty = qual_type_canon(qt);
+static const clang::FunctionProtoType *qual_type_get_fn_proto(clang::QualType qt, bool *is_ptr) {
+ const clang::Type *ty = qual_type_canon(qt);
*is_ptr = false;
- if (ty->getTypeClass() == Type::Pointer) {
+ if (ty->getTypeClass() == clang::Type::Pointer) {
*is_ptr = true;
- const PointerType *pointer_ty = static_cast<const PointerType*>(ty);
- QualType child_qt = pointer_ty->getPointeeType();
+ const clang::PointerType *pointer_ty = static_cast<const clang::PointerType*>(ty);
+ clang::QualType child_qt = pointer_ty->getPointeeType();
ty = child_qt.getTypePtr();
}
- if (ty->getTypeClass() == Type::FunctionProto) {
- return static_cast<const FunctionProtoType*>(ty);
+ if (ty->getTypeClass() == clang::Type::FunctionProto) {
+ return static_cast<const clang::FunctionProtoType*>(ty);
}
return nullptr;
}
-static bool qual_type_is_fn_ptr(QualType qt) {
+static bool qual_type_is_fn_ptr(clang::QualType qt) {
bool is_ptr;
if (qual_type_get_fn_proto(qt, &is_ptr)) {
return is_ptr;
@@ -570,30 +595,30 @@ static bool qual_type_is_fn_ptr(QualType qt) {
return false;
}
-static uint32_t qual_type_int_bit_width(Context *c, const QualType &qt, const SourceLocation &source_loc) {
- const Type *ty = qt.getTypePtr();
+static uint32_t qual_type_int_bit_width(Context *c, const clang::QualType &qt, const clang::SourceLocation &source_loc) {
+ const clang::Type *ty = qt.getTypePtr();
switch (ty->getTypeClass()) {
- case Type::Builtin:
+ case clang::Type::Builtin:
{
- const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(ty);
+ const clang::BuiltinType *builtin_ty = static_cast<const clang::BuiltinType*>(ty);
switch (builtin_ty->getKind()) {
- case BuiltinType::Char_U:
- case BuiltinType::UChar:
- case BuiltinType::Char_S:
- case BuiltinType::SChar:
+ case clang::BuiltinType::Char_U:
+ case clang::BuiltinType::UChar:
+ case clang::BuiltinType::Char_S:
+ case clang::BuiltinType::SChar:
return 8;
- case BuiltinType::UInt128:
- case BuiltinType::Int128:
+ case clang::BuiltinType::UInt128:
+ case clang::BuiltinType::Int128:
return 128;
default:
return 0;
}
zig_unreachable();
}
- case Type::Typedef:
+ case clang::Type::Typedef:
{
- const TypedefType *typedef_ty = static_cast<const TypedefType*>(ty);
- const TypedefNameDecl *typedef_decl = typedef_ty->getDecl();
+ const clang::TypedefType *typedef_ty = static_cast<const clang::TypedefType*>(ty);
+ const clang::TypedefNameDecl *typedef_decl = typedef_ty->getDecl();
const char *type_name = decl_name(typedef_decl);
if (strcmp(type_name, "uint8_t") == 0 || strcmp(type_name, "int8_t") == 0) {
return 8;
@@ -614,8 +639,8 @@ static uint32_t qual_type_int_bit_width(Context *c, const QualType &qt, const So
}
-static AstNode *qual_type_to_log2_int_ref(Context *c, const QualType &qt,
- const SourceLocation &source_loc)
+static AstNode *qual_type_to_log2_int_ref(Context *c, const clang::QualType &qt,
+ const clang::SourceLocation &source_loc)
{
uint32_t int_bit_width = qual_type_int_bit_width(c, qt, source_loc);
if (int_bit_width != 0) {
@@ -633,7 +658,7 @@ static AstNode *qual_type_to_log2_int_ref(Context *c, const QualType &qt,
// FieldAccess
// FnCall (.builtin = true)
// Symbol "import"
-// StringLiteral "std"
+// clang::StringLiteral "std"
// Symbol "math"
// Symbol "Log2Int"
// zig_type_node
@@ -647,21 +672,21 @@ static AstNode *qual_type_to_log2_int_ref(Context *c, const QualType &qt,
return log2int_fn_call;
}
-static bool qual_type_child_is_fn_proto(const QualType &qt) {
- if (qt.getTypePtr()->getTypeClass() == Type::Paren) {
- const ParenType *paren_type = static_cast<const ParenType *>(qt.getTypePtr());
- if (paren_type->getInnerType()->getTypeClass() == Type::FunctionProto) {
+static bool qual_type_child_is_fn_proto(const clang::QualType &qt) {
+ if (qt.getTypePtr()->getTypeClass() == clang::Type::Paren) {
+ const clang::ParenType *paren_type = static_cast<const clang::ParenType *>(qt.getTypePtr());
+ if (paren_type->getInnerType()->getTypeClass() == clang::Type::FunctionProto) {
return true;
}
- } else if (qt.getTypePtr()->getTypeClass() == Type::Attributed) {
- const AttributedType *attr_type = static_cast<const AttributedType *>(qt.getTypePtr());
+ } else if (qt.getTypePtr()->getTypeClass() == clang::Type::Attributed) {
+ const clang::AttributedType *attr_type = static_cast<const clang::AttributedType *>(qt.getTypePtr());
return qual_type_child_is_fn_proto(attr_type->getEquivalentType());
}
return false;
}
-static AstNode* trans_c_cast(Context *c, const SourceLocation &source_location, QualType dest_type,
- QualType src_type, AstNode *expr)
+static AstNode* trans_c_cast(Context *c, const clang::SourceLocation &source_location, clang::QualType dest_type,
+ clang::QualType src_type, AstNode *expr)
{
if (qual_types_equal(dest_type, src_type)) {
return expr;
@@ -678,72 +703,72 @@ static AstNode* trans_c_cast(Context *c, const SourceLocation &source_location,
return trans_create_node_fn_call_1(c, trans_qual_type(c, dest_type, source_location), expr);
}
-static bool c_is_signed_integer(Context *c, QualType qt) {
- const Type *c_type = qual_type_canon(qt);
- if (c_type->getTypeClass() != Type::Builtin)
+static bool c_is_signed_integer(Context *c, clang::QualType qt) {
+ const clang::Type *c_type = qual_type_canon(qt);
+ if (c_type->getTypeClass() != clang::Type::Builtin)
return false;
- const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(c_type);
+ const clang::BuiltinType *builtin_ty = static_cast<const clang::BuiltinType*>(c_type);
switch (builtin_ty->getKind()) {
- case BuiltinType::SChar:
- case BuiltinType::Short:
- case BuiltinType::Int:
- case BuiltinType::Long:
- case BuiltinType::LongLong:
- case BuiltinType::Int128:
- case BuiltinType::WChar_S:
+ case clang::BuiltinType::SChar:
+ case clang::BuiltinType::Short:
+ case clang::BuiltinType::Int:
+ case clang::BuiltinType::Long:
+ case clang::BuiltinType::LongLong:
+ case clang::BuiltinType::Int128:
+ case clang::BuiltinType::WChar_S:
return true;
default:
return false;
}
}
-static bool c_is_unsigned_integer(Context *c, QualType qt) {
- const Type *c_type = qual_type_canon(qt);
- if (c_type->getTypeClass() != Type::Builtin)
+static bool c_is_unsigned_integer(Context *c, clang::QualType qt) {
+ const clang::Type *c_type = qual_type_canon(qt);
+ if (c_type->getTypeClass() != clang::Type::Builtin)
return false;
- const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(c_type);
+ const clang::BuiltinType *builtin_ty = static_cast<const clang::BuiltinType*>(c_type);
switch (builtin_ty->getKind()) {
- case BuiltinType::Char_U:
- case BuiltinType::UChar:
- case BuiltinType::Char_S:
- case BuiltinType::UShort:
- case BuiltinType::UInt:
- case BuiltinType::ULong:
- case BuiltinType::ULongLong:
- case BuiltinType::UInt128:
- case BuiltinType::WChar_U:
+ case clang::BuiltinType::Char_U:
+ case clang::BuiltinType::UChar:
+ case clang::BuiltinType::Char_S:
+ case clang::BuiltinType::UShort:
+ case clang::BuiltinType::UInt:
+ case clang::BuiltinType::ULong:
+ case clang::BuiltinType::ULongLong:
+ case clang::BuiltinType::UInt128:
+ case clang::BuiltinType::WChar_U:
return true;
default:
return false;
}
}
-static bool c_is_builtin_type(Context *c, QualType qt, BuiltinType::Kind kind) {
- const Type *c_type = qual_type_canon(qt);
- if (c_type->getTypeClass() != Type::Builtin)
+static bool c_is_builtin_type(Context *c, clang::QualType qt, clang::BuiltinType::Kind kind) {
+ const clang::Type *c_type = qual_type_canon(qt);
+ if (c_type->getTypeClass() != clang::Type::Builtin)
return false;
- const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(c_type);
+ const clang::BuiltinType *builtin_ty = static_cast<const clang::BuiltinType*>(c_type);
return builtin_ty->getKind() == kind;
}
-static bool c_is_float(Context *c, QualType qt) {
- const Type *c_type = qt.getTypePtr();
- if (c_type->getTypeClass() != Type::Builtin)
+static bool c_is_float(Context *c, clang::QualType qt) {
+ const clang::Type *c_type = qt.getTypePtr();
+ if (c_type->getTypeClass() != clang::Type::Builtin)
return false;
- const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(c_type);
+ const clang::BuiltinType *builtin_ty = static_cast<const clang::BuiltinType*>(c_type);
switch (builtin_ty->getKind()) {
- case BuiltinType::Half:
- case BuiltinType::Float:
- case BuiltinType::Double:
- case BuiltinType::Float128:
- case BuiltinType::LongDouble:
+ case clang::BuiltinType::Half:
+ case clang::BuiltinType::Float:
+ case clang::BuiltinType::Double:
+ case clang::BuiltinType::Float128:
+ case clang::BuiltinType::LongDouble:
return true;
default:
return false;
}
}
-static bool qual_type_has_wrapping_overflow(Context *c, QualType qt) {
+static bool qual_type_has_wrapping_overflow(Context *c, clang::QualType qt) {
if (c_is_signed_integer(c, qt) || c_is_float(c, qt)) {
// float and signed integer overflow is undefined behavior.
return false;
@@ -753,23 +778,23 @@ static bool qual_type_has_wrapping_overflow(Context *c, QualType qt) {
}
}
-static bool type_is_opaque(Context *c, const Type *ty, const SourceLocation &source_loc) {
+static bool type_is_opaque(Context *c, const clang::Type *ty, const clang::SourceLocation &source_loc) {
switch (ty->getTypeClass()) {
- case Type::Builtin: {
- const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(ty);
- return builtin_ty->getKind() == BuiltinType::Void;
+ case clang::Type::Builtin: {
+ const clang::BuiltinType *builtin_ty = static_cast<const clang::BuiltinType*>(ty);
+ return builtin_ty->getKind() == clang::BuiltinType::Void;
}
- case Type::Record: {
- const RecordType *record_ty = static_cast<const RecordType*>(ty);
+ case clang::Type::Record: {
+ const clang::RecordType *record_ty = static_cast<const clang::RecordType*>(ty);
return record_ty->getDecl()->getDefinition() == nullptr;
}
- case Type::Elaborated: {
- const ElaboratedType *elaborated_ty = static_cast<const ElaboratedType*>(ty);
+ case clang::Type::Elaborated: {
+ const clang::ElaboratedType *elaborated_ty = static_cast<const clang::ElaboratedType*>(ty);
return type_is_opaque(c, elaborated_ty->getNamedType().getTypePtr(), source_loc);
}
- case Type::Typedef: {
- const TypedefType *typedef_ty = static_cast<const TypedefType*>(ty);
- const TypedefNameDecl *typedef_decl = typedef_ty->getDecl();
+ case clang::Type::Typedef: {
+ const clang::TypedefType *typedef_ty = static_cast<const clang::TypedefType*>(ty);
+ const clang::TypedefNameDecl *typedef_decl = typedef_ty->getDecl();
return type_is_opaque(c, typedef_decl->getUnderlyingType().getTypePtr(), source_loc);
}
default:
@@ -777,136 +802,136 @@ static bool type_is_opaque(Context *c, const Type *ty, const SourceLocation &sou
}
}
-static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &source_loc) {
+static AstNode *trans_type(Context *c, const clang::Type *ty, const clang::SourceLocation &source_loc) {
switch (ty->getTypeClass()) {
- case Type::Builtin:
+ case clang::Type::Builtin:
{
- const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(ty);
+ const clang::BuiltinType *builtin_ty = static_cast<const clang::BuiltinType*>(ty);
switch (builtin_ty->getKind()) {
- case BuiltinType::Void:
+ case clang::BuiltinType::Void:
return trans_create_node_symbol_str(c, "c_void");
- case BuiltinType::Bool:
+ case clang::BuiltinType::Bool:
return trans_create_node_symbol_str(c, "bool");
- case BuiltinType::Char_U:
- case BuiltinType::UChar:
- case BuiltinType::Char_S:
- case BuiltinType::Char8:
+ case clang::BuiltinType::Char_U:
+ case clang::BuiltinType::UChar:
+ case clang::BuiltinType::Char_S:
+ case clang::BuiltinType::Char8:
return trans_create_node_symbol_str(c, "u8");
- case BuiltinType::SChar:
+ case clang::BuiltinType::SChar:
return trans_create_node_symbol_str(c, "i8");
- case BuiltinType::UShort:
+ case clang::BuiltinType::UShort:
return trans_create_node_symbol_str(c, "c_ushort");
- case BuiltinType::UInt:
+ case clang::BuiltinType::UInt:
return trans_create_node_symbol_str(c, "c_uint");
- case BuiltinType::ULong:
+ case clang::BuiltinType::ULong:
return trans_create_node_symbol_str(c, "c_ulong");
- case BuiltinType::ULongLong:
+ case clang::BuiltinType::ULongLong:
return trans_create_node_symbol_str(c, "c_ulonglong");
- case BuiltinType::Short:
+ case clang::BuiltinType::Short:
return trans_create_node_symbol_str(c, "c_short");
- case BuiltinType::Int:
+ case clang::BuiltinType::Int:
return trans_create_node_symbol_str(c, "c_int");
- case BuiltinType::Long:
+ case clang::BuiltinType::Long:
return trans_create_node_symbol_str(c, "c_long");
- case BuiltinType::LongLong:
+ case clang::BuiltinType::LongLong:
return trans_create_node_symbol_str(c, "c_longlong");
- case BuiltinType::UInt128:
+ case clang::BuiltinType::UInt128:
return trans_create_node_symbol_str(c, "u128");
- case BuiltinType::Int128:
+ case clang::BuiltinType::Int128:
return trans_create_node_symbol_str(c, "i128");
- case BuiltinType::Float:
+ case clang::BuiltinType::Float:
return trans_create_node_symbol_str(c, "f32");
- case BuiltinType::Double:
+ case clang::BuiltinType::Double:
return trans_create_node_symbol_str(c, "f64");
- case BuiltinType::Float128:
+ case clang::BuiltinType::Float128:
return trans_create_node_symbol_str(c, "f128");
- case BuiltinType::Float16:
+ case clang::BuiltinType::Float16:
return trans_create_node_symbol_str(c, "f16");
- case BuiltinType::LongDouble:
+ case clang::BuiltinType::LongDouble:
return trans_create_node_symbol_str(c, "c_longdouble");
- case BuiltinType::WChar_U:
- case BuiltinType::Char16:
- case BuiltinType::Char32:
- case BuiltinType::WChar_S:
- case BuiltinType::Half:
- case BuiltinType::NullPtr:
- case BuiltinType::ObjCId:
- case BuiltinType::ObjCClass:
- case BuiltinType::ObjCSel:
- case BuiltinType::OMPArraySection:
- case BuiltinType::Dependent:
- case BuiltinType::Overload:
- case BuiltinType::BoundMember:
- case BuiltinType::PseudoObject:
- case BuiltinType::UnknownAny:
- case BuiltinType::BuiltinFn:
- case BuiltinType::ARCUnbridgedCast:
- case BuiltinType::ShortAccum:
- case BuiltinType::Accum:
- case BuiltinType::LongAccum:
- case BuiltinType::UShortAccum:
- case BuiltinType::UAccum:
- case BuiltinType::ULongAccum:
-
- case BuiltinType::OCLImage1dRO:
- case BuiltinType::OCLImage1dArrayRO:
- case BuiltinType::OCLImage1dBufferRO:
- case BuiltinType::OCLImage2dRO:
- case BuiltinType::OCLImage2dArrayRO:
- case BuiltinType::OCLImage2dDepthRO:
- case BuiltinType::OCLImage2dArrayDepthRO:
- case BuiltinType::OCLImage2dMSAARO:
- case BuiltinType::OCLImage2dArrayMSAARO:
- case BuiltinType::OCLImage2dMSAADepthRO:
- case BuiltinType::OCLImage2dArrayMSAADepthRO:
- case BuiltinType::OCLImage3dRO:
- case BuiltinType::OCLImage1dWO:
- case BuiltinType::OCLImage1dArrayWO:
- case BuiltinType::OCLImage1dBufferWO:
- case BuiltinType::OCLImage2dWO:
- case BuiltinType::OCLImage2dArrayWO:
- case BuiltinType::OCLImage2dDepthWO:
- case BuiltinType::OCLImage2dArrayDepthWO:
- case BuiltinType::OCLImage2dMSAAWO:
- case BuiltinType::OCLImage2dArrayMSAAWO:
- case BuiltinType::OCLImage2dMSAADepthWO:
- case BuiltinType::OCLImage2dArrayMSAADepthWO:
- case BuiltinType::OCLImage3dWO:
- case BuiltinType::OCLImage1dRW:
- case BuiltinType::OCLImage1dArrayRW:
- case BuiltinType::OCLImage1dBufferRW:
- case BuiltinType::OCLImage2dRW:
- case BuiltinType::OCLImage2dArrayRW:
- case BuiltinType::OCLImage2dDepthRW:
- case BuiltinType::OCLImage2dArrayDepthRW:
- case BuiltinType::OCLImage2dMSAARW:
- case BuiltinType::OCLImage2dArrayMSAARW:
- case BuiltinType::OCLImage2dMSAADepthRW:
- case BuiltinType::OCLImage2dArrayMSAADepthRW:
- case BuiltinType::OCLImage3dRW:
- case BuiltinType::OCLSampler:
- case BuiltinType::OCLEvent:
- case BuiltinType::OCLClkEvent:
- case BuiltinType::OCLQueue:
- case BuiltinType::OCLReserveID:
- case BuiltinType::ShortFract:
- case BuiltinType::Fract:
- case BuiltinType::LongFract:
- case BuiltinType::UShortFract:
- case BuiltinType::UFract:
- case BuiltinType::ULongFract:
- case BuiltinType::SatShortAccum:
- case BuiltinType::SatAccum:
- case BuiltinType::SatLongAccum:
- case BuiltinType::SatUShortAccum:
- case BuiltinType::SatUAccum:
- case BuiltinType::SatULongAccum:
- case BuiltinType::SatShortFract:
- case BuiltinType::SatFract:
- case BuiltinType::SatLongFract:
- case BuiltinType::SatUShortFract:
- case BuiltinType::SatUFract:
- case BuiltinType::SatULongFract:
+ case clang::BuiltinType::WChar_U:
+ case clang::BuiltinType::Char16:
+ case clang::BuiltinType::Char32:
+ case clang::BuiltinType::WChar_S:
+ case clang::BuiltinType::Half:
+ case clang::BuiltinType::NullPtr:
+ case clang::BuiltinType::ObjCId:
+ case clang::BuiltinType::ObjCClass:
+ case clang::BuiltinType::ObjCSel:
+ case clang::BuiltinType::OMPArraySection:
+ case clang::BuiltinType::Dependent:
+ case clang::BuiltinType::Overload:
+ case clang::BuiltinType::BoundMember:
+ case clang::BuiltinType::PseudoObject:
+ case clang::BuiltinType::UnknownAny:
+ case clang::BuiltinType::BuiltinFn:
+ case clang::BuiltinType::ARCUnbridgedCast:
+ case clang::BuiltinType::ShortAccum:
+ case clang::BuiltinType::Accum:
+ case clang::BuiltinType::LongAccum:
+ case clang::BuiltinType::UShortAccum:
+ case clang::BuiltinType::UAccum:
+ case clang::BuiltinType::ULongAccum:
+
+ case clang::BuiltinType::OCLImage1dRO:
+ case clang::BuiltinType::OCLImage1dArrayRO:
+ case clang::BuiltinType::OCLImage1dBufferRO:
+ case clang::BuiltinType::OCLImage2dRO:
+ case clang::BuiltinType::OCLImage2dArrayRO:
+ case clang::BuiltinType::OCLImage2dDepthRO:
+ case clang::BuiltinType::OCLImage2dArrayDepthRO:
+ case clang::BuiltinType::OCLImage2dMSAARO:
+ case clang::BuiltinType::OCLImage2dArrayMSAARO:
+ case clang::BuiltinType::OCLImage2dMSAADepthRO:
+ case clang::BuiltinType::OCLImage2dArrayMSAADepthRO:
+ case clang::BuiltinType::OCLImage3dRO:
+ case clang::BuiltinType::OCLImage1dWO:
+ case clang::BuiltinType::OCLImage1dArrayWO:
+ case clang::BuiltinType::OCLImage1dBufferWO:
+ case clang::BuiltinType::OCLImage2dWO:
+ case clang::BuiltinType::OCLImage2dArrayWO:
+ case clang::BuiltinType::OCLImage2dDepthWO:
+ case clang::BuiltinType::OCLImage2dArrayDepthWO:
+ case clang::BuiltinType::OCLImage2dMSAAWO:
+ case clang::BuiltinType::OCLImage2dArrayMSAAWO:
+ case clang::BuiltinType::OCLImage2dMSAADepthWO:
+ case clang::BuiltinType::OCLImage2dArrayMSAADepthWO:
+ case clang::BuiltinType::OCLImage3dWO:
+ case clang::BuiltinType::OCLImage1dRW:
+ case clang::BuiltinType::OCLImage1dArrayRW:
+ case clang::BuiltinType::OCLImage1dBufferRW:
+ case clang::BuiltinType::OCLImage2dRW:
+ case clang::BuiltinType::OCLImage2dArrayRW:
+ case clang::BuiltinType::OCLImage2dDepthRW:
+ case clang::BuiltinType::OCLImage2dArrayDepthRW:
+ case clang::BuiltinType::OCLImage2dMSAARW:
+ case clang::BuiltinType::OCLImage2dArrayMSAARW:
+ case clang::BuiltinType::OCLImage2dMSAADepthRW:
+ case clang::BuiltinType::OCLImage2dArrayMSAADepthRW:
+ case clang::BuiltinType::OCLImage3dRW:
+ case clang::BuiltinType::OCLSampler:
+ case clang::BuiltinType::OCLEvent:
+ case clang::BuiltinType::OCLClkEvent:
+ case clang::BuiltinType::OCLQueue:
+ case clang::BuiltinType::OCLReserveID:
+ case clang::BuiltinType::ShortFract:
+ case clang::BuiltinType::Fract:
+ case clang::BuiltinType::LongFract:
+ case clang::BuiltinType::UShortFract:
+ case clang::BuiltinType::UFract:
+ case clang::BuiltinType::ULongFract:
+ case clang::BuiltinType::SatShortAccum:
+ case clang::BuiltinType::SatAccum:
+ case clang::BuiltinType::SatLongAccum:
+ case clang::BuiltinType::SatUShortAccum:
+ case clang::BuiltinType::SatUAccum:
+ case clang::BuiltinType::SatULongAccum:
+ case clang::BuiltinType::SatShortFract:
+ case clang::BuiltinType::SatFract:
+ case clang::BuiltinType::SatLongFract:
+ case clang::BuiltinType::SatUShortFract:
+ case clang::BuiltinType::SatUFract:
+ case clang::BuiltinType::SatULongFract:
case BuiltinType::OCLIntelSubgroupAVCMcePayload:
case BuiltinType::OCLIntelSubgroupAVCImePayload:
case BuiltinType::OCLIntelSubgroupAVCRefPayload:
@@ -924,10 +949,10 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou
}
break;
}
- case Type::Pointer:
+ case clang::Type::Pointer:
{
- const PointerType *pointer_ty = static_cast<const PointerType*>(ty);
- QualType child_qt = pointer_ty->getPointeeType();
+ const clang::PointerType *pointer_ty = static_cast<const clang::PointerType*>(ty);
+ clang::QualType child_qt = pointer_ty->getPointeeType();
AstNode *child_node = trans_qual_type(c, child_qt, source_loc);
if (child_node == nullptr) {
emit_warning(c, source_loc, "pointer to unsupported type");
@@ -938,90 +963,94 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou
return trans_create_node_prefix_op(c, PrefixOpOptional, child_node);
}
- PtrLen ptr_len = type_is_opaque(c, child_qt.getTypePtr(), source_loc) ? PtrLenSingle : PtrLenUnknown;
-
- AstNode *pointer_node = trans_create_node_ptr_type(c, child_qt.isConstQualified(),
- child_qt.isVolatileQualified(), child_node, ptr_len);
- return trans_create_node_prefix_op(c, PrefixOpOptional, pointer_node);
+ if (type_is_opaque(c, child_qt.getTypePtr(), source_loc)) {
+ AstNode *pointer_node = trans_create_node_ptr_type(c, child_qt.isConstQualified(),
+ child_qt.isVolatileQualified(), child_node, PtrLenSingle);
+ return trans_create_node_prefix_op(c, PrefixOpOptional, pointer_node);
+ } else {
+ return trans_create_node_ptr_type(c, child_qt.isConstQualified(),
+ child_qt.isVolatileQualified(), child_node, PtrLenC);
+ }
}
- case Type::Typedef:
+ case clang::Type::Typedef:
{
- const TypedefType *typedef_ty = static_cast<const TypedefType*>(ty);
- const TypedefNameDecl *typedef_decl = typedef_ty->getDecl();
+ const clang::TypedefType *typedef_ty = static_cast<const clang::TypedefType*>(ty);
+ const clang::TypedefNameDecl *typedef_decl = typedef_ty->getDecl();
return resolve_typedef_decl(c, typedef_decl);
}
- case Type::Elaborated:
+ case clang::Type::Elaborated:
{
- const ElaboratedType *elaborated_ty = static_cast<const ElaboratedType*>(ty);
+ const clang::ElaboratedType *elaborated_ty = static_cast<const clang::ElaboratedType*>(ty);
switch (elaborated_ty->getKeyword()) {
- case ETK_Struct:
- case ETK_Enum:
- case ETK_Union:
+ case clang::ETK_Struct:
+ case clang::ETK_Enum:
+ case clang::ETK_Union:
return trans_qual_type(c, elaborated_ty->getNamedType(), source_loc);
- case ETK_Interface:
- case ETK_Class:
- case ETK_Typename:
- case ETK_None:
+ case clang::ETK_Interface:
+ case clang::ETK_Class:
+ case clang::ETK_Typename:
+ case clang::ETK_None:
emit_warning(c, source_loc, "unsupported elaborated type");
return nullptr;
}
}
- case Type::FunctionProto:
+ case clang::Type::FunctionProto:
+ case clang::Type::FunctionNoProto:
{
- const FunctionProtoType *fn_proto_ty = static_cast<const FunctionProtoType*>(ty);
+ const clang::FunctionType *fn_ty = static_cast<const clang::FunctionType*>(ty);
AstNode *proto_node = trans_create_node(c, NodeTypeFnProto);
- switch (fn_proto_ty->getCallConv()) {
- case CC_C: // __attribute__((cdecl))
+ switch (fn_ty->getCallConv()) {
+ case clang::CC_C: // __attribute__((cdecl))
proto_node->data.fn_proto.cc = CallingConventionC;
proto_node->data.fn_proto.is_extern = true;
break;
- case CC_X86StdCall: // __attribute__((stdcall))
+ case clang::CC_X86StdCall: // __attribute__((stdcall))
proto_node->data.fn_proto.cc = CallingConventionStdcall;
break;
- case CC_X86FastCall: // __attribute__((fastcall))
+ case clang::CC_X86FastCall: // __attribute__((fastcall))
emit_warning(c, source_loc, "unsupported calling convention: x86 fastcall");
return nullptr;
- case CC_X86ThisCall: // __attribute__((thiscall))
+ case clang::CC_X86ThisCall: // __attribute__((thiscall))
emit_warning(c, source_loc, "unsupported calling convention: x86 thiscall");
return nullptr;
- case CC_X86VectorCall: // __attribute__((vectorcall))
+ case clang::CC_X86VectorCall: // __attribute__((vectorcall))
emit_warning(c, source_loc, "unsupported calling convention: x86 vectorcall");
return nullptr;
- case CC_X86Pascal: // __attribute__((pascal))
+ case clang::CC_X86Pascal: // __attribute__((pascal))
emit_warning(c, source_loc, "unsupported calling convention: x86 pascal");
return nullptr;
- case CC_Win64: // __attribute__((ms_abi))
+ case clang::CC_Win64: // __attribute__((ms_abi))
emit_warning(c, source_loc, "unsupported calling convention: win64");
return nullptr;
- case CC_X86_64SysV: // __attribute__((sysv_abi))
+ case clang::CC_X86_64SysV: // __attribute__((sysv_abi))
emit_warning(c, source_loc, "unsupported calling convention: x86 64sysv");
return nullptr;
- case CC_X86RegCall:
+ case clang::CC_X86RegCall:
emit_warning(c, source_loc, "unsupported calling convention: x86 reg");
return nullptr;
- case CC_AAPCS: // __attribute__((pcs("aapcs")))
+ case clang::CC_AAPCS: // __attribute__((pcs("aapcs")))
emit_warning(c, source_loc, "unsupported calling convention: aapcs");
return nullptr;
- case CC_AAPCS_VFP: // __attribute__((pcs("aapcs-vfp")))
+ case clang::CC_AAPCS_VFP: // __attribute__((pcs("aapcs-vfp")))
emit_warning(c, source_loc, "unsupported calling convention: aapcs-vfp");
return nullptr;
- case CC_IntelOclBicc: // __attribute__((intel_ocl_bicc))
+ case clang::CC_IntelOclBicc: // __attribute__((intel_ocl_bicc))
emit_warning(c, source_loc, "unsupported calling convention: intel_ocl_bicc");
return nullptr;
- case CC_SpirFunction: // default for OpenCL functions on SPIR target
+ case clang::CC_SpirFunction: // default for OpenCL functions on SPIR target
emit_warning(c, source_loc, "unsupported calling convention: SPIR function");
return nullptr;
- case CC_OpenCLKernel:
+ case clang::CC_OpenCLKernel:
emit_warning(c, source_loc, "unsupported calling convention: OpenCLKernel");
return nullptr;
- case CC_Swift:
+ case clang::CC_Swift:
emit_warning(c, source_loc, "unsupported calling convention: Swift");
return nullptr;
- case CC_PreserveMost:
+ case clang::CC_PreserveMost:
emit_warning(c, source_loc, "unsupported calling convention: PreserveMost");
return nullptr;
- case CC_PreserveAll:
+ case clang::CC_PreserveAll:
emit_warning(c, source_loc, "unsupported calling convention: PreserveAll");
return nullptr;
case CC_AArch64VectorCall:
@@ -1029,20 +1058,17 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou
return nullptr;
}
- proto_node->data.fn_proto.is_var_args = fn_proto_ty->isVariadic();
- size_t param_count = fn_proto_ty->getNumParams();
-
- if (fn_proto_ty->getNoReturnAttr()) {
+ if (fn_ty->getNoReturnAttr()) {
proto_node->data.fn_proto.return_type = trans_create_node_symbol_str(c, "noreturn");
} else {
- proto_node->data.fn_proto.return_type = trans_qual_type(c, fn_proto_ty->getReturnType(),
+ proto_node->data.fn_proto.return_type = trans_qual_type(c, fn_ty->getReturnType(),
source_loc);
if (proto_node->data.fn_proto.return_type == nullptr) {
emit_warning(c, source_loc, "unsupported function proto return type");
return nullptr;
}
// convert c_void to actual void (only for return type)
- // we do want to look at the AstNode instead of QualType, because
+ // we do want to look at the AstNode instead of clang::QualType, because
// if they do something like:
// typedef Foo void;
// void foo(void) -> Foo;
@@ -1058,8 +1084,17 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou
proto_node->data.fn_proto.name = buf_create_from_str(fn_name);
}
+ if (ty->getTypeClass() == clang::Type::FunctionNoProto) {
+ return proto_node;
+ }
+
+ const clang::FunctionProtoType *fn_proto_ty = static_cast<const clang::FunctionProtoType*>(ty);
+
+ proto_node->data.fn_proto.is_var_args = fn_proto_ty->isVariadic();
+ size_t param_count = fn_proto_ty->getNumParams();
+
for (size_t i = 0; i < param_count; i += 1) {
- QualType qt = fn_proto_ty->getParamType(i);
+ clang::QualType qt = fn_proto_ty->getParamType(i);
AstNode *param_type_node = trans_qual_type(c, qt, source_loc);
if (param_type_node == nullptr) {
@@ -1082,19 +1117,19 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou
return proto_node;
}
- case Type::Record:
+ case clang::Type::Record:
{
- const RecordType *record_ty = static_cast<const RecordType*>(ty);
+ const clang::RecordType *record_ty = static_cast<const clang::RecordType*>(ty);
return resolve_record_decl(c, record_ty->getDecl());
}
- case Type::Enum:
+ case clang::Type::Enum:
{
- const EnumType *enum_ty = static_cast<const EnumType*>(ty);
+ const clang::EnumType *enum_ty = static_cast<const clang::EnumType*>(ty);
return resolve_enum_decl(c, enum_ty->getDecl());
}
- case Type::ConstantArray:
+ case clang::Type::ConstantArray:
{
- const ConstantArrayType *const_arr_ty = static_cast<const ConstantArrayType *>(ty);
+ const clang::ConstantArrayType *const_arr_ty = static_cast<const clang::ConstantArrayType *>(ty);
AstNode *child_type_node = trans_qual_type(c, const_arr_ty->getElementType(), source_loc);
if (child_type_node == nullptr) {
emit_warning(c, source_loc, "unresolved array element type");
@@ -1104,84 +1139,83 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou
AstNode *size_node = trans_create_node_unsigned(c, size);
return trans_create_node_array_type(c, size_node, child_type_node);
}
- case Type::Paren:
+ case clang::Type::Paren:
{
- const ParenType *paren_ty = static_cast<const ParenType *>(ty);
+ const clang::ParenType *paren_ty = static_cast<const clang::ParenType *>(ty);
return trans_qual_type(c, paren_ty->getInnerType(), source_loc);
}
- case Type::Decayed:
+ case clang::Type::Decayed:
{
- const DecayedType *decayed_ty = static_cast<const DecayedType *>(ty);
+ const clang::DecayedType *decayed_ty = static_cast<const clang::DecayedType *>(ty);
return trans_qual_type(c, decayed_ty->getDecayedType(), source_loc);
}
- case Type::Attributed:
+ case clang::Type::Attributed:
{
- const AttributedType *attributed_ty = static_cast<const AttributedType *>(ty);
+ const clang::AttributedType *attributed_ty = static_cast<const clang::AttributedType *>(ty);
return trans_qual_type(c, attributed_ty->getEquivalentType(), source_loc);
}
- case Type::IncompleteArray:
+ case clang::Type::IncompleteArray:
{
- const IncompleteArrayType *incomplete_array_ty = static_cast<const IncompleteArrayType *>(ty);
- QualType child_qt = incomplete_array_ty->getElementType();
+ const clang::IncompleteArrayType *incomplete_array_ty = static_cast<const clang::IncompleteArrayType *>(ty);
+ clang::QualType child_qt = incomplete_array_ty->getElementType();
AstNode *child_type_node = trans_qual_type(c, child_qt, source_loc);
if (child_type_node == nullptr) {
emit_warning(c, source_loc, "unresolved array element type");
return nullptr;
}
AstNode *pointer_node = trans_create_node_ptr_type(c, child_qt.isConstQualified(),
- child_qt.isVolatileQualified(), child_type_node, PtrLenUnknown);
+ child_qt.isVolatileQualified(), child_type_node, PtrLenC);
return pointer_node;
}
- case Type::BlockPointer:
- case Type::LValueReference:
- case Type::RValueReference:
- case Type::MemberPointer:
- case Type::VariableArray:
- case Type::DependentSizedArray:
- case Type::DependentSizedExtVector:
- case Type::Vector:
- case Type::ExtVector:
- case Type::FunctionNoProto:
- case Type::UnresolvedUsing:
- case Type::Adjusted:
- case Type::TypeOfExpr:
- case Type::TypeOf:
- case Type::Decltype:
- case Type::UnaryTransform:
- case Type::TemplateTypeParm:
- case Type::SubstTemplateTypeParm:
- case Type::SubstTemplateTypeParmPack:
- case Type::TemplateSpecialization:
- case Type::Auto:
- case Type::InjectedClassName:
- case Type::DependentName:
- case Type::DependentTemplateSpecialization:
- case Type::PackExpansion:
- case Type::ObjCObject:
- case Type::ObjCInterface:
- case Type::Complex:
- case Type::ObjCObjectPointer:
- case Type::Atomic:
- case Type::Pipe:
- case Type::ObjCTypeParam:
- case Type::DeducedTemplateSpecialization:
- case Type::DependentAddressSpace:
- case Type::DependentVector:
+ case clang::Type::BlockPointer:
+ case clang::Type::LValueReference:
+ case clang::Type::RValueReference:
+ case clang::Type::MemberPointer:
+ case clang::Type::VariableArray:
+ case clang::Type::DependentSizedArray:
+ case clang::Type::DependentSizedExtVector:
+ case clang::Type::Vector:
+ case clang::Type::ExtVector:
+ case clang::Type::UnresolvedUsing:
+ case clang::Type::Adjusted:
+ case clang::Type::TypeOfExpr:
+ case clang::Type::TypeOf:
+ case clang::Type::Decltype:
+ case clang::Type::UnaryTransform:
+ case clang::Type::TemplateTypeParm:
+ case clang::Type::SubstTemplateTypeParm:
+ case clang::Type::SubstTemplateTypeParmPack:
+ case clang::Type::TemplateSpecialization:
+ case clang::Type::Auto:
+ case clang::Type::InjectedClassName:
+ case clang::Type::DependentName:
+ case clang::Type::DependentTemplateSpecialization:
+ case clang::Type::PackExpansion:
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface:
+ case clang::Type::Complex:
+ case clang::Type::ObjCObjectPointer:
+ case clang::Type::Atomic:
+ case clang::Type::Pipe:
+ case clang::Type::ObjCTypeParam:
+ case clang::Type::DeducedTemplateSpecialization:
+ case clang::Type::DependentAddressSpace:
+ case clang::Type::DependentVector:
emit_warning(c, source_loc, "unsupported type: '%s'", ty->getTypeClassName());
return nullptr;
}
zig_unreachable();
}
-static AstNode *trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc) {
+static AstNode *trans_qual_type(Context *c, clang::QualType qt, const clang::SourceLocation &source_loc) {
return trans_type(c, qt.getTypePtr(), source_loc);
}
-static int trans_compound_stmt_inline(Context *c, TransScope *scope, const CompoundStmt *stmt,
+static int trans_compound_stmt_inline(Context *c, TransScope *scope, const clang::CompoundStmt *stmt,
AstNode *block_node, TransScope **out_node_scope)
{
assert(block_node->type == NodeTypeBlock);
- for (CompoundStmt::const_body_iterator it = stmt->body_begin(), end_it = stmt->body_end(); it != end_it; ++it) {
+ for (clang::CompoundStmt::const_body_iterator it = stmt->body_begin(), end_it = stmt->body_end(); it != end_it; ++it) {
AstNode *child_node;
scope = trans_stmt(c, scope, *it, &child_node);
if (scope == nullptr)
@@ -1195,7 +1229,7 @@ static int trans_compound_stmt_inline(Context *c, TransScope *scope, const Compo
return ErrorNone;
}
-static AstNode *trans_compound_stmt(Context *c, TransScope *scope, const CompoundStmt *stmt,
+static AstNode *trans_compound_stmt(Context *c, TransScope *scope, const clang::CompoundStmt *stmt,
TransScope **out_node_scope)
{
TransScopeBlock *child_scope_block = trans_scope_block_create(c, scope);
@@ -1204,8 +1238,8 @@ static AstNode *trans_compound_stmt(Context *c, TransScope *scope, const Compoun
return child_scope_block->node;
}
-static AstNode *trans_return_stmt(Context *c, TransScope *scope, const ReturnStmt *stmt) {
- const Expr *value_expr = stmt->getRetValue();
+static AstNode *trans_return_stmt(Context *c, TransScope *scope, const clang::ReturnStmt *stmt) {
+ const clang::Expr *value_expr = stmt->getRetValue();
if (value_expr == nullptr) {
return trans_create_node(c, NodeTypeReturnExpr);
} else {
@@ -1217,18 +1251,18 @@ static AstNode *trans_return_stmt(Context *c, TransScope *scope, const ReturnStm
}
}
-static AstNode *trans_integer_literal(Context *c, const IntegerLiteral *stmt) {
+static AstNode *trans_integer_literal(Context *c, const clang::IntegerLiteral *stmt) {
Expr::EvalResult result;
- if (!stmt->EvaluateAsInt(result, *c->ctx)) {
+ if (!stmt->EvaluateAsInt(result, *reinterpret_cast<clang::ASTContext *>(c->ctx))) {
emit_warning(c, stmt->getBeginLoc(), "invalid integer literal");
return nullptr;
}
return trans_create_node_apint(c, result.Val.getInt());
}
-static AstNode *trans_constant_expr(Context *c, const ConstantExpr *expr) {
+static AstNode *trans_constant_expr(Context *c, const clang::ConstantExpr *expr) {
Expr::EvalResult result;
- if (!expr->EvaluateAsConstantExpr(result, Expr::EvaluateForCodeGen, *c->ctx)) {
+ if (!expr->EvaluateAsConstantExpr(result, clang::Expr::EvaluateForCodeGen, *c->ctx)) {
emit_warning(c, expr->getBeginLoc(), "invalid constant expression");
return nullptr;
}
@@ -1236,13 +1270,13 @@ static AstNode *trans_constant_expr(Context *c, const ConstantExpr *expr) {
}
static AstNode *trans_conditional_operator(Context *c, ResultUsed result_used, TransScope *scope,
- const ConditionalOperator *stmt)
+ const clang::ConditionalOperator *stmt)
{
AstNode *node = trans_create_node(c, NodeTypeIfBoolExpr);
- Expr *cond_expr = stmt->getCond();
- Expr *true_expr = stmt->getTrueExpr();
- Expr *false_expr = stmt->getFalseExpr();
+ clang::Expr *cond_expr = stmt->getCond();
+ clang::Expr *true_expr = stmt->getTrueExpr();
+ clang::Expr *false_expr = stmt->getFalseExpr();
node->data.if_bool_expr.condition = trans_expr(c, ResultUsedYes, scope, cond_expr, TransRValue);
if (node->data.if_bool_expr.condition == nullptr)
@@ -1259,7 +1293,7 @@ static AstNode *trans_conditional_operator(Context *c, ResultUsed result_used, T
return maybe_suppress_result(c, result_used, node);
}
-static AstNode *trans_create_bin_op(Context *c, TransScope *scope, Expr *lhs, BinOpType bin_op, Expr *rhs) {
+static AstNode *trans_create_bin_op(Context *c, TransScope *scope, clang::Expr *lhs, BinOpType bin_op, clang::Expr *rhs) {
AstNode *node = trans_create_node(c, NodeTypeBinOpExpr);
node->data.bin_op_expr.bin_op = bin_op;
@@ -1274,7 +1308,7 @@ static AstNode *trans_create_bin_op(Context *c, TransScope *scope, Expr *lhs, Bi
return node;
}
-static AstNode *trans_create_bool_bin_op(Context *c, TransScope *scope, Expr *lhs, BinOpType bin_op, Expr *rhs) {
+static AstNode *trans_create_bool_bin_op(Context *c, TransScope *scope, clang::Expr *lhs, BinOpType bin_op, clang::Expr *rhs) {
assert(bin_op == BinOpTypeBoolAnd || bin_op == BinOpTypeBoolOr);
AstNode *node = trans_create_node(c, NodeTypeBinOpExpr);
node->data.bin_op_expr.bin_op = bin_op;
@@ -1290,7 +1324,7 @@ static AstNode *trans_create_bool_bin_op(Context *c, TransScope *scope, Expr *lh
return node;
}
-static AstNode *trans_create_assign(Context *c, ResultUsed result_used, TransScope *scope, Expr *lhs, Expr *rhs) {
+static AstNode *trans_create_assign(Context *c, ResultUsed result_used, TransScope *scope, clang::Expr *lhs, clang::Expr *rhs) {
if (result_used == ResultUsedNo) {
// common case
AstNode *node = trans_create_node(c, NodeTypeBinOpExpr);
@@ -1341,10 +1375,10 @@ static AstNode *trans_create_assign(Context *c, ResultUsed result_used, TransSco
}
}
-static AstNode *trans_create_shift_op(Context *c, TransScope *scope, QualType result_type,
- Expr *lhs_expr, BinOpType bin_op, Expr *rhs_expr)
+static AstNode *trans_create_shift_op(Context *c, TransScope *scope, clang::QualType result_type,
+ clang::Expr *lhs_expr, BinOpType bin_op, clang::Expr *rhs_expr)
{
- const SourceLocation &rhs_location = rhs_expr->getBeginLoc();
+ const clang::SourceLocation &rhs_location = rhs_expr->getBeginLoc();
AstNode *rhs_type = qual_type_to_log2_int_ref(c, result_type, rhs_location);
// lhs >> u5(rh)
@@ -1358,22 +1392,22 @@ static AstNode *trans_create_shift_op(Context *c, TransScope *scope, QualType re
return trans_create_node_bin_op(c, lhs, bin_op, coerced_rhs);
}
-static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransScope *scope, const BinaryOperator *stmt) {
+static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransScope *scope, const clang::BinaryOperator *stmt) {
switch (stmt->getOpcode()) {
- case BO_PtrMemD:
+ case clang::BO_PtrMemD:
emit_warning(c, stmt->getBeginLoc(), "TODO handle more C binary operators: BO_PtrMemD");
return nullptr;
- case BO_PtrMemI:
+ case clang::BO_PtrMemI:
emit_warning(c, stmt->getBeginLoc(), "TODO handle more C binary operators: BO_PtrMemI");
return nullptr;
- case BO_Cmp:
+ case clang::BO_Cmp:
emit_warning(c, stmt->getBeginLoc(), "TODO handle more C binary operators: BO_Cmp");
return nullptr;
- case BO_Mul:
+ case clang::BO_Mul:
return trans_create_bin_op(c, scope, stmt->getLHS(),
qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeMultWrap : BinOpTypeMult,
stmt->getRHS());
- case BO_Div:
+ case clang::BO_Div:
if (qual_type_has_wrapping_overflow(c, stmt->getType())) {
// unsigned/float division uses the operator
return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeDiv, stmt->getRHS());
@@ -1388,7 +1422,7 @@ static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransS
fn_call->data.fn_call_expr.params.append(rhs);
return fn_call;
}
- case BO_Rem:
+ case clang::BO_Rem:
if (qual_type_has_wrapping_overflow(c, stmt->getType())) {
// unsigned/float division uses the operator
return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeMod, stmt->getRHS());
@@ -1403,43 +1437,43 @@ static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransS
fn_call->data.fn_call_expr.params.append(rhs);
return fn_call;
}
- case BO_Add:
+ case clang::BO_Add:
return trans_create_bin_op(c, scope, stmt->getLHS(),
qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeAddWrap : BinOpTypeAdd,
stmt->getRHS());
- case BO_Sub:
+ case clang::BO_Sub:
return trans_create_bin_op(c, scope, stmt->getLHS(),
qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeSubWrap : BinOpTypeSub,
stmt->getRHS());
- case BO_Shl:
+ case clang::BO_Shl:
return trans_create_shift_op(c, scope, stmt->getType(), stmt->getLHS(), BinOpTypeBitShiftLeft, stmt->getRHS());
- case BO_Shr:
+ case clang::BO_Shr:
return trans_create_shift_op(c, scope, stmt->getType(), stmt->getLHS(), BinOpTypeBitShiftRight, stmt->getRHS());
- case BO_LT:
+ case clang::BO_LT:
return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpLessThan, stmt->getRHS());
- case BO_GT:
+ case clang::BO_GT:
return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpGreaterThan, stmt->getRHS());
- case BO_LE:
+ case clang::BO_LE:
return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpLessOrEq, stmt->getRHS());
- case BO_GE:
+ case clang::BO_GE:
return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpGreaterOrEq, stmt->getRHS());
- case BO_EQ:
+ case clang::BO_EQ:
return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpEq, stmt->getRHS());
- case BO_NE:
+ case clang::BO_NE:
return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpNotEq, stmt->getRHS());
- case BO_And:
+ case clang::BO_And:
return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBinAnd, stmt->getRHS());
- case BO_Xor:
+ case clang::BO_Xor:
return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBinXor, stmt->getRHS());
- case BO_Or:
+ case clang::BO_Or:
return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBinOr, stmt->getRHS());
- case BO_LAnd:
+ case clang::BO_LAnd:
return trans_create_bool_bin_op(c, scope, stmt->getLHS(), BinOpTypeBoolAnd, stmt->getRHS());
- case BO_LOr:
+ case clang::BO_LOr:
return trans_create_bool_bin_op(c, scope, stmt->getLHS(), BinOpTypeBoolOr, stmt->getRHS());
- case BO_Assign:
+ case clang::BO_Assign:
return trans_create_assign(c, result_used, scope, stmt->getLHS(), stmt->getRHS());
- case BO_Comma:
+ case clang::BO_Comma:
{
TransScopeBlock *scope_block = trans_scope_block_create(c, scope);
Buf *label_name = buf_create_from_str("x");
@@ -1456,16 +1490,16 @@ static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransS
scope_block->node->data.block.statements.append(trans_create_node_break(c, label_name, maybe_suppress_result(c, result_used, rhs)));
return scope_block->node;
}
- case BO_MulAssign:
- case BO_DivAssign:
- case BO_RemAssign:
- case BO_AddAssign:
- case BO_SubAssign:
- case BO_ShlAssign:
- case BO_ShrAssign:
- case BO_AndAssign:
- case BO_XorAssign:
- case BO_OrAssign:
+ case clang::BO_MulAssign:
+ case clang::BO_DivAssign:
+ case clang::BO_RemAssign:
+ case clang::BO_AddAssign:
+ case clang::BO_SubAssign:
+ case clang::BO_ShlAssign:
+ case clang::BO_ShrAssign:
+ case clang::BO_AndAssign:
+ case clang::BO_XorAssign:
+ case clang::BO_OrAssign:
zig_unreachable();
}
@@ -1473,9 +1507,9 @@ static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransS
}
static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result_used, TransScope *scope,
- const CompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op)
+ const clang::CompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op)
{
- const SourceLocation &rhs_location = stmt->getRHS()->getBeginLoc();
+ const clang::SourceLocation &rhs_location = stmt->getRHS()->getBeginLoc();
AstNode *rhs_type = qual_type_to_log2_int_ref(c, stmt->getComputationLHSType(), rhs_location);
bool use_intermediate_casts = stmt->getComputationLHSType().getTypePtr() != stmt->getComputationResultType().getTypePtr();
@@ -1555,7 +1589,7 @@ static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result
}
static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used, TransScope *scope,
- const CompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op)
+ const clang::CompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op)
{
if (result_used == ResultUsedNo) {
// simple common case, where the C and Zig are identical:
@@ -1615,76 +1649,76 @@ static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used,
static AstNode *trans_compound_assign_operator(Context *c, ResultUsed result_used, TransScope *scope,
- const CompoundAssignOperator *stmt)
+ const clang::CompoundAssignOperator *stmt)
{
switch (stmt->getOpcode()) {
- case BO_MulAssign:
+ case clang::BO_MulAssign:
if (qual_type_has_wrapping_overflow(c, stmt->getType()))
return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignTimesWrap, BinOpTypeMultWrap);
else
return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignTimes, BinOpTypeMult);
- case BO_DivAssign:
+ case clang::BO_DivAssign:
emit_warning(c, stmt->getBeginLoc(), "TODO handle more C compound assign operators: BO_DivAssign");
return nullptr;
- case BO_RemAssign:
+ case clang::BO_RemAssign:
emit_warning(c, stmt->getBeginLoc(), "TODO handle more C compound assign operators: BO_RemAssign");
return nullptr;
- case BO_Cmp:
+ case clang::BO_Cmp:
emit_warning(c, stmt->getBeginLoc(), "TODO handle more C compound assign operators: BO_Cmp");
return nullptr;
- case BO_AddAssign:
+ case clang::BO_AddAssign:
if (qual_type_has_wrapping_overflow(c, stmt->getType()))
return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignPlusWrap, BinOpTypeAddWrap);
else
return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignPlus, BinOpTypeAdd);
- case BO_SubAssign:
+ case clang::BO_SubAssign:
if (qual_type_has_wrapping_overflow(c, stmt->getType()))
return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignMinusWrap, BinOpTypeSubWrap);
else
return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignMinus, BinOpTypeSub);
- case BO_ShlAssign:
+ case clang::BO_ShlAssign:
return trans_create_compound_assign_shift(c, result_used, scope, stmt, BinOpTypeAssignBitShiftLeft, BinOpTypeBitShiftLeft);
- case BO_ShrAssign:
+ case clang::BO_ShrAssign:
return trans_create_compound_assign_shift(c, result_used, scope, stmt, BinOpTypeAssignBitShiftRight, BinOpTypeBitShiftRight);
- case BO_AndAssign:
+ case clang::BO_AndAssign:
return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignBitAnd, BinOpTypeBinAnd);
- case BO_XorAssign:
+ case clang::BO_XorAssign:
return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignBitXor, BinOpTypeBinXor);
- case BO_OrAssign:
+ case clang::BO_OrAssign:
return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignBitOr, BinOpTypeBinOr);
- case BO_PtrMemD:
- case BO_PtrMemI:
- case BO_Assign:
- case BO_Mul:
- case BO_Div:
- case BO_Rem:
- case BO_Add:
- case BO_Sub:
- case BO_Shl:
- case BO_Shr:
- case BO_LT:
- case BO_GT:
- case BO_LE:
- case BO_GE:
- case BO_EQ:
- case BO_NE:
- case BO_And:
- case BO_Xor:
- case BO_Or:
- case BO_LAnd:
- case BO_LOr:
- case BO_Comma:
+ case clang::BO_PtrMemD:
+ case clang::BO_PtrMemI:
+ case clang::BO_Assign:
+ case clang::BO_Mul:
+ case clang::BO_Div:
+ case clang::BO_Rem:
+ case clang::BO_Add:
+ case clang::BO_Sub:
+ case clang::BO_Shl:
+ case clang::BO_Shr:
+ case clang::BO_LT:
+ case clang::BO_GT:
+ case clang::BO_LE:
+ case clang::BO_GE:
+ case clang::BO_EQ:
+ case clang::BO_NE:
+ case clang::BO_And:
+ case clang::BO_Xor:
+ case clang::BO_Or:
+ case clang::BO_LAnd:
+ case clang::BO_LOr:
+ case clang::BO_Comma:
zig_unreachable();
}
zig_unreachable();
}
-static AstNode *trans_implicit_cast_expr(Context *c, TransScope *scope, const ImplicitCastExpr *stmt) {
+static AstNode *trans_implicit_cast_expr(Context *c, TransScope *scope, const clang::ImplicitCastExpr *stmt) {
switch (stmt->getCastKind()) {
- case CK_LValueToRValue:
+ case clang::CK_LValueToRValue:
return trans_expr(c, ResultUsedYes, scope, stmt->getSubExpr(), TransRValue);
- case CK_IntegralCast:
+ case clang::CK_IntegralCast:
{
AstNode *target_node = trans_expr(c, ResultUsedYes, scope, stmt->getSubExpr(), TransRValue);
if (target_node == nullptr)
@@ -1692,15 +1726,15 @@ static AstNode *trans_implicit_cast_expr(Context *c, TransScope *scope, const Im
return trans_c_cast(c, stmt->getExprLoc(), stmt->getType(),
stmt->getSubExpr()->getType(), target_node);
}
- case CK_FunctionToPointerDecay:
- case CK_ArrayToPointerDecay:
+ case clang::CK_FunctionToPointerDecay:
+ case clang::CK_ArrayToPointerDecay:
{
AstNode *target_node = trans_expr(c, ResultUsedYes, scope, stmt->getSubExpr(), TransRValue);
if (target_node == nullptr)
return nullptr;
return target_node;
}
- case CK_BitCast:
+ case clang::CK_BitCast:
{
AstNode *target_node = trans_expr(c, ResultUsedYes, scope, stmt->getSubExpr(), TransRValue);
if (target_node == nullptr)
@@ -1717,172 +1751,55 @@ static AstNode *trans_implicit_cast_expr(Context *c, TransScope *scope, const Im
node->data.fn_call_expr.params.append(target_node);
return node;
}
- case CK_NullToPointer:
- return trans_create_node(c, NodeTypeNullLiteral);
- case CK_Dependent:
+ case clang::CK_NullToPointer:
+ return trans_create_node_unsigned(c, 0);
+ case clang::CK_NoOp:
+ return trans_expr(c, ResultUsedYes, scope, stmt->getSubExpr(), TransRValue);
+ case clang::CK_Dependent:
emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_Dependent");
return nullptr;
- case CK_LValueBitCast:
+ case clang::CK_LValueBitCast:
emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_LValueBitCast");
return nullptr;
- case CK_NoOp:
- return trans_expr(c, ResultUsedYes, scope, stmt->getSubExpr(), TransRValue);
- case CK_BaseToDerived:
+ case clang::CK_BaseToDerived:
emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_BaseToDerived");
return nullptr;
- case CK_DerivedToBase:
+ case clang::CK_DerivedToBase:
emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_DerivedToBase");
return nullptr;
- case CK_UncheckedDerivedToBase:
+ case clang::CK_UncheckedDerivedToBase:
emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_UncheckedDerivedToBase");
return nullptr;
- case CK_Dynamic:
+ case clang::CK_Dynamic:
emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_Dynamic");
return nullptr;
- case CK_ToUnion:
+ case clang::CK_ToUnion:
emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_ToUnion");
return nullptr;
- case CK_NullToMemberPointer:
+ case clang::CK_NullToMemberPointer:
emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_NullToMemberPointer");
return nullptr;
- case CK_BaseToDerivedMemberPointer:
+ case clang::CK_BaseToDerivedMemberPointer:
emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_BaseToDerivedMemberPointer");
return nullptr;
- case CK_DerivedToBaseMemberPointer:
+ case clang::CK_DerivedToBaseMemberPointer:
emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_DerivedToBaseMemberPointer");
return nullptr;
- case CK_MemberPointerToBoolean:
+ case clang::CK_MemberPointerToBoolean:
emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_MemberPointerToBoolean");
return nullptr;
- case CK_ReinterpretMemberPointer:
+ case clang::CK_ReinterpretMemberPointer:
emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_ReinterpretMemberPointer");
return nullptr;
- case CK_UserDefinedConversion:
+ case clang::CK_UserDefinedConversion:
emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_UserDefinedConversion");
return nullptr;
- case CK_ConstructorConversion:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_ConstructorConversion");
- return nullptr;
- case CK_IntegralToPointer:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_IntegralToPointer");
- return nullptr;
- case CK_PointerToIntegral:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_PointerToIntegral");
- return nullptr;
- case CK_PointerToBoolean:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_PointerToBoolean");
- return nullptr;
- case CK_ToVoid:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_ToVoid");
- return nullptr;
- case CK_VectorSplat:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_VectorSplat");
- return nullptr;
- case CK_IntegralToBoolean:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_IntegralToBoolean");
- return nullptr;
- case CK_IntegralToFloating:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_IntegralToFloating");
- return nullptr;
- case CK_FloatingToIntegral:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_FloatingToIntegral");
- return nullptr;
- case CK_FloatingToBoolean:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_FloatingToBoolean");
- return nullptr;
- case CK_BooleanToSignedIntegral:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_BooleanToSignedIntegral");
- return nullptr;
- case CK_FloatingCast:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_FloatingCast");
- return nullptr;
- case CK_CPointerToObjCPointerCast:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_CPointerToObjCPointerCast");
- return nullptr;
- case CK_BlockPointerToObjCPointerCast:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_BlockPointerToObjCPointerCast");
- return nullptr;
- case CK_AnyPointerToBlockPointerCast:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_AnyPointerToBlockPointerCast");
- return nullptr;
- case CK_ObjCObjectLValueCast:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_ObjCObjectLValueCast");
- return nullptr;
- case CK_FloatingRealToComplex:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_FloatingRealToComplex");
- return nullptr;
- case CK_FloatingComplexToReal:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_FloatingComplexToReal");
- return nullptr;
- case CK_FloatingComplexToBoolean:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_FloatingComplexToBoolean");
- return nullptr;
- case CK_FloatingComplexCast:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_FloatingComplexCast");
- return nullptr;
- case CK_FloatingComplexToIntegralComplex:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_FloatingComplexToIntegralComplex");
- return nullptr;
- case CK_IntegralRealToComplex:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_IntegralRealToComplex");
- return nullptr;
- case CK_IntegralComplexToReal:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_IntegralComplexToReal");
- return nullptr;
- case CK_IntegralComplexToBoolean:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_IntegralComplexToBoolean");
- return nullptr;
- case CK_IntegralComplexCast:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_IntegralComplexCast");
- return nullptr;
- case CK_IntegralComplexToFloatingComplex:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_IntegralComplexToFloatingComplex");
- return nullptr;
- case CK_ARCProduceObject:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_ARCProduceObject");
- return nullptr;
- case CK_ARCConsumeObject:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_ARCConsumeObject");
- return nullptr;
- case CK_ARCReclaimReturnedObject:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_ARCReclaimReturnedObject");
- return nullptr;
- case CK_ARCExtendBlockObject:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_ARCExtendBlockObject");
- return nullptr;
- case CK_AtomicToNonAtomic:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_AtomicToNonAtomic");
- return nullptr;
- case CK_NonAtomicToAtomic:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_NonAtomicToAtomic");
- return nullptr;
- case CK_CopyAndAutoreleaseBlockObject:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_CopyAndAutoreleaseBlockObject");
- return nullptr;
- case CK_BuiltinFnToFnPtr:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_BuiltinFnToFnPtr");
- return nullptr;
- case CK_AddressSpaceConversion:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_AddressSpaceConversion");
- return nullptr;
- case CK_IntToOCLSampler:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_IntToOCLSampler");
- return nullptr;
- case CK_FixedPointCast:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_FixedPointCast");
- return nullptr;
- case CK_FixedPointToBoolean:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_FixedPointToBoolean");
- return nullptr;
- case CK_ZeroToOCLOpaqueType:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation cast CK_ZeroToOCLOpaqueType");
- return nullptr;
}
zig_unreachable();
}
-static AstNode *trans_decl_ref_expr(Context *c, TransScope *scope, const DeclRefExpr *stmt, TransLRValue lrval) {
- const ValueDecl *value_decl = stmt->getDecl();
+static AstNode *trans_decl_ref_expr(Context *c, TransScope *scope, const clang::DeclRefExpr *stmt, TransLRValue lrval) {
+ const clang::ValueDecl *value_decl = stmt->getDecl();
Buf *c_symbol_name = buf_create_from_str(decl_name(value_decl));
Buf *zig_symbol_name = trans_lookup_zig_symbol(c, scope, c_symbol_name);
if (lrval == TransLValue) {
@@ -1892,9 +1809,9 @@ static AstNode *trans_decl_ref_expr(Context *c, TransScope *scope, const DeclRef
}
static AstNode *trans_create_post_crement(Context *c, ResultUsed result_used, TransScope *scope,
- const UnaryOperator *stmt, BinOpType assign_op)
+ const clang::UnaryOperator *stmt, BinOpType assign_op)
{
- Expr *op_expr = stmt->getSubExpr();
+ clang::Expr *op_expr = stmt->getSubExpr();
if (result_used == ResultUsedNo) {
// common case
@@ -1948,9 +1865,9 @@ static AstNode *trans_create_post_crement(Context *c, ResultUsed result_used, Tr
}
static AstNode *trans_create_pre_crement(Context *c, ResultUsed result_used, TransScope *scope,
- const UnaryOperator *stmt, BinOpType assign_op)
+ const clang::UnaryOperator *stmt, BinOpType assign_op)
{
- Expr *op_expr = stmt->getSubExpr();
+ clang::Expr *op_expr = stmt->getSubExpr();
if (result_used == ResultUsedNo) {
// common case
@@ -1997,36 +1914,36 @@ static AstNode *trans_create_pre_crement(Context *c, ResultUsed result_used, Tra
return child_scope->node;
}
-static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransScope *scope, const UnaryOperator *stmt) {
+static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransScope *scope, const clang::UnaryOperator *stmt) {
switch (stmt->getOpcode()) {
- case UO_PostInc:
+ case clang::UO_PostInc:
if (qual_type_has_wrapping_overflow(c, stmt->getType()))
return trans_create_post_crement(c, result_used, scope, stmt, BinOpTypeAssignPlusWrap);
else
return trans_create_post_crement(c, result_used, scope, stmt, BinOpTypeAssignPlus);
- case UO_PostDec:
+ case clang::UO_PostDec:
if (qual_type_has_wrapping_overflow(c, stmt->getType()))
return trans_create_post_crement(c, result_used, scope, stmt, BinOpTypeAssignMinusWrap);
else
return trans_create_post_crement(c, result_used, scope, stmt, BinOpTypeAssignMinus);
- case UO_PreInc:
+ case clang::UO_PreInc:
if (qual_type_has_wrapping_overflow(c, stmt->getType()))
return trans_create_pre_crement(c, result_used, scope, stmt, BinOpTypeAssignPlusWrap);
else
return trans_create_pre_crement(c, result_used, scope, stmt, BinOpTypeAssignPlus);
- case UO_PreDec:
+ case clang::UO_PreDec:
if (qual_type_has_wrapping_overflow(c, stmt->getType()))
return trans_create_pre_crement(c, result_used, scope, stmt, BinOpTypeAssignMinusWrap);
else
return trans_create_pre_crement(c, result_used, scope, stmt, BinOpTypeAssignMinus);
- case UO_AddrOf:
+ case clang::UO_AddrOf:
{
AstNode *value_node = trans_expr(c, result_used, scope, stmt->getSubExpr(), TransLValue);
if (value_node == nullptr)
return value_node;
return trans_create_node_addr_of(c, value_node);
}
- case UO_Deref:
+ case clang::UO_Deref:
{
AstNode *value_node = trans_expr(c, result_used, scope, stmt->getSubExpr(), TransRValue);
if (value_node == nullptr)
@@ -2037,12 +1954,12 @@ static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransSc
AstNode *unwrapped = trans_create_node_unwrap_null(c, value_node);
return trans_create_node_ptr_deref(c, unwrapped);
}
- case UO_Plus:
+ case clang::UO_Plus:
emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation UO_Plus");
return nullptr;
- case UO_Minus:
+ case clang::UO_Minus:
{
- Expr *op_expr = stmt->getSubExpr();
+ clang::Expr *op_expr = stmt->getSubExpr();
if (!qual_type_has_wrapping_overflow(c, op_expr->getType())) {
AstNode *node = trans_create_node(c, NodeTypePrefixOpExpr);
node->data.prefix_op_expr.prefix_op = PrefixOpNegation;
@@ -2068,41 +1985,41 @@ static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransSc
return nullptr;
}
}
- case UO_Not:
+ case clang::UO_Not:
{
- Expr *op_expr = stmt->getSubExpr();
+ clang::Expr *op_expr = stmt->getSubExpr();
AstNode *sub_node = trans_expr(c, ResultUsedYes, scope, op_expr, TransRValue);
if (sub_node == nullptr)
return nullptr;
return trans_create_node_prefix_op(c, PrefixOpBinNot, sub_node);
}
- case UO_LNot:
+ case clang::UO_LNot:
{
- Expr *op_expr = stmt->getSubExpr();
+ clang::Expr *op_expr = stmt->getSubExpr();
AstNode *sub_node = trans_bool_expr(c, ResultUsedYes, scope, op_expr, TransRValue);
if (sub_node == nullptr)
return nullptr;
return trans_create_node_prefix_op(c, PrefixOpBoolNot, sub_node);
}
- case UO_Real:
+ case clang::UO_Real:
emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation UO_Real");
return nullptr;
- case UO_Imag:
+ case clang::UO_Imag:
emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation UO_Imag");
return nullptr;
- case UO_Extension:
+ case clang::UO_Extension:
emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation UO_Extension");
return nullptr;
- case UO_Coawait:
+ case clang::UO_Coawait:
emit_warning(c, stmt->getBeginLoc(), "TODO handle C translation UO_Coawait");
return nullptr;
}
zig_unreachable();
}
-static int trans_local_declaration(Context *c, TransScope *scope, const DeclStmt *stmt,
+static int trans_local_declaration(Context *c, TransScope *scope, const clang::DeclStmt *stmt,
AstNode **out_node, TransScope **out_scope)
{
// declarations are added via the scope
@@ -2112,11 +2029,11 @@ static int trans_local_declaration(Context *c, TransScope *scope, const DeclStmt
assert(scope_block != nullptr);
for (auto iter = stmt->decl_begin(); iter != stmt->decl_end(); iter++) {
- Decl *decl = *iter;
+ clang::Decl *decl = *iter;
switch (decl->getKind()) {
- case Decl::Var: {
- VarDecl *var_decl = (VarDecl *)decl;
- QualType qual_type = var_decl->getTypeSourceInfo()->getType();
+ case clang::Decl::Var: {
+ clang::VarDecl *var_decl = (clang::VarDecl *)decl;
+ clang::QualType qual_type = var_decl->getTypeSourceInfo()->getType();
AstNode *init_node = nullptr;
if (var_decl->hasInit()) {
init_node = trans_expr(c, ResultUsedYes, scope, var_decl->getInit(), TransRValue);
@@ -2141,225 +2058,9 @@ static int trans_local_declaration(Context *c, TransScope *scope, const DeclStmt
scope_block->node->data.block.statements.append(node);
continue;
}
- case Decl::AccessSpec:
+ case clang::Decl::AccessSpec:
emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind AccessSpec");
return ErrorUnexpected;
- case Decl::Block:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind Block");
- return ErrorUnexpected;
- case Decl::Captured:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind Captured");
- return ErrorUnexpected;
- case Decl::ClassScopeFunctionSpecialization:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind ClassScopeFunctionSpecialization");
- return ErrorUnexpected;
- case Decl::Empty:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind Empty");
- return ErrorUnexpected;
- case Decl::Export:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind Export");
- return ErrorUnexpected;
- case Decl::ExternCContext:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind ExternCContext");
- return ErrorUnexpected;
- case Decl::FileScopeAsm:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind FileScopeAsm");
- return ErrorUnexpected;
- case Decl::Friend:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind Friend");
- return ErrorUnexpected;
- case Decl::FriendTemplate:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind FriendTemplate");
- return ErrorUnexpected;
- case Decl::Import:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind Import");
- return ErrorUnexpected;
- case Decl::LinkageSpec:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind LinkageSpec");
- return ErrorUnexpected;
- case Decl::Label:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind Label");
- return ErrorUnexpected;
- case Decl::Namespace:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind Namespace");
- return ErrorUnexpected;
- case Decl::NamespaceAlias:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind NamespaceAlias");
- return ErrorUnexpected;
- case Decl::ObjCCompatibleAlias:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind ObjCCompatibleAlias");
- return ErrorUnexpected;
- case Decl::ObjCCategory:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind ObjCCategory");
- return ErrorUnexpected;
- case Decl::ObjCCategoryImpl:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind ObjCCategoryImpl");
- return ErrorUnexpected;
- case Decl::ObjCImplementation:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind ObjCImplementation");
- return ErrorUnexpected;
- case Decl::ObjCInterface:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind ObjCInterface");
- return ErrorUnexpected;
- case Decl::ObjCProtocol:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind ObjCProtocol");
- return ErrorUnexpected;
- case Decl::ObjCMethod:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind ObjCMethod");
- return ErrorUnexpected;
- case Decl::ObjCProperty:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind ObjCProperty");
- return ErrorUnexpected;
- case Decl::BuiltinTemplate:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind BuiltinTemplate");
- return ErrorUnexpected;
- case Decl::ClassTemplate:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind ClassTemplate");
- return ErrorUnexpected;
- case Decl::FunctionTemplate:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind FunctionTemplate");
- return ErrorUnexpected;
- case Decl::TypeAliasTemplate:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind TypeAliasTemplate");
- return ErrorUnexpected;
- case Decl::VarTemplate:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind VarTemplate");
- return ErrorUnexpected;
- case Decl::TemplateTemplateParm:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind TemplateTemplateParm");
- return ErrorUnexpected;
- case Decl::Enum:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind Enum");
- return ErrorUnexpected;
- case Decl::Record:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind Record");
- return ErrorUnexpected;
- case Decl::CXXRecord:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind CXXRecord");
- return ErrorUnexpected;
- case Decl::ClassTemplateSpecialization:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind ClassTemplateSpecialization");
- return ErrorUnexpected;
- case Decl::ClassTemplatePartialSpecialization:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind ClassTemplatePartialSpecialization");
- return ErrorUnexpected;
- case Decl::TemplateTypeParm:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind TemplateTypeParm");
- return ErrorUnexpected;
- case Decl::ObjCTypeParam:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind ObjCTypeParam");
- return ErrorUnexpected;
- case Decl::TypeAlias:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind TypeAlias");
- return ErrorUnexpected;
- case Decl::Typedef:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind Typedef");
- return ErrorUnexpected;
- case Decl::UnresolvedUsingTypename:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind UnresolvedUsingTypename");
- return ErrorUnexpected;
- case Decl::Using:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind Using");
- return ErrorUnexpected;
- case Decl::UsingDirective:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind UsingDirective");
- return ErrorUnexpected;
- case Decl::UsingPack:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind UsingPack");
- return ErrorUnexpected;
- case Decl::UsingShadow:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind UsingShadow");
- return ErrorUnexpected;
- case Decl::ConstructorUsingShadow:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind ConstructorUsingShadow");
- return ErrorUnexpected;
- case Decl::Binding:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind Binding");
- return ErrorUnexpected;
- case Decl::Field:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind Field");
- return ErrorUnexpected;
- case Decl::ObjCAtDefsField:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind ObjCAtDefsField");
- return ErrorUnexpected;
- case Decl::ObjCIvar:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind ObjCIvar");
- return ErrorUnexpected;
- case Decl::Function:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind Function");
- return ErrorUnexpected;
- case Decl::CXXDeductionGuide:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind CXXDeductionGuide");
- return ErrorUnexpected;
- case Decl::CXXMethod:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind CXXMethod");
- return ErrorUnexpected;
- case Decl::CXXConstructor:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind CXXConstructor");
- return ErrorUnexpected;
- case Decl::CXXConversion:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind CXXConversion");
- return ErrorUnexpected;
- case Decl::CXXDestructor:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind CXXDestructor");
- return ErrorUnexpected;
- case Decl::MSProperty:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind MSProperty");
- return ErrorUnexpected;
- case Decl::NonTypeTemplateParm:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind NonTypeTemplateParm");
- return ErrorUnexpected;
- case Decl::Decomposition:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind Decomposition");
- return ErrorUnexpected;
- case Decl::ImplicitParam:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind ImplicitParam");
- return ErrorUnexpected;
- case Decl::OMPCapturedExpr:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind OMPCapturedExpr");
- return ErrorUnexpected;
- case Decl::ParmVar:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind ParmVar");
- return ErrorUnexpected;
- case Decl::VarTemplateSpecialization:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind VarTemplateSpecialization");
- return ErrorUnexpected;
- case Decl::VarTemplatePartialSpecialization:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind VarTemplatePartialSpecialization");
- return ErrorUnexpected;
- case Decl::EnumConstant:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind EnumConstant");
- return ErrorUnexpected;
- case Decl::IndirectField:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind IndirectField");
- return ErrorUnexpected;
- case Decl::OMPDeclareReduction:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind OMPDeclareReduction");
- return ErrorUnexpected;
- case Decl::UnresolvedUsingValue:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind UnresolvedUsingValue");
- return ErrorUnexpected;
- case Decl::OMPThreadPrivate:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind OMPThreadPrivate");
- return ErrorUnexpected;
- case Decl::ObjCPropertyImpl:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind ObjCPropertyImpl");
- return ErrorUnexpected;
- case Decl::PragmaComment:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind PragmaComment");
- return ErrorUnexpected;
- case Decl::PragmaDetectMismatch:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind PragmaDetectMismatch");
- return ErrorUnexpected;
- case Decl::StaticAssert:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind StaticAssert");
- return ErrorUnexpected;
- case Decl::TranslationUnit:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind TranslationUnit");
- return ErrorUnexpected;
- case Decl::OMPRequires:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle decl kind OMPRequires");
- return ErrorUnexpected;
}
zig_unreachable();
}
@@ -2384,7 +2085,7 @@ static AstNode *to_enum_zero_cmp(Context *c, AstNode *expr, AstNode *enum_type)
return trans_create_node_bin_op(c, expr, BinOpTypeCmpNotEq, bitcast);
}
-static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *scope, const Expr *expr, TransLRValue lrval) {
+static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *scope, const clang::Expr *expr, TransLRValue lrval) {
AstNode *res = trans_expr(c, result_used, scope, expr, lrval);
if (res == nullptr)
return nullptr;
@@ -2421,143 +2122,145 @@ static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *
}
- const Type *ty = get_expr_qual_type_before_implicit_cast(c, expr).getTypePtr();
+ const clang::Type *ty = get_expr_qual_type_before_implicit_cast(c, expr).getTypePtr();
auto classs = ty->getTypeClass();
switch (classs) {
- case Type::Builtin:
+ case clang::Type::Builtin:
{
- const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(ty);
+ const clang::BuiltinType *builtin_ty = static_cast<const clang::BuiltinType*>(ty);
switch (builtin_ty->getKind()) {
- case BuiltinType::Bool:
- case BuiltinType::Char_U:
- case BuiltinType::UChar:
- case BuiltinType::Char_S:
- case BuiltinType::SChar:
- case BuiltinType::UShort:
- case BuiltinType::UInt:
- case BuiltinType::ULong:
- case BuiltinType::ULongLong:
- case BuiltinType::Short:
- case BuiltinType::Int:
- case BuiltinType::Long:
- case BuiltinType::LongLong:
- case BuiltinType::UInt128:
- case BuiltinType::Int128:
- case BuiltinType::Float:
- case BuiltinType::Double:
- case BuiltinType::Float128:
- case BuiltinType::LongDouble:
- case BuiltinType::WChar_U:
- case BuiltinType::Char8:
- case BuiltinType::Char16:
- case BuiltinType::Char32:
- case BuiltinType::WChar_S:
- case BuiltinType::Float16:
+ case clang::BuiltinType::Bool:
+ case clang::BuiltinType::Char_U:
+ case clang::BuiltinType::UChar:
+ case clang::BuiltinType::Char_S:
+ case clang::BuiltinType::SChar:
+ case clang::BuiltinType::UShort:
+ case clang::BuiltinType::UInt:
+ case clang::BuiltinType::ULong:
+ case clang::BuiltinType::ULongLong:
+ case clang::BuiltinType::Short:
+ case clang::BuiltinType::Int:
+ case clang::BuiltinType::Long:
+ case clang::BuiltinType::LongLong:
+ case clang::BuiltinType::UInt128:
+ case clang::BuiltinType::Int128:
+ case clang::BuiltinType::Float:
+ case clang::BuiltinType::Double:
+ case clang::BuiltinType::Float128:
+ case clang::BuiltinType::LongDouble:
+ case clang::BuiltinType::WChar_U:
+ case clang::BuiltinType::Char8:
+ case clang::BuiltinType::Char16:
+ case clang::BuiltinType::Char32:
+ case clang::BuiltinType::WChar_S:
+ case clang::BuiltinType::Float16:
return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node_unsigned_negative(c, 0, false));
- case BuiltinType::NullPtr:
- return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node(c, NodeTypeNullLiteral));
-
- case BuiltinType::Void:
- case BuiltinType::Half:
- case BuiltinType::ObjCId:
- case BuiltinType::ObjCClass:
- case BuiltinType::ObjCSel:
- case BuiltinType::OMPArraySection:
- case BuiltinType::Dependent:
- case BuiltinType::Overload:
- case BuiltinType::BoundMember:
- case BuiltinType::PseudoObject:
- case BuiltinType::UnknownAny:
- case BuiltinType::BuiltinFn:
- case BuiltinType::ARCUnbridgedCast:
- case BuiltinType::OCLImage1dRO:
- case BuiltinType::OCLImage1dArrayRO:
- case BuiltinType::OCLImage1dBufferRO:
- case BuiltinType::OCLImage2dRO:
- case BuiltinType::OCLImage2dArrayRO:
- case BuiltinType::OCLImage2dDepthRO:
- case BuiltinType::OCLImage2dArrayDepthRO:
- case BuiltinType::OCLImage2dMSAARO:
- case BuiltinType::OCLImage2dArrayMSAARO:
- case BuiltinType::OCLImage2dMSAADepthRO:
- case BuiltinType::OCLImage2dArrayMSAADepthRO:
- case BuiltinType::OCLImage3dRO:
- case BuiltinType::OCLImage1dWO:
- case BuiltinType::OCLImage1dArrayWO:
- case BuiltinType::OCLImage1dBufferWO:
- case BuiltinType::OCLImage2dWO:
- case BuiltinType::OCLImage2dArrayWO:
- case BuiltinType::OCLImage2dDepthWO:
- case BuiltinType::OCLImage2dArrayDepthWO:
- case BuiltinType::OCLImage2dMSAAWO:
- case BuiltinType::OCLImage2dArrayMSAAWO:
- case BuiltinType::OCLImage2dMSAADepthWO:
- case BuiltinType::OCLImage2dArrayMSAADepthWO:
- case BuiltinType::OCLImage3dWO:
- case BuiltinType::OCLImage1dRW:
- case BuiltinType::OCLImage1dArrayRW:
- case BuiltinType::OCLImage1dBufferRW:
- case BuiltinType::OCLImage2dRW:
- case BuiltinType::OCLImage2dArrayRW:
- case BuiltinType::OCLImage2dDepthRW:
- case BuiltinType::OCLImage2dArrayDepthRW:
- case BuiltinType::OCLImage2dMSAARW:
- case BuiltinType::OCLImage2dArrayMSAARW:
- case BuiltinType::OCLImage2dMSAADepthRW:
- case BuiltinType::OCLImage2dArrayMSAADepthRW:
- case BuiltinType::OCLImage3dRW:
- case BuiltinType::OCLSampler:
- case BuiltinType::OCLEvent:
- case BuiltinType::OCLClkEvent:
- case BuiltinType::OCLQueue:
- case BuiltinType::OCLReserveID:
- case BuiltinType::ShortAccum:
- case BuiltinType::Accum:
- case BuiltinType::LongAccum:
- case BuiltinType::UShortAccum:
- case BuiltinType::UAccum:
- case BuiltinType::ULongAccum:
- case BuiltinType::ShortFract:
- case BuiltinType::Fract:
- case BuiltinType::LongFract:
- case BuiltinType::UShortFract:
- case BuiltinType::UFract:
- case BuiltinType::ULongFract:
- case BuiltinType::SatShortAccum:
- case BuiltinType::SatAccum:
- case BuiltinType::SatLongAccum:
- case BuiltinType::SatUShortAccum:
- case BuiltinType::SatUAccum:
- case BuiltinType::SatULongAccum:
- case BuiltinType::SatShortFract:
- case BuiltinType::SatFract:
- case BuiltinType::SatLongFract:
- case BuiltinType::SatUShortFract:
- case BuiltinType::SatUFract:
- case BuiltinType::SatULongFract:
- case BuiltinType::OCLIntelSubgroupAVCMcePayload:
- case BuiltinType::OCLIntelSubgroupAVCImePayload:
- case BuiltinType::OCLIntelSubgroupAVCRefPayload:
- case BuiltinType::OCLIntelSubgroupAVCSicPayload:
- case BuiltinType::OCLIntelSubgroupAVCMceResult:
- case BuiltinType::OCLIntelSubgroupAVCImeResult:
- case BuiltinType::OCLIntelSubgroupAVCRefResult:
- case BuiltinType::OCLIntelSubgroupAVCSicResult:
- case BuiltinType::OCLIntelSubgroupAVCImeResultSingleRefStreamout:
- case BuiltinType::OCLIntelSubgroupAVCImeResultDualRefStreamout:
- case BuiltinType::OCLIntelSubgroupAVCImeSingleRefStreamin:
- case BuiltinType::OCLIntelSubgroupAVCImeDualRefStreamin:
+ case clang::BuiltinType::NullPtr:
+ return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq,
+ trans_create_node_unsigned(c, 0));
+
+ case clang::BuiltinType::Void:
+ case clang::BuiltinType::Half:
+ case clang::BuiltinType::ObjCId:
+ case clang::BuiltinType::ObjCClass:
+ case clang::BuiltinType::ObjCSel:
+ case clang::BuiltinType::OMPArraySection:
+ case clang::BuiltinType::Dependent:
+ case clang::BuiltinType::Overload:
+ case clang::BuiltinType::BoundMember:
+ case clang::BuiltinType::PseudoObject:
+ case clang::BuiltinType::UnknownAny:
+ case clang::BuiltinType::BuiltinFn:
+ case clang::BuiltinType::ARCUnbridgedCast:
+ case clang::BuiltinType::OCLImage1dRO:
+ case clang::BuiltinType::OCLImage1dArrayRO:
+ case clang::BuiltinType::OCLImage1dBufferRO:
+ case clang::BuiltinType::OCLImage2dRO:
+ case clang::BuiltinType::OCLImage2dArrayRO:
+ case clang::BuiltinType::OCLImage2dDepthRO:
+ case clang::BuiltinType::OCLImage2dArrayDepthRO:
+ case clang::BuiltinType::OCLImage2dMSAARO:
+ case clang::BuiltinType::OCLImage2dArrayMSAARO:
+ case clang::BuiltinType::OCLImage2dMSAADepthRO:
+ case clang::BuiltinType::OCLImage2dArrayMSAADepthRO:
+ case clang::BuiltinType::OCLImage3dRO:
+ case clang::BuiltinType::OCLImage1dWO:
+ case clang::BuiltinType::OCLImage1dArrayWO:
+ case clang::BuiltinType::OCLImage1dBufferWO:
+ case clang::BuiltinType::OCLImage2dWO:
+ case clang::BuiltinType::OCLImage2dArrayWO:
+ case clang::BuiltinType::OCLImage2dDepthWO:
+ case clang::BuiltinType::OCLImage2dArrayDepthWO:
+ case clang::BuiltinType::OCLImage2dMSAAWO:
+ case clang::BuiltinType::OCLImage2dArrayMSAAWO:
+ case clang::BuiltinType::OCLImage2dMSAADepthWO:
+ case clang::BuiltinType::OCLImage2dArrayMSAADepthWO:
+ case clang::BuiltinType::OCLImage3dWO:
+ case clang::BuiltinType::OCLImage1dRW:
+ case clang::BuiltinType::OCLImage1dArrayRW:
+ case clang::BuiltinType::OCLImage1dBufferRW:
+ case clang::BuiltinType::OCLImage2dRW:
+ case clang::BuiltinType::OCLImage2dArrayRW:
+ case clang::BuiltinType::OCLImage2dDepthRW:
+ case clang::BuiltinType::OCLImage2dArrayDepthRW:
+ case clang::BuiltinType::OCLImage2dMSAARW:
+ case clang::BuiltinType::OCLImage2dArrayMSAARW:
+ case clang::BuiltinType::OCLImage2dMSAADepthRW:
+ case clang::BuiltinType::OCLImage2dArrayMSAADepthRW:
+ case clang::BuiltinType::OCLImage3dRW:
+ case clang::BuiltinType::OCLSampler:
+ case clang::BuiltinType::OCLEvent:
+ case clang::BuiltinType::OCLClkEvent:
+ case clang::BuiltinType::OCLQueue:
+ case clang::BuiltinType::OCLReserveID:
+ case clang::BuiltinType::ShortAccum:
+ case clang::BuiltinType::Accum:
+ case clang::BuiltinType::LongAccum:
+ case clang::BuiltinType::UShortAccum:
+ case clang::BuiltinType::UAccum:
+ case clang::BuiltinType::ULongAccum:
+ case clang::BuiltinType::ShortFract:
+ case clang::BuiltinType::Fract:
+ case clang::BuiltinType::LongFract:
+ case clang::BuiltinType::UShortFract:
+ case clang::BuiltinType::UFract:
+ case clang::BuiltinType::ULongFract:
+ case clang::BuiltinType::SatShortAccum:
+ case clang::BuiltinType::SatAccum:
+ case clang::BuiltinType::SatLongAccum:
+ case clang::BuiltinType::SatUShortAccum:
+ case clang::BuiltinType::SatUAccum:
+ case clang::BuiltinType::SatULongAccum:
+ case clang::BuiltinType::SatShortFract:
+ case clang::BuiltinType::SatFract:
+ case clang::BuiltinType::SatLongFract:
+ case clang::BuiltinType::SatUShortFract:
+ case clang::BuiltinType::SatUFract:
+ case clang::BuiltinType::SatULongFract:
+ case clang::BuiltinType::OCLIntelSubgroupAVCMcePayload:
+ case clang::BuiltinType::OCLIntelSubgroupAVCImePayload:
+ case clang::BuiltinType::OCLIntelSubgroupAVCRefPayload:
+ case clang::BuiltinType::OCLIntelSubgroupAVCSicPayload:
+ case clang::BuiltinType::OCLIntelSubgroupAVCMceResult:
+ case clang::BuiltinType::OCLIntelSubgroupAVCImeResult:
+ case clang::BuiltinType::OCLIntelSubgroupAVCRefResult:
+ case clang::BuiltinType::OCLIntelSubgroupAVCSicResult:
+ case clang::BuiltinType::OCLIntelSubgroupAVCImeResultSingleRefStreamout:
+ case clang::BuiltinType::OCLIntelSubgroupAVCImeResultDualRefStreamout:
+ case clang::BuiltinType::OCLIntelSubgroupAVCImeSingleRefStreamin:
+ case clang::BuiltinType::OCLIntelSubgroupAVCImeDualRefStreamin:
return res;
}
break;
}
- case Type::Pointer:
- return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node(c, NodeTypeNullLiteral));
+ case clang::Type::Pointer:
+ return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq,
+ trans_create_node_unsigned(c, 0));
- case Type::Typedef:
+ case clang::Type::Typedef:
{
- const TypedefType *typedef_ty = static_cast<const TypedefType*>(ty);
- const TypedefNameDecl *typedef_decl = typedef_ty->getDecl();
+ const clang::TypedefType *typedef_ty = static_cast<const clang::TypedefType*>(ty);
+ const clang::TypedefNameDecl *typedef_decl = typedef_ty->getDecl();
auto existing_entry = c->decl_table.maybe_get((void*)typedef_decl->getCanonicalDecl());
if (existing_entry) {
return existing_entry->value;
@@ -2566,79 +2269,79 @@ static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *
return res;
}
- case Type::Enum:
+ case clang::Type::Enum:
{
- const EnumType *enum_ty = static_cast<const EnumType*>(ty);
+ const clang::EnumType *enum_ty = static_cast<const clang::EnumType*>(ty);
AstNode *enum_type = resolve_enum_decl(c, enum_ty->getDecl());
return to_enum_zero_cmp(c, res, enum_type);
}
- case Type::Elaborated:
+ case clang::Type::Elaborated:
{
- const ElaboratedType *elaborated_ty = static_cast<const ElaboratedType*>(ty);
+ const clang::ElaboratedType *elaborated_ty = static_cast<const clang::ElaboratedType*>(ty);
switch (elaborated_ty->getKeyword()) {
- case ETK_Enum: {
- AstNode *enum_type = trans_qual_type(c, elaborated_ty->getNamedType(), expr->getBeginLoc());
+ case clang::ETK_Enum: {
+ AstNode *enum_type = trans_qual_type(c, elaborated_ty->getNamedType(), expr->getBeginloc());
return to_enum_zero_cmp(c, res, enum_type);
}
- case ETK_Struct:
- case ETK_Union:
- case ETK_Interface:
- case ETK_Class:
- case ETK_Typename:
- case ETK_None:
+ case clang::ETK_Struct:
+ case clang::ETK_Union:
+ case clang::ETK_Interface:
+ case clang::ETK_Class:
+ case clang::ETK_Typename:
+ case clang::ETK_None:
return res;
}
}
- case Type::FunctionProto:
- case Type::Record:
- case Type::ConstantArray:
- case Type::Paren:
- case Type::Decayed:
- case Type::Attributed:
- case Type::IncompleteArray:
- case Type::BlockPointer:
- case Type::LValueReference:
- case Type::RValueReference:
- case Type::MemberPointer:
- case Type::VariableArray:
- case Type::DependentSizedArray:
- case Type::DependentSizedExtVector:
- case Type::Vector:
- case Type::ExtVector:
- case Type::FunctionNoProto:
- case Type::UnresolvedUsing:
- case Type::Adjusted:
- case Type::TypeOfExpr:
- case Type::TypeOf:
- case Type::Decltype:
- case Type::UnaryTransform:
- case Type::TemplateTypeParm:
- case Type::SubstTemplateTypeParm:
- case Type::SubstTemplateTypeParmPack:
- case Type::TemplateSpecialization:
- case Type::Auto:
- case Type::InjectedClassName:
- case Type::DependentName:
- case Type::DependentTemplateSpecialization:
- case Type::PackExpansion:
- case Type::ObjCObject:
- case Type::ObjCInterface:
- case Type::Complex:
- case Type::ObjCObjectPointer:
- case Type::Atomic:
- case Type::Pipe:
- case Type::ObjCTypeParam:
- case Type::DeducedTemplateSpecialization:
- case Type::DependentAddressSpace:
- case Type::DependentVector:
+ case clang::Type::FunctionProto:
+ case clang::Type::Record:
+ case clang::Type::ConstantArray:
+ case clang::Type::Paren:
+ case clang::Type::Decayed:
+ case clang::Type::Attributed:
+ case clang::Type::IncompleteArray:
+ case clang::Type::BlockPointer:
+ case clang::Type::LValueReference:
+ case clang::Type::RValueReference:
+ case clang::Type::MemberPointer:
+ case clang::Type::VariableArray:
+ case clang::Type::DependentSizedArray:
+ case clang::Type::DependentSizedExtVector:
+ case clang::Type::Vector:
+ case clang::Type::ExtVector:
+ case clang::Type::FunctionNoProto:
+ case clang::Type::UnresolvedUsing:
+ case clang::Type::Adjusted:
+ case clang::Type::TypeOfExpr:
+ case clang::Type::TypeOf:
+ case clang::Type::Decltype:
+ case clang::Type::UnaryTransform:
+ case clang::Type::TemplateTypeParm:
+ case clang::Type::SubstTemplateTypeParm:
+ case clang::Type::SubstTemplateTypeParmPack:
+ case clang::Type::TemplateSpecialization:
+ case clang::Type::Auto:
+ case clang::Type::InjectedClassName:
+ case clang::Type::DependentName:
+ case clang::Type::DependentTemplateSpecialization:
+ case clang::Type::PackExpansion:
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface:
+ case clang::Type::Complex:
+ case clang::Type::ObjCObjectPointer:
+ case clang::Type::Atomic:
+ case clang::Type::Pipe:
+ case clang::Type::ObjCTypeParam:
+ case clang::Type::DeducedTemplateSpecialization:
+ case clang::Type::DependentAddressSpace:
+ case clang::Type::DependentVector:
return res;
}
zig_unreachable();
}
-static AstNode *trans_while_loop(Context *c, TransScope *scope, const WhileStmt *stmt) {
+static AstNode *trans_while_loop(Context *c, TransScope *scope, const clang::WhileStmt *stmt) {
TransScopeWhile *while_scope = trans_scope_while_create(c, scope);
while_scope->node->data.while_expr.condition = trans_bool_expr(c, ResultUsedYes, scope, stmt->getCond(), TransRValue);
@@ -2653,7 +2356,7 @@ static AstNode *trans_while_loop(Context *c, TransScope *scope, const WhileStmt
return while_scope->node;
}
-static AstNode *trans_if_statement(Context *c, TransScope *scope, const IfStmt *stmt) {
+static AstNode *trans_if_statement(Context *c, TransScope *scope, const clang::IfStmt *stmt) {
// if (c) t
// if (c) t else e
AstNode *if_node = trans_create_node(c, NodeTypeIfBoolExpr);
@@ -2675,7 +2378,7 @@ static AstNode *trans_if_statement(Context *c, TransScope *scope, const IfStmt *
return if_node;
}
-static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope *scope, const CallExpr *stmt) {
+static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope *scope, const clang::CallExpr *stmt) {
AstNode *node = trans_create_node(c, NodeTypeFnCallExpr);
AstNode *callee_raw_node = trans_expr(c, ResultUsedYes, scope, stmt->getCallee(), TransRValue);
@@ -2683,16 +2386,16 @@ static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope *
return nullptr;
bool is_ptr = false;
- const FunctionProtoType *fn_ty = qual_type_get_fn_proto(stmt->getCallee()->getType(), &is_ptr);
+ const clang::FunctionProtoType *fn_ty = qual_type_get_fn_proto(stmt->getCallee()->getType(), &is_ptr);
AstNode *callee_node = nullptr;
if (is_ptr && fn_ty) {
- if (stmt->getCallee()->getStmtClass() == Stmt::ImplicitCastExprClass) {
- const ImplicitCastExpr *implicit_cast = static_cast<const ImplicitCastExpr *>(stmt->getCallee());
- if (implicit_cast->getCastKind() == CK_FunctionToPointerDecay) {
- if (implicit_cast->getSubExpr()->getStmtClass() == Stmt::DeclRefExprClass) {
- const DeclRefExpr *decl_ref = static_cast<const DeclRefExpr *>(implicit_cast->getSubExpr());
- const Decl *decl = decl_ref->getFoundDecl();
- if (decl->getKind() == Decl::Function) {
+ if (stmt->getCallee()->getStmtClass() == clang::Stmt::ImplicitCastExprClass) {
+ const clang::ImplicitCastExpr *implicit_cast = static_cast<const clang::ImplicitCastExpr *>(stmt->getCallee());
+ if (implicit_cast->getCastKind() == clang::CK_FunctionToPointerDecay) {
+ if (implicit_cast->getSubExpr()->getStmtClass() == clang::Stmt::DeclRefExprClass) {
+ const clang::DeclRefExpr *decl_ref = static_cast<const clang::DeclRefExpr *>(implicit_cast->getSubExpr());
+ const clang::Decl *decl = decl_ref->getFoundDecl();
+ if (decl->getKind() == clang::Decl::Function) {
callee_node = callee_raw_node;
}
}
@@ -2708,7 +2411,7 @@ static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope *
node->data.fn_call_expr.fn_ref_expr = callee_node;
unsigned num_args = stmt->getNumArgs();
- const Expr * const* args = stmt->getArgs();
+ const clang::Expr * const* args = stmt->getArgs();
for (unsigned i = 0; i < num_args; i += 1) {
AstNode *arg_node = trans_expr(c, ResultUsedYes, scope, args[i], TransRValue);
if (arg_node == nullptr)
@@ -2724,7 +2427,7 @@ static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope *
return node;
}
-static AstNode *trans_member_expr(Context *c, TransScope *scope, const MemberExpr *stmt) {
+static AstNode *trans_member_expr(Context *c, TransScope *scope, const clang::MemberExpr *stmt) {
AstNode *container_node = trans_expr(c, ResultUsedYes, scope, stmt->getBase(), TransRValue);
if (container_node == nullptr)
return nullptr;
@@ -2739,7 +2442,7 @@ static AstNode *trans_member_expr(Context *c, TransScope *scope, const MemberExp
return node;
}
-static AstNode *trans_array_subscript_expr(Context *c, TransScope *scope, const ArraySubscriptExpr *stmt) {
+static AstNode *trans_array_subscript_expr(Context *c, TransScope *scope, const clang::ArraySubscriptExpr *stmt) {
AstNode *container_node = trans_expr(c, ResultUsedYes, scope, stmt->getBase(), TransRValue);
if (container_node == nullptr)
return nullptr;
@@ -2756,7 +2459,7 @@ static AstNode *trans_array_subscript_expr(Context *c, TransScope *scope, const
}
static AstNode *trans_c_style_cast_expr(Context *c, ResultUsed result_used, TransScope *scope,
- const CStyleCastExpr *stmt, TransLRValue lrvalue)
+ const clang::CStyleCastExpr *stmt, TransLRValue lrvalue)
{
AstNode *sub_expr_node = trans_expr(c, result_used, scope, stmt->getSubExpr(), lrvalue);
if (sub_expr_node == nullptr)
@@ -2766,7 +2469,7 @@ static AstNode *trans_c_style_cast_expr(Context *c, ResultUsed result_used, Tran
}
static AstNode *trans_unary_expr_or_type_trait_expr(Context *c, TransScope *scope,
- const UnaryExprOrTypeTraitExpr *stmt)
+ const clang::UnaryExprOrTypeTraitExpr *stmt)
{
AstNode *type_node = trans_qual_type(c, stmt->getTypeOfArgument(), stmt->getBeginLoc());
if (type_node == nullptr)
@@ -2777,14 +2480,14 @@ static AstNode *trans_unary_expr_or_type_trait_expr(Context *c, TransScope *scop
return node;
}
-static AstNode *trans_do_loop(Context *c, TransScope *parent_scope, const DoStmt *stmt) {
+static AstNode *trans_do_loop(Context *c, TransScope *parent_scope, const clang::DoStmt *stmt) {
TransScopeWhile *while_scope = trans_scope_while_create(c, parent_scope);
while_scope->node->data.while_expr.condition = trans_create_node_bool(c, true);
AstNode *body_node;
TransScope *child_scope;
- if (stmt->getBody()->getStmtClass() == Stmt::CompoundStmtClass) {
+ if (stmt->getBody()->getStmtClass() == clang::Stmt::CompoundStmtClass) {
// there's already a block in C, so we'll append our condition to it.
// c: do {
// c: a;
@@ -2837,11 +2540,11 @@ static AstNode *trans_do_loop(Context *c, TransScope *parent_scope, const DoStmt
return while_scope->node;
}
-static AstNode *trans_for_loop(Context *c, TransScope *parent_scope, const ForStmt *stmt) {
+static AstNode *trans_for_loop(Context *c, TransScope *parent_scope, const clang::ForStmt *stmt) {
AstNode *loop_block_node;
TransScopeWhile *while_scope;
TransScope *cond_scope;
- const Stmt *init_stmt = stmt->getInit();
+ const clang::Stmt *init_stmt = stmt->getInit();
if (init_stmt == nullptr) {
while_scope = trans_scope_while_create(c, parent_scope);
loop_block_node = while_scope->node;
@@ -2862,12 +2565,12 @@ static AstNode *trans_for_loop(Context *c, TransScope *parent_scope, const ForSt
child_scope->node->data.block.statements.append(while_scope->node);
}
- const Stmt *cond_stmt = stmt->getCond();
+ const clang::Stmt *cond_stmt = stmt->getCond();
if (cond_stmt == nullptr) {
while_scope->node->data.while_expr.condition = trans_create_node_bool(c, true);
} else {
- if (Expr::classof(cond_stmt)) {
- const Expr *cond_expr = static_cast<const Expr*>(cond_stmt);
+ if (clang::Expr::classof(cond_stmt)) {
+ const clang::Expr *cond_expr = static_cast<const clang::Expr*>(cond_stmt);
while_scope->node->data.while_expr.condition = trans_bool_expr(c, ResultUsedYes, cond_scope, cond_expr, TransRValue);
if (while_scope->node->data.while_expr.condition == nullptr)
@@ -2880,7 +2583,7 @@ static AstNode *trans_for_loop(Context *c, TransScope *parent_scope, const ForSt
}
}
- const Stmt *inc_stmt = stmt->getInc();
+ const clang::Stmt *inc_stmt = stmt->getInc();
if (inc_stmt != nullptr) {
AstNode *inc_node;
TransScope *inc_scope = trans_stmt(c, cond_scope, inc_stmt, &inc_node);
@@ -2903,12 +2606,12 @@ static AstNode *trans_for_loop(Context *c, TransScope *parent_scope, const ForSt
return loop_block_node;
}
-static AstNode *trans_switch_stmt(Context *c, TransScope *parent_scope, const SwitchStmt *stmt) {
+static AstNode *trans_switch_stmt(Context *c, TransScope *parent_scope, const clang::SwitchStmt *stmt) {
TransScopeBlock *block_scope = trans_scope_block_create(c, parent_scope);
TransScopeSwitch *switch_scope;
- const DeclStmt *var_decl_stmt = stmt->getConditionVariableDeclStmt();
+ const clang::DeclStmt *var_decl_stmt = stmt->getConditionVariableDeclStmt();
if (var_decl_stmt == nullptr) {
switch_scope = trans_scope_switch_create(c, &block_scope->base);
} else {
@@ -2927,7 +2630,7 @@ static AstNode *trans_switch_stmt(Context *c, TransScope *parent_scope, const Sw
switch_scope->end_label_name = end_label_name;
block_scope->node->data.block.name = end_label_name;
- const Expr *cond_expr = stmt->getCond();
+ const clang::Expr *cond_expr = stmt->getCond();
assert(cond_expr != nullptr);
AstNode *expr_node = trans_expr(c, ResultUsedYes, &block_scope->base, cond_expr, TransRValue);
@@ -2936,9 +2639,9 @@ static AstNode *trans_switch_stmt(Context *c, TransScope *parent_scope, const Sw
switch_scope->switch_node->data.switch_expr.expr = expr_node;
AstNode *body_node;
- const Stmt *body_stmt = stmt->getBody();
- if (body_stmt->getStmtClass() == Stmt::CompoundStmtClass) {
- if (trans_compound_stmt_inline(c, &switch_scope->base, (const CompoundStmt *)body_stmt,
+ const clang::Stmt *body_stmt = stmt->getBody();
+ if (body_stmt->getStmtClass() == clang::Stmt::CompoundStmtClass) {
+ if (trans_compound_stmt_inline(c, &switch_scope->base, (const clang::CompoundStmt *)body_stmt,
block_scope->node, nullptr))
{
return nullptr;
@@ -2970,7 +2673,7 @@ static TransScopeSwitch *trans_scope_switch_find(TransScope *scope) {
return nullptr;
}
-static int trans_switch_case(Context *c, TransScope *parent_scope, const CaseStmt *stmt, AstNode **out_node,
+static int trans_switch_case(Context *c, TransScope *parent_scope, const clang::CaseStmt *stmt, AstNode **out_node,
TransScope **out_scope) {
*out_node = nullptr;
@@ -3015,7 +2718,7 @@ static int trans_switch_case(Context *c, TransScope *parent_scope, const CaseStm
return ErrorNone;
}
-static int trans_switch_default(Context *c, TransScope *parent_scope, const DefaultStmt *stmt, AstNode **out_node,
+static int trans_switch_default(Context *c, TransScope *parent_scope, const clang::DefaultStmt *stmt, AstNode **out_node,
TransScope **out_scope)
{
*out_node = nullptr;
@@ -3052,25 +2755,27 @@ static int trans_switch_default(Context *c, TransScope *parent_scope, const Defa
return ErrorNone;
}
-static AstNode *trans_string_literal(Context *c, TransScope *scope, const StringLiteral *stmt) {
+static AstNode *trans_string_literal(Context *c, TransScope *scope, const clang::StringLiteral *stmt) {
switch (stmt->getKind()) {
- case StringLiteral::Ascii:
- case StringLiteral::UTF8:
+ case clang::StringLiteral::Ascii:
+ case clang::StringLiteral::UTF8:
return trans_create_node_str_lit_c(c, string_ref_to_buf(stmt->getString()));
- case StringLiteral::UTF16:
+ case clang::StringLiteral::UTF16:
emit_warning(c, stmt->getBeginLoc(), "TODO support UTF16 string literals");
return nullptr;
- case StringLiteral::UTF32:
+ case clang::StringLiteral::UTF32:
emit_warning(c, stmt->getBeginLoc(), "TODO support UTF32 string literals");
+ case clang::StringLiteral::UTF32:
+ emit_warning(c, stmt->getLocStart(), "TODO support UTF32 string literals");
return nullptr;
- case StringLiteral::Wide:
+ case clang::StringLiteral::Wide:
emit_warning(c, stmt->getBeginLoc(), "TODO support wide string literals");
return nullptr;
}
zig_unreachable();
}
-static AstNode *trans_break_stmt(Context *c, TransScope *scope, const BreakStmt *stmt) {
+static AstNode *trans_break_stmt(Context *c, TransScope *scope, const clang::BreakStmt *stmt) {
TransScope *cur_scope = scope;
while (cur_scope != nullptr) {
if (cur_scope->id == TransScopeIdWhile) {
@@ -3084,7 +2789,7 @@ static AstNode *trans_break_stmt(Context *c, TransScope *scope, const BreakStmt
zig_unreachable();
}
-static AstNode *trans_continue_stmt(Context *c, TransScope *scope, const ContinueStmt *stmt) {
+static AstNode *trans_continue_stmt(Context *c, TransScope *scope, const clang::ContinueStmt *stmt) {
return trans_create_node(c, NodeTypeContinue);
}
@@ -3097,47 +2802,47 @@ static int wrap_stmt(AstNode **out_node, TransScope **out_scope, TransScope *in_
return ErrorNone;
}
-static int trans_stmt_extra(Context *c, TransScope *scope, const Stmt *stmt,
+static int trans_stmt_extra(Context *c, TransScope *scope, const clang::Stmt *stmt,
ResultUsed result_used, TransLRValue lrvalue,
AstNode **out_node, TransScope **out_child_scope,
TransScope **out_node_scope)
{
- Stmt::StmtClass sc = stmt->getStmtClass();
+ clang::Stmt::StmtClass sc = stmt->getStmtClass();
switch (sc) {
- case Stmt::ReturnStmtClass:
+ case clang::Stmt::ReturnStmtClass:
return wrap_stmt(out_node, out_child_scope, scope,
- trans_return_stmt(c, scope, (const ReturnStmt *)stmt));
- case Stmt::CompoundStmtClass:
+ trans_return_stmt(c, scope, (const clang::ReturnStmt *)stmt));
+ case clang::Stmt::CompoundStmtClass:
return wrap_stmt(out_node, out_child_scope, scope,
- trans_compound_stmt(c, scope, (const CompoundStmt *)stmt, out_node_scope));
- case Stmt::IntegerLiteralClass:
+ trans_compound_stmt(c, scope, (const clang::CompoundStmt *)stmt, out_node_scope));
+ case clang::Stmt::IntegerLiteralClass:
return wrap_stmt(out_node, out_child_scope, scope,
- trans_integer_literal(c, (const IntegerLiteral *)stmt));
- case Stmt::ConditionalOperatorClass:
+ trans_integer_literal(c, (const clang::IntegerLiteral *)stmt));
+ case clang::Stmt::ConditionalOperatorClass:
return wrap_stmt(out_node, out_child_scope, scope,
- trans_conditional_operator(c, result_used, scope, (const ConditionalOperator *)stmt));
- case Stmt::BinaryOperatorClass:
+ trans_conditional_operator(c, result_used, scope, (const clang::ConditionalOperator *)stmt));
+ case clang::Stmt::BinaryOperatorClass:
return wrap_stmt(out_node, out_child_scope, scope,
- trans_binary_operator(c, result_used, scope, (const BinaryOperator *)stmt));
- case Stmt::CompoundAssignOperatorClass:
+ trans_binary_operator(c, result_used, scope, (const clang::BinaryOperator *)stmt));
+ case clang::Stmt::CompoundAssignOperatorClass:
return wrap_stmt(out_node, out_child_scope, scope,
- trans_compound_assign_operator(c, result_used, scope, (const CompoundAssignOperator *)stmt));
- case Stmt::ImplicitCastExprClass:
+ trans_compound_assign_operator(c, result_used, scope, (const clang::CompoundAssignOperator *)stmt));
+ case clang::Stmt::ImplicitCastExprClass:
return wrap_stmt(out_node, out_child_scope, scope,
- trans_implicit_cast_expr(c, scope, (const ImplicitCastExpr *)stmt));
- case Stmt::DeclRefExprClass:
+ trans_implicit_cast_expr(c, scope, (const clang::ImplicitCastExpr *)stmt));
+ case clang::Stmt::DeclRefExprClass:
return wrap_stmt(out_node, out_child_scope, scope,
- trans_decl_ref_expr(c, scope, (const DeclRefExpr *)stmt, lrvalue));
- case Stmt::UnaryOperatorClass:
+ trans_decl_ref_expr(c, scope, (const clang::DeclRefExpr *)stmt, lrvalue));
+ case clang::Stmt::UnaryOperatorClass:
return wrap_stmt(out_node, out_child_scope, scope,
- trans_unary_operator(c, result_used, scope, (const UnaryOperator *)stmt));
- case Stmt::DeclStmtClass:
- return trans_local_declaration(c, scope, (const DeclStmt *)stmt, out_node, out_child_scope);
- case Stmt::DoStmtClass:
- case Stmt::WhileStmtClass: {
- AstNode *while_node = sc == Stmt::DoStmtClass
- ? trans_do_loop(c, scope, (const DoStmt *)stmt)
- : trans_while_loop(c, scope, (const WhileStmt *)stmt);
+ trans_unary_operator(c, result_used, scope, (const clang::UnaryOperator *)stmt));
+ case clang::Stmt::DeclStmtClass:
+ return trans_local_declaration(c, scope, (const clang::DeclStmt *)stmt, out_node, out_child_scope);
+ case clang::Stmt::DoStmtClass:
+ case clang::Stmt::WhileStmtClass: {
+ AstNode *while_node = sc == clang::Stmt::DoStmtClass
+ ? trans_do_loop(c, scope, (const clang::DoStmt *)stmt)
+ : trans_while_loop(c, scope, (const clang::WhileStmt *)stmt);
if (while_node == nullptr)
return ErrorUnexpected;
@@ -3148,567 +2853,63 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const Stmt *stmt,
return wrap_stmt(out_node, out_child_scope, scope, while_node);
}
- case Stmt::IfStmtClass:
+ case clang::Stmt::IfStmtClass:
return wrap_stmt(out_node, out_child_scope, scope,
- trans_if_statement(c, scope, (const IfStmt *)stmt));
- case Stmt::CallExprClass:
+ trans_if_statement(c, scope, (const clang::IfStmt *)stmt));
+ case clang::Stmt::CallExprClass:
return wrap_stmt(out_node, out_child_scope, scope,
- trans_call_expr(c, result_used, scope, (const CallExpr *)stmt));
- case Stmt::NullStmtClass:
+ trans_call_expr(c, result_used, scope, (const clang::CallExpr *)stmt));
+ case clang::Stmt::NullStmtClass:
*out_node = nullptr;
*out_child_scope = scope;
return ErrorNone;
- case Stmt::MemberExprClass:
+ case clang::Stmt::MemberExprClass:
return wrap_stmt(out_node, out_child_scope, scope,
- trans_member_expr(c, scope, (const MemberExpr *)stmt));
- case Stmt::ArraySubscriptExprClass:
+ trans_member_expr(c, scope, (const clang::MemberExpr *)stmt));
+ case clang::Stmt::ArraySubscriptExprClass:
return wrap_stmt(out_node, out_child_scope, scope,
- trans_array_subscript_expr(c, scope, (const ArraySubscriptExpr *)stmt));
- case Stmt::CStyleCastExprClass:
+ trans_array_subscript_expr(c, scope, (const clang::ArraySubscriptExpr *)stmt));
+ case clang::Stmt::CStyleCastExprClass:
return wrap_stmt(out_node, out_child_scope, scope,
- trans_c_style_cast_expr(c, result_used, scope, (const CStyleCastExpr *)stmt, lrvalue));
- case Stmt::UnaryExprOrTypeTraitExprClass:
+ trans_c_style_cast_expr(c, result_used, scope, (const clang::CStyleCastExpr *)stmt, lrvalue));
+ case clang::Stmt::UnaryExprOrTypeTraitExprClass:
return wrap_stmt(out_node, out_child_scope, scope,
- trans_unary_expr_or_type_trait_expr(c, scope, (const UnaryExprOrTypeTraitExpr *)stmt));
- case Stmt::ForStmtClass: {
- AstNode *node = trans_for_loop(c, scope, (const ForStmt *)stmt);
+ trans_unary_expr_or_type_trait_expr(c, scope, (const clang::UnaryExprOrTypeTraitExpr *)stmt));
+ case clang::Stmt::ForStmtClass: {
+ AstNode *node = trans_for_loop(c, scope, (const clang::ForStmt *)stmt);
return wrap_stmt(out_node, out_child_scope, scope, node);
}
- case Stmt::StringLiteralClass:
+ case clang::Stmt::StringLiteralClass:
return wrap_stmt(out_node, out_child_scope, scope,
- trans_string_literal(c, scope, (const StringLiteral *)stmt));
- case Stmt::BreakStmtClass:
+ trans_string_literal(c, scope, (const clang::StringLiteral *)stmt));
+ case clang::Stmt::BreakStmtClass:
return wrap_stmt(out_node, out_child_scope, scope,
- trans_break_stmt(c, scope, (const BreakStmt *)stmt));
- case Stmt::ContinueStmtClass:
+ trans_break_stmt(c, scope, (const clang::BreakStmt *)stmt));
+ case clang::Stmt::ContinueStmtClass:
return wrap_stmt(out_node, out_child_scope, scope,
- trans_continue_stmt(c, scope, (const ContinueStmt *)stmt));
- case Stmt::ParenExprClass:
+ trans_continue_stmt(c, scope, (const clang::ContinueStmt *)stmt));
+ case clang::Stmt::ParenExprClass:
return wrap_stmt(out_node, out_child_scope, scope,
- trans_expr(c, result_used, scope, ((const ParenExpr*)stmt)->getSubExpr(), lrvalue));
- case Stmt::SwitchStmtClass:
+ trans_expr(c, result_used, scope, ((const clang::ParenExpr*)stmt)->getSubExpr(), lrvalue));
+ case clang::Stmt::SwitchStmtClass:
return wrap_stmt(out_node, out_child_scope, scope,
- trans_switch_stmt(c, scope, (const SwitchStmt *)stmt));
- case Stmt::CaseStmtClass:
- return trans_switch_case(c, scope, (const CaseStmt *)stmt, out_node, out_child_scope);
- case Stmt::DefaultStmtClass:
- return trans_switch_default(c, scope, (const DefaultStmt *)stmt, out_node, out_child_scope);
- case Stmt::ConstantExprClass:
+ trans_switch_stmt(c, scope, (const clang::SwitchStmt *)stmt));
+ case clang::Stmt::CaseStmtClass:
+ return trans_switch_case(c, scope, (const clang::CaseStmt *)stmt, out_node, out_child_scope);
+ case clang::Stmt::DefaultStmtClass:
+ return trans_switch_default(c, scope, (const clang::DefaultStmt *)stmt, out_node, out_child_scope);
+ case clang::Stmt::ConstantExprClass:
return wrap_stmt(out_node, out_child_scope, scope,
- trans_constant_expr(c, (const ConstantExpr *)stmt));
- case Stmt::NoStmtClass:
+ trans_constant_expr(c, (const clang::ConstantExpr *)stmt));
+ case clang::Stmt::NoStmtClass:
emit_warning(c, stmt->getBeginLoc(), "TODO handle C NoStmtClass");
return ErrorUnexpected;
- case Stmt::GCCAsmStmtClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C GCCAsmStmtClass");
- return ErrorUnexpected;
- case Stmt::MSAsmStmtClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C MSAsmStmtClass");
- return ErrorUnexpected;
- case Stmt::AttributedStmtClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C AttributedStmtClass");
- return ErrorUnexpected;
- case Stmt::CXXCatchStmtClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXCatchStmtClass");
- return ErrorUnexpected;
- case Stmt::CXXForRangeStmtClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXForRangeStmtClass");
- return ErrorUnexpected;
- case Stmt::CXXTryStmtClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXTryStmtClass");
- return ErrorUnexpected;
- case Stmt::CapturedStmtClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CapturedStmtClass");
- return ErrorUnexpected;
- case Stmt::CoreturnStmtClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CoreturnStmtClass");
- return ErrorUnexpected;
- case Stmt::CoroutineBodyStmtClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CoroutineBodyStmtClass");
- return ErrorUnexpected;
- case Stmt::BinaryConditionalOperatorClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C BinaryConditionalOperatorClass");
- return ErrorUnexpected;
- case Stmt::AddrLabelExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C AddrLabelExprClass");
- return ErrorUnexpected;
- case Stmt::ArrayInitIndexExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ArrayInitIndexExprClass");
- return ErrorUnexpected;
- case Stmt::ArrayInitLoopExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ArrayInitLoopExprClass");
- return ErrorUnexpected;
- case Stmt::ArrayTypeTraitExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ArrayTypeTraitExprClass");
- return ErrorUnexpected;
- case Stmt::AsTypeExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C AsTypeExprClass");
- return ErrorUnexpected;
- case Stmt::AtomicExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C AtomicExprClass");
- return ErrorUnexpected;
- case Stmt::BlockExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C BlockExprClass");
- return ErrorUnexpected;
- case Stmt::CXXBindTemporaryExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXBindTemporaryExprClass");
- return ErrorUnexpected;
- case Stmt::CXXBoolLiteralExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXBoolLiteralExprClass");
- return ErrorUnexpected;
- case Stmt::CXXConstructExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXConstructExprClass");
- return ErrorUnexpected;
- case Stmt::CXXTemporaryObjectExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXTemporaryObjectExprClass");
- return ErrorUnexpected;
- case Stmt::CXXDefaultArgExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXDefaultArgExprClass");
- return ErrorUnexpected;
- case Stmt::CXXDefaultInitExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXDefaultInitExprClass");
- return ErrorUnexpected;
- case Stmt::CXXDeleteExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXDeleteExprClass");
- return ErrorUnexpected;
- case Stmt::CXXDependentScopeMemberExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXDependentScopeMemberExprClass");
- return ErrorUnexpected;
- case Stmt::CXXFoldExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXFoldExprClass");
- return ErrorUnexpected;
- case Stmt::CXXInheritedCtorInitExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXInheritedCtorInitExprClass");
- return ErrorUnexpected;
- case Stmt::CXXNewExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXNewExprClass");
- return ErrorUnexpected;
- case Stmt::CXXNoexceptExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXNoexceptExprClass");
- return ErrorUnexpected;
- case Stmt::CXXNullPtrLiteralExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXNullPtrLiteralExprClass");
- return ErrorUnexpected;
- case Stmt::CXXPseudoDestructorExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXPseudoDestructorExprClass");
- return ErrorUnexpected;
- case Stmt::CXXScalarValueInitExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXScalarValueInitExprClass");
- return ErrorUnexpected;
- case Stmt::CXXStdInitializerListExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXStdInitializerListExprClass");
- return ErrorUnexpected;
- case Stmt::CXXThisExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXThisExprClass");
- return ErrorUnexpected;
- case Stmt::CXXThrowExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXThrowExprClass");
- return ErrorUnexpected;
- case Stmt::CXXTypeidExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXTypeidExprClass");
- return ErrorUnexpected;
- case Stmt::CXXUnresolvedConstructExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXUnresolvedConstructExprClass");
- return ErrorUnexpected;
- case Stmt::CXXUuidofExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXUuidofExprClass");
- return ErrorUnexpected;
- case Stmt::CUDAKernelCallExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CUDAKernelCallExprClass");
- return ErrorUnexpected;
- case Stmt::CXXMemberCallExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXMemberCallExprClass");
- return ErrorUnexpected;
- case Stmt::CXXOperatorCallExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXOperatorCallExprClass");
- return ErrorUnexpected;
- case Stmt::UserDefinedLiteralClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C UserDefinedLiteralClass");
- return ErrorUnexpected;
- case Stmt::CXXFunctionalCastExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXFunctionalCastExprClass");
- return ErrorUnexpected;
- case Stmt::CXXConstCastExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXConstCastExprClass");
- return ErrorUnexpected;
- case Stmt::CXXDynamicCastExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXDynamicCastExprClass");
- return ErrorUnexpected;
- case Stmt::CXXReinterpretCastExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXReinterpretCastExprClass");
- return ErrorUnexpected;
- case Stmt::CXXStaticCastExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CXXStaticCastExprClass");
- return ErrorUnexpected;
- case Stmt::ObjCBridgedCastExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCBridgedCastExprClass");
- return ErrorUnexpected;
- case Stmt::CharacterLiteralClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CharacterLiteralClass");
- return ErrorUnexpected;
- case Stmt::ChooseExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ChooseExprClass");
- return ErrorUnexpected;
- case Stmt::CompoundLiteralExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CompoundLiteralExprClass");
- return ErrorUnexpected;
- case Stmt::ConvertVectorExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ConvertVectorExprClass");
- return ErrorUnexpected;
- case Stmt::CoawaitExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CoawaitExprClass");
- return ErrorUnexpected;
- case Stmt::CoyieldExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C CoyieldExprClass");
- return ErrorUnexpected;
- case Stmt::DependentCoawaitExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C DependentCoawaitExprClass");
- return ErrorUnexpected;
- case Stmt::DependentScopeDeclRefExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C DependentScopeDeclRefExprClass");
- return ErrorUnexpected;
- case Stmt::DesignatedInitExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C DesignatedInitExprClass");
- return ErrorUnexpected;
- case Stmt::DesignatedInitUpdateExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C DesignatedInitUpdateExprClass");
- return ErrorUnexpected;
- case Stmt::ExprWithCleanupsClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ExprWithCleanupsClass");
- return ErrorUnexpected;
- case Stmt::ExpressionTraitExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ExpressionTraitExprClass");
- return ErrorUnexpected;
- case Stmt::ExtVectorElementExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ExtVectorElementExprClass");
- return ErrorUnexpected;
- case Stmt::FloatingLiteralClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C FloatingLiteralClass");
- return ErrorUnexpected;
- case Stmt::FunctionParmPackExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C FunctionParmPackExprClass");
- return ErrorUnexpected;
- case Stmt::GNUNullExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C GNUNullExprClass");
- return ErrorUnexpected;
- case Stmt::GenericSelectionExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C GenericSelectionExprClass");
- return ErrorUnexpected;
- case Stmt::ImaginaryLiteralClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ImaginaryLiteralClass");
- return ErrorUnexpected;
- case Stmt::ImplicitValueInitExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ImplicitValueInitExprClass");
- return ErrorUnexpected;
- case Stmt::InitListExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C InitListExprClass");
- return ErrorUnexpected;
- case Stmt::LambdaExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C LambdaExprClass");
- return ErrorUnexpected;
- case Stmt::MSPropertyRefExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C MSPropertyRefExprClass");
- return ErrorUnexpected;
- case Stmt::MSPropertySubscriptExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C MSPropertySubscriptExprClass");
- return ErrorUnexpected;
- case Stmt::MaterializeTemporaryExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C MaterializeTemporaryExprClass");
- return ErrorUnexpected;
- case Stmt::NoInitExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C NoInitExprClass");
- return ErrorUnexpected;
- case Stmt::OMPArraySectionExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPArraySectionExprClass");
- return ErrorUnexpected;
- case Stmt::ObjCArrayLiteralClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCArrayLiteralClass");
- return ErrorUnexpected;
- case Stmt::ObjCAvailabilityCheckExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCAvailabilityCheckExprClass");
- return ErrorUnexpected;
- case Stmt::ObjCBoolLiteralExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCBoolLiteralExprClass");
- return ErrorUnexpected;
- case Stmt::ObjCBoxedExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCBoxedExprClass");
- return ErrorUnexpected;
- case Stmt::ObjCDictionaryLiteralClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCDictionaryLiteralClass");
- return ErrorUnexpected;
- case Stmt::ObjCEncodeExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCEncodeExprClass");
- return ErrorUnexpected;
- case Stmt::ObjCIndirectCopyRestoreExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCIndirectCopyRestoreExprClass");
- return ErrorUnexpected;
- case Stmt::ObjCIsaExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCIsaExprClass");
- return ErrorUnexpected;
- case Stmt::ObjCIvarRefExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCIvarRefExprClass");
- return ErrorUnexpected;
- case Stmt::ObjCMessageExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCMessageExprClass");
- return ErrorUnexpected;
- case Stmt::ObjCPropertyRefExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCPropertyRefExprClass");
- return ErrorUnexpected;
- case Stmt::ObjCProtocolExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCProtocolExprClass");
- return ErrorUnexpected;
- case Stmt::ObjCSelectorExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCSelectorExprClass");
- return ErrorUnexpected;
- case Stmt::ObjCStringLiteralClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCStringLiteralClass");
- return ErrorUnexpected;
- case Stmt::ObjCSubscriptRefExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCSubscriptRefExprClass");
- return ErrorUnexpected;
- case Stmt::OffsetOfExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OffsetOfExprClass");
- return ErrorUnexpected;
- case Stmt::OpaqueValueExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OpaqueValueExprClass");
- return ErrorUnexpected;
- case Stmt::UnresolvedLookupExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C UnresolvedLookupExprClass");
- return ErrorUnexpected;
- case Stmt::UnresolvedMemberExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C UnresolvedMemberExprClass");
- return ErrorUnexpected;
- case Stmt::PackExpansionExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C PackExpansionExprClass");
- return ErrorUnexpected;
- case Stmt::ParenListExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ParenListExprClass");
- return ErrorUnexpected;
- case Stmt::PredefinedExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C PredefinedExprClass");
- return ErrorUnexpected;
- case Stmt::PseudoObjectExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C PseudoObjectExprClass");
- return ErrorUnexpected;
- case Stmt::ShuffleVectorExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ShuffleVectorExprClass");
- return ErrorUnexpected;
- case Stmt::SizeOfPackExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C SizeOfPackExprClass");
- return ErrorUnexpected;
- case Stmt::StmtExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C StmtExprClass");
- return ErrorUnexpected;
- case Stmt::SubstNonTypeTemplateParmExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C SubstNonTypeTemplateParmExprClass");
- return ErrorUnexpected;
- case Stmt::SubstNonTypeTemplateParmPackExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C SubstNonTypeTemplateParmPackExprClass");
- return ErrorUnexpected;
- case Stmt::TypeTraitExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C TypeTraitExprClass");
- return ErrorUnexpected;
- case Stmt::TypoExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C TypoExprClass");
- return ErrorUnexpected;
- case Stmt::VAArgExprClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C VAArgExprClass");
- return ErrorUnexpected;
- case Stmt::GotoStmtClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C GotoStmtClass");
- return ErrorUnexpected;
- case Stmt::IndirectGotoStmtClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C IndirectGotoStmtClass");
- return ErrorUnexpected;
- case Stmt::LabelStmtClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C LabelStmtClass");
- return ErrorUnexpected;
- case Stmt::MSDependentExistsStmtClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C MSDependentExistsStmtClass");
- return ErrorUnexpected;
- case Stmt::OMPAtomicDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPAtomicDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPBarrierDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPBarrierDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPCancelDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPCancelDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPCancellationPointDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPCancellationPointDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPCriticalDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPCriticalDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPFlushDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPFlushDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPDistributeDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPDistributeDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPDistributeParallelForDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPDistributeParallelForDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPDistributeParallelForSimdDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPDistributeParallelForSimdDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPDistributeSimdDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPDistributeSimdDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPForDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPForDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPForSimdDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPForSimdDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPParallelForDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPParallelForDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPParallelForSimdDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPParallelForSimdDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPSimdDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPSimdDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPTargetParallelForSimdDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTargetParallelForSimdDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPTargetSimdDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTargetSimdDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPTargetTeamsDistributeDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTargetTeamsDistributeDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTargetTeamsDistributeParallelForDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTargetTeamsDistributeParallelForSimdDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTargetTeamsDistributeSimdDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPTaskLoopDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTaskLoopDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPTaskLoopSimdDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTaskLoopSimdDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPTeamsDistributeDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTeamsDistributeDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPTeamsDistributeParallelForDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTeamsDistributeParallelForDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTeamsDistributeParallelForSimdDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPTeamsDistributeSimdDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTeamsDistributeSimdDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPMasterDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPMasterDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPOrderedDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPOrderedDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPParallelDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPParallelDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPParallelSectionsDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPParallelSectionsDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPSectionDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPSectionDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPSectionsDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPSectionsDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPSingleDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPSingleDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPTargetDataDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTargetDataDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPTargetDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTargetDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPTargetEnterDataDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTargetEnterDataDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPTargetExitDataDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTargetExitDataDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPTargetParallelDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTargetParallelDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPTargetParallelForDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTargetParallelForDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPTargetTeamsDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTargetTeamsDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPTargetUpdateDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTargetUpdateDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPTaskDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTaskDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPTaskgroupDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTaskgroupDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPTaskwaitDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTaskwaitDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPTaskyieldDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTaskyieldDirectiveClass");
- return ErrorUnexpected;
- case Stmt::OMPTeamsDirectiveClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C OMPTeamsDirectiveClass");
- return ErrorUnexpected;
- case Stmt::ObjCAtCatchStmtClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCAtCatchStmtClass");
- return ErrorUnexpected;
- case Stmt::ObjCAtFinallyStmtClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCAtFinallyStmtClass");
- return ErrorUnexpected;
- case Stmt::ObjCAtSynchronizedStmtClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCAtSynchronizedStmtClass");
- return ErrorUnexpected;
- case Stmt::ObjCAtThrowStmtClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCAtThrowStmtClass");
- return ErrorUnexpected;
- case Stmt::ObjCAtTryStmtClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCAtTryStmtClass");
- return ErrorUnexpected;
- case Stmt::ObjCAutoreleasePoolStmtClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCAutoreleasePoolStmtClass");
- return ErrorUnexpected;
- case Stmt::ObjCForCollectionStmtClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C ObjCForCollectionStmtClass");
- return ErrorUnexpected;
- case Stmt::SEHExceptStmtClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C SEHExceptStmtClass");
- return ErrorUnexpected;
- case Stmt::SEHFinallyStmtClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C SEHFinallyStmtClass");
- return ErrorUnexpected;
- case Stmt::SEHLeaveStmtClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C SEHLeaveStmtClass");
- return ErrorUnexpected;
- case Stmt::SEHTryStmtClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C SEHTryStmtClass");
- return ErrorUnexpected;
- case Stmt::FixedPointLiteralClass:
- emit_warning(c, stmt->getBeginLoc(), "TODO handle C FixedPointLiteralClass");
- return ErrorUnexpected;
}
zig_unreachable();
}
// Returns null if there was an error
-static AstNode *trans_expr(Context *c, ResultUsed result_used, TransScope *scope, const Expr *expr,
+static AstNode *trans_expr(Context *c, ResultUsed result_used, TransScope *scope, const clang::Expr *expr,
TransLRValue lrval)
{
AstNode *result_node;
@@ -3721,7 +2922,7 @@ static AstNode *trans_expr(Context *c, ResultUsed result_used, TransScope *scope
// Statements have no result and no concept of L or R value.
// Returns child scope, or null if there was an error
-static TransScope *trans_stmt(Context *c, TransScope *scope, const Stmt *stmt, AstNode **out_node) {
+static TransScope *trans_stmt(Context *c, TransScope *scope, const clang::Stmt *stmt, AstNode **out_node) {
TransScope *child_scope;
if (trans_stmt_extra(c, scope, stmt, ResultUsedNo, TransRValue, out_node, &child_scope, nullptr)) {
return nullptr;
@@ -3729,7 +2930,7 @@ static TransScope *trans_stmt(Context *c, TransScope *scope, const Stmt *stmt, A
return child_scope;
}
-static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) {
+static void visit_fn_decl(Context *c, const clang::FunctionDecl *fn_decl) {
Buf *fn_name = buf_create_from_str(decl_name(fn_decl));
if (get_global(c, fn_name)) {
@@ -3746,13 +2947,13 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) {
proto_node->data.fn_proto.name = fn_name;
proto_node->data.fn_proto.is_extern = !fn_decl->hasBody();
- StorageClass sc = fn_decl->getStorageClass();
- if (sc == SC_None) {
+ clang::StorageClass sc = fn_decl->getStorageClass();
+ if (sc == clang::SC_None) {
proto_node->data.fn_proto.visib_mod = c->visib_mod;
proto_node->data.fn_proto.is_export = fn_decl->hasBody() ? c->want_export : false;
- } else if (sc == SC_Extern || sc == SC_Static) {
+ } else if (sc == clang::SC_Extern || sc == clang::SC_Static) {
proto_node->data.fn_proto.visib_mod = c->visib_mod;
- } else if (sc == SC_PrivateExtern) {
+ } else if (sc == clang::SC_PrivateExtern) {
emit_warning(c, fn_decl->getLocation(), "unsupported storage class: private extern");
return;
} else {
@@ -3764,7 +2965,7 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) {
for (size_t i = 0; i < proto_node->data.fn_proto.params.length; i += 1) {
AstNode *param_node = proto_node->data.fn_proto.params.at(i);
- const ParmVarDecl *param = fn_decl->getParamDecl(i);
+ const clang::ParmVarDecl *param = fn_decl->getParamDecl(i);
const char *name = decl_name(param);
Buf *proto_param_name;
@@ -3791,7 +2992,7 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) {
// actual function definition with body
c->ptr_params.clear();
- Stmt *body = fn_decl->getBody();
+ clang::Stmt *body = fn_decl->getBody();
AstNode *actual_body_node;
TransScope *result_scope = trans_stmt(c, scope, body, &actual_body_node);
if (result_scope == nullptr) {
@@ -3833,19 +3034,19 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) {
add_top_level_decl(c, fn_def_node->data.fn_def.fn_proto->data.fn_proto.name, fn_def_node);
}
-static AstNode *resolve_typdef_as_builtin(Context *c, const TypedefNameDecl *typedef_decl, const char *primitive_name) {
+static AstNode *resolve_typdef_as_builtin(Context *c, const clang::TypedefNameDecl *typedef_decl, const char *primitive_name) {
AstNode *node = trans_create_node_symbol_str(c, primitive_name);
c->decl_table.put(typedef_decl, node);
return node;
}
-static AstNode *resolve_typedef_decl(Context *c, const TypedefNameDecl *typedef_decl) {
+static AstNode *resolve_typedef_decl(Context *c, const clang::TypedefNameDecl *typedef_decl) {
auto existing_entry = c->decl_table.maybe_get((void*)typedef_decl->getCanonicalDecl());
if (existing_entry) {
return existing_entry->value;
}
- QualType child_qt = typedef_decl->getUnderlyingType();
+ clang::QualType child_qt = typedef_decl->getUnderlyingType();
Buf *type_name = buf_create_from_str(decl_name(typedef_decl));
if (buf_eql_str(type_name, "uint8_t")) {
@@ -3894,7 +3095,7 @@ static AstNode *resolve_typedef_decl(Context *c, const TypedefNameDecl *typedef_
return symbol_node;
}
-struct AstNode *demote_enum_to_opaque(Context *c, const EnumDecl *enum_decl,
+struct AstNode *demote_enum_to_opaque(Context *c, const clang::EnumDecl *enum_decl,
Buf *full_type_name, Buf *bare_name)
{
AstNode *opaque_node = trans_create_node_opaque(c);
@@ -3909,7 +3110,7 @@ struct AstNode *demote_enum_to_opaque(Context *c, const EnumDecl *enum_decl,
return symbol_node;
}
-static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) {
+static AstNode *resolve_enum_decl(Context *c, const clang::EnumDecl *enum_decl) {
auto existing_entry = c->decl_table.maybe_get((void*)enum_decl->getCanonicalDecl());
if (existing_entry) {
return existing_entry->value;
@@ -3920,7 +3121,7 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) {
Buf *bare_name = is_anonymous ? nullptr : buf_create_from_str(raw_name);
Buf *full_type_name = is_anonymous ? nullptr : buf_sprintf("enum_%s", buf_ptr(bare_name));
- const EnumDecl *enum_def = enum_decl->getDefinition();
+ const clang::EnumDecl *enum_def = enum_decl->getDefinition();
if (!enum_def) {
return demote_enum_to_opaque(c, enum_decl, full_type_name, bare_name);
}
@@ -3932,7 +3133,7 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) {
it_end = enum_def->enumerator_end();
it != it_end; ++it, field_count += 1)
{
- const EnumConstantDecl *enum_const = *it;
+ const clang::EnumConstantDecl *enum_const = *it;
if (enum_const->getInitExpr()) {
pure_enum = false;
}
@@ -3946,8 +3147,8 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) {
// TODO only emit this tag type if the enum tag type is not the default.
// I don't know what the default is, need to figure out how clang is deciding.
// it appears to at least be different across gcc/msvc
- if (!c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::UInt) &&
- !c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::Int))
+ if (!c_is_builtin_type(c, enum_decl->getIntegerType(), clang::BuiltinType::UInt) &&
+ !c_is_builtin_type(c, enum_decl->getIntegerType(), clang::BuiltinType::Int))
{
enum_node->data.container_decl.init_arg_expr = tag_int_type;
}
@@ -3957,7 +3158,7 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) {
it_end = enum_def->enumerator_end();
it != it_end; ++it, i += 1)
{
- const EnumConstantDecl *enum_const = *it;
+ const clang::EnumConstantDecl *enum_const = *it;
Buf *enum_val_name = buf_create_from_str(decl_name(enum_const));
Buf *field_name;
@@ -3998,7 +3199,7 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) {
}
}
-static AstNode *demote_struct_to_opaque(Context *c, const RecordDecl *record_decl,
+static AstNode *demote_struct_to_opaque(Context *c, const clang::RecordDecl *record_decl,
Buf *full_type_name, Buf *bare_name)
{
AstNode *opaque_node = trans_create_node_opaque(c);
@@ -4013,7 +3214,7 @@ static AstNode *demote_struct_to_opaque(Context *c, const RecordDecl *record_dec
return symbol_node;
}
-static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) {
+static AstNode *resolve_record_decl(Context *c, const clang::RecordDecl *record_decl) {
auto existing_entry = c->decl_table.maybe_get((void*)record_decl->getCanonicalDecl());
if (existing_entry) {
return existing_entry->value;
@@ -4039,7 +3240,7 @@ static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) {
Buf *full_type_name = (bare_name == nullptr) ?
nullptr : buf_sprintf("%s_%s", container_kind_name, buf_ptr(bare_name));
- RecordDecl *record_def = record_decl->getDefinition();
+ clang::RecordDecl *record_def = record_decl->getDefinition();
if (record_def == nullptr) {
return demote_struct_to_opaque(c, record_decl, full_type_name, bare_name);
}
@@ -4050,7 +3251,7 @@ static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) {
it_end = record_def->field_end();
it != it_end; ++it, field_count += 1)
{
- const FieldDecl *field_decl = *it;
+ const clang::FieldDecl *field_decl = *it;
if (field_decl->isBitField()) {
emit_warning(c, field_decl->getLocation(), "%s %s demoted to opaque type - has bitfield",
@@ -4080,7 +3281,7 @@ static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) {
it_end = record_def->field_end();
it != it_end; ++it, i += 1)
{
- const FieldDecl *field_decl = *it;
+ const clang::FieldDecl *field_decl = *it;
AstNode *field_node = trans_create_node(c, NodeTypeStructField);
field_node->data.struct_field.name = buf_create_from_str(decl_name(field_decl));
@@ -4107,13 +3308,13 @@ static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) {
}
}
-static AstNode *trans_ap_value(Context *c, APValue *ap_value, QualType qt, const SourceLocation &source_loc) {
+static AstNode *trans_ap_value(Context *c, clang::APValue *ap_value, clang::QualType qt, const clang::SourceLocation &source_loc) {
switch (ap_value->getKind()) {
- case APValue::Int:
+ case clang::APValue::Int:
return trans_create_node_apint(c, ap_value->getInt());
- case APValue::Uninitialized:
+ case clang::APValue::Uninitialized:
return trans_create_node(c, NodeTypeUndefinedLiteral);
- case APValue::Array: {
+ case clang::APValue::Array: {
emit_warning(c, source_loc, "TODO add a test case for this code");
unsigned init_count = ap_value->getArrayInitializedElts();
@@ -4121,13 +3322,16 @@ static AstNode *trans_ap_value(Context *c, APValue *ap_value, QualType qt, const
unsigned leftover_count = all_count - init_count;
AstNode *init_node = trans_create_node(c, NodeTypeContainerInitExpr);
AstNode *arr_type_node = trans_qual_type(c, qt, source_loc);
+ if (leftover_count != 0) { // We can't use the size of the final array for a partial initializer.
+ bigint_init_unsigned(arr_type_node->data.array_type.size->data.int_literal.bigint, init_count);
+ }
init_node->data.container_init_expr.type = arr_type_node;
init_node->data.container_init_expr.kind = ContainerInitKindArray;
- QualType child_qt = qt.getTypePtr()->getLocallyUnqualifiedSingleStepDesugaredType();
+ clang::QualType child_qt = qt.getTypePtr()->getAsArrayTypeUnsafe()->getElementType();
for (size_t i = 0; i < init_count; i += 1) {
- APValue &elem_ap_val = ap_value->getArrayInitializedElt(i);
+ clang::APValue &elem_ap_val = ap_value->getArrayInitializedElt(i);
AstNode *elem_node = trans_ap_value(c, &elem_ap_val, child_qt, source_loc);
if (elem_node == nullptr)
return nullptr;
@@ -4137,15 +3341,19 @@ static AstNode *trans_ap_value(Context *c, APValue *ap_value, QualType qt, const
return init_node;
}
- APValue &filler_ap_val = ap_value->getArrayFiller();
+ clang::APValue &filler_ap_val = ap_value->getArrayFiller();
AstNode *filler_node = trans_ap_value(c, &filler_ap_val, child_qt, source_loc);
if (filler_node == nullptr)
return nullptr;
+ AstNode* filler_arr_type = trans_create_node(c, NodeTypeArrayType);
+ *filler_arr_type = *arr_type_node;
+ filler_arr_type->data.array_type.size = trans_create_node_unsigned(c, 1);
+
AstNode *filler_arr_1 = trans_create_node(c, NodeTypeContainerInitExpr);
- init_node->data.container_init_expr.type = arr_type_node;
- init_node->data.container_init_expr.kind = ContainerInitKindArray;
- init_node->data.container_init_expr.entries.append(filler_node);
+ filler_arr_1->data.container_init_expr.type = filler_arr_type;
+ filler_arr_1->data.container_init_expr.kind = ContainerInitKindArray;
+ filler_arr_1->data.container_init_expr.entries.append(filler_node);
AstNode *rhs_node;
if (leftover_count == 1) {
@@ -4155,62 +3363,66 @@ static AstNode *trans_ap_value(Context *c, APValue *ap_value, QualType qt, const
rhs_node = trans_create_node_bin_op(c, filler_arr_1, BinOpTypeArrayMult, amt_node);
}
+ if (init_count == 0) {
+ return rhs_node;
+ }
+
return trans_create_node_bin_op(c, init_node, BinOpTypeArrayCat, rhs_node);
}
- case APValue::LValue: {
- const APValue::LValueBase lval_base = ap_value->getLValueBase();
- if (const Expr *expr = lval_base.dyn_cast<const Expr *>()) {
+ case clang::APValue::LValue: {
+ const clang::APValue::LValueBase lval_base = ap_value->getLValueBase();
+ if (const clang::Expr *expr = lval_base.dyn_cast<const clang::Expr *>()) {
return trans_expr(c, ResultUsedYes, &c->global_scope->base, expr, TransRValue);
}
- //const ValueDecl *value_decl = lval_base.get<const ValueDecl *>();
- emit_warning(c, source_loc, "TODO handle initializer LValue ValueDecl");
+ //const clang::ValueDecl *value_decl = lval_base.get<const clang::ValueDecl *>();
+ emit_warning(c, source_loc, "TODO handle initializer LValue clang::ValueDecl");
return nullptr;
}
- case APValue::Float:
+ case clang::APValue::Float:
emit_warning(c, source_loc, "unsupported initializer value kind: Float");
return nullptr;
- case APValue::ComplexInt:
+ case clang::APValue::ComplexInt:
emit_warning(c, source_loc, "unsupported initializer value kind: ComplexInt");
return nullptr;
- case APValue::ComplexFloat:
+ case clang::APValue::ComplexFloat:
emit_warning(c, source_loc, "unsupported initializer value kind: ComplexFloat");
return nullptr;
- case APValue::Vector:
+ case clang::APValue::Vector:
emit_warning(c, source_loc, "unsupported initializer value kind: Vector");
return nullptr;
- case APValue::Struct:
+ case clang::APValue::Struct:
emit_warning(c, source_loc, "unsupported initializer value kind: Struct");
return nullptr;
- case APValue::Union:
+ case clang::APValue::Union:
emit_warning(c, source_loc, "unsupported initializer value kind: Union");
return nullptr;
- case APValue::MemberPointer:
+ case clang::APValue::MemberPointer:
emit_warning(c, source_loc, "unsupported initializer value kind: MemberPointer");
return nullptr;
- case APValue::AddrLabelDiff:
+ case clang::APValue::AddrLabelDiff:
emit_warning(c, source_loc, "unsupported initializer value kind: AddrLabelDiff");
return nullptr;
}
zig_unreachable();
}
-static void visit_var_decl(Context *c, const VarDecl *var_decl) {
+static void visit_var_decl(Context *c, const clang::VarDecl *var_decl) {
Buf *name = buf_create_from_str(decl_name(var_decl));
switch (var_decl->getTLSKind()) {
- case VarDecl::TLS_None:
+ case clang::VarDecl::TLS_None:
break;
- case VarDecl::TLS_Static:
+ case clang::VarDecl::TLS_Static:
emit_warning(c, var_decl->getLocation(),
"ignoring variable '%s' - static thread local storage", buf_ptr(name));
return;
- case VarDecl::TLS_Dynamic:
+ case clang::VarDecl::TLS_Dynamic:
emit_warning(c, var_decl->getLocation(),
"ignoring variable '%s' - dynamic thread local storage", buf_ptr(name));
return;
}
- QualType qt = var_decl->getType();
+ clang::QualType qt = var_decl->getType();
AstNode *var_type = trans_qual_type(c, qt, var_decl->getLocation());
if (var_type == nullptr) {
emit_warning(c, var_decl->getLocation(), "ignoring variable '%s' - unresolved type", buf_ptr(name));
@@ -4224,7 +3436,7 @@ static void visit_var_decl(Context *c, const VarDecl *var_decl) {
if (is_static && !is_extern) {
AstNode *init_node;
if (var_decl->hasInit()) {
- APValue *ap_value = var_decl->evaluateValue();
+ clang::APValue *ap_value = var_decl->evaluateValue();
if (ap_value == nullptr) {
emit_warning(c, var_decl->getLocation(),
"ignoring variable '%s' - unable to evaluate initializer", buf_ptr(name));
@@ -4254,24 +3466,25 @@ static void visit_var_decl(Context *c, const VarDecl *var_decl) {
return;
}
-static bool decl_visitor(void *context, const Decl *decl) {
+static bool decl_visitor(void *context, const ZigClangDecl *zdecl) {
+ const clang::Decl *decl = reinterpret_cast<const clang::Decl *>(zdecl);
Context *c = (Context*)context;
switch (decl->getKind()) {
- case Decl::Function:
- visit_fn_decl(c, static_cast<const FunctionDecl*>(decl));
+ case clang::Decl::Function:
+ visit_fn_decl(c, static_cast<const clang::FunctionDecl*>(decl));
break;
- case Decl::Typedef:
- resolve_typedef_decl(c, static_cast<const TypedefNameDecl *>(decl));
+ case clang::Decl::Typedef:
+ resolve_typedef_decl(c, static_cast<const clang::TypedefNameDecl *>(decl));
break;
- case Decl::Enum:
- resolve_enum_decl(c, static_cast<const EnumDecl *>(decl));
+ case clang::Decl::Enum:
+ resolve_enum_decl(c, static_cast<const clang::EnumDecl *>(decl));
break;
- case Decl::Record:
- resolve_record_decl(c, static_cast<const RecordDecl *>(decl));
+ case clang::Decl::Record:
+ resolve_record_decl(c, static_cast<const clang::RecordDecl *>(decl));
break;
- case Decl::Var:
- visit_var_decl(c, static_cast<const VarDecl *>(decl));
+ case clang::Decl::Var:
+ visit_var_decl(c, static_cast<const clang::VarDecl *>(decl));
break;
default:
emit_warning(c, decl->getLocation(), "ignoring %s decl", decl->getDeclKindName());
@@ -4613,7 +3826,7 @@ static AstNode *parse_ctok_suffix_op_expr(Context *c, CTokenize *ctok, size_t *t
} else if (first_tok->id == CTokIdAsterisk) {
*tok_i += 1;
- node = trans_create_node_ptr_type(c, false, false, node, PtrLenUnknown);
+ node = trans_create_node_ptr_type(c, false, false, node, PtrLenC);
} else {
return node;
}
@@ -4692,24 +3905,25 @@ static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *ch
c->macro_table.put(name, result_node);
}
-static void process_preprocessor_entities(Context *c, ASTUnit &unit) {
+static void process_preprocessor_entities(Context *c, ZigClangASTUnit *zunit) {
+ clang::ASTUnit *unit = reinterpret_cast<clang::ASTUnit *>(zunit);
CTokenize ctok = {{0}};
// TODO if we see #undef, delete it from the table
- for (PreprocessedEntity *entity : unit.getLocalPreprocessingEntities()) {
+ for (clang::PreprocessedEntity *entity : unit->getLocalPreprocessingEntities()) {
switch (entity->getKind()) {
- case PreprocessedEntity::InvalidKind:
- case PreprocessedEntity::InclusionDirectiveKind:
- case PreprocessedEntity::MacroExpansionKind:
+ case clang::PreprocessedEntity::InvalidKind:
+ case clang::PreprocessedEntity::InclusionDirectiveKind:
+ case clang::PreprocessedEntity::MacroExpansionKind:
continue;
- case PreprocessedEntity::MacroDefinitionKind:
+ case clang::PreprocessedEntity::MacroDefinitionKind:
{
- MacroDefinitionRecord *macro = static_cast<MacroDefinitionRecord *>(entity);
+ clang::MacroDefinitionRecord *macro = static_cast<clang::MacroDefinitionRecord *>(entity);
const char *raw_name = macro->getName()->getNameStart();
- SourceRange range = macro->getSourceRange();
- SourceLocation begin_loc = range.getBegin();
- SourceLocation end_loc = range.getEnd();
+ clang::SourceRange range = macro->getSourceRange();
+ clang::SourceLocation begin_loc = range.getBegin();
+ clang::SourceLocation end_loc = range.getEnd();
if (begin_loc == end_loc) {
// this means it is a macro without a value
@@ -4721,7 +3935,7 @@ static void process_preprocessor_entities(Context *c, ASTUnit &unit) {
continue;
}
- const char *begin_c = c->source_manager->getCharacterData(begin_loc);
+ const char *begin_c = ZigClangSourceManager_getCharacterData(c->source_manager, bitcast(begin_loc));
process_macro(c, &ctok, name, begin_c);
}
}
@@ -4772,7 +3986,16 @@ Error parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const
clang_argv.append("-x");
clang_argv.append("c");
- if (c->codegen->is_native_target) {
+ Buf *out_dep_path = nullptr;
+ if (codegen->enable_cache) {
+ Buf *prefix = buf_sprintf("%s" OS_SEP, buf_ptr(&codegen->cache_dir));
+ out_dep_path = os_tmp_filename(prefix, buf_create_from_str(".d"));
+ clang_argv.append("-MD");
+ clang_argv.append("-MF");
+ clang_argv.append(buf_ptr(out_dep_path));
+ }
+
+ if (c->codegen->zig_target->is_native) {
char *ZIG_PARSEC_CFLAGS = getenv("ZIG_NATIVE_PARSEC_CFLAGS");
if (ZIG_PARSEC_CFLAGS) {
Buf tmp_buf = BUF_INIT;
@@ -4791,12 +4014,24 @@ Error parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const
}
}
+ clang_argv.append("-nobuiltininc");
+ clang_argv.append("-nostdinc");
+ clang_argv.append("-nostdinc++");
+ if (codegen->libc_link_lib == nullptr) {
+ clang_argv.append("-nolibc");
+ }
+
clang_argv.append("-isystem");
clang_argv.append(buf_ptr(codegen->zig_c_headers_dir));
- if (codegen->libc_include_dir != nullptr) {
+ if (codegen->libc != nullptr) {
clang_argv.append("-isystem");
- clang_argv.append(buf_ptr(codegen->libc_include_dir));
+ clang_argv.append(buf_ptr(&codegen->libc->include_dir));
+
+ if (!buf_eql_buf(&codegen->libc->include_dir, &codegen->libc->sys_include_dir)) {
+ clang_argv.append("-isystem");
+ clang_argv.append(buf_ptr(&codegen->libc->sys_include_dir));
+ }
}
// windows c runtime requires -D_DEBUG if using debug libraries
@@ -4816,7 +4051,9 @@ Error parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const
clang_argv.append("-Xclang");
clang_argv.append("-detailed-preprocessing-record");
- if (!c->codegen->is_native_target) {
+ if (c->codegen->zig_target->is_native) {
+ clang_argv.append("-march=native");
+ } else {
clang_argv.append("-target");
clang_argv.append(buf_ptr(&c->codegen->triple_str));
}
@@ -4834,9 +4071,9 @@ Error parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const
// to make the [start...end] argument work
clang_argv.append(nullptr);
- IntrusiveRefCntPtr<DiagnosticsEngine> diags(CompilerInstance::createDiagnostics(new DiagnosticOptions));
+ clang::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diags(clang::CompilerInstance::createDiagnostics(new clang::DiagnosticOptions));
- std::shared_ptr<PCHContainerOperations> pch_container_ops = std::make_shared<PCHContainerOperations>();
+ std::shared_ptr<clang::PCHContainerOperations> pch_container_ops = std::make_shared<clang::PCHContainerOperations>();
bool only_local_decls = true;
bool capture_diagnostics = true;
@@ -4845,13 +4082,13 @@ Error parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const
bool single_file_parse = false;
bool for_serialization = false;
const char *resources_path = buf_ptr(codegen->zig_c_headers_dir);
- std::unique_ptr<ASTUnit> err_unit;
- std::unique_ptr<ASTUnit> ast_unit(ASTUnit::LoadFromCommandLine(
+ std::unique_ptr<clang::ASTUnit> err_unit;
+ ZigClangASTUnit *ast_unit = reinterpret_cast<ZigClangASTUnit *>(clang::ASTUnit::LoadFromCommandLine(
&clang_argv.at(0), &clang_argv.last(),
pch_container_ops, diags, resources_path,
- only_local_decls, capture_diagnostics, None, true, 0, TU_Complete,
- false, false, allow_pch_with_compiler_errors, SkipFunctionBodiesScope::None,
- single_file_parse, user_files_are_volatile, for_serialization, None, &err_unit,
+ only_local_decls, capture_diagnostics, clang::None, true, 0, clang::TU_Complete,
+ false, false, allow_pch_with_compiler_errors, clang::SkipFunctionBodiesScope::None,
+ single_file_parse, user_files_are_volatile, for_serialization, clang::None, &err_unit,
nullptr));
// Early failures in LoadFromCommandLine may return with ErrUnit unset.
@@ -4861,29 +4098,29 @@ Error parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const
if (diags->getClient()->getNumErrors() > 0) {
if (ast_unit) {
- err_unit = std::move(ast_unit);
+ err_unit = std::unique_ptr<clang::ASTUnit>(reinterpret_cast<clang::ASTUnit *>(ast_unit));
}
- for (ASTUnit::stored_diag_iterator it = err_unit->stored_diag_begin(),
+ for (clang::ASTUnit::stored_diag_iterator it = err_unit->stored_diag_begin(),
it_end = err_unit->stored_diag_end();
it != it_end; ++it)
{
switch (it->getLevel()) {
- case DiagnosticsEngine::Ignored:
- case DiagnosticsEngine::Note:
- case DiagnosticsEngine::Remark:
- case DiagnosticsEngine::Warning:
+ case clang::DiagnosticsEngine::Ignored:
+ case clang::DiagnosticsEngine::Note:
+ case clang::DiagnosticsEngine::Remark:
+ case clang::DiagnosticsEngine::Warning:
continue;
- case DiagnosticsEngine::Error:
- case DiagnosticsEngine::Fatal:
+ case clang::DiagnosticsEngine::Error:
+ case clang::DiagnosticsEngine::Fatal:
break;
}
StringRef msg_str_ref = it->getMessage();
Buf *msg = string_ref_to_buf(msg_str_ref);
- FullSourceLoc fsl = it->getLocation();
+ clang::FullSourceLoc fsl = it->getLocation();
if (fsl.hasManager()) {
- FileID file_id = fsl.getFileID();
- StringRef filename = fsl.getManager().getFilename(fsl);
+ clang::FileID file_id = fsl.getFileID();
+ clang::StringRef filename = fsl.getManager().getFilename(fsl);
unsigned line = fsl.getSpellingLineNumber() - 1;
unsigned column = fsl.getSpellingColumnNumber() - 1;
unsigned offset = fsl.getManager().getFileOffset(fsl);
@@ -4908,14 +4145,25 @@ Error parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const
return ErrorCCompileErrors;
}
- c->ctx = &ast_unit->getASTContext();
- c->source_manager = &ast_unit->getSourceManager();
+ if (codegen->enable_cache) {
+ Error err;
+ assert(out_dep_path != nullptr);
+ if ((err = cache_add_dep_file(&codegen->cache_hash, out_dep_path, codegen->verbose_cimport))) {
+ if (codegen->verbose_cimport) {
+ fprintf(stderr, "translate-c: aborting due to failed cache operation: %s\n", err_str(err));
+ }
+ return err;
+ }
+ }
+
+ c->ctx = ZigClangASTUnit_getASTContext(ast_unit);
+ c->source_manager = ZigClangASTUnit_getSourceManager(ast_unit);
c->root = trans_create_node(c, NodeTypeContainerDecl);
c->root->data.container_decl.is_root = true;
- ast_unit->visitLocalTopLevelDecls(c, decl_visitor);
+ ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, c, decl_visitor);
- process_preprocessor_entities(c, *ast_unit);
+ process_preprocessor_entities(c, ast_unit);
render_macros(c);
render_aliases(c);
diff --git a/src/util.hpp b/src/util.hpp
@@ -147,11 +147,14 @@ static inline T clamp(T min_value, T value, T max_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) {
- size_t str_len = strlen(str);
- if (str_len != mem_len)
+static inline bool mem_eql_mem(const char *a_ptr, size_t a_len, const char *b_ptr, size_t b_len) {
+ if (a_len != b_len)
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) {
diff --git a/src/zig_clang.cpp b/src/zig_clang.cpp
@@ -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));
+}
diff --git a/src/zig_clang.h b/src/zig_clang.h
@@ -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
diff --git a/src/zig_clang_cc1_main.cpp b/src/zig_clang_cc1_main.cpp
@@ -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;
+}
+
diff --git a/src/zig_clang_cc1as_main.cpp b/src/zig_clang_cc1as_main.cpp
@@ -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;
+}
+
diff --git a/src/zig_clang_driver.cpp b/src/zig_clang_driver.cpp
@@ -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;
+}
+
diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp
@@ -732,7 +732,7 @@ void ZigLLVMGetNativeTarget(ZigLLVM_ArchType *arch_type, ZigLLVM_SubArchType *su
const char *ZigLLVMGetSubArchTypeName(ZigLLVM_SubArchType sub_arch) {
switch (sub_arch) {
case ZigLLVM_NoSubArch:
- return "(none)";
+ return "";
case ZigLLVM_ARMSubArch_v8_5a:
return "v8_5a";
case ZigLLVM_ARMSubArch_v8_4a:
diff --git a/src/zig_llvm.h b/src/zig_llvm.h
@@ -215,7 +215,7 @@ ZIG_EXTERN_C void ZigLLVMParseCommandLineOptions(size_t argc, const char *const
// copied from include/llvm/ADT/Triple.h
-
+// synchronize with target.cpp::arch_list
enum ZigLLVM_ArchType {
ZigLLVM_UnknownArch,
@@ -272,6 +272,7 @@ enum ZigLLVM_ArchType {
ZigLLVM_LastArchType = ZigLLVM_renderscript64
};
+// synchronize with lists in target.cpp
enum ZigLLVM_SubArchType {
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 *ZigLLVMGetVendorTypeName(enum ZigLLVM_VendorType vendor);
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,
void (*append_diagnostic)(void *, const char *, size_t), void *context);
diff --git a/std/buf_set.zig b/std/buf_set.zig
@@ -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 {
const entry = self.hash_map.remove(key) orelse return;
self.free(entry.key);
diff --git a/std/build.zig b/std/build.zig
@@ -15,6 +15,8 @@ const BufSet = std.BufSet;
const BufMap = std.BufMap;
const fmt_lib = std.fmt;
+pub const FmtStep = @import("build/fmt.zig").FmtStep;
+
pub const Builder = struct {
uninstall_tls: TopLevelStep,
install_tls: TopLevelStep,
@@ -31,6 +33,7 @@ pub const Builder = struct {
verbose_tokenize: bool,
verbose_ast: bool,
verbose_link: bool,
+ verbose_cc: bool,
verbose_ir: bool,
verbose_llvm_ir: bool,
verbose_cimport: bool,
@@ -99,6 +102,7 @@ pub const Builder = struct {
.verbose_tokenize = false,
.verbose_ast = false,
.verbose_link = false,
+ .verbose_cc = false,
.verbose_ir = false,
.verbose_llvm_ir = false,
.verbose_cimport = false,
@@ -157,7 +161,7 @@ pub const Builder = struct {
return LibExeObjStep.createExecutable(self, name, root_src, true);
}
- pub fn addObject(self: *Builder, name: []const u8, root_src: []const u8) *LibExeObjStep {
+ pub fn addObject(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
return LibExeObjStep.createObject(self, name, root_src);
}
@@ -169,10 +173,8 @@ pub const Builder = struct {
return LibExeObjStep.createStaticLibrary(self, name, root_src);
}
- pub fn addTest(self: *Builder, root_src: []const u8) *TestStep {
- const test_step = self.allocator.create(TestStep) catch unreachable;
- test_step.* = TestStep.init(self, root_src);
- return test_step;
+ pub fn addTest(self: *Builder, root_src: []const u8) *LibExeObjStep {
+ return LibExeObjStep.createTest(self, "test", root_src);
}
pub fn addAssemble(self: *Builder, name: []const u8, src: []const u8) *LibExeObjStep {
@@ -181,22 +183,6 @@ pub const Builder = struct {
return obj_step;
}
- pub fn addCStaticLibrary(self: *Builder, name: []const u8) *LibExeObjStep {
- return LibExeObjStep.createCStaticLibrary(self, name);
- }
-
- pub fn addCSharedLibrary(self: *Builder, name: []const u8, ver: Version) *LibExeObjStep {
- return LibExeObjStep.createCSharedLibrary(self, name, ver);
- }
-
- pub fn addCExecutable(self: *Builder, name: []const u8) *LibExeObjStep {
- return LibExeObjStep.createCExecutable(self, name);
- }
-
- pub fn addCObject(self: *Builder, name: []const u8, src: []const u8) *LibExeObjStep {
- return LibExeObjStep.createCObject(self, name, src);
- }
-
/// ::argv is copied.
pub fn addCommand(self: *Builder, cwd: ?[]const u8, env_map: *const BufMap, argv: []const []const u8) *CommandStep {
return CommandStep.create(self, cwd, env_map, argv);
@@ -221,6 +207,10 @@ pub const Builder = struct {
return remove_dir_step;
}
+ pub fn addFmt(self: *Builder, paths: []const []const u8) *FmtStep {
+ return FmtStep.create(self, paths);
+ }
+
pub fn version(self: *const Builder, major: u32, minor: u32, patch: u32) Version {
return Version{
.major = major,
@@ -663,14 +653,6 @@ pub const Builder = struct {
return fmt_lib.allocPrint(self.allocator, format, args) catch unreachable;
}
- fn getCCExe(self: *Builder) []const u8 {
- if (builtin.environ == builtin.Environ.msvc) {
- return "cl.exe";
- } else {
- return os.getEnvVarOwned(self.allocator, "CC") catch |err| if (err == error.EnvironmentVariableNotFound) ([]const u8)("cc") else debug.panic("Unable to get environment variable: {}", err);
- }
- }
-
pub fn findProgram(self: *Builder, names: []const []const u8, paths: []const []const u8) ![]const u8 {
// TODO report error for ambiguous situations
const exe_extension = (Target{ .Native = {} }).exeFileExt();
@@ -755,20 +737,40 @@ const Version = struct {
const CrossTarget = struct {
arch: builtin.Arch,
os: builtin.Os,
- environ: builtin.Environ,
+ abi: builtin.Abi,
};
pub const Target = union(enum) {
Native: void,
Cross: CrossTarget,
+ fn archSubArchName(arch: builtin.Arch) []const u8 {
+ return switch (arch) {
+ builtin.Arch.arm => |sub| @tagName(sub),
+ builtin.Arch.armeb => |sub| @tagName(sub),
+ builtin.Arch.thumb => |sub| @tagName(sub),
+ builtin.Arch.thumbeb => |sub| @tagName(sub),
+ builtin.Arch.aarch64 => |sub| @tagName(sub),
+ builtin.Arch.aarch64_be => |sub| @tagName(sub),
+ builtin.Arch.kalimba => |sub| @tagName(sub),
+ else => "",
+ };
+ }
+
+ pub fn subArchName(self: Target) []const u8 {
+ switch (self) {
+ Target.Native => return archSubArchName(builtin.arch),
+ Target.Cross => |cross| return archSubArchName(cross.arch),
+ }
+ }
+
pub fn oFileExt(self: *const Target) []const u8 {
- const environ = switch (self.*) {
- Target.Native => builtin.environ,
- Target.Cross => |t| t.environ,
+ const abi = switch (self.*) {
+ Target.Native => builtin.abi,
+ Target.Cross => |t| t.abi,
};
- return switch (environ) {
- builtin.Environ.msvc => ".obj",
+ return switch (abi) {
+ builtin.Abi.msvc => ".obj",
else => ".o",
};
}
@@ -825,6 +827,11 @@ const Pkg = struct {
path: []const u8,
};
+const CSourceFile = struct {
+ source_path: []const u8,
+ args: []const []const u8,
+};
+
pub const LibExeObjStep = struct {
step: Step,
builder: *Builder,
@@ -834,6 +841,7 @@ pub const LibExeObjStep = struct {
linker_script: ?[]const u8,
out_filename: []const u8,
output_path: ?[]const u8,
+ output_lib_path: ?[]const u8,
static: bool,
version: Version,
object_files: ArrayList([]const u8),
@@ -844,33 +852,34 @@ pub const LibExeObjStep = struct {
strip: bool,
full_path_libs: ArrayList([]const u8),
need_flat_namespace_hack: bool,
- is_zig: bool,
- cflags: ArrayList([]const u8),
include_dirs: ArrayList([]const u8),
lib_paths: ArrayList([]const u8),
- disable_libc: bool,
frameworks: BufSet,
verbose_link: bool,
- no_rosegment: bool,
+ verbose_cc: bool,
c_std: Builder.CStd,
+ override_std_dir: ?[]const u8,
+ exec_cmd_args: ?[]const ?[]const u8,
+ name_prefix: []const u8,
+ filter: ?[]const u8,
- // zig only stuff
root_src: ?[]const u8,
output_h_path: ?[]const u8,
out_h_filename: []const u8,
+ out_lib_filename: []const u8,
assembly_files: ArrayList([]const u8),
packages: ArrayList(Pkg),
build_options_contents: std.Buffer,
system_linker_hack: bool,
- // C only stuff
- source_files: ArrayList([]const u8),
+ c_source_files: ArrayList(*CSourceFile),
object_src: []const u8,
const Kind = enum {
Exe,
Lib,
Obj,
+ Test,
};
pub fn createSharedLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8, ver: Version) *LibExeObjStep {
@@ -879,55 +888,36 @@ pub const LibExeObjStep = struct {
return self;
}
- pub fn createCSharedLibrary(builder: *Builder, name: []const u8, version: Version) *LibExeObjStep {
- const self = builder.allocator.create(LibExeObjStep) catch unreachable;
- self.* = initC(builder, name, Kind.Lib, version, false);
- return self;
- }
-
pub fn createStaticLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
const self = builder.allocator.create(LibExeObjStep) catch unreachable;
self.* = initExtraArgs(builder, name, root_src, Kind.Lib, true, builder.version(0, 0, 0));
return self;
}
- pub fn createCStaticLibrary(builder: *Builder, name: []const u8) *LibExeObjStep {
- const self = builder.allocator.create(LibExeObjStep) catch unreachable;
- self.* = initC(builder, name, Kind.Lib, builder.version(0, 0, 0), true);
- return self;
- }
-
- pub fn createObject(builder: *Builder, name: []const u8, root_src: []const u8) *LibExeObjStep {
+ pub fn createObject(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
const self = builder.allocator.create(LibExeObjStep) catch unreachable;
self.* = initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0));
return self;
}
- pub fn createCObject(builder: *Builder, name: []const u8, src: []const u8) *LibExeObjStep {
- const self = builder.allocator.create(LibExeObjStep) catch unreachable;
- self.* = initC(builder, name, Kind.Obj, builder.version(0, 0, 0), false);
- self.object_src = src;
- return self;
- }
-
pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?[]const u8, static: bool) *LibExeObjStep {
const self = builder.allocator.create(LibExeObjStep) catch unreachable;
self.* = initExtraArgs(builder, name, root_src, Kind.Exe, static, builder.version(0, 0, 0));
return self;
}
- pub fn createCExecutable(builder: *Builder, name: []const u8) *LibExeObjStep {
+ pub fn createTest(builder: *Builder, name: []const u8, root_src: []const u8) *LibExeObjStep {
const self = builder.allocator.create(LibExeObjStep) catch unreachable;
- self.* = initC(builder, name, Kind.Exe, builder.version(0, 0, 0), false);
+ self.* = initExtraArgs(builder, name, root_src, Kind.Test, false, builder.version(0, 0, 0));
return self;
}
fn initExtraArgs(builder: *Builder, name: []const u8, root_src: ?[]const u8, kind: Kind, static: bool, ver: Version) LibExeObjStep {
var self = LibExeObjStep{
- .no_rosegment = false,
.strip = false,
.builder = builder,
.verbose_link = false,
+ .verbose_cc = false,
.build_mode = builtin.Mode.Debug,
.static = static,
.kind = kind,
@@ -939,80 +929,35 @@ pub const LibExeObjStep = struct {
.frameworks = BufSet.init(builder.allocator),
.step = Step.init(name, builder.allocator, make),
.output_path = null,
+ .output_lib_path = null,
.output_h_path = null,
.version = ver,
.out_filename = undefined,
.out_h_filename = builder.fmt("{}.h", name),
+ .out_lib_filename = undefined,
.major_only_filename = undefined,
.name_only_filename = undefined,
.object_files = ArrayList([]const u8).init(builder.allocator),
.assembly_files = ArrayList([]const u8).init(builder.allocator),
.packages = ArrayList(Pkg).init(builder.allocator),
- .is_zig = true,
.full_path_libs = ArrayList([]const u8).init(builder.allocator),
.need_flat_namespace_hack = false,
- .cflags = ArrayList([]const u8).init(builder.allocator),
- .source_files = undefined,
+ .c_source_files = ArrayList(*CSourceFile).init(builder.allocator),
.include_dirs = ArrayList([]const u8).init(builder.allocator),
.lib_paths = ArrayList([]const u8).init(builder.allocator),
.object_src = undefined,
- .disable_libc = true,
.build_options_contents = std.Buffer.initSize(builder.allocator, 0) catch unreachable,
.c_std = Builder.CStd.C99,
.system_linker_hack = false,
+ .override_std_dir = null,
+ .exec_cmd_args = null,
+ .name_prefix = "",
+ .filter = null,
};
self.computeOutFileNames();
return self;
}
- fn initC(builder: *Builder, name: []const u8, kind: Kind, version: Version, static: bool) LibExeObjStep {
- var self = LibExeObjStep{
- .no_rosegment = false,
- .builder = builder,
- .name = name,
- .kind = kind,
- .version = version,
- .static = static,
- .target = Target.Native,
- .cflags = ArrayList([]const u8).init(builder.allocator),
- .source_files = ArrayList([]const u8).init(builder.allocator),
- .object_files = ArrayList([]const u8).init(builder.allocator),
- .step = Step.init(name, builder.allocator, make),
- .link_libs = BufSet.init(builder.allocator),
- .frameworks = BufSet.init(builder.allocator),
- .full_path_libs = ArrayList([]const u8).init(builder.allocator),
- .include_dirs = ArrayList([]const u8).init(builder.allocator),
- .lib_paths = ArrayList([]const u8).init(builder.allocator),
- .output_path = null,
- .out_filename = undefined,
- .major_only_filename = undefined,
- .name_only_filename = undefined,
- .object_src = undefined,
- .build_mode = builtin.Mode.Debug,
- .strip = false,
- .need_flat_namespace_hack = false,
- .disable_libc = false,
- .is_zig = false,
- .linker_script = null,
- .c_std = Builder.CStd.C99,
- .system_linker_hack = false,
-
- .root_src = undefined,
- .verbose_link = false,
- .output_h_path = undefined,
- .out_h_filename = undefined,
- .assembly_files = undefined,
- .packages = undefined,
- .build_options_contents = undefined,
- };
- self.computeOutFileNames();
- return self;
- }
-
- pub fn setNoRoSegment(self: *LibExeObjStep, value: bool) void {
- self.no_rosegment = value;
- }
-
fn computeOutFileNames(self: *LibExeObjStep) void {
switch (self.kind) {
Kind.Obj => {
@@ -1021,23 +966,37 @@ pub const LibExeObjStep = struct {
Kind.Exe => {
self.out_filename = self.builder.fmt("{}{}", self.name, self.target.exeFileExt());
},
+ Kind.Test => {
+ self.out_filename = self.builder.fmt("test{}", self.target.exeFileExt());
+ },
Kind.Lib => {
if (self.static) {
- self.out_filename = self.builder.fmt("lib{}.a", self.name);
+ switch (self.target.getOs()) {
+ builtin.Os.windows => {
+ self.out_filename = self.builder.fmt("{}.lib", self.name);
+ },
+ else => {
+ self.out_filename = self.builder.fmt("lib{}.a", self.name);
+ },
+ }
+ self.out_lib_filename = self.out_filename;
} else {
switch (self.target.getOs()) {
builtin.Os.ios, builtin.Os.macosx => {
self.out_filename = self.builder.fmt("lib{}.{d}.{d}.{d}.dylib", self.name, self.version.major, self.version.minor, self.version.patch);
self.major_only_filename = self.builder.fmt("lib{}.{d}.dylib", self.name, self.version.major);
self.name_only_filename = self.builder.fmt("lib{}.dylib", self.name);
+ self.out_lib_filename = self.out_filename;
},
builtin.Os.windows => {
self.out_filename = self.builder.fmt("{}.dll", self.name);
+ self.out_lib_filename = self.builder.fmt("{}.lib", self.name);
},
else => {
self.out_filename = self.builder.fmt("lib{}.so.{d}.{d}.{d}", self.name, self.version.major, self.version.minor, self.version.patch);
self.major_only_filename = self.builder.fmt("lib{}.so.{d}", self.name, self.version.major);
self.name_only_filename = self.builder.fmt("lib{}.so", self.name);
+ self.out_lib_filename = self.out_filename;
},
}
}
@@ -1045,12 +1004,17 @@ pub const LibExeObjStep = struct {
}
}
- pub fn setTarget(self: *LibExeObjStep, target_arch: builtin.Arch, target_os: builtin.Os, target_environ: builtin.Environ) void {
+ pub fn setTarget(
+ self: *LibExeObjStep,
+ target_arch: builtin.Arch,
+ target_os: builtin.Os,
+ target_abi: builtin.Abi,
+ ) void {
self.target = Target{
.Cross = CrossTarget{
.arch = target_arch,
.os = target_os,
- .environ = target_environ,
+ .abi = target_abi,
},
};
self.computeOutFileNames();
@@ -1072,7 +1036,15 @@ pub const LibExeObjStep = struct {
self.step.dependOn(&lib.step);
- self.full_path_libs.append(lib.getOutputPath()) catch unreachable;
+ if (lib.static or self.target.isWindows()) {
+ self.object_files.append(lib.getOutputLibPath()) catch unreachable;
+ } else {
+ self.full_path_libs.append(lib.getOutputPath()) catch unreachable;
+ }
+
+ if (lib.link_libs.exists("c")) {
+ self.link_libs.put("c") catch unreachable;
+ }
// TODO should be some kind of isolated directory that only has this header in it
self.include_dirs.append(self.builder.cache_root) catch unreachable;
@@ -1088,24 +1060,44 @@ pub const LibExeObjStep = struct {
}
pub fn linkSystemLibrary(self: *LibExeObjStep, name: []const u8) void {
- assert(self.kind != Kind.Obj);
self.link_libs.put(name) catch unreachable;
}
- pub fn addSourceFile(self: *LibExeObjStep, file: []const u8) void {
- assert(self.kind != Kind.Obj);
- assert(!self.is_zig);
- self.source_files.append(file) catch unreachable;
+ pub fn setNamePrefix(self: *LibExeObjStep, text: []const u8) void {
+ assert(self.kind == Kind.Test);
+ self.name_prefix = text;
+ }
+
+ pub fn setFilter(self: *LibExeObjStep, text: ?[]const u8) void {
+ assert(self.kind == Kind.Test);
+ self.filter = text;
+ }
+
+ pub fn addCSourceFile(self: *LibExeObjStep, file: []const u8, args: []const []const u8) void {
+ const c_source_file = self.builder.allocator.create(CSourceFile) catch unreachable;
+ c_source_file.* = CSourceFile{
+ .source_path = file,
+ .args = args,
+ };
+ self.c_source_files.append(c_source_file) catch unreachable;
}
pub fn setVerboseLink(self: *LibExeObjStep, value: bool) void {
self.verbose_link = value;
}
+ pub fn setVerboseCC(self: *LibExeObjStep, value: bool) void {
+ self.verbose_cc = value;
+ }
+
pub fn setBuildMode(self: *LibExeObjStep, mode: builtin.Mode) void {
self.build_mode = mode;
}
+ pub fn overrideStdDir(self: *LibExeObjStep, dir_path: []const u8) void {
+ self.override_std_dir = dir_path;
+ }
+
pub fn setOutputPath(self: *LibExeObjStep, file_path: []const u8) void {
self.output_path = file_path;
@@ -1122,6 +1114,22 @@ pub const LibExeObjStep = struct {
) catch unreachable;
}
+ pub fn setOutputLibPath(self: *LibExeObjStep, file_path: []const u8) void {
+ assert(self.kind == Kind.Lib);
+ if (self.static)
+ return self.setOutputPath(file_path);
+
+ self.output_lib_path = file_path;
+ }
+
+ pub fn getOutputLibPath(self: *LibExeObjStep) []const u8 {
+ assert(self.kind == Kind.Lib);
+ return if (self.output_lib_path) |output_lib_path| output_lib_path else os.path.join(
+ self.builder.allocator,
+ [][]const u8{ self.builder.cache_root, self.out_lib_filename },
+ ) catch unreachable;
+ }
+
pub fn setOutputHPath(self: *LibExeObjStep, file_path: []const u8) void {
self.output_h_path = file_path;
@@ -1156,17 +1164,15 @@ pub const LibExeObjStep = struct {
self.object_files.append(obj.getOutputPath()) catch unreachable;
- // TODO make this lazy instead of stateful
- if (!obj.disable_libc) {
- self.disable_libc = false;
- }
-
// TODO should be some kind of isolated directory that only has this header in it
self.include_dirs.append(self.builder.cache_root) catch unreachable;
+
+ if (obj.link_libs.exists("c")) {
+ self.link_libs.put("c") catch unreachable;
+ }
}
pub fn addBuildOption(self: *LibExeObjStep, comptime T: type, name: []const u8, value: T) void {
- assert(self.is_zig);
const out = &std.io.BufferOutStream.init(&self.build_options_contents).stream;
out.print("pub const {} = {};\n", name, value) catch unreachable;
}
@@ -1180,23 +1186,15 @@ pub const LibExeObjStep = struct {
}
pub fn addPackagePath(self: *LibExeObjStep, name: []const u8, pkg_index_path: []const u8) void {
- assert(self.is_zig);
-
self.packages.append(Pkg{
.name = name,
.path = pkg_index_path,
}) catch unreachable;
}
- pub fn addCompileFlags(self: *LibExeObjStep, flags: []const []const u8) void {
- for (flags) |flag| {
- self.cflags.append(flag) catch unreachable;
- }
- }
-
- pub fn setNoStdLib(self: *LibExeObjStep, disable: bool) void {
- assert(!self.is_zig);
- self.disable_libc = disable;
+ pub fn setExecCmd(self: *LibExeObjStep, args: []const ?[]const u8) void {
+ assert(self.kind == Kind.Test);
+ self.exec_cmd_args = args;
}
pub fn enableSystemLinkerHack(self: *LibExeObjStep) void {
@@ -1205,15 +1203,11 @@ pub const LibExeObjStep = struct {
fn make(step: *Step) !void {
const self = @fieldParentPtr(LibExeObjStep, "step", step);
- return if (self.is_zig) self.makeZig() else self.makeC();
- }
-
- fn makeZig(self: *LibExeObjStep) !void {
const builder = self.builder;
- assert(self.is_zig);
-
- if (self.root_src == null and self.object_files.len == 0 and self.assembly_files.len == 0) {
+ if (self.root_src == null and self.object_files.len == 0 and
+ self.assembly_files.len == 0 and self.c_source_files.len == 0)
+ {
warn("{}: linker needs 1 or more objects to link\n", self.step.name);
return error.NeedAnObject;
}
@@ -1227,6 +1221,7 @@ pub const LibExeObjStep = struct {
Kind.Lib => "build-lib",
Kind.Exe => "build-exe",
Kind.Obj => "build-obj",
+ Kind.Test => "test",
};
zig_args.append(cmd) catch unreachable;
@@ -1234,6 +1229,14 @@ pub const LibExeObjStep = struct {
zig_args.append(builder.pathFromRoot(root_src)) catch unreachable;
}
+ for (self.c_source_files.toSliceConst()) |c_source_file| {
+ try zig_args.append("--c-source");
+ for (c_source_file.args) |arg| {
+ try zig_args.append(arg);
+ }
+ try zig_args.append(self.builder.pathFromRoot(c_source_file.source_path));
+ }
+
if (self.build_options_contents.len() > 0) {
const build_options_file = try os.path.join(
builder.allocator,
@@ -1246,6 +1249,16 @@ pub const LibExeObjStep = struct {
try zig_args.append("--pkg-end");
}
+ if (self.filter) |filter| {
+ try zig_args.append("--test-filter");
+ try zig_args.append(filter);
+ }
+
+ if (self.name_prefix.len != 0) {
+ try zig_args.append("--test-name-prefix");
+ try zig_args.append(self.name_prefix);
+ }
+
for (self.object_files.toSliceConst()) |object_file| {
zig_args.append("--object") catch unreachable;
zig_args.append(builder.pathFromRoot(object_file)) catch unreachable;
@@ -1262,6 +1275,7 @@ pub const LibExeObjStep = struct {
if (builder.verbose_ir) zig_args.append("--verbose-ir") catch unreachable;
if (builder.verbose_llvm_ir) zig_args.append("--verbose-llvm-ir") catch unreachable;
if (builder.verbose_link or self.verbose_link) zig_args.append("--verbose-link") catch unreachable;
+ if (builder.verbose_cc or self.verbose_cc) zig_args.append("--verbose-cc") catch unreachable;
if (self.strip) {
zig_args.append("--strip") catch unreachable;
@@ -1281,7 +1295,13 @@ pub const LibExeObjStep = struct {
zig_args.append("--output") catch unreachable;
zig_args.append(output_path) catch unreachable;
- if (self.kind != Kind.Exe) {
+ if (self.kind == Kind.Lib and !self.static) {
+ const output_lib_path = builder.pathFromRoot(self.getOutputLibPath());
+ zig_args.append("--output-lib") catch unreachable;
+ zig_args.append(output_lib_path) catch unreachable;
+ }
+
+ if (self.kind != Kind.Exe and self.root_src != null) {
const output_h_path = self.getOutputHPath();
zig_args.append("--output-h") catch unreachable;
zig_args.append(builder.pathFromRoot(output_h_path)) catch unreachable;
@@ -1300,21 +1320,23 @@ pub const LibExeObjStep = struct {
zig_args.append("--ver-patch") catch unreachable;
zig_args.append(builder.fmt("{}", self.version.patch)) catch unreachable;
}
- if (self.kind == Kind.Exe and self.static) {
+ if ((self.kind == Kind.Exe or self.kind == Kind.Test) and self.static) {
zig_args.append("--static") catch unreachable;
}
switch (self.target) {
Target.Native => {},
Target.Cross => |cross_target| {
- zig_args.append("--target-arch") catch unreachable;
- zig_args.append(@tagName(cross_target.arch)) catch unreachable;
-
- zig_args.append("--target-os") catch unreachable;
- zig_args.append(@tagName(cross_target.os)) catch unreachable;
-
- zig_args.append("--target-environ") catch unreachable;
- zig_args.append(@tagName(cross_target.environ)) catch unreachable;
+ const triple = builder.fmt(
+ "{}{}-{}-{}",
+ @tagName(cross_target.arch),
+ Target.archSubArchName(cross_target.arch),
+ @tagName(cross_target.os),
+ @tagName(cross_target.abi),
+ );
+
+ try zig_args.append("-target");
+ try zig_args.append(triple);
},
}
@@ -1332,11 +1354,16 @@ pub const LibExeObjStep = struct {
}
}
- if (!self.disable_libc) {
- zig_args.append("--library") catch unreachable;
- zig_args.append("c") catch unreachable;
+ if (self.exec_cmd_args) |exec_cmd_args| {
+ for (exec_cmd_args) |cmd_arg| {
+ if (cmd_arg) |arg| {
+ try zig_args.append("--test-cmd");
+ try zig_args.append(arg);
+ } else {
+ try zig_args.append("--test-cmd-bin");
+ }
+ }
}
-
for (self.packages.toSliceConst()) |pkg| {
zig_args.append("--pkg-begin") catch unreachable;
zig_args.append(pkg.name) catch unreachable;
@@ -1370,8 +1397,14 @@ pub const LibExeObjStep = struct {
}
for (self.full_path_libs.toSliceConst()) |full_path_lib| {
- zig_args.append("--library") catch unreachable;
- zig_args.append(builder.pathFromRoot(full_path_lib)) catch unreachable;
+ try zig_args.append("--library");
+ try zig_args.append(builder.pathFromRoot(full_path_lib));
+
+ const full_path_lib_abs = builder.pathFromRoot(full_path_lib);
+ if (os.path.dirname(full_path_lib_abs)) |dirname| {
+ try zig_args.append("-rpath");
+ try zig_args.append(dirname);
+ }
}
if (self.target.isDarwin()) {
@@ -1382,574 +1415,20 @@ pub const LibExeObjStep = struct {
}
}
- if (self.no_rosegment) {
- try zig_args.append("--no-rosegment");
- }
if (self.system_linker_hack) {
try zig_args.append("--system-linker-hack");
}
- try builder.spawnChild(zig_args.toSliceConst());
-
- if (self.kind == Kind.Lib and !self.static and self.target.wantSharedLibSymLinks()) {
- try doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename, self.name_only_filename);
- }
- }
-
- fn appendCompileFlags(self: *LibExeObjStep, args: *ArrayList([]const u8)) void {
- if (!self.strip) {
- args.append("-g") catch unreachable;
- }
- switch (self.build_mode) {
- builtin.Mode.Debug => {
- if (self.disable_libc) {
- args.append("-fno-stack-protector") catch unreachable;
- } else {
- args.append("-fstack-protector-strong") catch unreachable;
- args.append("--param") catch unreachable;
- args.append("ssp-buffer-size=4") catch unreachable;
- }
- },
- builtin.Mode.ReleaseSafe => {
- args.append("-O2") catch unreachable;
- if (self.disable_libc) {
- args.append("-fno-stack-protector") catch unreachable;
- } else {
- args.append("-D_FORTIFY_SOURCE=2") catch unreachable;
- args.append("-fstack-protector-strong") catch unreachable;
- args.append("--param") catch unreachable;
- args.append("ssp-buffer-size=4") catch unreachable;
- }
- },
- builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => {
- args.append("-O2") catch unreachable;
- args.append("-fno-stack-protector") catch unreachable;
- },
- }
-
- for (self.include_dirs.toSliceConst()) |dir| {
- args.append("-I") catch unreachable;
- args.append(self.builder.pathFromRoot(dir)) catch unreachable;
- }
-
- for (self.cflags.toSliceConst()) |cflag| {
- args.append(cflag) catch unreachable;
- }
-
- if (self.disable_libc) {
- args.append("-nostdlib") catch unreachable;
- }
- }
-
- fn makeC(self: *LibExeObjStep) !void {
- const builder = self.builder;
-
- const cc = builder.getCCExe();
-
- assert(!self.is_zig);
-
- var cc_args = ArrayList([]const u8).init(builder.allocator);
- defer cc_args.deinit();
-
- cc_args.append(cc) catch unreachable;
-
- const is_darwin = self.target.isDarwin();
-
- const c_std_arg = switch (self.c_std) {
- Builder.CStd.C89 => "-std=c89",
- Builder.CStd.C99 => "-std=c99",
- Builder.CStd.C11 => "-std=c11",
- };
- try cc_args.append(c_std_arg);
-
- switch (self.kind) {
- Kind.Obj => {
- cc_args.append("-c") catch unreachable;
- cc_args.append(builder.pathFromRoot(self.object_src)) catch unreachable;
-
- const output_path = builder.pathFromRoot(self.getOutputPath());
- cc_args.append("-o") catch unreachable;
- cc_args.append(output_path) catch unreachable;
-
- self.appendCompileFlags(&cc_args);
-
- try builder.spawnChild(cc_args.toSliceConst());
- },
- Kind.Lib => {
- for (self.source_files.toSliceConst()) |source_file| {
- cc_args.resize(0) catch unreachable;
- cc_args.append(cc) catch unreachable;
-
- if (!self.static) {
- cc_args.append("-fPIC") catch unreachable;
- }
-
- const abs_source_file = builder.pathFromRoot(source_file);
- cc_args.append("-c") catch unreachable;
- cc_args.append(abs_source_file) catch unreachable;
-
- const cache_o_src = os.path.join(
- builder.allocator,
- [][]const u8{ builder.cache_root, source_file },
- ) catch unreachable;
- if (os.path.dirname(cache_o_src)) |cache_o_dir| {
- try builder.makePath(cache_o_dir);
- }
- const cache_o_file = builder.fmt("{}{}", cache_o_src, self.target.oFileExt());
- cc_args.append("-o") catch unreachable;
- cc_args.append(builder.pathFromRoot(cache_o_file)) catch unreachable;
-
- self.appendCompileFlags(&cc_args);
-
- try builder.spawnChild(cc_args.toSliceConst());
-
- self.object_files.append(cache_o_file) catch unreachable;
- }
-
- if (self.static) {
- // ar
- cc_args.resize(0) catch unreachable;
- cc_args.append("ar") catch unreachable;
-
- cc_args.append("qc") catch unreachable;
-
- const output_path = builder.pathFromRoot(self.getOutputPath());
- cc_args.append(output_path) catch unreachable;
-
- for (self.object_files.toSliceConst()) |object_file| {
- cc_args.append(builder.pathFromRoot(object_file)) catch unreachable;
- }
-
- try builder.spawnChild(cc_args.toSliceConst());
-
- // ranlib
- cc_args.resize(0) catch unreachable;
- cc_args.append("ranlib") catch unreachable;
- cc_args.append(output_path) catch unreachable;
-
- try builder.spawnChild(cc_args.toSliceConst());
- } else {
- cc_args.resize(0) catch unreachable;
- cc_args.append(cc) catch unreachable;
-
- if (is_darwin) {
- cc_args.append("-dynamiclib") catch unreachable;
-
- cc_args.append("-Wl,-headerpad_max_install_names") catch unreachable;
-
- cc_args.append("-compatibility_version") catch unreachable;
- cc_args.append(builder.fmt("{}.0.0", self.version.major)) catch unreachable;
-
- cc_args.append("-current_version") catch unreachable;
- cc_args.append(builder.fmt("{}.{}.{}", self.version.major, self.version.minor, self.version.patch)) catch unreachable;
-
- const install_name = builder.pathFromRoot(os.path.join(
- builder.allocator,
- [][]const u8{ builder.cache_root, self.major_only_filename },
- ) catch unreachable);
- cc_args.append("-install_name") catch unreachable;
- cc_args.append(install_name) catch unreachable;
- } else {
- cc_args.append("-fPIC") catch unreachable;
- cc_args.append("-shared") catch unreachable;
-
- const soname_arg = builder.fmt("-Wl,-soname,lib{}.so.{d}", self.name, self.version.major);
- defer builder.allocator.free(soname_arg);
- cc_args.append(soname_arg) catch unreachable;
- }
-
- const output_path = builder.pathFromRoot(self.getOutputPath());
- cc_args.append("-o") catch unreachable;
- cc_args.append(output_path) catch unreachable;
-
- for (self.object_files.toSliceConst()) |object_file| {
- cc_args.append(builder.pathFromRoot(object_file)) catch unreachable;
- }
-
- if (!is_darwin) {
- const rpath_arg = builder.fmt("-Wl,-rpath,{}", try os.path.realAlloc(
- builder.allocator,
- builder.pathFromRoot(builder.cache_root),
- ));
- defer builder.allocator.free(rpath_arg);
- try cc_args.append(rpath_arg);
-
- try cc_args.append("-rdynamic");
- }
-
- for (self.full_path_libs.toSliceConst()) |full_path_lib| {
- cc_args.append(builder.pathFromRoot(full_path_lib)) catch unreachable;
- }
-
- {
- var it = self.link_libs.iterator();
- while (it.next()) |entry| {
- cc_args.append(builder.fmt("-l{}", entry.key)) catch unreachable;
- }
- }
-
- if (is_darwin and !self.static) {
- var it = self.frameworks.iterator();
- while (it.next()) |entry| {
- cc_args.append("-framework") catch unreachable;
- cc_args.append(entry.key) catch unreachable;
- }
- }
-
- try builder.spawnChild(cc_args.toSliceConst());
-
- if (self.target.wantSharedLibSymLinks()) {
- try doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename, self.name_only_filename);
- }
- }
- },
- Kind.Exe => {
- for (self.source_files.toSliceConst()) |source_file| {
- cc_args.resize(0) catch unreachable;
- cc_args.append(cc) catch unreachable;
-
- const abs_source_file = builder.pathFromRoot(source_file);
- cc_args.append("-c") catch unreachable;
- cc_args.append(abs_source_file) catch unreachable;
-
- const cache_o_src = os.path.join(
- builder.allocator,
- [][]const u8{ builder.cache_root, source_file },
- ) catch unreachable;
- if (os.path.dirname(cache_o_src)) |cache_o_dir| {
- try builder.makePath(cache_o_dir);
- }
- const cache_o_file = builder.fmt("{}{}", cache_o_src, self.target.oFileExt());
- cc_args.append("-o") catch unreachable;
- cc_args.append(builder.pathFromRoot(cache_o_file)) catch unreachable;
-
- for (self.cflags.toSliceConst()) |cflag| {
- cc_args.append(cflag) catch unreachable;
- }
-
- for (self.include_dirs.toSliceConst()) |dir| {
- cc_args.append("-I") catch unreachable;
- cc_args.append(builder.pathFromRoot(dir)) catch unreachable;
- }
-
- try builder.spawnChild(cc_args.toSliceConst());
-
- self.object_files.append(cache_o_file) catch unreachable;
- }
-
- cc_args.resize(0) catch unreachable;
- cc_args.append(cc) catch unreachable;
-
- for (self.object_files.toSliceConst()) |object_file| {
- cc_args.append(builder.pathFromRoot(object_file)) catch unreachable;
- }
-
- const output_path = builder.pathFromRoot(self.getOutputPath());
- cc_args.append("-o") catch unreachable;
- cc_args.append(output_path) catch unreachable;
-
- const rpath_arg = builder.fmt("-Wl,-rpath,{}", try os.path.realAlloc(
- builder.allocator,
- builder.pathFromRoot(builder.cache_root),
- ));
- defer builder.allocator.free(rpath_arg);
- try cc_args.append(rpath_arg);
-
- try cc_args.append("-rdynamic");
-
- {
- var it = self.link_libs.iterator();
- while (it.next()) |entry| {
- cc_args.append(builder.fmt("-l{}", entry.key)) catch unreachable;
- }
- }
-
- if (is_darwin) {
- if (self.need_flat_namespace_hack) {
- cc_args.append("-Wl,-flat_namespace") catch unreachable;
- }
- cc_args.append("-Wl,-search_paths_first") catch unreachable;
- }
-
- for (self.full_path_libs.toSliceConst()) |full_path_lib| {
- cc_args.append(builder.pathFromRoot(full_path_lib)) catch unreachable;
- }
-
- if (is_darwin) {
- var it = self.frameworks.iterator();
- while (it.next()) |entry| {
- cc_args.append("-framework") catch unreachable;
- cc_args.append(entry.key) catch unreachable;
- }
- }
-
- try builder.spawnChild(cc_args.toSliceConst());
- },
- }
- }
-};
-
-pub const TestStep = struct {
- step: Step,
- builder: *Builder,
- root_src: []const u8,
- build_mode: builtin.Mode,
- verbose: bool,
- link_libs: BufSet,
- name_prefix: []const u8,
- filter: ?[]const u8,
- target: Target,
- exec_cmd_args: ?[]const ?[]const u8,
- include_dirs: ArrayList([]const u8),
- lib_paths: ArrayList([]const u8),
- packages: ArrayList(Pkg),
- object_files: ArrayList([]const u8),
- no_rosegment: bool,
- output_path: ?[]const u8,
- system_linker_hack: bool,
- override_std_dir: ?[]const u8,
-
- pub fn init(builder: *Builder, root_src: []const u8) TestStep {
- const step_name = builder.fmt("test {}", root_src);
- return TestStep{
- .step = Step.init(step_name, builder.allocator, make),
- .builder = builder,
- .root_src = root_src,
- .build_mode = builtin.Mode.Debug,
- .verbose = false,
- .name_prefix = "",
- .filter = null,
- .link_libs = BufSet.init(builder.allocator),
- .target = Target{ .Native = {} },
- .exec_cmd_args = null,
- .include_dirs = ArrayList([]const u8).init(builder.allocator),
- .lib_paths = ArrayList([]const u8).init(builder.allocator),
- .packages = ArrayList(Pkg).init(builder.allocator),
- .object_files = ArrayList([]const u8).init(builder.allocator),
- .no_rosegment = false,
- .output_path = null,
- .system_linker_hack = false,
- .override_std_dir = null,
- };
- }
-
- pub fn setNoRoSegment(self: *TestStep, value: bool) void {
- self.no_rosegment = value;
- }
-
- pub fn addLibPath(self: *TestStep, path: []const u8) void {
- self.lib_paths.append(path) catch unreachable;
- }
-
- pub fn addPackagePath(self: *TestStep, name: []const u8, pkg_index_path: []const u8) void {
- self.packages.append(Pkg{
- .name = name,
- .path = pkg_index_path,
- }) catch unreachable;
- }
-
- pub fn setVerbose(self: *TestStep, value: bool) void {
- self.verbose = value;
- }
-
- pub fn addIncludeDir(self: *TestStep, path: []const u8) void {
- self.include_dirs.append(path) catch unreachable;
- }
-
- pub fn setBuildMode(self: *TestStep, mode: builtin.Mode) void {
- self.build_mode = mode;
- }
-
- pub fn overrideStdDir(self: *TestStep, dir_path: []const u8) void {
- self.override_std_dir = dir_path;
- }
-
- pub fn setOutputPath(self: *TestStep, file_path: []const u8) void {
- self.output_path = file_path;
-
- // catch a common mistake
- if (mem.eql(u8, self.builder.pathFromRoot(file_path), self.builder.pathFromRoot("."))) {
- debug.panic("setOutputPath wants a file path, not a directory\n");
- }
- }
-
- pub fn getOutputPath(self: *TestStep) []const u8 {
- if (self.output_path) |output_path| {
- return output_path;
- } else {
- const basename = self.builder.fmt("test{}", self.target.exeFileExt());
- return os.path.join(
- self.builder.allocator,
- [][]const u8{ self.builder.cache_root, basename },
- ) catch unreachable;
- }
- }
-
- pub fn linkSystemLibrary(self: *TestStep, name: []const u8) void {
- self.link_libs.put(name) catch unreachable;
- }
-
- pub fn setNamePrefix(self: *TestStep, text: []const u8) void {
- self.name_prefix = text;
- }
-
- pub fn setFilter(self: *TestStep, text: ?[]const u8) void {
- self.filter = text;
- }
-
- pub fn addObject(self: *TestStep, obj: *LibExeObjStep) void {
- assert(obj.kind == LibExeObjStep.Kind.Obj);
-
- self.step.dependOn(&obj.step);
-
- self.object_files.append(obj.getOutputPath()) catch unreachable;
-
- // TODO should be some kind of isolated directory that only has this header in it
- self.include_dirs.append(self.builder.cache_root) catch unreachable;
- }
-
- pub fn addObjectFile(self: *TestStep, path: []const u8) void {
- self.object_files.append(path) catch unreachable;
- }
-
- pub fn setTarget(self: *TestStep, target_arch: builtin.Arch, target_os: builtin.Os, target_environ: builtin.Environ) void {
- self.target = Target{
- .Cross = CrossTarget{
- .arch = target_arch,
- .os = target_os,
- .environ = target_environ,
- },
- };
- }
-
- pub fn setExecCmd(self: *TestStep, args: []const ?[]const u8) void {
- self.exec_cmd_args = args;
- }
-
- pub fn enableSystemLinkerHack(self: *TestStep) void {
- self.system_linker_hack = true;
- }
-
- fn make(step: *Step) !void {
- const self = @fieldParentPtr(TestStep, "step", step);
- const builder = self.builder;
-
- var zig_args = ArrayList([]const u8).init(builder.allocator);
- defer zig_args.deinit();
-
- try zig_args.append(builder.zig_exe);
-
- try zig_args.append("test");
- try zig_args.append(builder.pathFromRoot(self.root_src));
-
- if (self.verbose) {
- try zig_args.append("--verbose");
- }
-
- switch (self.build_mode) {
- builtin.Mode.Debug => {},
- builtin.Mode.ReleaseSafe => try zig_args.append("--release-safe"),
- builtin.Mode.ReleaseFast => try zig_args.append("--release-fast"),
- builtin.Mode.ReleaseSmall => try zig_args.append("--release-small"),
- }
-
- const output_path = builder.pathFromRoot(self.getOutputPath());
- try zig_args.append("--output");
- try zig_args.append(output_path);
-
- switch (self.target) {
- Target.Native => {},
- Target.Cross => |cross_target| {
- try zig_args.append("--target-arch");
- try zig_args.append(@tagName(cross_target.arch));
-
- try zig_args.append("--target-os");
- try zig_args.append(@tagName(cross_target.os));
-
- try zig_args.append("--target-environ");
- try zig_args.append(@tagName(cross_target.environ));
- },
- }
-
- if (self.filter) |filter| {
- try zig_args.append("--test-filter");
- try zig_args.append(filter);
- }
-
- if (self.name_prefix.len != 0) {
- try zig_args.append("--test-name-prefix");
- try zig_args.append(self.name_prefix);
- }
-
- for (self.object_files.toSliceConst()) |object_file| {
- try zig_args.append("--object");
- try zig_args.append(builder.pathFromRoot(object_file));
- }
-
- {
- var it = self.link_libs.iterator();
- while (true) {
- const entry = it.next() orelse break;
- try zig_args.append("--library");
- try zig_args.append(entry.key);
- }
- }
-
- if (self.exec_cmd_args) |exec_cmd_args| {
- for (exec_cmd_args) |cmd_arg| {
- if (cmd_arg) |arg| {
- try zig_args.append("--test-cmd");
- try zig_args.append(arg);
- } else {
- try zig_args.append("--test-cmd-bin");
- }
- }
- }
-
- for (self.include_dirs.toSliceConst()) |include_path| {
- try zig_args.append("-isystem");
- try zig_args.append(builder.pathFromRoot(include_path));
- }
-
- for (builder.include_paths.toSliceConst()) |include_path| {
- try zig_args.append("-isystem");
- try zig_args.append(builder.pathFromRoot(include_path));
- }
-
- for (builder.rpaths.toSliceConst()) |rpath| {
- try zig_args.append("-rpath");
- try zig_args.append(rpath);
- }
-
- for (self.lib_paths.toSliceConst()) |lib_path| {
- try zig_args.append("--library-path");
- try zig_args.append(lib_path);
- }
-
- for (builder.lib_paths.toSliceConst()) |lib_path| {
- try zig_args.append("--library-path");
- try zig_args.append(lib_path);
- }
-
- for (self.packages.toSliceConst()) |pkg| {
- zig_args.append("--pkg-begin") catch unreachable;
- zig_args.append(pkg.name) catch unreachable;
- zig_args.append(builder.pathFromRoot(pkg.path)) catch unreachable;
- zig_args.append("--pkg-end") catch unreachable;
- }
-
- if (self.no_rosegment) {
- try zig_args.append("--no-rosegment");
- }
- if (self.system_linker_hack) {
- try zig_args.append("--system-linker-hack");
- }
if (self.override_std_dir) |dir| {
try zig_args.append("--override-std-dir");
try zig_args.append(builder.pathFromRoot(dir));
}
try builder.spawnChild(zig_args.toSliceConst());
+
+ if (self.kind == Kind.Lib and !self.static and self.target.wantSharedLibSymLinks()) {
+ try doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename, self.name_only_filename);
+ }
}
};
@@ -1995,6 +1474,7 @@ const InstallArtifactStep = struct {
pub fn create(builder: *Builder, artifact: *LibExeObjStep) *Self {
const dest_dir = switch (artifact.kind) {
LibExeObjStep.Kind.Obj => unreachable,
+ LibExeObjStep.Kind.Test => unreachable,
LibExeObjStep.Kind.Exe => builder.exe_dir,
LibExeObjStep.Kind.Lib => builder.lib_dir,
};
@@ -2031,6 +1511,7 @@ const InstallArtifactStep = struct {
builtin.Os.windows => {},
else => switch (self.artifact.kind) {
LibExeObjStep.Kind.Obj => unreachable,
+ LibExeObjStep.Kind.Test => unreachable,
LibExeObjStep.Kind.Exe => u32(0o755),
LibExeObjStep.Kind.Lib => if (self.artifact.static) u32(0o666) else u32(0o755),
},
diff --git a/std/build/fmt.zig b/std/build/fmt.zig
@@ -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);
+ }
+};
diff --git a/std/c/darwin.zig b/std/c/darwin.zig
@@ -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 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
/// 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
/// 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 = macho.mach_header;
diff --git a/std/c/index.zig b/std/c/index.zig
@@ -6,6 +6,7 @@ pub use switch (builtin.os) {
Os.windows => @import("windows.zig"),
Os.macosx, Os.ios => @import("darwin.zig"),
Os.freebsd => @import("freebsd.zig"),
+ Os.netbsd => @import("netbsd.zig"),
else => empty_import,
};
const empty_import = @import("../empty.zig");
diff --git a/std/c/netbsd.zig b/std/c/netbsd.zig
@@ -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,
+};
diff --git a/std/debug/index.zig b/std/debug/index.zig
@@ -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.
/// 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 debug_info = getSelfDebugInfo() catch |err| {
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();
stderr.print(format ++ "\n", args) catch os.abort();
if (trace) |t| {
- dumpStackTrace(t);
+ dumpStackTrace(t.*);
}
dumpCurrentStackTrace(first_trace_addr);
@@ -155,16 +206,15 @@ const WHITE = "\x1b[37;1m";
const DIM = "\x1b[2m";
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 {
- var frame_index: usize = undefined;
- var frames_left: usize = undefined;
- if (stack_trace.index < stack_trace.instruction_addresses.len) {
- frame_index = 0;
- frames_left = stack_trace.index;
- } else {
- frame_index = (stack_trace.index + 1) % stack_trace.instruction_addresses.len;
- frames_left = stack_trace.instruction_addresses.len;
- }
+pub fn writeStackTrace(
+ stack_trace: builtin.StackTrace,
+ out_stream: var,
+ allocator: *mem.Allocator,
+ debug_info: *DebugInfo,
+ tty_color: bool,
+) !void {
+ var frame_index: usize = 0;
+ var frames_left: usize = stack_trace.index;
while (frames_left != 0) : ({
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 {
switch (builtin.os) {
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),
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 {
- const base_addr = @ptrToInt(&std.c._mh_execute_header);
+ const base_addr = std.os.getBaseAddress();
const adjusted_addr = 0x100000000 + (address - base_addr);
const symbol = machoSearchSymbols(di.symbols, adjusted_addr) orelse {
@@ -717,7 +767,7 @@ pub const OpenSelfDebugInfoError = error{
pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo {
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.windows => return openSelfDebugInfoWindows(allocator),
else => return error.UnsupportedOperatingSystem,
@@ -1141,7 +1191,7 @@ pub const DebugInfo = switch (builtin.os) {
sect_contribs: []pdb.SectionContribEntry,
modules: []Module,
},
- builtin.Os.linux, builtin.Os.freebsd => DwarfInfo,
+ builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => DwarfInfo,
else => @compileError("Unsupported OS"),
};
diff --git a/std/event/fs.zig b/std/event/fs.zig
@@ -85,6 +85,7 @@ pub async fn pwritev(loop: *Loop, fd: os.FileHandle, data: []const []const u8, o
builtin.Os.macosx,
builtin.Os.linux,
builtin.Os.freebsd,
+ builtin.Os.netbsd,
=> {
const iovecs = try loop.allocator.alloc(os.posix.iovec_const, data.len);
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.linux,
builtin.Os.freebsd,
+ builtin.Os.netbsd,
=> {
const iovecs = try loop.allocator.alloc(os.posix.iovec, data.len);
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 {
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;
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.linux,
builtin.Os.freebsd,
+ builtin.Os.netbsd,
=> {
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);
@@ -453,7 +460,7 @@ pub async fn openReadWrite(
mode: os.File.Mode,
) os.File.OpenError!os.FileHandle {
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;
return await (async openPosix(loop, path, flags, mode) catch unreachable);
},
@@ -481,7 +488,7 @@ pub const CloseOperation = struct {
os_data: OsData,
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 {
handle: ?os.FileHandle,
@@ -500,7 +507,7 @@ pub const CloseOperation = struct {
self.* = CloseOperation{
.loop = loop,
.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 },
else => @compileError("Unsupported OS"),
},
@@ -530,6 +537,7 @@ pub const CloseOperation = struct {
builtin.Os.linux,
builtin.Os.macosx,
builtin.Os.freebsd,
+ builtin.Os.netbsd,
=> {
if (self.os_data.have_fd) {
self.loop.posixFsRequest(&self.os_data.close_req_node);
@@ -552,6 +560,7 @@ pub const CloseOperation = struct {
builtin.Os.linux,
builtin.Os.macosx,
builtin.Os.freebsd,
+ builtin.Os.netbsd,
=> {
self.os_data.close_req_node.data.msg.Close.fd = handle;
self.os_data.have_fd = true;
@@ -569,6 +578,7 @@ pub const CloseOperation = struct {
builtin.Os.linux,
builtin.Os.macosx,
builtin.Os.freebsd,
+ builtin.Os.netbsd,
=> {
self.os_data.have_fd = false;
},
@@ -584,6 +594,7 @@ pub const CloseOperation = struct {
builtin.Os.linux,
builtin.Os.macosx,
builtin.Os.freebsd,
+ builtin.Os.netbsd,
=> {
assert(self.os_data.have_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.macosx,
builtin.Os.freebsd,
+ builtin.Os.netbsd,
=> return await (async writeFileModeThread(loop, path, contents, mode) catch unreachable),
builtin.Os.windows => return await (async writeFileWindows(loop, path, contents) catch unreachable),
else => @compileError("Unsupported OS"),
@@ -713,7 +725,7 @@ pub fn Watch(comptime V: type) type {
os_data: OsData,
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,
table_lock: event.Lock,
@@ -802,7 +814,7 @@ pub fn Watch(comptime V: type) type {
return self;
},
- builtin.Os.macosx, builtin.Os.freebsd => {
+ builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
const self = try loop.allocator.create(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.
pub fn destroy(self: *Self) void {
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
self.os_data.table_lock.deinit();
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 {
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.windows => return await (async addFileWindows(self, file_path, value) catch unreachable),
else => @compileError("Unsupported OS"),
diff --git a/std/event/loop.zig b/std/event/loop.zig
@@ -50,7 +50,7 @@ pub const Loop = struct {
};
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 {
base: ResumeNode,
epoll_op: u32,
@@ -69,7 +69,7 @@ pub const Loop = struct {
};
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 {
base: ResumeNode,
},
@@ -221,7 +221,7 @@ pub const Loop = struct {
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();
errdefer os.close(self.os_data.kqfd);
@@ -386,7 +386,7 @@ pub const Loop = struct {
os.close(self.os_data.epollfd);
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.fs_kqfd);
},
@@ -501,7 +501,7 @@ pub const Loop = struct {
const eventfd_node = &resume_stack_node.data;
eventfd_node.base.handle = next_tick_node.data;
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 empty_kevs = ([*]posix.Kevent)(undefined)[0..0];
_ = 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.macosx,
builtin.Os.freebsd,
+ builtin.Os.netbsd,
=> self.os_data.fs_thread.wait(),
else => {},
}
@@ -628,7 +629,7 @@ pub const Loop = struct {
os.posixWrite(self.os_data.final_eventfd, wakeup_bytes) catch unreachable;
return;
},
- builtin.Os.macosx, builtin.Os.freebsd => {
+ builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
self.posixFsRequest(&self.os_data.fs_end_request);
const final_kevent = (*[1]posix.Kevent)(&self.os_data.final_kevent);
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;
const empty_kevs = ([*]posix.Kevent)(undefined)[0..0];
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.os_data.fs_queue.put(request_node);
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 empty_kevs = ([*]posix.Kevent)(undefined)[0..0];
_ = os.bsdKEvent(self.os_data.fs_kqfd, fs_kevs, empty_kevs, null) catch unreachable;
@@ -819,7 +820,7 @@ pub const Loop = struct {
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);
var out_kevs: [1]posix.Kevent = undefined;
_ = 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) {
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 {
io_port: windows.HANDLE,
extra_thread_count: usize,
diff --git a/std/fmt/index.zig b/std/fmt/index.zig
@@ -236,6 +236,9 @@ pub fn formatType(
const casted_value = ([]const u8)(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| {
if (info.child == u8) {
@@ -828,7 +831,7 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsigned
return x;
}
-test "parseUnsigned" {
+test "fmt.parseUnsigned" {
testing.expect((try parseUnsigned(u16, "050124", 10)) == 50124);
testing.expect((try parseUnsigned(u16, "65535", 10)) == 65535);
testing.expectError(error.Overflow, parseUnsigned(u16, "65536", 10));
@@ -855,6 +858,12 @@ test "parseUnsigned" {
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) {
const value = switch (c) {
'0'...'9' => c - '0',
@@ -1109,7 +1118,7 @@ test "fmt.format" {
const result = try bufPrint(buf1[0..], "f64: {}\n", math.nan_f64);
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,
// and ARM thus normalizes it to positive nan
var buf1: [32]u8 = undefined;
diff --git a/std/fmt/parse_float.zig b/std/fmt/parse_float.zig
@@ -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));
+ }
+ }
+}
diff --git a/std/hash_map.zig b/std/hash_map.zig
@@ -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.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.C => @compileError("TODO auto hash C pointers"),
builtin.TypeInfo.Pointer.Size.Slice => {
const interval = std.math.max(1, key.len / 256);
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.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.C => @compileError("TODO auto eql for C pointers"),
builtin.TypeInfo.Pointer.Size.Slice => {
if (a.len != b.len) return false;
for (a) |a_item, i| {
diff --git a/std/heap.zig b/std/heap.zig
@@ -71,7 +71,7 @@ pub const DirectAllocator = struct {
const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);
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 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);
@@ -120,7 +120,7 @@ pub const DirectAllocator = struct {
const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);
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) {
const base_addr = @ptrToInt(old_mem.ptr);
const old_addr_end = base_addr + old_mem.len;
@@ -164,7 +164,7 @@ pub const DirectAllocator = struct {
const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);
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.windows => {
diff --git a/std/index.zig b/std/index.zig
@@ -9,6 +9,7 @@ pub const DynLib = @import("dynamic_library.zig").DynLib;
pub const HashMap = @import("hash_map.zig").HashMap;
pub const LinkedList = @import("linked_list.zig").LinkedList;
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 SegmentedList = @import("segmented_list.zig").SegmentedList;
pub const SpinLock = @import("spinlock.zig").SpinLock;
@@ -59,7 +60,7 @@ test "std" {
_ = @import("statically_initialized_mutex.zig");
_ = @import("segmented_list.zig");
_ = @import("spinlock.zig");
-
+
_ = @import("base64.zig");
_ = @import("build.zig");
_ = @import("c/index.zig");
@@ -85,6 +86,7 @@ test "std" {
_ = @import("net.zig");
_ = @import("os/index.zig");
_ = @import("pdb.zig");
+ _ = @import("priority_queue.zig");
_ = @import("rand/index.zig");
_ = @import("sort.zig");
_ = @import("testing.zig");
diff --git a/std/io.zig b/std/io.zig
@@ -343,23 +343,24 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type)
const amt_buffered = self.end_index - self.start_index;
if (amt_buffered == 0) {
assert(self.end_index <= buffer_size);
- if (self.end_index == buffer_size) {
- // we can read more data from the unbuffered stream
- if (dest_space < buffer_size) {
- self.start_index = 0;
- self.end_index = try self.unbuffered_in_stream.read(self.buffer[0..]);
- } else {
- // asking for so much data that buffering is actually less efficient.
- // forward the request directly to the unbuffered stream
- const amt_read = try self.unbuffered_in_stream.read(dest[dest_index..]);
- return dest_index + amt_read;
- }
- } else {
- // reading from the unbuffered stream returned less than we asked for
- // so we cannot read any more data.
+ // 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
+ if (dest_space < buffer_size) {
+ self.start_index = 0;
+ self.end_index = try self.unbuffered_in_stream.read(self.buffer[0..]);
+ } else {
+ // asking for so much data that buffering is actually less efficient.
+ // forward the request directly to the unbuffered stream
+ const amt_read = try self.unbuffered_in_stream.read(dest[dest_index..]);
+ return dest_index + amt_read;
+ }
}
+
const copy_amount = math.min(dest_space, amt_buffered);
const copy_end_index = self.start_index + copy_amount;
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.
/// This makes look-ahead style parsing much easier.
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 {
atomic_file: os.AtomicFile,
file_stream: os.File.OutStream,
@@ -978,7 +1017,6 @@ pub const BufferedAtomicFile = struct {
}
};
-
pub fn readLine(buf: *std.Buffer) ![]u8 {
var stdin = try getStdIn();
var stdin_stream = stdin.inStream();
@@ -1073,13 +1111,13 @@ pub fn Deserializer(comptime endian: builtin.Endian, is_packed: bool, comptime E
else => in_stream,
} };
}
-
+
pub fn alignToByte(self: *Self) void {
- if(!is_packed) return;
+ if (!is_packed) return;
self.in_stream.alignToByte();
}
- //@BUG: inferred error issue. See: #1386
+ //@BUG: inferred error issue. See: #1386
fn deserializeInt(self: *Self, comptime T: type) (Error || error{EndOfStream})!T {
comptime assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T));
@@ -1088,7 +1126,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, is_packed: bool, comptime E
const U = @IntType(false, t_bit_count);
const Log2U = math.Log2Int(U);
- const int_size = @sizeOf(U);
+ const int_size = (U.bit_count + 7) / 8;
if (is_packed) {
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 Log2U = math.Log2Int(U);
- const int_size = @sizeOf(U);
+ const int_size = (U.bit_count + 7) / 8;
const u_value = @bitCast(U, value);
@@ -1414,3 +1452,4 @@ test "import io tests" {
_ = @import("io_test.zig");
}
}
+
diff --git a/std/io_test.zig b/std/io_test.zig
@@ -29,6 +29,17 @@ test "write a file, read it, then delete it" {
try st.print("end");
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);
defer file.close();
diff --git a/std/json.zig b/std/json.zig
@@ -1345,7 +1345,7 @@ pub const Parser = struct {
return if (token.number_is_integer)
Value{ .Integer = try std.fmt.parseInt(i64, token.slice(input, i), 10) }
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,
\\ "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;
testing.expect(mem.eql(u8, obj0.String, "m"));
+
+ const double = image.Object.get("double").?.value;
+ testing.expect(double.Float == 1.3412);
}
diff --git a/std/math/fabs.zig b/std/math/fabs.zig
@@ -14,6 +14,7 @@ pub fn fabs(x: var) @typeOf(x) {
f16 => fabs16(x),
f32 => fabs32(x),
f64 => fabs64(x),
+ f128 => fabs128(x),
else => @compileError("fabs not implemented for " ++ @typeName(T)),
};
}
@@ -36,10 +37,17 @@ fn fabs64(x: f64) f64 {
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" {
expect(fabs(f16(1.0)) == fabs16(1.0));
expect(fabs(f32(1.0)) == fabs32(1.0));
expect(fabs(f64(1.0)) == fabs64(1.0));
+ expect(fabs(f128(1.0)) == fabs128(1.0));
}
test "math.fabs16" {
@@ -57,6 +65,11 @@ test "math.fabs64" {
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" {
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.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))));
+}
diff --git a/std/math/index.zig b/std/math/index.zig
@@ -51,6 +51,12 @@ pub const nan_f64 = @bitCast(f64, nan_u64);
pub const inf_u64 = u64(0x7FF << 52);
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 snan = @import("nan.zig").snan;
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;
}
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 upper = (1 << 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(u32) == 4294967295);
testing.expect(maxInt(u64) == 18446744073709551615);
+ testing.expect(maxInt(u128) == 340282366920938463463374607431768211455);
testing.expect(maxInt(i0) == 0);
testing.expect(maxInt(i1) == 0);
@@ -760,6 +767,7 @@ test "minInt and maxInt" {
testing.expect(maxInt(i32) == 2147483647);
testing.expect(maxInt(i63) == 4611686018427387903);
testing.expect(maxInt(i64) == 9223372036854775807);
+ testing.expect(maxInt(i128) == 170141183460469231731687303715884105727);
testing.expect(minInt(u0) == 0);
testing.expect(minInt(u1) == 0);
@@ -768,6 +776,7 @@ test "minInt and maxInt" {
testing.expect(minInt(u32) == 0);
testing.expect(minInt(u63) == 0);
testing.expect(minInt(u64) == 0);
+ testing.expect(minInt(u128) == 0);
testing.expect(minInt(i0) == 0);
testing.expect(minInt(i1) == -1);
@@ -776,6 +785,7 @@ test "minInt and maxInt" {
testing.expect(minInt(i32) == -2147483648);
testing.expect(minInt(i63) == -4611686018427387904);
testing.expect(minInt(i64) == -9223372036854775808);
+ testing.expect(minInt(i128) == -170141183460469231731687303715884105728);
}
test "max value type" {
diff --git a/std/math/inf.zig b/std/math/inf.zig
@@ -3,9 +3,10 @@ const math = std.math;
pub fn inf(comptime T: type) T {
return switch (T) {
- f16 => @bitCast(f16, math.inf_u16),
- f32 => @bitCast(f32, math.inf_u32),
- f64 => @bitCast(f64, math.inf_u64),
+ f16 => math.inf_f16,
+ f32 => math.inf_f32,
+ f64 => math.inf_f64,
+ f128 => math.inf_f128,
else => @compileError("inf not implemented for " ++ @typeName(T)),
};
}
diff --git a/std/math/isinf.zig b/std/math/isinf.zig
@@ -18,6 +18,10 @@ pub fn isInf(x: var) bool {
const bits = @bitCast(u64, x);
return bits & (maxInt(u64) >> 1) == (0x7FF << 52);
},
+ f128 => {
+ const bits = @bitCast(u128, x);
+ return bits & (maxInt(u128) >> 1) == (0x7FFF << 112);
+ },
else => {
@compileError("isInf not implemented for " ++ @typeName(T));
},
@@ -36,6 +40,9 @@ pub fn isPositiveInf(x: var) bool {
f64 => {
return @bitCast(u64, x) == 0x7FF << 52;
},
+ f128 => {
+ return @bitCast(u128, x) == 0x7FFF << 112;
+ },
else => {
@compileError("isPositiveInf not implemented for " ++ @typeName(T));
},
@@ -54,6 +61,9 @@ pub fn isNegativeInf(x: var) bool {
f64 => {
return @bitCast(u64, x) == 0xFFF << 52;
},
+ f128 => {
+ return @bitCast(u128, x) == 0xFFFF << 112;
+ },
else => {
@compileError("isNegativeInf not implemented for " ++ @typeName(T));
},
@@ -67,12 +77,16 @@ test "math.isInf" {
expect(!isInf(f32(-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(f32)));
expect(isInf(-math.inf(f32)));
expect(isInf(math.inf(f64)));
expect(isInf(-math.inf(f64)));
+ expect(isInf(math.inf(f128)));
+ expect(isInf(-math.inf(f128)));
}
test "math.isPositiveInf" {
@@ -82,12 +96,16 @@ test "math.isPositiveInf" {
expect(!isPositiveInf(f32(-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(f32)));
expect(!isPositiveInf(-math.inf(f32)));
expect(isPositiveInf(math.inf(f64)));
expect(!isPositiveInf(-math.inf(f64)));
+ expect(isPositiveInf(math.inf(f128)));
+ expect(!isPositiveInf(-math.inf(f128)));
}
test "math.isNegativeInf" {
@@ -97,10 +115,14 @@ test "math.isNegativeInf" {
expect(!isNegativeInf(f32(-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(f32)));
expect(isNegativeInf(-math.inf(f32)));
expect(!isNegativeInf(math.inf(f64)));
expect(isNegativeInf(-math.inf(f64)));
+ expect(!isNegativeInf(math.inf(f128)));
+ expect(isNegativeInf(-math.inf(f128)));
}
diff --git a/std/math/isnan.zig b/std/math/isnan.zig
@@ -18,6 +18,10 @@ pub fn isNan(x: var) bool {
const bits = @bitCast(u64, x);
return (bits & (maxInt(u64) >> 1)) > (u64(0x7FF) << 52);
},
+ f128 => {
+ const bits = @bitCast(u128, x);
+ return (bits & (maxInt(u128) >> 1)) > (u128(0x7FFF) << 112);
+ },
else => {
@compileError("isNan not implemented for " ++ @typeName(T));
},
@@ -34,7 +38,9 @@ test "math.isNan" {
expect(isNan(math.nan(f16)));
expect(isNan(math.nan(f32)));
expect(isNan(math.nan(f64)));
+ expect(isNan(math.nan(f128)));
expect(!isNan(f16(1.0)));
expect(!isNan(f32(1.0)));
expect(!isNan(f64(1.0)));
+ expect(!isNan(f128(1.0)));
}
diff --git a/std/math/nan.zig b/std/math/nan.zig
@@ -2,9 +2,10 @@ const math = @import("index.zig");
pub fn nan(comptime T: type) T {
return switch (T) {
- f16 => @bitCast(f16, math.nan_u16),
- f32 => @bitCast(f32, math.nan_u32),
- f64 => @bitCast(f64, math.nan_u64),
+ f16 => math.nan_f16,
+ f32 => math.nan_f32,
+ f64 => math.nan_f64,
+ f128 => math.nan_f128,
else => @compileError("nan not implemented for " ++ @typeName(T)),
};
}
diff --git a/std/math/powi.zig b/std/math/powi.zig
@@ -25,7 +25,7 @@ pub fn powi(comptime T: type, x: T, y: T) (error{
// powi(x, +-0) = 1 for any x
if (y == 0 or y == -0) {
- return 0;
+ return 1;
}
switch (x) {
@@ -174,4 +174,11 @@ test "math.powi.special" {
testing.expectError(error.Overflow, powi(u64, 2, 64));
testing.expectError(error.Overflow, powi(u17, 2, 17));
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);
}
diff --git a/std/mem.zig b/std/mem.zig
@@ -423,8 +423,7 @@ pub fn readVarInt(comptime ReturnType: type, bytes: []const u8, endian: builtin.
/// This function cannot fail and cannot cause undefined behavior.
/// Assumes the endianness of memory is native. This means the function can
/// simply pointer cast memory.
-pub fn readIntNative(comptime T: type, bytes: *const [@sizeOf(T)]u8) T {
- comptime assert(T.bit_count % 8 == 0);
+pub fn readIntNative(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)]u8) T {
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.
/// This function cannot fail and cannot cause undefined behavior.
/// 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));
}
@@ -446,22 +445,20 @@ pub const readIntBig = switch (builtin.endian) {
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.
-/// Note that @sizeOf(u24) is 3.
/// The bit count of T must be evenly divisible by 8.
/// Assumes the endianness of memory is native. This means the function can
/// simply pointer cast memory.
pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T {
- assert(@sizeOf(u24) == 3);
- assert(bytes.len >= @sizeOf(T));
+ const n = @divExact(T.bit_count, 8);
+ assert(bytes.len >= n);
// 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.
-/// Note that @sizeOf(u24) is 3.
/// The bit count of T must be evenly divisible by 8.
/// Assumes the endianness of memory is foreign, so it must byte-swap.
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.
/// The bit count of T must be evenly divisible by 8.
/// 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) {
return readIntNative(T, bytes);
} 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.
-/// Note that @sizeOf(u24) is 3.
/// The bit count of T must be evenly divisible by 8.
pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) T {
- assert(@sizeOf(u24) == 3);
- assert(bytes.len >= @sizeOf(T));
+ const n = @divExact(T.bit_count, 8);
+ assert(bytes.len >= n);
// 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" {
@@ -540,7 +536,7 @@ test "readIntBig and readIntLittle" {
/// accepts any integer bit width.
/// This function stores in native endian, which means it is implemented as a simple
/// 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;
}
@@ -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
/// the integer bit width must be divisible by 8.
/// 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));
}
@@ -565,8 +561,7 @@ pub const writeIntBig = switch (builtin.endian) {
/// Writes an integer to memory, storing it in twos-complement.
/// This function always succeeds, has defined behavior for all inputs, but
/// 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 {
- comptime assert(T.bit_count % 8 == 0);
+pub fn writeInt(comptime T: type, buffer: *[@divExact(T.bit_count, 8)]u8, value: T, endian: builtin.Endian) void {
if (endian == builtin.endian) {
return writeIntNative(T, buffer, value);
} 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.
-/// 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.
/// 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
/// instead.
pub fn writeIntSliceLittle(comptime T: type, buffer: []u8, value: T) void {
- comptime assert(@sizeOf(u24) == 3);
- comptime assert(T.bit_count % 8 == 0);
- assert(buffer.len >= @sizeOf(T));
+ assert(buffer.len >= @divExact(T.bit_count, 8));
// TODO I want to call writeIntLittle here but comptime eval facilities aren't good enough
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.
-/// 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.
/// 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.
pub fn writeIntSliceBig(comptime T: type, buffer: []u8, value: T) void {
- comptime assert(@sizeOf(u24) == 3);
- comptime assert(T.bit_count % 8 == 0);
- assert(buffer.len >= @sizeOf(T));
+ assert(buffer.len >= @divExact(T.bit_count, 8));
// TODO I want to call writeIntBig here but comptime eval facilities aren't good enough
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.
-/// 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.
/// 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,
diff --git a/std/meta/index.zig b/std/meta/index.zig
@@ -463,13 +463,16 @@ pub fn eql(a: var, b: @typeOf(a)) bool {
builtin.TypeId.Pointer => {
const info = @typeInfo(T).Pointer;
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.TypeId.Optional => {
- if(a == null and b == null) return true;
- if(a == null or b == null) return false;
+ if (a == null and b == null) return true;
+ if (a == null or b == null) return false;
return eql(a.?, b.?);
},
else => return a == b,
diff --git a/std/os/darwin.zig b/std/os/darwin.zig
@@ -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 {
const ptr_result = c.mmap(
- @ptrCast(*c_void, address),
+ @ptrCast(?*c_void, address),
length,
@bitCast(c_int, @intCast(c_uint, prot)),
@bitCast(c_int, c_uint(flags)),
diff --git a/std/os/file.zig b/std/os/file.zig
@@ -105,7 +105,7 @@ pub const File = struct {
pub fn openWriteNoClobber(path: []const u8, file_mode: Mode) OpenError!File {
if (is_posix) {
const path_c = try os.toPosixPath(path);
- return openWriteNoClobberC(path_c, file_mode);
+ return openWriteNoClobberC(&path_c, file_mode);
} else if (is_windows) {
const path_w = try windows_util.sliceToPrefixedFileW(path);
return openWriteNoClobberW(&path_w, file_mode);
@@ -237,7 +237,7 @@ pub const File = struct {
pub fn seekForward(self: File, amount: isize) SeekError!void {
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 err = posix.getErrno(result);
if (err > 0) {
@@ -268,7 +268,7 @@ pub const File = struct {
pub fn seekTo(self: File, pos: usize) SeekError!void {
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 result = posix.lseek(self.handle, ipos, posix.SEEK_SET);
const err = posix.getErrno(result);
@@ -309,7 +309,7 @@ pub const File = struct {
pub fn getPos(self: File) GetSeekPosError!usize {
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 err = posix.getErrno(result);
if (err > 0) {
diff --git a/std/os/freebsd/index.zig b/std/os/freebsd/index.zig
@@ -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 {
const ptr_result = c.mmap(
- @ptrCast(*c_void, address),
+ @ptrCast(?*c_void, address),
length,
@bitCast(c_int, @intCast(c_uint, prot)),
@bitCast(c_int, c_uint(flags)),
diff --git a/std/os/get_app_data_dir.zig b/std/os/get_app_data_dir.zig
@@ -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 });
},
- builtin.Os.linux, builtin.Os.freebsd => {
+ builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => {
const home_dir = os.getEnvPosix("HOME") orelse {
// TODO look in /etc/passwd
return error.AppDataDirUnavailable;
diff --git a/std/os/get_user_id.zig b/std/os/get_user_id.zig
@@ -11,7 +11,7 @@ pub const UserInfo = struct {
/// POSIX function which gets a uid from username.
pub fn getUserInfo(name: []const u8) !UserInfo {
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"),
};
}
diff --git a/std/os/index.zig b/std/os/index.zig
@@ -3,7 +3,7 @@ const builtin = @import("builtin");
const Os = builtin.Os;
const is_windows = builtin.os == Os.windows;
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,
};
const os = @This();
@@ -30,6 +30,7 @@ pub const windows = @import("windows/index.zig");
pub const darwin = @import("darwin.zig");
pub const linux = @import("linux/index.zig");
pub const freebsd = @import("freebsd/index.zig");
+pub const netbsd = @import("netbsd/index.zig");
pub const zen = @import("zen.zig");
pub const uefi = @import("uefi.zig");
@@ -37,6 +38,7 @@ pub const posix = switch (builtin.os) {
Os.linux => linux,
Os.macosx, Os.ios => darwin,
Os.freebsd => freebsd,
+ Os.netbsd => netbsd,
Os.zen => zen,
else => @compileError("Unsupported OS"),
};
@@ -50,7 +52,7 @@ pub const time = @import("time.zig");
pub const page_size = 4 * 1024;
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.
// 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.
@@ -125,7 +127,7 @@ pub fn getRandomBytes(buf: []u8) !void {
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 => {
// Call RtlGenRandom() instead of CryptGetRandom() on Windows
// https://github.com/rust-lang-nursery/rand/issues/111
@@ -185,7 +187,7 @@ pub fn abort() noreturn {
c.abort();
}
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.SIGKILL);
while (true) {}
@@ -211,7 +213,7 @@ pub fn exit(status: u8) noreturn {
c.exit(status);
}
switch (builtin.os) {
- Os.linux, Os.macosx, Os.ios, Os.freebsd => {
+ Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
posix.exit(status);
},
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 err = posix.getErrno(rc);
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 err = posix.getErrno(rc);
switch (err) {
@@ -699,7 +701,9 @@ pub fn getBaseAddress() usize {
const phdr = linuxGetAuxVal(std.elf.AT_PHDR);
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)),
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);
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));
switch (err) {
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);
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);
return deleteDirC(&dir_path_c);
},
@@ -1501,7 +1505,7 @@ pub const Dir = struct {
allocator: *Allocator,
pub const Handle = switch (builtin.os) {
- Os.macosx, Os.ios, Os.freebsd => struct {
+ Os.macosx, Os.ios, Os.freebsd, Os.netbsd => struct {
fd: i32,
seek: i64,
buf: []u8,
@@ -1578,7 +1582,7 @@ pub const Dir = struct {
.name_data = undefined,
};
},
- Os.macosx, Os.ios, Os.freebsd => Handle{
+ Os.macosx, Os.ios, Os.freebsd, Os.netbsd => Handle{
.fd = try posixOpen(
dir_path,
posix.O_RDONLY | posix.O_NONBLOCK | posix.O_DIRECTORY | posix.O_CLOEXEC,
@@ -1609,7 +1613,7 @@ pub const Dir = struct {
Os.windows => {
_ = 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);
os.close(self.handle.fd);
},
@@ -1625,6 +1629,7 @@ pub const Dir = struct {
Os.macosx, Os.ios => return self.nextDarwin(),
Os.windows => return self.nextWindows(),
Os.freebsd => return self.nextFreebsd(),
+ Os.netbsd => return self.nextFreebsd(),
else => @compileError("unimplemented"),
}
}
@@ -2256,7 +2261,7 @@ pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError {
pub fn openSelfExe() !os.File {
switch (builtin.os) {
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;
const self_exe_path = try selfExePath(&buf);
buf[self_exe_path.len] = 0;
@@ -2317,6 +2322,19 @@ pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
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 => {
var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
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.
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);
// Assume that the OS APIs return absolute paths, and therefore dirname
// will not return null.
@@ -3227,7 +3245,7 @@ pub const CpuCountError = error{
pub fn cpuCount(fallback_allocator: *mem.Allocator) CpuCountError!usize {
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_len: usize = @sizeOf(c_int);
const rc = posix.sysctlbyname(switch (builtin.os) {
diff --git a/std/os/linux/index.zig b/std/os/linux/index.zig
@@ -6,7 +6,7 @@ const vdso = @import("vdso.zig");
pub use switch (builtin.arch) {
builtin.Arch.x86_64 => @import("x86_64.zig"),
builtin.Arch.i386 => @import("i386.zig"),
- builtin.Arch.aarch64v8 => @import("arm64.zig"),
+ builtin.Arch.aarch64 => @import("arm64.zig"),
else => @compileError("unsupported arch"),
};
pub use @import("errno.zig");
diff --git a/std/os/netbsd/errno.zig b/std/os/netbsd/errno.zig
@@ -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
diff --git a/std/os/netbsd/index.zig b/std/os/netbsd/index.zig
@@ -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);
+}
diff --git a/std/os/path.zig b/std/os/path.zig
@@ -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);
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
const err = posix.getErrno(posix.realpath(pathname, out_buffer));
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);
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);
return realC(out_buffer, &pathname_c);
},
diff --git a/std/os/time.zig b/std/os/time.zig
@@ -14,7 +14,7 @@ pub const epoch = @import("epoch.zig");
/// Sleep for the specified duration
pub fn sleep(nanoseconds: u64) void {
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 ns = nanoseconds % ns_per_s;
posixSleep(@intCast(u63, s), @intCast(u63, ns));
@@ -62,7 +62,7 @@ pub fn timestamp() u64 {
/// Get the posix timestamp, UTC, in milliseconds
pub const milliTimestamp = switch (builtin.os) {
Os.windows => milliTimestampWindows,
- Os.linux, Os.freebsd => milliTimestampPosix,
+ Os.linux, Os.freebsd, Os.netbsd => milliTimestampPosix,
Os.macosx, Os.ios => milliTimestampDarwin,
else => @compileError("Unsupported OS"),
};
@@ -178,7 +178,7 @@ pub const Timer = struct {
debug.assert(err != windows.FALSE);
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
// syscalls, including return any errno value it wants and
// inconsistently throwing errors. Since we can't account for
@@ -214,7 +214,7 @@ pub const Timer = struct {
var clock = clockNative() - self.start_time;
return switch (builtin.os) {
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),
else => @compileError("Unsupported OS"),
};
@@ -235,7 +235,7 @@ pub const Timer = struct {
const clockNative = switch (builtin.os) {
Os.windows => clockWindows,
- Os.linux, Os.freebsd => clockLinux,
+ Os.linux, Os.freebsd, Os.netbsd => clockLinux,
Os.macosx, Os.ios => clockDarwin,
else => @compileError("Unsupported OS"),
};
diff --git a/std/priority_queue.zig b/std/priority_queue.zig
@@ -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());
+}
diff --git a/std/special/bootstrap.zig b/std/special/bootstrap.zig
@@ -23,15 +23,15 @@ nakedcc fn _start() noreturn {
switch (builtin.arch) {
builtin.Arch.x86_64 => {
argc_ptr = asm ("lea (%%rsp), %[argc]"
- : [argc] "=r" (-> [*]usize)
- );
+ : [argc] "=r" (-> [*]usize)
+ );
},
builtin.Arch.i386 => {
argc_ptr = asm ("lea (%%esp), %[argc]"
: [argc] "=r" (-> [*]usize)
);
},
- builtin.Arch.aarch64v8 => {
+ builtin.Arch.aarch64, builtin.Arch.aarch64_be => {
argc_ptr = asm ("mov %[argc], sp"
: [argc] "=r" (-> [*]usize)
);
@@ -123,7 +123,7 @@ inline fn callMain() u8 {
std.debug.warn("error: {}\n", @errorName(err));
if (builtin.os != builtin.Os.zen) {
if (@errorReturnTrace()) |trace| {
- std.debug.dumpStackTrace(trace);
+ std.debug.dumpStackTrace(trace.*);
}
}
return 1;
@@ -142,7 +142,10 @@ fn linuxInitializeThreadLocalStorage(at_phdr: usize, at_phnum: usize, at_phent:
var phdr_addr = at_phdr;
var n = at_phnum;
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);
// TODO look for PT_DYNAMIC when we have https://github.com/ziglang/zig/issues/1917
switch (phdr.p_type) {
diff --git a/std/special/compiler_rt/addXf3.zig b/std/special/compiler_rt/addXf3.zig
@@ -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");
+}
diff --git a/std/special/compiler_rt/addXf3_test.zig b/std/special/compiler_rt/addXf3_test.zig
@@ -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);
+}
diff --git a/std/special/compiler_rt/index.zig b/std/special/compiler_rt/index.zig
@@ -21,6 +21,9 @@ comptime {
@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("__floattidf", @import("floattidf.zig").__floattidf, linkage);
@export("__floattisf", @import("floattisf.zig").__floattisf, linkage);
@@ -37,6 +40,7 @@ comptime {
@export("__extendhfsf2", @import("extendXfYf2.zig").__extendhfsf2, linkage);
@export("__truncsfhf2", @import("truncXfYf2.zig").__truncsfhf2, linkage);
+ @export("__truncdfhf2", @import("truncXfYf2.zig").__truncdfhf2, linkage);
@export("__trunctfdf2", @import("truncXfYf2.zig").__trunctfdf2, 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) {
- 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_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.arm,
+ builtin.Arch.armeb,
+ builtin.Arch.aarch64,
+ builtin.Arch.aarch64_be,
builtin.Arch.thumb,
builtin.Arch.thumbeb,
=> true,
diff --git a/std/special/compiler_rt/truncXfYf2.zig b/std/special/compiler_rt/truncXfYf2.zig
@@ -4,6 +4,10 @@ pub extern fn __truncsfhf2(a: f32) u16 {
return @bitCast(u16, truncXfYf2(f16, f32, a));
}
+pub extern fn __truncdfhf2(a: f64) u16 {
+ return @bitCast(u16, truncXfYf2(f16, f64, a));
+}
+
pub extern fn __trunctfsf2(a: f128) f32 {
return truncXfYf2(f32, f128, a);
}
diff --git a/std/special/compiler_rt/truncXfYf2_test.zig b/std/special/compiler_rt/truncXfYf2_test.zig
@@ -63,6 +63,74 @@ test "truncsfhf2" {
test__truncsfhf2(0x33000000, 0x0000); // 0x1.0p-25 -> zero
}
+const __truncdfhf2 = @import("truncXfYf2.zig").__truncdfhf2;
+
+fn test__truncdfhf2(a: f64, expected: u16) void {
+ const rep = @bitCast(u16, __truncdfhf2(a));
+
+ if (rep == expected) {
+ return;
+ }
+ // test other possible NaN representation(signal NaN)
+ else if (expected == 0x7e00) {
+ if ((rep & 0x7c00) == 0x7c00 and (rep & 0x3ff) > 0) {
+ return;
+ }
+ }
+
+ @panic("__truncdfhf2 test failure");
+}
+
+fn test__truncdfhf2_raw(a: u64, expected: u16) void {
+ const actual = __truncdfhf2(@bitCast(f64, a));
+
+ if (actual == expected) {
+ return;
+ }
+
+ @panic("__truncdfhf2 test failure");
+}
+
+test "truncdfhf2" {
+ test__truncdfhf2_raw(0x7ff8000000000000, 0x7e00); // qNaN
+ test__truncdfhf2_raw(0x7ff0000000008000, 0x7e00); // NaN
+
+ test__truncdfhf2_raw(0x7ff0000000000000, 0x7c00); //inf
+ test__truncdfhf2_raw(0xfff0000000000000, 0xfc00); // -inf
+
+ test__truncdfhf2(0.0, 0x0); // zero
+ test__truncdfhf2_raw(0x80000000 << 32, 0x8000); // -zero
+
+ test__truncdfhf2(3.1415926535, 0x4248);
+ test__truncdfhf2(-3.1415926535, 0xc248);
+
+ test__truncdfhf2(0x1.987124876876324p+1000, 0x7c00);
+ test__truncdfhf2(0x1.987124876876324p+12, 0x6e62);
+ test__truncdfhf2(0x1.0p+0, 0x3c00);
+ test__truncdfhf2(0x1.0p-14, 0x0400);
+
+ // denormal
+ test__truncdfhf2(0x1.0p-20, 0x0010);
+ test__truncdfhf2(0x1.0p-24, 0x0001);
+ test__truncdfhf2(-0x1.0p-24, 0x8001);
+ test__truncdfhf2(0x1.5p-25, 0x0001);
+
+ // and back to zero
+ test__truncdfhf2(0x1.0p-25, 0x0000);
+ test__truncdfhf2(-0x1.0p-25, 0x8000);
+
+ // max (precise)
+ test__truncdfhf2(65504.0, 0x7bff);
+
+ // max (rounded)
+ test__truncdfhf2(65519.0, 0x7bff);
+
+ // max (to +inf)
+ test__truncdfhf2(65520.0, 0x7c00);
+ test__truncdfhf2(-65520.0, 0xfc00);
+ test__truncdfhf2(65536.0, 0x7c00);
+}
+
const __trunctfsf2 = @import("truncXfYf2.zig").__trunctfsf2;
fn test__trunctfsf2(a: f128, expected: u32) void {
diff --git a/std/special/fmt_runner.zig b/std/special/fmt_runner.zig
@@ -0,0 +1,260 @@
+const std = @import("std");
+const builtin = @import("builtin");
+
+const os = std.os;
+const io = std.io;
+const mem = std.mem;
+const Allocator = mem.Allocator;
+const ArrayList = std.ArrayList;
+const Buffer = std.Buffer;
+const ast = std.zig.ast;
+
+const arg = @import("fmt/arg.zig");
+const self_hosted_main = @import("fmt/main.zig");
+const Args = arg.Args;
+const Flag = arg.Flag;
+const errmsg = @import("fmt/errmsg.zig");
+
+var stderr_file: os.File = undefined;
+var stderr: *io.OutStream(os.File.WriteError) = undefined;
+var stdout: *io.OutStream(os.File.WriteError) = undefined;
+
+// This brings `zig fmt` to stage 1.
+pub fn main() !void {
+ // Here we use an ArenaAllocator backed by a DirectAllocator because `zig fmt` is a short-lived,
+ // one shot program. We don't need to waste time freeing memory and finding places to squish
+ // bytes into. So we free everything all at once at the very end.
+ var direct_allocator = std.heap.DirectAllocator.init();
+ var arena = std.heap.ArenaAllocator.init(&direct_allocator.allocator);
+ const allocator = &arena.allocator;
+
+ var stdout_file = try std.io.getStdOut();
+ var stdout_out_stream = stdout_file.outStream();
+ stdout = &stdout_out_stream.stream;
+
+ stderr_file = try std.io.getStdErr();
+ var stderr_out_stream = stderr_file.outStream();
+ stderr = &stderr_out_stream.stream;
+ const args = try std.os.argsAlloc(allocator);
+
+ var flags = try Args.parse(allocator, self_hosted_main.args_fmt_spec, args[1..]);
+ defer flags.deinit();
+
+ if (flags.present("help")) {
+ try stdout.write(self_hosted_main.usage_fmt);
+ os.exit(0);
+ }
+
+ const color = blk: {
+ if (flags.single("color")) |color_flag| {
+ if (mem.eql(u8, color_flag, "auto")) {
+ break :blk errmsg.Color.Auto;
+ } else if (mem.eql(u8, color_flag, "on")) {
+ break :blk errmsg.Color.On;
+ } else if (mem.eql(u8, color_flag, "off")) {
+ break :blk errmsg.Color.Off;
+ } else unreachable;
+ } else {
+ break :blk errmsg.Color.Auto;
+ }
+ };
+
+ if (flags.present("stdin")) {
+ if (flags.positionals.len != 0) {
+ try stderr.write("cannot use --stdin with positional arguments\n");
+ os.exit(1);
+ }
+
+ var stdin_file = try io.getStdIn();
+ var stdin = stdin_file.inStream();
+
+ const source_code = try stdin.stream.readAllAlloc(allocator, self_hosted_main.max_src_size);
+ defer allocator.free(source_code);
+
+ var tree = std.zig.parse(allocator, source_code) catch |err| {
+ try stderr.print("error parsing stdin: {}\n", err);
+ os.exit(1);
+ };
+ defer tree.deinit();
+
+ var error_it = tree.errors.iterator(0);
+ while (error_it.next()) |parse_error| {
+ try printErrMsgToFile(allocator, parse_error, &tree, "<stdin>", stderr_file, color);
+ }
+ if (tree.errors.len != 0) {
+ os.exit(1);
+ }
+ if (flags.present("check")) {
+ const anything_changed = try std.zig.render(allocator, io.null_out_stream, &tree);
+ const code = if (anything_changed) u8(1) else u8(0);
+ os.exit(code);
+ }
+
+ _ = try std.zig.render(allocator, stdout, &tree);
+ return;
+ }
+
+ if (flags.positionals.len == 0) {
+ try stderr.write("expected at least one source file argument\n");
+ os.exit(1);
+ }
+
+ var fmt = Fmt{
+ .seen = Fmt.SeenMap.init(allocator),
+ .any_error = false,
+ .color = color,
+ .allocator = allocator,
+ };
+
+ const check_mode = flags.present("check");
+
+ for (flags.positionals.toSliceConst()) |file_path| {
+ try fmtPath(&fmt, file_path, check_mode);
+ }
+ if (fmt.any_error) {
+ os.exit(1);
+ }
+}
+
+const FmtError = error{
+ SystemResources,
+ OperationAborted,
+ IoPending,
+ BrokenPipe,
+ Unexpected,
+ WouldBlock,
+ FileClosed,
+ DestinationAddressRequired,
+ DiskQuota,
+ FileTooBig,
+ InputOutput,
+ NoSpaceLeft,
+ AccessDenied,
+ OutOfMemory,
+ RenameAcrossMountPoints,
+ ReadOnlyFileSystem,
+ LinkQuotaExceeded,
+ FileBusy,
+} || os.File.OpenError;
+
+fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void {
+ const file_path = try std.mem.dupe(fmt.allocator, u8, file_path_ref);
+ defer fmt.allocator.free(file_path);
+
+ if (try fmt.seen.put(file_path, {})) |_| return;
+
+ const source_code = io.readFileAlloc(fmt.allocator, file_path) catch |err| switch (err) {
+ error.IsDir, error.AccessDenied => {
+ // TODO make event based (and dir.next())
+ var dir = try std.os.Dir.open(fmt.allocator, file_path);
+ defer dir.close();
+
+ while (try dir.next()) |entry| {
+ if (entry.kind == std.os.Dir.Entry.Kind.Directory or mem.endsWith(u8, entry.name, ".zig")) {
+ const full_path = try os.path.join(fmt.allocator, [][]const u8{ file_path, entry.name });
+ try fmtPath(fmt, full_path, check_mode);
+ }
+ }
+ return;
+ },
+ else => {
+ // TODO lock stderr printing
+ try stderr.print("unable to open '{}': {}\n", file_path, err);
+ fmt.any_error = true;
+ return;
+ },
+ };
+ defer fmt.allocator.free(source_code);
+
+ var tree = std.zig.parse(fmt.allocator, source_code) catch |err| {
+ try stderr.print("error parsing file '{}': {}\n", file_path, err);
+ fmt.any_error = true;
+ return;
+ };
+ defer tree.deinit();
+
+ var error_it = tree.errors.iterator(0);
+ while (error_it.next()) |parse_error| {
+ try printErrMsgToFile(fmt.allocator, parse_error, &tree, file_path, stderr_file, fmt.color);
+ }
+ if (tree.errors.len != 0) {
+ fmt.any_error = true;
+ return;
+ }
+
+ if (check_mode) {
+ const anything_changed = try std.zig.render(fmt.allocator, io.null_out_stream, &tree);
+ if (anything_changed) {
+ try stderr.print("{}\n", file_path);
+ fmt.any_error = true;
+ }
+ } else {
+ // TODO make this evented
+ const baf = try io.BufferedAtomicFile.create(fmt.allocator, file_path);
+ defer baf.destroy();
+
+ const anything_changed = try std.zig.render(fmt.allocator, baf.stream(), &tree);
+ if (anything_changed) {
+ try stderr.print("{}\n", file_path);
+ try baf.finish();
+ }
+ }
+}
+
+const Fmt = struct {
+ seen: SeenMap,
+ any_error: bool,
+ color: errmsg.Color,
+ allocator: *mem.Allocator,
+
+ const SeenMap = std.HashMap([]const u8, void, mem.hash_slice_u8, mem.eql_slice_u8);
+};
+
+fn printErrMsgToFile(allocator: *mem.Allocator, parse_error: *const ast.Error, tree: *ast.Tree,
+ path: []const u8, file: os.File, color: errmsg.Color,) !void
+{
+ const color_on = switch (color) {
+ errmsg.Color.Auto => file.isTty(),
+ errmsg.Color.On => true,
+ errmsg.Color.Off => false,
+ };
+ const lok_token = parse_error.loc();
+ const span = errmsg.Span{
+ .first = lok_token,
+ .last = lok_token,
+ };
+
+ const first_token = tree.tokens.at(span.first);
+ const last_token = tree.tokens.at(span.last);
+ const start_loc = tree.tokenLocationPtr(0, first_token);
+ const end_loc = tree.tokenLocationPtr(first_token.end, last_token);
+
+ var text_buf = try std.Buffer.initSize(allocator, 0);
+ var out_stream = &std.io.BufferOutStream.init(&text_buf).stream;
+ try parse_error.render(&tree.tokens, out_stream);
+ const text = text_buf.toOwnedSlice();
+
+ const stream = &file.outStream().stream;
+ if (!color_on) {
+ try stream.print(
+ "{}:{}:{}: error: {}\n",
+ path,
+ start_loc.line + 1,
+ start_loc.column + 1,
+ text,
+ );
+ return;
+ }
+
+ try stream.print(
+ "{}:{}:{}: error: {}\n{}\n",
+ path,
+ start_loc.line + 1,
+ start_loc.column + 1,
+ text,
+ tree.source[start_loc.line_start..start_loc.line_end],
+ );
+ try stream.writeByteNTimes(' ', start_loc.column);
+ try stream.writeByteNTimes('~', last_token.end - first_token.start);
+ try stream.write("\n");
+}
diff --git a/std/testing.zig b/std/testing.zig
@@ -59,13 +59,14 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {
switch (pointer.size) {
builtin.TypeInfo.Pointer.Size.One,
builtin.TypeInfo.Pointer.Size.Many,
+ builtin.TypeInfo.Pointer.Size.C,
=> {
if (actual != expected) {
std.debug.panic("expected {}, found {}", expected, actual);
}
},
- builtin.TypeInfo.Pointer.Size.Slice => {
+ builtin.TypeInfo.Pointer.Size.Slice => {
if (actual.ptr != expected.ptr) {
std.debug.panic("expected slice ptr {}, found {}", expected.ptr, actual.ptr);
}
@@ -118,7 +119,6 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {
}
}
},
-
}
}
diff --git a/std/zig/parse.zig b/std/zig/parse.zig
@@ -3525,7 +3525,12 @@ fn tokenIdToPrefixOp(id: Token.Id) ?ast.Node.PrefixOp.Op {
Token.Id.Minus => ast.Node.PrefixOp.Op{ .Negation = void{} },
Token.Id.MinusPercent => ast.Node.PrefixOp.Op{ .NegationWrap = void{} },
Token.Id.Ampersand => ast.Node.PrefixOp.Op{ .AddressOf = void{} },
- Token.Id.Asterisk, Token.Id.AsteriskAsterisk, Token.Id.BracketStarBracket => ast.Node.PrefixOp.Op{
+
+ Token.Id.Asterisk,
+ Token.Id.AsteriskAsterisk,
+ Token.Id.BracketStarBracket,
+ Token.Id.BracketStarCBracket,
+ => ast.Node.PrefixOp.Op{
.PtrType = ast.Node.PrefixOp.PtrInfo{
.align_info = null,
.const_token = null,
diff --git a/std/zig/parser_test.zig b/std/zig/parser_test.zig
@@ -1,3 +1,19 @@
+test "zig fmt: infix operator and then multiline string literal" {
+ try testCanonical(
+ \\const x = "" ++
+ \\ \\ hi
+ \\;
+ \\
+ );
+}
+
+test "zig fmt: C pointers" {
+ try testCanonical(
+ \\const Ptr = [*c]i32;
+ \\
+ );
+}
+
test "zig fmt: threadlocal" {
try testCanonical(
\\threadlocal var x: i32 = 1234;
diff --git a/std/zig/render.zig b/std/zig/render.zig
@@ -340,7 +340,6 @@ fn renderExpression(
ast.Node.Id.InfixOp => {
const infix_op_node = @fieldParentPtr(ast.Node.InfixOp, "base", base);
- const op_token = tree.tokens.at(infix_op_node.op_token);
const op_space = switch (infix_op_node.op) {
ast.Node.InfixOp.Op.Period, ast.Node.InfixOp.Op.ErrorUnion, ast.Node.InfixOp.Op.Range => Space.None,
else => Space.Space,
@@ -353,7 +352,9 @@ fn renderExpression(
};
try renderToken(tree, stream, infix_op_node.op_token, indent, start_col, after_op_space);
- if (after_op_space == Space.Newline) {
+ if (after_op_space == Space.Newline and
+ tree.tokens.at(tree.nextToken(infix_op_node.op_token)).id != Token.Id.MultilineStringLiteralLine)
+ {
try stream.writeByteNTimes(' ', indent + indent_delta);
start_col.* = indent + indent_delta;
}
diff --git a/std/zig/tokenizer.zig b/std/zig/tokenizer.zig
@@ -141,6 +141,7 @@ pub const Token = struct {
LineComment,
DocComment,
BracketStarBracket,
+ BracketStarCBracket,
ShebangLine,
Keyword_align,
Keyword_and,
@@ -279,6 +280,7 @@ pub const Tokenizer = struct {
SawAtSign,
LBracket,
LBracketStar,
+ LBracketStarC,
};
pub fn next(self: *Tokenizer) Token {
@@ -456,6 +458,9 @@ pub const Tokenizer = struct {
},
State.LBracketStar => switch (c) {
+ 'c' => {
+ state = State.LBracketStarC;
+ },
']' => {
result.id = Token.Id.BracketStarBracket;
self.index += 1;
@@ -467,6 +472,18 @@ pub const Tokenizer = struct {
},
},
+ State.LBracketStarC => switch (c) {
+ ']' => {
+ result.id = Token.Id.BracketStarCBracket;
+ self.index += 1;
+ break;
+ },
+ else => {
+ result.id = Token.Id.Invalid;
+ break;
+ },
+ },
+
State.Ampersand => switch (c) {
'=' => {
result.id = Token.Id.AmpersandEqual;
@@ -1035,6 +1052,7 @@ pub const Tokenizer = struct {
State.CharLiteralEnd,
State.StringLiteralBackslash,
State.LBracketStar,
+ State.LBracketStarC,
=> {
result.id = Token.Id.Invalid;
},
@@ -1169,12 +1187,15 @@ test "tokenizer" {
testTokenize("test", []Token.Id{Token.Id.Keyword_test});
}
-test "tokenizer - unknown length pointer" {
+test "tokenizer - unknown length pointer and then c pointer" {
testTokenize(
\\[*]u8
+ \\[*c]u8
, []Token.Id{
Token.Id.BracketStarBracket,
Token.Id.Identifier,
+ Token.Id.BracketStarCBracket,
+ Token.Id.Identifier,
});
}
diff --git a/test/build_examples.zig b/test/build_examples.zig
@@ -7,12 +7,8 @@ pub fn addCases(cases: *tests.BuildExamplesContext) void {
cases.addC("example/hello_world/hello_libc.zig");
cases.add("example/cat/main.zig");
cases.add("example/guess_number/main.zig");
- if (!is_windows) {
- // TODO get this test passing on windows
- // See https://github.com/ziglang/zig/issues/538
- cases.addBuildFile("example/shared_library/build.zig");
- cases.addBuildFile("example/mix_o_files/build.zig");
- }
+ cases.addBuildFile("example/shared_library/build.zig");
+ cases.addBuildFile("example/mix_o_files/build.zig");
if (builtin.os != builtin.Os.macosx) {
// TODO https://github.com/ziglang/zig/issues/1126
cases.addBuildFile("test/standalone/issue_339/build.zig");
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
@@ -1,13 +1,330 @@
const tests = @import("tests.zig");
+const builtin = @import("builtin");
pub fn addCases(cases: *tests.CompileErrorContext) void {
cases.addTest(
+ "not an enum type",
+ \\export fn entry() void {
+ \\ var self: Error = undefined;
+ \\ switch (self) {
+ \\ InvalidToken => |x| return x.token,
+ \\ ExpectedVarDeclOrFn => |x| return x.token,
+ \\ }
+ \\}
+ \\const Error = union(enum) {
+ \\ A: InvalidToken,
+ \\ B: ExpectedVarDeclOrFn,
+ \\};
+ \\const InvalidToken = struct {};
+ \\const ExpectedVarDeclOrFn = struct {};
+ ,
+ ".tmp_source.zig:4:9: error: not an enum type",
+ );
+
+ cases.addTest(
+ "binary OR operator on error sets",
+ \\pub const A = error.A;
+ \\pub const AB = A | error.B;
+ \\export fn entry() void {
+ \\ var x: AB = undefined;
+ \\}
+ ,
+ ".tmp_source.zig:2:18: error: invalid operands to binary expression: 'error{A}' and 'error{B}'",
+ );
+
+ if (builtin.os == builtin.Os.linux) {
+ cases.addTest(
+ "implicit dependency on libc",
+ \\extern "c" fn exit(u8) void;
+ \\export fn entry() void {
+ \\ exit(0);
+ \\}
+ ,
+ ".tmp_source.zig:3:5: error: dependency on library c must be explicitly specified in the build command",
+ );
+
+ cases.addTest(
+ "libc headers note",
+ \\const c = @cImport(@cInclude("stdio.h"));
+ \\export fn entry() void {
+ \\ _ = c.printf(c"hello, world!\n");
+ \\}
+ ,
+ ".tmp_source.zig:1:11: error: C import failed",
+ ".tmp_source.zig:1:11: note: libc headers not available; compilation does not link against libc",
+ );
+ }
+
+ cases.addTest(
+ "comptime vector overflow shows the index",
+ \\comptime {
+ \\ var a: @Vector(4, u8) = []u8{ 1, 2, 255, 4 };
+ \\ var b: @Vector(4, u8) = []u8{ 5, 6, 1, 8 };
+ \\ var x = a + b;
+ \\}
+ ,
+ ".tmp_source.zig:4:15: error: operation caused overflow",
+ ".tmp_source.zig:4:15: note: when computing vector element at index 2",
+ );
+
+ cases.addTest(
+ "packed struct with fields of not allowed types",
+ \\const A = packed struct {
+ \\ x: anyerror,
+ \\};
+ \\const B = packed struct {
+ \\ x: [2]u24,
+ \\};
+ \\const C = packed struct {
+ \\ x: [1]anyerror,
+ \\};
+ \\const D = packed struct {
+ \\ x: [1]S,
+ \\};
+ \\const E = packed struct {
+ \\ x: [1]U,
+ \\};
+ \\const F = packed struct {
+ \\ x: ?anyerror,
+ \\};
+ \\const G = packed struct {
+ \\ x: Enum,
+ \\};
+ \\export fn entry() void {
+ \\ var a: A = undefined;
+ \\ var b: B = undefined;
+ \\ var r: C = undefined;
+ \\ var d: D = undefined;
+ \\ var e: E = undefined;
+ \\ var f: F = undefined;
+ \\ var g: G = undefined;
+ \\}
+ \\const S = struct {
+ \\ x: i32,
+ \\};
+ \\const U = struct {
+ \\ A: i32,
+ \\ B: u32,
+ \\};
+ \\const Enum = enum {
+ \\ A,
+ \\ B,
+ \\};
+ ,
+ ".tmp_source.zig:2:5: error: type 'anyerror' not allowed in packed struct; no guaranteed in-memory representation",
+ ".tmp_source.zig:5:5: error: array of 'u24' not allowed in packed struct due to padding bits",
+ ".tmp_source.zig:8:5: error: type 'anyerror' not allowed in packed struct; no guaranteed in-memory representation",
+ ".tmp_source.zig:11:5: error: non-packed, non-extern struct 'S' not allowed in packed struct; no guaranteed in-memory representation",
+ ".tmp_source.zig:14:5: error: non-packed, non-extern struct 'U' not allowed in packed struct; no guaranteed in-memory representation",
+ ".tmp_source.zig:17:5: error: type '?anyerror' not allowed in packed struct; no guaranteed in-memory representation",
+ ".tmp_source.zig:20:5: error: type 'Enum' not allowed in packed struct; no guaranteed in-memory representation",
+ ".tmp_source.zig:38:14: note: enum declaration does not specify an integer tag type",
+ );
+
+ cases.addCase(x: {
+ var tc = cases.create(
+ "deduplicate undeclared identifier",
+ \\export fn a() void {
+ \\ x += 1;
+ \\}
+ \\export fn b() void {
+ \\ x += 1;
+ \\}
+ ,
+ ".tmp_source.zig:2:5: error: use of undeclared identifier 'x'",
+ );
+ tc.expect_exact = true;
+ break :x tc;
+ });
+
+ cases.addTest(
+ "export generic function",
+ \\export fn foo(num: var) i32 {
+ \\ return 0;
+ \\}
+ ,
+ ".tmp_source.zig:1:15: error: parameter of type 'var' not allowed in function with calling convention 'ccc'",
+ );
+
+ cases.addTest(
+ "C pointer to c_void",
+ \\export fn a() void {
+ \\ var x: *c_void = undefined;
+ \\ var y: [*c]c_void = x;
+ \\}
+ ,
+ ".tmp_source.zig:3:12: error: C pointers cannot point opaque types",
+ );
+
+ cases.addTest(
+ "directly embedding opaque type in struct and union",
+ \\const O = @OpaqueType();
+ \\const Foo = struct {
+ \\ o: O,
+ \\};
+ \\const Bar = union {
+ \\ One: i32,
+ \\ Two: O,
+ \\};
+ \\export fn a() void {
+ \\ var foo: Foo = undefined;
+ \\}
+ \\export fn b() void {
+ \\ var bar: Bar = undefined;
+ \\}
+ ,
+ ".tmp_source.zig:3:8: error: opaque types have unknown size and therefore cannot be directly embedded in structs",
+ ".tmp_source.zig:7:10: error: opaque types have unknown size and therefore cannot be directly embedded in unions",
+ );
+
+ cases.addTest(
+ "implicit cast between C pointer and Zig pointer - bad const/align/child",
+ \\export fn a() void {
+ \\ var x: [*c]u8 = undefined;
+ \\ var y: *align(4) u8 = x;
+ \\}
+ \\export fn b() void {
+ \\ var x: [*c]const u8 = undefined;
+ \\ var y: *u8 = x;
+ \\}
+ \\export fn c() void {
+ \\ var x: [*c]u8 = undefined;
+ \\ var y: *u32 = x;
+ \\}
+ \\export fn d() void {
+ \\ var y: *align(1) u32 = undefined;
+ \\ var x: [*c]u32 = y;
+ \\}
+ \\export fn e() void {
+ \\ var y: *const u8 = undefined;
+ \\ var x: [*c]u8 = y;
+ \\}
+ \\export fn f() void {
+ \\ var y: *u8 = undefined;
+ \\ var x: [*c]u32 = y;
+ \\}
+ ,
+ ".tmp_source.zig:3:27: error: cast increases pointer alignment",
+ ".tmp_source.zig:7:18: error: cast discards const qualifier",
+ ".tmp_source.zig:11:19: error: expected type '*u32', found '[*c]u8'",
+ ".tmp_source.zig:11:19: note: pointer type child 'u8' cannot cast into pointer type child 'u32'",
+ ".tmp_source.zig:15:22: error: cast increases pointer alignment",
+ ".tmp_source.zig:19:21: error: cast discards const qualifier",
+ ".tmp_source.zig:23:22: error: expected type '[*c]u32', found '*u8'",
+ );
+
+ cases.addTest(
+ "implicit casting null c pointer to zig pointer",
+ \\comptime {
+ \\ var c_ptr: [*c]u8 = 0;
+ \\ var zig_ptr: *u8 = c_ptr;
+ \\}
+ ,
+ ".tmp_source.zig:3:24: error: null pointer casted to type '*u8'",
+ );
+
+ cases.addTest(
+ "implicit casting undefined c pointer to zig pointer",
+ \\comptime {
+ \\ var c_ptr: [*c]u8 = undefined;
+ \\ var zig_ptr: *u8 = c_ptr;
+ \\}
+ ,
+ ".tmp_source.zig:3:24: error: use of undefined value here causes undefined behavior",
+ );
+
+ cases.addTest(
+ "implicit casting C pointers which would mess up null semantics",
+ \\export fn entry() void {
+ \\ var slice: []const u8 = "aoeu";
+ \\ const opt_many_ptr: [*]const u8 = slice.ptr;
+ \\ var ptr_opt_many_ptr = &opt_many_ptr;
+ \\ var c_ptr: [*c]const [*c]const u8 = ptr_opt_many_ptr;
+ \\ ptr_opt_many_ptr = c_ptr;
+ \\}
+ \\export fn entry2() void {
+ \\ var buf: [4]u8 = "aoeu";
+ \\ var slice: []u8 = &buf;
+ \\ var opt_many_ptr: [*]u8 = slice.ptr;
+ \\ var ptr_opt_many_ptr = &opt_many_ptr;
+ \\ var c_ptr: [*c][*c]const u8 = ptr_opt_many_ptr;
+ \\}
+ ,
+ ".tmp_source.zig:6:24: error: expected type '*const [*]const u8', found '[*c]const [*c]const u8'",
+ ".tmp_source.zig:6:24: note: pointer type child '[*c]const u8' cannot cast into pointer type child '[*]const u8'",
+ ".tmp_source.zig:6:24: note: '[*c]const u8' could have null values which are illegal in type '[*]const u8'",
+ ".tmp_source.zig:13:35: error: expected type '[*c][*c]const u8', found '*[*]u8'",
+ ".tmp_source.zig:13:35: note: pointer type child '[*]u8' cannot cast into pointer type child '[*c]const u8'",
+ ".tmp_source.zig:13:35: note: mutable '[*c]const u8' allows illegal null values stored to type '[*]u8'",
+ );
+
+ cases.addTest(
+ "implicit casting too big integers to C pointers",
+ \\export fn a() void {
+ \\ var ptr: [*c]u8 = (1 << 64) + 1;
+ \\}
+ \\export fn b() void {
+ \\ var x: @IntType(false, 65) = 0x1234;
+ \\ var ptr: [*c]u8 = x;
+ \\}
+ ,
+ ".tmp_source.zig:2:33: error: integer value 71615590737044764481 cannot be implicitly casted to type 'usize'",
+ ".tmp_source.zig:6:23: error: integer type 'u65' too big for implicit @intToPtr to type '[*c]u8'",
+ );
+
+ cases.addTest(
+ "C pointer pointing to non C ABI compatible type or has align attr",
+ \\const Foo = struct {};
+ \\export fn a() void {
+ \\ const T = [*c]Foo;
+ \\}
+ ,
+ ".tmp_source.zig:3:15: error: C pointers cannot point to non-C-ABI-compatible type 'Foo'",
+ );
+
+ cases.addCase(x: {
+ var tc = cases.create(
+ "compile log statement warning deduplication in generic fn",
+ \\export fn entry() void {
+ \\ inner(1);
+ \\ inner(2);
+ \\}
+ \\fn inner(comptime n: usize) void {
+ \\ comptime var i = 0;
+ \\ inline while (i < n) : (i += 1) { @compileLog("!@#$"); }
+ \\}
+ ,
+ ".tmp_source.zig:7:39: error: found compile log statement",
+ );
+ tc.expect_exact = true;
+ break :x tc;
+ });
+
+ cases.addTest(
+ "assign to invalid dereference",
+ \\export fn entry() void {
+ \\ 'a'.* = 1;
+ \\}
+ ,
+ ".tmp_source.zig:2:8: error: attempt to dereference non-pointer type 'comptime_int'",
+ );
+
+ cases.addTest(
+ "take slice of invalid dereference",
+ \\export fn entry() void {
+ \\ const x = 'a'.*[0..];
+ \\}
+ ,
+ ".tmp_source.zig:2:18: error: attempt to dereference non-pointer type 'comptime_int'",
+ );
+
+ cases.addTest(
"@truncate undefined value",
\\export fn entry() void {
\\ var z = @truncate(u8, u16(undefined));
\\}
,
- ".tmp_source.zig:2:30: error: use of undefined value",
+ ".tmp_source.zig:2:30: error: use of undefined value here causes undefined behavior",
);
cases.addTest(
@@ -121,12 +438,12 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"reading past end of pointer casted array",
\\comptime {
\\ const array = "aoeu";
- \\ const slice = array[2..];
+ \\ const slice = array[1..];
\\ const int_ptr = @ptrCast(*const u24, slice.ptr);
\\ const deref = int_ptr.*;
\\}
,
- ".tmp_source.zig:5:26: error: attempt to read 3 bytes from [4]u8 at index 2 which is 2 bytes",
+ ".tmp_source.zig:5:26: error: attempt to read 4 bytes from [4]u8 at index 1 which is 3 bytes",
);
cases.add(
@@ -210,13 +527,23 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
);
cases.add(
- "Panic declared with wrong type signature in tests",
+ "wrong panic signature, runtime function",
\\test "" {}
\\
\\pub fn panic() void {}
\\
,
- ".tmp_source.zig:3:5: error: expected 'fn([]const u8, ?*builtin.StackTrace) noreturn', found 'fn() void'",
+ ".tmp_source.zig:3:5: error: expected type 'fn([]const u8, ?*StackTrace) noreturn', found 'fn() void'",
+ );
+
+ cases.add(
+ "wrong panic signature, generic function",
+ \\pub fn panic(comptime msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {
+ \\ while (true) {}
+ \\}
+ ,
+ ".tmp_source.zig:1:5: error: expected type 'fn([]const u8, ?*StackTrace) noreturn', found 'fn([]const u8,var)var'",
+ ".tmp_source.zig:1:5: note: only one of the functions is generic",
);
cases.add(
@@ -301,7 +628,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a.*.len;
\\}
,
- ".tmp_source.zig:3:12: error: attempt to dereference non-pointer type '[]u8'",
+ ".tmp_source.zig:3:10: error: attempt to dereference non-pointer type '[]u8'",
);
cases.add(
@@ -368,7 +695,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ f(i32);
\\}
,
- ".tmp_source.zig:4:5: error: use of undefined value",
+ ".tmp_source.zig:4:5: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -768,7 +1095,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ command.exec();
\\}
,
- ".tmp_source.zig:6:12: error: use of undefined value",
+ ".tmp_source.zig:6:12: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -781,7 +1108,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ command.exec();
\\}
,
- ".tmp_source.zig:6:12: error: use of undefined value",
+ ".tmp_source.zig:6:12: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -1012,7 +1339,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ Filled,
\\};
,
- ".tmp_source.zig:3:17: error: invalid deref on switch target",
+ ".tmp_source.zig:3:17: error: attempt to dereference non-pointer type 'Tile'",
);
cases.add(
@@ -2089,7 +2416,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
,
".tmp_source.zig:2:5: error: use of undeclared identifier 'i'",
- ".tmp_source.zig:2:12: error: use of undeclared identifier 'i'",
);
cases.add(
@@ -2752,7 +3078,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(x)); }
,
- ".tmp_source.zig:1:15: error: use of undefined value",
+ ".tmp_source.zig:1:15: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -2762,7 +3088,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a / a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value",
+ ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -2772,7 +3098,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ a /= a;
\\}
,
- ".tmp_source.zig:3:5: error: use of undefined value",
+ ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -2782,7 +3108,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a % a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value",
+ ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -2792,7 +3118,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ a %= a;
\\}
,
- ".tmp_source.zig:3:5: error: use of undefined value",
+ ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -2802,7 +3128,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a + a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value",
+ ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -2812,7 +3138,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ a += a;
\\}
,
- ".tmp_source.zig:3:5: error: use of undefined value",
+ ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -2822,7 +3148,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a +% a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value",
+ ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -2832,7 +3158,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ a +%= a;
\\}
,
- ".tmp_source.zig:3:5: error: use of undefined value",
+ ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -2842,7 +3168,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a - a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value",
+ ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -2852,7 +3178,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ a -= a;
\\}
,
- ".tmp_source.zig:3:5: error: use of undefined value",
+ ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -2862,7 +3188,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a -% a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value",
+ ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -2872,7 +3198,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ a -%= a;
\\}
,
- ".tmp_source.zig:3:5: error: use of undefined value",
+ ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -2882,7 +3208,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a * a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value",
+ ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -2892,7 +3218,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ a *= a;
\\}
,
- ".tmp_source.zig:3:5: error: use of undefined value",
+ ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -2902,7 +3228,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a *% a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value",
+ ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -2912,7 +3238,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ a *%= a;
\\}
,
- ".tmp_source.zig:3:5: error: use of undefined value",
+ ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -2922,7 +3248,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a << 2;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value",
+ ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -2932,7 +3258,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ a <<= 2;
\\}
,
- ".tmp_source.zig:3:5: error: use of undefined value",
+ ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -2942,7 +3268,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a >> 2;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value",
+ ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -2952,7 +3278,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ a >>= 2;
\\}
,
- ".tmp_source.zig:3:5: error: use of undefined value",
+ ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -2962,7 +3288,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a & a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value",
+ ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -2972,7 +3298,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ a &= a;
\\}
,
- ".tmp_source.zig:3:5: error: use of undefined value",
+ ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -2982,7 +3308,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a | a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value",
+ ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -2992,7 +3318,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ a |= a;
\\}
,
- ".tmp_source.zig:3:5: error: use of undefined value",
+ ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3002,7 +3328,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a ^ a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value",
+ ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3012,7 +3338,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ a ^= a;
\\}
,
- ".tmp_source.zig:3:5: error: use of undefined value",
+ ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3022,7 +3348,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a == a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value",
+ ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3032,7 +3358,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a != a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value",
+ ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3042,7 +3368,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a > a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value",
+ ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3052,7 +3378,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a >= a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value",
+ ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3062,7 +3388,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a < a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value",
+ ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3072,7 +3398,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a <= a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value",
+ ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3082,7 +3408,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a and a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value",
+ ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3092,7 +3418,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a or a;
\\}
,
- ".tmp_source.zig:3:9: error: use of undefined value",
+ ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3102,7 +3428,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = -a;
\\}
,
- ".tmp_source.zig:3:10: error: use of undefined value",
+ ".tmp_source.zig:3:10: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3112,7 +3438,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = -%a;
\\}
,
- ".tmp_source.zig:3:11: error: use of undefined value",
+ ".tmp_source.zig:3:11: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3122,7 +3448,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = ~a;
\\}
,
- ".tmp_source.zig:3:10: error: use of undefined value",
+ ".tmp_source.zig:3:10: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3132,7 +3458,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = !a;
\\}
,
- ".tmp_source.zig:3:10: error: use of undefined value",
+ ".tmp_source.zig:3:10: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3142,7 +3468,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a orelse false;
\\}
,
- ".tmp_source.zig:3:11: error: use of undefined value",
+ ".tmp_source.zig:3:11: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3152,7 +3478,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _ = a catch |err| false;
\\}
,
- ".tmp_source.zig:3:11: error: use of undefined value",
+ ".tmp_source.zig:3:11: error: use of undefined value here causes undefined behavior",
);
cases.add(
@@ -3854,7 +4180,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\export fn entry() usize { return @sizeOf(@typeOf(pass)); }
,
- ".tmp_source.zig:4:10: error: attempt to dereference non pointer type '[10]u8'",
+ ".tmp_source.zig:4:10: error: attempt to dereference non-pointer type '[10]u8'",
);
cases.add(
@@ -4555,20 +4881,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
);
cases.add(
- "@setEvalBranchQuota in non-root comptime execution context",
- \\comptime {
- \\ foo();
- \\}
- \\fn foo() void {
- \\ @setEvalBranchQuota(1001);
- \\}
- ,
- ".tmp_source.zig:5:5: error: @setEvalBranchQuota must be called from the top of the comptime stack",
- ".tmp_source.zig:2:8: note: called from here",
- ".tmp_source.zig:1:10: note: called from here",
- );
-
- cases.add(
"wrong pointer implicitly casted to pointer to @OpaqueType()",
\\const Derp = @OpaqueType();
\\extern fn bar(d: *Derp) void;
@@ -4788,7 +5100,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
cases.add(
"non-printable invalid character",
- "\xff\xfe" ++
+ "\xff\xfe" ++
\\fn test() bool {\r
\\ true\r
\\}
@@ -5348,7 +5660,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ Baz: void,
\\};
\\comptime {
- \\ var foo = Foo {.Baz = {}};
+ \\ var foo = Foo {.Baz = {}};
\\ const bar_val = foo.Bar;
\\}
,
@@ -5430,4 +5742,28 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
,
".tmp_source.zig:7:30: error: unable to evaluate constant expression",
);
+
+ cases.addTest(
+ "nested vectors",
+ \\export fn entry() void {
+ \\ const V = @Vector(4, @Vector(4, u8));
+ \\ var v: V = undefined;
+ \\}
+ ,
+ ".tmp_source.zig:2:26: error: vector element type must be integer, float, or pointer; '@Vector(4, u8)' is invalid",
+ );
+
+ cases.add("compileLog of tagged enum doesn't crash the compiler",
+ \\const Bar = union(enum(u32)) {
+ \\ X: i32 = 1
+ \\};
+ \\
+ \\fn testCompileLog(x: Bar) void {
+ \\ @compileLog(x);
+ \\}
+ \\
+ \\pub fn main () void {
+ \\ comptime testCompileLog(Bar{.X = 123});
+ \\}
+ , ".tmp_source.zig:6:5: error: found compile log statement");
}
diff --git a/test/runtime_safety.zig b/test/runtime_safety.zig
@@ -1,6 +1,16 @@
const tests = @import("tests.zig");
pub fn addCases(cases: *tests.CompareOutputContext) void {
+ cases.addRuntimeSafety("pointer casting null to non-optional pointer",
+ \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
+ \\ @import("std").os.exit(126);
+ \\}
+ \\pub fn main() void {
+ \\ var c_ptr: [*c]u8 = 0;
+ \\ var zig_ptr: *u8 = c_ptr;
+ \\}
+ );
+
cases.addRuntimeSafety("@intToEnum - no matching tag value",
\\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
\\ @import("std").os.exit(126);
@@ -108,6 +118,47 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
\\}
);
+ cases.addRuntimeSafety("vector integer subtraction overflow",
+ \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
+ \\ @import("std").os.exit(126);
+ \\}
+ \\pub fn main() void {
+ \\ var a: @Vector(4, u32) = []u32{ 1, 2, 8, 4 };
+ \\ var b: @Vector(4, u32) = []u32{ 5, 6, 7, 8 };
+ \\ const x = sub(b, a);
+ \\}
+ \\fn sub(a: @Vector(4, u32), b: @Vector(4, u32)) @Vector(4, u32) {
+ \\ return a - b;
+ \\}
+ );
+
+ cases.addRuntimeSafety("vector integer multiplication overflow",
+ \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
+ \\ @import("std").os.exit(126);
+ \\}
+ \\pub fn main() void {
+ \\ var a: @Vector(4, u8) = []u8{ 1, 2, 200, 4 };
+ \\ var b: @Vector(4, u8) = []u8{ 5, 6, 2, 8 };
+ \\ const x = mul(b, a);
+ \\}
+ \\fn mul(a: @Vector(4, u8), b: @Vector(4, u8)) @Vector(4, u8) {
+ \\ return a * b;
+ \\}
+ );
+
+ cases.addRuntimeSafety("vector integer negation overflow",
+ \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
+ \\ @import("std").os.exit(126);
+ \\}
+ \\pub fn main() void {
+ \\ var a: @Vector(4, i16) = []i16{ 1, -32768, 200, 4 };
+ \\ const x = neg(a);
+ \\}
+ \\fn neg(a: @Vector(4, i16)) @Vector(4, i16) {
+ \\ return -a;
+ \\}
+ );
+
cases.addRuntimeSafety("integer subtraction overflow",
\\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
\\ @import("std").os.exit(126);
diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig
@@ -11,15 +11,22 @@ comptime {
_ = @import("behavior/bswap.zig");
_ = @import("behavior/bugs/1076.zig");
_ = @import("behavior/bugs/1111.zig");
+ _ = @import("behavior/bugs/1120.zig");
_ = @import("behavior/bugs/1277.zig");
_ = @import("behavior/bugs/1322.zig");
_ = @import("behavior/bugs/1381.zig");
_ = @import("behavior/bugs/1421.zig");
_ = @import("behavior/bugs/1442.zig");
_ = @import("behavior/bugs/1486.zig");
+ _ = @import("behavior/bugs/1851.zig");
+ _ = @import("behavior/bugs/2006.zig");
_ = @import("behavior/bugs/394.zig");
+ _ = @import("behavior/bugs/421.zig");
+ _ = @import("behavior/bugs/529.zig");
_ = @import("behavior/bugs/655.zig");
_ = @import("behavior/bugs/656.zig");
+ _ = @import("behavior/bugs/704.zig");
+ _ = @import("behavior/bugs/718.zig");
_ = @import("behavior/bugs/726.zig");
_ = @import("behavior/bugs/828.zig");
_ = @import("behavior/bugs/920.zig");
@@ -59,6 +66,7 @@ comptime {
_ = @import("behavior/reflection.zig");
_ = @import("behavior/sizeof_and_typeof.zig");
_ = @import("behavior/slice.zig");
+ _ = @import("behavior/slicetobytes.zig");
_ = @import("behavior/struct.zig");
_ = @import("behavior/struct_contains_null_ptr_itself.zig");
_ = @import("behavior/struct_contains_slice_of_itself.zig");
diff --git a/test/stage1/behavior/bitcast.zig b/test/stage1/behavior/bitcast.zig
@@ -1,4 +1,5 @@
const std = @import("std");
+const builtin = @import("builtin");
const expect = std.testing.expect;
const maxInt = std.math.maxInt;
@@ -34,3 +35,80 @@ test "@bitCast extern enum to its integer type" {
SOCK.testBitCastExternEnum();
comptime SOCK.testBitCastExternEnum();
}
+
+test "@bitCast packed structs at runtime and comptime" {
+ const Full = packed struct {
+ number: u16,
+ };
+ const Divided = packed struct {
+ half1: u8,
+ quarter3: u4,
+ quarter4: u4,
+ };
+ const S = struct {
+ fn doTheTest() void {
+ var full = Full{ .number = 0x1234 };
+ var two_halves = @bitCast(Divided, full);
+ switch (builtin.endian) {
+ builtin.Endian.Big => {
+ expect(two_halves.half1 == 0x12);
+ expect(two_halves.quarter3 == 0x3);
+ expect(two_halves.quarter4 == 0x4);
+ },
+ builtin.Endian.Little => {
+ expect(two_halves.half1 == 0x34);
+ expect(two_halves.quarter3 == 0x2);
+ expect(two_halves.quarter4 == 0x1);
+ },
+ }
+ }
+ };
+ S.doTheTest();
+ comptime S.doTheTest();
+}
+
+test "@bitCast extern structs at runtime and comptime" {
+ const Full = extern struct {
+ number: u16,
+ };
+ const TwoHalves = extern struct {
+ half1: u8,
+ half2: u8,
+ };
+ const S = struct {
+ fn doTheTest() void {
+ var full = Full{ .number = 0x1234 };
+ var two_halves = @bitCast(TwoHalves, full);
+ switch (builtin.endian) {
+ builtin.Endian.Big => {
+ expect(two_halves.half1 == 0x12);
+ expect(two_halves.half2 == 0x34);
+ },
+ builtin.Endian.Little => {
+ expect(two_halves.half1 == 0x34);
+ expect(two_halves.half2 == 0x12);
+ },
+ }
+ }
+ };
+ S.doTheTest();
+ comptime S.doTheTest();
+}
+
+test "bitcast packed struct to integer and back" {
+ const LevelUpMove = packed struct {
+ move_id: u9,
+ level: u7,
+ };
+ const S = struct {
+ fn doTheTest() void {
+ var move = LevelUpMove{ .move_id = 1, .level = 2 };
+ var v = @bitCast(u16, move);
+ var back_to_a_move = @bitCast(LevelUpMove, v);
+ expect(back_to_a_move.move_id == 1);
+ expect(back_to_a_move.level == 2);
+ }
+ };
+ S.doTheTest();
+ comptime S.doTheTest();
+}
diff --git a/test/stage1/behavior/bugs/1120.zig b/test/stage1/behavior/bugs/1120.zig
@@ -0,0 +1,23 @@
+const std = @import("std");
+const expect = std.testing.expect;
+
+const A = packed struct {
+ a: u2,
+ b: u6,
+};
+const B = packed struct {
+ q: u8,
+ a: u2,
+ b: u6,
+};
+test "bug 1120" {
+ var a = A{ .a = 2, .b = 2 };
+ var b = B{ .q = 22, .a = 3, .b = 2 };
+ var t: usize = 0;
+ const ptr = switch (t) {
+ 0 => &a.a,
+ 1 => &b.a,
+ else => unreachable,
+ };
+ expect(ptr.* == 2);
+}
diff --git a/test/stage1/behavior/bugs/1851.zig b/test/stage1/behavior/bugs/1851.zig
@@ -0,0 +1,27 @@
+const std = @import("std");
+const expect = std.testing.expect;
+
+test "allocation and looping over 3-byte integer" {
+ expect(@sizeOf(u24) == 4);
+ expect(@sizeOf([1]u24) == 4);
+ expect(@alignOf(u24) == 4);
+ expect(@alignOf([1]u24) == 4);
+ var buffer: [100]u8 = undefined;
+ const a = &std.heap.FixedBufferAllocator.init(&buffer).allocator;
+
+ var x = a.alloc(u24, 2) catch unreachable;
+ expect(x.len == 2);
+ x[0] = 0xFFFFFF;
+ x[1] = 0xFFFFFF;
+
+ const bytes = @sliceToBytes(x);
+ expect(@typeOf(bytes) == []align(4) u8);
+ expect(bytes.len == 8);
+
+ for (bytes) |*b| {
+ b.* = 0x00;
+ }
+
+ expect(x[0] == 0x00);
+ expect(x[1] == 0x00);
+}
diff --git a/test/stage1/behavior/bugs/2006.zig b/test/stage1/behavior/bugs/2006.zig
@@ -0,0 +1,12 @@
+const std = @import("std");
+const expect = std.testing.expect;
+
+const S = struct {
+ p: *S,
+};
+test "bug 2006" {
+ var a: S = undefined;
+ a = S{ .p = undefined };
+ expect(@sizeOf(S) != 0);
+ expect(@sizeOf(*void) == 0);
+}
diff --git a/test/stage1/behavior/bugs/421.zig b/test/stage1/behavior/bugs/421.zig
@@ -0,0 +1,16 @@
+const assert = @import("std").debug.assert;
+
+test "bitCast to array" {
+ comptime testBitCastArray();
+ testBitCastArray();
+}
+
+fn testBitCastArray() void {
+ assert(extractOne64(0x0123456789abcdef0123456789abcdef) == 0x0123456789abcdef);
+}
+
+fn extractOne64(a: u128) u64 {
+ const x = @bitCast([2]u64, a);
+ return x[1];
+}
+
diff --git a/test/stage1/behavior/bugs/529.zig b/test/stage1/behavior/bugs/529.zig
@@ -0,0 +1,15 @@
+const A = extern struct {
+ field: c_int,
+};
+
+extern fn issue529(?*A) void;
+
+comptime {
+ _ = @import("529_other_file_2.zig");
+}
+
+test "issue 529 fixed" {
+ @import("529_other_file.zig").issue529(null);
+ issue529(null);
+}
+
diff --git a/test/stage1/behavior/bugs/529_other_file.zig b/test/stage1/behavior/bugs/529_other_file.zig
@@ -0,0 +1,5 @@
+pub const A = extern struct {
+ field: c_int,
+};
+
+pub extern fn issue529(?*A) void;
diff --git a/test/stage1/behavior/bugs/529_other_file_2.zig b/test/stage1/behavior/bugs/529_other_file_2.zig
@@ -0,0 +1,4 @@
+pub const A = extern struct {
+ field: c_int,
+};
+export fn issue529(a: ?*A) void {}
diff --git a/test/stage1/behavior/bugs/704.zig b/test/stage1/behavior/bugs/704.zig
@@ -0,0 +1,7 @@
+const xxx = struct {
+ pub fn bar(self: *xxx) void {}
+};
+test "bug 704" {
+ var x: xxx = undefined;
+ x.bar();
+}
diff --git a/test/stage1/behavior/bugs/718.zig b/test/stage1/behavior/bugs/718.zig
@@ -0,0 +1,17 @@
+const std = @import("std");
+const mem = std.mem;
+const expect = std.testing.expect;
+const Keys = struct {
+ up: bool,
+ down: bool,
+ left: bool,
+ right: bool,
+};
+var keys: Keys = undefined;
+test "zero keys with @memset" {
+ @memset(@ptrCast([*]u8, &keys), 0, @sizeOf(@typeOf(keys)));
+ expect(!keys.up);
+ expect(!keys.down);
+ expect(!keys.left);
+ expect(!keys.right);
+}
diff --git a/test/stage1/behavior/pointers.zig b/test/stage1/behavior/pointers.zig
@@ -1,5 +1,6 @@
const std = @import("std");
const expect = std.testing.expect;
+const expectError = std.testing.expectError;
test "dereference pointer" {
comptime testDerefPtr();
@@ -42,3 +43,84 @@ test "double pointer parsing" {
fn PtrOf(comptime T: type) type {
return *T;
}
+
+test "assigning integer to C pointer" {
+ var x: i32 = 0;
+ var ptr: [*c]u8 = 0;
+ var ptr2: [*c]u8 = x;
+}
+
+test "implicit cast single item pointer to C pointer and back" {
+ var y: u8 = 11;
+ var x: [*c]u8 = &y;
+ var z: *u8 = x;
+ z.* += 1;
+ expect(y == 12);
+}
+
+test "C pointer comparison and arithmetic" {
+ const S = struct {
+ fn doTheTest() void {
+ var one: usize = 1;
+ var ptr1: [*c]u32 = 0;
+ var ptr2 = ptr1 + 10;
+ expect(ptr1 == 0);
+ expect(ptr1 >= 0);
+ expect(ptr1 <= 0);
+ expect(ptr1 < 1);
+ expect(ptr1 < one);
+ expect(1 > ptr1);
+ expect(one > ptr1);
+ expect(ptr1 < ptr2);
+ expect(ptr2 > ptr1);
+ expect(ptr2 >= 40);
+ expect(ptr2 == 40);
+ expect(ptr2 <= 40);
+ ptr2 -= 10;
+ expect(ptr1 == ptr2);
+ }
+ };
+ S.doTheTest();
+ comptime S.doTheTest();
+}
+
+test "peer type resolution with C pointers" {
+ var ptr_one: *u8 = undefined;
+ var ptr_many: [*]u8 = undefined;
+ var ptr_c: [*c]u8 = undefined;
+ var t = true;
+ var x1 = if (t) ptr_one else ptr_c;
+ var x2 = if (t) ptr_many else ptr_c;
+ var x3 = if (t) ptr_c else ptr_one;
+ var x4 = if (t) ptr_c else ptr_many;
+ expect(@typeOf(x1) == [*c]u8);
+ expect(@typeOf(x2) == [*c]u8);
+ expect(@typeOf(x3) == [*c]u8);
+ expect(@typeOf(x4) == [*c]u8);
+}
+
+test "implicit casting between C pointer and optional non-C pointer" {
+ var slice: []const u8 = "aoeu";
+ const opt_many_ptr: ?[*]const u8 = slice.ptr;
+ var ptr_opt_many_ptr = &opt_many_ptr;
+ var c_ptr: [*c]const [*c]const u8 = ptr_opt_many_ptr;
+ expect(c_ptr.*.* == 'a');
+ ptr_opt_many_ptr = c_ptr;
+ expect(ptr_opt_many_ptr.*.?[1] == 'o');
+}
+
+test "implicit cast error unions with non-optional to optional pointer" {
+ const S = struct {
+ fn doTheTest() void {
+ expectError(error.Fail, foo());
+ }
+ fn foo() anyerror!?*u8 {
+ return bar() orelse error.Fail;
+ }
+ fn bar() ?*u8 {
+ return null;
+ }
+ };
+ S.doTheTest();
+ comptime S.doTheTest();
+}
diff --git a/test/stage1/behavior/ptrcast.zig b/test/stage1/behavior/ptrcast.zig
@@ -50,3 +50,11 @@ const Bytes = struct {
return res;
}
};
+
+test "comptime ptrcast keeps larger alignment" {
+ comptime {
+ const a: u32 = 1234;
+ const p = @ptrCast([*]const u8, &a);
+ std.debug.assert(@typeOf(p) == [*]align(@alignOf(u32)) const u8);
+ }
+}
diff --git a/test/stage1/behavior/slicetobytes.zig b/test/stage1/behavior/slicetobytes.zig
@@ -0,0 +1,29 @@
+const std = @import("std");
+const builtin = @import("builtin");
+const expect = std.testing.expect;
+
+test "@sliceToBytes packed struct at runtime and comptime" {
+ const Foo = packed struct {
+ a: u4,
+ b: u4,
+ };
+ const S = struct {
+ fn doTheTest() void {
+ var foo: Foo = undefined;
+ var slice = @sliceToBytes(((*[1]Foo)(&foo))[0..1]);
+ slice[0] = 0x13;
+ switch (builtin.endian) {
+ builtin.Endian.Big => {
+ expect(foo.a == 0x1);
+ expect(foo.b == 0x3);
+ },
+ builtin.Endian.Little => {
+ expect(foo.a == 0x3);
+ expect(foo.b == 0x1);
+ },
+ }
+ }
+ };
+ S.doTheTest();
+ comptime S.doTheTest();
+}
diff --git a/test/stage1/behavior/struct.zig b/test/stage1/behavior/struct.zig
@@ -1,5 +1,6 @@
const std = @import("std");
const expect = std.testing.expect;
+const expectEqualSlices = std.testing.expectEqualSlices;
const builtin = @import("builtin");
const maxInt = std.math.maxInt;
@@ -103,19 +104,20 @@ fn structInitializer() void {
}
test "fn call of struct field" {
- expect(callStructField(Foo{ .ptr = aFunc }) == 13);
-}
-
-const Foo = struct {
- ptr: fn () i32,
-};
+ const Foo = struct {
+ ptr: fn () i32,
+ };
+ const S = struct {
+ fn aFunc() i32 {
+ return 13;
+ }
-fn aFunc() i32 {
- return 13;
-}
+ fn callStructField(foo: Foo) i32 {
+ return foo.ptr();
+ }
+ };
-fn callStructField(foo: Foo) i32 {
- return foo.ptr();
+ expect(S.callStructField(Foo{ .ptr = S.aFunc }) == 13);
}
test "store member function in variable" {
@@ -468,3 +470,32 @@ test "pointer to packed struct member in a stack variable" {
b_ptr.* = 2;
expect(s.b == 2);
}
+
+test "non-byte-aligned array inside packed struct" {
+ const Foo = packed struct {
+ a: bool,
+ b: [0x16]u8,
+ };
+ const S = struct {
+ fn bar(slice: []const u8) void {
+ expectEqualSlices(u8, slice, "abcdefghijklmnopqurstu");
+ }
+ fn doTheTest() void {
+ var foo = Foo{
+ .a = true,
+ .b = "abcdefghijklmnopqurstu",
+ };
+ bar(foo.b);
+ }
+ };
+ S.doTheTest();
+ comptime S.doTheTest();
+}
+
+test "packed struct with u0 field access" {
+ const S = packed struct {
+ f0: u0,
+ };
+ var s = S{ .f0 = 0 };
+ comptime expect(s.f0 == 0);
+}
diff --git a/test/stage1/behavior/truncate.zig b/test/stage1/behavior/truncate.zig
@@ -29,3 +29,8 @@ test "truncate sign mismatch but comptime known so it works anyway" {
var result = @truncate(i8, x);
expect(result == 10);
}
+
+test "truncate on comptime integer" {
+ var x = @truncate(u16, 9999);
+ expect(x == 9999);
+}
diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig
@@ -61,6 +61,21 @@ fn testUnknownLenPtr() void {
expect(u32_ptr_info.Pointer.child == f64);
}
+test "type info: C pointer type info" {
+ testCPtr();
+ comptime testCPtr();
+}
+
+fn testCPtr() void {
+ const ptr_info = @typeInfo([*c]align(4) const i8);
+ expect(TypeId(ptr_info) == TypeId.Pointer);
+ expect(ptr_info.Pointer.size == TypeInfo.Pointer.Size.C);
+ expect(ptr_info.Pointer.is_const);
+ expect(!ptr_info.Pointer.is_volatile);
+ expect(ptr_info.Pointer.alignment == 4);
+ expect(ptr_info.Pointer.child == i8);
+}
+
test "type info: slice type info" {
testSlice();
comptime testSlice();
diff --git a/test/stage1/behavior/union.zig b/test/stage1/behavior/union.zig
@@ -350,3 +350,18 @@ test "union with only 1 field casted to its enum type which has enum value speci
expect(@enumToInt(t) == 33);
comptime expect(@enumToInt(t) == 33);
}
+
+test "@enumToInt works on unions" {
+ const Bar = union(enum) {
+ A: bool,
+ B: u8,
+ C,
+ };
+
+ const a = Bar{ .A = true };
+ var b = Bar{ .B = undefined };
+ var c = Bar.C;
+ expect(@enumToInt(a) == 0);
+ expect(@enumToInt(b) == 1);
+ expect(@enumToInt(c) == 2);
+}
diff --git a/test/stage1/behavior/vector.zig b/test/stage1/behavior/vector.zig
@@ -5,11 +5,57 @@ const expect = std.testing.expect;
test "vector wrap operators" {
const S = struct {
fn doTheTest() void {
- const v: @Vector(4, i32) = [4]i32{ 10, 20, 30, 40 };
- const x: @Vector(4, i32) = [4]i32{ 1, 2, 3, 4 };
- expect(mem.eql(i32, ([4]i32)(v +% x), [4]i32{ 11, 22, 33, 44 }));
- expect(mem.eql(i32, ([4]i32)(v -% x), [4]i32{ 9, 18, 27, 36 }));
- expect(mem.eql(i32, ([4]i32)(v *% x), [4]i32{ 10, 40, 90, 160 }));
+ var v: @Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 };
+ var x: @Vector(4, i32) = [4]i32{ 1, 2147483647, 3, 4 };
+ expect(mem.eql(i32, ([4]i32)(v +% x), [4]i32{ -2147483648, 2147483645, 33, 44 }));
+ expect(mem.eql(i32, ([4]i32)(v -% x), [4]i32{ 2147483646, 2147483647, 27, 36 }));
+ expect(mem.eql(i32, ([4]i32)(v *% x), [4]i32{ 2147483647, 2, 90, 160 }));
+ var z: @Vector(4, i32) = [4]i32{ 1, 2, 3, -2147483648 };
+ expect(mem.eql(i32, ([4]i32)(-%z), [4]i32{ -1, -2, -3, -2147483648 }));
+ }
+ };
+ S.doTheTest();
+ comptime S.doTheTest();
+}
+
+test "vector int operators" {
+ const S = struct {
+ fn doTheTest() void {
+ var v: @Vector(4, i32) = [4]i32{ 10, 20, 30, 40 };
+ var x: @Vector(4, i32) = [4]i32{ 1, 2, 3, 4 };
+ expect(mem.eql(i32, ([4]i32)(v + x), [4]i32{ 11, 22, 33, 44 }));
+ expect(mem.eql(i32, ([4]i32)(v - x), [4]i32{ 9, 18, 27, 36 }));
+ expect(mem.eql(i32, ([4]i32)(v * x), [4]i32{ 10, 40, 90, 160 }));
+ expect(mem.eql(i32, ([4]i32)(-v), [4]i32{ -10, -20, -30, -40 }));
+ }
+ };
+ S.doTheTest();
+ comptime S.doTheTest();
+}
+
+test "vector float operators" {
+ const S = struct {
+ fn doTheTest() void {
+ var v: @Vector(4, f32) = [4]f32{ 10, 20, 30, 40 };
+ var x: @Vector(4, f32) = [4]f32{ 1, 2, 3, 4 };
+ expect(mem.eql(f32, ([4]f32)(v + x), [4]f32{ 11, 22, 33, 44 }));
+ expect(mem.eql(f32, ([4]f32)(v - x), [4]f32{ 9, 18, 27, 36 }));
+ expect(mem.eql(f32, ([4]f32)(v * x), [4]f32{ 10, 40, 90, 160 }));
+ expect(mem.eql(f32, ([4]f32)(-x), [4]f32{ -1, -2, -3, -4 }));
+ }
+ };
+ S.doTheTest();
+ comptime S.doTheTest();
+}
+
+test "vector bit operators" {
+ const S = struct {
+ fn doTheTest() void {
+ var v: @Vector(4, u8) = [4]u8{ 0b10101010, 0b10101010, 0b10101010, 0b10101010 };
+ var x: @Vector(4, u8) = [4]u8{ 0b11110000, 0b00001111, 0b10101010, 0b01010101 };
+ expect(mem.eql(u8, ([4]u8)(v ^ x), [4]u8{ 0b01011010, 0b10100101, 0b00000000, 0b11111111 }));
+ expect(mem.eql(u8, ([4]u8)(v | x), [4]u8{ 0b11111010, 0b10101111, 0b10101010, 0b11111111 }));
+ expect(mem.eql(u8, ([4]u8)(v & x), [4]u8{ 0b10100000, 0b00001010, 0b10101010, 0b00000000 }));
}
};
S.doTheTest();
diff --git a/test/stage1/c_abi/build.zig b/test/stage1/c_abi/build.zig
@@ -3,9 +3,10 @@ const Builder = @import("std").build.Builder;
pub fn build(b: *Builder) void {
const rel_opts = b.standardReleaseOptions();
- const c_obj = b.addCObject("cfuncs", "cfuncs.c");
+ const c_obj = b.addObject("cfuncs", null);
+ c_obj.addCSourceFile("cfuncs.c", [][]const u8{"-std=c99"});
c_obj.setBuildMode(rel_opts);
- c_obj.setNoStdLib(true);
+ c_obj.linkSystemLibrary("c");
const main = b.addTest("main.zig");
main.setBuildMode(rel_opts);
diff --git a/test/tests.zig b/test/tests.zig
@@ -24,24 +24,24 @@ const gen_h = @import("gen_h.zig");
const TestTarget = struct {
os: builtin.Os,
arch: builtin.Arch,
- environ: builtin.Environ,
+ abi: builtin.Abi,
};
const test_targets = []TestTarget{
TestTarget{
.os = builtin.Os.linux,
.arch = builtin.Arch.x86_64,
- .environ = builtin.Environ.gnu,
+ .abi = builtin.Abi.gnu,
},
TestTarget{
.os = builtin.Os.macosx,
.arch = builtin.Arch.x86_64,
- .environ = builtin.Environ.unknown,
+ .abi = builtin.Abi.gnu,
},
TestTarget{
.os = builtin.Os.windows,
.arch = builtin.Arch.x86_64,
- .environ = builtin.Environ.msvc,
+ .abi = builtin.Abi.msvc,
},
};
@@ -189,7 +189,7 @@ pub fn addPkgTests(b: *build.Builder, test_filter: ?[]const u8, root_src: []cons
these_tests.setFilter(test_filter);
these_tests.setBuildMode(mode);
if (!is_native) {
- these_tests.setTarget(test_target.arch, test_target.os, test_target.environ);
+ these_tests.setTarget(test_target.arch, test_target.os, test_target.abi);
}
if (link_libc) {
these_tests.linkSystemLibrary("c");
@@ -536,6 +536,7 @@ pub const CompileErrorContext = struct {
name: []const u8,
sources: ArrayList(SourceFile),
expected_errors: ArrayList([]const u8),
+ expect_exact: bool,
link_libc: bool,
is_exe: bool,
is_test: bool,
@@ -565,6 +566,24 @@ pub const CompileErrorContext = struct {
case: *const TestCase,
build_mode: Mode,
+ const ErrLineIter = struct {
+ lines: mem.SplitIterator,
+
+ const source_file = ".tmp_source.zig";
+
+ fn init(input: []const u8) ErrLineIter {
+ return ErrLineIter{ .lines = mem.separate(input, "\n") };
+ }
+
+ fn next(self: *ErrLineIter) ?[]const u8 {
+ while (self.lines.next()) |line| {
+ if (mem.indexOf(u8, line, source_file) != null)
+ return line;
+ }
+ return null;
+ }
+ };
+
pub fn create(context: *CompileErrorContext, name: []const u8, case: *const TestCase, build_mode: Mode) *CompileCmpOutputStep {
const allocator = context.b.allocator;
const ptr = allocator.create(CompileCmpOutputStep) catch unreachable;
@@ -674,19 +693,49 @@ pub const CompileErrorContext = struct {
return error.TestFailed;
}
- for (self.case.expected_errors.toSliceConst()) |expected_error| {
- if (mem.indexOf(u8, stderr, expected_error) == null) {
- warn(
- \\
- \\========= Expected this compile error: =========
- \\{}
- \\================================================
- \\{}
- \\
- , expected_error, stderr);
- return error.TestFailed;
+ var ok = true;
+ if (self.case.expect_exact) {
+ var err_iter = ErrLineIter.init(stderr);
+ var i: usize = 0;
+ ok = while (err_iter.next()) |line| : (i += 1) {
+ if (i >= self.case.expected_errors.len) break false;
+ const expected = self.case.expected_errors.at(i);
+ if (mem.indexOf(u8, line, expected) == null) break false;
+ continue;
+ } else true;
+
+ ok = ok and i == self.case.expected_errors.len;
+
+ if (!ok) {
+ warn("\n======== Expected these compile errors: ========\n");
+ for (self.case.expected_errors.toSliceConst()) |expected| {
+ warn("{}\n", expected);
+ }
+ }
+ } else {
+ for (self.case.expected_errors.toSliceConst()) |expected| {
+ if (mem.indexOf(u8, stderr, expected) == null) {
+ warn(
+ \\
+ \\=========== Expected compile error: ============
+ \\{}
+ \\
+ , expected);
+ ok = false;
+ break;
+ }
}
}
+
+ if (!ok) {
+ warn(
+ \\================= Full output: =================
+ \\{}
+ \\
+ , stderr);
+ return error.TestFailed;
+ }
+
warn("OK\n");
}
};
@@ -704,6 +753,7 @@ pub const CompileErrorContext = struct {
.name = name,
.sources = ArrayList(TestCase.SourceFile).init(self.b.allocator),
.expected_errors = ArrayList([]const u8).init(self.b.allocator),
+ .expect_exact = false,
.link_libc = false,
.is_exe = false,
.is_test = false,
diff --git a/test/translate_c.zig b/test/translate_c.zig
@@ -117,11 +117,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\};
,
\\pub const struct_Foo = extern struct {
- \\ a: ?[*]Foo,
+ \\ a: [*c]Foo,
\\};
\\pub const Foo = struct_Foo;
\\pub const struct_Bar = extern struct {
- \\ a: ?[*]Foo,
+ \\ a: [*c]Foo,
\\};
);
@@ -213,7 +213,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
,
\\const struct_Foo = extern struct {
\\ x: c_int,
- \\ y: ?[*]u8,
+ \\ y: [*c]u8,
\\};
,
\\pub const Foo = struct_Foo;
@@ -244,7 +244,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
,
\\pub const BarB = enum_Bar.B;
,
- \\pub extern fn func(a: ?[*]struct_Foo, b: ?[*](?[*]enum_Bar)) void;
+ \\pub extern fn func(a: [*c]struct_Foo, b: [*c]([*c]enum_Bar)) void;
,
\\pub const Foo = struct_Foo;
,
@@ -254,7 +254,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
cases.add("constant size array",
\\void func(int array[20]);
,
- \\pub extern fn func(array: ?[*]c_int) void;
+ \\pub extern fn func(array: [*c]c_int) void;
);
cases.add("self referential struct with function pointer",
@@ -263,7 +263,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\};
,
\\pub const struct_Foo = extern struct {
- \\ derp: ?extern fn(?[*]struct_Foo) void,
+ \\ derp: ?extern fn([*c]struct_Foo) void,
\\};
,
\\pub const Foo = struct_Foo;
@@ -322,11 +322,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\};
,
\\pub const struct_Bar = extern struct {
- \\ next: ?[*]struct_Foo,
+ \\ next: [*c]struct_Foo,
\\};
,
\\pub const struct_Foo = extern struct {
- \\ next: ?[*]struct_Bar,
+ \\ next: [*c]struct_Bar,
\\};
);
@@ -610,11 +610,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
,
\\pub export fn and_or_none_bool(a: c_int, b: f32, c: ?*c_void) c_int {
\\ if ((a != 0) and (b != 0)) return 0;
- \\ if ((b != 0) and (c != null)) return 1;
- \\ if ((a != 0) and (c != null)) return 2;
+ \\ if ((b != 0) and (c != 0)) return 1;
+ \\ if ((a != 0) and (c != 0)) return 2;
\\ if ((a != 0) or (b != 0)) return 3;
- \\ if ((b != 0) or (c != null)) return 4;
- \\ if ((a != 0) or (c != null)) return 5;
+ \\ if ((b != 0) or (c != 0)) return 4;
+ \\ if ((a != 0) or (c != 0)) return 5;
\\ return 6;
\\}
);
@@ -710,7 +710,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub const struct_Foo = extern struct {
\\ field: c_int,
\\};
- \\pub export fn read_field(foo: ?[*]struct_Foo) c_int {
+ \\pub export fn read_field(foo: [*c]struct_Foo) c_int {
\\ return foo.?.field;
\\}
);
@@ -756,7 +756,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ return x;
\\}
,
- \\pub export fn foo(x: ?[*]c_ushort) ?*c_void {
+ \\pub export fn foo(x: [*c]c_ushort) ?*c_void {
\\ return @ptrCast(?*c_void, x);
\\}
);
@@ -777,8 +777,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ return 0;
\\}
,
- \\pub export fn foo() ?[*]c_int {
- \\ return null;
+ \\pub export fn foo() [*c]c_int {
+ \\ return 0;
\\}
);
@@ -1086,7 +1086,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ *x = 1;
\\}
,
- \\pub export fn foo(x: ?[*]c_int) void {
+ \\pub export fn foo(x: [*c]c_int) void {
\\ x.?.* = 1;
\\}
);
@@ -1114,7 +1114,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
,
\\pub fn foo() c_int {
\\ var x: c_int = 1234;
- \\ var ptr: ?[*]c_int = &x;
+ \\ var ptr: [*c]c_int = &x;
\\ return ptr.?.*;
\\}
);
@@ -1124,7 +1124,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ return "bar";
\\}
,
- \\pub fn foo() ?[*]const u8 {
+ \\pub fn foo() [*c]const u8 {
\\ return c"bar";
\\}
);
@@ -1253,8 +1253,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ return (float *)a;
\\}
,
- \\fn ptrcast(a: ?[*]c_int) ?[*]f32 {
- \\ return @ptrCast(?[*]f32, a);
+ \\fn ptrcast(a: [*c]c_int) [*c]f32 {
+ \\ return @ptrCast([*c]f32, a);
\\}
);
@@ -1280,7 +1280,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ return !(a == 0);
\\ return !(a != 0);
\\ return !(b != 0);
- \\ return !(c != null);
+ \\ return !(c != 0);
\\}
);
@@ -1297,7 +1297,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
cases.add("const ptr initializer",
\\static const char *v0 = "0.0.0";
,
- \\pub var v0: ?[*]const u8 = c"0.0.0";
+ \\pub var v0: [*c]const u8 = c"0.0.0";
);
cases.add("static incomplete array inside function",
@@ -1306,17 +1306,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
,
\\pub fn foo() void {
- \\ const v2: [*]const u8 = c"2.2.2";
+ \\ const v2: [*c]const u8 = c"2.2.2";
\\}
);
cases.add("macro pointer cast",
\\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)
,
- \\pub const NRF_GPIO = if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Pointer) @ptrCast([*]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Int) @intToPtr([*]NRF_GPIO_Type, NRF_GPIO_BASE) else ([*]NRF_GPIO_Type)(NRF_GPIO_BASE);
+ \\pub const NRF_GPIO = if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else ([*c]NRF_GPIO_Type)(NRF_GPIO_BASE);
);
- cases.add("if on none bool",
+ cases.add("if on non-bool",
\\enum SomeEnum { A, B, C };
\\int if_none_bool(int a, float b, void *c, enum SomeEnum d) {
\\ if (a) return 0;
@@ -1337,13 +1337,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub fn if_none_bool(a: c_int, b: f32, c: ?*c_void, d: enum_SomeEnum) c_int {
\\ if (a != 0) return 0;
\\ if (b != 0) return 1;
- \\ if (c != null) return 2;
+ \\ if (c != 0) return 2;
\\ if (d != @bitCast(enum_SomeEnum, @TagType(enum_SomeEnum)(0))) return 3;
\\ return 4;
\\}
);
- cases.add("while on none bool",
+ cases.add("while on non-bool",
\\int while_none_bool(int a, float b, void *c) {
\\ while (a) return 0;
\\ while (b) return 1;
@@ -1354,12 +1354,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub fn while_none_bool(a: c_int, b: f32, c: ?*c_void) c_int {
\\ while (a != 0) return 0;
\\ while (b != 0) return 1;
- \\ while (c != null) return 2;
+ \\ while (c != 0) return 2;
\\ return 3;
\\}
);
- cases.add("for on none bool",
+ cases.add("for on non-bool",
\\int for_none_bool(int a, float b, void *c) {
\\ for (;a;) return 0;
\\ for (;b;) return 1;
@@ -1370,7 +1370,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub fn for_none_bool(a: c_int, b: f32, c: ?*c_void) c_int {
\\ while (a != 0) return 0;
\\ while (b != 0) return 1;
- \\ while (c != null) return 2;
+ \\ while (c != 0) return 2;
\\ return 3;
\\}
);
@@ -1416,4 +1416,42 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ }
\\}
);
+
+ cases.addC("Parameterless function prototypes",
+ \\void foo() {}
+ \\void bar(void) {}
+ ,
+ \\pub export fn foo() void {}
+ \\pub export fn bar() void {}
+ );
+
+ // cases.add("empty array with initializer",
+ // "int a[4] = {};"
+ // ,
+ // "pub var a: [4]c_int = [1]c_int{0} ** 4;"
+ // );
+
+ // cases.add("array with initialization",
+ // "int a[4] = {1, 2, 3, 4};"
+ // ,
+ // "pub var a: [4]c_int = [4]c_int{1, 2, 3, 4};"
+ // );
+
+ // cases.add("array with incomplete initialization",
+ // "int a[4] = {3, 4};"
+ // ,
+ // "pub var a: [4]c_int = [2]c_int{3, 4} ++ ([1]c_int{0} ** 2);"
+ // );
+
+ // cases.add("2D array with initialization",
+ // "int a[3][3] = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };"
+ // ,
+ // "pub var a: [3][3]c_int = [3][3]c_int{[3]c_int{1, 2, 3}, [3]c_int{4, 5, 6}, [3]c_int{7, 8, 9}};"
+ // );
+
+ // cases.add("2D array with incomplete initialization",
+ // "int a[3][3] = { {1, 2}, {4, 5, 6} };"
+ // ,
+ // "pub var a: [3][3]c_int = [2][3]c_int{[2]c_int{1, 2} ++ [1]c_int{0}, [3]c_int{4, 5, 6}} ++ [1][3]c_int{[1]c_int{0} ** 3};"
+ // );
}