diff --git a/CMakeLists.txt b/CMakeLists.txt index d8e2d9ff7a199d08f704d3a66f070279e9f3335b..1cf2f2d8e61899cd279cf017e165e21268fb3c1e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,8 @@ option(ZIG_FORCE_EXTERNAL_LLD "If your system has the LLD patches use it instead find_package(llvm) find_package(clang) +set(ZIG_CPP_LIB_DIR "${CMAKE_BINARY_DIR}/zig_cpp") + if(ZIG_FORCE_EXTERNAL_LLD) find_package(lld) include_directories(${LLVM_INCLUDE_DIRS}) @@ -192,6 +194,7 @@ else() embedded_lld_coff embedded_lld_lib ) + install(TARGETS embedded_lld_elf embedded_lld_coff embedded_lld_lib DESTINATION "${ZIG_CPP_LIB_DIR}") endif() # No patches have been applied to SoftFloat-3d @@ -345,6 +348,8 @@ set(ZIG_SOURCES "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp" "${CMAKE_SOURCE_DIR}/src/util.cpp" "${CMAKE_SOURCE_DIR}/src/translate_c.cpp" +) +set(ZIG_CPP_SOURCES "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp" ) @@ -390,6 +395,11 @@ if(ZIG_TEST_COVERAGE) set(EXE_LDFLAGS "${EXE_LDFLAGS} -fprofile-arcs -ftest-coverage") endif() +add_library(zig_cpp STATIC ${ZIG_CPP_SOURCES}) +set_target_properties(zig_cpp PROPERTIES + COMPILE_FLAGS ${EXE_CFLAGS} +) + add_executable(zig ${ZIG_SOURCES}) set_target_properties(zig PROPERTIES COMPILE_FLAGS ${EXE_CFLAGS} @@ -397,6 +407,7 @@ set_target_properties(zig PROPERTIES ) target_link_libraries(zig LINK_PUBLIC + zig_cpp ${SOFTFLOAT_LIBRARIES} ${CLANG_LIBRARIES} ${LLD_LIBRARIES} @@ -407,6 +418,7 @@ if(MSVC OR MINGW) target_link_libraries(zig LINK_PUBLIC version) endif() install(TARGETS zig DESTINATION bin) +install(TARGETS zig_cpp DESTINATION "${ZIG_CPP_LIB_DIR}") install(FILES "${CMAKE_SOURCE_DIR}/c_headers/__clang_cuda_builtin_vars.h" DESTINATION "${C_HEADERS_DEST}") install(FILES "${CMAKE_SOURCE_DIR}/c_headers/__clang_cuda_cmath.h" DESTINATION "${C_HEADERS_DEST}") @@ -516,7 +528,8 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/c/index.zig" DESTINATION "${ZIG_STD_DEST} install(FILES "${CMAKE_SOURCE_DIR}/std/c/linux.zig" DESTINATION "${ZIG_STD_DEST}/c") install(FILES "${CMAKE_SOURCE_DIR}/std/c/windows.zig" DESTINATION "${ZIG_STD_DEST}/c") install(FILES "${CMAKE_SOURCE_DIR}/std/cstr.zig" DESTINATION "${ZIG_STD_DEST}") -install(FILES "${CMAKE_SOURCE_DIR}/std/debug.zig" DESTINATION "${ZIG_STD_DEST}") +install(FILES "${CMAKE_SOURCE_DIR}/std/debug/index.zig" DESTINATION "${ZIG_STD_DEST}/debug") +install(FILES "${CMAKE_SOURCE_DIR}/std/debug/failing_allocator.zig" DESTINATION "${ZIG_STD_DEST}/debug") install(FILES "${CMAKE_SOURCE_DIR}/std/dwarf.zig" DESTINATION "${ZIG_STD_DEST}") install(FILES "${CMAKE_SOURCE_DIR}/std/elf.zig" DESTINATION "${ZIG_STD_DEST}") install(FILES "${CMAKE_SOURCE_DIR}/std/empty.zig" DESTINATION "${ZIG_STD_DEST}") @@ -618,16 +631,3 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/udivti3.zig" DESTINAT install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/umodti3.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt") install(FILES "${CMAKE_SOURCE_DIR}/std/special/panic.zig" DESTINATION "${ZIG_STD_DEST}/special") install(FILES "${CMAKE_SOURCE_DIR}/std/special/test_runner.zig" DESTINATION "${ZIG_STD_DEST}/special") - -if (ZIG_TEST_COVERAGE) - add_custom_target(coverage - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - COMMAND lcov --directory . --zerocounters --rc lcov_branch_coverage=1 - COMMAND ./zig build --build-file ../build.zig test - COMMAND lcov --directory . --capture --output-file coverage.info --rc lcov_branch_coverage=1 - COMMAND lcov --remove coverage.info '/usr/*' --output-file coverage.info.cleaned --rc lcov_branch_coverage=1 - COMMAND genhtml -o coverage coverage.info.cleaned --rc lcov_branch_coverage=1 - COMMAND rm coverage.info coverage.info.cleaned - ) -endif() - diff --git a/README.md b/README.md index 7598c623c3c9093f44bc11bfbb0e471b93f68f0c..914383729908f60fc82323a89582c8f28d27e642 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ clarity. always compiled against statically in source form. Compile units do not depend on libc unless explicitly linked. * Nullable type instead of null pointers. - * Tagged union type instead of raw unions. + * Safe unions, tagged unions, and C ABI compatible unions. * Generics so that one can write efficient data structures that work for any data type. * No header files required. Top level declarations are entirely @@ -35,7 +35,7 @@ clarity. * Partial compile-time function evaluation with eliminates the need for a preprocessor or macros. * The binaries produced by Zig have complete debugging information so you can, - for example, use GDB to debug your software. + for example, use GDB or MSVC to debug your software. * Built-in unit tests with `zig test`. * Friendly toward package maintainers. Reproducible build, bootstrapping process carefully documented. Issues filed by package maintainers are @@ -78,10 +78,10 @@ that counts as "freestanding" for the purposes of this table. ### Wanted: Windows Developers -Help get the tests passing on Windows, flesh out the standard library for -Windows, streamline Zig installation and distribution for Windows. Work with -LLVM and LLD teams to improve PDB/CodeView/MSVC debugging. Implement stack traces -for Windows in the MinGW environment and the MSVC environment. +Flesh out the standard library for Windows, streamline Zig installation and +distribution for Windows. Work with LLVM and LLD teams to improve +PDB/CodeView/MSVC debugging. Implement stack traces for Windows in the MinGW +environment and the MSVC environment. ### Wanted: MacOS and iOS Developers @@ -178,6 +178,10 @@ Dependencies are the same as Stage 1, except now you have a working zig compiler bin/zig build --build-file ../build.zig --prefix $(pwd)/stage2 install ``` +This produces `./stage2/bin/zig` which can be used for testing and development. +Once it is feature complete, it will be used to build stage 3 - the final compiler +binary. + ### Stage 3: Rebuild Self-Hosted Zig Using the Self-Hosted Compiler This is the actual compiler binary that we will install to the system. @@ -194,20 +198,6 @@ This is the actual compiler binary that we will install to the system. ./stage2/bin/zig build --build-file ../build.zig install -Drelease-fast ``` -### Test Coverage - -To see test coverage in Zig, configure with `-DZIG_TEST_COVERAGE=ON` as an -additional parameter to the Debug build. - -You must have `lcov` installed and available. - -Then `make coverage`. - -With GCC you will get a nice HTML view of the coverage data. With clang, -the last step will fail, but you can execute -`llvm-cov gcov $(find CMakeFiles/ -name "*.gcda")` and then inspect the -produced .gcov files. - ### Related Projects * [zig-mode](https://github.com/AndreaOrru/zig-mode) - Emacs integration diff --git a/build.zig b/build.zig index dbb54f8c3e6d12d9b2c50705c62cb319e467c2f9..cfc83cf424f73d3cc3fa538ad89503483d4431be 100644 --- a/build.zig +++ b/build.zig @@ -1,3 +1,4 @@ +const builtin = @import("builtin"); const std = @import("std"); const Builder = std.build.Builder; const tests = @import("test/tests.zig"); @@ -33,11 +34,32 @@ pub fn build(b: &Builder) { docs_step.dependOn(&docgen_home_cmd.step); if (findLLVM(b)) |llvm| { + // find the stage0 build artifacts because we're going to re-use config.h and zig_cpp library + const build_info = b.exec([][]const u8{b.zig_exe, "BUILD_INFO"}); + var build_info_it = mem.split(build_info, "\n"); + const cmake_binary_dir = ??build_info_it.next(); + const cxx_compiler = ??build_info_it.next(); + var exe = b.addExecutable("zig", "src-self-hosted/main.zig"); exe.setBuildMode(mode); - exe.linkSystemLibrary("c"); + exe.addIncludeDir("src"); + exe.addIncludeDir(cmake_binary_dir); + addCppLib(b, exe, cmake_binary_dir, "libzig_cpp"); + addCppLib(b, exe, cmake_binary_dir, "libembedded_lld_elf"); + addCppLib(b, exe, cmake_binary_dir, "libembedded_lld_coff"); + addCppLib(b, exe, cmake_binary_dir, "libembedded_lld_lib"); dependOnLib(exe, llvm); + if (!exe.target.isWindows()) { + const libstdcxx_path_padded = b.exec([][]const u8{cxx_compiler, "-print-file-name=libstdc++.a"}); + const libstdcxx_path = ??mem.split(libstdcxx_path_padded, "\n").next(); + exe.addObjectFile(libstdcxx_path); + + exe.linkSystemLibrary("pthread"); + } + + exe.linkSystemLibrary("c"); + b.default_step.dependOn(&exe.step); b.default_step.dependOn(docs_step); @@ -91,6 +113,11 @@ fn dependOnLib(lib_exe_obj: &std.build.LibExeObjStep, dep: &const LibraryDep) { } } +fn addCppLib(b: &Builder, lib_exe_obj: &std.build.LibExeObjStep, cmake_binary_dir: []const u8, lib_name: []const u8) { + lib_exe_obj.addObjectFile(%%os.path.join(b.allocator, cmake_binary_dir, "zig_cpp", + b.fmt("{}{}", lib_name, lib_exe_obj.target.libFileExt()))); +} + const LibraryDep = struct { libdirs: ArrayList([]const u8), libs: ArrayList([]const u8), @@ -172,7 +199,8 @@ pub fn installStdLib(b: &Builder) { "c/linux.zig", "c/windows.zig", "cstr.zig", - "debug.zig", + "debug/failing_allocator.zig", + "debug/index.zig", "dwarf.zig", "elf.zig", "empty.zig", diff --git a/doc/langref.html.in b/doc/langref.html.in index 162c8b3e0322fbc6ad01262ec122daf8645ee739..c35e3262543a081001afbd02a94bd7734e48bb39 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -291,6 +291,15 @@ pub fn main() -> %void {
Zig source code is encoded in UTF-8. An invalid UTF-8 byte sequence results in a compile error.
+Throughout all zig source code (including in comments), some codepoints are never allowed:
+The codepoint U+000a (LF) (which is encoded as the single-byte value 0x0a) is the line terminator character. This character always terminates a line of zig source code. A non-empty zig source must end with the line terminator character.
+For some discussion on the rationale behind these design decisions, see issue #663
const warn = @import("std").debug.warn;
const os = @import("std").os;
diff --git a/src-self-hosted/c.zig b/src-self-hosted/c.zig
index b7e057b941bb1e3f67a87f1f724936e8f57460b8..9a4b56adeac456663f325dab9d6d615e1f55474d 100644
--- a/src-self-hosted/c.zig
+++ b/src-self-hosted/c.zig
@@ -1,7 +1,4 @@
pub use @cImport({
- @cInclude("llvm-c/Core.h");
- @cInclude("llvm-c/Analysis.h");
- @cInclude("llvm-c/Target.h");
- @cInclude("llvm-c/Initialization.h");
- @cInclude("llvm-c/TargetMachine.h");
+ @cInclude("config.h");
+ @cInclude("zig_llvm.h");
});
diff --git a/src-self-hosted/ir.zig b/src-self-hosted/ir.zig
new file mode 100644
index 0000000000000000000000000000000000000000..b25bb183c55cd4cbf8a22b56e6cd1c865addbb64
--- /dev/null
+++ b/src-self-hosted/ir.zig
@@ -0,0 +1,112 @@
+const Scope = @import("scope.zig").Scope;
+
+pub const Instruction = struct {
+ id: Id,
+ scope: &Scope,
+
+ pub const Id = enum {
+ Br,
+ CondBr,
+ SwitchBr,
+ SwitchVar,
+ SwitchTarget,
+ Phi,
+ UnOp,
+ BinOp,
+ DeclVar,
+ LoadPtr,
+ StorePtr,
+ FieldPtr,
+ StructFieldPtr,
+ UnionFieldPtr,
+ ElemPtr,
+ VarPtr,
+ Call,
+ Const,
+ Return,
+ Cast,
+ ContainerInitList,
+ ContainerInitFields,
+ StructInit,
+ UnionInit,
+ Unreachable,
+ TypeOf,
+ ToPtrType,
+ PtrTypeChild,
+ SetDebugSafety,
+ SetFloatMode,
+ ArrayType,
+ SliceType,
+ Asm,
+ SizeOf,
+ TestNonNull,
+ UnwrapMaybe,
+ MaybeWrap,
+ UnionTag,
+ Clz,
+ Ctz,
+ Import,
+ CImport,
+ CInclude,
+ CDefine,
+ CUndef,
+ ArrayLen,
+ Ref,
+ MinValue,
+ MaxValue,
+ CompileErr,
+ CompileLog,
+ ErrName,
+ EmbedFile,
+ Cmpxchg,
+ Fence,
+ Truncate,
+ IntType,
+ BoolNot,
+ Memset,
+ Memcpy,
+ Slice,
+ MemberCount,
+ MemberType,
+ MemberName,
+ Breakpoint,
+ ReturnAddress,
+ FrameAddress,
+ AlignOf,
+ OverflowOp,
+ TestErr,
+ UnwrapErrCode,
+ UnwrapErrPayload,
+ ErrWrapCode,
+ ErrWrapPayload,
+ FnProto,
+ TestComptime,
+ PtrCast,
+ BitCast,
+ WidenOrShorten,
+ IntToPtr,
+ PtrToInt,
+ IntToEnum,
+ IntToErr,
+ ErrToInt,
+ CheckSwitchProngs,
+ CheckStatementIsVoid,
+ TypeName,
+ CanImplicitCast,
+ DeclRef,
+ Panic,
+ TagName,
+ TagType,
+ FieldParentPtr,
+ OffsetOf,
+ TypeId,
+ SetEvalBranchQuota,
+ PtrTypeOf,
+ AlignCast,
+ OpaqueType,
+ SetAlignStack,
+ ArgType,
+ Export,
+ };
+
+};
diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig
index 6fdacda4b27d1e7225463f2980ac8d3ee0316fb3..ff8fb37b42e4024dababeb01aeb1ea08baaf20ce 100644
--- a/src-self-hosted/main.zig
+++ b/src-self-hosted/main.zig
@@ -12,6 +12,7 @@ const ErrColor = Module.ErrColor;
const Emit = Module.Emit;
const builtin = @import("builtin");
const ArrayList = std.ArrayList;
+const c = @import("c.zig");
error InvalidCommandLineArguments;
error ZigLibDirNotFound;
@@ -462,7 +463,11 @@ pub fn main2() -> %void {
else => unreachable,
}
},
- Cmd.Version => @panic("TODO zig version"),
+ Cmd.Version => {
+ var stdout_file = %return io.getStdErr();
+ %return stdout_file.write(std.cstr.toSliceConst(c.ZIG_VERSION_STRING));
+ %return stdout_file.write("\n");
+ },
Cmd.Targets => @panic("TODO zig targets"),
}
}
diff --git a/src-self-hosted/module.zig b/src-self-hosted/module.zig
index 700ccf01762e73bebd6bfed210a033a3fb182dbe..a0cbe9c864edfebdfb572981a40e7f071a0de998 100644
--- a/src-self-hosted/module.zig
+++ b/src-self-hosted/module.zig
@@ -199,6 +199,13 @@ pub const Module = struct {
}
pub fn build(self: &Module) -> %void {
+ if (self.llvm_argv.len != 0) {
+ var c_compatible_args = %return std.cstr.NullTerminated2DArray.fromSlices(self.allocator,
+ [][]const []const u8 { [][]const u8{"zig (LLVM option parsing)"}, self.llvm_argv, });
+ defer c_compatible_args.deinit();
+ c.ZigLLVMParseCommandLineOptions(self.llvm_argv.len + 1, c_compatible_args.ptr);
+ }
+
const root_src_path = self.root_src_path ?? @panic("TODO handle null root src path");
const root_src_real_path = os.path.real(self.allocator, root_src_path) %% |err| {
%return printError("unable to open '{}': {}", root_src_path, err);
diff --git a/src-self-hosted/parser.zig b/src-self-hosted/parser.zig
index c997536ce2df5267e9316f07029dc5ffbaec4338..faba8e6059c7dab26d383ba943ba484f9c3cd9f6 100644
--- a/src-self-hosted/parser.zig
+++ b/src-self-hosted/parser.zig
@@ -1119,18 +1119,24 @@ fn testCanonical(source: []const u8) {
break :x failing_allocator.index;
};
- // TODO make this pass
- //var fail_index = needed_alloc_count;
- //while (fail_index != 0) {
- // fail_index -= 1;
- // var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
- // var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, fail_index);
- // if (testParse(source, &failing_allocator.allocator)) |_| {
- // @panic("non-deterministic memory usage");
- // } else |err| {
- // assert(err == error.OutOfMemory);
- // }
- //}
+ var fail_index: usize = 0;
+ while (fail_index < needed_alloc_count) : (fail_index += 1) {
+ var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
+ var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, fail_index);
+ if (testParse(source, &failing_allocator.allocator)) |_| {
+ @panic("non-deterministic memory usage");
+ } else |err| {
+ assert(err == error.OutOfMemory);
+ // TODO make this pass
+ //if (failing_allocator.allocated_bytes != failing_allocator.freed_bytes) {
+ // warn("\nfail_index: {}/{}\nallocated bytes: {}\nfreed bytes: {}\nallocations: {}\ndeallocations: {}\n",
+ // fail_index, needed_alloc_count,
+ // failing_allocator.allocated_bytes, failing_allocator.freed_bytes,
+ // failing_allocator.index, failing_allocator.deallocations);
+ // @panic("memory leak detected");
+ //}
+ }
+ }
}
test "zig fmt" {
diff --git a/src-self-hosted/scope.zig b/src-self-hosted/scope.zig
new file mode 100644
index 0000000000000000000000000000000000000000..05e586daaeb8c9d8104818c8905effbaf9c8b062
--- /dev/null
+++ b/src-self-hosted/scope.zig
@@ -0,0 +1,16 @@
+pub const Scope = struct {
+ id: Id,
+ parent: &Scope,
+
+ pub const Id = enum {
+ Decls,
+ Block,
+ Defer,
+ DeferExpr,
+ VarDecl,
+ CImport,
+ Loop,
+ FnDef,
+ CompTime,
+ };
+};
diff --git a/src-self-hosted/tokenizer.zig b/src-self-hosted/tokenizer.zig
index 570d41fa7e1b2fbc4ab722c04a066f2da307be1c..49225447a8b6e3dbcae2d1b904d5a9fffa69dc73 100644
--- a/src-self-hosted/tokenizer.zig
+++ b/src-self-hosted/tokenizer.zig
@@ -70,6 +70,7 @@ pub const Token = struct {
Identifier,
StringLiteral: StrLitKind,
Eof,
+ NoEolAtEof,
Builtin,
Bang,
Equal,
@@ -139,6 +140,8 @@ pub const Token = struct {
pub const Tokenizer = struct {
buffer: []const u8,
index: usize,
+ actual_file_end: usize,
+ pending_invalid_token: ?Token,
pub const Location = struct {
line: usize,
@@ -177,9 +180,17 @@ pub const Tokenizer = struct {
}
pub fn init(buffer: []const u8) -> Tokenizer {
+ var source_len = buffer.len;
+ while (source_len > 0) : (source_len -= 1) {
+ if (buffer[source_len - 1] == '\n') break;
+ // last line is incomplete, so skip it, and give an error when we get there.
+ }
+
return Tokenizer {
- .buffer = buffer,
+ .buffer = buffer[0..source_len],
.index = 0,
+ .actual_file_end = buffer.len,
+ .pending_invalid_token = null,
};
}
@@ -207,6 +218,10 @@ pub const Tokenizer = struct {
};
pub fn next(self: &Tokenizer) -> Token {
+ if (self.pending_invalid_token) |token| {
+ self.pending_invalid_token = null;
+ return token;
+ }
var state = State.Start;
var result = Token {
.id = Token.Id.Eof,
@@ -352,7 +367,7 @@ pub const Tokenizer = struct {
break;
},
'\n' => break, // Look for this error later.
- else => {},
+ else => self.checkLiteralCharacter(),
},
State.StringLiteralBackslash => switch (c) {
@@ -439,7 +454,7 @@ pub const Tokenizer = struct {
.end = undefined,
};
},
- else => {},
+ else => self.checkLiteralCharacter(),
},
State.Zero => switch (c) {
'b', 'o', 'x' => {
@@ -497,13 +512,211 @@ pub const Tokenizer = struct {
}
}
result.end = self.index;
- // TODO check state when returning EOF
+ if (result.id == Token.Id.Eof) {
+ if (self.pending_invalid_token) |token| {
+ self.pending_invalid_token = null;
+ return token;
+ }
+ if (self.actual_file_end != self.buffer.len) {
+ // instead of an Eof, give an error token
+ result.id = Token.Id.NoEolAtEof;
+ result.end = self.actual_file_end;
+ }
+ }
return result;
}
pub fn getTokenSlice(self: &const Tokenizer, token: &const Token) -> []const u8 {
return self.buffer[token.start..token.end];
}
+
+ fn checkLiteralCharacter(self: &Tokenizer) {
+ if (self.pending_invalid_token != null) return;
+ const invalid_length = self.getInvalidCharacterLength();
+ if (invalid_length == 0) return;
+ self.pending_invalid_token = Token {
+ .id = Token.Id.Invalid,
+ .start = self.index,
+ .end = self.index + invalid_length,
+ };
+ }
+
+ fn getInvalidCharacterLength(self: &Tokenizer) -> u3 {
+ const c0 = self.buffer[self.index];
+ if (c0 < 0x80) {
+ if (c0 < 0x20 or c0 == 0x7f) {
+ // ascii control codes are never allowed
+ // (note that \n was checked before we got here)
+ return 1;
+ }
+ // looks fine to me.
+ return 0;
+ } else {
+ // check utf8-encoded character.
+ // remember that the last byte in the buffer is guaranteed to be '\n',
+ // which means we really don't need to do bounds checks here,
+ // as long as we check one byte at a time for being a continuation byte.
+ var value: u32 = undefined;
+ var length: u3 = undefined;
+ if (c0 & 0b11100000 == 0b11000000) {value = c0 & 0b00011111; length = 2;}
+ else if (c0 & 0b11110000 == 0b11100000) {value = c0 & 0b00001111; length = 3;}
+ else if (c0 & 0b11111000 == 0b11110000) {value = c0 & 0b00000111; length = 4;}
+ else return 1; // unexpected continuation or too many leading 1's
+
+ const c1 = self.buffer[self.index + 1];
+ if (c1 & 0b11000000 != 0b10000000) return 1; // expected continuation
+ value <<= 6;
+ value |= c1 & 0b00111111;
+ if (length == 2) {
+ if (value < 0x80) return length; // overlong
+ if (value == 0x85) return length; // U+0085 (NEL)
+ self.index += length - 1;
+ return 0;
+ }
+ const c2 = self.buffer[self.index + 2];
+ if (c2 & 0b11000000 != 0b10000000) return 2; // expected continuation
+ value <<= 6;
+ value |= c2 & 0b00111111;
+ if (length == 3) {
+ if (value < 0x800) return length; // overlong
+ if (value == 0x2028) return length; // U+2028 (LS)
+ if (value == 0x2029) return length; // U+2029 (PS)
+ if (0xd800 <= value and value <= 0xdfff) return length; // surrogate halves not allowed in utf8
+ self.index += length - 1;
+ return 0;
+ }
+ const c3 = self.buffer[self.index + 3];
+ if (c3 & 0b11000000 != 0b10000000) return 3; // expected continuation
+ value <<= 6;
+ value |= c3 & 0b00111111;
+ if (length == 4) {
+ if (value < 0x10000) return length; // overlong
+ if (value > 0x10FFFF) return length; // out of bounds
+ self.index += length - 1;
+ return 0;
+ }
+ unreachable;
+ }
+ }
};
+
+test "tokenizer - source must end with eol" {
+ testTokenizeWithEol("", []Token.Id {
+ }, true);
+ testTokenizeWithEol("no newline", []Token.Id {
+ }, false);
+ testTokenizeWithEol("test\n", []Token.Id {
+ Token.Id.Keyword_test,
+ }, true);
+ testTokenizeWithEol("test\nno newline", []Token.Id {
+ Token.Id.Keyword_test,
+ }, false);
+}
+
+test "tokenizer - invalid token characters" {
+ testTokenize("#\n", []Token.Id{Token.Id.Invalid});
+ testTokenize("`\n", []Token.Id{Token.Id.Invalid});
+}
+
+test "tokenizer - invalid literal/comment characters" {
+ testTokenize("\"\x00\"\n", []Token.Id {
+ Token.Id { .StringLiteral = Token.StrLitKind.Normal },
+ Token.Id.Invalid,
+ });
+ testTokenize("//\x00\n", []Token.Id {
+ Token.Id.Invalid,
+ });
+ testTokenize("//\x1f\n", []Token.Id {
+ Token.Id.Invalid,
+ });
+ testTokenize("//\x7f\n", []Token.Id {
+ Token.Id.Invalid,
+ });
+}
+
+test "tokenizer - valid unicode" {
+ testTokenize("//\xc2\x80\n", []Token.Id{});
+ testTokenize("//\xdf\xbf\n", []Token.Id{});
+ testTokenize("//\xe0\xa0\x80\n", []Token.Id{});
+ testTokenize("//\xe1\x80\x80\n", []Token.Id{});
+ testTokenize("//\xef\xbf\xbf\n", []Token.Id{});
+ testTokenize("//\xf0\x90\x80\x80\n", []Token.Id{});
+ testTokenize("//\xf1\x80\x80\x80\n", []Token.Id{});
+ testTokenize("//\xf3\xbf\xbf\xbf\n", []Token.Id{});
+ testTokenize("//\xf4\x8f\xbf\xbf\n", []Token.Id{});
+}
+
+test "tokenizer - invalid unicode continuation bytes" {
+ // unexpected continuation
+ testTokenize("//\x80\n", []Token.Id{Token.Id.Invalid});
+ testTokenize("//\xbf\n", []Token.Id{Token.Id.Invalid});
+ // too many leading 1's
+ testTokenize("//\xf8\n", []Token.Id{Token.Id.Invalid});
+ testTokenize("//\xff\n", []Token.Id{Token.Id.Invalid});
+ // expected continuation for 2 byte sequences
+ testTokenize("//\xc2\x00\n", []Token.Id{Token.Id.Invalid});
+ testTokenize("//\xc2\xc0\n", []Token.Id{Token.Id.Invalid});
+ // expected continuation for 3 byte sequences
+ testTokenize("//\xe0\x00\n", []Token.Id{Token.Id.Invalid});
+ testTokenize("//\xe0\xc0\n", []Token.Id{Token.Id.Invalid});
+ testTokenize("//\xe0\xa0\n", []Token.Id{Token.Id.Invalid});
+ testTokenize("//\xe0\xa0\x00\n", []Token.Id{Token.Id.Invalid});
+ testTokenize("//\xe0\xa0\xc0\n", []Token.Id{Token.Id.Invalid});
+ // expected continuation for 4 byte sequences
+ testTokenize("//\xf0\x00\n", []Token.Id{Token.Id.Invalid});
+ testTokenize("//\xf0\xc0\n", []Token.Id{Token.Id.Invalid});
+ testTokenize("//\xf0\x90\x00\n", []Token.Id{Token.Id.Invalid});
+ testTokenize("//\xf0\x90\xc0\n", []Token.Id{Token.Id.Invalid});
+ testTokenize("//\xf0\x90\x80\x00\n", []Token.Id{Token.Id.Invalid});
+ testTokenize("//\xf0\x90\x80\xc0\n", []Token.Id{Token.Id.Invalid});
+}
+
+test "tokenizer - overlong utf8 codepoint" {
+ testTokenize("//\xc0\x80\n", []Token.Id{Token.Id.Invalid});
+ testTokenize("//\xc1\xbf\n", []Token.Id{Token.Id.Invalid});
+ testTokenize("//\xe0\x80\x80\n", []Token.Id{Token.Id.Invalid});
+ testTokenize("//\xe0\x9f\xbf\n", []Token.Id{Token.Id.Invalid});
+ testTokenize("//\xf0\x80\x80\x80\n", []Token.Id{Token.Id.Invalid});
+ testTokenize("//\xf0\x8f\xbf\xbf\n", []Token.Id{Token.Id.Invalid});
+}
+
+test "tokenizer - misc invalid utf8" {
+ // codepoint out of bounds
+ testTokenize("//\xf4\x90\x80\x80\n", []Token.Id{Token.Id.Invalid});
+ testTokenize("//\xf7\xbf\xbf\xbf\n", []Token.Id{Token.Id.Invalid});
+ // unicode newline characters.U+0085, U+2028, U+2029
+ testTokenize("//\xc2\x84\n", []Token.Id{});
+ testTokenize("//\xc2\x85\n", []Token.Id{Token.Id.Invalid});
+ testTokenize("//\xc2\x86\n", []Token.Id{});
+ testTokenize("//\xe2\x80\xa7\n", []Token.Id{});
+ testTokenize("//\xe2\x80\xa8\n", []Token.Id{Token.Id.Invalid});
+ testTokenize("//\xe2\x80\xa9\n", []Token.Id{Token.Id.Invalid});
+ testTokenize("//\xe2\x80\xaa\n", []Token.Id{});
+ // surrogate halves
+ testTokenize("//\xed\x9f\x80\n", []Token.Id{});
+ testTokenize("//\xed\xa0\x80\n", []Token.Id{Token.Id.Invalid});
+ testTokenize("//\xed\xbf\xbf\n", []Token.Id{Token.Id.Invalid});
+ testTokenize("//\xee\x80\x80\n", []Token.Id{});
+ // surrogate halves are invalid, even in surrogate pairs
+ testTokenize("//\xed\xa0\xad\xed\xb2\xa9\n", []Token.Id{Token.Id.Invalid});
+}
+
+fn testTokenize(source: []const u8, expected_tokens: []const Token.Id) {
+ testTokenizeWithEol(source, expected_tokens, true);
+}
+fn testTokenizeWithEol(source: []const u8, expected_tokens: []const Token.Id, expected_eol_at_eof: bool) {
+ var tokenizer = Tokenizer.init(source);
+ for (expected_tokens) |expected_token_id| {
+ const token = tokenizer.next();
+ std.debug.assert(@TagType(Token.Id)(token.id) == @TagType(Token.Id)(expected_token_id));
+ switch (expected_token_id) {
+ Token.Id.StringLiteral => |expected_kind| {
+ std.debug.assert(expected_kind == switch (token.id) { Token.Id.StringLiteral => |kind| kind, else => unreachable });
+ },
+ else => {},
+ }
+ }
+ std.debug.assert(tokenizer.next().id == if (expected_eol_at_eof) Token.Id.Eof else Token.Id.NoEolAtEof);
+}
diff --git a/src/all_types.hpp b/src/all_types.hpp
index a582f561ccbd6b3b04237b53e9ba80239a287e17..12ecc84a86f3046017a42db261b6f7bd83556098 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -10,7 +10,7 @@
#include "list.hpp"
#include "buffer.hpp"
-#include "zig_llvm.hpp"
+#include "zig_llvm.h"
#include "hash_map.hpp"
#include "errmsg.hpp"
#include "bigint.hpp"
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 9ec4db824cf2a4b91da98a6cb1440c713bdfd3a5..02cdb3485db79c9815ea662199fec2227abe5781 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -14,7 +14,7 @@
#include "os.hpp"
#include "parser.hpp"
#include "softfloat.hpp"
-#include "zig_llvm.hpp"
+#include "zig_llvm.h"
static const size_t default_backward_branch_quota = 1000;
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 339c6434252c6b15a13fa39a31273fb9542f61a1..108b5e0e2ec86d421f46e256ffa99f1a721dcf49 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -17,7 +17,7 @@
#include "os.hpp"
#include "translate_c.hpp"
#include "target.hpp"
-#include "zig_llvm.hpp"
+#include "zig_llvm.h"
#include
#include
@@ -3705,12 +3705,24 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *ar
ConstParent *parent = &array_const_val->data.x_array.s_none.parent;
LLVMValueRef base_ptr = gen_parent_ptr(g, array_const_val, parent);
- TypeTableEntry *usize = g->builtin_types.entry_usize;
- LLVMValueRef indices[] = {
- LLVMConstNull(usize->type_ref),
- LLVMConstInt(usize->type_ref, index, false),
- };
- return LLVMConstInBoundsGEP(base_ptr, indices, 2);
+ LLVMTypeKind el_type = LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(base_ptr)));
+ if (el_type == LLVMArrayTypeKind) {
+ TypeTableEntry *usize = g->builtin_types.entry_usize;
+ LLVMValueRef indices[] = {
+ LLVMConstNull(usize->type_ref),
+ LLVMConstInt(usize->type_ref, index, false),
+ };
+ return LLVMConstInBoundsGEP(base_ptr, indices, 2);
+ } else if (el_type == LLVMStructTypeKind) {
+ TypeTableEntry *u32 = g->builtin_types.entry_u32;
+ LLVMValueRef indices[] = {
+ LLVMConstNull(u32->type_ref),
+ LLVMConstInt(u32->type_ref, index, false),
+ };
+ return LLVMConstInBoundsGEP(base_ptr, indices, 2);
+ } else {
+ zig_unreachable();
+ }
}
static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index) {
@@ -3732,7 +3744,7 @@ static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *un
TypeTableEntry *u32 = g->builtin_types.entry_u32;
LLVMValueRef indices[] = {
LLVMConstNull(u32->type_ref),
- LLVMConstInt(u32->type_ref, 0, false),
+ LLVMConstInt(u32->type_ref, 0, false), // TODO test const union with more aligned tag type than payload
};
return LLVMConstInBoundsGEP(base_ptr, indices, 2);
}
diff --git a/src/config.h.in b/src/config.h.in
index a596213a3d82e861c195790a48d4a812cf7edf2f..73e1de27c192b770d8ccadd22a276b03bd629cc6 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -24,4 +24,8 @@
// Only used for running tests before installing.
#define ZIG_TEST_DIR "@CMAKE_SOURCE_DIR@/test"
+// Used for communicating build information to self hosted build.
+#define ZIG_CMAKE_BINARY_DIR "@CMAKE_BINARY_DIR@"
+#define ZIG_CXX_COMPILER "@CMAKE_CXX_COMPILER@"
+
#endif
diff --git a/src/link.cpp b/src/link.cpp
index bc84b27b89ef7db921aee9ff999fe4c46a734733..f07364e5bc67fb0f5da0ab9ed4799b78f8d0ca16 100644
--- a/src/link.cpp
+++ b/src/link.cpp
@@ -351,6 +351,16 @@ static void coff_append_machine_arg(CodeGen *g, ZigList *list) {
}
}
+static void link_diag_callback(void *context, const char *ptr, size_t len) {
+ Buf *diag = reinterpret_cast(context);
+ buf_append_mem(diag, ptr, len);
+}
+
+static bool zig_lld_link(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_count, Buf *diag) {
+ buf_resize(diag, 0);
+ return ZigLLDLink(oformat, args, arg_count, link_diag_callback, diag);
+}
+
static void construct_linker_job_coff(LinkJob *lj) {
CodeGen *g = lj->codegen;
@@ -515,7 +525,7 @@ 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 (!ZigLLDLink(g->zig_target.oformat, gen_lib_args.items, gen_lib_args.length, &diag)) {
+ if (!zig_lld_link(g->zig_target.oformat, gen_lib_args.items, gen_lib_args.length, &diag)) {
fprintf(stderr, "%s\n", buf_ptr(&diag));
exit(1);
}
@@ -930,7 +940,7 @@ void codegen_link(CodeGen *g, const char *out_file) {
Buf diag = BUF_INIT;
codegen_add_time_event(g, "LLVM Link");
- if (!ZigLLDLink(g->zig_target.oformat, lj.args.items, lj.args.length, &diag)) {
+ if (!zig_lld_link(g->zig_target.oformat, 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
index 60d2750bdefcbfb95fb64e49b548a361dfbf4b3d..66ffbbde82af617e3c5bb0f1f3cd1fbd6670708c 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -266,6 +266,11 @@ static void add_package(CodeGen *g, CliPkg *cli_pkg, PackageTableEntry *pkg) {
}
int main(int argc, char **argv) {
+ if (argc == 2 && strcmp(argv[1], "BUILD_INFO") == 0) {
+ printf("%s\n%s\n", ZIG_CMAKE_BINARY_DIR, ZIG_CXX_COMPILER);
+ return 0;
+ }
+
os_init();
char *arg0 = argv[0];
diff --git a/src/os.hpp b/src/os.hpp
index d4d1676df6f60a90a0e5f4e1d3226e02f4e740d7..5d29db0d078eef5715b428f6f1ef8956835d315c 100644
--- a/src/os.hpp
+++ b/src/os.hpp
@@ -11,7 +11,7 @@
#include "list.hpp"
#include "buffer.hpp"
#include "error.hpp"
-#include "zig_llvm.hpp"
+#include "zig_llvm.h"
#include
#include
diff --git a/src/target.hpp b/src/target.hpp
index 2b678b313dd69be1af1b582a2f4c23393a6af104..9bcca776f434139548f2e5b604d5a4cdf6a9e901 100644
--- a/src/target.hpp
+++ b/src/target.hpp
@@ -8,7 +8,7 @@
#ifndef ZIG_TARGET_HPP
#define ZIG_TARGET_HPP
-#include
+#include
struct Buf;
diff --git a/src/util.hpp b/src/util.hpp
index 73608b3b0892bea65182491a6502635d8cb2281d..ce6cc09a593e8382b9fbed6fd5dd26d48d08f92d 100644
--- a/src/util.hpp
+++ b/src/util.hpp
@@ -13,8 +13,6 @@
#include
#include
-#include
-
#if defined(_MSC_VER)
#include
diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp
index bd3eadbee9eba6cd3bc25f9984515feb12059717..2a455c79d4cd69b866b9210abc27097bd1a9c15a 100644
--- a/src/zig_llvm.cpp
+++ b/src/zig_llvm.cpp
@@ -13,7 +13,7 @@
* 3. Prevent C++ from infecting the rest of the project.
*/
-#include "zig_llvm.hpp"
+#include "zig_llvm.h"
#include
#include
@@ -39,8 +39,35 @@
#include
+#include
+
+#include
+
+#if defined(_MSC_VER)
+#define ATTRIBUTE_RETURNS_NOALIAS __declspec(restrict)
+#else
+#define ATTRIBUTE_RETURNS_NOALIAS __attribute__((__malloc__))
+#endif
+
using namespace llvm;
+template
+ATTRIBUTE_RETURNS_NOALIAS static inline T * create(Args... args) {
+ T * ptr = reinterpret_cast(malloc(sizeof(T)));
+ if (ptr == nullptr)
+ return nullptr;
+ new (ptr) T(args...);
+ return ptr;
+}
+
+template
+static inline void destroy(T * ptr) {
+ if (ptr != nullptr) {
+ ptr[0].~T();
+ }
+ free(ptr);
+}
+
void ZigLLVMInitializeLoopStrengthReducePass(LLVMPassRegistryRef R) {
initializeLoopStrengthReducePass(*unwrap(R));
}
@@ -50,8 +77,7 @@ void ZigLLVMInitializeLowerIntrinsicsPass(LLVMPassRegistryRef R) {
}
char *ZigLLVMGetHostCPUName(void) {
- std::string str = sys::getHostCPUName();
- return strdup(str.c_str());
+ return strdup((const char *)sys::getHostCPUName().bytes_begin());
}
char *ZigLLVMGetNativeFeatures(void) {
@@ -63,11 +89,11 @@ char *ZigLLVMGetNativeFeatures(void) {
features.AddFeature(F.first(), F.second);
}
- return strdup(features.getString().c_str());
+ return strdup((const char *)StringRef(features.getString()).bytes_begin());
}
static void addDiscriminatorsPass(const PassManagerBuilder &Builder, legacy::PassManagerBase &PM) {
- PM.add(createAddDiscriminatorsPass());
+ PM.add(createAddDiscriminatorsPass());
}
#ifndef NDEBUG
@@ -82,7 +108,7 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
std::error_code EC;
raw_fd_ostream dest(filename, EC, sys::fs::F_None);
if (EC) {
- *error_message = strdup(EC.message().c_str());
+ *error_message = strdup((const char *)StringRef(EC.message()).bytes_begin());
return true;
}
TargetMachine* target_machine = reinterpret_cast(targ_machine_ref);
@@ -90,7 +116,7 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
Module* module = unwrap(module_ref);
- PassManagerBuilder *PMBuilder = new PassManagerBuilder();
+ PassManagerBuilder *PMBuilder = create();
PMBuilder->OptLevel = target_machine->getOptLevel();
PMBuilder->SizeLevel = 0;
@@ -123,7 +149,7 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
// Set up the per-function pass manager.
legacy::FunctionPassManager FPM = legacy::FunctionPassManager(module);
- FPM.add(new TargetLibraryInfoWrapperPass(tlii));
+ FPM.add(create(tlii));
FPM.add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis()));
if (assertions_on) {
FPM.add(createVerifierPass());
@@ -415,7 +441,10 @@ unsigned ZigLLVMTag_DW_union_type(void) {
}
ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved) {
- DIBuilder *di_builder = new DIBuilder(*unwrap(module), allow_unresolved);
+ DIBuilder *di_builder = reinterpret_cast(malloc(sizeof(DIBuilder)));
+ if (di_builder == nullptr)
+ return nullptr;
+ new (di_builder) DIBuilder(*unwrap(module), allow_unresolved);
return reinterpret_cast(di_builder);
}
@@ -617,7 +646,7 @@ void ZigLLVMAddFunctionAttrCold(LLVMValueRef fn_ref) {
func->setAttributes(new_attr_set);
}
-void ZigLLVMParseCommandLineOptions(int argc, const char *const *argv) {
+void ZigLLVMParseCommandLineOptions(size_t argc, const char *const *argv) {
llvm::cl::ParseCommandLineOptions(argc, argv);
}
@@ -775,29 +804,35 @@ LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLV
}
-#include "buffer.hpp"
+class MyOStream: public raw_ostream {
+ public:
+ MyOStream(void (*_append_diagnostic)(void *, const char *, size_t), void *_context) :
+ raw_ostream(true), append_diagnostic(_append_diagnostic), context(_context), pos(0) {
-bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_count, Buf *diag_buf) {
+ }
+ void write_impl(const char *ptr, size_t len) override {
+ append_diagnostic(context, ptr, len);
+ pos += len;
+ }
+ uint64_t current_pos() const override {
+ return pos;
+ }
+ void (*append_diagnostic)(void *, const char *, size_t);
+ void *context;
+ size_t pos;
+};
+
+
+bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_count,
+ void (*append_diagnostic)(void *, const char *, size_t), void *context)
+{
ArrayRef array_ref_args(args, arg_count);
- buf_resize(diag_buf, 0);
- class MyOStream: public raw_ostream {
- public:
- MyOStream(Buf *_diag_buf) : raw_ostream(true), diag_buf(_diag_buf) {
-
- }
- void write_impl(const char *ptr, size_t len) override {
- buf_append_mem(diag_buf, ptr, len);
- }
- uint64_t current_pos() const override {
- return buf_len(diag_buf);
- }
- Buf *diag_buf;
- } diag(diag_buf);
+ MyOStream diag(append_diagnostic, context);
switch (oformat) {
case ZigLLVM_UnknownObjectFormat:
- zig_unreachable();
+ assert(false); // unreachable
case ZigLLVM_COFF:
return lld::coff::link(array_ref_args, false, diag);
@@ -809,7 +844,8 @@ bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_
return lld::mach_o::link(array_ref_args, diag);
case ZigLLVM_Wasm:
- zig_panic("ZigLLDLink for Wasm");
+ assert(false); // TODO ZigLLDLink for Wasm
}
- zig_unreachable();
+ assert(false); // unreachable
+ abort();
}
diff --git a/src/zig_llvm.h b/src/zig_llvm.h
new file mode 100644
index 0000000000000000000000000000000000000000..9cdb28dc5884cad412c15740a373775f76a66741
--- /dev/null
+++ b/src/zig_llvm.h
@@ -0,0 +1,398 @@
+/*
+ * Copyright (c) 2015 Andrew Kelley
+ *
+ * This file is part of zig, which is MIT licensed.
+ * See http://opensource.org/licenses/MIT
+ */
+
+#ifndef ZIG_ZIG_LLVM_HPP
+#define ZIG_ZIG_LLVM_HPP
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef __cplusplus
+#define ZIG_EXTERN_C extern "C"
+#else
+#define ZIG_EXTERN_C
+#endif
+
+struct ZigLLVMDIType;
+struct ZigLLVMDIBuilder;
+struct ZigLLVMDICompileUnit;
+struct ZigLLVMDIScope;
+struct ZigLLVMDIFile;
+struct ZigLLVMDILexicalBlock;
+struct ZigLLVMDISubprogram;
+struct ZigLLVMDISubroutineType;
+struct ZigLLVMDILocalVariable;
+struct ZigLLVMDIGlobalVariable;
+struct ZigLLVMDILocation;
+struct ZigLLVMDIEnumerator;
+struct ZigLLVMInsertionPoint;
+
+ZIG_EXTERN_C void ZigLLVMInitializeLoopStrengthReducePass(LLVMPassRegistryRef R);
+ZIG_EXTERN_C void ZigLLVMInitializeLowerIntrinsicsPass(LLVMPassRegistryRef R);
+
+/// Caller must free memory.
+ZIG_EXTERN_C char *ZigLLVMGetHostCPUName(void);
+ZIG_EXTERN_C char *ZigLLVMGetNativeFeatures(void);
+
+// We use a custom enum here since LLVM does not expose LLVMIr as an emit
+// output through the same mechanism as assembly/binary.
+enum ZigLLVM_EmitOutputType {
+ ZigLLVM_EmitAssembly,
+ ZigLLVM_EmitBinary,
+ ZigLLVM_EmitLLVMIr,
+};
+
+ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
+ const char *filename, enum ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug);
+
+enum ZigLLVM_FnInline {
+ ZigLLVM_FnInlineAuto,
+ ZigLLVM_FnInlineAlways,
+ ZigLLVM_FnInlineNever,
+};
+ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,
+ unsigned NumArgs, unsigned CC, enum ZigLLVM_FnInline fn_inline, const char *Name);
+
+ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp,
+ LLVMValueRef new_val, LLVMAtomicOrdering success_ordering,
+ LLVMAtomicOrdering failure_ordering);
+
+ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildNSWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
+ const char *name);
+ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildNUWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
+ const char *name);
+ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildLShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
+ const char *name);
+ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
+ const char *name);
+
+ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateDebugPointerType(struct ZigLLVMDIBuilder *dibuilder,
+ struct ZigLLVMDIType *pointee_type, uint64_t size_in_bits, uint64_t align_in_bits, const char *name);
+
+ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateDebugBasicType(struct ZigLLVMDIBuilder *dibuilder, const char *name,
+ uint64_t size_in_bits, unsigned encoding);
+
+ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateDebugArrayType(struct ZigLLVMDIBuilder *dibuilder,
+ uint64_t size_in_bits, uint64_t align_in_bits, struct ZigLLVMDIType *elem_type,
+ int elem_count);
+
+ZIG_EXTERN_C struct ZigLLVMDIEnumerator *ZigLLVMCreateDebugEnumerator(struct ZigLLVMDIBuilder *dibuilder,
+ const char *name, int64_t val);
+
+ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateDebugEnumerationType(struct ZigLLVMDIBuilder *dibuilder,
+ struct ZigLLVMDIScope *scope, const char *name, struct ZigLLVMDIFile *file, unsigned line_number,
+ uint64_t size_in_bits, uint64_t align_in_bits, struct ZigLLVMDIEnumerator **enumerator_array,
+ int enumerator_array_len, struct ZigLLVMDIType *underlying_type, const char *unique_id);
+
+ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateDebugStructType(struct ZigLLVMDIBuilder *dibuilder,
+ struct ZigLLVMDIScope *scope, const char *name, struct ZigLLVMDIFile *file, unsigned line_number,
+ uint64_t size_in_bits, uint64_t align_in_bits, unsigned flags, struct ZigLLVMDIType *derived_from,
+ struct ZigLLVMDIType **types_array, int types_array_len, unsigned run_time_lang,
+ struct ZigLLVMDIType *vtable_holder, const char *unique_id);
+
+ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateDebugUnionType(struct ZigLLVMDIBuilder *dibuilder,
+ struct ZigLLVMDIScope *scope, const char *name, struct ZigLLVMDIFile *file, unsigned line_number,
+ uint64_t size_in_bits, uint64_t align_in_bits, unsigned flags, struct ZigLLVMDIType **types_array,
+ int types_array_len, unsigned run_time_lang, const char *unique_id);
+
+ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateDebugMemberType(struct ZigLLVMDIBuilder *dibuilder,
+ struct ZigLLVMDIScope *scope, const char *name, struct ZigLLVMDIFile *file, unsigned line,
+ uint64_t size_in_bits, uint64_t align_in_bits, uint64_t offset_in_bits, unsigned flags,
+ struct ZigLLVMDIType *type);
+
+ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateReplaceableCompositeType(struct ZigLLVMDIBuilder *dibuilder,
+ unsigned tag, const char *name, struct ZigLLVMDIScope *scope, struct ZigLLVMDIFile *file, unsigned line);
+
+ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateDebugForwardDeclType(struct ZigLLVMDIBuilder *dibuilder, unsigned tag,
+ const char *name, struct ZigLLVMDIScope *scope, struct ZigLLVMDIFile *file, unsigned line);
+
+ZIG_EXTERN_C void ZigLLVMReplaceTemporary(struct ZigLLVMDIBuilder *dibuilder, struct ZigLLVMDIType *type,
+ struct ZigLLVMDIType *replacement);
+
+ZIG_EXTERN_C void ZigLLVMReplaceDebugArrays(struct ZigLLVMDIBuilder *dibuilder, struct ZigLLVMDIType *type,
+ struct ZigLLVMDIType **types_array, int types_array_len);
+
+ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateSubroutineType(struct ZigLLVMDIBuilder *dibuilder_wrapped,
+ struct ZigLLVMDIType **types_array, int types_array_len, unsigned flags);
+
+ZIG_EXTERN_C unsigned ZigLLVMEncoding_DW_ATE_unsigned(void);
+ZIG_EXTERN_C unsigned ZigLLVMEncoding_DW_ATE_signed(void);
+ZIG_EXTERN_C unsigned ZigLLVMEncoding_DW_ATE_float(void);
+ZIG_EXTERN_C unsigned ZigLLVMEncoding_DW_ATE_boolean(void);
+ZIG_EXTERN_C unsigned ZigLLVMEncoding_DW_ATE_unsigned_char(void);
+ZIG_EXTERN_C unsigned ZigLLVMEncoding_DW_ATE_signed_char(void);
+ZIG_EXTERN_C unsigned ZigLLVMLang_DW_LANG_C99(void);
+ZIG_EXTERN_C unsigned ZigLLVMTag_DW_variable(void);
+ZIG_EXTERN_C unsigned ZigLLVMTag_DW_structure_type(void);
+ZIG_EXTERN_C unsigned ZigLLVMTag_DW_union_type(void);
+
+ZIG_EXTERN_C struct ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved);
+ZIG_EXTERN_C void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module);
+ZIG_EXTERN_C void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module);
+
+ZIG_EXTERN_C void ZigLLVMSetCurrentDebugLocation(LLVMBuilderRef builder, int line, int column,
+ struct ZigLLVMDIScope *scope);
+ZIG_EXTERN_C void ZigLLVMClearCurrentDebugLocation(LLVMBuilderRef builder);
+
+ZIG_EXTERN_C struct ZigLLVMDIScope *ZigLLVMLexicalBlockToScope(struct ZigLLVMDILexicalBlock *lexical_block);
+ZIG_EXTERN_C struct ZigLLVMDIScope *ZigLLVMCompileUnitToScope(struct ZigLLVMDICompileUnit *compile_unit);
+ZIG_EXTERN_C struct ZigLLVMDIScope *ZigLLVMFileToScope(struct ZigLLVMDIFile *difile);
+ZIG_EXTERN_C struct ZigLLVMDIScope *ZigLLVMSubprogramToScope(struct ZigLLVMDISubprogram *subprogram);
+ZIG_EXTERN_C struct ZigLLVMDIScope *ZigLLVMTypeToScope(struct ZigLLVMDIType *type);
+
+ZIG_EXTERN_C struct ZigLLVMDILocalVariable *ZigLLVMCreateAutoVariable(struct ZigLLVMDIBuilder *dbuilder,
+ struct ZigLLVMDIScope *scope, const char *name, struct ZigLLVMDIFile *file, unsigned line_no,
+ struct ZigLLVMDIType *type, bool always_preserve, unsigned flags);
+
+ZIG_EXTERN_C struct ZigLLVMDIGlobalVariable *ZigLLVMCreateGlobalVariable(struct ZigLLVMDIBuilder *dbuilder,
+ struct ZigLLVMDIScope *scope, const char *name, const char *linkage_name, struct ZigLLVMDIFile *file,
+ unsigned line_no, struct ZigLLVMDIType *di_type, bool is_local_to_unit);
+
+ZIG_EXTERN_C struct ZigLLVMDILocalVariable *ZigLLVMCreateParameterVariable(struct ZigLLVMDIBuilder *dbuilder,
+ struct ZigLLVMDIScope *scope, const char *name, struct ZigLLVMDIFile *file, unsigned line_no,
+ struct ZigLLVMDIType *type, bool always_preserve, unsigned flags, unsigned arg_no);
+
+ZIG_EXTERN_C struct ZigLLVMDILexicalBlock *ZigLLVMCreateLexicalBlock(struct ZigLLVMDIBuilder *dbuilder,
+ struct ZigLLVMDIScope *scope, struct ZigLLVMDIFile *file, unsigned line, unsigned col);
+
+ZIG_EXTERN_C struct ZigLLVMDICompileUnit *ZigLLVMCreateCompileUnit(struct ZigLLVMDIBuilder *dibuilder,
+ unsigned lang, struct ZigLLVMDIFile *difile, const char *producer,
+ bool is_optimized, const char *flags, unsigned runtime_version, const char *split_name,
+ uint64_t dwo_id, bool emit_debug_info);
+
+ZIG_EXTERN_C struct ZigLLVMDIFile *ZigLLVMCreateFile(struct ZigLLVMDIBuilder *dibuilder, const char *filename,
+ const char *directory);
+
+ZIG_EXTERN_C struct ZigLLVMDISubprogram *ZigLLVMCreateFunction(struct ZigLLVMDIBuilder *dibuilder,
+ struct ZigLLVMDIScope *scope, const char *name, const char *linkage_name, struct ZigLLVMDIFile *file,
+ unsigned lineno, struct ZigLLVMDIType *fn_di_type, bool is_local_to_unit, bool is_definition,
+ unsigned scope_line, unsigned flags, bool is_optimized, struct ZigLLVMDISubprogram *decl_subprogram);
+
+ZIG_EXTERN_C void ZigLLVMFnSetSubprogram(LLVMValueRef fn, struct ZigLLVMDISubprogram *subprogram);
+
+ZIG_EXTERN_C void ZigLLVMDIBuilderFinalize(struct ZigLLVMDIBuilder *dibuilder);
+
+ZIG_EXTERN_C LLVMValueRef ZigLLVMInsertDeclareAtEnd(struct ZigLLVMDIBuilder *dibuilder, LLVMValueRef storage,
+ struct ZigLLVMDILocalVariable *var_info, struct ZigLLVMDILocation *debug_loc,
+ LLVMBasicBlockRef basic_block_ref);
+
+ZIG_EXTERN_C LLVMValueRef ZigLLVMInsertDeclare(struct ZigLLVMDIBuilder *dibuilder, LLVMValueRef storage,
+ struct ZigLLVMDILocalVariable *var_info, struct ZigLLVMDILocation *debug_loc, LLVMValueRef insert_before_instr);
+ZIG_EXTERN_C struct ZigLLVMDILocation *ZigLLVMGetDebugLoc(unsigned line, unsigned col, struct ZigLLVMDIScope *scope);
+
+ZIG_EXTERN_C void ZigLLVMSetFastMath(LLVMBuilderRef builder_wrapped, bool on_state);
+
+ZIG_EXTERN_C void ZigLLVMAddFunctionAttr(LLVMValueRef fn, const char *attr_name, const char *attr_value);
+ZIG_EXTERN_C void ZigLLVMAddFunctionAttrCold(LLVMValueRef fn);
+
+ZIG_EXTERN_C void ZigLLVMParseCommandLineOptions(size_t argc, const char *const *argv);
+
+
+// copied from include/llvm/ADT/Triple.h
+
+enum ZigLLVM_ArchType {
+ ZigLLVM_UnknownArch,
+
+ 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
+ ZigLLVM_mipsel, // MIPSEL: mipsel, mipsallegrexel
+ ZigLLVM_mips64, // MIPS64: mips64
+ ZigLLVM_mips64el, // MIPS64EL: mips64el
+ ZigLLVM_msp430, // MSP430: msp430
+ ZigLLVM_nios2, // NIOSII: nios2
+ 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
+
+ ZigLLVM_LastArchType = ZigLLVM_renderscript64
+};
+
+enum ZigLLVM_SubArchType {
+ ZigLLVM_NoSubArch,
+
+ 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,
+
+ ZigLLVM_KalimbaSubArch_v3,
+ ZigLLVM_KalimbaSubArch_v4,
+ ZigLLVM_KalimbaSubArch_v5,
+};
+
+enum ZigLLVM_VendorType {
+ ZigLLVM_UnknownVendor,
+
+ ZigLLVM_Apple,
+ ZigLLVM_PC,
+ ZigLLVM_SCEI,
+ ZigLLVM_BGP,
+ ZigLLVM_BGQ,
+ ZigLLVM_Freescale,
+ ZigLLVM_IBM,
+ ZigLLVM_ImaginationTechnologies,
+ ZigLLVM_MipsTechnologies,
+ ZigLLVM_NVIDIA,
+ ZigLLVM_CSR,
+ ZigLLVM_Myriad,
+ ZigLLVM_AMD,
+ ZigLLVM_Mesa,
+ ZigLLVM_SUSE,
+
+ ZigLLVM_LastVendorType = ZigLLVM_SUSE
+};
+
+enum ZigLLVM_OSType {
+ ZigLLVM_UnknownOS,
+
+ ZigLLVM_Ananas,
+ ZigLLVM_CloudABI,
+ ZigLLVM_Darwin,
+ ZigLLVM_DragonFly,
+ ZigLLVM_FreeBSD,
+ ZigLLVM_Fuchsia,
+ ZigLLVM_IOS,
+ ZigLLVM_KFreeBSD,
+ ZigLLVM_Linux,
+ ZigLLVM_Lv2, // PS3
+ ZigLLVM_MacOSX,
+ ZigLLVM_NetBSD,
+ ZigLLVM_OpenBSD,
+ ZigLLVM_Solaris,
+ ZigLLVM_Win32,
+ ZigLLVM_Haiku,
+ ZigLLVM_Minix,
+ ZigLLVM_RTEMS,
+ ZigLLVM_NaCl, // Native Client
+ ZigLLVM_CNK, // BG/P Compute-Node Kernel
+ ZigLLVM_Bitrig,
+ ZigLLVM_AIX,
+ ZigLLVM_CUDA, // NVIDIA CUDA
+ ZigLLVM_NVCL, // NVIDIA OpenCL
+ ZigLLVM_AMDHSA, // AMD HSA Runtime
+ ZigLLVM_PS4,
+ ZigLLVM_ELFIAMCU,
+ ZigLLVM_TvOS, // Apple tvOS
+ ZigLLVM_WatchOS, // Apple watchOS
+ ZigLLVM_Mesa3D,
+ ZigLLVM_Contiki,
+
+ ZigLLVM_LastOSType = ZigLLVM_Contiki
+};
+
+enum ZigLLVM_EnvironmentType {
+ ZigLLVM_UnknownEnvironment,
+
+ ZigLLVM_GNU,
+ ZigLLVM_GNUABIN32,
+ ZigLLVM_GNUABI64,
+ ZigLLVM_GNUEABI,
+ ZigLLVM_GNUEABIHF,
+ ZigLLVM_GNUX32,
+ ZigLLVM_CODE16,
+ ZigLLVM_EABI,
+ ZigLLVM_EABIHF,
+ ZigLLVM_Android,
+ ZigLLVM_Musl,
+ ZigLLVM_MuslEABI,
+ ZigLLVM_MuslEABIHF,
+
+ ZigLLVM_MSVC,
+ ZigLLVM_Itanium,
+ ZigLLVM_Cygnus,
+ ZigLLVM_AMDOpenCL,
+ ZigLLVM_CoreCLR,
+ ZigLLVM_OpenCL,
+ ZigLLVM_Simulator,
+
+ ZigLLVM_LastEnvironmentType = ZigLLVM_Simulator
+};
+
+enum ZigLLVM_ObjectFormatType {
+ ZigLLVM_UnknownObjectFormat,
+
+ ZigLLVM_COFF,
+ ZigLLVM_ELF,
+ ZigLLVM_MachO,
+ ZigLLVM_Wasm,
+};
+
+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 bool ZigLLDLink(enum ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_count,
+ void (*append_diagnostic)(void *, const char *, size_t), void *context);
+
+ZIG_EXTERN_C void ZigLLVMGetNativeTarget(enum ZigLLVM_ArchType *arch_type, enum ZigLLVM_SubArchType *sub_arch_type,
+ enum ZigLLVM_VendorType *vendor_type, enum ZigLLVM_OSType *os_type, enum ZigLLVM_EnvironmentType *environ_type,
+ enum ZigLLVM_ObjectFormatType *oformat);
+
+#endif
diff --git a/src/zig_llvm.hpp b/src/zig_llvm.hpp
deleted file mode 100644
index f335a8955a0f46df8a031be5395672feab6af6c8..0000000000000000000000000000000000000000
--- a/src/zig_llvm.hpp
+++ /dev/null
@@ -1,387 +0,0 @@
-/*
- * Copyright (c) 2015 Andrew Kelley
- *
- * This file is part of zig, which is MIT licensed.
- * See http://opensource.org/licenses/MIT
- */
-
-#ifndef ZIG_ZIG_LLVM_HPP
-#define ZIG_ZIG_LLVM_HPP
-
-#include
-#include
-#include
-#include
-#include
-
-struct ZigLLVMDIType;
-struct ZigLLVMDIBuilder;
-struct ZigLLVMDICompileUnit;
-struct ZigLLVMDIScope;
-struct ZigLLVMDIFile;
-struct ZigLLVMDILexicalBlock;
-struct ZigLLVMDISubprogram;
-struct ZigLLVMDISubroutineType;
-struct ZigLLVMDILocalVariable;
-struct ZigLLVMDIGlobalVariable;
-struct ZigLLVMDILocation;
-struct ZigLLVMDIEnumerator;
-struct ZigLLVMInsertionPoint;
-
-void ZigLLVMInitializeLoopStrengthReducePass(LLVMPassRegistryRef R);
-void ZigLLVMInitializeLowerIntrinsicsPass(LLVMPassRegistryRef R);
-
-char *ZigLLVMGetHostCPUName(void);
-char *ZigLLVMGetNativeFeatures(void);
-
-// We use a custom enum here since LLVM does not expose LLVMIr as an emit
-// output through the same mechanism as assembly/binary.
-enum ZigLLVM_EmitOutputType {
- ZigLLVM_EmitAssembly,
- ZigLLVM_EmitBinary,
- ZigLLVM_EmitLLVMIr,
-};
-
-bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
- const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug);
-
-enum ZigLLVM_FnInline {
- ZigLLVM_FnInlineAuto,
- ZigLLVM_FnInlineAlways,
- ZigLLVM_FnInlineNever,
-};
-LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,
- unsigned NumArgs, unsigned CC, ZigLLVM_FnInline fn_inline, const char *Name);
-
-LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp,
- LLVMValueRef new_val, LLVMAtomicOrdering success_ordering,
- LLVMAtomicOrdering failure_ordering);
-
-LLVMValueRef ZigLLVMBuildNSWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
- const char *name);
-LLVMValueRef ZigLLVMBuildNUWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
- const char *name);
-LLVMValueRef ZigLLVMBuildLShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
- const char *name);
-LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
- const char *name);
-
-ZigLLVMDIType *ZigLLVMCreateDebugPointerType(ZigLLVMDIBuilder *dibuilder, ZigLLVMDIType *pointee_type,
- uint64_t size_in_bits, uint64_t align_in_bits, const char *name);
-
-ZigLLVMDIType *ZigLLVMCreateDebugBasicType(ZigLLVMDIBuilder *dibuilder, const char *name,
- uint64_t size_in_bits, unsigned encoding);
-
-ZigLLVMDIType *ZigLLVMCreateDebugArrayType(ZigLLVMDIBuilder *dibuilder,
- uint64_t size_in_bits, uint64_t align_in_bits, ZigLLVMDIType *elem_type,
- int elem_count);
-
-ZigLLVMDIEnumerator *ZigLLVMCreateDebugEnumerator(ZigLLVMDIBuilder *dibuilder, const char *name, int64_t val);
-
-ZigLLVMDIType *ZigLLVMCreateDebugEnumerationType(ZigLLVMDIBuilder *dibuilder, ZigLLVMDIScope *scope,
- const char *name, ZigLLVMDIFile *file, unsigned line_number, uint64_t size_in_bits,
- uint64_t align_in_bits, ZigLLVMDIEnumerator **enumerator_array, int enumerator_array_len,
- ZigLLVMDIType *underlying_type, const char *unique_id);
-
-ZigLLVMDIType *ZigLLVMCreateDebugStructType(ZigLLVMDIBuilder *dibuilder, ZigLLVMDIScope *scope,
- const char *name, ZigLLVMDIFile *file, unsigned line_number, uint64_t size_in_bits,
- uint64_t align_in_bits, unsigned flags, ZigLLVMDIType *derived_from,
- ZigLLVMDIType **types_array, int types_array_len, unsigned run_time_lang, ZigLLVMDIType *vtable_holder,
- const char *unique_id);
-
-ZigLLVMDIType *ZigLLVMCreateDebugUnionType(ZigLLVMDIBuilder *dibuilder, ZigLLVMDIScope *scope,
- const char *name, ZigLLVMDIFile *file, unsigned line_number, uint64_t size_in_bits,
- uint64_t align_in_bits, unsigned flags, ZigLLVMDIType **types_array, int types_array_len,
- unsigned run_time_lang, const char *unique_id);
-
-ZigLLVMDIType *ZigLLVMCreateDebugMemberType(ZigLLVMDIBuilder *dibuilder, ZigLLVMDIScope *scope,
- const char *name, ZigLLVMDIFile *file, unsigned line, uint64_t size_in_bits,
- uint64_t align_in_bits, uint64_t offset_in_bits, unsigned flags, ZigLLVMDIType *type);
-
-ZigLLVMDIType *ZigLLVMCreateReplaceableCompositeType(ZigLLVMDIBuilder *dibuilder, unsigned tag,
- const char *name, ZigLLVMDIScope *scope, ZigLLVMDIFile *file, unsigned line);
-
-ZigLLVMDIType *ZigLLVMCreateDebugForwardDeclType(ZigLLVMDIBuilder *dibuilder, unsigned tag,
- const char *name, ZigLLVMDIScope *scope, ZigLLVMDIFile *file, unsigned line);
-
-void ZigLLVMReplaceTemporary(ZigLLVMDIBuilder *dibuilder, ZigLLVMDIType *type,
- ZigLLVMDIType *replacement);
-
-void ZigLLVMReplaceDebugArrays(ZigLLVMDIBuilder *dibuilder, ZigLLVMDIType *type,
- ZigLLVMDIType **types_array, int types_array_len);
-
-ZigLLVMDIType *ZigLLVMCreateSubroutineType(ZigLLVMDIBuilder *dibuilder_wrapped,
- ZigLLVMDIType **types_array, int types_array_len, unsigned flags);
-
-unsigned ZigLLVMEncoding_DW_ATE_unsigned(void);
-unsigned ZigLLVMEncoding_DW_ATE_signed(void);
-unsigned ZigLLVMEncoding_DW_ATE_float(void);
-unsigned ZigLLVMEncoding_DW_ATE_boolean(void);
-unsigned ZigLLVMEncoding_DW_ATE_unsigned_char(void);
-unsigned ZigLLVMEncoding_DW_ATE_signed_char(void);
-unsigned ZigLLVMLang_DW_LANG_C99(void);
-unsigned ZigLLVMTag_DW_variable(void);
-unsigned ZigLLVMTag_DW_structure_type(void);
-unsigned ZigLLVMTag_DW_union_type(void);
-
-ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved);
-void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module);
-void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module);
-
-void ZigLLVMSetCurrentDebugLocation(LLVMBuilderRef builder, int line, int column, ZigLLVMDIScope *scope);
-void ZigLLVMClearCurrentDebugLocation(LLVMBuilderRef builder);
-
-ZigLLVMDIScope *ZigLLVMLexicalBlockToScope(ZigLLVMDILexicalBlock *lexical_block);
-ZigLLVMDIScope *ZigLLVMCompileUnitToScope(ZigLLVMDICompileUnit *compile_unit);
-ZigLLVMDIScope *ZigLLVMFileToScope(ZigLLVMDIFile *difile);
-ZigLLVMDIScope *ZigLLVMSubprogramToScope(ZigLLVMDISubprogram *subprogram);
-ZigLLVMDIScope *ZigLLVMTypeToScope(ZigLLVMDIType *type);
-
-ZigLLVMDILocalVariable *ZigLLVMCreateAutoVariable(ZigLLVMDIBuilder *dbuilder,
- ZigLLVMDIScope *scope, const char *name, ZigLLVMDIFile *file, unsigned line_no,
- ZigLLVMDIType *type, bool always_preserve, unsigned flags);
-
-ZigLLVMDIGlobalVariable *ZigLLVMCreateGlobalVariable(ZigLLVMDIBuilder *dbuilder,
- ZigLLVMDIScope *scope, const char *name, const char *linkage_name, ZigLLVMDIFile *file,
- unsigned line_no, ZigLLVMDIType *di_type, bool is_local_to_unit);
-
-ZigLLVMDILocalVariable *ZigLLVMCreateParameterVariable(ZigLLVMDIBuilder *dbuilder,
- ZigLLVMDIScope *scope, const char *name, ZigLLVMDIFile *file, unsigned line_no,
- ZigLLVMDIType *type, bool always_preserve, unsigned flags, unsigned arg_no);
-
-ZigLLVMDILexicalBlock *ZigLLVMCreateLexicalBlock(ZigLLVMDIBuilder *dbuilder, ZigLLVMDIScope *scope,
- ZigLLVMDIFile *file, unsigned line, unsigned col);
-
-ZigLLVMDICompileUnit *ZigLLVMCreateCompileUnit(ZigLLVMDIBuilder *dibuilder,
- unsigned lang, ZigLLVMDIFile *difile, const char *producer,
- bool is_optimized, const char *flags, unsigned runtime_version, const char *split_name,
- uint64_t dwo_id, bool emit_debug_info);
-
-ZigLLVMDIFile *ZigLLVMCreateFile(ZigLLVMDIBuilder *dibuilder, const char *filename, const char *directory);
-
-ZigLLVMDISubprogram *ZigLLVMCreateFunction(ZigLLVMDIBuilder *dibuilder, ZigLLVMDIScope *scope,
- const char *name, const char *linkage_name, ZigLLVMDIFile *file, unsigned lineno,
- ZigLLVMDIType *fn_di_type, bool is_local_to_unit, bool is_definition, unsigned scope_line,
- unsigned flags, bool is_optimized, ZigLLVMDISubprogram *decl_subprogram);
-
-void ZigLLVMFnSetSubprogram(LLVMValueRef fn, ZigLLVMDISubprogram *subprogram);
-
-void ZigLLVMDIBuilderFinalize(ZigLLVMDIBuilder *dibuilder);
-
-LLVMValueRef ZigLLVMInsertDeclareAtEnd(ZigLLVMDIBuilder *dibuilder, LLVMValueRef storage,
- ZigLLVMDILocalVariable *var_info, ZigLLVMDILocation *debug_loc, LLVMBasicBlockRef basic_block_ref);
-LLVMValueRef ZigLLVMInsertDeclare(ZigLLVMDIBuilder *dibuilder, LLVMValueRef storage,
- ZigLLVMDILocalVariable *var_info, ZigLLVMDILocation *debug_loc, LLVMValueRef insert_before_instr);
-ZigLLVMDILocation *ZigLLVMGetDebugLoc(unsigned line, unsigned col, ZigLLVMDIScope *scope);
-
-void ZigLLVMSetFastMath(LLVMBuilderRef builder_wrapped, bool on_state);
-
-void ZigLLVMAddFunctionAttr(LLVMValueRef fn, const char *attr_name, const char *attr_value);
-void ZigLLVMAddFunctionAttrCold(LLVMValueRef fn);
-
-void ZigLLVMParseCommandLineOptions(int argc, const char *const *argv);
-
-
-// copied from include/llvm/ADT/Triple.h
-
-enum ZigLLVM_ArchType {
- ZigLLVM_UnknownArch,
-
- 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
- ZigLLVM_mipsel, // MIPSEL: mipsel, mipsallegrexel
- ZigLLVM_mips64, // MIPS64: mips64
- ZigLLVM_mips64el, // MIPS64EL: mips64el
- ZigLLVM_msp430, // MSP430: msp430
- ZigLLVM_nios2, // NIOSII: nios2
- 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
-
- ZigLLVM_LastArchType = ZigLLVM_renderscript64
-};
-
-enum ZigLLVM_SubArchType {
- ZigLLVM_NoSubArch,
-
- 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,
-
- ZigLLVM_KalimbaSubArch_v3,
- ZigLLVM_KalimbaSubArch_v4,
- ZigLLVM_KalimbaSubArch_v5,
-};
-
-enum ZigLLVM_VendorType {
- ZigLLVM_UnknownVendor,
-
- ZigLLVM_Apple,
- ZigLLVM_PC,
- ZigLLVM_SCEI,
- ZigLLVM_BGP,
- ZigLLVM_BGQ,
- ZigLLVM_Freescale,
- ZigLLVM_IBM,
- ZigLLVM_ImaginationTechnologies,
- ZigLLVM_MipsTechnologies,
- ZigLLVM_NVIDIA,
- ZigLLVM_CSR,
- ZigLLVM_Myriad,
- ZigLLVM_AMD,
- ZigLLVM_Mesa,
- ZigLLVM_SUSE,
-
- ZigLLVM_LastVendorType = ZigLLVM_SUSE
-};
-
-enum ZigLLVM_OSType {
- ZigLLVM_UnknownOS,
-
- ZigLLVM_Ananas,
- ZigLLVM_CloudABI,
- ZigLLVM_Darwin,
- ZigLLVM_DragonFly,
- ZigLLVM_FreeBSD,
- ZigLLVM_Fuchsia,
- ZigLLVM_IOS,
- ZigLLVM_KFreeBSD,
- ZigLLVM_Linux,
- ZigLLVM_Lv2, // PS3
- ZigLLVM_MacOSX,
- ZigLLVM_NetBSD,
- ZigLLVM_OpenBSD,
- ZigLLVM_Solaris,
- ZigLLVM_Win32,
- ZigLLVM_Haiku,
- ZigLLVM_Minix,
- ZigLLVM_RTEMS,
- ZigLLVM_NaCl, // Native Client
- ZigLLVM_CNK, // BG/P Compute-Node Kernel
- ZigLLVM_Bitrig,
- ZigLLVM_AIX,
- ZigLLVM_CUDA, // NVIDIA CUDA
- ZigLLVM_NVCL, // NVIDIA OpenCL
- ZigLLVM_AMDHSA, // AMD HSA Runtime
- ZigLLVM_PS4,
- ZigLLVM_ELFIAMCU,
- ZigLLVM_TvOS, // Apple tvOS
- ZigLLVM_WatchOS, // Apple watchOS
- ZigLLVM_Mesa3D,
- ZigLLVM_Contiki,
-
- ZigLLVM_LastOSType = ZigLLVM_Contiki
-};
-
-enum ZigLLVM_EnvironmentType {
- ZigLLVM_UnknownEnvironment,
-
- ZigLLVM_GNU,
- ZigLLVM_GNUABIN32,
- ZigLLVM_GNUABI64,
- ZigLLVM_GNUEABI,
- ZigLLVM_GNUEABIHF,
- ZigLLVM_GNUX32,
- ZigLLVM_CODE16,
- ZigLLVM_EABI,
- ZigLLVM_EABIHF,
- ZigLLVM_Android,
- ZigLLVM_Musl,
- ZigLLVM_MuslEABI,
- ZigLLVM_MuslEABIHF,
-
- ZigLLVM_MSVC,
- ZigLLVM_Itanium,
- ZigLLVM_Cygnus,
- ZigLLVM_AMDOpenCL,
- ZigLLVM_CoreCLR,
- ZigLLVM_OpenCL,
- ZigLLVM_Simulator, // Simulator variants of other systems, e.g., Apple's iOS
-
- ZigLLVM_LastEnvironmentType = ZigLLVM_Simulator
-};
-
-enum ZigLLVM_ObjectFormatType {
- ZigLLVM_UnknownObjectFormat,
-
- ZigLLVM_COFF,
- ZigLLVM_ELF,
- ZigLLVM_MachO,
- ZigLLVM_Wasm,
-};
-
-const char *ZigLLVMGetArchTypeName(ZigLLVM_ArchType arch);
-const char *ZigLLVMGetSubArchTypeName(ZigLLVM_SubArchType sub_arch);
-const char *ZigLLVMGetVendorTypeName(ZigLLVM_VendorType vendor);
-const char *ZigLLVMGetOSTypeName(ZigLLVM_OSType os);
-const char *ZigLLVMGetEnvironmentTypeName(ZigLLVM_EnvironmentType env_type);
-
-/*
- * This stuff is not LLVM API but it depends on the LLVM C++ API so we put it here.
- */
-struct Buf;
-
-bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_count, Buf *diag);
-
-void ZigLLVMGetNativeTarget(ZigLLVM_ArchType *arch_type, ZigLLVM_SubArchType *sub_arch_type,
- ZigLLVM_VendorType *vendor_type, ZigLLVM_OSType *os_type, ZigLLVM_EnvironmentType *environ_type,
- ZigLLVM_ObjectFormatType *oformat);
-
-#endif
diff --git a/std/array_list.zig b/std/array_list.zig
index 04db4dd280121b23e25db76a11fb4308cae93bd3..db5581dc08b7fa21fac2e0007efe09b2ac05d0cc 100644
--- a/std/array_list.zig
+++ b/std/array_list.zig
@@ -1,6 +1,7 @@
-const debug = @import("debug.zig");
+const std = @import("index.zig");
+const debug = std.debug;
const assert = debug.assert;
-const mem = @import("mem.zig");
+const mem = std.mem;
const Allocator = mem.Allocator;
pub fn ArrayList(comptime T: type) -> type {
diff --git a/std/base64.zig b/std/base64.zig
index 840643b565b454f72e1ae9abf7527598df2818fa..0b405b1f4cd72ae5ef83b931ff25bf2069e1779c 100644
--- a/std/base64.zig
+++ b/std/base64.zig
@@ -1,5 +1,6 @@
-const assert = @import("debug.zig").assert;
-const mem = @import("mem.zig");
+const std = @import("index.zig");
+const assert = std.debug.assert;
+const mem = std.mem;
pub const standard_alphabet_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
pub const standard_pad_char = '=';
diff --git a/std/buffer.zig b/std/buffer.zig
index 4f5d281f4898eddf8237c5adc1e1436728545450..2bb395d0fb2a93e9df314f82c71cfd482d36b888 100644
--- a/std/buffer.zig
+++ b/std/buffer.zig
@@ -1,10 +1,11 @@
-const debug = @import("debug.zig");
-const mem = @import("mem.zig");
+const std = @import("index.zig");
+const debug = std.debug;
+const mem = std.mem;
const Allocator = mem.Allocator;
const assert = debug.assert;
-const ArrayList = @import("array_list.zig").ArrayList;
+const ArrayList = std.ArrayList;
-const fmt = @import("fmt/index.zig");
+const fmt = std.fmt;
/// A buffer that allocates memory and maintains a null byte at the end.
pub const Buffer = struct {
diff --git a/std/build.zig b/std/build.zig
index 3a2079db15b16d0726e442027962921e9995f5e2..bb5280837f9695eb547313ec3c88467908841ba5 100644
--- a/std/build.zig
+++ b/std/build.zig
@@ -784,6 +784,13 @@ const Target = union(enum) {
};
}
+ pub fn libFileExt(self: &const Target) -> []const u8 {
+ return switch (self.getOs()) {
+ builtin.Os.windows => ".lib",
+ else => ".a",
+ };
+ }
+
pub fn getOs(self: &const Target) -> builtin.Os {
return switch (*self) {
Target.Native => builtin.os,
diff --git a/std/cstr.zig b/std/cstr.zig
index 445f7ab89234f90a77af112811dbe6e404afcebd..1610f12481dfc7863b1d74fea9b80ace4c30ae18 100644
--- a/std/cstr.zig
+++ b/std/cstr.zig
@@ -1,5 +1,6 @@
-const debug = @import("debug.zig");
-const mem = @import("mem.zig");
+const std = @import("index.zig");
+const debug = std.debug;
+const mem = std.mem;
const assert = debug.assert;
pub fn len(ptr: &const u8) -> usize {
@@ -47,3 +48,57 @@ pub fn addNullByte(allocator: &mem.Allocator, slice: []const u8) -> %[]u8 {
result[slice.len] = 0;
return result;
}
+
+pub const NullTerminated2DArray = struct {
+ allocator: &mem.Allocator,
+ byte_count: usize,
+ ptr: ?&?&u8,
+
+ /// Takes N lists of strings, concatenates the lists together, and adds a null terminator
+ /// Caller must deinit result
+ pub fn fromSlices(allocator: &mem.Allocator, slices: []const []const []const u8) -> %NullTerminated2DArray {
+ var new_len: usize = 1; // 1 for the list null
+ var byte_count: usize = 0;
+ for (slices) |slice| {
+ new_len += slice.len;
+ for (slice) |inner| {
+ byte_count += inner.len;
+ }
+ byte_count += slice.len; // for the null terminators of inner
+ }
+
+ const index_size = @sizeOf(usize) * new_len; // size of the ptrs
+ byte_count += index_size;
+
+ const buf = %return allocator.alignedAlloc(u8, @alignOf(?&u8), byte_count);
+ %defer allocator.free(buf);
+
+ var write_index = index_size;
+ const index_buf = ([]?&u8)(buf);
+
+ var i: usize = 0;
+ for (slices) |slice| {
+ for (slice) |inner| {
+ index_buf[i] = &buf[write_index];
+ i += 1;
+ mem.copy(u8, buf[write_index..], inner);
+ write_index += inner.len;
+ buf[write_index] = 0;
+ write_index += 1;
+ }
+ }
+ index_buf[i] = null;
+
+ return NullTerminated2DArray {
+ .allocator = allocator,
+ .byte_count = byte_count,
+ .ptr = @ptrCast(?&?&u8, buf.ptr),
+ };
+ }
+
+ pub fn deinit(self: &NullTerminated2DArray) {
+ const buf = @ptrCast(&u8, self.ptr);
+ self.allocator.free(buf[0..self.byte_count]);
+ }
+};
+
diff --git a/std/debug.zig b/std/debug.zig
deleted file mode 100644
index a683b5ae15d3beae19d17ae5f01441919533f0d4..0000000000000000000000000000000000000000
--- a/std/debug.zig
+++ /dev/null
@@ -1,1050 +0,0 @@
-const std = @import("index.zig");
-const math = std.math;
-const mem = std.mem;
-const io = std.io;
-const os = std.os;
-const elf = @import("elf.zig");
-const DW = @import("dwarf.zig");
-const ArrayList = std.ArrayList;
-const builtin = @import("builtin");
-
-error MissingDebugInfo;
-error InvalidDebugInfo;
-error UnsupportedDebugInfo;
-
-
-/// Tries to write to stderr, unbuffered, and ignores any error returned.
-/// Does not append a newline.
-/// TODO atomic/multithread support
-var stderr_file: io.File = undefined;
-var stderr_file_out_stream: io.FileOutStream = undefined;
-var stderr_stream: ?&io.OutStream = null;
-pub fn warn(comptime fmt: []const u8, args: ...) {
- const stderr = getStderrStream() %% return;
- stderr.print(fmt, args) %% return;
-}
-fn getStderrStream() -> %&io.OutStream {
- if (stderr_stream) |st| {
- return st;
- } else {
- stderr_file = %return io.getStdErr();
- stderr_file_out_stream = io.FileOutStream.init(&stderr_file);
- const st = &stderr_file_out_stream.stream;
- stderr_stream = st;
- return st;
- }
-}
-
-/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.
-pub fn dumpStackTrace() {
- const stderr = getStderrStream() %% return;
- writeStackTrace(stderr, global_allocator, stderr_file.isTty(), 1) %% return;
-}
-
-/// This function invokes undefined behavior when `ok` is `false`.
-/// In Debug and ReleaseSafe modes, calls to this function are always
-/// generated, and the `unreachable` statement triggers a panic.
-/// In ReleaseFast and ReleaseSmall modes, calls to this function can be
-/// optimized away.
-pub fn assert(ok: bool) {
- if (!ok) {
- // In ReleaseFast test mode, we still want assert(false) to crash, so
- // we insert an explicit call to @panic instead of unreachable.
- // TODO we should use `assertOrPanic` in tests and remove this logic.
- if (builtin.is_test) {
- @panic("assertion failure");
- } else {
- unreachable; // assertion failure
- }
- }
-}
-
-/// Call this function when you want to panic if the condition is not true.
-/// If `ok` is `false`, this function will panic in every release mode.
-pub fn assertOrPanic(ok: bool) {
- if (!ok) {
- @panic("assertion failure");
- }
-}
-
-var panicking = false;
-/// This is the default panic implementation.
-pub fn panic(comptime format: []const u8, args: ...) -> noreturn {
- // TODO an intrinsic that labels this as unlikely to be reached
-
- // TODO
- // if (@atomicRmw(AtomicOp.XChg, &panicking, true, AtomicOrder.SeqCst)) { }
- if (panicking) {
- // Panicked during a panic.
- // TODO detect if a different thread caused the panic, because in that case
- // we would want to return here instead of calling abort, so that the thread
- // which first called panic can finish printing a stack trace.
- os.abort();
- } else {
- panicking = true;
- }
-
- const stderr = getStderrStream() %% os.abort();
- stderr.print(format ++ "\n", args) %% os.abort();
- writeStackTrace(stderr, global_allocator, stderr_file.isTty(), 1) %% os.abort();
-
- os.abort();
-}
-
-const GREEN = "\x1b[32;1m";
-const WHITE = "\x1b[37;1m";
-const DIM = "\x1b[2m";
-const RESET = "\x1b[0m";
-
-error PathNotFound;
-error InvalidDebugInfo;
-
-pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty_color: bool,
- ignore_frame_count: usize) -> %void
-{
- switch (builtin.object_format) {
- builtin.ObjectFormat.elf => {
- var stack_trace = ElfStackTrace {
- .self_exe_file = undefined,
- .elf = undefined,
- .debug_info = undefined,
- .debug_abbrev = undefined,
- .debug_str = undefined,
- .debug_line = undefined,
- .debug_ranges = null,
- .abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator),
- .compile_unit_list = ArrayList(CompileUnit).init(allocator),
- };
- const st = &stack_trace;
- st.self_exe_file = %return os.openSelfExe();
- defer st.self_exe_file.close();
-
- %return st.elf.openFile(allocator, &st.self_exe_file);
- defer st.elf.close();
-
- st.debug_info = (%return st.elf.findSection(".debug_info")) ?? return error.MissingDebugInfo;
- st.debug_abbrev = (%return st.elf.findSection(".debug_abbrev")) ?? return error.MissingDebugInfo;
- st.debug_str = (%return st.elf.findSection(".debug_str")) ?? return error.MissingDebugInfo;
- st.debug_line = (%return st.elf.findSection(".debug_line")) ?? return error.MissingDebugInfo;
- st.debug_ranges = (%return st.elf.findSection(".debug_ranges"));
- %return scanAllCompileUnits(st);
-
- var ignored_count: usize = 0;
-
- var fp = @ptrToInt(@frameAddress());
- while (fp != 0) : (fp = *@intToPtr(&const usize, fp)) {
- if (ignored_count < ignore_frame_count) {
- ignored_count += 1;
- continue;
- }
-
- const return_address = *@intToPtr(&const usize, fp + @sizeOf(usize));
-
- // TODO we really should be able to convert @sizeOf(usize) * 2 to a string literal
- // at compile time. I'll call it issue #313
- const ptr_hex = if (@sizeOf(usize) == 4) "0x{x8}" else "0x{x16}";
-
- const compile_unit = findCompileUnit(st, return_address) %% {
- %return out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n",
- return_address);
- continue;
- };
- const compile_unit_name = %return compile_unit.die.getAttrString(st, DW.AT_name);
- if (getLineNumberInfo(st, compile_unit, usize(return_address) - 1)) |line_info| {
- defer line_info.deinit();
- %return out_stream.print(WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++
- DIM ++ ptr_hex ++ " in ??? ({})" ++ RESET ++ "\n",
- line_info.file_name, line_info.line, line_info.column,
- return_address, compile_unit_name);
- if (printLineFromFile(st.allocator(), out_stream, line_info)) {
- if (line_info.column == 0) {
- %return out_stream.write("\n");
- } else {
- {var col_i: usize = 1; while (col_i < line_info.column) : (col_i += 1) {
- %return out_stream.writeByte(' ');
- }}
- %return out_stream.write(GREEN ++ "^" ++ RESET ++ "\n");
- }
- } else |err| switch (err) {
- error.EndOfFile, error.PathNotFound => {},
- else => return err,
- }
- } else |err| switch (err) {
- error.MissingDebugInfo, error.InvalidDebugInfo => {
- %return out_stream.print(ptr_hex ++ " in ??? ({})\n",
- return_address, compile_unit_name);
- },
- else => return err,
- }
- }
- },
- builtin.ObjectFormat.coff => {
- %return out_stream.write("(stack trace unavailable for COFF object format)\n");
- },
- builtin.ObjectFormat.macho => {
- %return out_stream.write("(stack trace unavailable for Mach-O object format)\n");
- },
- builtin.ObjectFormat.wasm => {
- %return out_stream.write("(stack trace unavailable for WASM object format)\n");
- },
- builtin.ObjectFormat.unknown => {
- %return out_stream.write("(stack trace unavailable for unknown object format)\n");
- },
- }
-}
-
-fn printLineFromFile(allocator: &mem.Allocator, out_stream: &io.OutStream, line_info: &const LineInfo) -> %void {
- var f = %return io.File.openRead(line_info.file_name, allocator);
- defer f.close();
- // TODO fstat and make sure that the file has the correct size
-
- var buf: [os.page_size]u8 = undefined;
- var line: usize = 1;
- var column: usize = 1;
- var abs_index: usize = 0;
- while (true) {
- const amt_read = %return f.read(buf[0..]);
- const slice = buf[0..amt_read];
-
- for (slice) |byte| {
- if (line == line_info.line) {
- %return out_stream.writeByte(byte);
- if (byte == '\n') {
- return;
- }
- }
- if (byte == '\n') {
- line += 1;
- column = 1;
- } else {
- column += 1;
- }
- }
-
- if (amt_read < buf.len)
- return error.EndOfFile;
- }
-}
-
-const ElfStackTrace = struct {
- self_exe_file: io.File,
- elf: elf.Elf,
- debug_info: &elf.SectionHeader,
- debug_abbrev: &elf.SectionHeader,
- debug_str: &elf.SectionHeader,
- debug_line: &elf.SectionHeader,
- debug_ranges: ?&elf.SectionHeader,
- abbrev_table_list: ArrayList(AbbrevTableHeader),
- compile_unit_list: ArrayList(CompileUnit),
-
- pub fn allocator(self: &const ElfStackTrace) -> &mem.Allocator {
- return self.abbrev_table_list.allocator;
- }
-
- pub fn readString(self: &ElfStackTrace) -> %[]u8 {
- var in_file_stream = io.FileInStream.init(&self.self_exe_file);
- const in_stream = &in_file_stream.stream;
- return readStringRaw(self.allocator(), in_stream);
- }
-};
-
-const PcRange = struct {
- start: u64,
- end: u64,
-};
-
-const CompileUnit = struct {
- version: u16,
- is_64: bool,
- die: &Die,
- index: usize,
- pc_range: ?PcRange,
-};
-
-const AbbrevTable = ArrayList(AbbrevTableEntry);
-
-const AbbrevTableHeader = struct {
- // offset from .debug_abbrev
- offset: u64,
- table: AbbrevTable,
-};
-
-const AbbrevTableEntry = struct {
- has_children: bool,
- abbrev_code: u64,
- tag_id: u64,
- attrs: ArrayList(AbbrevAttr),
-};
-
-const AbbrevAttr = struct {
- attr_id: u64,
- form_id: u64,
-};
-
-const FormValue = union(enum) {
- Address: u64,
- Block: []u8,
- Const: Constant,
- ExprLoc: []u8,
- Flag: bool,
- SecOffset: u64,
- Ref: []u8,
- RefAddr: u64,
- RefSig8: u64,
- String: []u8,
- StrPtr: u64,
-};
-
-const Constant = struct {
- payload: []u8,
- signed: bool,
-
- fn asUnsignedLe(self: &const Constant) -> %u64 {
- if (self.payload.len > @sizeOf(u64))
- return error.InvalidDebugInfo;
- if (self.signed)
- return error.InvalidDebugInfo;
- return mem.readInt(self.payload, u64, builtin.Endian.Little);
- }
-};
-
-const Die = struct {
- tag_id: u64,
- has_children: bool,
- attrs: ArrayList(Attr),
-
- const Attr = struct {
- id: u64,
- value: FormValue,
- };
-
- fn getAttr(self: &const Die, id: u64) -> ?&const FormValue {
- for (self.attrs.toSliceConst()) |*attr| {
- if (attr.id == id)
- return &attr.value;
- }
- return null;
- }
-
- fn getAttrAddr(self: &const Die, id: u64) -> %u64 {
- const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
- return switch (*form_value) {
- FormValue.Address => |value| value,
- else => error.InvalidDebugInfo,
- };
- }
-
- fn getAttrSecOffset(self: &const Die, id: u64) -> %u64 {
- const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
- return switch (*form_value) {
- FormValue.Const => |value| value.asUnsignedLe(),
- FormValue.SecOffset => |value| value,
- else => error.InvalidDebugInfo,
- };
- }
-
- fn getAttrUnsignedLe(self: &const Die, id: u64) -> %u64 {
- const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
- return switch (*form_value) {
- FormValue.Const => |value| value.asUnsignedLe(),
- else => error.InvalidDebugInfo,
- };
- }
-
- fn getAttrString(self: &const Die, st: &ElfStackTrace, id: u64) -> %[]u8 {
- const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
- return switch (*form_value) {
- FormValue.String => |value| value,
- FormValue.StrPtr => |offset| getString(st, offset),
- else => error.InvalidDebugInfo,
- };
- }
-};
-
-const FileEntry = struct {
- file_name: []const u8,
- dir_index: usize,
- mtime: usize,
- len_bytes: usize,
-};
-
-const LineInfo = struct {
- line: usize,
- column: usize,
- file_name: []u8,
- allocator: &mem.Allocator,
-
- fn deinit(self: &const LineInfo) {
- self.allocator.free(self.file_name);
- }
-};
-
-const LineNumberProgram = struct {
- address: usize,
- file: usize,
- line: isize,
- column: usize,
- is_stmt: bool,
- basic_block: bool,
- end_sequence: bool,
-
- target_address: usize,
- include_dirs: []const []const u8,
- file_entries: &ArrayList(FileEntry),
-
- prev_address: usize,
- prev_file: usize,
- prev_line: isize,
- prev_column: usize,
- prev_is_stmt: bool,
- prev_basic_block: bool,
- prev_end_sequence: bool,
-
- pub fn init(is_stmt: bool, include_dirs: []const []const u8,
- file_entries: &ArrayList(FileEntry), target_address: usize) -> LineNumberProgram
- {
- return LineNumberProgram {
- .address = 0,
- .file = 1,
- .line = 1,
- .column = 0,
- .is_stmt = is_stmt,
- .basic_block = false,
- .end_sequence = false,
- .include_dirs = include_dirs,
- .file_entries = file_entries,
- .target_address = target_address,
- .prev_address = 0,
- .prev_file = undefined,
- .prev_line = undefined,
- .prev_column = undefined,
- .prev_is_stmt = undefined,
- .prev_basic_block = undefined,
- .prev_end_sequence = undefined,
- };
- }
-
- pub fn checkLineMatch(self: &LineNumberProgram) -> %?LineInfo {
- if (self.target_address >= self.prev_address and self.target_address < self.address) {
- const file_entry = if (self.prev_file == 0) {
- return error.MissingDebugInfo;
- } else if (self.prev_file - 1 >= self.file_entries.len) {
- return error.InvalidDebugInfo;
- } else &self.file_entries.items[self.prev_file - 1];
-
- const dir_name = if (file_entry.dir_index >= self.include_dirs.len) {
- return error.InvalidDebugInfo;
- } else self.include_dirs[file_entry.dir_index];
- const file_name = %return os.path.join(self.file_entries.allocator, dir_name, file_entry.file_name);
- %defer self.file_entries.allocator.free(file_name);
- return LineInfo {
- .line = if (self.prev_line >= 0) usize(self.prev_line) else 0,
- .column = self.prev_column,
- .file_name = file_name,
- .allocator = self.file_entries.allocator,
- };
- }
-
- self.prev_address = self.address;
- self.prev_file = self.file;
- self.prev_line = self.line;
- self.prev_column = self.column;
- self.prev_is_stmt = self.is_stmt;
- self.prev_basic_block = self.basic_block;
- self.prev_end_sequence = self.end_sequence;
- return null;
- }
-};
-
-fn readStringRaw(allocator: &mem.Allocator, in_stream: &io.InStream) -> %[]u8 {
- var buf = ArrayList(u8).init(allocator);
- while (true) {
- const byte = %return in_stream.readByte();
- if (byte == 0)
- break;
- %return buf.append(byte);
- }
- return buf.toSlice();
-}
-
-fn getString(st: &ElfStackTrace, offset: u64) -> %[]u8 {
- const pos = st.debug_str.offset + offset;
- %return st.self_exe_file.seekTo(pos);
- return st.readString();
-}
-
-fn readAllocBytes(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %[]u8 {
- const buf = %return global_allocator.alloc(u8, size);
- %defer global_allocator.free(buf);
- if ((%return in_stream.read(buf)) < size) return error.EndOfFile;
- return buf;
-}
-
-fn parseFormValueBlockLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
- const buf = %return readAllocBytes(allocator, in_stream, size);
- return FormValue { .Block = buf };
-}
-
-fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
- const block_len = %return in_stream.readVarInt(builtin.Endian.Little, usize, size);
- return parseFormValueBlockLen(allocator, in_stream, block_len);
-}
-
-fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: &io.InStream, signed: bool, size: usize) -> %FormValue {
- return FormValue { .Const = Constant {
- .signed = signed,
- .payload = %return readAllocBytes(allocator, in_stream, size),
- }};
-}
-
-fn parseFormValueDwarfOffsetSize(in_stream: &io.InStream, is_64: bool) -> %u64 {
- return if (is_64) %return in_stream.readIntLe(u64)
- else u64(%return in_stream.readIntLe(u32)) ;
-}
-
-fn parseFormValueTargetAddrSize(in_stream: &io.InStream) -> %u64 {
- return if (@sizeOf(usize) == 4) u64(%return in_stream.readIntLe(u32))
- else if (@sizeOf(usize) == 8) %return in_stream.readIntLe(u64)
- else unreachable;
-}
-
-fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
- const buf = %return readAllocBytes(allocator, in_stream, size);
- return FormValue { .Ref = buf };
-}
-
-fn parseFormValueRef(allocator: &mem.Allocator, in_stream: &io.InStream, comptime T: type) -> %FormValue {
- const block_len = %return in_stream.readIntLe(T);
- return parseFormValueRefLen(allocator, in_stream, block_len);
-}
-
-fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u64, is_64: bool) -> %FormValue {
- return switch (form_id) {
- DW.FORM_addr => FormValue { .Address = %return parseFormValueTargetAddrSize(in_stream) },
- DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
- DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),
- DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),
- DW.FORM_block => x: {
- const block_len = %return readULeb128(in_stream);
- return parseFormValueBlockLen(allocator, in_stream, block_len);
- },
- DW.FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1),
- DW.FORM_data2 => parseFormValueConstant(allocator, in_stream, false, 2),
- DW.FORM_data4 => parseFormValueConstant(allocator, in_stream, false, 4),
- DW.FORM_data8 => parseFormValueConstant(allocator, in_stream, false, 8),
- DW.FORM_udata, DW.FORM_sdata => {
- const block_len = %return readULeb128(in_stream);
- const signed = form_id == DW.FORM_sdata;
- return parseFormValueConstant(allocator, in_stream, signed, block_len);
- },
- DW.FORM_exprloc => {
- const size = %return readULeb128(in_stream);
- const buf = %return readAllocBytes(allocator, in_stream, size);
- return FormValue { .ExprLoc = buf };
- },
- DW.FORM_flag => FormValue { .Flag = (%return in_stream.readByte()) != 0 },
- DW.FORM_flag_present => FormValue { .Flag = true },
- DW.FORM_sec_offset => FormValue { .SecOffset = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
-
- DW.FORM_ref1 => parseFormValueRef(allocator, in_stream, u8),
- DW.FORM_ref2 => parseFormValueRef(allocator, in_stream, u16),
- DW.FORM_ref4 => parseFormValueRef(allocator, in_stream, u32),
- DW.FORM_ref8 => parseFormValueRef(allocator, in_stream, u64),
- DW.FORM_ref_udata => {
- const ref_len = %return readULeb128(in_stream);
- return parseFormValueRefLen(allocator, in_stream, ref_len);
- },
-
- DW.FORM_ref_addr => FormValue { .RefAddr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
- DW.FORM_ref_sig8 => FormValue { .RefSig8 = %return in_stream.readIntLe(u64) },
-
- DW.FORM_string => FormValue { .String = %return readStringRaw(allocator, in_stream) },
- DW.FORM_strp => FormValue { .StrPtr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
- DW.FORM_indirect => {
- const child_form_id = %return readULeb128(in_stream);
- return parseFormValue(allocator, in_stream, child_form_id, is_64);
- },
- else => error.InvalidDebugInfo,
- };
-}
-
-fn parseAbbrevTable(st: &ElfStackTrace) -> %AbbrevTable {
- const in_file = &st.self_exe_file;
- var in_file_stream = io.FileInStream.init(in_file);
- const in_stream = &in_file_stream.stream;
- var result = AbbrevTable.init(st.allocator());
- while (true) {
- const abbrev_code = %return readULeb128(in_stream);
- if (abbrev_code == 0)
- return result;
- %return result.append(AbbrevTableEntry {
- .abbrev_code = abbrev_code,
- .tag_id = %return readULeb128(in_stream),
- .has_children = (%return in_stream.readByte()) == DW.CHILDREN_yes,
- .attrs = ArrayList(AbbrevAttr).init(st.allocator()),
- });
- const attrs = &result.items[result.len - 1].attrs;
-
- while (true) {
- const attr_id = %return readULeb128(in_stream);
- const form_id = %return readULeb128(in_stream);
- if (attr_id == 0 and form_id == 0)
- break;
- %return attrs.append(AbbrevAttr {
- .attr_id = attr_id,
- .form_id = form_id,
- });
- }
- }
-}
-
-/// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
-/// seeks in the stream and parses it.
-fn getAbbrevTable(st: &ElfStackTrace, abbrev_offset: u64) -> %&const AbbrevTable {
- for (st.abbrev_table_list.toSlice()) |*header| {
- if (header.offset == abbrev_offset) {
- return &header.table;
- }
- }
- %return st.self_exe_file.seekTo(st.debug_abbrev.offset + abbrev_offset);
- %return st.abbrev_table_list.append(AbbrevTableHeader {
- .offset = abbrev_offset,
- .table = %return parseAbbrevTable(st),
- });
- return &st.abbrev_table_list.items[st.abbrev_table_list.len - 1].table;
-}
-
-fn getAbbrevTableEntry(abbrev_table: &const AbbrevTable, abbrev_code: u64) -> ?&const AbbrevTableEntry {
- for (abbrev_table.toSliceConst()) |*table_entry| {
- if (table_entry.abbrev_code == abbrev_code)
- return table_entry;
- }
- return null;
-}
-
-fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) -> %Die {
- const in_file = &st.self_exe_file;
- var in_file_stream = io.FileInStream.init(in_file);
- const in_stream = &in_file_stream.stream;
- const abbrev_code = %return readULeb128(in_stream);
- const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) ?? return error.InvalidDebugInfo;
-
- var result = Die {
- .tag_id = table_entry.tag_id,
- .has_children = table_entry.has_children,
- .attrs = ArrayList(Die.Attr).init(st.allocator()),
- };
- %return result.attrs.resize(table_entry.attrs.len);
- for (table_entry.attrs.toSliceConst()) |attr, i| {
- result.attrs.items[i] = Die.Attr {
- .id = attr.attr_id,
- .value = %return parseFormValue(st.allocator(), in_stream, attr.form_id, is_64),
- };
- }
- return result;
-}
-
-fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, target_address: usize) -> %LineInfo {
- const compile_unit_cwd = %return compile_unit.die.getAttrString(st, DW.AT_comp_dir);
-
- const in_file = &st.self_exe_file;
- const debug_line_end = st.debug_line.offset + st.debug_line.size;
- var this_offset = st.debug_line.offset;
- var this_index: usize = 0;
-
- var in_file_stream = io.FileInStream.init(in_file);
- const in_stream = &in_file_stream.stream;
-
- while (this_offset < debug_line_end) : (this_index += 1) {
- %return in_file.seekTo(this_offset);
-
- var is_64: bool = undefined;
- const unit_length = %return readInitialLength(in_stream, &is_64);
- if (unit_length == 0)
- return error.MissingDebugInfo;
- const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
-
- if (compile_unit.index != this_index) {
- this_offset += next_offset;
- continue;
- }
-
- const version = %return in_stream.readInt(st.elf.endian, u16);
- if (version != 2) return error.InvalidDebugInfo;
-
- const prologue_length = %return in_stream.readInt(st.elf.endian, u32);
- const prog_start_offset = (%return in_file.getPos()) + prologue_length;
-
- const minimum_instruction_length = %return in_stream.readByte();
- if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
-
- const default_is_stmt = (%return in_stream.readByte()) != 0;
- const line_base = %return in_stream.readByteSigned();
-
- const line_range = %return in_stream.readByte();
- if (line_range == 0)
- return error.InvalidDebugInfo;
-
- const opcode_base = %return in_stream.readByte();
-
- const standard_opcode_lengths = %return st.allocator().alloc(u8, opcode_base - 1);
-
- {var i: usize = 0; while (i < opcode_base - 1) : (i += 1) {
- standard_opcode_lengths[i] = %return in_stream.readByte();
- }}
-
- var include_directories = ArrayList([]u8).init(st.allocator());
- %return include_directories.append(compile_unit_cwd);
- while (true) {
- const dir = %return st.readString();
- if (dir.len == 0)
- break;
- %return include_directories.append(dir);
- }
-
- var file_entries = ArrayList(FileEntry).init(st.allocator());
- var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(),
- &file_entries, target_address);
-
- while (true) {
- const file_name = %return st.readString();
- if (file_name.len == 0)
- break;
- const dir_index = %return readULeb128(in_stream);
- const mtime = %return readULeb128(in_stream);
- const len_bytes = %return readULeb128(in_stream);
- %return file_entries.append(FileEntry {
- .file_name = file_name,
- .dir_index = dir_index,
- .mtime = mtime,
- .len_bytes = len_bytes,
- });
- }
-
- %return in_file.seekTo(prog_start_offset);
-
- while (true) {
- const opcode = %return in_stream.readByte();
-
- var sub_op: u8 = undefined; // TODO move this to the correct scope and fix the compiler crash
- if (opcode == DW.LNS_extended_op) {
- const op_size = %return readULeb128(in_stream);
- if (op_size < 1)
- return error.InvalidDebugInfo;
- sub_op = %return in_stream.readByte();
- switch (sub_op) {
- DW.LNE_end_sequence => {
- prog.end_sequence = true;
- if (%return prog.checkLineMatch()) |info| return info;
- return error.MissingDebugInfo;
- },
- DW.LNE_set_address => {
- const addr = %return in_stream.readInt(st.elf.endian, usize);
- prog.address = addr;
- },
- DW.LNE_define_file => {
- const file_name = %return st.readString();
- const dir_index = %return readULeb128(in_stream);
- const mtime = %return readULeb128(in_stream);
- const len_bytes = %return readULeb128(in_stream);
- %return file_entries.append(FileEntry {
- .file_name = file_name,
- .dir_index = dir_index,
- .mtime = mtime,
- .len_bytes = len_bytes,
- });
- },
- else => {
- const fwd_amt = math.cast(isize, op_size - 1) %% return error.InvalidDebugInfo;
- %return in_file.seekForward(fwd_amt);
- },
- }
- } else if (opcode >= opcode_base) {
- // special opcodes
- const adjusted_opcode = opcode - opcode_base;
- const inc_addr = minimum_instruction_length * (adjusted_opcode / line_range);
- const inc_line = i32(line_base) + i32(adjusted_opcode % line_range);
- prog.line += inc_line;
- prog.address += inc_addr;
- if (%return prog.checkLineMatch()) |info| return info;
- prog.basic_block = false;
- } else {
- switch (opcode) {
- DW.LNS_copy => {
- if (%return prog.checkLineMatch()) |info| return info;
- prog.basic_block = false;
- },
- DW.LNS_advance_pc => {
- const arg = %return readULeb128(in_stream);
- prog.address += arg * minimum_instruction_length;
- },
- DW.LNS_advance_line => {
- const arg = %return readILeb128(in_stream);
- prog.line += arg;
- },
- DW.LNS_set_file => {
- const arg = %return readULeb128(in_stream);
- prog.file = arg;
- },
- DW.LNS_set_column => {
- const arg = %return readULeb128(in_stream);
- prog.column = arg;
- },
- DW.LNS_negate_stmt => {
- prog.is_stmt = !prog.is_stmt;
- },
- DW.LNS_set_basic_block => {
- prog.basic_block = true;
- },
- DW.LNS_const_add_pc => {
- const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range);
- prog.address += inc_addr;
- },
- DW.LNS_fixed_advance_pc => {
- const arg = %return in_stream.readInt(st.elf.endian, u16);
- prog.address += arg;
- },
- DW.LNS_set_prologue_end => {
- },
- else => {
- if (opcode - 1 >= standard_opcode_lengths.len)
- return error.InvalidDebugInfo;
- const len_bytes = standard_opcode_lengths[opcode - 1];
- %return in_file.seekForward(len_bytes);
- },
- }
- }
- }
-
- this_offset += next_offset;
- }
-
- return error.MissingDebugInfo;
-}
-
-fn scanAllCompileUnits(st: &ElfStackTrace) -> %void {
- const debug_info_end = st.debug_info.offset + st.debug_info.size;
- var this_unit_offset = st.debug_info.offset;
- var cu_index: usize = 0;
-
- var in_file_stream = io.FileInStream.init(&st.self_exe_file);
- const in_stream = &in_file_stream.stream;
-
- while (this_unit_offset < debug_info_end) {
- %return st.self_exe_file.seekTo(this_unit_offset);
-
- var is_64: bool = undefined;
- const unit_length = %return readInitialLength(in_stream, &is_64);
- if (unit_length == 0)
- return;
- const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
-
- const version = %return in_stream.readInt(st.elf.endian, u16);
- if (version < 2 or version > 5) return error.InvalidDebugInfo;
-
- const debug_abbrev_offset =
- if (is_64) %return in_stream.readInt(st.elf.endian, u64)
- else %return in_stream.readInt(st.elf.endian, u32);
-
- const address_size = %return in_stream.readByte();
- if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
-
- const compile_unit_pos = %return st.self_exe_file.getPos();
- const abbrev_table = %return getAbbrevTable(st, debug_abbrev_offset);
-
- %return st.self_exe_file.seekTo(compile_unit_pos);
-
- const compile_unit_die = %return st.allocator().create(Die);
- *compile_unit_die = %return parseDie(st, abbrev_table, is_64);
-
- if (compile_unit_die.tag_id != DW.TAG_compile_unit)
- return error.InvalidDebugInfo;
-
- const pc_range = x: {
- if (compile_unit_die.getAttrAddr(DW.AT_low_pc)) |low_pc| {
- if (compile_unit_die.getAttr(DW.AT_high_pc)) |high_pc_value| {
- const pc_end = switch (*high_pc_value) {
- FormValue.Address => |value| value,
- FormValue.Const => |value| b: {
- const offset = %return value.asUnsignedLe();
- break :b (low_pc + offset);
- },
- else => return error.InvalidDebugInfo,
- };
- break :x PcRange {
- .start = low_pc,
- .end = pc_end,
- };
- } else {
- break :x null;
- }
- } else |err| {
- if (err != error.MissingDebugInfo)
- return err;
- break :x null;
- }
- };
-
- %return st.compile_unit_list.append(CompileUnit {
- .version = version,
- .is_64 = is_64,
- .pc_range = pc_range,
- .die = compile_unit_die,
- .index = cu_index,
- });
-
- this_unit_offset += next_offset;
- cu_index += 1;
- }
-}
-
-fn findCompileUnit(st: &ElfStackTrace, target_address: u64) -> %&const CompileUnit {
- var in_file_stream = io.FileInStream.init(&st.self_exe_file);
- const in_stream = &in_file_stream.stream;
- for (st.compile_unit_list.toSlice()) |*compile_unit| {
- if (compile_unit.pc_range) |range| {
- if (target_address >= range.start and target_address < range.end)
- return compile_unit;
- }
- if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| {
- var base_address: usize = 0;
- if (st.debug_ranges) |debug_ranges| {
- %return st.self_exe_file.seekTo(debug_ranges.offset + ranges_offset);
- while (true) {
- const begin_addr = %return in_stream.readIntLe(usize);
- const end_addr = %return in_stream.readIntLe(usize);
- if (begin_addr == 0 and end_addr == 0) {
- break;
- }
- if (begin_addr == @maxValue(usize)) {
- base_address = begin_addr;
- continue;
- }
- if (target_address >= begin_addr and target_address < end_addr) {
- return compile_unit;
- }
- }
- }
- } else |err| {
- if (err != error.MissingDebugInfo)
- return err;
- continue;
- }
- }
- return error.MissingDebugInfo;
-}
-
-fn readInitialLength(in_stream: &io.InStream, is_64: &bool) -> %u64 {
- const first_32_bits = %return in_stream.readIntLe(u32);
- *is_64 = (first_32_bits == 0xffffffff);
- if (*is_64) {
- return in_stream.readIntLe(u64);
- } else {
- if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
- return u64(first_32_bits);
- }
-}
-
-fn readULeb128(in_stream: &io.InStream) -> %u64 {
- var result: u64 = 0;
- var shift: usize = 0;
-
- while (true) {
- const byte = %return in_stream.readByte();
-
- var operand: u64 = undefined;
-
- if (@shlWithOverflow(u64, byte & 0b01111111, u6(shift), &operand))
- return error.InvalidDebugInfo;
-
- result |= operand;
-
- if ((byte & 0b10000000) == 0)
- return result;
-
- shift += 7;
- }
-}
-
-fn readILeb128(in_stream: &io.InStream) -> %i64 {
- var result: i64 = 0;
- var shift: usize = 0;
-
- while (true) {
- const byte = %return in_stream.readByte();
-
- var operand: i64 = undefined;
-
- if (@shlWithOverflow(i64, byte & 0b01111111, u6(shift), &operand))
- return error.InvalidDebugInfo;
-
- result |= operand;
- shift += 7;
-
- if ((byte & 0b10000000) == 0) {
- if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0)
- result |= -(i64(1) << u6(shift));
- return result;
- }
- }
-}
-
-pub const global_allocator = &global_fixed_allocator.allocator;
-var global_fixed_allocator = mem.FixedBufferAllocator.init(global_allocator_mem[0..]);
-var global_allocator_mem: [100 * 1024]u8 = undefined;
-
-/// Allocator that fails after N allocations, useful for making sure out of
-/// memory conditions are handled correctly.
-pub const FailingAllocator = struct {
- allocator: mem.Allocator,
- index: usize,
- fail_index: usize,
- internal_allocator: &mem.Allocator,
- allocated_bytes: usize,
-
- pub fn init(allocator: &mem.Allocator, fail_index: usize) -> FailingAllocator {
- return FailingAllocator {
- .internal_allocator = allocator,
- .fail_index = fail_index,
- .index = 0,
- .allocated_bytes = 0,
- .allocator = mem.Allocator {
- .allocFn = alloc,
- .reallocFn = realloc,
- .freeFn = free,
- },
- };
- }
-
- fn alloc(allocator: &mem.Allocator, n: usize, alignment: u29) -> %[]u8 {
- const self = @fieldParentPtr(FailingAllocator, "allocator", allocator);
- if (self.index == self.fail_index) {
- return error.OutOfMemory;
- }
- self.index += 1;
- const result = %return self.internal_allocator.allocFn(self.internal_allocator, n, alignment);
- self.allocated_bytes += result.len;
- return result;
- }
-
- fn realloc(allocator: &mem.Allocator, old_mem: []u8, new_size: usize, alignment: u29) -> %[]u8 {
- const self = @fieldParentPtr(FailingAllocator, "allocator", allocator);
- if (new_size <= old_mem.len) {
- self.allocated_bytes -= old_mem.len - new_size;
- return self.internal_allocator.reallocFn(self.internal_allocator, old_mem, new_size, alignment);
- }
- if (self.index == self.fail_index) {
- return error.OutOfMemory;
- }
- self.index += 1;
- const result = %return self.internal_allocator.reallocFn(self.internal_allocator, old_mem, new_size, alignment);
- self.allocated_bytes += new_size - old_mem.len;
- return result;
- }
-
- fn free(allocator: &mem.Allocator, bytes: []u8) {
- const self = @fieldParentPtr(FailingAllocator, "allocator", allocator);
- self.allocated_bytes -= bytes.len;
- return self.internal_allocator.freeFn(self.internal_allocator, bytes);
- }
-};
diff --git a/std/debug/failing_allocator.zig b/std/debug/failing_allocator.zig
new file mode 100644
index 0000000000000000000000000000000000000000..9b12ff5cb7e499acb8093490a02b1d979cc687bf
--- /dev/null
+++ b/std/debug/failing_allocator.zig
@@ -0,0 +1,64 @@
+const std = @import("../index.zig");
+const mem = std.mem;
+
+/// Allocator that fails after N allocations, useful for making sure out of
+/// memory conditions are handled correctly.
+pub const FailingAllocator = struct {
+ allocator: mem.Allocator,
+ index: usize,
+ fail_index: usize,
+ internal_allocator: &mem.Allocator,
+ allocated_bytes: usize,
+ freed_bytes: usize,
+ deallocations: usize,
+
+ pub fn init(allocator: &mem.Allocator, fail_index: usize) -> FailingAllocator {
+ return FailingAllocator {
+ .internal_allocator = allocator,
+ .fail_index = fail_index,
+ .index = 0,
+ .allocated_bytes = 0,
+ .freed_bytes = 0,
+ .deallocations = 0,
+ .allocator = mem.Allocator {
+ .allocFn = alloc,
+ .reallocFn = realloc,
+ .freeFn = free,
+ },
+ };
+ }
+
+ fn alloc(allocator: &mem.Allocator, n: usize, alignment: u29) -> %[]u8 {
+ const self = @fieldParentPtr(FailingAllocator, "allocator", allocator);
+ if (self.index == self.fail_index) {
+ return error.OutOfMemory;
+ }
+ const result = %return self.internal_allocator.allocFn(self.internal_allocator, n, alignment);
+ self.allocated_bytes += result.len;
+ self.index += 1;
+ return result;
+ }
+
+ fn realloc(allocator: &mem.Allocator, old_mem: []u8, new_size: usize, alignment: u29) -> %[]u8 {
+ const self = @fieldParentPtr(FailingAllocator, "allocator", allocator);
+ if (new_size <= old_mem.len) {
+ self.freed_bytes += old_mem.len - new_size;
+ return self.internal_allocator.reallocFn(self.internal_allocator, old_mem, new_size, alignment);
+ }
+ if (self.index == self.fail_index) {
+ return error.OutOfMemory;
+ }
+ const result = %return self.internal_allocator.reallocFn(self.internal_allocator, old_mem, new_size, alignment);
+ self.allocated_bytes += new_size - old_mem.len;
+ self.deallocations += 1;
+ self.index += 1;
+ return result;
+ }
+
+ fn free(allocator: &mem.Allocator, bytes: []u8) {
+ const self = @fieldParentPtr(FailingAllocator, "allocator", allocator);
+ self.freed_bytes += bytes.len;
+ self.deallocations += 1;
+ return self.internal_allocator.freeFn(self.internal_allocator, bytes);
+ }
+};
diff --git a/std/debug/index.zig b/std/debug/index.zig
new file mode 100644
index 0000000000000000000000000000000000000000..251b6f6f93ed38618ac13c3080623e62ea134fb4
--- /dev/null
+++ b/std/debug/index.zig
@@ -0,0 +1,996 @@
+const std = @import("../index.zig");
+const math = std.math;
+const mem = std.mem;
+const io = std.io;
+const os = std.os;
+const elf = std.elf;
+const DW = std.dwarf;
+const ArrayList = std.ArrayList;
+const builtin = @import("builtin");
+
+pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator;
+
+error MissingDebugInfo;
+error InvalidDebugInfo;
+error UnsupportedDebugInfo;
+
+
+/// Tries to write to stderr, unbuffered, and ignores any error returned.
+/// Does not append a newline.
+/// TODO atomic/multithread support
+var stderr_file: io.File = undefined;
+var stderr_file_out_stream: io.FileOutStream = undefined;
+var stderr_stream: ?&io.OutStream = null;
+pub fn warn(comptime fmt: []const u8, args: ...) {
+ const stderr = getStderrStream() %% return;
+ stderr.print(fmt, args) %% return;
+}
+fn getStderrStream() -> %&io.OutStream {
+ if (stderr_stream) |st| {
+ return st;
+ } else {
+ stderr_file = %return io.getStdErr();
+ stderr_file_out_stream = io.FileOutStream.init(&stderr_file);
+ const st = &stderr_file_out_stream.stream;
+ stderr_stream = st;
+ return st;
+ }
+}
+
+/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.
+pub fn dumpStackTrace() {
+ const stderr = getStderrStream() %% return;
+ writeStackTrace(stderr, global_allocator, stderr_file.isTty(), 1) %% return;
+}
+
+/// This function invokes undefined behavior when `ok` is `false`.
+/// In Debug and ReleaseSafe modes, calls to this function are always
+/// generated, and the `unreachable` statement triggers a panic.
+/// In ReleaseFast and ReleaseSmall modes, calls to this function can be
+/// optimized away.
+pub fn assert(ok: bool) {
+ if (!ok) {
+ // In ReleaseFast test mode, we still want assert(false) to crash, so
+ // we insert an explicit call to @panic instead of unreachable.
+ // TODO we should use `assertOrPanic` in tests and remove this logic.
+ if (builtin.is_test) {
+ @panic("assertion failure");
+ } else {
+ unreachable; // assertion failure
+ }
+ }
+}
+
+/// Call this function when you want to panic if the condition is not true.
+/// If `ok` is `false`, this function will panic in every release mode.
+pub fn assertOrPanic(ok: bool) {
+ if (!ok) {
+ @panic("assertion failure");
+ }
+}
+
+var panicking = false;
+/// This is the default panic implementation.
+pub fn panic(comptime format: []const u8, args: ...) -> noreturn {
+ // TODO an intrinsic that labels this as unlikely to be reached
+
+ // TODO
+ // if (@atomicRmw(AtomicOp.XChg, &panicking, true, AtomicOrder.SeqCst)) { }
+ if (panicking) {
+ // Panicked during a panic.
+ // TODO detect if a different thread caused the panic, because in that case
+ // we would want to return here instead of calling abort, so that the thread
+ // which first called panic can finish printing a stack trace.
+ os.abort();
+ } else {
+ panicking = true;
+ }
+
+ const stderr = getStderrStream() %% os.abort();
+ stderr.print(format ++ "\n", args) %% os.abort();
+ writeStackTrace(stderr, global_allocator, stderr_file.isTty(), 1) %% os.abort();
+
+ os.abort();
+}
+
+const GREEN = "\x1b[32;1m";
+const WHITE = "\x1b[37;1m";
+const DIM = "\x1b[2m";
+const RESET = "\x1b[0m";
+
+error PathNotFound;
+error InvalidDebugInfo;
+
+pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty_color: bool,
+ ignore_frame_count: usize) -> %void
+{
+ switch (builtin.object_format) {
+ builtin.ObjectFormat.elf => {
+ var stack_trace = ElfStackTrace {
+ .self_exe_file = undefined,
+ .elf = undefined,
+ .debug_info = undefined,
+ .debug_abbrev = undefined,
+ .debug_str = undefined,
+ .debug_line = undefined,
+ .debug_ranges = null,
+ .abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator),
+ .compile_unit_list = ArrayList(CompileUnit).init(allocator),
+ };
+ const st = &stack_trace;
+ st.self_exe_file = %return os.openSelfExe();
+ defer st.self_exe_file.close();
+
+ %return st.elf.openFile(allocator, &st.self_exe_file);
+ defer st.elf.close();
+
+ st.debug_info = (%return st.elf.findSection(".debug_info")) ?? return error.MissingDebugInfo;
+ st.debug_abbrev = (%return st.elf.findSection(".debug_abbrev")) ?? return error.MissingDebugInfo;
+ st.debug_str = (%return st.elf.findSection(".debug_str")) ?? return error.MissingDebugInfo;
+ st.debug_line = (%return st.elf.findSection(".debug_line")) ?? return error.MissingDebugInfo;
+ st.debug_ranges = (%return st.elf.findSection(".debug_ranges"));
+ %return scanAllCompileUnits(st);
+
+ var ignored_count: usize = 0;
+
+ var fp = @ptrToInt(@frameAddress());
+ while (fp != 0) : (fp = *@intToPtr(&const usize, fp)) {
+ if (ignored_count < ignore_frame_count) {
+ ignored_count += 1;
+ continue;
+ }
+
+ const return_address = *@intToPtr(&const usize, fp + @sizeOf(usize));
+
+ // TODO we really should be able to convert @sizeOf(usize) * 2 to a string literal
+ // at compile time. I'll call it issue #313
+ const ptr_hex = if (@sizeOf(usize) == 4) "0x{x8}" else "0x{x16}";
+
+ const compile_unit = findCompileUnit(st, return_address) %% {
+ %return out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n",
+ return_address);
+ continue;
+ };
+ const compile_unit_name = %return compile_unit.die.getAttrString(st, DW.AT_name);
+ if (getLineNumberInfo(st, compile_unit, usize(return_address) - 1)) |line_info| {
+ defer line_info.deinit();
+ %return out_stream.print(WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++
+ DIM ++ ptr_hex ++ " in ??? ({})" ++ RESET ++ "\n",
+ line_info.file_name, line_info.line, line_info.column,
+ return_address, compile_unit_name);
+ if (printLineFromFile(st.allocator(), out_stream, line_info)) {
+ if (line_info.column == 0) {
+ %return out_stream.write("\n");
+ } else {
+ {var col_i: usize = 1; while (col_i < line_info.column) : (col_i += 1) {
+ %return out_stream.writeByte(' ');
+ }}
+ %return out_stream.write(GREEN ++ "^" ++ RESET ++ "\n");
+ }
+ } else |err| switch (err) {
+ error.EndOfFile, error.PathNotFound => {},
+ else => return err,
+ }
+ } else |err| switch (err) {
+ error.MissingDebugInfo, error.InvalidDebugInfo => {
+ %return out_stream.print(ptr_hex ++ " in ??? ({})\n",
+ return_address, compile_unit_name);
+ },
+ else => return err,
+ }
+ }
+ },
+ builtin.ObjectFormat.coff => {
+ %return out_stream.write("(stack trace unavailable for COFF object format)\n");
+ },
+ builtin.ObjectFormat.macho => {
+ %return out_stream.write("(stack trace unavailable for Mach-O object format)\n");
+ },
+ builtin.ObjectFormat.wasm => {
+ %return out_stream.write("(stack trace unavailable for WASM object format)\n");
+ },
+ builtin.ObjectFormat.unknown => {
+ %return out_stream.write("(stack trace unavailable for unknown object format)\n");
+ },
+ }
+}
+
+fn printLineFromFile(allocator: &mem.Allocator, out_stream: &io.OutStream, line_info: &const LineInfo) -> %void {
+ var f = %return io.File.openRead(line_info.file_name, allocator);
+ defer f.close();
+ // TODO fstat and make sure that the file has the correct size
+
+ var buf: [os.page_size]u8 = undefined;
+ var line: usize = 1;
+ var column: usize = 1;
+ var abs_index: usize = 0;
+ while (true) {
+ const amt_read = %return f.read(buf[0..]);
+ const slice = buf[0..amt_read];
+
+ for (slice) |byte| {
+ if (line == line_info.line) {
+ %return out_stream.writeByte(byte);
+ if (byte == '\n') {
+ return;
+ }
+ }
+ if (byte == '\n') {
+ line += 1;
+ column = 1;
+ } else {
+ column += 1;
+ }
+ }
+
+ if (amt_read < buf.len)
+ return error.EndOfFile;
+ }
+}
+
+const ElfStackTrace = struct {
+ self_exe_file: io.File,
+ elf: elf.Elf,
+ debug_info: &elf.SectionHeader,
+ debug_abbrev: &elf.SectionHeader,
+ debug_str: &elf.SectionHeader,
+ debug_line: &elf.SectionHeader,
+ debug_ranges: ?&elf.SectionHeader,
+ abbrev_table_list: ArrayList(AbbrevTableHeader),
+ compile_unit_list: ArrayList(CompileUnit),
+
+ pub fn allocator(self: &const ElfStackTrace) -> &mem.Allocator {
+ return self.abbrev_table_list.allocator;
+ }
+
+ pub fn readString(self: &ElfStackTrace) -> %[]u8 {
+ var in_file_stream = io.FileInStream.init(&self.self_exe_file);
+ const in_stream = &in_file_stream.stream;
+ return readStringRaw(self.allocator(), in_stream);
+ }
+};
+
+const PcRange = struct {
+ start: u64,
+ end: u64,
+};
+
+const CompileUnit = struct {
+ version: u16,
+ is_64: bool,
+ die: &Die,
+ index: usize,
+ pc_range: ?PcRange,
+};
+
+const AbbrevTable = ArrayList(AbbrevTableEntry);
+
+const AbbrevTableHeader = struct {
+ // offset from .debug_abbrev
+ offset: u64,
+ table: AbbrevTable,
+};
+
+const AbbrevTableEntry = struct {
+ has_children: bool,
+ abbrev_code: u64,
+ tag_id: u64,
+ attrs: ArrayList(AbbrevAttr),
+};
+
+const AbbrevAttr = struct {
+ attr_id: u64,
+ form_id: u64,
+};
+
+const FormValue = union(enum) {
+ Address: u64,
+ Block: []u8,
+ Const: Constant,
+ ExprLoc: []u8,
+ Flag: bool,
+ SecOffset: u64,
+ Ref: []u8,
+ RefAddr: u64,
+ RefSig8: u64,
+ String: []u8,
+ StrPtr: u64,
+};
+
+const Constant = struct {
+ payload: []u8,
+ signed: bool,
+
+ fn asUnsignedLe(self: &const Constant) -> %u64 {
+ if (self.payload.len > @sizeOf(u64))
+ return error.InvalidDebugInfo;
+ if (self.signed)
+ return error.InvalidDebugInfo;
+ return mem.readInt(self.payload, u64, builtin.Endian.Little);
+ }
+};
+
+const Die = struct {
+ tag_id: u64,
+ has_children: bool,
+ attrs: ArrayList(Attr),
+
+ const Attr = struct {
+ id: u64,
+ value: FormValue,
+ };
+
+ fn getAttr(self: &const Die, id: u64) -> ?&const FormValue {
+ for (self.attrs.toSliceConst()) |*attr| {
+ if (attr.id == id)
+ return &attr.value;
+ }
+ return null;
+ }
+
+ fn getAttrAddr(self: &const Die, id: u64) -> %u64 {
+ const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
+ return switch (*form_value) {
+ FormValue.Address => |value| value,
+ else => error.InvalidDebugInfo,
+ };
+ }
+
+ fn getAttrSecOffset(self: &const Die, id: u64) -> %u64 {
+ const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
+ return switch (*form_value) {
+ FormValue.Const => |value| value.asUnsignedLe(),
+ FormValue.SecOffset => |value| value,
+ else => error.InvalidDebugInfo,
+ };
+ }
+
+ fn getAttrUnsignedLe(self: &const Die, id: u64) -> %u64 {
+ const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
+ return switch (*form_value) {
+ FormValue.Const => |value| value.asUnsignedLe(),
+ else => error.InvalidDebugInfo,
+ };
+ }
+
+ fn getAttrString(self: &const Die, st: &ElfStackTrace, id: u64) -> %[]u8 {
+ const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
+ return switch (*form_value) {
+ FormValue.String => |value| value,
+ FormValue.StrPtr => |offset| getString(st, offset),
+ else => error.InvalidDebugInfo,
+ };
+ }
+};
+
+const FileEntry = struct {
+ file_name: []const u8,
+ dir_index: usize,
+ mtime: usize,
+ len_bytes: usize,
+};
+
+const LineInfo = struct {
+ line: usize,
+ column: usize,
+ file_name: []u8,
+ allocator: &mem.Allocator,
+
+ fn deinit(self: &const LineInfo) {
+ self.allocator.free(self.file_name);
+ }
+};
+
+const LineNumberProgram = struct {
+ address: usize,
+ file: usize,
+ line: isize,
+ column: usize,
+ is_stmt: bool,
+ basic_block: bool,
+ end_sequence: bool,
+
+ target_address: usize,
+ include_dirs: []const []const u8,
+ file_entries: &ArrayList(FileEntry),
+
+ prev_address: usize,
+ prev_file: usize,
+ prev_line: isize,
+ prev_column: usize,
+ prev_is_stmt: bool,
+ prev_basic_block: bool,
+ prev_end_sequence: bool,
+
+ pub fn init(is_stmt: bool, include_dirs: []const []const u8,
+ file_entries: &ArrayList(FileEntry), target_address: usize) -> LineNumberProgram
+ {
+ return LineNumberProgram {
+ .address = 0,
+ .file = 1,
+ .line = 1,
+ .column = 0,
+ .is_stmt = is_stmt,
+ .basic_block = false,
+ .end_sequence = false,
+ .include_dirs = include_dirs,
+ .file_entries = file_entries,
+ .target_address = target_address,
+ .prev_address = 0,
+ .prev_file = undefined,
+ .prev_line = undefined,
+ .prev_column = undefined,
+ .prev_is_stmt = undefined,
+ .prev_basic_block = undefined,
+ .prev_end_sequence = undefined,
+ };
+ }
+
+ pub fn checkLineMatch(self: &LineNumberProgram) -> %?LineInfo {
+ if (self.target_address >= self.prev_address and self.target_address < self.address) {
+ const file_entry = if (self.prev_file == 0) {
+ return error.MissingDebugInfo;
+ } else if (self.prev_file - 1 >= self.file_entries.len) {
+ return error.InvalidDebugInfo;
+ } else &self.file_entries.items[self.prev_file - 1];
+
+ const dir_name = if (file_entry.dir_index >= self.include_dirs.len) {
+ return error.InvalidDebugInfo;
+ } else self.include_dirs[file_entry.dir_index];
+ const file_name = %return os.path.join(self.file_entries.allocator, dir_name, file_entry.file_name);
+ %defer self.file_entries.allocator.free(file_name);
+ return LineInfo {
+ .line = if (self.prev_line >= 0) usize(self.prev_line) else 0,
+ .column = self.prev_column,
+ .file_name = file_name,
+ .allocator = self.file_entries.allocator,
+ };
+ }
+
+ self.prev_address = self.address;
+ self.prev_file = self.file;
+ self.prev_line = self.line;
+ self.prev_column = self.column;
+ self.prev_is_stmt = self.is_stmt;
+ self.prev_basic_block = self.basic_block;
+ self.prev_end_sequence = self.end_sequence;
+ return null;
+ }
+};
+
+fn readStringRaw(allocator: &mem.Allocator, in_stream: &io.InStream) -> %[]u8 {
+ var buf = ArrayList(u8).init(allocator);
+ while (true) {
+ const byte = %return in_stream.readByte();
+ if (byte == 0)
+ break;
+ %return buf.append(byte);
+ }
+ return buf.toSlice();
+}
+
+fn getString(st: &ElfStackTrace, offset: u64) -> %[]u8 {
+ const pos = st.debug_str.offset + offset;
+ %return st.self_exe_file.seekTo(pos);
+ return st.readString();
+}
+
+fn readAllocBytes(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %[]u8 {
+ const buf = %return global_allocator.alloc(u8, size);
+ %defer global_allocator.free(buf);
+ if ((%return in_stream.read(buf)) < size) return error.EndOfFile;
+ return buf;
+}
+
+fn parseFormValueBlockLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
+ const buf = %return readAllocBytes(allocator, in_stream, size);
+ return FormValue { .Block = buf };
+}
+
+fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
+ const block_len = %return in_stream.readVarInt(builtin.Endian.Little, usize, size);
+ return parseFormValueBlockLen(allocator, in_stream, block_len);
+}
+
+fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: &io.InStream, signed: bool, size: usize) -> %FormValue {
+ return FormValue { .Const = Constant {
+ .signed = signed,
+ .payload = %return readAllocBytes(allocator, in_stream, size),
+ }};
+}
+
+fn parseFormValueDwarfOffsetSize(in_stream: &io.InStream, is_64: bool) -> %u64 {
+ return if (is_64) %return in_stream.readIntLe(u64)
+ else u64(%return in_stream.readIntLe(u32)) ;
+}
+
+fn parseFormValueTargetAddrSize(in_stream: &io.InStream) -> %u64 {
+ return if (@sizeOf(usize) == 4) u64(%return in_stream.readIntLe(u32))
+ else if (@sizeOf(usize) == 8) %return in_stream.readIntLe(u64)
+ else unreachable;
+}
+
+fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
+ const buf = %return readAllocBytes(allocator, in_stream, size);
+ return FormValue { .Ref = buf };
+}
+
+fn parseFormValueRef(allocator: &mem.Allocator, in_stream: &io.InStream, comptime T: type) -> %FormValue {
+ const block_len = %return in_stream.readIntLe(T);
+ return parseFormValueRefLen(allocator, in_stream, block_len);
+}
+
+fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u64, is_64: bool) -> %FormValue {
+ return switch (form_id) {
+ DW.FORM_addr => FormValue { .Address = %return parseFormValueTargetAddrSize(in_stream) },
+ DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
+ DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),
+ DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),
+ DW.FORM_block => x: {
+ const block_len = %return readULeb128(in_stream);
+ return parseFormValueBlockLen(allocator, in_stream, block_len);
+ },
+ DW.FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1),
+ DW.FORM_data2 => parseFormValueConstant(allocator, in_stream, false, 2),
+ DW.FORM_data4 => parseFormValueConstant(allocator, in_stream, false, 4),
+ DW.FORM_data8 => parseFormValueConstant(allocator, in_stream, false, 8),
+ DW.FORM_udata, DW.FORM_sdata => {
+ const block_len = %return readULeb128(in_stream);
+ const signed = form_id == DW.FORM_sdata;
+ return parseFormValueConstant(allocator, in_stream, signed, block_len);
+ },
+ DW.FORM_exprloc => {
+ const size = %return readULeb128(in_stream);
+ const buf = %return readAllocBytes(allocator, in_stream, size);
+ return FormValue { .ExprLoc = buf };
+ },
+ DW.FORM_flag => FormValue { .Flag = (%return in_stream.readByte()) != 0 },
+ DW.FORM_flag_present => FormValue { .Flag = true },
+ DW.FORM_sec_offset => FormValue { .SecOffset = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
+
+ DW.FORM_ref1 => parseFormValueRef(allocator, in_stream, u8),
+ DW.FORM_ref2 => parseFormValueRef(allocator, in_stream, u16),
+ DW.FORM_ref4 => parseFormValueRef(allocator, in_stream, u32),
+ DW.FORM_ref8 => parseFormValueRef(allocator, in_stream, u64),
+ DW.FORM_ref_udata => {
+ const ref_len = %return readULeb128(in_stream);
+ return parseFormValueRefLen(allocator, in_stream, ref_len);
+ },
+
+ DW.FORM_ref_addr => FormValue { .RefAddr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
+ DW.FORM_ref_sig8 => FormValue { .RefSig8 = %return in_stream.readIntLe(u64) },
+
+ DW.FORM_string => FormValue { .String = %return readStringRaw(allocator, in_stream) },
+ DW.FORM_strp => FormValue { .StrPtr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
+ DW.FORM_indirect => {
+ const child_form_id = %return readULeb128(in_stream);
+ return parseFormValue(allocator, in_stream, child_form_id, is_64);
+ },
+ else => error.InvalidDebugInfo,
+ };
+}
+
+fn parseAbbrevTable(st: &ElfStackTrace) -> %AbbrevTable {
+ const in_file = &st.self_exe_file;
+ var in_file_stream = io.FileInStream.init(in_file);
+ const in_stream = &in_file_stream.stream;
+ var result = AbbrevTable.init(st.allocator());
+ while (true) {
+ const abbrev_code = %return readULeb128(in_stream);
+ if (abbrev_code == 0)
+ return result;
+ %return result.append(AbbrevTableEntry {
+ .abbrev_code = abbrev_code,
+ .tag_id = %return readULeb128(in_stream),
+ .has_children = (%return in_stream.readByte()) == DW.CHILDREN_yes,
+ .attrs = ArrayList(AbbrevAttr).init(st.allocator()),
+ });
+ const attrs = &result.items[result.len - 1].attrs;
+
+ while (true) {
+ const attr_id = %return readULeb128(in_stream);
+ const form_id = %return readULeb128(in_stream);
+ if (attr_id == 0 and form_id == 0)
+ break;
+ %return attrs.append(AbbrevAttr {
+ .attr_id = attr_id,
+ .form_id = form_id,
+ });
+ }
+ }
+}
+
+/// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
+/// seeks in the stream and parses it.
+fn getAbbrevTable(st: &ElfStackTrace, abbrev_offset: u64) -> %&const AbbrevTable {
+ for (st.abbrev_table_list.toSlice()) |*header| {
+ if (header.offset == abbrev_offset) {
+ return &header.table;
+ }
+ }
+ %return st.self_exe_file.seekTo(st.debug_abbrev.offset + abbrev_offset);
+ %return st.abbrev_table_list.append(AbbrevTableHeader {
+ .offset = abbrev_offset,
+ .table = %return parseAbbrevTable(st),
+ });
+ return &st.abbrev_table_list.items[st.abbrev_table_list.len - 1].table;
+}
+
+fn getAbbrevTableEntry(abbrev_table: &const AbbrevTable, abbrev_code: u64) -> ?&const AbbrevTableEntry {
+ for (abbrev_table.toSliceConst()) |*table_entry| {
+ if (table_entry.abbrev_code == abbrev_code)
+ return table_entry;
+ }
+ return null;
+}
+
+fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) -> %Die {
+ const in_file = &st.self_exe_file;
+ var in_file_stream = io.FileInStream.init(in_file);
+ const in_stream = &in_file_stream.stream;
+ const abbrev_code = %return readULeb128(in_stream);
+ const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) ?? return error.InvalidDebugInfo;
+
+ var result = Die {
+ .tag_id = table_entry.tag_id,
+ .has_children = table_entry.has_children,
+ .attrs = ArrayList(Die.Attr).init(st.allocator()),
+ };
+ %return result.attrs.resize(table_entry.attrs.len);
+ for (table_entry.attrs.toSliceConst()) |attr, i| {
+ result.attrs.items[i] = Die.Attr {
+ .id = attr.attr_id,
+ .value = %return parseFormValue(st.allocator(), in_stream, attr.form_id, is_64),
+ };
+ }
+ return result;
+}
+
+fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, target_address: usize) -> %LineInfo {
+ const compile_unit_cwd = %return compile_unit.die.getAttrString(st, DW.AT_comp_dir);
+
+ const in_file = &st.self_exe_file;
+ const debug_line_end = st.debug_line.offset + st.debug_line.size;
+ var this_offset = st.debug_line.offset;
+ var this_index: usize = 0;
+
+ var in_file_stream = io.FileInStream.init(in_file);
+ const in_stream = &in_file_stream.stream;
+
+ while (this_offset < debug_line_end) : (this_index += 1) {
+ %return in_file.seekTo(this_offset);
+
+ var is_64: bool = undefined;
+ const unit_length = %return readInitialLength(in_stream, &is_64);
+ if (unit_length == 0)
+ return error.MissingDebugInfo;
+ const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
+
+ if (compile_unit.index != this_index) {
+ this_offset += next_offset;
+ continue;
+ }
+
+ const version = %return in_stream.readInt(st.elf.endian, u16);
+ if (version != 2) return error.InvalidDebugInfo;
+
+ const prologue_length = %return in_stream.readInt(st.elf.endian, u32);
+ const prog_start_offset = (%return in_file.getPos()) + prologue_length;
+
+ const minimum_instruction_length = %return in_stream.readByte();
+ if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
+
+ const default_is_stmt = (%return in_stream.readByte()) != 0;
+ const line_base = %return in_stream.readByteSigned();
+
+ const line_range = %return in_stream.readByte();
+ if (line_range == 0)
+ return error.InvalidDebugInfo;
+
+ const opcode_base = %return in_stream.readByte();
+
+ const standard_opcode_lengths = %return st.allocator().alloc(u8, opcode_base - 1);
+
+ {var i: usize = 0; while (i < opcode_base - 1) : (i += 1) {
+ standard_opcode_lengths[i] = %return in_stream.readByte();
+ }}
+
+ var include_directories = ArrayList([]u8).init(st.allocator());
+ %return include_directories.append(compile_unit_cwd);
+ while (true) {
+ const dir = %return st.readString();
+ if (dir.len == 0)
+ break;
+ %return include_directories.append(dir);
+ }
+
+ var file_entries = ArrayList(FileEntry).init(st.allocator());
+ var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(),
+ &file_entries, target_address);
+
+ while (true) {
+ const file_name = %return st.readString();
+ if (file_name.len == 0)
+ break;
+ const dir_index = %return readULeb128(in_stream);
+ const mtime = %return readULeb128(in_stream);
+ const len_bytes = %return readULeb128(in_stream);
+ %return file_entries.append(FileEntry {
+ .file_name = file_name,
+ .dir_index = dir_index,
+ .mtime = mtime,
+ .len_bytes = len_bytes,
+ });
+ }
+
+ %return in_file.seekTo(prog_start_offset);
+
+ while (true) {
+ const opcode = %return in_stream.readByte();
+
+ var sub_op: u8 = undefined; // TODO move this to the correct scope and fix the compiler crash
+ if (opcode == DW.LNS_extended_op) {
+ const op_size = %return readULeb128(in_stream);
+ if (op_size < 1)
+ return error.InvalidDebugInfo;
+ sub_op = %return in_stream.readByte();
+ switch (sub_op) {
+ DW.LNE_end_sequence => {
+ prog.end_sequence = true;
+ if (%return prog.checkLineMatch()) |info| return info;
+ return error.MissingDebugInfo;
+ },
+ DW.LNE_set_address => {
+ const addr = %return in_stream.readInt(st.elf.endian, usize);
+ prog.address = addr;
+ },
+ DW.LNE_define_file => {
+ const file_name = %return st.readString();
+ const dir_index = %return readULeb128(in_stream);
+ const mtime = %return readULeb128(in_stream);
+ const len_bytes = %return readULeb128(in_stream);
+ %return file_entries.append(FileEntry {
+ .file_name = file_name,
+ .dir_index = dir_index,
+ .mtime = mtime,
+ .len_bytes = len_bytes,
+ });
+ },
+ else => {
+ const fwd_amt = math.cast(isize, op_size - 1) %% return error.InvalidDebugInfo;
+ %return in_file.seekForward(fwd_amt);
+ },
+ }
+ } else if (opcode >= opcode_base) {
+ // special opcodes
+ const adjusted_opcode = opcode - opcode_base;
+ const inc_addr = minimum_instruction_length * (adjusted_opcode / line_range);
+ const inc_line = i32(line_base) + i32(adjusted_opcode % line_range);
+ prog.line += inc_line;
+ prog.address += inc_addr;
+ if (%return prog.checkLineMatch()) |info| return info;
+ prog.basic_block = false;
+ } else {
+ switch (opcode) {
+ DW.LNS_copy => {
+ if (%return prog.checkLineMatch()) |info| return info;
+ prog.basic_block = false;
+ },
+ DW.LNS_advance_pc => {
+ const arg = %return readULeb128(in_stream);
+ prog.address += arg * minimum_instruction_length;
+ },
+ DW.LNS_advance_line => {
+ const arg = %return readILeb128(in_stream);
+ prog.line += arg;
+ },
+ DW.LNS_set_file => {
+ const arg = %return readULeb128(in_stream);
+ prog.file = arg;
+ },
+ DW.LNS_set_column => {
+ const arg = %return readULeb128(in_stream);
+ prog.column = arg;
+ },
+ DW.LNS_negate_stmt => {
+ prog.is_stmt = !prog.is_stmt;
+ },
+ DW.LNS_set_basic_block => {
+ prog.basic_block = true;
+ },
+ DW.LNS_const_add_pc => {
+ const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range);
+ prog.address += inc_addr;
+ },
+ DW.LNS_fixed_advance_pc => {
+ const arg = %return in_stream.readInt(st.elf.endian, u16);
+ prog.address += arg;
+ },
+ DW.LNS_set_prologue_end => {
+ },
+ else => {
+ if (opcode - 1 >= standard_opcode_lengths.len)
+ return error.InvalidDebugInfo;
+ const len_bytes = standard_opcode_lengths[opcode - 1];
+ %return in_file.seekForward(len_bytes);
+ },
+ }
+ }
+ }
+
+ this_offset += next_offset;
+ }
+
+ return error.MissingDebugInfo;
+}
+
+fn scanAllCompileUnits(st: &ElfStackTrace) -> %void {
+ const debug_info_end = st.debug_info.offset + st.debug_info.size;
+ var this_unit_offset = st.debug_info.offset;
+ var cu_index: usize = 0;
+
+ var in_file_stream = io.FileInStream.init(&st.self_exe_file);
+ const in_stream = &in_file_stream.stream;
+
+ while (this_unit_offset < debug_info_end) {
+ %return st.self_exe_file.seekTo(this_unit_offset);
+
+ var is_64: bool = undefined;
+ const unit_length = %return readInitialLength(in_stream, &is_64);
+ if (unit_length == 0)
+ return;
+ const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
+
+ const version = %return in_stream.readInt(st.elf.endian, u16);
+ if (version < 2 or version > 5) return error.InvalidDebugInfo;
+
+ const debug_abbrev_offset =
+ if (is_64) %return in_stream.readInt(st.elf.endian, u64)
+ else %return in_stream.readInt(st.elf.endian, u32);
+
+ const address_size = %return in_stream.readByte();
+ if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
+
+ const compile_unit_pos = %return st.self_exe_file.getPos();
+ const abbrev_table = %return getAbbrevTable(st, debug_abbrev_offset);
+
+ %return st.self_exe_file.seekTo(compile_unit_pos);
+
+ const compile_unit_die = %return st.allocator().create(Die);
+ *compile_unit_die = %return parseDie(st, abbrev_table, is_64);
+
+ if (compile_unit_die.tag_id != DW.TAG_compile_unit)
+ return error.InvalidDebugInfo;
+
+ const pc_range = x: {
+ if (compile_unit_die.getAttrAddr(DW.AT_low_pc)) |low_pc| {
+ if (compile_unit_die.getAttr(DW.AT_high_pc)) |high_pc_value| {
+ const pc_end = switch (*high_pc_value) {
+ FormValue.Address => |value| value,
+ FormValue.Const => |value| b: {
+ const offset = %return value.asUnsignedLe();
+ break :b (low_pc + offset);
+ },
+ else => return error.InvalidDebugInfo,
+ };
+ break :x PcRange {
+ .start = low_pc,
+ .end = pc_end,
+ };
+ } else {
+ break :x null;
+ }
+ } else |err| {
+ if (err != error.MissingDebugInfo)
+ return err;
+ break :x null;
+ }
+ };
+
+ %return st.compile_unit_list.append(CompileUnit {
+ .version = version,
+ .is_64 = is_64,
+ .pc_range = pc_range,
+ .die = compile_unit_die,
+ .index = cu_index,
+ });
+
+ this_unit_offset += next_offset;
+ cu_index += 1;
+ }
+}
+
+fn findCompileUnit(st: &ElfStackTrace, target_address: u64) -> %&const CompileUnit {
+ var in_file_stream = io.FileInStream.init(&st.self_exe_file);
+ const in_stream = &in_file_stream.stream;
+ for (st.compile_unit_list.toSlice()) |*compile_unit| {
+ if (compile_unit.pc_range) |range| {
+ if (target_address >= range.start and target_address < range.end)
+ return compile_unit;
+ }
+ if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| {
+ var base_address: usize = 0;
+ if (st.debug_ranges) |debug_ranges| {
+ %return st.self_exe_file.seekTo(debug_ranges.offset + ranges_offset);
+ while (true) {
+ const begin_addr = %return in_stream.readIntLe(usize);
+ const end_addr = %return in_stream.readIntLe(usize);
+ if (begin_addr == 0 and end_addr == 0) {
+ break;
+ }
+ if (begin_addr == @maxValue(usize)) {
+ base_address = begin_addr;
+ continue;
+ }
+ if (target_address >= begin_addr and target_address < end_addr) {
+ return compile_unit;
+ }
+ }
+ }
+ } else |err| {
+ if (err != error.MissingDebugInfo)
+ return err;
+ continue;
+ }
+ }
+ return error.MissingDebugInfo;
+}
+
+fn readInitialLength(in_stream: &io.InStream, is_64: &bool) -> %u64 {
+ const first_32_bits = %return in_stream.readIntLe(u32);
+ *is_64 = (first_32_bits == 0xffffffff);
+ if (*is_64) {
+ return in_stream.readIntLe(u64);
+ } else {
+ if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
+ return u64(first_32_bits);
+ }
+}
+
+fn readULeb128(in_stream: &io.InStream) -> %u64 {
+ var result: u64 = 0;
+ var shift: usize = 0;
+
+ while (true) {
+ const byte = %return in_stream.readByte();
+
+ var operand: u64 = undefined;
+
+ if (@shlWithOverflow(u64, byte & 0b01111111, u6(shift), &operand))
+ return error.InvalidDebugInfo;
+
+ result |= operand;
+
+ if ((byte & 0b10000000) == 0)
+ return result;
+
+ shift += 7;
+ }
+}
+
+fn readILeb128(in_stream: &io.InStream) -> %i64 {
+ var result: i64 = 0;
+ var shift: usize = 0;
+
+ while (true) {
+ const byte = %return in_stream.readByte();
+
+ var operand: i64 = undefined;
+
+ if (@shlWithOverflow(i64, byte & 0b01111111, u6(shift), &operand))
+ return error.InvalidDebugInfo;
+
+ result |= operand;
+ shift += 7;
+
+ if ((byte & 0b10000000) == 0) {
+ if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0)
+ result |= -(i64(1) << u6(shift));
+ return result;
+ }
+ }
+}
+
+pub const global_allocator = &global_fixed_allocator.allocator;
+var global_fixed_allocator = mem.FixedBufferAllocator.init(global_allocator_mem[0..]);
+var global_allocator_mem: [100 * 1024]u8 = undefined;
diff --git a/std/fmt/errol/index.zig b/std/fmt/errol/index.zig
index 0a1ea7deef4e1a9d1f3cfb1d638bd3b307065919..ba4447c6315e825649f67a2a522ca728650769f3 100644
--- a/std/fmt/errol/index.zig
+++ b/std/fmt/errol/index.zig
@@ -1,10 +1,11 @@
+const std = @import("../../index.zig");
const enum3 = @import("enum3.zig").enum3;
const enum3_data = @import("enum3.zig").enum3_data;
const lookup_table = @import("lookup.zig").lookup_table;
const HP = @import("lookup.zig").HP;
-const math = @import("../../math/index.zig");
-const mem = @import("../../mem.zig");
-const assert = @import("../../debug.zig").assert;
+const math = std.math;
+const mem = std.mem;
+const assert = std.debug.assert;
pub const FloatDecimal = struct {
digits: []u8,
diff --git a/std/fmt/index.zig b/std/fmt/index.zig
index fef968a1d5e8418014d2e134de391ca36fc8aa72..550fa1ce1f5ba993a9e69e81fde202551fe39348 100644
--- a/std/fmt/index.zig
+++ b/std/fmt/index.zig
@@ -1,7 +1,8 @@
-const math = @import("../math/index.zig");
-const debug = @import("../debug.zig");
+const std = @import("../index.zig");
+const math = std.math;
+const debug = std.debug;
const assert = debug.assert;
-const mem = @import("../mem.zig");
+const mem = std.mem;
const builtin = @import("builtin");
const errol3 = @import("errol/index.zig").errol3;
diff --git a/std/hash_map.zig b/std/hash_map.zig
index 837ee0742395b54e1622de121080a67ed0ae900f..cf83815798eff983b8da6b7da0dd6fc9b7e6f2d3 100644
--- a/std/hash_map.zig
+++ b/std/hash_map.zig
@@ -1,7 +1,8 @@
-const debug = @import("debug.zig");
+const std = @import("index.zig");
+const debug = std.debug;
const assert = debug.assert;
-const math = @import("math/index.zig");
-const mem = @import("mem.zig");
+const math = std.math;
+const mem = std.mem;
const Allocator = mem.Allocator;
const builtin = @import("builtin");
diff --git a/std/heap.zig b/std/heap.zig
index ec447c1aa82092f202bff583f89e11ab8257c60b..6a78692ec636a11b74d8a9c5b912914601092a60 100644
--- a/std/heap.zig
+++ b/std/heap.zig
@@ -1,10 +1,11 @@
-const debug = @import("debug.zig");
+const std = @import("index.zig");
+const debug = std.debug;
const assert = debug.assert;
-const mem = @import("mem.zig");
-const os = @import("os/index.zig");
+const mem = std.mem;
+const os = std.os;
const builtin = @import("builtin");
const Os = builtin.Os;
-const c = @import("c/index.zig");
+const c = std.c;
const Allocator = mem.Allocator;
diff --git a/std/index.zig b/std/index.zig
index 323eee203eeb706838b4052a07970ab064c86936..07da469b5e3d02683dda12fcc310c980ebf26422 100644
--- a/std/index.zig
+++ b/std/index.zig
@@ -11,7 +11,7 @@ pub const base64 = @import("base64.zig");
pub const build = @import("build.zig");
pub const c = @import("c/index.zig");
pub const cstr = @import("cstr.zig");
-pub const debug = @import("debug.zig");
+pub const debug = @import("debug/index.zig");
pub const dwarf = @import("dwarf.zig");
pub const elf = @import("elf.zig");
pub const empty_import = @import("empty.zig");
@@ -39,7 +39,7 @@ test "std" {
_ = @import("build.zig");
_ = @import("c/index.zig");
_ = @import("cstr.zig");
- _ = @import("debug.zig");
+ _ = @import("debug/index.zig");
_ = @import("dwarf.zig");
_ = @import("elf.zig");
_ = @import("empty.zig");
diff --git a/std/linked_list.zig b/std/linked_list.zig
index f4b6d274c97f2af271be94f180d0815efa063b8c..3c516dab7d50f2decde3b442ca061cc93c60edbe 100644
--- a/std/linked_list.zig
+++ b/std/linked_list.zig
@@ -1,6 +1,7 @@
-const debug = @import("debug.zig");
+const std = @import("index.zig");
+const debug = std.debug;
const assert = debug.assert;
-const mem = @import("mem.zig");
+const mem = std.mem;
const Allocator = mem.Allocator;
/// Generic doubly linked list.
diff --git a/std/math/acos.zig b/std/math/acos.zig
index 7690497da5f627183f4b4420cb29b2ed877df501..478d5a846d325242ebd14a6a243c14318b576c99 100644
--- a/std/math/acos.zig
+++ b/std/math/acos.zig
@@ -2,8 +2,9 @@
//
// - acos(x) = nan if x < -1 or x > 1
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
pub fn acos(x: var) -> @typeOf(x) {
const T = @typeOf(x);
diff --git a/std/math/acosh.zig b/std/math/acosh.zig
index 3b2c2c0f31472c0daf383d20f35e235fbaed4ed8..150bcd4543af42997b8b7b6f2096e9dc2a822e81 100644
--- a/std/math/acosh.zig
+++ b/std/math/acosh.zig
@@ -4,8 +4,9 @@
// - acosh(nan) = nan
const builtin = @import("builtin");
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
pub fn acosh(x: var) -> @typeOf(x) {
const T = @typeOf(x);
diff --git a/std/math/asin.zig b/std/math/asin.zig
index c5d24c35e515f372df3edc8091091e9af3082a99..a0209be0c890fa961c7dc8491cf1c0ecec037c4d 100644
--- a/std/math/asin.zig
+++ b/std/math/asin.zig
@@ -3,8 +3,9 @@
// - asin(+-0) = +-0
// - asin(x) = nan if x < -1 or x > 1
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
pub fn asin(x: var) -> @typeOf(x) {
const T = @typeOf(x);
diff --git a/std/math/asinh.zig b/std/math/asinh.zig
index f963dae77bdf7f672d3fcabf80aff315e04aec99..d95565fc6dc4d150dbe3539b0adcdd80f5c8cf63 100644
--- a/std/math/asinh.zig
+++ b/std/math/asinh.zig
@@ -4,8 +4,9 @@
// - asinh(+-inf) = +-inf
// - asinh(nan) = nan
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
pub fn asinh(x: var) -> @typeOf(x) {
const T = @typeOf(x);
diff --git a/std/math/atan.zig b/std/math/atan.zig
index cf244eb7627769464097b1f8e891e65053fdf0e4..fbfade50a08df250efa0e7d61c26a95a4eb3d44f 100644
--- a/std/math/atan.zig
+++ b/std/math/atan.zig
@@ -3,8 +3,9 @@
// - atan(+-0) = +-0
// - atan(+-inf) = +-pi/2
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
pub fn atan(x: var) -> @typeOf(x) {
const T = @typeOf(x);
diff --git a/std/math/atan2.zig b/std/math/atan2.zig
index b3af18cd9e71f26ac660541c82e4e2594fec69a3..11e1b8cd8958cf1d0ae7a6d62a527959b5b15972 100644
--- a/std/math/atan2.zig
+++ b/std/math/atan2.zig
@@ -18,8 +18,9 @@
// atan2(+inf, x) = +pi/2
// atan2(-inf, x) = -pi/2
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
fn atan2(comptime T: type, x: T, y: T) -> T {
return switch (T) {
diff --git a/std/math/atanh.zig b/std/math/atanh.zig
index 13de90279bdb3dddc4d2efdbf57a37566f008ae9..e78750676557233999c259a09d9ee357ad541372 100644
--- a/std/math/atanh.zig
+++ b/std/math/atanh.zig
@@ -4,8 +4,9 @@
// - atanh(x) = nan if |x| > 1 with signal
// - atanh(nan) = nan
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
pub fn atanh(x: var) -> @typeOf(x) {
const T = @typeOf(x);
diff --git a/std/math/cbrt.zig b/std/math/cbrt.zig
index a8df75dff215c037307551e42b1db09de4f4905a..9725716f3bb4c0114b237e842d23a4554a881b65 100644
--- a/std/math/cbrt.zig
+++ b/std/math/cbrt.zig
@@ -4,8 +4,9 @@
// - cbrt(+-inf) = +-inf
// - cbrt(nan) = nan
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
pub fn cbrt(x: var) -> @typeOf(x) {
const T = @typeOf(x);
diff --git a/std/math/ceil.zig b/std/math/ceil.zig
index 8e27132e25d1e61783e051aa2851a18237330df7..141b5c0fc5d855464dd1adbd1cfb9757a0a49da6 100644
--- a/std/math/ceil.zig
+++ b/std/math/ceil.zig
@@ -5,8 +5,9 @@
// - ceil(nan) = nan
const builtin = @import("builtin");
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
pub fn ceil(x: var) -> @typeOf(x) {
const T = @typeOf(x);
diff --git a/std/math/copysign.zig b/std/math/copysign.zig
index 05205e1a0e7e435901eca10138d02f13116ff84e..ebf12313fffbad231ea95a5f55ad9a245bb10dc3 100644
--- a/std/math/copysign.zig
+++ b/std/math/copysign.zig
@@ -1,5 +1,6 @@
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
pub fn copysign(comptime T: type, x: T, y: T) -> T {
return switch (T) {
diff --git a/std/math/cos.zig b/std/math/cos.zig
index 4c3b8e1282c477632028b23a4653ce9874aae64a..a65ea1ace80835ae2d46cd41c7108b47f22b4fb8 100644
--- a/std/math/cos.zig
+++ b/std/math/cos.zig
@@ -4,8 +4,9 @@
// - cos(nan) = nan
const builtin = @import("builtin");
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
pub fn cos(x: var) -> @typeOf(x) {
const T = @typeOf(x);
diff --git a/std/math/cosh.zig b/std/math/cosh.zig
index 6d40d71b8da23e03f1feaae2c49800155dcbe531..05565d6b3ab677bddc2066b3a662bd1ce5764df4 100644
--- a/std/math/cosh.zig
+++ b/std/math/cosh.zig
@@ -5,9 +5,10 @@
// - cosh(nan) = nan
const builtin = @import("builtin");
-const math = @import("index.zig");
+const std = @import("../index.zig");
+const math = std.math;
const expo2 = @import("expo2.zig").expo2;
-const assert = @import("../debug.zig").assert;
+const assert = std.debug.assert;
pub fn cosh(x: var) -> @typeOf(x) {
const T = @typeOf(x);
diff --git a/std/math/exp.zig b/std/math/exp.zig
index 6e591daea3e0430c6f6d4fc05d88ffd347fabbdf..4cce18ffe5d70b141e89cef93556dcd26fb09f27 100644
--- a/std/math/exp.zig
+++ b/std/math/exp.zig
@@ -3,8 +3,9 @@
// - exp(+inf) = +inf
// - exp(nan) = nan
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
pub fn exp(x: var) -> @typeOf(x) {
const T = @typeOf(x);
diff --git a/std/math/exp2.zig b/std/math/exp2.zig
index 6061f323918f5005254d315c43d027620664a071..4ce7de909e580e7ad869d0d9aff16baa317b6bb4 100644
--- a/std/math/exp2.zig
+++ b/std/math/exp2.zig
@@ -3,8 +3,9 @@
// - exp2(+inf) = +inf
// - exp2(nan) = nan
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
pub fn exp2(x: var) -> @typeOf(x) {
const T = @typeOf(x);
diff --git a/std/math/expm1.zig b/std/math/expm1.zig
index fbe18410303f3d17de0ad05374b5492cb7ca72d0..10670c4cfcd0f2d5e3f21efd83ee590bd1c16927 100644
--- a/std/math/expm1.zig
+++ b/std/math/expm1.zig
@@ -4,8 +4,9 @@
// - expm1(-inf) = -1
// - expm1(nan) = nan
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
pub fn expm1(x: var) -> @typeOf(x) {
const T = @typeOf(x);
diff --git a/std/math/fabs.zig b/std/math/fabs.zig
index cf1b8f1f14cc49a4bd417d45b369fa8820c670a2..dc1184dcc8fe8b02b7d1906d1cac4b8a8c00617d 100644
--- a/std/math/fabs.zig
+++ b/std/math/fabs.zig
@@ -3,8 +3,9 @@
// - fabs(+-inf) = +inf
// - fabs(nan) = nan
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
pub fn fabs(x: var) -> @typeOf(x) {
const T = @typeOf(x);
diff --git a/std/math/floor.zig b/std/math/floor.zig
index d7de45e9d01214526fd00cbdaea68bb7fc2a1c20..910dfd19016f45447348c9f903b299cbe94aeb55 100644
--- a/std/math/floor.zig
+++ b/std/math/floor.zig
@@ -5,8 +5,9 @@
// - floor(nan) = nan
const builtin = @import("builtin");
-const assert = @import("../debug.zig").assert;
-const math = @import("index.zig");
+const assert = std.debug.assert;
+const std = @import("../index.zig");
+const math = std.math;
pub fn floor(x: var) -> @typeOf(x) {
const T = @typeOf(x);
diff --git a/std/math/fma.zig b/std/math/fma.zig
index 8e5adc80b24db5d6401b693884a4da9f26a80286..b48cfc83b2d08e0789e251f260871c23664970c2 100644
--- a/std/math/fma.zig
+++ b/std/math/fma.zig
@@ -1,5 +1,6 @@
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
pub fn fma(comptime T: type, x: T, y: T, z: T) -> T {
return switch (T) {
diff --git a/std/math/frexp.zig b/std/math/frexp.zig
index 1a317a2c80cf5e77c2d5083d8613d687f9d39268..a90121e5fe93966584b7590e92dd8a9aaaaf838c 100644
--- a/std/math/frexp.zig
+++ b/std/math/frexp.zig
@@ -4,8 +4,9 @@
// - frexp(+-inf) = +-inf, 0
// - frexp(nan) = nan, undefined
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
fn frexp_result(comptime T: type) -> type {
return struct {
diff --git a/std/math/hypot.zig b/std/math/hypot.zig
index 9b09ed53a41159c43322bac16d063d0ad87b2a44..6c0039b176625f36861e695ede384c3786795655 100644
--- a/std/math/hypot.zig
+++ b/std/math/hypot.zig
@@ -5,8 +5,9 @@
// - hypot(nan, y) = nan
// - hypot(x, nan) = nan
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
pub fn hypot(comptime T: type, x: T, y: T) -> T {
return switch (T) {
diff --git a/std/math/ilogb.zig b/std/math/ilogb.zig
index 41a1e2d83f522a111861cd036a10fcd758a19a5e..db8e24d6c84910fce10c783e4af84ae4ae9d345e 100644
--- a/std/math/ilogb.zig
+++ b/std/math/ilogb.zig
@@ -4,8 +4,9 @@
// - ilogb(0) = @maxValue(i32)
// - ilogb(nan) = @maxValue(i32)
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
pub fn ilogb(x: var) -> i32 {
const T = @typeOf(x);
diff --git a/std/math/index.zig b/std/math/index.zig
index 1991864f691cb824ca4fdd7c575b89e6532b6637..d382154059d770a2e65b11820588941a48399d7e 100644
--- a/std/math/index.zig
+++ b/std/math/index.zig
@@ -1,6 +1,7 @@
const builtin = @import("builtin");
+const std = @import("../index.zig");
const TypeId = builtin.TypeId;
-const assert = @import("../debug.zig").assert;
+const assert = std.debug.assert;
pub const e = 2.71828182845904523536028747135266249775724709369995;
pub const pi = 3.14159265358979323846264338327950288419716939937510;
diff --git a/std/math/inf.zig b/std/math/inf.zig
index 546e6f3af8d61ade6160528eddc9715e962acd96..b253124c84dfd8ee56913fc7e84f48c2a93dcdd3 100644
--- a/std/math/inf.zig
+++ b/std/math/inf.zig
@@ -1,5 +1,6 @@
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
pub fn inf(comptime T: type) -> T {
return switch (T) {
diff --git a/std/math/isfinite.zig b/std/math/isfinite.zig
index d44d373cf14d207629e13d92e031f3d4e505b1cb..67fcf3cd18592d81ff4471fd36468cb13d734ee9 100644
--- a/std/math/isfinite.zig
+++ b/std/math/isfinite.zig
@@ -1,5 +1,6 @@
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
pub fn isFinite(x: var) -> bool {
const T = @typeOf(x);
diff --git a/std/math/isinf.zig b/std/math/isinf.zig
index 98c90e72a915ce8ee577b3646a448b1dc6dbbcd8..75529fbb5ee9d6be30247349054d1f716e8058e8 100644
--- a/std/math/isinf.zig
+++ b/std/math/isinf.zig
@@ -1,5 +1,6 @@
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
pub fn isInf(x: var) -> bool {
const T = @typeOf(x);
diff --git a/std/math/isnan.zig b/std/math/isnan.zig
index e996a726930071921c5b1e844c0e59df15f3eb99..d494dddca80727499a2890b4cb5577a53d5db937 100644
--- a/std/math/isnan.zig
+++ b/std/math/isnan.zig
@@ -1,5 +1,6 @@
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
pub fn isNan(x: var) -> bool {
const T = @typeOf(x);
diff --git a/std/math/isnormal.zig b/std/math/isnormal.zig
index f815c2680b760160c948b6806162ac7128da76b1..4d07bf4cb32f4bd320757b5fe70bbdb9b5a8aaec 100644
--- a/std/math/isnormal.zig
+++ b/std/math/isnormal.zig
@@ -1,5 +1,6 @@
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
pub fn isNormal(x: var) -> bool {
const T = @typeOf(x);
diff --git a/std/math/ln.zig b/std/math/ln.zig
index 4ded89d328d546ce02d012a1f631f1b57bb1f427..c5a5c93842cccbaa0a888d2cba1be8c7c53da521 100644
--- a/std/math/ln.zig
+++ b/std/math/ln.zig
@@ -5,8 +5,9 @@
// - ln(x) = nan if x < 0
// - ln(nan) = nan
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
const builtin = @import("builtin");
const TypeId = builtin.TypeId;
diff --git a/std/math/log.zig b/std/math/log.zig
index 1ff226f7e5b9dba79cfe8af39830f1d76109b422..4edb77bb1a96076c4773ebd83c0a94e445965b4d 100644
--- a/std/math/log.zig
+++ b/std/math/log.zig
@@ -1,7 +1,8 @@
-const math = @import("index.zig");
+const std = @import("../index.zig");
+const math = std.math;
const builtin = @import("builtin");
const TypeId = builtin.TypeId;
-const assert = @import("../debug.zig").assert;
+const assert = std.debug.assert;
pub fn log(comptime T: type, base: T, x: T) -> T {
if (base == 2) {
diff --git a/std/math/log10.zig b/std/math/log10.zig
index 73168dec8db7ee446458ec7daacf8b71ecb23a23..0b6fc31aa774896d890e5b1ce4f164d3d92f7912 100644
--- a/std/math/log10.zig
+++ b/std/math/log10.zig
@@ -5,8 +5,9 @@
// - log10(x) = nan if x < 0
// - log10(nan) = nan
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
const builtin = @import("builtin");
const TypeId = builtin.TypeId;
diff --git a/std/math/log1p.zig b/std/math/log1p.zig
index b369385038d3bb014b4b1c545781b0236af9a96b..ce5aad1d85ece2eec3cc53ce7c4a77365600d529 100644
--- a/std/math/log1p.zig
+++ b/std/math/log1p.zig
@@ -6,8 +6,9 @@
// - log1p(x) = nan if x < -1
// - log1p(nan) = nan
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
pub fn log1p(x: var) -> @typeOf(x) {
const T = @typeOf(x);
diff --git a/std/math/log2.zig b/std/math/log2.zig
index 1b38a9eceec62c9ae706f61ceb45932c8b8352d5..a9789e47cfbe936b2fa4fd3e4232cc58ceffbd51 100644
--- a/std/math/log2.zig
+++ b/std/math/log2.zig
@@ -5,8 +5,9 @@
// - log2(x) = nan if x < 0
// - log2(nan) = nan
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
const builtin = @import("builtin");
const TypeId = builtin.TypeId;
diff --git a/std/math/modf.zig b/std/math/modf.zig
index 72730b67d78c1ebc8a9db959e4e1471938e703e8..dc17f35b54b4b4382cd52f9e2fb641b1c1495f96 100644
--- a/std/math/modf.zig
+++ b/std/math/modf.zig
@@ -3,8 +3,9 @@
// - modf(+-inf) = +-inf, nan
// - modf(nan) = nan, nan
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
fn modf_result(comptime T: type) -> type {
return struct {
diff --git a/std/math/pow.zig b/std/math/pow.zig
index 55a2cd8c3e4036650469bb503c1805eb2b8011cb..b21fb3a9213b46a5fdb84de7b63dfe0a59ae32f8 100644
--- a/std/math/pow.zig
+++ b/std/math/pow.zig
@@ -22,8 +22,9 @@
// pow(x, y) = nan for finite x < 0 and finite non-integer y
const builtin = @import("builtin");
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
// This implementation is taken from the go stlib, musl is a bit more complex.
pub fn pow(comptime T: type, x: T, y: T) -> T {
diff --git a/std/math/round.zig b/std/math/round.zig
index 1e193fb1d7a752fdf65d64015eac49946c6e62e6..3abee040ef74856810e60006668d86b95b14adc5 100644
--- a/std/math/round.zig
+++ b/std/math/round.zig
@@ -5,8 +5,9 @@
// - round(nan) = nan
const builtin = @import("builtin");
-const assert = @import("../debug.zig").assert;
-const math = @import("index.zig");
+const assert = std.debug.assert;
+const std = @import("../index.zig");
+const math = std.math;
pub fn round(x: var) -> @typeOf(x) {
const T = @typeOf(x);
diff --git a/std/math/scalbn.zig b/std/math/scalbn.zig
index 0be6a3d47ef98043f384bf4c08ac5c27ce2f793c..6d1c77659303518b5bd4510f96fd1e7a29d59d0b 100644
--- a/std/math/scalbn.zig
+++ b/std/math/scalbn.zig
@@ -1,5 +1,6 @@
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
pub fn scalbn(x: var, n: i32) -> @typeOf(x) {
const T = @typeOf(x);
diff --git a/std/math/signbit.zig b/std/math/signbit.zig
index b8ccecfa1bcdb177739ec2d2b02739a7da659c32..b9bfe818de5e245b6ed45f507ecd94c9f6ec0945 100644
--- a/std/math/signbit.zig
+++ b/std/math/signbit.zig
@@ -1,5 +1,6 @@
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
pub fn signbit(x: var) -> bool {
const T = @typeOf(x);
diff --git a/std/math/sin.zig b/std/math/sin.zig
index 392bef1bc076921bc06cb69a2663262cbd1a741e..99008af469e1bbd12198384005e16e0deefc8d4b 100644
--- a/std/math/sin.zig
+++ b/std/math/sin.zig
@@ -5,8 +5,9 @@
// - sin(nan) = nan
const builtin = @import("builtin");
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
pub fn sin(x: var) -> @typeOf(x) {
const T = @typeOf(x);
diff --git a/std/math/sinh.zig b/std/math/sinh.zig
index 4c575f10ec8cdf5dfaa753b58a14fa1172b26227..ca06bc615a75b7df86423802c953c115cd61ccb2 100644
--- a/std/math/sinh.zig
+++ b/std/math/sinh.zig
@@ -5,8 +5,9 @@
// - sinh(nan) = nan
const builtin = @import("builtin");
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
const expo2 = @import("expo2.zig").expo2;
pub fn sinh(x: var) -> @typeOf(x) {
diff --git a/std/math/sqrt.zig b/std/math/sqrt.zig
index 263e616617a25fd91570403ca70f54687cf7c497..4d84756b4af62d110f769830eb2940d3b96a75ee 100644
--- a/std/math/sqrt.zig
+++ b/std/math/sqrt.zig
@@ -5,8 +5,9 @@
// - sqrt(x) = nan if x < 0
// - sqrt(nan) = nan
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
const builtin = @import("builtin");
const TypeId = builtin.TypeId;
diff --git a/std/math/tan.zig b/std/math/tan.zig
index ff53a758b4a3e19ffe2df814637ad8eb02f075f5..e62e9b889936a7977c34156858b490481da080df 100644
--- a/std/math/tan.zig
+++ b/std/math/tan.zig
@@ -5,8 +5,9 @@
// - tan(nan) = nan
const builtin = @import("builtin");
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
pub fn tan(x: var) -> @typeOf(x) {
const T = @typeOf(x);
diff --git a/std/math/tanh.zig b/std/math/tanh.zig
index 7715029361b065fd733c6281e383270430d91d30..813b4f4561c60ca164cdea38e2b4e5ebff0e413f 100644
--- a/std/math/tanh.zig
+++ b/std/math/tanh.zig
@@ -5,8 +5,9 @@
// - sinh(nan) = nan
const builtin = @import("builtin");
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
const expo2 = @import("expo2.zig").expo2;
pub fn tanh(x: var) -> @typeOf(x) {
diff --git a/std/math/trunc.zig b/std/math/trunc.zig
index 81eacb30bae791ee253bc4e7b58746d722e47e68..1d9032a22c807cb31c9605badc6dca1aec7f1ae7 100644
--- a/std/math/trunc.zig
+++ b/std/math/trunc.zig
@@ -4,8 +4,9 @@
// - trunc(+-inf) = +-inf
// - trunc(nan) = nan
-const math = @import("index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const math = std.math;
+const assert = std.debug.assert;
pub fn trunc(x: var) -> @typeOf(x) {
const T = @typeOf(x);
diff --git a/std/mem.zig b/std/mem.zig
index 7438eba70ac92f564731693c3d30c75062b1b267..41a4155b60d5a650978bdbfc3e1f65e7588242b7 100644
--- a/std/mem.zig
+++ b/std/mem.zig
@@ -1,6 +1,7 @@
-const debug = @import("debug.zig");
+const std = @import("index.zig");
+const debug = std.debug;
const assert = debug.assert;
-const math = @import("math/index.zig");
+const math = std.math;
const builtin = @import("builtin");
error OutOfMemory;
diff --git a/std/net.zig b/std/net.zig
index a5fd4d60368a012422ac2acf458ec1a1395c68c0..da078eab3f9c2ed20eb250c094a8fe294deb13e8 100644
--- a/std/net.zig
+++ b/std/net.zig
@@ -1,6 +1,7 @@
-const linux = @import("os/linux.zig");
-const assert = @import("debug.zig").assert;
-const endian = @import("endian.zig");
+const std = @import("index.zig");
+const linux = std.os.linux;
+const assert = std.debug.assert;
+const endian = std.endian;
error SigInterrupt;
error Io;
diff --git a/std/os/darwin.zig b/std/os/darwin.zig
index e230826b7e5bc4ff46159559b1e13326b708174a..7e3e5e823e3ee3132e8237213bb1c86c872ae013 100644
--- a/std/os/darwin.zig
+++ b/std/os/darwin.zig
@@ -1,5 +1,6 @@
-const c = @import("../c/index.zig");
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const c = std.c;
+const assert = std.debug.assert;
pub use @import("darwin_errno.zig");
diff --git a/std/os/index.zig b/std/os/index.zig
index 8e79eda40bc0030183099f9014215af41c6c0feb..0fd3f02e9a4e185c6ff24bd4d82a05a0d066b02f 100644
--- a/std/os/index.zig
+++ b/std/os/index.zig
@@ -1,3 +1,4 @@
+const std = @import("../index.zig");
const builtin = @import("builtin");
const Os = builtin.Os;
const is_windows = builtin.os == Os.windows;
@@ -37,22 +38,22 @@ pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock;
pub const FileHandle = if (is_windows) windows.HANDLE else i32;
-const debug = @import("../debug.zig");
+const debug = std.debug;
const assert = debug.assert;
-const c = @import("../c/index.zig");
+const c = std.c;
-const mem = @import("../mem.zig");
+const mem = std.mem;
const Allocator = mem.Allocator;
-const BufMap = @import("../buf_map.zig").BufMap;
-const cstr = @import("../cstr.zig");
+const BufMap = std.BufMap;
+const cstr = std.cstr;
-const io = @import("../io.zig");
-const base64 = @import("../base64.zig");
-const ArrayList = @import("../array_list.zig").ArrayList;
-const Buffer = @import("../buffer.zig").Buffer;
-const math = @import("../index.zig").math;
+const io = std.io;
+const base64 = std.base64;
+const ArrayList = std.ArrayList;
+const Buffer = std.Buffer;
+const math = std.math;
error SystemResources;
error AccessDenied;
diff --git a/std/os/linux.zig b/std/os/linux.zig
index f9baa43098e6515fb958bdfa197e7422b34d77de..c254f83d10139a7dbdf7a8c564fd690130cd0089 100644
--- a/std/os/linux.zig
+++ b/std/os/linux.zig
@@ -1,4 +1,5 @@
-const assert = @import("../debug.zig").assert;
+const std = @import("../index.zig");
+const assert = std.debug.assert;
const builtin = @import("builtin");
const arch = switch (builtin.arch) {
builtin.Arch.x86_64 => @import("linux_x86_64.zig"),
diff --git a/std/os/path.zig b/std/os/path.zig
index db514add9ca0a9546aa4b3b00b7edce230b90ebb..9417cb4299dc778fe94581d065aa33003ac5bfad 100644
--- a/std/os/path.zig
+++ b/std/os/path.zig
@@ -1,16 +1,16 @@
+const std = @import("../index.zig");
const builtin = @import("builtin");
const Os = builtin.Os;
-const debug = @import("../debug.zig");
+const debug = std.debug;
const assert = debug.assert;
-const mem = @import("../mem.zig");
-const fmt = @import("../fmt/index.zig");
+const mem = std.mem;
+const fmt = std.fmt;
const Allocator = mem.Allocator;
-const os = @import("index.zig");
-const math = @import("../math/index.zig");
+const os = std.os;
+const math = std.math;
const posix = os.posix;
const windows = os.windows;
-const c = @import("../c/index.zig");
-const cstr = @import("../cstr.zig");
+const cstr = std.cstr;
pub const sep_windows = '\\';
pub const sep_posix = '/';
diff --git a/std/rand.zig b/std/rand.zig
index 73801a078fae816c19802a9808fd33d7d4f2bfce..f35229ea3c0f4c8a9f434c22ac852954f554cbe4 100644
--- a/std/rand.zig
+++ b/std/rand.zig
@@ -1,8 +1,9 @@
+const std = @import("index.zig");
const builtin = @import("builtin");
-const assert = @import("debug.zig").assert;
+const assert = std.debug.assert;
const rand_test = @import("rand_test.zig");
-const mem = @import("mem.zig");
-const math = @import("math/index.zig");
+const mem = std.mem;
+const math = std.math;
pub const MT19937_32 = MersenneTwister(
u32, 624, 397, 31,
diff --git a/std/special/compiler_rt/fixunsdfdi_test.zig b/std/special/compiler_rt/fixunsdfdi_test.zig
index cb4a52b9edea95ea60331a6f85207391b9a8ad2b..2a0e778ba3ca66c4fbb7aa03b2f89b2161b83521 100644
--- a/std/special/compiler_rt/fixunsdfdi_test.zig
+++ b/std/special/compiler_rt/fixunsdfdi_test.zig
@@ -1,5 +1,5 @@
const __fixunsdfdi = @import("fixunsdfdi.zig").__fixunsdfdi;
-const assert = @import("../../debug.zig").assert;
+const assert = @import("../../index.zig").debug.assert;
fn test__fixunsdfdi(a: f64, expected: u64) {
const x = __fixunsdfdi(a);
diff --git a/std/special/compiler_rt/fixunsdfsi_test.zig b/std/special/compiler_rt/fixunsdfsi_test.zig
index eef374773d4c0b3d955838de11bf46507900bbe3..6116391391a82bd9a9d559298f2bb166a664d6fc 100644
--- a/std/special/compiler_rt/fixunsdfsi_test.zig
+++ b/std/special/compiler_rt/fixunsdfsi_test.zig
@@ -1,5 +1,5 @@
const __fixunsdfsi = @import("fixunsdfsi.zig").__fixunsdfsi;
-const assert = @import("../../debug.zig").assert;
+const assert = @import("../../index.zig").debug.assert;
fn test__fixunsdfsi(a: f64, expected: u32) {
const x = __fixunsdfsi(a);
diff --git a/std/special/compiler_rt/fixunsdfti_test.zig b/std/special/compiler_rt/fixunsdfti_test.zig
index cd348fffde90e9026880c23bfdce888d7049c260..dc7f1c29cd768bd17107ef6fff4a996b24f0e439 100644
--- a/std/special/compiler_rt/fixunsdfti_test.zig
+++ b/std/special/compiler_rt/fixunsdfti_test.zig
@@ -1,5 +1,5 @@
const __fixunsdfti = @import("fixunsdfti.zig").__fixunsdfti;
-const assert = @import("../../debug.zig").assert;
+const assert = @import("../../index.zig").debug.assert;
fn test__fixunsdfti(a: f64, expected: u128) {
const x = __fixunsdfti(a);
diff --git a/std/special/compiler_rt/fixunssfdi_test.zig b/std/special/compiler_rt/fixunssfdi_test.zig
index 67e3cd24c4bd9cd31db7703b74368a8011e1d8ae..41827a083480add05fd83607d213a26681802a67 100644
--- a/std/special/compiler_rt/fixunssfdi_test.zig
+++ b/std/special/compiler_rt/fixunssfdi_test.zig
@@ -1,5 +1,5 @@
const __fixunssfdi = @import("fixunssfdi.zig").__fixunssfdi;
-const assert = @import("../../debug.zig").assert;
+const assert = @import("../../index.zig").debug.assert;
fn test__fixunssfdi(a: f32, expected: u64) {
const x = __fixunssfdi(a);
diff --git a/std/special/compiler_rt/fixunssfsi_test.zig b/std/special/compiler_rt/fixunssfsi_test.zig
index bdb033933553881a8df12b01ae1d9e97074f6c68..664c02ea73685efa48fc17aa33c917b5b2d95d77 100644
--- a/std/special/compiler_rt/fixunssfsi_test.zig
+++ b/std/special/compiler_rt/fixunssfsi_test.zig
@@ -1,5 +1,5 @@
const __fixunssfsi = @import("fixunssfsi.zig").__fixunssfsi;
-const assert = @import("../../debug.zig").assert;
+const assert = @import("../../index.zig").debug.assert;
fn test__fixunssfsi(a: f32, expected: u32) {
const x = __fixunssfsi(a);
diff --git a/std/special/compiler_rt/fixunssfti_test.zig b/std/special/compiler_rt/fixunssfti_test.zig
index aaa7c70ab7077d763b363d8ff3b77f5c59a4d198..712df893c1a6a9bbad7e0591669742ca2b76dbf0 100644
--- a/std/special/compiler_rt/fixunssfti_test.zig
+++ b/std/special/compiler_rt/fixunssfti_test.zig
@@ -1,5 +1,5 @@
const __fixunssfti = @import("fixunssfti.zig").__fixunssfti;
-const assert = @import("../../debug.zig").assert;
+const assert = @import("../../index.zig").debug.assert;
fn test__fixunssfti(a: f32, expected: u128) {
const x = __fixunssfti(a);
diff --git a/std/special/compiler_rt/fixunstfdi_test.zig b/std/special/compiler_rt/fixunstfdi_test.zig
index c33062fad801b940174b297c805dc8ea78abdc75..b5526f62a61bf77e74de25857b94d87174fa0f05 100644
--- a/std/special/compiler_rt/fixunstfdi_test.zig
+++ b/std/special/compiler_rt/fixunstfdi_test.zig
@@ -1,5 +1,5 @@
const __fixunstfdi = @import("fixunstfdi.zig").__fixunstfdi;
-const assert = @import("../../debug.zig").assert;
+const assert = @import("../../index.zig").debug.assert;
fn test__fixunstfdi(a: f128, expected: u64) {
const x = __fixunstfdi(a);
diff --git a/std/special/compiler_rt/fixunstfsi_test.zig b/std/special/compiler_rt/fixunstfsi_test.zig
index 87bb1b9fa7bfcfe4565288c94563fd67f0765505..74b3507c44135b38d6137f8d0fa2963f0e05f310 100644
--- a/std/special/compiler_rt/fixunstfsi_test.zig
+++ b/std/special/compiler_rt/fixunstfsi_test.zig
@@ -1,5 +1,5 @@
const __fixunstfsi = @import("fixunstfsi.zig").__fixunstfsi;
-const assert = @import("../../debug.zig").assert;
+const assert = @import("../../index.zig").debug.assert;
fn test__fixunstfsi(a: f128, expected: u32) {
const x = __fixunstfsi(a);
diff --git a/std/special/compiler_rt/fixunstfti_test.zig b/std/special/compiler_rt/fixunstfti_test.zig
index f18c39d04dc1be01ec0a534dafa0b8526e4cd512..a6c9ea0f688e30ceb0df1f1cbbd7325025fd67a4 100644
--- a/std/special/compiler_rt/fixunstfti_test.zig
+++ b/std/special/compiler_rt/fixunstfti_test.zig
@@ -1,5 +1,5 @@
const __fixunstfti = @import("fixunstfti.zig").__fixunstfti;
-const assert = @import("../../debug.zig").assert;
+const assert = @import("../../index.zig").debug.assert;
fn test__fixunstfti(a: f128, expected: u128) {
const x = __fixunstfti(a);
diff --git a/std/special/compiler_rt/index.zig b/std/special/compiler_rt/index.zig
index 5e8c91c8d5e9efb96e40b3de6e4e07635f30eb8c..a554da5bf25b97ba371500a46c2b5627dd64a7e7 100644
--- a/std/special/compiler_rt/index.zig
+++ b/std/special/compiler_rt/index.zig
@@ -68,7 +68,7 @@ comptime {
}
}
-const assert = @import("../../debug.zig").assert;
+const assert = @import("../../index.zig").debug.assert;
const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4;
diff --git a/test/cases/union.zig b/test/cases/union.zig
index 90d869289ff0559cd3fad65831f8025553cf6523..6db43fc14be11e2b2ecf4a638e2a8c38b699a31b 100644
--- a/test/cases/union.zig
+++ b/test/cases/union.zig
@@ -220,3 +220,18 @@ fn assertIsTheUnion2Item1(value: &const TheUnion2) {
assert(*value == TheUnion2.Item1);
}
+
+pub const PackThis = union(enum) {
+ Invalid: bool,
+ StringLiteral: u2,
+};
+
+test "constant packed union" {
+ testConstPackedUnion([]PackThis {
+ PackThis { .StringLiteral = 1 },
+ });
+}
+
+fn testConstPackedUnion(expected_tokens: []const PackThis) {
+ assert(expected_tokens[0].StringLiteral == 1);
+}