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 {
  • Errors
  • Root Source File
  • +

    Source encoding

    +

    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

    Values

    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);
    +}