From 45ab752f9acd5247cd970ab01a388390ac3bdd94 Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Sat, 23 Dec 2017 17:47:48 -0700 Subject: [PATCH 01/14] source files must end with newline --- src-self-hosted/tokenizer.zig | 57 ++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 5 deletions(-) diff --git a/src-self-hosted/tokenizer.zig b/src-self-hosted/tokenizer.zig index 570d41fa7e..8c9ce44893 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,7 @@ pub const Token = struct { pub const Tokenizer = struct { buffer: []const u8, index: usize, + actual_file_end: usize, pub const Location = struct { line: usize, @@ -177,10 +179,24 @@ pub const Tokenizer = struct { } pub fn init(buffer: []const u8) -> Tokenizer { - return Tokenizer { - .buffer = buffer, - .index = 0, - }; + if (buffer.len == 0 or buffer[buffer.len - 1] == '\n') { + return Tokenizer { + .buffer = buffer, + .index = 0, + .actual_file_end = buffer.len, + }; + } else { + // last line is incomplete, so skip it, and give an error when we get there. + var source_len = buffer.len; + while (source_len > 0) : (source_len -= 1) { + if (buffer[source_len - 1] == '\n') break; + } + return Tokenizer { + .buffer = buffer[0..source_len], + .index = 0, + .actual_file_end = buffer.len, + }; + } } const State = enum { @@ -497,7 +513,11 @@ pub const Tokenizer = struct { } } result.end = self.index; - // TODO check state when returning EOF + if (result.id == Token.Id.Eof and 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; } @@ -507,3 +527,30 @@ pub const Tokenizer = struct { }; + +test "tokenizer" { + // source must end with eol + testTokenize("no newline", []Token.Id { + }, false); + testTokenize("test\n", []Token.Id { + Token.Id.Keyword_test, + }, true); + testTokenize("test\nno newline", []Token.Id { + Token.Id.Keyword_test, + }, false); +} + +fn testTokenize(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 => |kind| { + @panic("TODO: how do i test this?"); + }, + else => {}, + } + } + std.debug.assert(tokenizer.next().id == if (expected_eol_at_eof) Token.Id.Eof else Token.Id.NoEolAtEof); +} From 0082989f22165c6607a02528f868204285ad982a Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Sat, 23 Dec 2017 18:35:45 -0700 Subject: [PATCH 02/14] [self-hosted] tokenizer error for ascii control codes --- src-self-hosted/tokenizer.zig | 93 ++++++++++++++++++++++++++--------- 1 file changed, 69 insertions(+), 24 deletions(-) diff --git a/src-self-hosted/tokenizer.zig b/src-self-hosted/tokenizer.zig index 8c9ce44893..5d53d2833e 100644 --- a/src-self-hosted/tokenizer.zig +++ b/src-self-hosted/tokenizer.zig @@ -141,6 +141,7 @@ pub const Tokenizer = struct { buffer: []const u8, index: usize, actual_file_end: usize, + pending_invalid_token: ?Token, pub const Location = struct { line: usize, @@ -179,24 +180,18 @@ pub const Tokenizer = struct { } pub fn init(buffer: []const u8) -> Tokenizer { - if (buffer.len == 0 or buffer[buffer.len - 1] == '\n') { - return Tokenizer { - .buffer = buffer, - .index = 0, - .actual_file_end = buffer.len, - }; - } else { + 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. - var source_len = buffer.len; - while (source_len > 0) : (source_len -= 1) { - if (buffer[source_len - 1] == '\n') break; - } - return Tokenizer { - .buffer = buffer[0..source_len], - .index = 0, - .actual_file_end = buffer.len, - }; } + + return Tokenizer { + .buffer = buffer[0..source_len], + .index = 0, + .actual_file_end = buffer.len, + .pending_invalid_token = null, + }; } const State = enum { @@ -223,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, @@ -368,7 +367,7 @@ pub const Tokenizer = struct { break; }, '\n' => break, // Look for this error later. - else => {}, + else => self.checkLiteralCharacter(), }, State.StringLiteralBackslash => switch (c) { @@ -455,7 +454,7 @@ pub const Tokenizer = struct { .end = undefined, }; }, - else => {}, + else => self.checkLiteralCharacter(), }, State.Zero => switch (c) { 'b', 'o', 'x' => { @@ -513,10 +512,16 @@ pub const Tokenizer = struct { } } result.end = self.index; - if (result.id == Token.Id.Eof and 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; + 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; } @@ -524,12 +529,29 @@ pub const Tokenizer = struct { 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 c0 = self.buffer[self.index]; + if (c0 < 0x20 or c0 == 0x7f) { + // ascii control codes are never allowed + // (note that \n was checked before we got here) + self.pending_invalid_token = Token { + .id = Token.Id.Invalid, + .start = self.index, + .end = self.index + 1, + }; + return; + } + } }; test "tokenizer" { // source must end with eol + testTokenize("", []Token.Id { + }, true); testTokenize("no newline", []Token.Id { }, false); testTokenize("test\n", []Token.Id { @@ -538,6 +560,29 @@ test "tokenizer" { testTokenize("test\nno newline", []Token.Id { Token.Id.Keyword_test, }, false); + + // invalid token characters + testTokenize("#\n", []Token.Id { + Token.Id.Invalid, + }, true); + testTokenize("`\n", []Token.Id { + Token.Id.Invalid, + }, true); + + // invalid literal/comment characters + testTokenize("\"\x00\"\n", []Token.Id { + Token.Id { .StringLiteral = Token.StrLitKind.Normal }, + Token.Id.Invalid, + }, true); + testTokenize("//\x00\n", []Token.Id { + Token.Id.Invalid, + }, true); + testTokenize("//\x1f\n", []Token.Id { + Token.Id.Invalid, + }, true); + testTokenize("//\x7f\n", []Token.Id { + Token.Id.Invalid, + }, true); } fn testTokenize(source: []const u8, expected_tokens: []const Token.Id, expected_eol_at_eof: bool) { @@ -546,8 +591,8 @@ fn testTokenize(source: []const u8, expected_tokens: []const Token.Id, expected_ 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 => |kind| { - @panic("TODO: how do i test this?"); + Token.Id.StringLiteral => |expected_kind| { + std.debug.assert(expected_kind == switch (token.id) { Token.Id.StringLiteral => |kind| kind, else => unreachable }); }, else => {}, } From 2031989d981f05dca9d2b0da0bfcfb67f0333dac Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 23 Dec 2017 19:42:19 -0500 Subject: [PATCH 03/14] std.os.path.resolve handles an absolute path that is missing the drive --- std/os/path.zig | 370 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 261 insertions(+), 109 deletions(-) diff --git a/std/os/path.zig b/std/os/path.zig index 59e9a53027..db514add9c 100644 --- a/std/os/path.zig +++ b/std/os/path.zig @@ -111,6 +111,7 @@ test "os.path.isAbsoluteWindows" { testIsAbsoluteWindows("C:cwd\\another", false); testIsAbsoluteWindows("directory/directory", false); testIsAbsoluteWindows("directory\\directory", false); + testIsAbsoluteWindows("/usr/local", true); } test "os.path.isAbsolutePosix" { @@ -128,53 +129,115 @@ fn testIsAbsolutePosix(path: []const u8, expected_result: bool) { assert(isAbsolutePosix(path) == expected_result); } -pub fn drive(path: []const u8) -> ?[]const u8 { - if (path.len < 2) - return null; - if (path[1] != ':') - return null; - return path[0..2]; -} +pub const WindowsPath = struct { + is_abs: bool, + kind: Kind, + disk_designator: []const u8, -pub fn networkShare(path: []const u8) -> ?[]const u8 { - if (path.len < "//a/b".len) - return null; + pub const Kind = enum { + None, + Drive, + NetworkShare, + }; +}; + +pub fn windowsParsePath(path: []const u8) -> WindowsPath { + if (path.len >= 2 and path[1] == ':') { + return WindowsPath { + .is_abs = isAbsoluteWindows(path), + .kind = WindowsPath.Kind.Drive, + .disk_designator = path[0..2], + }; + } + if (path.len >= 1 and (path[0] == '/' or path[0] == '\\') and + (path.len == 1 or (path[1] != '/' and path[1] != '\\'))) + { + return WindowsPath { + .is_abs = true, + .kind = WindowsPath.Kind.None, + .disk_designator = path[0..0], + }; + } + const relative_path = WindowsPath { + .kind = WindowsPath.Kind.None, + .disk_designator = []u8{}, + .is_abs = false, + }; + if (path.len < "//a/b".len) { + return relative_path; + } // TODO when I combined these together with `inline for` the compiler crashed { const this_sep = '/'; const two_sep = []u8{this_sep, this_sep}; if (mem.startsWith(u8, path, two_sep)) { - if (path[2] == this_sep) - return null; + if (path[2] == this_sep) { + return relative_path; + } var it = mem.split(path, []u8{this_sep}); - _ = (it.next() ?? return null); - _ = (it.next() ?? return null); - return path[0..it.index]; + _ = (it.next() ?? return relative_path); + _ = (it.next() ?? return relative_path); + return WindowsPath { + .is_abs = isAbsoluteWindows(path), + .kind = WindowsPath.Kind.NetworkShare, + .disk_designator = path[0..it.index], + }; } } { const this_sep = '\\'; const two_sep = []u8{this_sep, this_sep}; if (mem.startsWith(u8, path, two_sep)) { - if (path[2] == this_sep) - return null; + if (path[2] == this_sep) { + return relative_path; + } var it = mem.split(path, []u8{this_sep}); - _ = (it.next() ?? return null); - _ = (it.next() ?? return null); - return path[0..it.index]; + _ = (it.next() ?? return relative_path); + _ = (it.next() ?? return relative_path); + return WindowsPath { + .is_abs = isAbsoluteWindows(path), + .kind = WindowsPath.Kind.NetworkShare, + .disk_designator = path[0..it.index], + }; } } - return null; + return relative_path; } -test "os.path.networkShare" { - assert(mem.eql(u8, ??networkShare("//a/b"), "//a/b")); - assert(mem.eql(u8, ??networkShare("\\\\a\\b"), "\\\\a\\b")); - - assert(networkShare("\\\\a\\") == null); +test "os.path.windowsParsePath" { + { + const parsed = windowsParsePath("//a/b"); + assert(parsed.is_abs); + assert(parsed.kind == WindowsPath.Kind.NetworkShare); + assert(mem.eql(u8, parsed.disk_designator, "//a/b")); + } + { + const parsed = windowsParsePath("\\\\a\\b"); + assert(parsed.is_abs); + assert(parsed.kind == WindowsPath.Kind.NetworkShare); + assert(mem.eql(u8, parsed.disk_designator, "\\\\a\\b")); + } + { + const parsed = windowsParsePath("\\\\a\\"); + assert(!parsed.is_abs); + assert(parsed.kind == WindowsPath.Kind.None); + assert(mem.eql(u8, parsed.disk_designator, "")); + } + { + const parsed = windowsParsePath("/usr/local"); + assert(parsed.is_abs); + assert(parsed.kind == WindowsPath.Kind.None); + assert(mem.eql(u8, parsed.disk_designator, "")); + } + { + const parsed = windowsParsePath("c:../"); + assert(!parsed.is_abs); + assert(parsed.kind == WindowsPath.Kind.Drive); + assert(mem.eql(u8, parsed.disk_designator, "c:")); + } } pub fn diskDesignator(path: []const u8) -> []const u8 { @@ -186,10 +249,9 @@ pub fn diskDesignator(path: []const u8) -> []const u8 { } pub fn diskDesignatorWindows(path: []const u8) -> []const u8 { - return drive(path) ?? (networkShare(path) ?? []u8{}); + return windowsParsePath(path).disk_designator; } -// TODO ASCII is wrong, we actually need full unicode support to compare paths. fn networkShareServersEql(ns1: []const u8, ns2: []const u8) -> bool { const sep1 = ns1[0]; const sep2 = ns2[0]; @@ -197,9 +259,33 @@ fn networkShareServersEql(ns1: []const u8, ns2: []const u8) -> bool { var it1 = mem.split(ns1, []u8{sep1}); var it2 = mem.split(ns2, []u8{sep2}); + // TODO ASCII is wrong, we actually need full unicode support to compare paths. return asciiEqlIgnoreCase(??it1.next(), ??it2.next()); } +fn compareDiskDesignators(kind: WindowsPath.Kind, p1: []const u8, p2: []const u8) -> bool { + switch (kind) { + WindowsPath.Kind.None => { + assert(p1.len == 0); + assert(p2.len == 0); + return true; + }, + WindowsPath.Kind.Drive => { + return asciiUpper(p1[0]) == asciiUpper(p2[0]); + }, + WindowsPath.Kind.NetworkShare => { + const sep1 = p1[0]; + const sep2 = p2[0]; + + var it1 = mem.split(p1, []u8{sep1}); + var it2 = mem.split(p2, []u8{sep2}); + + // TODO ASCII is wrong, we actually need full unicode support to compare paths. + return asciiEqlIgnoreCase(??it1.next(), ??it2.next()) and asciiEqlIgnoreCase(??it1.next(), ??it2.next()); + }, + } +} + fn asciiUpper(byte: u8) -> u8 { return switch (byte) { 'a' ... 'z' => 'A' + (byte - 'a'), @@ -249,120 +335,157 @@ pub fn resolveWindows(allocator: &Allocator, paths: []const []const u8) -> %[]u8 return os.getCwd(allocator); } - // determine which drive we want to result with - var result_drive_upcase: ?u8 = null; - var have_abs = false; + // determine which disk designator we will result with, if any + var result_drive_buf = "_:"; + var result_disk_designator: []const u8 = ""; + var have_drive_kind = WindowsPath.Kind.None; + var have_abs_path = false; var first_index: usize = 0; var max_size: usize = 0; for (paths) |p, i| { - const is_abs = isAbsoluteWindows(p); - if (is_abs) { - have_abs = true; + const parsed = windowsParsePath(p); + if (parsed.is_abs) { + have_abs_path = true; first_index = i; - max_size = 0; + max_size = result_disk_designator.len; } - if (drive(p)) |d| { - result_drive_upcase = asciiUpper(d[0]); - } else if (networkShare(p)) |_| { - result_drive_upcase = null; + switch (parsed.kind) { + WindowsPath.Kind.Drive => { + result_drive_buf[0] = asciiUpper(parsed.disk_designator[0]); + result_disk_designator = result_drive_buf[0..]; + have_drive_kind = WindowsPath.Kind.Drive; + }, + WindowsPath.Kind.NetworkShare => { + result_disk_designator = parsed.disk_designator; + have_drive_kind = WindowsPath.Kind.NetworkShare; + }, + WindowsPath.Kind.None => {}, } max_size += p.len + 1; } - // if we will result with a drive, loop again to determine - // which is the first time the drive is absolutely specified, if any - // and count up the max bytes for paths related to this drive - if (result_drive_upcase) |res_dr| { - have_abs = false; + // if we will result with a disk designator, loop again to determine + // which is the last time the disk designator is absolutely specified, if any + // and count up the max bytes for paths related to this disk designator + if (have_drive_kind != WindowsPath.Kind.None) { + have_abs_path = false; first_index = 0; - max_size = "_:".len; - var correct_drive = false; + max_size = result_disk_designator.len; + var correct_disk_designator = false; for (paths) |p, i| { - if (drive(p)) |dr| { - correct_drive = asciiUpper(dr[0]) == res_dr; - } else if (networkShare(p)) |_| { + const parsed = windowsParsePath(p); + if (parsed.kind != WindowsPath.Kind.None) { + if (parsed.kind == have_drive_kind) { + correct_disk_designator = compareDiskDesignators(have_drive_kind, + result_disk_designator, parsed.disk_designator); + } else { + continue; + } + } + if (!correct_disk_designator) { continue; } - if (!correct_drive) { - continue; - } - const is_abs = isAbsoluteWindows(p); - if (is_abs) { + if (parsed.is_abs) { first_index = i; - max_size = "_:".len; - have_abs = true; + max_size = result_disk_designator.len; + have_abs_path = true; } max_size += p.len + 1; } } - var drive_buf = "_:"; + + // Allocate result and fill in the disk designator, calling getCwd if we have to. var result: []u8 = undefined; var result_index: usize = 0; - var root_slice: []const u8 = undefined; - if (have_abs) { - result = %return allocator.alloc(u8, max_size); + if (have_abs_path) { + switch (have_drive_kind) { + WindowsPath.Kind.Drive => { + result = %return allocator.alloc(u8, max_size); - if (result_drive_upcase) |res_dr| { - drive_buf[0] = res_dr; - root_slice = drive_buf[0..]; + mem.copy(u8, result, result_disk_designator); + result_index += result_disk_designator.len; + }, + WindowsPath.Kind.NetworkShare => { + result = %return allocator.alloc(u8, max_size); + var it = mem.split(paths[first_index], "/\\"); + const server_name = ??it.next(); + const other_name = ??it.next(); - mem.copy(u8, result, root_slice); - result_index += root_slice.len; - } else { - // We know it looks like //a/b or \\a\b because of earlier code - var it = mem.split(paths[first_index], "/\\"); - const server_name = ??it.next(); - const other_name = ??it.next(); - - result[result_index] = '\\'; - result_index += 1; - result[result_index] = '\\'; - result_index += 1; - mem.copy(u8, result[result_index..], server_name); - result_index += server_name.len; - result[result_index] = '\\'; - result_index += 1; - mem.copy(u8, result[result_index..], other_name); - result_index += other_name.len; - - root_slice = result[0..result_index]; + result[result_index] = '\\'; + result_index += 1; + result[result_index] = '\\'; + result_index += 1; + mem.copy(u8, result[result_index..], server_name); + result_index += server_name.len; + result[result_index] = '\\'; + result_index += 1; + mem.copy(u8, result[result_index..], other_name); + result_index += other_name.len; + + result_disk_designator = result[0..result_index]; + }, + WindowsPath.Kind.None => { + assert(is_windows); // resolveWindows called on non windows can't use getCwd + const cwd = %return os.getCwd(allocator); + defer allocator.free(cwd); + const parsed_cwd = windowsParsePath(cwd); + result = %return allocator.alloc(u8, max_size + parsed_cwd.disk_designator.len + 1); + mem.copy(u8, result, parsed_cwd.disk_designator); + result_index += parsed_cwd.disk_designator.len; + result_disk_designator = result[0..parsed_cwd.disk_designator.len]; + if (parsed_cwd.kind == WindowsPath.Kind.Drive) { + result[0] = asciiUpper(result[0]); + } + have_drive_kind = parsed_cwd.kind; + }, } } else { assert(is_windows); // resolveWindows called on non windows can't use getCwd - // TODO get cwd for result_drive if applicable + // TODO call get cwd for the result_disk_designator instead of the global one const cwd = %return os.getCwd(allocator); defer allocator.free(cwd); + result = %return allocator.alloc(u8, max_size + cwd.len + 1); + mem.copy(u8, result, cwd); result_index += cwd.len; - - root_slice = diskDesignatorWindows(result[0..result_index]); + const parsed_cwd = windowsParsePath(result[0..result_index]); + result_disk_designator = parsed_cwd.disk_designator; + if (parsed_cwd.kind == WindowsPath.Kind.Drive) { + result[0] = asciiUpper(result[0]); + } + have_drive_kind = parsed_cwd.kind; } %defer allocator.free(result); - var correct_drive = true; + // Now we know the disk designator to use, if any, and what kind it is. And our result + // is big enough to append all the paths to. + var correct_disk_designator = true; for (paths[first_index..]) |p, i| { - if (result_drive_upcase) |res_dr| { - if (drive(p)) |dr| { - correct_drive = asciiUpper(dr[0]) == res_dr; - } else if (networkShare(p)) |_| { - continue; - } - if (!correct_drive) { + const parsed = windowsParsePath(p); + + if (parsed.kind != WindowsPath.Kind.None) { + if (parsed.kind == have_drive_kind) { + correct_disk_designator = compareDiskDesignators(have_drive_kind, + result_disk_designator, parsed.disk_designator); + } else { continue; } } - var it = mem.split(p[diskDesignatorWindows(p).len..], "/\\"); + if (!correct_disk_designator) { + continue; + } + var it = mem.split(p[parsed.disk_designator.len..], "/\\"); while (it.next()) |component| { if (mem.eql(u8, component, ".")) { continue; } else if (mem.eql(u8, component, "..")) { while (true) { - if (result_index == 0 or result_index == root_slice.len) + if (result_index == 0 or result_index == result_disk_designator.len) break; result_index -= 1; if (result[result_index] == '\\' or result[result_index] == '/') @@ -377,7 +500,7 @@ pub fn resolveWindows(allocator: &Allocator, paths: []const []const u8) -> %[]u8 } } - if (result_index == root_slice.len) { + if (result_index == result_disk_designator.len) { result[result_index] = '\\'; result_index += 1; } @@ -455,6 +578,9 @@ pub fn resolvePosix(allocator: &Allocator, paths: []const []const u8) -> %[]u8 { test "os.path.resolve" { const cwd = %%os.getCwd(debug.global_allocator); if (is_windows) { + if (windowsParsePath(cwd).kind == WindowsPath.Kind.Drive) { + cwd[0] = asciiUpper(cwd[0]); + } assert(mem.eql(u8, testResolveWindows([][]const u8{"."}), cwd)); } else { assert(mem.eql(u8, testResolvePosix([][]const u8{"a/b/c/", "../../.."}), cwd)); @@ -463,6 +589,29 @@ test "os.path.resolve" { } test "os.path.resolveWindows" { + if (is_windows) { + const cwd = %%os.getCwd(debug.global_allocator); + const parsed_cwd = windowsParsePath(cwd); + { + const result = testResolveWindows([][]const u8{"/usr/local", "lib\\zig\\std\\array_list.zig"}); + const expected = %%join(debug.global_allocator, + parsed_cwd.disk_designator, "usr\\local\\lib\\zig\\std\\array_list.zig"); + if (parsed_cwd.kind == WindowsPath.Kind.Drive) { + expected[0] = asciiUpper(parsed_cwd.disk_designator[0]); + } + assert(mem.eql(u8, result, expected)); + } + { + const result = testResolveWindows([][]const u8{"usr/local", "lib\\zig"}); + const expected = %%join(debug.global_allocator, cwd, "usr\\local\\lib\\zig"); + if (parsed_cwd.kind == WindowsPath.Kind.Drive) { + expected[0] = asciiUpper(parsed_cwd.disk_designator[0]); + } + assert(mem.eql(u8, result, expected)); + } + } + + assert(mem.eql(u8, testResolveWindows([][]const u8{"c:\\a\\b\\c", "/hi", "ok"}), "C:\\hi\\ok")); assert(mem.eql(u8, testResolveWindows([][]const u8{"c:/blah\\blah", "d:/games", "c:../a"}), "C:\\blah\\a")); assert(mem.eql(u8, testResolveWindows([][]const u8{"c:/blah\\blah", "d:/games", "C:../a"}), "C:\\blah\\a")); assert(mem.eql(u8, testResolveWindows([][]const u8{"c:/ignore", "d:\\a/b\\c/d", "\\e.exe"}), "D:\\e.exe")); @@ -749,18 +898,21 @@ pub fn relativeWindows(allocator: &Allocator, from: []const u8, to: []const u8) const resolved_to = %return resolveWindows(allocator, [][]const u8{to}); defer if (clean_up_resolved_to) allocator.free(resolved_to); - const result_is_to = if (drive(resolved_to)) |to_drive| - if (drive(resolved_from)) |from_drive| - asciiUpper(from_drive[0]) != asciiUpper(to_drive[0]) - else - true - else if (networkShare(resolved_to)) |to_ns| - if (networkShare(resolved_from)) |from_ns| - !networkShareServersEql(to_ns, from_ns) - else - true - else - unreachable; + const parsed_from = windowsParsePath(resolved_from); + const parsed_to = windowsParsePath(resolved_to); + const result_is_to = x: { + if (parsed_from.kind != parsed_to.kind) { + break :x true; + } else switch (parsed_from.kind) { + WindowsPath.Kind.NetworkShare => { + break :x !networkShareServersEql(parsed_to.disk_designator, parsed_from.disk_designator); + }, + WindowsPath.Kind.Drive => { + break :x asciiUpper(parsed_from.disk_designator[0]) != asciiUpper(parsed_to.disk_designator[0]); + }, + else => unreachable, + } + }; if (result_is_to) { clean_up_resolved_to = false; From e0a1466bd842f23983bb4a175bd16b005001a3f9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 23 Dec 2017 20:21:57 -0500 Subject: [PATCH 04/14] build: add --search-prefix option --- build.zig | 17 ++++++++++++----- std/build.zig | 21 +++++++++++++++++++++ std/special/build_runner.zig | 7 +++++++ 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/build.zig b/build.zig index 96638659be..285c124f8f 100644 --- a/build.zig +++ b/build.zig @@ -80,9 +80,12 @@ fn dependOnLib(lib_exe_obj: &std.build.LibExeObjStep, dep: &const LibraryDep) { for (dep.libdirs.toSliceConst()) |lib_dir| { lib_exe_obj.addLibPath(lib_dir); } - for (dep.libs.toSliceConst()) |lib| { + for (dep.system_libs.toSliceConst()) |lib| { lib_exe_obj.linkSystemLibrary(lib); } + for (dep.libs.toSliceConst()) |lib| { + lib_exe_obj.addObjectFile(lib); + } for (dep.includes.toSliceConst()) |include_path| { lib_exe_obj.addIncludeDir(include_path); } @@ -91,6 +94,7 @@ fn dependOnLib(lib_exe_obj: &std.build.LibExeObjStep, dep: &const LibraryDep) { const LibraryDep = struct { libdirs: ArrayList([]const u8), libs: ArrayList([]const u8), + system_libs: ArrayList([]const u8), includes: ArrayList([]const u8), }; @@ -98,11 +102,11 @@ fn findLLVM(b: &Builder) -> ?LibraryDep { const llvm_config_exe = b.findProgram( [][]const u8{"llvm-config-5.0", "llvm-config"}, [][]const u8{ - "/usr/local/opt/llvm@5/bin", - "/mingw64/bin", + "C:/Libraries/llvm-5.0.0/bin", "/c/msys64/mingw64/bin", "c:/msys64/mingw64/bin", - "C:/Libraries/llvm-5.0.0/bin", + "/usr/local/opt/llvm@5/bin", + "/mingw64/bin", }) %% |err| { warn("unable to find llvm-config: {}\n", err); @@ -114,6 +118,7 @@ fn findLLVM(b: &Builder) -> ?LibraryDep { var result = LibraryDep { .libs = ArrayList([]const u8).init(b.allocator), + .system_libs = ArrayList([]const u8).init(b.allocator), .includes = ArrayList([]const u8).init(b.allocator), .libdirs = ArrayList([]const u8).init(b.allocator), }; @@ -121,7 +126,9 @@ fn findLLVM(b: &Builder) -> ?LibraryDep { var it = mem.split(libs_output, " \n"); while (it.next()) |lib_arg| { if (mem.startsWith(u8, lib_arg, "-l")) { - %%result.libs.append(lib_arg[2..]); + %%result.system_libs.append(lib_arg[2..]); + } else { + %%result.libs.append(lib_arg); } } } diff --git a/std/build.zig b/std/build.zig index 0a23a77f80..3a2079db15 100644 --- a/std/build.zig +++ b/std/build.zig @@ -47,6 +47,7 @@ pub const Builder = struct { env_map: BufMap, top_level_steps: ArrayList(&TopLevelStep), prefix: []const u8, + search_prefixes: ArrayList([]const u8), lib_dir: []const u8, exe_dir: []const u8, installed_files: ArrayList([]const u8), @@ -114,6 +115,7 @@ pub const Builder = struct { .default_step = undefined, .env_map = %%os.getEnvMap(allocator), .prefix = undefined, + .search_prefixes = ArrayList([]const u8).init(allocator), .lib_dir = undefined, .exe_dir = undefined, .installed_files = ArrayList([]const u8).init(allocator), @@ -671,7 +673,22 @@ pub const Builder = struct { } pub fn findProgram(self: &Builder, names: []const []const u8, paths: []const []const u8) -> %[]const u8 { + // TODO report error for ambiguous situations const exe_extension = (Target { .Native = {}}).exeFileExt(); + for (self.search_prefixes.toSliceConst()) |search_prefix| { + for (names) |name| { + if (os.path.isAbsolute(name)) { + return name; + } + const full_path = %return os.path.join(self.allocator, search_prefix, "bin", + self.fmt("{}{}", name, exe_extension)); + if (os.path.real(self.allocator, full_path)) |real_path| { + return real_path; + } else |_| { + continue; + } + } + } if (self.env_map.get("PATH")) |PATH| { for (names) |name| { if (os.path.isAbsolute(name)) { @@ -727,6 +744,10 @@ pub const Builder = struct { }, } } + + pub fn addSearchPrefix(self: &Builder, search_prefix: []const u8) { + %%self.search_prefixes.append(search_prefix); + } }; const Version = struct { diff --git a/std/special/build_runner.zig b/std/special/build_runner.zig index e54d85e6ef..0ae76a560b 100644 --- a/std/special/build_runner.zig +++ b/std/special/build_runner.zig @@ -84,6 +84,12 @@ pub fn main() -> %void { warn("Expected argument after --prefix\n\n"); return usageAndErr(&builder, false, %return stderr_stream); }); + } else if (mem.eql(u8, arg, "--search-prefix")) { + const search_prefix = %return unwrapArg(arg_it.next(allocator) ?? { + warn("Expected argument after --search-prefix\n\n"); + return usageAndErr(&builder, false, %return stderr_stream); + }); + builder.addSearchPrefix(search_prefix); } else if (mem.eql(u8, arg, "--verbose-tokenize")) { builder.verbose_tokenize = true; } else if (mem.eql(u8, arg, "--verbose-ast")) { @@ -145,6 +151,7 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream) \\ --help Print this help and exit \\ --verbose Print commands before executing them \\ --prefix [path] Override default install prefix + \\ --search-prefix [path] Add a path to look for binaries, libraries, headers \\ \\Project-Specific Options: \\ From 79c2ceb2d59af1f84edcc7a5a683ecf38dfb1bf6 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 23 Dec 2017 21:19:48 -0500 Subject: [PATCH 05/14] build: findLLVM correctly handles system libraries --- build.zig | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/build.zig b/build.zig index 285c124f8f..dbb54f8c3e 100644 --- a/build.zig +++ b/build.zig @@ -128,7 +128,11 @@ fn findLLVM(b: &Builder) -> ?LibraryDep { if (mem.startsWith(u8, lib_arg, "-l")) { %%result.system_libs.append(lib_arg[2..]); } else { - %%result.libs.append(lib_arg); + if (os.path.isAbsolute(lib_arg)) { + %%result.libs.append(lib_arg); + } else { + %%result.system_libs.append(lib_arg); + } } } } From 9dae796fe3bd08c4e636f09d1849f6ce2879a50b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 23 Dec 2017 21:20:38 -0500 Subject: [PATCH 06/14] translate-c: set up debug scope for translated functions --- src/codegen.cpp | 4 +++- src/ir.cpp | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 0aecacb0b2..339c643425 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -590,8 +590,10 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { bool is_optimized = g->build_mode != BuildModeDebug; bool is_internal_linkage = (fn_table_entry->body_node != nullptr && fn_table_entry->export_list.length == 0); + ZigLLVMDIScope *fn_di_scope = get_di_scope(g, scope->parent); + assert(fn_di_scope != nullptr); ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder, - get_di_scope(g, scope->parent), buf_ptr(&fn_table_entry->symbol_name), "", + fn_di_scope, buf_ptr(&fn_table_entry->symbol_name), "", import->di_file, line_number, fn_table_entry->type_entry->di_type, is_internal_linkage, is_definition, scope_line, flags, is_optimized, nullptr); diff --git a/src/ir.cpp b/src/ir.cpp index a0f5a9be47..8698456379 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -14051,6 +14051,8 @@ static TypeTableEntry *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruc child_import->package = new_anonymous_package(); child_import->package->package_table.put(buf_create_from_str("builtin"), ira->codegen->compile_var_package); child_import->package->package_table.put(buf_create_from_str("std"), ira->codegen->std_package); + child_import->di_file = ZigLLVMCreateFile(ira->codegen->dbuilder, + buf_ptr(buf_create_from_str("cimport.h")), buf_ptr(buf_create_from_str("."))); ZigList errors = {0}; From 4183c6f1a52959ab5eef540c8eec1758079554eb Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 23 Dec 2017 22:08:53 -0500 Subject: [PATCH 07/14] move std/debug.zig to a subdirectory self hosted compiler parser tests do some fuzz testing --- CMakeLists.txt | 3 +- build.zig | 3 +- src-self-hosted/parser.zig | 30 ++++++---- std/array_list.zig | 5 +- std/base64.zig | 5 +- std/buffer.zig | 9 +-- std/cstr.zig | 5 +- std/debug/failing_allocator.zig | 64 +++++++++++++++++++++ std/{debug.zig => debug/index.zig} | 62 +------------------- std/fmt/errol/index.zig | 7 ++- std/fmt/index.zig | 7 ++- std/hash_map.zig | 7 ++- std/heap.zig | 9 +-- std/index.zig | 4 +- std/linked_list.zig | 5 +- std/math/acos.zig | 5 +- std/math/acosh.zig | 5 +- std/math/asin.zig | 5 +- std/math/asinh.zig | 5 +- std/math/atan.zig | 5 +- std/math/atan2.zig | 5 +- std/math/atanh.zig | 5 +- std/math/cbrt.zig | 5 +- std/math/ceil.zig | 5 +- std/math/copysign.zig | 5 +- std/math/cos.zig | 5 +- std/math/cosh.zig | 5 +- std/math/exp.zig | 5 +- std/math/exp2.zig | 5 +- std/math/expm1.zig | 5 +- std/math/fabs.zig | 5 +- std/math/floor.zig | 5 +- std/math/fma.zig | 5 +- std/math/frexp.zig | 5 +- std/math/hypot.zig | 5 +- std/math/ilogb.zig | 5 +- std/math/index.zig | 3 +- std/math/inf.zig | 5 +- std/math/isfinite.zig | 5 +- std/math/isinf.zig | 5 +- std/math/isnan.zig | 5 +- std/math/isnormal.zig | 5 +- std/math/ln.zig | 5 +- std/math/log.zig | 5 +- std/math/log10.zig | 5 +- std/math/log1p.zig | 5 +- std/math/log2.zig | 5 +- std/math/modf.zig | 5 +- std/math/pow.zig | 5 +- std/math/round.zig | 5 +- std/math/scalbn.zig | 5 +- std/math/signbit.zig | 5 +- std/math/sin.zig | 5 +- std/math/sinh.zig | 5 +- std/math/sqrt.zig | 5 +- std/math/tan.zig | 5 +- std/math/tanh.zig | 5 +- std/math/trunc.zig | 5 +- std/mem.zig | 5 +- std/net.zig | 7 ++- std/os/darwin.zig | 5 +- std/os/index.zig | 21 +++---- std/os/linux.zig | 3 +- std/os/path.zig | 14 ++--- std/rand.zig | 7 ++- std/special/compiler_rt/fixunsdfdi_test.zig | 2 +- std/special/compiler_rt/fixunsdfsi_test.zig | 2 +- std/special/compiler_rt/fixunsdfti_test.zig | 2 +- std/special/compiler_rt/fixunssfdi_test.zig | 2 +- std/special/compiler_rt/fixunssfsi_test.zig | 2 +- std/special/compiler_rt/fixunssfti_test.zig | 2 +- std/special/compiler_rt/fixunstfdi_test.zig | 2 +- std/special/compiler_rt/fixunstfsi_test.zig | 2 +- std/special/compiler_rt/fixunstfti_test.zig | 2 +- std/special/compiler_rt/index.zig | 2 +- 75 files changed, 297 insertions(+), 223 deletions(-) create mode 100644 std/debug/failing_allocator.zig rename std/{debug.zig => debug/index.zig} (94%) diff --git a/CMakeLists.txt b/CMakeLists.txt index d8e2d9ff7a..b94b4e1323 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -516,7 +516,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}") diff --git a/build.zig b/build.zig index dbb54f8c3e..e6564db96e 100644 --- a/build.zig +++ b/build.zig @@ -172,7 +172,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/src-self-hosted/parser.zig b/src-self-hosted/parser.zig index c997536ce2..faba8e6059 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/std/array_list.zig b/std/array_list.zig index 04db4dd280..db5581dc08 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 840643b565..0b405b1f4c 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 4f5d281f48..2bb395d0fb 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/cstr.zig b/std/cstr.zig index 445f7ab892..d17b69c7a1 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 { diff --git a/std/debug/failing_allocator.zig b/std/debug/failing_allocator.zig new file mode 100644 index 0000000000..9b12ff5cb7 --- /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.zig b/std/debug/index.zig similarity index 94% rename from std/debug.zig rename to std/debug/index.zig index a683b5ae15..e1025b291b 100644 --- a/std/debug.zig +++ b/std/debug/index.zig @@ -1,10 +1,10 @@ -const std = @import("index.zig"); +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 elf = std.elf; +const DW = std.dwarf; const ArrayList = std.ArrayList; const builtin = @import("builtin"); @@ -992,59 +992,3 @@ fn readILeb128(in_stream: &io.InStream) -> %i64 { 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/fmt/errol/index.zig b/std/fmt/errol/index.zig index 0a1ea7deef..ba4447c631 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 fef968a1d5..550fa1ce1f 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 837ee07423..cf83815798 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 ec447c1aa8..6a78692ec6 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 323eee203e..07da469b5e 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 f4b6d274c9..3c516dab7d 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 7690497da5..478d5a846d 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 3b2c2c0f31..150bcd4543 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 c5d24c35e5..a0209be0c8 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 f963dae77b..d95565fc6d 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 cf244eb762..fbfade50a0 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 b3af18cd9e..11e1b8cd89 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 13de90279b..e787506765 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 a8df75dff2..9725716f3b 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 8e27132e25..141b5c0fc5 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 05205e1a0e..ebf12313ff 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 4c3b8e1282..a65ea1ace8 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 6d40d71b8d..05565d6b3a 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 6e591daea3..4cce18ffe5 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 6061f32391..4ce7de909e 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 fbe1841030..10670c4cfc 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 cf1b8f1f14..dc1184dcc8 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 d7de45e9d0..910dfd1901 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 8e5adc80b2..b48cfc83b2 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 1a317a2c80..a90121e5fe 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 9b09ed53a4..6c0039b176 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 41a1e2d83f..db8e24d6c8 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 1991864f69..d382154059 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 546e6f3af8..b253124c84 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 d44d373cf1..67fcf3cd18 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 98c90e72a9..75529fbb5e 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 e996a72693..d494dddca8 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 f815c2680b..4d07bf4cb3 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 4ded89d328..c5a5c93842 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 1ff226f7e5..4edb77bb1a 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 73168dec8d..0b6fc31aa7 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 b369385038..ce5aad1d85 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 1b38a9ecee..a9789e47cf 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 72730b67d7..dc17f35b54 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 55a2cd8c3e..b21fb3a921 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 1e193fb1d7..3abee040ef 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 0be6a3d47e..6d1c776593 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 b8ccecfa1b..b9bfe818de 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 392bef1bc0..99008af469 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 4c575f10ec..ca06bc615a 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 263e616617..4d84756b4a 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 ff53a758b4..e62e9b8899 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 7715029361..813b4f4561 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 81eacb30ba..1d9032a22c 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 7438eba70a..41a4155b60 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 a5fd4d6036..da078eab3f 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 e230826b7e..7e3e5e823e 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 8e79eda40b..0fd3f02e9a 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 f9baa43098..c254f83d10 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 db514add9c..9417cb4299 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 73801a078f..f35229ea3c 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 cb4a52b9ed..2a0e778ba3 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 eef374773d..6116391391 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 cd348fffde..dc7f1c29cd 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 67e3cd24c4..41827a0834 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 bdb0339335..664c02ea73 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 aaa7c70ab7..712df893c1 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 c33062fad8..b5526f62a6 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 87bb1b9fa7..74b3507c44 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 f18c39d04d..a6c9ea0f68 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 fab7b7c878..5034a6fd90 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; From fb96c3e73ec840e5c46bf5080aa9ffc90784f6b9 Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Sat, 23 Dec 2017 21:47:04 -0700 Subject: [PATCH 08/14] debug needs to export FailingAllocator --- std/debug/index.zig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/std/debug/index.zig b/std/debug/index.zig index e1025b291b..3f722b494d 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -8,6 +8,8 @@ const DW = std.dwarf; const ArrayList = std.ArrayList; const builtin = @import("builtin"); +pub use @import("./failing_allocator.zig"); + error MissingDebugInfo; error InvalidDebugInfo; error UnsupportedDebugInfo; From d6a74ed463d1d4262009c67689d98cb67c5e85f2 Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Sat, 23 Dec 2017 21:34:04 -0700 Subject: [PATCH 09/14] [self-hosted] source must be valid utf8. see #663 --- src-self-hosted/tokenizer.zig | 177 ++++++++++++++++++++++++++++------ 1 file changed, 149 insertions(+), 28 deletions(-) diff --git a/src-self-hosted/tokenizer.zig b/src-self-hosted/tokenizer.zig index 5d53d2833e..49225447a8 100644 --- a/src-self-hosted/tokenizer.zig +++ b/src-self-hosted/tokenizer.zig @@ -532,60 +532,181 @@ pub const Tokenizer = struct { 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 < 0x20 or c0 == 0x7f) { - // ascii control codes are never allowed - // (note that \n was checked before we got here) - self.pending_invalid_token = Token { - .id = Token.Id.Invalid, - .start = self.index, - .end = self.index + 1, - }; - return; + 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 - testTokenize("", []Token.Id { +test "tokenizer - source must end with eol" { + testTokenizeWithEol("", []Token.Id { }, true); - testTokenize("no newline", []Token.Id { + testTokenizeWithEol("no newline", []Token.Id { }, false); - testTokenize("test\n", []Token.Id { + testTokenizeWithEol("test\n", []Token.Id { Token.Id.Keyword_test, }, true); - testTokenize("test\nno newline", []Token.Id { + testTokenizeWithEol("test\nno newline", []Token.Id { Token.Id.Keyword_test, }, false); +} - // invalid token characters - testTokenize("#\n", []Token.Id { - Token.Id.Invalid, - }, true); - testTokenize("`\n", []Token.Id { - Token.Id.Invalid, - }, true); +test "tokenizer - invalid token characters" { + testTokenize("#\n", []Token.Id{Token.Id.Invalid}); + testTokenize("`\n", []Token.Id{Token.Id.Invalid}); +} - // invalid literal/comment characters +test "tokenizer - invalid literal/comment characters" { testTokenize("\"\x00\"\n", []Token.Id { Token.Id { .StringLiteral = Token.StrLitKind.Normal }, Token.Id.Invalid, - }, true); + }); testTokenize("//\x00\n", []Token.Id { Token.Id.Invalid, - }, true); + }); testTokenize("//\x1f\n", []Token.Id { Token.Id.Invalid, - }, true); + }); testTokenize("//\x7f\n", []Token.Id { Token.Id.Invalid, - }, true); + }); } -fn testTokenize(source: []const u8, expected_tokens: []const Token.Id, expected_eol_at_eof: bool) { +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(); From f0a17536074c159aee4b2f378f5918d5d2a2ab73 Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Sat, 23 Dec 2017 22:23:06 -0700 Subject: [PATCH 10/14] add source encoding rules to the docs. see #663 --- doc/langref.html.in | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/langref.html.in b/doc/langref.html.in index 162c8b3e03..09f67a800b 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:

    +
      +
    • Ascii control characters, except for U+000a (LF): U+0000 - U+0009, U+000b - U+0001f, U+007f. (Note that Windows line endings (CRLF) are not allowed, and hard tabs are not allowed.)
    • +
    • Non-Ascii Unicode line endings: U+0085 (NEL), U+2028 (LS), U+2029 (PS).
    • +
    +

    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 designe decisions, see issue #663

    Values

    const warn = @import("std").debug.warn;
     const os = @import("std").os;
    
    From 86397a532ec3c6699c39c8eeb966cd56b66c6c96 Mon Sep 17 00:00:00 2001
    From: Andrew Kelley 
    Date: Sun, 24 Dec 2017 02:52:30 -0500
    Subject: [PATCH 11/14] docs: fix typo
    
    ---
     doc/langref.html.in | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/doc/langref.html.in b/doc/langref.html.in
    index 09f67a800b..c35e326254 100644
    --- a/doc/langref.html.in
    +++ b/doc/langref.html.in
    @@ -299,7 +299,7 @@ pub fn main() -> %void {
             
  • Non-Ascii Unicode line endings: U+0085 (NEL), U+2028 (LS), U+2029 (PS).
  • 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 designe decisions, see issue #663

    +

    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;
    
    From 2a25398c869fcdefe8b6508974a5c463ca833520 Mon Sep 17 00:00:00 2001
    From: Andrew Kelley 
    Date: Sun, 24 Dec 2017 04:10:26 -0500
    Subject: [PATCH 12/14] fix segfault when passing union enum with sub byte...
    
    ...field to const slice parameter
    
    we use a packed struct internally to represent a const array
    of disparate union values, and needed to update the internal
    getelementptr instruction to recognize that.
    
    closes #664
    ---
     src/codegen.cpp      | 26 +++++++++++++++++++-------
     std/debug/index.zig  |  2 +-
     test/cases/union.zig | 15 +++++++++++++++
     3 files changed, 35 insertions(+), 8 deletions(-)
    
    diff --git a/src/codegen.cpp b/src/codegen.cpp
    index 339c643425..552467989e 100644
    --- a/src/codegen.cpp
    +++ b/src/codegen.cpp
    @@ -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/std/debug/index.zig b/std/debug/index.zig
    index 3f722b494d..251b6f6f93 100644
    --- a/std/debug/index.zig
    +++ b/std/debug/index.zig
    @@ -8,7 +8,7 @@ const DW = std.dwarf;
     const ArrayList = std.ArrayList;
     const builtin = @import("builtin");
     
    -pub use @import("./failing_allocator.zig");
    +pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator;
     
     error MissingDebugInfo;
     error InvalidDebugInfo;
    diff --git a/test/cases/union.zig b/test/cases/union.zig
    index 90d869289f..6db43fc14b 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);
    +}
    
    From 6fece14cfbb852c108c2094ae0879da76f2f445e Mon Sep 17 00:00:00 2001
    From: Andrew Kelley 
    Date: Tue, 26 Dec 2017 19:44:08 -0500
    Subject: [PATCH 13/14] self-hosted: build against zig_llvm and embedded LLD
    
    Now the self-hosted compiler re-uses the same C++ code for interfacing
    with LLVM as the C++ code.
    It also links against the same LLD library files.
    ---
     CMakeLists.txt             |  22 +--
     README.md                  |  30 +--
     build.zig                  |  29 ++-
     src-self-hosted/c.zig      |   7 +-
     src-self-hosted/ir.zig     | 112 +++++++++++
     src-self-hosted/main.zig   |   7 +-
     src-self-hosted/module.zig |   7 +
     src-self-hosted/scope.zig  |  16 ++
     src/all_types.hpp          |   2 +-
     src/analyze.cpp            |   2 +-
     src/codegen.cpp            |   2 +-
     src/config.h.in            |   4 +
     src/link.cpp               |  14 +-
     src/main.cpp               |   5 +
     src/os.hpp                 |   2 +-
     src/target.hpp             |   2 +-
     src/util.hpp               |   2 -
     src/zig_llvm.cpp           |  94 ++++++---
     src/zig_llvm.h             | 394 +++++++++++++++++++++++++++++++++++++
     src/zig_llvm.hpp           | 383 -----------------------------------
     std/build.zig              |   7 +
     std/cstr.zig               |  54 +++++
     22 files changed, 736 insertions(+), 461 deletions(-)
     create mode 100644 src-self-hosted/ir.zig
     create mode 100644 src-self-hosted/scope.zig
     create mode 100644 src/zig_llvm.h
     delete mode 100644 src/zig_llvm.hpp
    
    diff --git a/CMakeLists.txt b/CMakeLists.txt
    index b94b4e1323..7da082805a 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,8 @@ if(ZIG_TEST_COVERAGE)
         set(EXE_LDFLAGS "${EXE_LDFLAGS} -fprofile-arcs -ftest-coverage")
     endif()
     
    +add_library(zig_cpp STATIC ${ZIG_CPP_SOURCES})
    +
     add_executable(zig ${ZIG_SOURCES})
     set_target_properties(zig PROPERTIES
         COMPILE_FLAGS ${EXE_CFLAGS}
    @@ -397,6 +404,7 @@ set_target_properties(zig PROPERTIES
     )
     
     target_link_libraries(zig LINK_PUBLIC
    +    zig_cpp
         ${SOFTFLOAT_LIBRARIES}
         ${CLANG_LIBRARIES}
         ${LLD_LIBRARIES}
    @@ -407,6 +415,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}")
    @@ -619,16 +628,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 987197289c..1ba90c004c 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 e6564db96e..cfc83cf424 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),
    diff --git a/src-self-hosted/c.zig b/src-self-hosted/c.zig
    index b7e057b941..9a4b56adea 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 0000000000..b25bb183c5
    --- /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 6fdacda4b2..ff8fb37b42 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 700ccf0176..a0cbe9c864 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/scope.zig b/src-self-hosted/scope.zig
    new file mode 100644
    index 0000000000..05e586daae
    --- /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/all_types.hpp b/src/all_types.hpp
    index a582f561cc..12ecc84a86 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 9ec4db824c..02cdb3485d 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 552467989e..108b5e0e2e 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 
    diff --git a/src/config.h.in b/src/config.h.in
    index a596213a3d..73e1de27c1 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 bc84b27b89..f07364e5bc 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 60d2750bde..66ffbbde82 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 d4d1676df6..5d29db0d07 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 2b678b313d..9bcca776f4 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 73608b3b08..ce6cc09a59 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 0c3e711dd5..94d18b1d49 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);
     }
     
    @@ -771,29 +800,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);
    @@ -805,7 +840,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 0000000000..9a67bf7135
    --- /dev/null
    +++ b/src/zig_llvm.h
    @@ -0,0 +1,394 @@
    +/*
    + * 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_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_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_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_LastEnvironmentType = ZigLLVM_OpenCL
    +};
    +
    +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 404154835e..0000000000
    --- a/src/zig_llvm.hpp
    +++ /dev/null
    @@ -1,383 +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_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_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_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_LastEnvironmentType = ZigLLVM_OpenCL
    -};
    -
    -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/build.zig b/std/build.zig
    index 3a2079db15..bb5280837f 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 d17b69c7a1..1610f12481 100644
    --- a/std/cstr.zig
    +++ b/std/cstr.zig
    @@ -48,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]);
    +    }
    +};
    +
    
    From 08dd1b553b37de24eaf24a37558b0f9993d4ca42 Mon Sep 17 00:00:00 2001
    From: Josh Wolfe 
    Date: Tue, 26 Dec 2017 18:04:09 -0700
    Subject: [PATCH 14/14] set compile flags for zip_cpp
    
    ---
     CMakeLists.txt | 3 +++
     1 file changed, 3 insertions(+)
    
    diff --git a/CMakeLists.txt b/CMakeLists.txt
    index 7da082805a..1cf2f2d8e6 100644
    --- a/CMakeLists.txt
    +++ b/CMakeLists.txt
    @@ -396,6 +396,9 @@ if(ZIG_TEST_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